github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/migration/phase.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package migration 5 6 // Phase values specify model migration phases. 7 type Phase int 8 9 // Enumerate all possible migration phases. 10 const ( 11 UNKNOWN Phase = iota 12 NONE 13 QUIESCE 14 IMPORT 15 PROCESSRELATIONS 16 VALIDATION 17 SUCCESS 18 LOGTRANSFER 19 REAP 20 REAPFAILED 21 DONE 22 ABORT 23 ABORTDONE 24 ) 25 26 var phaseNames = []string{ 27 "UNKNOWN", // To catch uninitialised fields. 28 "NONE", // For watchers to indicate there's never been a migration attempt. 29 "QUIESCE", 30 "IMPORT", 31 "PROCESSRELATIONS", 32 "VALIDATION", 33 "SUCCESS", 34 "LOGTRANSFER", 35 "REAP", 36 "REAPFAILED", 37 "DONE", 38 "ABORT", 39 "ABORTDONE", 40 } 41 42 // Those phases are only used to get a complete successful round for testing purposes. 43 func SuccessfulMigrationPhases() []Phase { 44 return []Phase{ 45 IMPORT, 46 PROCESSRELATIONS, 47 VALIDATION, 48 SUCCESS, 49 LOGTRANSFER, 50 REAP, 51 DONE, 52 } 53 } 54 55 // String returns the name of an model migration phase constant. 56 func (p Phase) String() string { 57 i := int(p) 58 if i >= 0 && i < len(phaseNames) { 59 return phaseNames[i] 60 } 61 return "UNKNOWN" 62 } 63 64 // CanTransitionTo returns true if the given phase is a valid next 65 // model migration phase. 66 func (p Phase) CanTransitionTo(targetPhase Phase) bool { 67 nextPhases, exists := validTransitions[p] 68 if !exists { 69 return false 70 } 71 for _, nextPhase := range nextPhases { 72 if nextPhase == targetPhase { 73 return true 74 } 75 } 76 return false 77 } 78 79 // IsTerminal returns true if the phase is one which signifies the end 80 // of a migration. 81 func (p Phase) IsTerminal() bool { 82 for _, t := range terminalPhases { 83 if p == t { 84 return true 85 } 86 } 87 return false 88 } 89 90 // IsRunning returns true if the phase indicates the migration is 91 // active and up to or at the SUCCESS phase. It returns false if the 92 // phase is one of the final cleanup phases or indicates an failed 93 // migration. 94 func (p Phase) IsRunning() bool { 95 if p.IsTerminal() { 96 return false 97 } 98 switch p { 99 case QUIESCE, IMPORT, PROCESSRELATIONS, VALIDATION, SUCCESS: 100 return true 101 default: 102 return false 103 } 104 } 105 106 // Define all possible phase transitions. 107 // 108 // The keys are the "from" states and the values enumerate the 109 // possible "to" states. 110 var validTransitions = map[Phase][]Phase{ 111 QUIESCE: {IMPORT, ABORT}, 112 IMPORT: {PROCESSRELATIONS, ABORT}, 113 PROCESSRELATIONS: {VALIDATION, ABORT}, 114 VALIDATION: {SUCCESS, ABORT}, 115 SUCCESS: {LOGTRANSFER}, 116 LOGTRANSFER: {REAP}, 117 REAP: {DONE, REAPFAILED}, 118 ABORT: {ABORTDONE}, 119 } 120 121 var terminalPhases []Phase 122 123 func init() { 124 // Compute the terminal phases. 125 for p := 0; p <= len(phaseNames); p++ { 126 phase := Phase(p) 127 if _, exists := validTransitions[phase]; !exists { 128 terminalPhases = append(terminalPhases, phase) 129 } 130 } 131 } 132 133 // ParsePhase converts a string model migration phase name 134 // to its constant value. 135 func ParsePhase(target string) (Phase, bool) { 136 for p, name := range phaseNames { 137 if target == name { 138 return Phase(p), true 139 } 140 } 141 return UNKNOWN, false 142 }