func (s *backingStatus) updated(st *State, store *multiwatcherStore, id string) error { parentID, ok := backingEntityIdForGlobalKey(id) if !ok { return nil } info0 := store.Get(parentID) switch info := info0.(type) { case nil: // The parent info doesn't exist. Ignore the status until it does. return nil case *multiwatcher.UnitInfo: newInfo := *info // Get the unit's current recorded status from state. // It's needed to reset the unit status when a unit comes off error. statusInfo, err := getStatus(st, unitGlobalKey(newInfo.Name), "unit") if err != nil { return err } if err := s.updatedUnitStatus(st, store, id, statusInfo, &newInfo); err != nil { return err } info0 = &newInfo case *multiwatcher.ServiceInfo: newInfo := *info newInfo.Status.Current = multiwatcher.Status(s.Status) newInfo.Status.Message = s.StatusInfo newInfo.Status.Data = s.StatusData newInfo.Status.Since = unixNanoToTime(s.Updated) info0 = &newInfo case *multiwatcher.MachineInfo: newInfo := *info newInfo.Status = multiwatcher.Status(s.Status) newInfo.StatusInfo = s.StatusInfo newInfo.StatusData = s.StatusData info0 = &newInfo default: panic(fmt.Errorf("status for unexpected entity with id %q; type %T", id, info)) } store.Update(info0) return nil }
func (m *backingMachine) updated(st *State, store *multiwatcherStore, id string) error { info := &multiwatcher.MachineInfo{ EnvUUID: st.EnvironUUID(), Id: m.Id, Life: multiwatcher.Life(m.Life.String()), Series: m.Series, Jobs: paramsJobsFromJobs(m.Jobs), Addresses: mergedAddresses(m.MachineAddresses, m.Addresses), SupportedContainers: m.SupportedContainers, SupportedContainersKnown: m.SupportedContainersKnown, HasVote: m.HasVote, WantsVote: wantsVote(m.Jobs, m.NoVote), } oldInfo := store.Get(info.EntityId()) if oldInfo == nil { // We're adding the entry for the first time, // so fetch the associated machine status. statusInfo, err := getStatus(st, machineGlobalKey(m.Id), "machine") if err != nil { return err } info.Status = multiwatcher.Status(statusInfo.Status) info.StatusInfo = statusInfo.Message } else { // The entry already exists, so preserve the current status and // instance data. oldInfo := oldInfo.(*multiwatcher.MachineInfo) info.Status = oldInfo.Status info.StatusInfo = oldInfo.StatusInfo info.InstanceId = oldInfo.InstanceId info.HardwareCharacteristics = oldInfo.HardwareCharacteristics } // If the machine is been provisioned, fetch the instance id as required, // and set instance id and hardware characteristics. if m.Nonce != "" && info.InstanceId == "" { instanceData, err := getInstanceData(st, m.Id) if err == nil { info.InstanceId = string(instanceData.InstanceId) info.HardwareCharacteristics = hardwareCharacteristics(instanceData) } else if !errors.IsNotFound(err) { return err } } store.Update(info) return nil }
about: "ServiceInfo Delta", value: multiwatcher.Delta{ Entity: &multiwatcher.ServiceInfo{ Name: "Benji", Exposed: true, CharmURL: "cs:quantal/name", Life: multiwatcher.Life("dying"), OwnerTag: "test-owner", MinUnits: 42, Constraints: constraints.MustParse("arch=armhf mem=1024M"), Config: charm.Settings{ "hello": "goodbye", "foo": false, }, Status: multiwatcher.StatusInfo{ Current: multiwatcher.Status("active"), Message: "all good", }, }, }, json: `["service","change",{"CharmURL": "cs:quantal/name","Name":"Benji","Exposed":true,"Life":"dying","OwnerTag":"test-owner","MinUnits":42,"Constraints":{"arch":"armhf", "mem": 1024},"Config": {"hello":"goodbye","foo":false},"Subordinate":false,"Status":{"Current":"active", "Message":"all good", "Version": "", "Err": null, "Data": null, "Since": null}}]`, }, { about: "UnitInfo Delta", value: multiwatcher.Delta{ Entity: &multiwatcher.UnitInfo{ Name: "Benji", Service: "Shazam", Series: "precise", CharmURL: "cs:~user/precise/wordpress-42", Ports: []network.Port{{ Protocol: "http",
func (s *backingStatus) updatedUnitStatus(st *State, store *multiwatcherStore, id string, unitStatus StatusInfo, newInfo *multiwatcher.UnitInfo) error { // Unit or workload status - display the agent status or any error. if strings.HasSuffix(id, "#charm") || s.Status == StatusError { newInfo.WorkloadStatus.Current = multiwatcher.Status(s.Status) newInfo.WorkloadStatus.Message = s.StatusInfo newInfo.WorkloadStatus.Data = s.StatusData newInfo.WorkloadStatus.Since = unixNanoToTime(s.Updated) } else { newInfo.AgentStatus.Current = multiwatcher.Status(s.Status) newInfo.AgentStatus.Message = s.StatusInfo newInfo.AgentStatus.Data = s.StatusData newInfo.AgentStatus.Since = unixNanoToTime(s.Updated) // If the unit was in error and now it's not, we need to reset its // status back to what was previously recorded. if newInfo.WorkloadStatus.Current == multiwatcher.Status(StatusError) { newInfo.WorkloadStatus.Current = multiwatcher.Status(unitStatus.Status) newInfo.WorkloadStatus.Message = unitStatus.Message newInfo.WorkloadStatus.Data = unitStatus.Data newInfo.WorkloadStatus.Since = unixNanoToTime(s.Updated) } } // Legacy status info - it is an aggregated value between workload and agent statuses. legacyStatus, ok := TranslateToLegacyAgentState( Status(newInfo.AgentStatus.Current), Status(newInfo.WorkloadStatus.Current), newInfo.WorkloadStatus.Message, ) if !ok { logger.Warningf( "translate to legacy status encounted unexpected workload status %q and agent status %q", newInfo.WorkloadStatus.Current, newInfo.AgentStatus.Current) } newInfo.Status = multiwatcher.Status(legacyStatus) if newInfo.Status == multiwatcher.Status(StatusError) { newInfo.StatusInfo = newInfo.WorkloadStatus.Message newInfo.StatusData = newInfo.WorkloadStatus.Data } else { newInfo.StatusInfo = newInfo.AgentStatus.Message newInfo.StatusData = newInfo.AgentStatus.Data } // A change in a unit's status might also affect it's service. service, err := st.Service(newInfo.Service) if err != nil { return errors.Trace(err) } serviceId, ok := backingEntityIdForGlobalKey(service.globalKey()) if !ok { return nil } serviceInfo := store.Get(serviceId) if serviceInfo == nil { return nil } status, err := service.Status() if err != nil { return errors.Trace(err) } newServiceInfo := *serviceInfo.(*multiwatcher.ServiceInfo) newServiceInfo.Status.Current = multiwatcher.Status(status.Status) newServiceInfo.Status.Message = status.Message newServiceInfo.Status.Data = status.Data newServiceInfo.Status.Since = status.Since store.Update(&newServiceInfo) return nil }
func (svc *backingService) updated(st *State, store *multiwatcherStore, id string) error { if svc.CharmURL == nil { return errors.Errorf("charm url is nil") } env, err := st.Environment() if err != nil { return errors.Trace(err) } info := &multiwatcher.ServiceInfo{ EnvUUID: st.EnvironUUID(), Name: svc.Name, Exposed: svc.Exposed, CharmURL: svc.CharmURL.String(), OwnerTag: svc.fixOwnerTag(env), Life: multiwatcher.Life(svc.Life.String()), MinUnits: svc.MinUnits, Subordinate: svc.Subordinate, } oldInfo := store.Get(info.EntityId()) needConfig := false if oldInfo == nil { logger.Debugf("new service %q added to backing state", svc.Name) key := serviceGlobalKey(svc.Name) // We're adding the entry for the first time, // so fetch the associated child documents. c, err := readConstraints(st, key) if err != nil { return errors.Trace(err) } info.Constraints = c needConfig = true // Fetch the status. service, err := st.Service(svc.Name) if err != nil { return errors.Trace(err) } serviceStatus, err := service.Status() if err != nil { logger.Warningf("reading service status for key %s: %v", key, err) } if err != nil && !errors.IsNotFound(err) { return errors.Annotatef(err, "reading service status for key %s", key) } if err == nil { info.Status = multiwatcher.StatusInfo{ Current: multiwatcher.Status(serviceStatus.Status), Message: serviceStatus.Message, Data: serviceStatus.Data, Since: serviceStatus.Since, } } else { // TODO(wallyworld) - bug http://pad.lv/1451283 // return an error here once we figure out what's happening // Not sure how status can even return NotFound as it is created // with the service initially. For now, we'll log the error as per // the above and return Unknown. now := time.Now() info.Status = multiwatcher.StatusInfo{ Current: multiwatcher.Status(StatusUnknown), Since: &now, } } } else { // The entry already exists, so preserve the current status. oldInfo := oldInfo.(*multiwatcher.ServiceInfo) info.Constraints = oldInfo.Constraints if info.CharmURL == oldInfo.CharmURL { // The charm URL remains the same - we can continue to // use the same config settings. info.Config = oldInfo.Config } else { // The charm URL has changed - we need to fetch the // settings from the new charm's settings doc. needConfig = true } } if needConfig { var err error info.Config, _, err = readSettingsDoc(st, serviceSettingsKey(svc.Name, svc.CharmURL)) if err != nil { return errors.Trace(err) } } store.Update(info) return nil }
func (u *backingUnit) updated(st *State, store *multiwatcherStore, id string) error { info := &multiwatcher.UnitInfo{ EnvUUID: st.EnvironUUID(), Name: u.Name, Service: u.Service, Series: u.Series, MachineId: u.MachineId, Subordinate: u.Principal != "", } if u.CharmURL != nil { info.CharmURL = u.CharmURL.String() } oldInfo := store.Get(info.EntityId()) if oldInfo == nil { logger.Debugf("new unit %q added to backing state", u.Name) // We're adding the entry for the first time, // so fetch the associated unit status and opened ports. unitStatus, agentStatus, err := unitAndAgentStatus(st, u.Name) if err != nil { return errors.Annotatef(err, "reading unit and agent status for %q", u.Name) } // Unit and workload status. info.WorkloadStatus = multiwatcher.StatusInfo{ Current: multiwatcher.Status(unitStatus.Status), Message: unitStatus.Message, Data: unitStatus.Data, Since: unitStatus.Since, } if u.Tools != nil { info.AgentStatus.Version = u.Tools.Version.Number.String() } info.AgentStatus = multiwatcher.StatusInfo{ Current: multiwatcher.Status(agentStatus.Status), Message: agentStatus.Message, Data: agentStatus.Data, Since: agentStatus.Since, } // Legacy status info. if unitStatus.Status == StatusError { info.Status = multiwatcher.Status(unitStatus.Status) info.StatusInfo = unitStatus.Message info.StatusData = unitStatus.Data } else { legacyStatus, ok := TranslateToLegacyAgentState(agentStatus.Status, unitStatus.Status, unitStatus.Message) if !ok { logger.Warningf( "translate to legacy status encounted unexpected workload status %q and agent status %q", unitStatus.Status, agentStatus.Status) } info.Status = multiwatcher.Status(legacyStatus) info.StatusInfo = agentStatus.Message info.StatusData = agentStatus.Data } if len(info.StatusData) == 0 { info.StatusData = nil } portRanges, compatiblePorts, err := getUnitPortRangesAndPorts(st, u.Name) if err != nil { return errors.Trace(err) } info.PortRanges = portRanges info.Ports = compatiblePorts } else { // The entry already exists, so preserve the current status and ports. oldInfo := oldInfo.(*multiwatcher.UnitInfo) // Legacy status. info.Status = oldInfo.Status info.StatusInfo = oldInfo.StatusInfo // Unit and workload status. info.AgentStatus = oldInfo.AgentStatus info.WorkloadStatus = oldInfo.WorkloadStatus info.Ports = oldInfo.Ports info.PortRanges = oldInfo.PortRanges } publicAddress, privateAddress, err := getUnitAddresses(st, u.Name) if err != nil { return err } info.PublicAddress = publicAddress info.PrivateAddress = privateAddress store.Update(info) return nil }