github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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-unstable/hooks" 10 11 "github.com/juju/juju/state" 12 "github.com/juju/juju/status" 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 Name() string 30 Life() state.Life 31 } 32 33 // UnitStatus returns the unit agent and workload status for a given 34 // unit, with special handling for agent presence. 35 func UnitStatus(unit UnitStatusGetter) (agent StatusAndErr, workload StatusAndErr) { 36 agent.Status, agent.Err = unit.AgentStatus() 37 workload.Status, workload.Err = unit.Status() 38 39 if !canBeLost(agent.Status, workload.Status) { 40 // The unit is allocating or installing - there's no point in 41 // enquiring about the agent liveness. 42 return 43 } 44 45 agentAlive, err := unit.AgentPresence() 46 if err != nil { 47 return 48 } 49 if unit.Life() != state.Dead && !agentAlive { 50 // If the unit is in error, it would be bad to throw away 51 // the error information as when the agent reconnects, that 52 // error information would then be lost. 53 if workload.Status.Status != status.Error { 54 workload.Status.Status = status.Unknown 55 workload.Status.Message = fmt.Sprintf("agent lost, see 'juju show-status-log %s'", unit.Name()) 56 } 57 agent.Status.Status = status.Lost 58 agent.Status.Message = "agent is not communicating with the server" 59 } 60 return 61 } 62 63 func canBeLost(agent, workload status.StatusInfo) bool { 64 switch agent.Status { 65 case status.Allocating: 66 return false 67 case status.Executing: 68 return agent.Message != operation.RunningHookMessage(string(hooks.Install)) 69 } 70 71 // TODO(fwereade/wallyworld): we should have an explicit place in the model 72 // to tell us when we've hit this point, instead of piggybacking on top of 73 // status and/or status history. 74 75 return isWorkloadInstalled(workload) 76 } 77 78 func isWorkloadInstalled(workload status.StatusInfo) bool { 79 switch workload.Status { 80 case status.Maintenance: 81 return workload.Message != status.MessageInstallingCharm 82 case status.Waiting: 83 switch workload.Message { 84 case status.MessageWaitForMachine: 85 case status.MessageInstallingAgent: 86 case status.MessageInitializingAgent: 87 return false 88 } 89 } 90 return true 91 }