24
24
func Status(conn *juju.Conn, patterns []string) (*api.Status, error) {
25
var nilStatus api.Status
25
26
var context statusContext
26
27
unitMatcher, err := NewUnitMatcher(patterns)
29
return &nilStatus, err
30
if context.services, context.units, err = fetchAllServicesAndUnits(conn.State, unitMatcher); err != nil {
32
context.units, context.latestCharms, err = fetchAllServicesAndUnits(conn.State, unitMatcher); err != nil {
33
return &nilStatus, err
34
36
// Filter machines by units in scope.
36
38
if !unitMatcher.matchesAny() {
37
39
machineIds, err = fetchUnitMachineIds(context.units)
41
return &nilStatus, err
42
44
if context.machines, err = fetchMachines(conn.State, machineIds); err != nil {
45
return &nilStatus, err
46
48
context.instances, err = fetchAllInstances(conn.Environ)
58
60
type statusContext struct {
59
instances map[instance.Id]instance.Instance
60
machines map[string][]*state.Machine
61
services map[string]*state.Service
62
units map[string]map[string]*state.Unit
61
instances map[instance.Id]instance.Instance
62
machines map[string][]*state.Machine
63
services map[string]*state.Service
64
units map[string]map[string]*state.Unit
65
latestCharms map[charm.URL]string
65
68
type unitMatcher struct {
199
// fetchAllServicesAndUnits returns a map from service name to service
200
// and a map from service name to unit name to unit.
201
func fetchAllServicesAndUnits(st *state.State, unitMatcher unitMatcher) (map[string]*state.Service, map[string]map[string]*state.Unit, error) {
202
// fetchAllServicesAndUnits returns a map from service name to service,
203
// a map from service name to unit name to unit, and a map from base charm URL to latest URL.
204
func fetchAllServicesAndUnits(
205
st *state.State, unitMatcher unitMatcher) (
206
map[string]*state.Service, map[string]map[string]*state.Unit, map[charm.URL]string, error) {
202
208
svcMap := make(map[string]*state.Service)
203
209
unitMap := make(map[string]map[string]*state.Unit)
210
latestCharms := make(map[charm.URL]string)
204
211
services, err := st.AllServices()
213
return nil, nil, nil, err
208
215
for _, s := range services {
209
216
units, err := s.AllUnits()
218
return nil, nil, nil, err
213
220
svcUnitMap := make(map[string]*state.Unit)
214
221
for _, u := range units {
220
227
if unitMatcher.matchesAny() || len(svcUnitMap) > 0 {
221
228
unitMap[s.Name()] = svcUnitMap
222
229
svcMap[s.Name()] = s
225
return svcMap, unitMap, nil
230
// Record the base URL for the service's charm so that
231
// the latest store revision can be looked up.
232
charmURL, _ := s.CharmURL()
233
if charmURL.Schema == "cs" {
234
latestCharms[*charmURL.WithRevision(-1)] = ""
238
for baseURL, _ := range latestCharms {
239
ch, err := st.LatestPlaceholderCharm(&baseURL)
240
if errors.IsNotFoundError(err) {
244
return nil, nil, nil, err
246
latestCharms[baseURL] = ch.String()
248
return svcMap, unitMap, latestCharms, nil
228
251
// fetchUnitMachineIds returns a set of IDs for machines that
292
315
status.InstanceId = instid
293
316
inst, ok := context.instances[instid]
295
status.DNSName, _ = inst.DNSName()
318
status.DNSName = instance.SelectPublicAddress(machine.Addresses())
296
319
status.InstanceState = inst.Status()
298
321
// Double plus ungood. There is an instance id recorded
335
358
func (context *statusContext) processService(service *state.Service) (status api.ServiceStatus) {
336
url, _ := service.CharmURL()
337
status.Charm = url.String()
359
serviceCharmURL, _ := service.CharmURL()
360
status.Charm = serviceCharmURL.String()
338
361
status.Exposed = service.IsExposed()
339
362
status.Life = processLife(service)
364
latestCharm, ok := context.latestCharms[*serviceCharmURL.WithRevision(-1)]
365
if ok && latestCharm != serviceCharmURL.String() {
366
status.CanUpgradeTo = latestCharm
341
369
status.Relations, status.SubordinateTo, err = context.processRelations(service)
346
374
if service.IsPrincipal() {
347
status.Units = context.processUnits(context.units[service.Name()])
375
status.Units = context.processUnits(context.units[service.Name()], serviceCharmURL.String())
352
func (context *statusContext) processUnits(units map[string]*state.Unit) map[string]api.UnitStatus {
380
func (context *statusContext) processUnits(units map[string]*state.Unit, serviceCharm string) map[string]api.UnitStatus {
353
381
unitsMap := make(map[string]api.UnitStatus)
354
382
for _, unit := range units {
355
unitsMap[unit.Name()] = context.processUnit(unit)
383
unitsMap[unit.Name()] = context.processUnit(unit, serviceCharm)
360
func (context *statusContext) processUnit(unit *state.Unit) (status api.UnitStatus) {
388
func (context *statusContext) processUnit(unit *state.Unit, serviceCharm string) (status api.UnitStatus) {
361
389
status.PublicAddress, _ = unit.PublicAddress()
362
390
for _, port := range unit.OpenedPorts() {
363
391
status.OpenedPorts = append(status.OpenedPorts, port.String())
365
393
if unit.IsPrincipal() {
366
394
status.Machine, _ = unit.AssignedMachineId()
396
curl, _ := unit.CharmURL()
397
if serviceCharm != "" && curl != nil && curl.String() != serviceCharm {
398
status.Charm = curl.String()
369
401
status.AgentVersion,
370
402
status.AgentState,
376
408
subUnit := context.unitByName(name)
377
409
// subUnit may be nil if subordinate was filtered out.
378
410
if subUnit != nil {
379
status.Subordinates[name] = context.processUnit(subUnit)
411
status.Subordinates[name] = context.processUnit(subUnit, serviceCharm)