github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/common/unitstatus.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"gopkg.in/juju/charm.v6/hooks"
    10  
    11  	"github.com/juju/juju/core/status"
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/juju/worker/uniter/operation"
    14  )
    15  
    16  // StatusAndErr pairs a StatusInfo with an error associated with
    17  // retrieving it.
    18  type StatusAndErr struct {
    19  	Status status.StatusInfo
    20  	Err    error
    21  }
    22  
    23  // UnitStatusGetter defines the unit functionality required to
    24  // determine unit agent and workload status.
    25  type UnitStatusGetter interface {
    26  	AgentStatus() (status.StatusInfo, error)
    27  	Status() (status.StatusInfo, error)
    28  	AgentPresence() (bool, error)
    29  	ShouldBeAssigned() bool
    30  	Name() string
    31  	Life() state.Life
    32  }
    33  
    34  // UnitStatus returns the unit agent and workload status for a given
    35  // unit, with special handling for agent presence.
    36  func (c *ModelPresenceContext) UnitStatus(unit UnitStatusGetter) (agent StatusAndErr, workload StatusAndErr) {
    37  	agent.Status, agent.Err = unit.AgentStatus()
    38  	workload.Status, workload.Err = unit.Status()
    39  
    40  	if !canBeLost(agent.Status, workload.Status) {
    41  		// The unit is allocating or installing - there's no point in
    42  		// enquiring about the agent liveness.
    43  		return
    44  	}
    45  
    46  	agentAlive, err := c.unitPresence(unit)
    47  	if err != nil {
    48  		return
    49  	}
    50  	if unit.Life() != state.Dead && !agentAlive {
    51  		// If the unit is in error, it would be bad to throw away
    52  		// the error information as when the agent reconnects, that
    53  		// error information would then be lost.
    54  		if workload.Status.Status != status.Error {
    55  			workload.Status.Status = status.Unknown
    56  			workload.Status.Message = fmt.Sprintf("agent lost, see 'juju show-status-log %s'", unit.Name())
    57  		}
    58  		agent.Status.Status = status.Lost
    59  		agent.Status.Message = "agent is not communicating with the server"
    60  	}
    61  	return
    62  }
    63  
    64  func canBeLost(agent, workload status.StatusInfo) bool {
    65  	switch agent.Status {
    66  	case status.Allocating, status.Running:
    67  		return false
    68  	case status.Executing:
    69  		return agent.Message != operation.RunningHookMessage(string(hooks.Install))
    70  	}
    71  
    72  	// TODO(fwereade/wallyworld): we should have an explicit place in the model
    73  	// to tell us when we've hit this point, instead of piggybacking on top of
    74  	// status and/or status history.
    75  
    76  	return isWorkloadInstalled(workload)
    77  }
    78  
    79  func isWorkloadInstalled(workload status.StatusInfo) bool {
    80  	switch workload.Status {
    81  	case status.Maintenance:
    82  		return workload.Message != status.MessageInstallingCharm
    83  	case status.Waiting:
    84  		switch workload.Message {
    85  		case status.MessageWaitForMachine:
    86  		case status.MessageInstallingAgent:
    87  		case status.MessageInitializingAgent:
    88  			return false
    89  		}
    90  	}
    91  	return true
    92  }