github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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  	VALIDATION
    16  	SUCCESS
    17  	LOGTRANSFER
    18  	REAP
    19  	REAPFAILED
    20  	DONE
    21  	ABORT
    22  	ABORTDONE
    23  )
    24  
    25  var phaseNames = []string{
    26  	"UNKNOWN", // To catch uninitialised fields.
    27  	"NONE",    // For watchers to indicate there's never been a migration attempt.
    28  	"QUIESCE",
    29  	"IMPORT",
    30  	"VALIDATION",
    31  	"SUCCESS",
    32  	"LOGTRANSFER",
    33  	"REAP",
    34  	"REAPFAILED",
    35  	"DONE",
    36  	"ABORT",
    37  	"ABORTDONE",
    38  }
    39  
    40  // String returns the name of an model migration phase constant.
    41  func (p Phase) String() string {
    42  	i := int(p)
    43  	if i >= 0 && i < len(phaseNames) {
    44  		return phaseNames[i]
    45  	}
    46  	return "UNKNOWN"
    47  }
    48  
    49  // CanTransitionTo returns true if the given phase is a valid next
    50  // model migration phase.
    51  func (p Phase) CanTransitionTo(targetPhase Phase) bool {
    52  	nextPhases, exists := validTransitions[p]
    53  	if !exists {
    54  		return false
    55  	}
    56  	for _, nextPhase := range nextPhases {
    57  		if nextPhase == targetPhase {
    58  			return true
    59  		}
    60  	}
    61  	return false
    62  }
    63  
    64  // IsTerminal returns true if the phase is one which signifies the end
    65  // of a migration.
    66  func (p Phase) IsTerminal() bool {
    67  	for _, t := range terminalPhases {
    68  		if p == t {
    69  			return true
    70  		}
    71  	}
    72  	return false
    73  }
    74  
    75  // IsRunning returns true if the phase indicates the migration is
    76  // active and up to or at the SUCCESS phase. It returns false if the
    77  // phase is one of the final cleanup phases or indicates an failed
    78  // migration.
    79  func (p Phase) IsRunning() bool {
    80  	if p.IsTerminal() {
    81  		return false
    82  	}
    83  	switch p {
    84  	case QUIESCE, IMPORT, VALIDATION, SUCCESS:
    85  		return true
    86  	default:
    87  		return false
    88  	}
    89  }
    90  
    91  // Define all possible phase transitions.
    92  //
    93  // The keys are the "from" states and the values enumerate the
    94  // possible "to" states.
    95  var validTransitions = map[Phase][]Phase{
    96  	QUIESCE:     {IMPORT, ABORT},
    97  	IMPORT:      {VALIDATION, ABORT},
    98  	VALIDATION:  {SUCCESS, ABORT},
    99  	SUCCESS:     {LOGTRANSFER},
   100  	LOGTRANSFER: {REAP},
   101  	REAP:        {DONE, REAPFAILED},
   102  	ABORT:       {ABORTDONE},
   103  }
   104  
   105  var terminalPhases []Phase
   106  
   107  func init() {
   108  	// Compute the terminal phases.
   109  	for p := 0; p <= len(phaseNames); p++ {
   110  		phase := Phase(p)
   111  		if _, exists := validTransitions[phase]; !exists {
   112  			terminalPhases = append(terminalPhases, phase)
   113  		}
   114  	}
   115  }
   116  
   117  // ParsePhase converts a string model migration phase name
   118  // to its constant value.
   119  func ParsePhase(target string) (Phase, bool) {
   120  	for p, name := range phaseNames {
   121  		if target == name {
   122  			return Phase(p), true
   123  		}
   124  	}
   125  	return UNKNOWN, false
   126  }