Example #1
0
// SetInstanceStatus updates the instance status for each given
// entity. Only machine tags are accepted.
func (a *InstancePollerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	canAccess, err := a.accessMachine()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		machine, err := a.getOneMachine(arg.Tag, canAccess)
		if err == nil {
			now := a.clock.Now()
			s := status.StatusInfo{
				Status:  status.Status(arg.Status),
				Message: arg.Info,
				Data:    arg.Data,
				Since:   &now,
			}
			err = machine.SetInstanceStatus(s)
			if status.Status(arg.Status) == status.ProvisioningError {
				s.Status = status.Error
				if err == nil {
					err = machine.SetStatus(s)
				}
			}
		}
		result.Results[i].Error = common.ServerError(err)
	}
	return result, nil
}
func (s *InstancePollerSuite) TestSetInstanceStatusFailure(c *gc.C) {
	s.st.SetErrors(
		errors.New("pow!"),                   // m1 := FindEntity("1")
		nil,                                  // m2 := FindEntity("2")
		errors.New("FAIL"),                   // m2.SetInstanceStatus()
		errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved)
	)
	s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: statusInfo("foo")})
	s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: statusInfo("")})

	result, err := s.api.SetInstanceStatus(params.SetStatus{
		Entities: []params.EntityStatusArgs{
			{Tag: "machine-1", Status: status.Status("new")},
			{Tag: "machine-2", Status: status.Status("invalid")},
			{Tag: "machine-3", Status: status.Status("")},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result, jc.DeepEquals, s.machineErrorResults)

	s.st.CheckFindEntityCall(c, 0, "1")
	s.st.CheckFindEntityCall(c, 1, "2")
	s.st.CheckCall(c, 2, "SetInstanceStatus", status.Status("invalid"))
	s.st.CheckFindEntityCall(c, 3, "3")
}
func (s *InstancePollerSuite) TestInstanceStatusSuccess(c *gc.C) {
	s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: statusInfo("foo")})
	s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: statusInfo("")})

	result, err := s.api.InstanceStatus(s.mixedEntities)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result, jc.DeepEquals, params.StatusResults{
		Results: []params.StatusResult{
			{Status: status.Status("foo")},
			{Status: status.Status("")},
			{Error: apiservertesting.NotFoundError("machine 42")},
			{Error: apiservertesting.ServerError(`"service-unknown" is not a valid machine tag`)},
			{Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)},
			{Error: apiservertesting.ServerError(`"unit-missing-1" is not a valid machine tag`)},
			{Error: apiservertesting.ServerError(`"" is not a valid tag`)},
			{Error: apiservertesting.ServerError(`"42" is not a valid tag`)},
		},
	},
	)

	s.st.CheckFindEntityCall(c, 0, "1")
	s.st.CheckCall(c, 1, "InstanceStatus")
	s.st.CheckFindEntityCall(c, 2, "2")
	s.st.CheckCall(c, 3, "InstanceStatus")
	s.st.CheckFindEntityCall(c, 4, "42")
}
Example #4
0
// SetInstanceStatus updates the instance status for each given
// entity. Only machine tags are accepted.
func (p *ProvisionerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	canAccess, err := p.getAuthFunc()
	if err != nil {
		logger.Errorf("failed to get an authorisation function: %v", err)
		return result, errors.Trace(err)
	}
	for i, arg := range args.Entities {
		mTag, err := names.ParseMachineTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		machine, err := p.getMachine(canAccess, mTag)
		if err == nil {
			// TODO(perrito666) 2016-05-02 lp:1558657
			now := time.Now()
			s := status.StatusInfo{
				Status:  status.Status(arg.Status),
				Message: arg.Info,
				Data:    arg.Data,
				Since:   &now,
			}
			err = machine.SetInstanceStatus(s)
		}
		result.Results[i].Error = common.ServerError(err)
	}
	return result, nil
}
Example #5
0
// SetStatus sets the status of each given entity.
func (s *StatusSetter) SetStatus(args params.SetStatus) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canModify, err := s.getCanModify()
	if err != nil {
		return params.ErrorResults{}, err
	}
	// TODO(perrito666) 2016-05-02 lp:1558657
	now := time.Now()
	for i, arg := range args.Entities {
		tag, err := names.ParseTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}
		err = ErrPerm
		if canModify(tag) {
			err = s.setEntityStatus(tag, status.Status(arg.Status), arg.Info, arg.Data, &now)
		}
		result.Results[i].Error = ServerError(err)
	}
	return result, nil
}
Example #6
0
// makeStatusDoc assumes status is non-nil.
func (i *importer) makeStatusDoc(statusVal description.Status) statusDoc {
	return statusDoc{
		Status:     status.Status(statusVal.Value()),
		StatusInfo: statusVal.Message(),
		StatusData: statusVal.Data(),
		Updated:    statusVal.Updated().UnixNano(),
	}
}
Example #7
0
File: context.go Project: bac/juju
// SetUnitStatus will set the given status for this unit.
func (ctx *HookContext) SetUnitStatus(unitStatus jujuc.StatusInfo) error {
	ctx.hasRunStatusSet = true
	logger.Tracef("[WORKLOAD-STATUS] %s: %s", unitStatus.Status, unitStatus.Info)
	return ctx.unit.SetUnitStatus(
		status.Status(unitStatus.Status),
		unitStatus.Info,
		unitStatus.Data,
	)
}
Example #8
0
func (s *InstancePollerSuite) TestSetInstanceStatusSuccess(c *gc.C) {
	s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: statusInfo("foo")})
	s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: statusInfo("")})

	result, err := s.api.SetInstanceStatus(params.SetStatus{
		Entities: []params.EntityStatusArgs{
			{Tag: "machine-1", Status: ""},
			{Tag: "machine-2", Status: "new status"},
			{Tag: "machine-42", Status: ""},
			{Tag: "application-unknown", Status: ""},
			{Tag: "invalid-tag", Status: ""},
			{Tag: "unit-missing-1", Status: ""},
			{Tag: "", Status: ""},
			{Tag: "42", Status: ""},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result, jc.DeepEquals, s.mixedErrorResults)

	now := s.clock.Now()
	s.st.CheckFindEntityCall(c, 0, "1")
	s.st.CheckCall(c, 1, "SetInstanceStatus", status.StatusInfo{Status: status.Status(""), Since: &now})
	s.st.CheckFindEntityCall(c, 2, "2")
	s.st.CheckCall(c, 3, "SetInstanceStatus", status.StatusInfo{Status: status.Status("new status"), Since: &now})
	s.st.CheckFindEntityCall(c, 4, "42")

	// Ensure machines were updated.
	machine, err := s.st.Machine("1")
	c.Assert(err, jc.ErrorIsNil)
	// TODO (perrito666) there should not be an empty StatusInfo here,
	// this is certainly a smell.
	setStatus, err := machine.InstanceStatus()
	c.Assert(err, jc.ErrorIsNil)
	setStatus.Since = nil
	c.Assert(setStatus, gc.DeepEquals, status.StatusInfo{})

	machine, err = s.st.Machine("2")
	c.Assert(err, jc.ErrorIsNil)
	setStatus, err = machine.InstanceStatus()
	c.Assert(err, jc.ErrorIsNil)
	setStatus.Since = nil
	c.Assert(setStatus, gc.DeepEquals, status.StatusInfo{Status: "new status"})
}
Example #9
0
File: updater.go Project: bac/juju
// pollInstanceInfo checks the current provider addresses and status
// for the given machine's instance, and sets them on the machine if they've changed.
func pollInstanceInfo(context machineContext, m machine) (instInfo instanceInfo, err error) {
	instInfo = instanceInfo{}
	instId, err := m.InstanceId()
	// We can't ask the machine for its addresses if it isn't provisioned yet.
	if params.IsCodeNotProvisioned(err) {
		return instanceInfo{}, err
	}
	if err != nil {
		return instanceInfo{}, errors.Annotate(err, "cannot get machine's instance id")
	}
	instInfo, err = context.instanceInfo(instId)
	if err != nil {
		// TODO (anastasiamac 2016-02-01) This does not look like it needs to be removed now.
		if params.IsCodeNotImplemented(err) {
			return instanceInfo{}, err
		}
		logger.Warningf("cannot get instance info for instance %q: %v", instId, err)
		return instInfo, nil
	}
	if instStat, err := m.InstanceStatus(); err != nil {
		// This should never occur since the machine is provisioned.
		// But just in case, we reset polled status so we try again next time.
		logger.Warningf("cannot get current instance status for machine %v: %v", m.Id(), err)
		instInfo.status = instance.InstanceStatus{status.Unknown, ""}
	} else {
		// TODO(perrito666) add status validation.
		currentInstStatus := instance.InstanceStatus{
			Status:  status.Status(instStat.Status),
			Message: instStat.Info,
		}
		if instInfo.status != currentInstStatus {
			logger.Infof("machine %q instance status changed from %q to %q", m.Id(), currentInstStatus, instInfo.status)
			if err = m.SetInstanceStatus(instInfo.status.Status, instInfo.status.Message, nil); err != nil {
				logger.Errorf("cannot set instance status on %q: %v", m, err)
				return instanceInfo{}, err
			}
		}

	}
	if m.Life() != params.Dead {
		providerAddresses, err := m.ProviderAddresses()
		if err != nil {
			return instanceInfo{}, err
		}
		if !addressesEqual(providerAddresses, instInfo.addresses) {
			logger.Infof("machine %q has new addresses: %v", m.Id(), instInfo.addresses)
			if err := m.SetProviderAddresses(instInfo.addresses...); err != nil {
				logger.Errorf("cannot set addresses on %q: %v", m, err)
				return instanceInfo{}, err
			}
		}
	}
	return instInfo, nil
}
Example #10
0
func (sf *statusFormatter) updateUnitStatusInfo(unit *params.UnitStatus, applicationName string) {
	// TODO(perrito66) add status validation.
	if status.Status(unit.WorkloadStatus.Status) == status.Error {
		if relation, ok := sf.relations[getRelationIdFromData(unit)]; ok {
			// Append the details of the other endpoint on to the status info string.
			if ep, ok := findOtherEndpoint(relation.Endpoints, applicationName); ok {
				unit.WorkloadStatus.Info = unit.WorkloadStatus.Info + " for " + ep.String()
			}
		}
	}
}
Example #11
0
func (s *ServiceStatusSuite) TestSetUnknownStatus(c *gc.C) {
	now := testing.ZeroTime()
	sInfo := status.StatusInfo{
		Status:  status.Status("vliegkat"),
		Message: "orville",
		Since:   &now,
	}
	err := s.service.SetStatus(sInfo)
	c.Check(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`)

	s.checkInitialStatus(c)
}
Example #12
0
func (s *MachineStatusSuite) TestSetUnknownStatus(c *gc.C) {
	now := time.Now()
	sInfo := status.StatusInfo{
		Status:  status.Status("vliegkat"),
		Message: "orville",
		Since:   &now,
	}
	err := s.machine.SetStatus(sInfo)
	c.Assert(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`)

	s.checkInitialStatus(c)
}
Example #13
0
func (sf *statusFormatter) getServiceStatusInfo(service params.ApplicationStatus) statusInfoContents {
	// TODO(perrito66) add status validation.
	info := statusInfoContents{
		Err:     service.Status.Err,
		Current: status.Status(service.Status.Status),
		Message: service.Status.Info,
		Version: service.Status.Version,
	}
	if service.Status.Since != nil {
		info.Since = common.FormatTime(service.Status.Since, sf.isoTime)
	}
	return info
}
Example #14
0
func checkStatusInfo(c *gc.C, obtained []params.DetailedStatus, expected []status.StatusInfo) {
	c.Assert(len(obtained), gc.Equals, len(expected))
	lastTimestamp := int64(0)
	for i, obtainedInfo := range obtained {
		c.Logf("Checking status %q with info %q", obtainedInfo.Status, obtainedInfo.Info)
		thisTimeStamp := obtainedInfo.Since.Unix()
		c.Assert(thisTimeStamp >= lastTimestamp, jc.IsTrue)
		lastTimestamp = thisTimeStamp
		obtainedInfo.Since = nil
		c.Assert(obtainedInfo.Status, gc.Equals, status.Status(expected[i].Status))
		c.Assert(obtainedInfo.Info, gc.Equals, expected[i].Message)
	}
}
Example #15
0
func (sf *statusFormatter) getAgentStatusInfo(unit params.UnitStatus) statusInfoContents {
	// TODO(perrito66) add status validation.
	info := statusInfoContents{
		Err:     unit.AgentStatus.Err,
		Current: status.Status(unit.AgentStatus.Status),
		Message: unit.AgentStatus.Info,
		Version: unit.AgentStatus.Version,
	}
	if unit.AgentStatus.Since != nil {
		info.Since = common.FormatTime(unit.AgentStatus.Since, sf.isoTime)
	}
	return info
}
Example #16
0
func (s *StatusModelSuite) TestUnitAgentStatusDocValidation(c *gc.C) {
	unit := s.Factory.MakeUnit(c, nil)
	for i, test := range []struct {
		status status.Status
		info   string
		err    string
	}{{
		status: status.StatusPending,
		err:    `cannot set invalid status "pending"`,
	}, {
		status: status.StatusDown,
		err:    `cannot set invalid status "down"`,
	}, {
		status: status.StatusStarted,
		err:    `cannot set invalid status "started"`,
	}, {
		status: status.StatusStopped,
		err:    `cannot set invalid status "stopped"`,
	}, {
		status: status.StatusAllocating,
		err:    `cannot set status "allocating"`,
	}, {
		status: status.StatusAllocating,
		info:   "any message",
		err:    `cannot set status "allocating"`,
	}, {
		status: status.StatusLost,
		err:    `cannot set status "lost"`,
	}, {
		status: status.StatusLost,
		info:   "any message",
		err:    `cannot set status "lost"`,
	}, {
		status: status.StatusError,
		err:    `cannot set status "error" without info`,
	}, {
		status: status.StatusError,
		info:   "some error info",
	}, {
		status: status.Status("bogus"),
		err:    `cannot set invalid status "bogus"`,
	}} {
		c.Logf("test %d", i)
		err := unit.SetAgentStatus(test.status, test.info, nil)
		if test.err != "" {
			c.Check(err, gc.ErrorMatches, test.err)
		} else {
			c.Check(err, jc.ErrorIsNil)
		}
	}
}
func (s *InstancePollerSuite) TestSetInstanceStatusSuccess(c *gc.C) {
	s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: statusInfo("foo")})
	s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: statusInfo("")})

	result, err := s.api.SetInstanceStatus(params.SetStatus{
		Entities: []params.EntityStatusArgs{
			{Tag: "machine-1", Status: status.Status("")},
			{Tag: "machine-2", Status: status.Status("new status")},
			{Tag: "machine-42", Status: status.Status("")},
			{Tag: "service-unknown", Status: status.Status("")},
			{Tag: "invalid-tag", Status: status.Status("")},
			{Tag: "unit-missing-1", Status: status.Status("")},
			{Tag: "", Status: status.Status("")},
			{Tag: "42", Status: status.Status("")},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result, jc.DeepEquals, s.mixedErrorResults)

	s.st.CheckFindEntityCall(c, 0, "1")
	s.st.CheckCall(c, 1, "SetInstanceStatus", status.Status(""))
	s.st.CheckFindEntityCall(c, 2, "2")
	s.st.CheckCall(c, 3, "SetInstanceStatus", status.Status("new status"))
	s.st.CheckFindEntityCall(c, 4, "42")

	// Ensure machines were updated.
	machine, err := s.st.Machine("1")
	c.Assert(err, jc.ErrorIsNil)
	setStatus, err := machine.InstanceStatus()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(setStatus, gc.DeepEquals, status.StatusInfo{})

	machine, err = s.st.Machine("2")
	c.Assert(err, jc.ErrorIsNil)
	setStatus, err = machine.InstanceStatus()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(setStatus, gc.DeepEquals, status.StatusInfo{Status: "new status"})
}
Example #18
0
func (sf *statusFormatter) getStatusInfoContents(inst params.DetailedStatus) statusInfoContents {
	// TODO(perrito66) add status validation.
	info := statusInfoContents{
		Err:     inst.Err,
		Current: status.Status(inst.Status),
		Message: inst.Info,
		Version: inst.Version,
		Life:    inst.Life,
	}
	if inst.Since != nil {
		info.Since = common.FormatTime(inst.Since, sf.isoTime)
	}
	return info
}
Example #19
0
func matchAgentStatus(patterns []string, agentStatus status.Status) (bool, bool, error) {
	oneValidStatus := false
	for _, p := range patterns {
		// If the pattern isn't a known status, ignore it.
		ps := status.Status(p)
		if !ps.KnownAgentStatus() {
			continue
		}

		oneValidStatus = true
		if agentStatus.Matches(ps) {
			return true, true, nil
		}
	}
	return false, oneValidStatus, nil
}
Example #20
0
File: client.go Project: bac/juju
// StatusHistory retrieves the last <size> results of
// <kind:combined|agent|workload|machine|machineinstance|container|containerinstance> status
// for <name> unit
func (c *Client) StatusHistory(kind status.HistoryKind, tag names.Tag, filter status.StatusHistoryFilter) (status.History, error) {
	var results params.StatusHistoryResults
	args := params.StatusHistoryRequest{
		Kind: string(kind),
		Filter: params.StatusHistoryFilter{
			Size:  filter.Size,
			Date:  filter.Date,
			Delta: filter.Delta,
		},
		Tag: tag.String(),
	}
	bulkArgs := params.StatusHistoryRequests{Requests: []params.StatusHistoryRequest{args}}
	err := c.facade.FacadeCall("StatusHistory", bulkArgs, &results)
	if err != nil {
		return status.History{}, errors.Trace(err)
	}
	if len(results.Results) != 1 {
		return status.History{}, errors.Errorf("expected 1 result got %d", len(results.Results))
	}
	if results.Results[0].Error != nil {
		return status.History{}, errors.Annotatef(results.Results[0].Error, "while processing the request")
	}
	history := make(status.History, len(results.Results[0].History.Statuses))
	if results.Results[0].History.Error != nil {
		return status.History{}, results.Results[0].History.Error
	}
	for i, h := range results.Results[0].History.Statuses {
		history[i] = status.DetailedStatus{
			Status:  status.Status(h.Status),
			Info:    h.Info,
			Data:    h.Data,
			Since:   h.Since,
			Kind:    status.HistoryKind(h.Kind),
			Version: h.Version,
			// TODO(perrito666) make sure these are still used.
			Life: h.Life,
			Err:  h.Err,
		}
		// TODO(perrito666) https://launchpad.net/bugs/1577589
		if !history[i].Kind.Valid() {
			logger.Errorf("history returned an unknown status kind %q", h.Kind)
		}
	}
	return history, nil
}
Example #21
0
func matchWorkloadStatus(patterns []string, workloadStatus status.Status, agentStatus status.Status) (bool, bool, error) {
	oneValidStatus := false
	for _, p := range patterns {
		// If the pattern isn't a known status, ignore it.
		ps := status.Status(p)
		if !ps.KnownWorkloadStatus() {
			continue
		}

		oneValidStatus = true
		// To preserve current expected behaviour, we only report on workload status
		// if the agent itself is not in error.
		if agentStatus != status.Error && workloadStatus.WorkloadMatches(ps) {
			return true, true, nil
		}
	}
	return false, oneValidStatus, nil
}
Example #22
0
func (inst *dummyInstance) Status() instance.InstanceStatus {
	inst.mu.Lock()
	defer inst.mu.Unlock()
	// TODO(perrito666) add a provider status -> juju status mapping.
	jujuStatus := status.StatusPending
	if inst.status != "" {
		dummyStatus := status.Status(inst.status)
		if dummyStatus.KnownInstanceStatus() {
			jujuStatus = dummyStatus
		}
	}

	return instance.InstanceStatus{
		Status:  jujuStatus,
		Message: inst.status,
	}

}
Example #23
0
File: machine.go Project: bac/juju
// InstanceStatus returns the status of the provider instance.
func (m *Machine) InstanceStatus() (status.Status, string, error) {
	var results params.StatusResults
	args := params.Entities{Entities: []params.Entity{
		{Tag: m.tag.String()},
	}}
	err := m.st.facade.FacadeCall("InstanceStatus", args, &results)
	if err != nil {
		return "", "", err
	}
	if len(results.Results) != 1 {
		return "", "", fmt.Errorf("expected 1 result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		return "", "", result.Error
	}
	// TODO(perrito666) add status validation.
	return status.Status(result.Status), result.Info, nil
}
Example #24
0
func (i *importer) importStatusHistory(globalKey string, history []description.Status) error {
	docs := make([]interface{}, len(history))
	for i, statusVal := range history {
		docs[i] = historicalStatusDoc{
			GlobalKey:  globalKey,
			Status:     status.Status(statusVal.Value()),
			StatusInfo: statusVal.Message(),
			StatusData: statusVal.Data(),
			Updated:    statusVal.Updated().UnixNano(),
		}
	}

	statusHistory, closer := i.st.getCollection(statusesHistoryC)
	defer closer()

	if err := statusHistory.Writeable().Insert(docs...); err != nil {
		return errors.Trace(err)
	}
	return nil
}
Example #25
0
// MachinesWithTransientErrors returns status data for machines with provisioning
// errors which are transient.
func (p *ProvisionerAPI) MachinesWithTransientErrors() (params.StatusResults, error) {
	var results params.StatusResults
	canAccessFunc, err := p.getAuthFunc()
	if err != nil {
		return results, err
	}
	// TODO (wallyworld) - add state.State API for more efficient machines query
	machines, err := p.st.AllMachines()
	if err != nil {
		return results, err
	}
	for _, machine := range machines {
		if !canAccessFunc(machine.Tag()) {
			continue
		}
		if _, provisionedErr := machine.InstanceId(); provisionedErr == nil {
			// Machine may have been provisioned but machiner hasn't set the
			// status to Started yet.
			continue
		}
		var result params.StatusResult
		statusInfo, err := machine.Status()
		if err != nil {
			continue
		}
		result.Status = status.Status(statusInfo.Status)
		result.Info = statusInfo.Message
		result.Data = statusInfo.Data
		if result.Status != status.StatusError {
			continue
		}
		// Transient errors are marked as such in the status data.
		if transient, ok := result.Data["transient"].(bool); !ok || !transient {
			continue
		}
		result.Id = machine.Id()
		result.Life = params.Life(machine.Life().String())
		results.Results = append(results.Results, result)
	}
	return results, nil
}
Example #26
0
File: context.go Project: bac/juju
// SetApplicationStatus will set the given status to the service to which this
// unit's belong, only if this unit is the leader.
func (ctx *HookContext) SetApplicationStatus(serviceStatus jujuc.StatusInfo) error {
	logger.Tracef("[APPLICATION-STATUS] %s: %s", serviceStatus.Status, serviceStatus.Info)
	isLeader, err := ctx.IsLeader()
	if err != nil {
		return errors.Annotatef(err, "cannot determine leadership")
	}
	if !isLeader {
		return ErrIsNotLeader
	}

	service, err := ctx.unit.Application()
	if err != nil {
		return errors.Trace(err)
	}
	return service.SetStatus(
		ctx.unit.Name(),
		status.Status(serviceStatus.Status),
		serviceStatus.Info,
		serviceStatus.Data,
	)
}
func (s *MachineStatusSuite) TestSetUnknownStatus(c *gc.C) {
	err := s.machine.SetStatus(status.Status("vliegkat"), "orville", nil)
	c.Assert(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`)

	s.checkInitialStatus(c)
}
Example #28
0
// SetStatus sets the status on the service given by the unit in args if the unit is the leader.
func (s *ServiceStatusSetter) SetStatus(args params.SetStatus) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}

	canModify, err := s.getCanModify()
	if err != nil {
		return params.ErrorResults{}, err
	}

	for i, arg := range args.Entities {

		// TODO(fwereade): the auth is basically nonsense, and basically only
		// works by coincidence. Read carefully.

		// We "know" that arg.Tag is either the calling unit or its service
		// (because getCanModify is authUnitOrService, and we'll fail out if
		// it isn't); and, in practice, it's always going to be the calling
		// unit (because, /sigh, we don't actually use service tags to refer
		// to services in this method).
		tag, err := names.ParseTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}
		if !canModify(tag) {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		unitTag, ok := tag.(names.UnitTag)
		if !ok {
			// No matter what the canModify says, if this entity is not
			// a unit, we say "NO".
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		unitId := unitTag.Id()

		// Now we have the unit, we can get the service that should have been
		// specified in the first place...
		serviceId, err := names.UnitApplication(unitId)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}
		service, err := s.st.Application(serviceId)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}

		// ...and set the status, conditional on the unit being (and remaining)
		// service leader.
		checker := s.st.LeadershipChecker()
		token := checker.LeadershipCheck(serviceId, unitId)

		// TODO(fwereade) pass token into SetStatus instead of checking here.
		if err := token.Check(nil); err != nil {
			// TODO(fwereade) this should probably be ErrPerm is certain cases,
			// but I don't think I implemented an exported ErrNotLeader. I
			// should have done, though.
			result.Results[i].Error = ServerError(err)
			continue
		}
		// TODO(perrito666) 2016-05-02 lp:1558657
		now := time.Now()
		sInfo := status.StatusInfo{
			Status:  status.Status(arg.Status),
			Message: arg.Info,
			Data:    arg.Data,
			Since:   &now,
		}
		if err := service.SetStatus(sInfo); err != nil {
			result.Results[i].Error = ServerError(err)
		}

	}
	return result, nil
}
Example #29
0
func (f *summaryFormatter) printStateToCount(m map[status.Status]int) {
	for _, stateToCount := range common.SortStringsNaturally(stringKeysFromMap(m)) {
		numInStatus := m[status.Status(stateToCount)]
		f.delimitValuesWithTabs(stateToCount+":", fmt.Sprintf(" %d ", numInStatus))
	}
}
Example #30
0
func (i *importer) machine(m description.Machine) error {
	// Import this machine, then import its containers.
	i.logger.Debugf("importing machine %s", m.Id())

	// 1. construct a machineDoc
	mdoc, err := i.makeMachineDoc(m)
	if err != nil {
		return errors.Annotatef(err, "machine %s", m.Id())
	}
	// 2. construct enough MachineTemplate to pass into 'insertNewMachineOps'
	//    - adds constraints doc
	//    - adds status doc
	//    - adds requested network doc
	//    - adds machine block devices doc

	// TODO: consider filesystems and volumes
	mStatus := m.Status()
	if mStatus == nil {
		return errors.NotValidf("missing status")
	}
	machineStatusDoc := statusDoc{
		ModelUUID:  i.st.ModelUUID(),
		Status:     status.Status(mStatus.Value()),
		StatusInfo: mStatus.Message(),
		StatusData: mStatus.Data(),
		Updated:    mStatus.Updated().UnixNano(),
	}
	// XXX(mjs) - this needs to be included in the serialized model
	// (a card exists for the work). Fake it for now.
	instanceStatusDoc := statusDoc{
		ModelUUID: i.st.ModelUUID(),
		Status:    status.StatusStarted,
	}
	cons := i.constraints(m.Constraints())
	networks := []string{}
	prereqOps, machineOp := i.st.baseNewMachineOps(mdoc, machineStatusDoc,
		instanceStatusDoc, cons, networks)

	// 3. create op for adding in instance data
	if instance := m.Instance(); instance != nil {
		prereqOps = append(prereqOps, i.machineInstanceOp(mdoc, instance))
	}

	if parentId := ParentId(mdoc.Id); parentId != "" {
		prereqOps = append(prereqOps,
			// Update containers record for host machine.
			i.st.addChildToContainerRefOp(parentId, mdoc.Id),
		)
	}
	// insertNewContainerRefOp adds an empty doc into the containerRefsC
	// collection for the machine being added.
	prereqOps = append(prereqOps, i.st.insertNewContainerRefOp(mdoc.Id))

	// 4. gather prereqs and machine op, run ops.
	ops := append(prereqOps, machineOp)

	// 5. add any ops that we may need to add the opened ports information.
	ops = append(ops, i.machinePortsOps(m)...)

	if err := i.st.runTransaction(ops); err != nil {
		return errors.Trace(err)
	}

	machine := newMachine(i.st, mdoc)
	if annotations := m.Annotations(); len(annotations) > 0 {
		if err := i.st.SetAnnotations(machine, annotations); err != nil {
			return errors.Trace(err)
		}
	}
	if err := i.importStatusHistory(machine.globalKey(), m.StatusHistory()); err != nil {
		return errors.Trace(err)
	}

	// Now that this machine exists in the database, process each of the
	// containers in this machine.
	for _, container := range m.Containers() {
		if err := i.machine(container); err != nil {
			return errors.Annotate(err, container.Id())
		}
	}
	return nil
}