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 }