Beispiel #1
0
// updateAllMachines finds all machines and resets the stored state address
// in each of them. The address does not include the port.
func updateAllMachines(apiState *api.State, stateAddr string) error {
	client := apiState.Client()
	status, err := client.Status(nil)
	if err != nil {
		return errors.Annotate(err, "cannot get status")
	}
	pendingMachineCount := 0
	done := make(chan error)
	for _, machineStatus := range status.Machines {
		// A newly resumed state server requires no updating, and more
		// than one state server is not yet support by this plugin.
		if machineStatus.HasVote || machineStatus.WantsVote || params.Life(machineStatus.Life) == params.Dead {
			continue
		}
		pendingMachineCount++
		machine := machineStatus
		go func() {
			err := runMachineUpdate(client, machine.Id, setAgentAddressScript(stateAddr))
			if err != nil {
				logger.Errorf("failed to update machine %s: %v", machine.Id, err)
			} else {
				progress("updated machine %s", machine.Id)
			}
			done <- err
		}()
	}
	err = nil
	for ; pendingMachineCount > 0; pendingMachineCount-- {
		if updateErr := <-done; updateErr != nil && err == nil {
			err = errors.Annotate(updateErr, "machine update failed")
		}
	}
	return err
}
Beispiel #2
0
// ModelInfo returns information about the current model.
func (c *Client) ModelInfo() (params.ModelInfo, error) {
	if err := c.checkCanWrite(); err != nil {
		return params.ModelInfo{}, err
	}
	state := c.api.stateAccessor
	conf, err := state.ModelConfig()
	if err != nil {
		return params.ModelInfo{}, err
	}
	model, err := state.Model()
	if err != nil {
		return params.ModelInfo{}, err
	}
	info := params.ModelInfo{
		DefaultSeries: config.PreferredSeries(conf),
		CloudTag:      names.NewCloudTag(model.Cloud()).String(),
		CloudRegion:   model.CloudRegion(),
		ProviderType:  conf.Type(),
		Name:          conf.Name(),
		UUID:          model.UUID(),
		OwnerTag:      model.Owner().String(),
		Life:          params.Life(model.Life().String()),
	}
	if tag, ok := model.CloudCredential(); ok {
		info.CloudCredentialTag = tag.String()
	}
	return info, nil
}
Beispiel #3
0
Datei: life.go Projekt: bac/juju
func (lg *LifeGetter) oneLife(tag names.Tag) (params.Life, error) {
	entity0, err := lg.st.FindEntity(tag)
	if err != nil {
		return "", err
	}
	entity, ok := entity0.(state.Lifer)
	if !ok {
		return "", NotSupportedError(tag, "life cycles")
	}
	return params.Life(entity.Life().String()), nil
}
Beispiel #4
0
func (m *mockClient) EnvironInfo() (params.UndertakerEnvironInfoResult, error) {
	defer m.mockCall("EnvironInfo")
	result := params.UndertakerEnvironInfo{
		Life:        params.Life(m.mockEnviron.Life.String()),
		UUID:        m.mockEnviron.UUID,
		Name:        "dummy",
		GlobalName:  "bob/dummy",
		IsSystem:    m.mockEnviron.IsSystem,
		TimeOfDeath: m.mockEnviron.TimeOfDeath,
	}
	return params.UndertakerEnvironInfoResult{Result: result}, nil
}
Beispiel #5
0
func (*FacadeSuite) TestLifeNotFound(c *gc.C) {
	backend := &mockBackend{}
	facade, err := lifeflag.NewFacade(backend, nil, auth(true))
	c.Assert(err, jc.ErrorIsNil)

	results, err := facade.Life(modelEntity())
	c.Check(err, jc.ErrorIsNil)
	c.Assert(results.Results, gc.HasLen, 1)
	result := results.Results[0]
	c.Check(result.Life, gc.Equals, params.Life(""))
	c.Check(result.Error, jc.Satisfies, params.IsCodeNotFound)
}
Beispiel #6
0
func (*FacadeSuite) TestLifeAuthFailure(c *gc.C) {
	backend := &mockBackend{}
	facade, err := lifeflag.NewFacade(backend, nil, auth(true))
	c.Assert(err, jc.ErrorIsNil)

	results, err := facade.Life(entities("unit-foo-1"))
	c.Check(err, jc.ErrorIsNil)
	c.Assert(results.Results, gc.HasLen, 1)
	result := results.Results[0]
	c.Check(result.Life, gc.Equals, params.Life(""))
	c.Check(result.Error, jc.Satisfies, params.IsCodeUnauthorized)
}
Beispiel #7
0
func (c *ModelStatusAPI) modelStatus(tag string) (params.ModelStatus, error) {
	var status params.ModelStatus
	modelTag, err := names.ParseModelTag(tag)
	if err != nil {
		return status, errors.Trace(err)
	}
	st := c.backend
	if modelTag != c.backend.ModelTag() {
		if st, err = c.backend.ForModel(modelTag); err != nil {
			return status, errors.Trace(err)
		}
		defer st.Close()
	}

	model, err := st.Model()
	if err != nil {
		return status, errors.Trace(err)
	}
	if err := c.modelAuthCheck(modelTag, model.Owner()); err != nil {
		return status, errors.Trace(err)
	}

	machines, err := st.AllMachines()
	if err != nil {
		return status, errors.Trace(err)
	}

	var hostedMachines []Machine
	for _, m := range machines {
		if !m.IsManager() {
			hostedMachines = append(hostedMachines, m)
		}
	}

	applications, err := st.AllApplications()
	if err != nil {
		return status, errors.Trace(err)
	}

	modelMachines, err := ModelMachineInfo(st)
	if err != nil {
		return status, errors.Trace(err)
	}

	return params.ModelStatus{
		ModelTag:           tag,
		OwnerTag:           model.Owner().String(),
		Life:               params.Life(model.Life().String()),
		HostedMachineCount: len(hostedMachines),
		ApplicationCount:   len(applications),
		Machines:           modelMachines,
	}, nil
}
Beispiel #8
0
func (svc *backingService) updated(st *State, store *multiwatcher.Store, id interface{}) error {
	if svc.CharmURL == nil {
		return errors.Errorf("charm url is nil")
	}
	env, err := st.Environment()
	if err != nil {
		return errors.Trace(err)
	}
	info := &params.ServiceInfo{
		Name:     svc.Name,
		Exposed:  svc.Exposed,
		CharmURL: svc.CharmURL.String(),
		OwnerTag: svc.fixOwnerTag(env),
		Life:     params.Life(svc.Life.String()),
		MinUnits: svc.MinUnits,
	}
	oldInfo := store.Get(info.EntityId())
	needConfig := false
	if oldInfo == nil {
		// We're adding the entry for the first time,
		// so fetch the associated child documents.
		c, err := readConstraints(st, serviceGlobalKey(svc.Name))
		if err != nil {
			return err
		}
		info.Constraints = c
		needConfig = true
	} else {
		// The entry already exists, so preserve the current status.
		oldInfo := oldInfo.(*params.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 err
		}
	}
	store.Update(info)
	return nil
}
Beispiel #9
0
func (c *ControllerAPI) modelStatus(tag string) (params.ModelStatus, error) {
	var status params.ModelStatus
	modelTag, err := names.ParseModelTag(tag)
	if err != nil {
		return status, errors.Trace(err)
	}
	st, err := c.state.ForModel(modelTag)
	if err != nil {
		return status, errors.Trace(err)
	}
	defer st.Close()

	machines, err := st.AllMachines()
	if err != nil {
		return status, errors.Trace(err)
	}

	var hostedMachines []*state.Machine
	for _, m := range machines {
		if !m.IsManager() {
			hostedMachines = append(hostedMachines, m)
		}
	}

	applications, err := st.AllApplications()
	if err != nil {
		return status, errors.Trace(err)
	}

	model, err := st.Model()
	if err != nil {
		return status, errors.Trace(err)
	}
	if err != nil {
		return status, errors.Trace(err)
	}

	modelMachines, err := common.ModelMachineInfo(common.NewModelManagerBackend(st))
	if err != nil {
		return status, errors.Trace(err)
	}

	return params.ModelStatus{
		ModelTag:           tag,
		OwnerTag:           model.Owner().String(),
		Life:               params.Life(model.Life().String()),
		HostedMachineCount: len(hostedMachines),
		ApplicationCount:   len(applications),
		Machines:           modelMachines,
	}, nil
}
Beispiel #10
0
func (s *InstancePollerSuite) TestMachineCallsLife(c *gc.C) {
	// We have tested separately the Life method, here we just check
	// it's called internally.
	var called int
	expectedResults := params.LifeResults{
		Results: []params.LifeResult{{Life: "working"}},
	}
	apiCaller := successAPICaller(c, "Life", entitiesArgs, expectedResults, &called)
	api := instancepoller.NewAPI(apiCaller)
	m, err := api.Machine(names.NewMachineTag("42"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(called, gc.Equals, 1)
	c.Assert(m.Life(), gc.Equals, params.Life("working"))
	c.Assert(m.Id(), gc.Equals, "42")
}
Beispiel #11
0
func (*FacadeSuite) TestLifeBadEntity(c *gc.C) {
	backend := &mockBackend{}
	facade, err := lifeflag.NewFacade(backend, nil, auth(true))
	c.Assert(err, jc.ErrorIsNil)

	results, err := facade.Life(entities("archibald snookums"))
	c.Check(err, jc.ErrorIsNil)
	c.Assert(results.Results, gc.HasLen, 1)
	result := results.Results[0]
	c.Check(result.Life, gc.Equals, params.Life(""))

	// TODO(fwereade): this is DUMB. should just be a parse error.
	// but I'm not fixing the underlying implementation as well.
	c.Check(result.Error, jc.Satisfies, params.IsCodeUnauthorized)
}
Beispiel #12
0
func (c *ControllerAPI) environStatus(tag string) (params.EnvironmentStatus, error) {
	var status params.EnvironmentStatus
	envTag, err := names.ParseEnvironTag(tag)
	if err != nil {
		return status, errors.Trace(err)
	}
	st, err := c.state.ForEnviron(envTag)
	if err != nil {
		return status, errors.Trace(err)
	}
	defer st.Close()

	machines, err := st.AllMachines()
	if err != nil {
		return status, errors.Trace(err)
	}

	var hostedMachines []*state.Machine
	for _, m := range machines {
		if !m.IsManager() {
			hostedMachines = append(hostedMachines, m)
		}
	}

	services, err := st.AllServices()
	if err != nil {
		return status, errors.Trace(err)
	}

	env, err := st.Environment()
	if err != nil {
		return status, errors.Trace(err)
	}
	if err != nil {
		return status, errors.Trace(err)
	}

	return params.EnvironmentStatus{
		EnvironTag:         tag,
		OwnerTag:           env.Owner().String(),
		Life:               params.Life(env.Life().String()),
		HostedMachineCount: len(hostedMachines),
		ServiceCount:       len(services),
	}, nil
}
Beispiel #13
0
// ModelInfo returns information on the model needed by the undertaker worker.
func (u *UndertakerAPI) ModelInfo() (params.UndertakerModelInfoResult, error) {
	result := params.UndertakerModelInfoResult{}
	env, err := u.st.Model()

	if err != nil {
		return result, errors.Trace(err)
	}

	result.Result = params.UndertakerModelInfo{
		UUID:       env.UUID(),
		GlobalName: env.Owner().String() + "/" + env.Name(),
		Name:       env.Name(),
		IsSystem:   u.st.IsController(),
		Life:       params.Life(env.Life().String()),
	}

	return result, nil
}
Beispiel #14
0
func (u *UniterAPI) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
	nothing := params.RelationResult{}
	ep, err := rel.Endpoint(unit.ServiceName())
	if err != nil {
		// An error here means the unit's service is not part of the
		// relation.
		return nothing, err
	}
	return params.RelationResult{
		Id:   rel.Id(),
		Key:  rel.String(),
		Life: params.Life(rel.Life().String()),
		Endpoint: params.Endpoint{
			ServiceName: ep.ServiceName,
			Relation:    ep.Relation,
		},
	}, nil
}
Beispiel #15
0
func (u *UniterAPIV3) prepareRelationResult(rel *state.Relation, unit *state.Unit) (params.RelationResult, error) {
	nothing := params.RelationResult{}
	ep, err := rel.Endpoint(unit.ApplicationName())
	if err != nil {
		// An error here means the unit's service is not part of the
		// relation.
		return nothing, err
	}
	return params.RelationResult{
		Id:   rel.Id(),
		Key:  rel.String(),
		Life: params.Life(rel.Life().String()),
		Endpoint: multiwatcher.Endpoint{
			ApplicationName: ep.ApplicationName,
			Relation:        multiwatcher.NewCharmRelation(ep.Relation),
		},
	}, nil
}
Beispiel #16
0
// StorageAttachmentLife returns the lifecycle state of the storage attachments
// with the specified tags.
func (s *StorageAPI) StorageAttachmentLife(args params.StorageAttachmentIds) (params.LifeResults, error) {
	canAccess, err := s.accessUnit()
	if err != nil {
		return params.LifeResults{}, err
	}
	result := params.LifeResults{
		Results: make([]params.LifeResult, len(args.Ids)),
	}
	for i, id := range args.Ids {
		stateStorageAttachment, err := s.getOneStateStorageAttachment(canAccess, id)
		if err == nil {
			life := stateStorageAttachment.Life()
			result.Results[i].Life = params.Life(life.String())
		}
		result.Results[i].Error = common.ServerError(err)
	}
	return result, nil
}
Beispiel #17
0
func (m *backingMachine) updated(st *State, store *multiwatcher.Store, id interface{}) error {
	info := &params.MachineInfo{
		Id:                       m.Id,
		Life:                     params.Life(m.Life.String()),
		Series:                   m.Series,
		Jobs:                     paramsJobsFromJobs(m.Jobs),
		Addresses:                mergedAddresses(m.MachineAddresses, m.Addresses),
		SupportedContainers:      m.SupportedContainers,
		SupportedContainersKnown: m.SupportedContainersKnown,
	}

	oldInfo := store.Get(info.EntityId())
	if oldInfo == nil {
		// We're adding the entry for the first time,
		// so fetch the associated machine status.
		sdoc, err := getStatus(st, machineGlobalKey(m.Id))
		if err != nil {
			return err
		}
		info.Status = sdoc.Status
		info.StatusInfo = sdoc.StatusInfo
	} else {
		// The entry already exists, so preserve the current status and
		// instance data.
		oldInfo := oldInfo.(*params.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
}
Beispiel #18
0
// AttachmentLife returns the lifecycle state of each specified machine
// storage attachment.
func (s *StorageProvisionerAPI) AttachmentLife(args params.MachineStorageIds) (params.LifeResults, error) {
	canAccess, err := s.getAttachmentAuthFunc()
	if err != nil {
		return params.LifeResults{}, err
	}
	results := params.LifeResults{
		Results: make([]params.LifeResult, len(args.Ids)),
	}
	one := func(arg params.MachineStorageId) (params.Life, error) {
		machineTag, err := names.ParseMachineTag(arg.MachineTag)
		if err != nil {
			return "", err
		}
		attachmentTag, err := names.ParseTag(arg.AttachmentTag)
		if err != nil {
			return "", err
		}
		if !canAccess(machineTag, attachmentTag) {
			return "", common.ErrPerm
		}
		var lifer state.Lifer
		switch attachmentTag := attachmentTag.(type) {
		case names.VolumeTag:
			lifer, err = s.st.VolumeAttachment(machineTag, attachmentTag)
		case names.FilesystemTag:
			lifer, err = s.st.FilesystemAttachment(machineTag, attachmentTag)
		}
		if errors.IsNotFound(err) {
			return "", common.ErrPerm
		} else if err != nil {
			return "", errors.Trace(err)
		}
		return params.Life(lifer.Life().String()), nil
	}
	for i, arg := range args.Ids {
		life, err := one(arg)
		if err != nil {
			results.Results[i].Error = common.ServerError(err)
		} else {
			results.Results[i].Life = life
		}
	}
	return results, nil
}
Beispiel #19
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 = statusInfo.Status.String()
		result.Info = statusInfo.Message
		result.Data = statusInfo.Data
		if statusInfo.Status != status.Error {
			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 #20
0
func (s *StorageAPI) fromStateStorageAttachment(stateStorageAttachment state.StorageAttachment) (params.StorageAttachment, error) {
	machineTag, err := s.st.UnitAssignedMachine(stateStorageAttachment.Unit())
	if err != nil {
		return params.StorageAttachment{}, err
	}
	info, err := common.StorageAttachmentInfo(s.st, stateStorageAttachment, machineTag)
	if err != nil {
		return params.StorageAttachment{}, err
	}
	stateStorageInstance, err := s.st.StorageInstance(stateStorageAttachment.StorageInstance())
	if err != nil {
		return params.StorageAttachment{}, err
	}
	return params.StorageAttachment{
		stateStorageAttachment.StorageInstance().String(),
		stateStorageInstance.Owner().String(),
		stateStorageAttachment.Unit().String(),
		params.StorageKind(stateStorageInstance.Kind()),
		info.Location,
		params.Life(stateStorageAttachment.Life().String()),
	}, nil
}
Beispiel #21
0
// ModelInfo returns information on the model needed by the undertaker worker.
func (u *UndertakerAPI) ModelInfo() (params.UndertakerModelInfoResult, error) {
	result := params.UndertakerModelInfoResult{}
	env, err := u.st.Model()

	if err != nil {
		return result, errors.Trace(err)
	}
	tod := env.TimeOfDeath()

	result.Result = params.UndertakerModelInfo{
		UUID:        env.UUID(),
		GlobalName:  env.Owner().String() + "/" + env.Name(),
		Name:        env.Name(),
		IsSystem:    u.st.IsStateServer(),
		Life:        params.Life(env.Life().String()),
		TimeOfDeath: &tod,
	}
	if tod.IsZero() {
		result.Result.TimeOfDeath = nil
	}

	return result, nil
}
Beispiel #22
0
func (api *AgentAPIV2) getEntity(tag names.Tag) (result params.AgentGetEntitiesResult, err error) {
	// Allow only for the owner agent.
	// Note: having a bulk API call for this is utter madness, given that
	// this check means we can only ever return a single object.
	if !api.auth.AuthOwner(tag) {
		err = common.ErrPerm
		return
	}
	entity0, err := api.st.FindEntity(tag)
	if err != nil {
		return
	}
	entity, ok := entity0.(state.Lifer)
	if !ok {
		err = common.NotSupportedError(tag, "life cycles")
		return
	}
	result.Life = params.Life(entity.Life().String())
	if machine, ok := entity.(*state.Machine); ok {
		result.Jobs = stateJobsToAPIParamsJobs(machine.Jobs())
		result.ContainerType = machine.ContainerType()
	}
	return
}
Beispiel #23
0
func (m *ModelManagerAPI) getModelInfo(tag names.ModelTag) (params.ModelInfo, error) {
	st, err := m.state.ForModel(tag)
	if errors.IsNotFound(err) {
		return params.ModelInfo{}, common.ErrPerm
	} else if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}
	defer st.Close()

	model, err := st.Model()
	if errors.IsNotFound(err) {
		return params.ModelInfo{}, common.ErrPerm
	} else if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}

	cfg, err := model.Config()
	if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}
	controllerCfg, err := st.ControllerConfig()
	if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}
	users, err := model.Users()
	if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}
	status, err := model.Status()
	if err != nil {
		return params.ModelInfo{}, errors.Trace(err)
	}

	owner := model.Owner()
	info := params.ModelInfo{
		Name:           cfg.Name(),
		UUID:           cfg.UUID(),
		ControllerUUID: controllerCfg.ControllerUUID(),
		OwnerTag:       owner.String(),
		Life:           params.Life(model.Life().String()),
		Status:         common.EntityStatusFromState(status),
		ProviderType:   cfg.Type(),
		DefaultSeries:  config.PreferredSeries(cfg),
		CloudTag:       names.NewCloudTag(model.Cloud()).String(),
		CloudRegion:    model.CloudRegion(),
	}

	if cloudCredentialTag, ok := model.CloudCredential(); ok {
		info.CloudCredentialTag = cloudCredentialTag.String()
	}

	authorizedOwner := m.authCheck(owner) == nil
	for _, user := range users {
		if !authorizedOwner && m.authCheck(user.UserTag) != nil {
			// The authenticated user is neither the owner
			// nor administrator, nor the model user, so
			// has no business knowing about the model user.
			continue
		}

		userInfo, err := common.ModelUserInfo(user, st)
		if err != nil {
			return params.ModelInfo{}, errors.Trace(err)
		}
		info.Users = append(info.Users, userInfo)
	}

	if len(info.Users) == 0 {
		// No users, which means the authenticated user doesn't
		// have access to the model.
		return params.ModelInfo{}, common.ErrPerm
	}

	canSeeMachines := authorizedOwner
	if !canSeeMachines {
		if canSeeMachines, err = m.hasWriteAccess(tag); err != nil {
			return params.ModelInfo{}, errors.Trace(err)
		}
	}
	if canSeeMachines {
		if info.Machines, err = common.ModelMachineInfo(st); err != nil {
			return params.ModelInfo{}, err
		}
	}
	return info, nil
}
Beispiel #24
0
// ModelInfo returns information about the specified models.
func (m *ModelManagerAPI) ModelInfo(args params.Entities) (params.ModelInfoResults, error) {
	results := params.ModelInfoResults{
		Results: make([]params.ModelInfoResult, len(args.Entities)),
	}

	getModelInfo := func(arg params.Entity) (params.ModelInfo, error) {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			return params.ModelInfo{}, err
		}

		st, err := m.state.ForModel(tag)
		if errors.IsNotFound(err) {
			return params.ModelInfo{}, common.ErrPerm
		} else if err != nil {
			return params.ModelInfo{}, err
		}
		defer st.Close()

		model, err := st.Model()
		if errors.IsNotFound(err) {
			return params.ModelInfo{}, common.ErrPerm
		} else if err != nil {
			return params.ModelInfo{}, err
		}

		cfg, err := model.Config()
		if err != nil {
			return params.ModelInfo{}, err
		}
		users, err := model.Users()
		if err != nil {
			return params.ModelInfo{}, err
		}
		status, err := model.Status()
		if err != nil {
			return params.ModelInfo{}, err
		}

		owner := model.Owner()
		info := params.ModelInfo{
			Name:           cfg.Name(),
			UUID:           cfg.UUID(),
			ControllerUUID: cfg.ControllerUUID(),
			OwnerTag:       owner.String(),
			Life:           params.Life(model.Life().String()),
			Status:         common.EntityStatusFromState(status),
			ProviderType:   cfg.Type(),
			DefaultSeries:  config.PreferredSeries(cfg),
		}

		authorizedOwner := m.authCheck(owner) == nil
		for _, user := range users {
			if !authorizedOwner && m.authCheck(user.UserTag()) != nil {
				// The authenticated user is neither the owner
				// nor administrator, nor the model user, so
				// has no business knowing about the model user.
				continue
			}
			userInfo, err := common.ModelUserInfo(user)
			if err != nil {
				return params.ModelInfo{}, errors.Trace(err)
			}
			info.Users = append(info.Users, userInfo)
		}

		if len(info.Users) == 0 {
			// No users, which means the authenticated user doesn't
			// have access to the model.
			return params.ModelInfo{}, common.ErrPerm
		}

		return info, nil
	}

	for i, arg := range args.Entities {
		modelInfo, err := getModelInfo(arg)
		if err != nil {
			results.Results[i].Error = common.ServerError(err)
			continue
		}
		results.Results[i].Result = &modelInfo
	}
	return results, nil
}
Beispiel #25
0
func (s *subnetShim) Life() params.Life {
	return params.Life(s.subnet.Life().String())
}