mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-24 17:47:46 +01:00
105 lines
2.5 KiB
Go
105 lines
2.5 KiB
Go
|
package job
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"github.com/vmware/harbor/dao"
|
||
|
"github.com/vmware/harbor/utils/log"
|
||
|
)
|
||
|
|
||
|
type StateHandler interface {
|
||
|
Enter() error
|
||
|
//Exit should be idempotent
|
||
|
Exit() error
|
||
|
}
|
||
|
|
||
|
type DummyHandler struct {
|
||
|
JobID int64
|
||
|
}
|
||
|
|
||
|
func (dh DummyHandler) Enter() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (dh DummyHandler) Exit() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type StatusUpdater struct {
|
||
|
DummyHandler
|
||
|
State string
|
||
|
}
|
||
|
|
||
|
func (su StatusUpdater) Enter() error {
|
||
|
err := dao.UpdateJobStatus(su.JobID, su.State)
|
||
|
if err != nil {
|
||
|
log.Warningf("Failed to update state of job: %d, state: %s, error: %v", su.JobID, su.State, err)
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
type JobSM struct {
|
||
|
JobID int64
|
||
|
CurrentState string
|
||
|
PreviousState string
|
||
|
//The states that don't have to exist in transition map, such as "Error", "Canceled"
|
||
|
ForcedStates map[string]struct{}
|
||
|
Transitions map[string]map[string]struct{}
|
||
|
Handlers map[string]StateHandler
|
||
|
}
|
||
|
|
||
|
func (sm *JobSM) EnterState(s string) error {
|
||
|
log.Debugf("Trying to transit from State: %s, to State: %s", sm.CurrentState, s)
|
||
|
targets, ok := sm.Transitions[sm.CurrentState]
|
||
|
_, exist := targets[s]
|
||
|
_, isForced := sm.ForcedStates[s]
|
||
|
if !exist && !isForced {
|
||
|
return fmt.Errorf("Transition from %s to %s does not exist!", sm.CurrentState, s)
|
||
|
}
|
||
|
exitHandler, ok := sm.Handlers[sm.CurrentState]
|
||
|
if ok {
|
||
|
if err := exitHandler.Exit(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
log.Debugf("No handler found for state:%s, skip", sm.CurrentState)
|
||
|
}
|
||
|
enterHandler, ok := sm.Handlers[s]
|
||
|
if ok {
|
||
|
if err := enterHandler.Enter(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
} else {
|
||
|
log.Debugf("No handler found for state:%s, skip", s)
|
||
|
}
|
||
|
sm.PreviousState = sm.CurrentState
|
||
|
sm.CurrentState = s
|
||
|
log.Debugf("Transition succeeded, current state: %s", s)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (sm *JobSM) AddTransition(from string, to string, h StateHandler) {
|
||
|
_, ok := sm.Transitions[from]
|
||
|
if !ok {
|
||
|
sm.Transitions[from] = make(map[string]struct{})
|
||
|
}
|
||
|
sm.Transitions[from][to] = struct{}{}
|
||
|
sm.Handlers[to] = h
|
||
|
}
|
||
|
|
||
|
func (sm *JobSM) RemoveTransition(from string, to string) {
|
||
|
_, ok := sm.Transitions[from]
|
||
|
if !ok {
|
||
|
return
|
||
|
}
|
||
|
delete(sm.Transitions[from], to)
|
||
|
}
|
||
|
|
||
|
func (sm *JobSM) InitJobSM() {
|
||
|
sm.Handlers = make(map[string]StateHandler)
|
||
|
sm.Transitions = make(map[string]map[string]struct{})
|
||
|
sm.CurrentState = dao.JobPending
|
||
|
log.Debugf("sm.Handlers: %v", sm.Handlers)
|
||
|
sm.AddTransition(dao.JobPending, dao.JobRunning, StatusUpdater{DummyHandler{JobID: sm.JobID}, dao.JobRunning})
|
||
|
sm.Handlers[dao.JobError] = StatusUpdater{DummyHandler{JobID: sm.JobID}, dao.JobError}
|
||
|
}
|