Beispiel #1
0
func (s *serviceStatusGetterSuite) TestGetUnitStatusIsLeader(c *gc.C) {
	// If the unit isn't the leader, it can't get it.
	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Status: &state.StatusInfo{
		Status: state.StatusMaintenance,
	}})
	service, err := unit.Service()
	c.Assert(err, jc.ErrorIsNil)
	s.State.LeadershipClaimer().ClaimLeadership(
		service.Name(),
		unit.Name(),
		time.Minute)
	result, err := s.getter.Status(params.Entities{[]params.Entity{{
		unit.Tag().String(),
	}}})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Results, gc.HasLen, 1)
	r := result.Results[0]
	c.Assert(r.Error, gc.IsNil)
	c.Assert(r.Service.Error, gc.IsNil)
	c.Assert(r.Service.Status, gc.Equals, params.Status(state.StatusMaintenance))
	units := r.Units
	c.Assert(units, gc.HasLen, 1)
	status, ok := units[unit.Name()]
	c.Assert(ok, jc.IsTrue)
	c.Assert(status.Error, gc.IsNil)
	c.Assert(status.Status, gc.Equals, params.Status(state.StatusMaintenance))
}
Beispiel #2
0
func serviceStatus(s *ServiceStatusGetter, args params.Entities, getService serviceGetter, isLeaderCheck isLeaderFunc) (params.ServiceStatusResults, error) {
	results := params.ServiceStatusResults{
		Results: make([]params.ServiceStatusResult, len(args.Entities)),
	}
	canAccess, err := s.getcanAccess()
	if err != nil {
		return params.ServiceStatusResults{}, err
	}

	for i, serviceUnit := range args.Entities {
		leader, err := isLeaderCheck(s.st, serviceUnit.Tag)
		if err != nil {
			results.Results[i].Error = ServerError(err)
			continue
		}
		if !leader {
			results.Results[i].Error = ServerError(ErrIsNotLeader)
			continue
		}
		var service StatusService
		service, err = getService(s.st, serviceUnit.Tag)
		if err != nil {
			results.Results[i].Error = ServerError(err)
			continue
		}
		if !canAccess(service.Tag()) {
			results.Results[i].Error = ServerError(ErrPerm)
			continue
		}

		serviceStatus, unitStatuses, err := service.ServiceAndUnitsStatus()
		if err != nil {
			results.Results[i].Service.Error = ServerError(err)
			results.Results[i].Error = ServerError(err)
			continue
		}
		results.Results[i].Service.Status = params.Status(serviceStatus.Status)
		results.Results[i].Service.Info = serviceStatus.Message
		results.Results[i].Service.Data = serviceStatus.Data
		results.Results[i].Service.Since = serviceStatus.Since

		results.Results[i].Units = make(map[string]params.StatusResult, len(unitStatuses))
		for uTag, r := range unitStatuses {
			ur := params.StatusResult{
				Status: params.Status(r.Status),
				Info:   r.Message,
				Data:   r.Data,
				Since:  r.Since,
			}
			results.Results[i].Units[uTag] = ur
		}
	}
	return results, nil
}
Beispiel #3
0
// processUnitAndAgentStatus retrieves status information for both unit and unitAgents.
func processUnitAndAgentStatus(unit *state.Unit, status *params.UnitStatus) {
	status.UnitAgent, status.Workload = processUnitStatus(unit)

	// Legacy fields required until Juju 2.0.
	// We only display pending, started, error, stopped.
	var ok bool
	legacyState, ok := state.TranslateToLegacyAgentState(
		state.Status(status.UnitAgent.Status),
		state.Status(status.Workload.Status),
		status.Workload.Info,
	)
	if !ok {
		logger.Warningf(
			"translate to legacy status encounted unexpected workload status %q and agent status %q",
			status.Workload.Status, status.UnitAgent.Status)
	}
	status.AgentState = params.Status(legacyState)
	if status.AgentState == params.StatusError {
		status.AgentStateInfo = status.Workload.Info
	}
	status.AgentVersion = status.UnitAgent.Version
	status.Life = status.UnitAgent.Life
	status.Err = status.UnitAgent.Err

	processUnitLost(unit, status)

	return
}
Beispiel #4
0
func storageDetailsFromLegacy(legacy params.LegacyStorageDetails) params.StorageDetails {
	nowUTC := time.Now().UTC()
	details := params.StorageDetails{
		legacy.StorageTag,
		legacy.OwnerTag,
		legacy.Kind,
		params.EntityStatus{
			Status: params.Status(legacy.Status),
			Since:  &nowUTC,
		},
		legacy.Persistent,
		nil,
	}
	if legacy.UnitTag != "" {
		details.Attachments = map[string]params.StorageAttachmentDetails{
			legacy.UnitTag: params.StorageAttachmentDetails{
				legacy.StorageTag,
				legacy.UnitTag,
				"", // machine is unknown in legacy
				legacy.Location,
			},
		}
	}
	return details
}
Beispiel #5
0
// makeStatusForEntity creates status information for machines, units.
func makeStatusForEntity(agent *api.AgentStatus, getter state.StatusGetter) {
	statusInfo, err := getter.Status()
	agent.Err = err
	agent.Status = params.Status(statusInfo.Status)
	agent.Info = statusInfo.Message
	agent.Data = filterStatusData(statusInfo.Data)
	agent.Since = statusInfo.Since
}
Beispiel #6
0
// populateStatusFromGetter creates status information for machines, units.
func populateStatusFromGetter(agent *params.AgentStatus, getter state.StatusGetter) {
	statusInfo, err := getter.Status()
	agent.Err = err
	agent.Status = params.Status(statusInfo.Status)
	agent.Info = statusInfo.Message
	agent.Data = filterStatusData(statusInfo.Data)
	agent.Since = statusInfo.Since
}
Beispiel #7
0
// EntityStatusFromState converts a state.StatusInfo into a params.EntityStatus.
func EntityStatusFromState(status state.StatusInfo) params.EntityStatus {
	return params.EntityStatus{
		params.Status(status.Status),
		status.Message,
		status.Data,
		status.Since,
	}
}
Beispiel #8
0
// SetUnitStatus will set the given status for this unit.
func (ctx *HookContext) SetUnitStatus(status jujuc.StatusInfo) error {
	ctx.hasRunStatusSet = true
	logger.Debugf("[WORKLOAD-STATUS] %s: %s", status.Status, status.Info)
	return ctx.unit.SetUnitStatus(
		params.Status(status.Status),
		status.Info,
		status.Data,
	)
}
Beispiel #9
0
func (context *statusContext) processService(service *state.Service) (status params.ServiceStatus) {
	serviceCharmURL, _ := service.CharmURL()
	status.Charm = serviceCharmURL.String()
	status.Exposed = service.IsExposed()
	status.Life = processLife(service)

	latestCharm, ok := context.latestCharms[*serviceCharmURL.WithRevision(-1)]
	if ok && latestCharm != serviceCharmURL.String() {
		status.CanUpgradeTo = latestCharm
	}
	var err error
	status.Relations, status.SubordinateTo, err = context.processServiceRelations(service)
	if err != nil {
		status.Err = err
		return
	}
	networks, err := service.Networks()
	if err != nil {
		status.Err = err
		return
	}
	var cons constraints.Value
	if service.IsPrincipal() {
		// Only principals can have constraints.
		cons, err = service.Constraints()
		if err != nil {
			status.Err = err
			return
		}
	}
	// TODO(dimitern): Drop support for this in a follow-up.
	if len(networks) > 0 || cons.HaveNetworks() {
		// Only the explicitly requested networks (using "juju deploy
		// <svc> --networks=...") will be enabled, and altough when
		// specified, networks constraints will be used for instance
		// selection, they won't be actually enabled.
		status.Networks = params.NetworksSpecification{
			Enabled:  networks,
			Disabled: append(cons.IncludeNetworks(), cons.ExcludeNetworks()...),
		}
	}
	if service.IsPrincipal() {
		status.Units = context.processUnits(context.units[service.Name()], serviceCharmURL.String())
		serviceStatus, err := service.Status()
		if err != nil {
			status.Err = err
			return
		}
		status.Status.Status = params.Status(serviceStatus.Status)
		status.Status.Info = serviceStatus.Message
		status.Status.Data = serviceStatus.Data
		status.Status.Since = serviceStatus.Since

		status.MeterStatuses = context.processUnitMeterStatuses(context.units[service.Name()])
	}
	return status
}
Beispiel #10
0
func (s *statusGetterSuite) TestGetMachineStatus(c *gc.C) {
	machine := s.Factory.MakeMachine(c, nil)
	result, err := s.getter.Status(params.Entities{[]params.Entity{{
		machine.Tag().String(),
	}}})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Results, gc.HasLen, 1)
	status := result.Results[0]
	c.Assert(status.Error, gc.IsNil)
	c.Assert(status.Status, gc.Equals, params.Status(state.StatusPending))
}
Beispiel #11
0
func checkStatusInfo(c *gc.C, obtained []params.AgentStatus, expected []state.StatusInfo) {
	c.Assert(len(obtained), gc.Equals, len(expected))
	lastTimestamp := int64(0)
	for i, obtainedInfo := range obtained {
		thisTimeStamp := obtainedInfo.Since.Unix()
		c.Assert(thisTimeStamp >= lastTimestamp, jc.IsTrue)
		lastTimestamp = thisTimeStamp
		obtainedInfo.Since = nil
		c.Assert(obtainedInfo.Status, gc.Equals, params.Status(expected[i].Status))
		c.Assert(obtainedInfo.Info, gc.Equals, expected[i].Message)
	}
}
Beispiel #12
0
func (s *statusGetterSuite) TestGetServiceStatus(c *gc.C) {
	service := s.Factory.MakeService(c, &factory.ServiceParams{Status: &state.StatusInfo{
		Status: state.StatusMaintenance,
	}})
	result, err := s.getter.Status(params.Entities{[]params.Entity{{
		service.Tag().String(),
	}}})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Results, gc.HasLen, 1)
	status := result.Results[0]
	c.Assert(status.Error, gc.IsNil)
	c.Assert(status.Status, gc.Equals, params.Status(state.StatusMaintenance))
}
Beispiel #13
0
func agentStatusFromStatusInfo(s []state.StatusInfo, kind params.HistoryKind) []params.AgentStatus {
	result := []params.AgentStatus{}
	for _, v := range s {
		result = append(result, params.AgentStatus{
			Status: params.Status(v.Status),
			Info:   v.Message,
			Data:   v.Data,
			Since:  v.Since,
			Kind:   kind,
		})
	}
	return result

}
Beispiel #14
0
func (s *statusGetterSuite) TestGetUnitStatus(c *gc.C) {
	// The status has to be a valid workload status, because get status
	// on the unit returns the workload status not the agent status as it
	// does on a machine.
	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Status: &state.StatusInfo{
		Status: state.StatusMaintenance,
	}})
	result, err := s.getter.Status(params.Entities{[]params.Entity{{
		unit.Tag().String(),
	}}})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Results, gc.HasLen, 1)
	status := result.Results[0]
	c.Assert(status.Error, gc.IsNil)
	c.Assert(status.Status, gc.Equals, params.Status(state.StatusMaintenance))
}
Beispiel #15
0
func (s *statusGetterSuite) TestBulk(c *gc.C) {
	s.badTag = names.NewMachineTag("42")
	machine := s.Factory.MakeMachine(c, nil)
	result, err := s.getter.Status(params.Entities{[]params.Entity{{
		s.badTag.String(),
	}, {
		machine.Tag().String(),
	}, {
		"bad-tag",
	}}})
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(result.Results, gc.HasLen, 3)
	c.Assert(result.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized)
	c.Assert(result.Results[1].Error, gc.IsNil)
	c.Assert(result.Results[1].Status, gc.Equals, params.Status(state.StatusPending))
	c.Assert(result.Results[2].Error, gc.ErrorMatches, `"bad-tag" is not a valid tag`)
}
Beispiel #16
0
func (s *StatusGetter) getEntityStatus(tag names.Tag) params.StatusResult {
	var result params.StatusResult
	entity, err := s.st.FindEntity(tag)
	if err != nil {
		result.Error = ServerError(err)
		return result
	}
	switch getter := entity.(type) {
	case state.StatusGetter:
		statusInfo, err := getter.Status()
		result.Status = params.Status(statusInfo.Status)
		result.Info = statusInfo.Message
		result.Data = statusInfo.Data
		result.Since = statusInfo.Since
		result.Error = ServerError(err)
	default:
		result.Error = ServerError(NotSupportedError(tag, fmt.Sprintf("getting status, %T", getter)))
	}
	return result
}
Beispiel #17
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 = params.Status(statusInfo.Status)
		result.Info = statusInfo.Message
		result.Data = statusInfo.Data
		if result.Status != params.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
}
Beispiel #18
0
// SetServiceStatus will set the given status to the service to which this
// unit's belong, only if this unit is the leader.
func (ctx *HookContext) SetServiceStatus(status jujuc.StatusInfo) error {
	logger.Debugf("[SERVICE-STATUS] %s: %s", status.Status, status.Info)
	isLeader, err := ctx.IsLeader()
	if err != nil {
		return errors.Annotatef(err, "cannot determine leadership")
	}
	if !isLeader {
		return ErrIsNotLeader
	}

	service, err := ctx.unit.Service()
	if err != nil {
		return errors.Trace(err)
	}
	return service.SetStatus(
		ctx.unit.Name(),
		params.Status(status.Status),
		status.Info,
		status.Data,
	)
}
Beispiel #19
0
func (s *UnitSuite) TestGetSetStatusWhileAlive(c *gc.C) {
	err := s.unit.SetStatus(params.StatusError, "", nil)
	c.Assert(err, gc.ErrorMatches, `cannot set status "error" without info`)
	err = s.unit.SetStatus(params.StatusPending, "", nil)
	c.Assert(err, gc.ErrorMatches, `cannot set status "pending"`)
	err = s.unit.SetStatus(params.StatusDown, "", nil)
	c.Assert(err, gc.ErrorMatches, `cannot set status "down"`)
	err = s.unit.SetStatus(params.Status("vliegkat"), "orville", nil)
	c.Assert(err, gc.ErrorMatches, `cannot set invalid status "vliegkat"`)

	status, info, data, err := s.unit.Status()
	c.Assert(err, gc.IsNil)
	c.Assert(status, gc.Equals, params.StatusPending)
	c.Assert(info, gc.Equals, "")
	c.Assert(data, gc.HasLen, 0)

	err = s.unit.SetStatus(params.StatusStarted, "", nil)
	c.Assert(err, gc.IsNil)
	status, info, data, err = s.unit.Status()
	c.Assert(err, gc.IsNil)
	c.Assert(status, gc.Equals, params.StatusStarted)
	c.Assert(info, gc.Equals, "")
	c.Assert(data, gc.HasLen, 0)

	err = s.unit.SetStatus(params.StatusError, "test-hook failed", params.StatusData{
		"foo": "bar",
	})
	c.Assert(err, gc.IsNil)
	status, info, data, err = s.unit.Status()
	c.Assert(err, gc.IsNil)
	c.Assert(status, gc.Equals, params.StatusError)
	c.Assert(info, gc.Equals, "test-hook failed")
	c.Assert(data, gc.DeepEquals, params.StatusData{
		"foo": "bar",
	})
}
Beispiel #20
0
func (f *summaryFormatter) printStateToCount(m map[params.Status]int) {
	for _, status := range common.SortStringsNaturally(stringKeysFromMap(m)) {
		numInStatus := m[params.Status(status)]
		f.delimitValuesWithTabs(status+":", fmt.Sprintf(" %d ", numInStatus))
	}
}
Beispiel #21
0
// Status returns the status of the Service for each given Unit tag.
func (s *ServiceStatusGetter) Status(args params.Entities) (params.ServiceStatusResults, error) {
	result := params.ServiceStatusResults{
		Results: make([]params.ServiceStatusResult, len(args.Entities)),
	}
	canAccess, err := s.getCanAccess()
	if err != nil {
		return params.ServiceStatusResults{}, err
	}

	for i, arg := range args.Entities {
		// TODO(fwereade): the auth is basically nonsense, and basically only
		// works by coincidence (and is happening at the wrong layer anyway).
		// Read carefully.

		// We "know" that arg.Tag is either the calling unit or its service
		// (because getCanAccess 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 !canAccess(tag) {
			result.Results[i].Error = ServerError(ErrPerm)
			continue
		}
		unitTag, ok := tag.(names.UnitTag)
		if !ok {
			// No matter what the canAccess 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.UnitService(unitId)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}
		service, err := s.st.Service(serviceId)
		if err != nil {
			result.Results[i].Error = ServerError(err)
			continue
		}

		// ...so we can check the unit's service leadership...
		checker := s.st.LeadershipChecker()
		token := checker.LeadershipCheck(serviceId, unitId)
		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
		}

		// ...and collect the results.
		serviceStatus, unitStatuses, err := service.ServiceAndUnitsStatus()
		if err != nil {
			result.Results[i].Service.Error = ServerError(err)
			result.Results[i].Error = ServerError(err)
			continue
		}
		result.Results[i].Service.Status = params.Status(serviceStatus.Status)
		result.Results[i].Service.Info = serviceStatus.Message
		result.Results[i].Service.Data = serviceStatus.Data
		result.Results[i].Service.Since = serviceStatus.Since

		result.Results[i].Units = make(map[string]params.StatusResult, len(unitStatuses))
		for uTag, r := range unitStatuses {
			ur := params.StatusResult{
				Status: params.Status(r.Status),
				Info:   r.Message,
				Data:   r.Data,
				Since:  r.Since,
			}
			result.Results[i].Units[uTag] = ur
		}
	}
	return result, nil
}