github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/status/status.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package status
     5  
     6  import (
     7  	"time"
     8  )
     9  
    10  // Status used to represent the status of an entity, but has recently become
    11  // and applies to "workloads" as well, which we don't currently model, for no
    12  // very clear reason.
    13  //
    14  // Status values currently apply to machine (agents), unit (agents), unit
    15  // (workloads), application (workloads), volumes, filesystems, and models.
    16  type Status string
    17  
    18  // String returns a string representation of the Status.
    19  func (s Status) String() string {
    20  	return string(s)
    21  }
    22  
    23  // StatusInfo holds a Status and associated information.
    24  type StatusInfo struct {
    25  	Status  Status
    26  	Message string
    27  	Data    map[string]interface{}
    28  	Since   *time.Time
    29  }
    30  
    31  // StatusSetter represents a type whose status can be set.
    32  type StatusSetter interface {
    33  	SetStatus(StatusInfo) error
    34  }
    35  
    36  // StatusGetter represents a type whose status can be read.
    37  type StatusGetter interface {
    38  	Status() (StatusInfo, error)
    39  }
    40  
    41  // ModificationStatusGetter represents a type whose modification status can be
    42  // read.
    43  type ModificationStatusGetter interface {
    44  	ModificationStatus() (StatusInfo, error)
    45  }
    46  
    47  const (
    48  	// Status values common to machine and unit agents.
    49  
    50  	// Error means the entity requires human intervention
    51  	// in order to operate correctly.
    52  	Error Status = "error"
    53  
    54  	// Started is set when:
    55  	// The entity is actively participating in the model.
    56  	// For unit agents, this is a state we preserve for backwards
    57  	// compatibility with scripts during the life of Juju 1.x.
    58  	// In Juju 2.x, the agent-state will remain “active” and scripts
    59  	// will watch the unit-state instead for signals of application readiness.
    60  	Started Status = "started"
    61  )
    62  
    63  const (
    64  	// Status values specific to machine agents.
    65  
    66  	// Pending is set when:
    67  	// The machine is not yet participating in the model.
    68  	Pending Status = "pending"
    69  
    70  	// Stopped is set when:
    71  	// The machine's agent will perform no further action, other than
    72  	// to set the unit to Dead at a suitable moment.
    73  	Stopped Status = "stopped"
    74  
    75  	// Down is set when:
    76  	// The machine ought to be signalling activity, but it cannot be
    77  	// detected.
    78  	Down Status = "down"
    79  )
    80  
    81  const (
    82  	// Status values specific to unit agents.
    83  
    84  	// Allocating is set when:
    85  	// The machine on which a unit is to be hosted is still being
    86  	// spun up in the cloud.
    87  	Allocating Status = "allocating"
    88  
    89  	// Rebooting is set when:
    90  	// The machine on which this agent is running is being rebooted.
    91  	// The juju-agent should move from rebooting to idle when the reboot is complete.
    92  	Rebooting Status = "rebooting"
    93  
    94  	// Executing is set when:
    95  	// The agent is running a hook or action. The human-readable message should reflect
    96  	// which hook or action is being run.
    97  	Executing Status = "executing"
    98  
    99  	// Idle is set when:
   100  	// Once the agent is installed and running it will notify the Juju server and its state
   101  	// becomes "idle". It will stay "idle" until some action (e.g. it needs to run a hook) or
   102  	// error (e.g it loses contact with the Juju server) moves it to a different state.
   103  	Idle Status = "idle"
   104  
   105  	// Failed is set when:
   106  	// The unit agent has failed in some way,eg the agent ought to be signalling
   107  	// activity, but it cannot be detected. It might also be that the unit agent
   108  	// detected an unrecoverable condition and managed to tell the Juju server about it.
   109  	Failed Status = "failed"
   110  
   111  	// Lost is set when:
   112  	// The juju agent has not communicated with the juju server for an unexpectedly long time;
   113  	// the unit agent ought to be signalling activity, but none has been detected.
   114  	Lost Status = "lost"
   115  )
   116  
   117  const (
   118  	// Status values specific to applications and units, reflecting the
   119  	// state of the software itself.
   120  
   121  	// Unset is only for applications, and is a placeholder status.
   122  	// The core/cache package deals with aggregating the unit status
   123  	// to the application level.
   124  	Unset Status = "unset"
   125  
   126  	// Maintenance is set when:
   127  	// The unit is not yet providing services, but is actively doing stuff
   128  	// in preparation for providing those services.
   129  	// This is a "spinning" state, not an error state.
   130  	// It reflects activity on the unit itself, not on peers or related units.
   131  	Maintenance Status = "maintenance"
   132  
   133  	// Terminated is set when:
   134  	// This unit used to exist, we have a record of it (perhaps because of storage
   135  	// allocated for it that was flagged to survive it). Nonetheless, it is now gone.
   136  	Terminated Status = "terminated"
   137  
   138  	// Unknown is set when:
   139  	// A unit-agent has finished calling install, config-changed, and start,
   140  	// but the charm has not called status-set yet.
   141  	Unknown Status = "unknown"
   142  
   143  	// Waiting is set when:
   144  	// The unit is unable to progress to an active state because an application to
   145  	// which it is related is not running.
   146  	Waiting Status = "waiting"
   147  
   148  	// Blocked is set when:
   149  	// The unit needs manual intervention to get back to the Running state.
   150  	Blocked Status = "blocked"
   151  
   152  	// Active is set when:
   153  	// The unit believes it is correctly offering all the services it has
   154  	// been asked to offer.
   155  	Active Status = "active"
   156  )
   157  
   158  const (
   159  	// Status values specific to storage.
   160  
   161  	// Attaching indicates that the storage is being attached
   162  	// to a machine.
   163  	Attaching Status = "attaching"
   164  
   165  	// Attached indicates that the storage is attached to a
   166  	// machine.
   167  	Attached Status = "attached"
   168  
   169  	// Detaching indicates that the storage is being detached
   170  	// from a machine.
   171  	Detaching Status = "detaching"
   172  
   173  	// Detached indicates that the storage is not attached to
   174  	// any machine.
   175  	Detached Status = "detached"
   176  )
   177  
   178  const (
   179  	// Status values specific to models.
   180  
   181  	// Available indicates that the model is available for use.
   182  	Available Status = "available"
   183  
   184  	// Busy indicates that the model is not available for use because it is
   185  	// running a process that must take the model offline, such as a migration,
   186  	// upgrade, or backup.  This is a spinning state, it is not an error state,
   187  	// and it should be expected that the model will eventually go back to
   188  	// available.
   189  	Busy Status = "busy"
   190  )
   191  
   192  const (
   193  	// Status values specific to relations.
   194  
   195  	// Joining is used to signify that a relation should become joined soon.
   196  	Joining Status = "joining"
   197  
   198  	// Joined is the normal status for a healthy, alive relation.
   199  	Joined Status = "joined"
   200  
   201  	// Broken is the status for when a relation life goes to Dead.
   202  	Broken Status = "broken"
   203  
   204  	// Suspending is used to signify that a relation will be temporarily broken
   205  	// pending action to resume it.
   206  	Suspending Status = "suspending"
   207  
   208  	// Suspended is used to signify that a relation is temporarily broken pending
   209  	// action to resume it.
   210  	Suspended Status = "suspended"
   211  )
   212  
   213  const (
   214  	// Status values that are common to several entities.
   215  
   216  	// Destroying indicates that the entity is being destroyed.
   217  	//
   218  	// This is valid for volumes, filesystems, and models.
   219  	Destroying Status = "destroying"
   220  )
   221  
   222  // InstanceStatus
   223  const (
   224  	Empty             Status = ""
   225  	Provisioning      Status = "allocating"
   226  	Running           Status = "running"
   227  	ProvisioningError Status = "provisioning error"
   228  )
   229  
   230  // ModificationStatus
   231  const (
   232  	Applied Status = "applied"
   233  )
   234  
   235  const (
   236  	MessageWaitForMachine    = "waiting for machine"
   237  	MessageWaitForContainer  = "waiting for container"
   238  	MessageInstallingAgent   = "installing agent"
   239  	MessageInitializingAgent = "agent initialising"
   240  	MessageInstallingCharm   = "installing charm software"
   241  )
   242  
   243  // KnownModificationStatus returns true if the status has a known value for
   244  // a modification of an instance.
   245  func (s Status) KnownModificationStatus() bool {
   246  	switch s {
   247  	case
   248  		Idle,
   249  		Applied,
   250  		Error,
   251  		Unknown:
   252  		return true
   253  	}
   254  	return false
   255  }
   256  
   257  func (s Status) KnownInstanceStatus() bool {
   258  	switch s {
   259  	case
   260  		Pending,
   261  		ProvisioningError,
   262  		Allocating,
   263  		Running,
   264  		Error,
   265  		Unknown:
   266  		return true
   267  	}
   268  	return false
   269  }
   270  
   271  // KnownAgentStatus returns true if status has a known value for an agent.
   272  // It includes every status that has ever been valid for a unit or machine agent.
   273  // This is used by the apiserver client facade to filter out unknown values.
   274  func (s Status) KnownAgentStatus() bool {
   275  	switch s {
   276  	case
   277  		Allocating,
   278  		Error,
   279  		Failed,
   280  		Rebooting,
   281  		Executing,
   282  		Idle:
   283  		return true
   284  	}
   285  	return false
   286  }
   287  
   288  // KnownWorkloadStatus returns true if status has a known value for a workload.
   289  // It includes every status that has ever been valid for a unit agent.
   290  // This is used by the apiserver client facade to filter out unknown values.
   291  func (s Status) KnownWorkloadStatus() bool {
   292  	if ValidWorkloadStatus(s) {
   293  		return true
   294  	}
   295  	switch s {
   296  	case Error: // include error so that we can filter on what the spec says is valid
   297  		return true
   298  	default:
   299  		return false
   300  	}
   301  }
   302  
   303  // ValidWorkloadStatus returns true if status has a valid value (that is to say,
   304  // a value that it's OK to set) for units or applications.
   305  func ValidWorkloadStatus(status Status) bool {
   306  	switch status {
   307  	case
   308  		Blocked,
   309  		Maintenance,
   310  		Waiting,
   311  		Active,
   312  		Unknown,
   313  		Terminated:
   314  		return true
   315  	default:
   316  		return false
   317  	}
   318  }
   319  
   320  // WorkloadMatches returns true if the candidate matches status,
   321  // taking into account that the candidate may be a legacy
   322  // status value which has been deprecated.
   323  func (s Status) WorkloadMatches(candidate Status) bool {
   324  	return s == candidate
   325  }
   326  
   327  // ValidModelStatus returns true if status has a valid value (that is to say,
   328  // a value that it's OK to set) for models.
   329  func ValidModelStatus(status Status) bool {
   330  	switch status {
   331  	case
   332  		Available,
   333  		Busy,
   334  		Destroying,
   335  		Suspended, // For  model, this means that its cloud credential is invalid and model will not be doing any cloud calls.
   336  		Error:
   337  		return true
   338  	default:
   339  		return false
   340  	}
   341  }
   342  
   343  // Matches returns true if the candidate matches status,
   344  // taking into account that the candidate may be a legacy
   345  // status value which has been deprecated.
   346  func (s Status) Matches(candidate Status) bool {
   347  	return s == candidate
   348  }
   349  
   350  // DeriveStatus is used to determine the application
   351  // status from a set of unit status values.
   352  func DeriveStatus(statuses []StatusInfo) StatusInfo {
   353  	// By providing an unknown default, we get a reasonable answer
   354  	// even if there are no units.
   355  	result := StatusInfo{
   356  		Status: Unknown,
   357  	}
   358  	for _, unitStatus := range statuses {
   359  		currentSeverity := statusSeverities[result.Status]
   360  		unitSeverity := statusSeverities[unitStatus.Status]
   361  		if unitSeverity > currentSeverity {
   362  			result.Status = unitStatus.Status
   363  			result.Message = unitStatus.Message
   364  			result.Data = unitStatus.Data
   365  			result.Since = unitStatus.Since
   366  		}
   367  	}
   368  	return result
   369  }
   370  
   371  // statusSeverities holds status values with a severity measure.
   372  // Status values with higher severity are used in preference to others.
   373  var statusSeverities = map[Status]int{
   374  	Error:       100,
   375  	Blocked:     90,
   376  	Maintenance: 80, // Maintenance (us busy) is higher than Waiting (someone else busy)
   377  	Waiting:     70,
   378  	Active:      60,
   379  	Terminated:  50,
   380  	Unknown:     40,
   381  }