Example #1
0
// ModifyModelAccess changes the model access granted to users.
func (m *ModelManagerAPI) ModifyModelAccess(args params.ModifyModelAccessRequest) (result params.ErrorResults, err error) {
	result = params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Changes)),
	}
	if len(args.Changes) == 0 {
		return result, nil
	}

	for i, arg := range args.Changes {
		modelAccess, err := FromModelAccessParam(arg.Access)
		if err != nil {
			err = errors.Annotate(err, "could not modify model access")
			result.Results[i].Error = common.ServerError(err)
			continue
		}

		targetUserTag, err := names.ParseUserTag(arg.UserTag)
		if err != nil {
			result.Results[i].Error = common.ServerError(errors.Annotate(err, "could not modify model access"))
			continue
		}
		modelTag, err := names.ParseModelTag(arg.ModelTag)
		if err != nil {
			result.Results[i].Error = common.ServerError(errors.Annotate(err, "could not modify model access"))
			continue
		}

		result.Results[i].Error = common.ServerError(
			ChangeModelAccess(m.state, modelTag, m.apiUser, targetUserTag, arg.Action, modelAccess, m.isAdmin))
	}
	return result, nil
}
Example #2
0
// CleanupOldMetrics removes old metrics from the collection.
// The single arg params is expected to contain and environment uuid.
// Even though the call will delete all metrics across environments
// it serves to validate that the connection has access to at least one environment.
func (api *MetricsManagerAPI) CleanupOldMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		err = api.state.CleanupOldMetrics()
		if err != nil {
			err = errors.Annotate(err, "failed to cleanup old metrics")
			result.Results[i].Error = common.ServerError(err)
		}
	}
	return result, nil
}
Example #3
0
// ModelStatus returns a status summary for each model tag passed in.
func (c *Client) ModelStatus(tags ...names.ModelTag) ([]base.ModelStatus, error) {
	result := params.ModelStatusResults{}
	models := make([]params.Entity, len(tags))
	for i, tag := range tags {
		models[i] = params.Entity{Tag: tag.String()}
	}
	req := params.Entities{
		Entities: models,
	}
	if err := c.facade.FacadeCall("ModelStatus", req, &result); err != nil {
		return nil, err
	}

	results := make([]base.ModelStatus, len(result.Results))
	for i, r := range result.Results {
		model, err := names.ParseModelTag(r.ModelTag)
		if err != nil {
			return nil, errors.Annotatef(err, "ModelTag %q at position %d", r.ModelTag, i)
		}
		owner, err := names.ParseUserTag(r.OwnerTag)
		if err != nil {
			return nil, errors.Annotatef(err, "OwnerTag %q at position %d", r.OwnerTag, i)
		}

		results[i] = base.ModelStatus{
			UUID:               model.Id(),
			Life:               r.Life,
			Owner:              owner.Canonical(),
			HostedMachineCount: r.HostedMachineCount,
			ServiceCount:       r.ServiceCount,
		}

	}
	return results, nil
}
Example #4
0
// SendMetrics will send any unsent metrics onto the metric collection service.
func (api *MetricsManagerAPI) SendMetrics(args params.Entities) (params.ErrorResults, error) {
	result := params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Entities)),
	}
	if len(args.Entities) == 0 {
		return result, nil
	}
	canAccess, err := api.accessEnviron()
	if err != nil {
		return result, err
	}
	for i, arg := range args.Entities {
		tag, err := names.ParseModelTag(arg.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		if !canAccess(tag) {
			result.Results[i].Error = common.ServerError(common.ErrPerm)
			continue
		}
		err = metricsender.SendMetrics(api.state, sender, maxBatchesPerSend)
		if err != nil {
			err = errors.Annotate(err, "failed to send metrics")
			logger.Warningf("%v", err)
			result.Results[i].Error = common.ServerError(err)
			continue
		}
	}
	return result, nil
}
Example #5
0
func (c *ControllerAPI) initiateOneModelMigration(spec params.ModelMigrationSpec) (string, error) {
	modelTag, err := names.ParseModelTag(spec.ModelTag)
	if err != nil {
		return "", errors.Annotate(err, "model tag")
	}

	// Ensure the model exists.
	if _, err := c.state.GetModel(modelTag); err != nil {
		return "", errors.Annotate(err, "unable to read model")
	}

	// Get State for model.
	hostedState, err := c.state.ForModel(modelTag)
	if err != nil {
		return "", errors.Trace(err)
	}
	defer hostedState.Close()

	// Start the migration.
	targetInfo := spec.TargetInfo

	controllerTag, err := names.ParseModelTag(targetInfo.ControllerTag)
	if err != nil {
		return "", errors.Annotate(err, "controller tag")
	}
	authTag, err := names.ParseUserTag(targetInfo.AuthTag)
	if err != nil {
		return "", errors.Annotate(err, "auth tag")
	}

	args := state.ModelMigrationSpec{
		InitiatedBy: c.apiUser,
		TargetInfo: migration.TargetInfo{
			ControllerTag: controllerTag,
			Addrs:         targetInfo.Addrs,
			CACert:        targetInfo.CACert,
			AuthTag:       authTag,
			Password:      targetInfo.Password,
		},
	}
	mig, err := hostedState.CreateModelMigration(args)
	if err != nil {
		return "", errors.Trace(err)
	}
	return mig.Id(), nil
}
Example #6
0
File: facade.go Project: makyo/juju
// auth is very simplistic: it only accepts the model tag reported by
// the backend.
func (facade *Facade) auth(tagString string) error {
	tag, err := names.ParseModelTag(tagString)
	if err != nil {
		return errors.Trace(err)
	}
	if tag.Id() != facade.backend.ModelUUID() {
		return common.ErrPerm
	}
	return nil
}
Example #7
0
File: client.go Project: makyo/juju
// GetMigrationStatus implements Client.
func (c *client) GetMigrationStatus() (MigrationStatus, error) {
	var empty MigrationStatus
	var status params.FullMigrationStatus
	err := c.caller.FacadeCall("GetMigrationStatus", nil, &status)
	if err != nil {
		return empty, errors.Trace(err)
	}

	modelTag, err := names.ParseModelTag(status.Spec.ModelTag)
	if err != nil {
		return empty, errors.Annotatef(err, "parsing model tag")
	}

	phase, ok := migration.ParsePhase(status.Phase)
	if !ok {
		return empty, errors.New("unable to parse phase")
	}

	target := status.Spec.TargetInfo
	controllerTag, err := names.ParseModelTag(target.ControllerTag)
	if err != nil {
		return empty, errors.Annotatef(err, "parsing controller tag")
	}

	authTag, err := names.ParseUserTag(target.AuthTag)
	if err != nil {
		return empty, errors.Annotatef(err, "unable to parse auth tag")
	}

	return MigrationStatus{
		ModelUUID: modelTag.Id(),
		Attempt:   status.Attempt,
		Phase:     phase,
		TargetInfo: migration.TargetInfo{
			ControllerTag: controllerTag,
			Addrs:         target.Addrs,
			CACert:        target.CACert,
			AuthTag:       authTag,
			Password:      target.Password,
		},
	}, nil
}
Example #8
0
func (api *API) getModel(args params.ModelArgs) (*state.Model, error) {
	tag, err := names.ParseModelTag(args.ModelTag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	model, err := api.state.GetModel(tag)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if model.MigrationMode() != state.MigrationModeImporting {
		return nil, errors.New("migration mode for the model is not importing")
	}
	return model, nil
}
Example #9
0
// EnableHASingle applies a single ControllersServersSpec specification to the current environment.
// Exported so it can be called by the legacy client API in the client package.
func EnableHASingle(st *state.State, spec params.ControllersSpec) (params.ControllersChanges, error) {
	if !st.IsController() {
		return params.ControllersChanges{}, errors.New("unsupported with hosted models")
	}
	// Check if changes are allowed and the command may proceed.
	blockChecker := common.NewBlockChecker(st)
	if err := blockChecker.ChangeAllowed(); err != nil {
		return params.ControllersChanges{}, errors.Trace(err)
	}
	// Validate the environment tag if present.
	if spec.ModelTag != "" {
		tag, err := names.ParseModelTag(spec.ModelTag)
		if err != nil {
			return params.ControllersChanges{}, errors.Errorf("invalid model tag: %v", err)
		}
		if _, err := st.FindEntity(tag); err != nil {
			return params.ControllersChanges{}, err
		}
	}

	series := spec.Series
	if series == "" {
		ssi, err := st.ControllerInfo()
		if err != nil {
			return params.ControllersChanges{}, err
		}

		// We should always have at least one voting machine
		// If we *really* wanted we could just pick whatever series is
		// in the majority, but really, if we always copy the value of
		// the first one, then they'll stay in sync.
		if len(ssi.VotingMachineIds) == 0 {
			// Better than a panic()?
			return params.ControllersChanges{}, fmt.Errorf("internal error, failed to find any voting machines")
		}
		templateMachine, err := st.Machine(ssi.VotingMachineIds[0])
		if err != nil {
			return params.ControllersChanges{}, err
		}
		series = templateMachine.Series()
	}
	changes, err := st.EnableHA(spec.NumControllers, spec.Constraints, series, spec.Placement)
	if err != nil {
		return params.ControllersChanges{}, err
	}
	return controllersChanges(changes), nil
}
Example #10
0
func (c *ControllerAPI) environStatus(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)
		}
	}

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

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

	return params.ModelStatus{
		ModelTag:           tag,
		OwnerTag:           env.Owner().String(),
		Life:               params.Life(env.Life().String()),
		HostedMachineCount: len(hostedMachines),
		ServiceCount:       len(services),
	}, nil
}
Example #11
0
// ModifyModelAccess changes the model access granted to users.
func (em *ModelManagerAPI) ModifyModelAccess(args params.ModifyModelAccessRequest) (result params.ErrorResults, err error) {
	// API user must be a controller admin.
	createdBy, _ := em.authorizer.GetAuthTag().(names.UserTag)
	isAdmin, err := em.state.IsControllerAdministrator(createdBy)
	if err != nil {
		return result, errors.Trace(err)
	}
	if !isAdmin {
		return result, errors.New("only controller admins can grant or revoke model access")
	}

	result = params.ErrorResults{
		Results: make([]params.ErrorResult, len(args.Changes)),
	}
	if len(args.Changes) == 0 {
		return result, nil
	}

	for i, arg := range args.Changes {
		modelAccess, err := FromModelAccessParam(arg.Access)
		if err != nil {
			err = errors.Annotate(err, "could not modify model access")
			result.Results[i].Error = common.ServerError(err)
			continue
		}

		userTagString := arg.UserTag
		user, err := names.ParseUserTag(userTagString)
		if err != nil {
			result.Results[i].Error = common.ServerError(errors.Annotate(err, "could not modify model access"))
			continue
		}
		modelTagString := arg.ModelTag
		model, err := names.ParseModelTag(modelTagString)
		if err != nil {
			result.Results[i].Error = common.ServerError(errors.Annotate(err, "could not modify model access"))
			continue
		}

		result.Results[i].Error = common.ServerError(
			ChangeModelAccess(em.state, model, createdBy, user, arg.Action, modelAccess))
	}
	return result, nil
}
Example #12
0
func (w *migrationMasterWatcher) loop() error {
	w.newResult = func() interface{} { return new(params.ModelMigrationTargetInfo) }
	w.call = makeWatcherAPICaller(w.caller, "MigrationMasterWatcher", w.id)
	w.commonWatcher.init()
	go w.commonLoop()

	for {
		var data interface{}
		var ok bool

		select {
		case data, ok = <-w.in:
			if !ok {
				// The tomb is already killed with the correct error
				// at this point, so just return.
				return nil
			}
		case <-w.tomb.Dying():
			return nil
		}

		info := data.(*params.ModelMigrationTargetInfo)
		controllerTag, err := names.ParseModelTag(info.ControllerTag)
		if err != nil {
			return errors.Annotatef(err, "unable to parse %q", info.ControllerTag)
		}
		authTag, err := names.ParseUserTag(info.AuthTag)
		if err != nil {
			return errors.Annotatef(err, "unable to parse %q", info.AuthTag)
		}
		outInfo := migration.TargetInfo{
			ControllerTag: controllerTag,
			Addrs:         info.Addrs,
			CACert:        info.CACert,
			AuthTag:       authTag,
			Password:      info.Password,
		}
		select {
		case w.out <- outInfo:
		case <-w.tomb.Dying():
			return nil
		}
	}
}
Example #13
0
// EnableHASingle applies a single ControllersServersSpec specification to the current environment.
// Exported so it can be called by the legacy client API in the client package.
func EnableHASingle(st *state.State, spec params.ControllersSpec) (params.ControllersChanges, error) {
	if !st.IsController() {
		return params.ControllersChanges{}, errors.New("unsupported with hosted models")
	}
	// Check if changes are allowed and the command may proceed.
	blockChecker := common.NewBlockChecker(st)
	if err := blockChecker.ChangeAllowed(); err != nil {
		return params.ControllersChanges{}, errors.Trace(err)
	}
	// Validate the environment tag if present.
	if spec.ModelTag != "" {
		tag, err := names.ParseModelTag(spec.ModelTag)
		if err != nil {
			return params.ControllersChanges{}, errors.Errorf("invalid model tag: %v", err)
		}
		if _, err := st.FindEntity(tag); err != nil {
			return params.ControllersChanges{}, err
		}
	}

	series := spec.Series
	if series == "" {
		ssi, err := st.ControllerInfo()
		if err != nil {
			return params.ControllersChanges{}, err
		}

		// We should always have at least one voting machine
		// If we *really* wanted we could just pick whatever series is
		// in the majority, but really, if we always copy the value of
		// the first one, then they'll stay in sync.
		if len(ssi.VotingMachineIds) == 0 {
			// Better than a panic()?
			return params.ControllersChanges{}, errors.Errorf("internal error, failed to find any voting machines")
		}
		templateMachine, err := st.Machine(ssi.VotingMachineIds[0])
		if err != nil {
			return params.ControllersChanges{}, err
		}
		series = templateMachine.Series()
	}
	if constraints.IsEmpty(&spec.Constraints) {
		// No constraints specified, so we'll use the constraints off
		// a running controller.
		controllerInfo, err := st.ControllerInfo()
		if err != nil {
			return params.ControllersChanges{}, err
		}
		// We'll sort the controller ids to find the smallest.
		// This will typically give the initial bootstrap machine.
		var controllerIds []int
		for _, id := range controllerInfo.MachineIds {
			idNum, err := strconv.Atoi(id)
			if err != nil {
				logger.Warningf("ignoring non numeric controller id %v", id)
				continue
			}
			controllerIds = append(controllerIds, idNum)
		}
		if len(controllerIds) == 0 {
			errors.Errorf("internal error, failed to find any controllers")
		}
		sort.Ints(controllerIds)

		// Load the controller machine and get its constraints.
		controllerId := controllerIds[0]
		controller, err := st.Machine(strconv.Itoa(controllerId))
		if err != nil {
			return params.ControllersChanges{}, errors.Annotatef(err, "reading controller id %v", controllerId)
		}
		spec.Constraints, err = controller.Constraints()
		if err != nil {
			return params.ControllersChanges{}, errors.Annotatef(err, "reading constraints for controller id %v", controllerId)
		}
	}

	changes, err := st.EnableHA(spec.NumControllers, spec.Constraints, series, spec.Placement)
	if err != nil {
		return params.ControllersChanges{}, err
	}
	return controllersChanges(changes), nil
}
Example #14
0
func (s *fakeHomeSuite) TestModelTagValid(c *gc.C) {
	asString := testing.ModelTag.String()
	tag, err := names.ParseModelTag(asString)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(tag, gc.Equals, testing.ModelTag)
}
Example #15
0
func (formatter_1_18) unmarshal(data []byte) (*configInternal, error) {
	// NOTE: this needs to handle the absence of StatePort and get it from the
	// address
	var format format_1_18Serialization
	if err := goyaml.Unmarshal(data, &format); err != nil {
		return nil, err
	}
	if format.UpgradedToVersion == nil || *format.UpgradedToVersion == version.Zero {
		// Assume we upgrade from 1.16.
		upgradedToVersion := version.MustParse("1.16.0")
		format.UpgradedToVersion = &upgradedToVersion
	}
	tag, err := names.ParseTag(format.Tag)
	if err != nil {
		return nil, err
	}
	var modelTag names.ModelTag
	if format.Model != "" {
		modelTag, err = names.ParseModelTag(format.Model)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	config := &configInternal{
		tag: tag,
		paths: NewPathsWithDefaults(Paths{
			DataDir:         format.DataDir,
			LogDir:          format.LogDir,
			MetricsSpoolDir: format.MetricsSpoolDir,
		}),
		jobs:              format.Jobs,
		upgradedToVersion: *format.UpgradedToVersion,
		nonce:             format.Nonce,
		model:             modelTag,
		caCert:            format.CACert,
		oldPassword:       format.OldPassword,
		values:            format.Values,
		preferIPv6:        format.PreferIPv6,
	}
	if len(format.StateAddresses) > 0 {
		config.stateDetails = &connectionDetails{
			format.StateAddresses,
			format.StatePassword,
		}
	}
	if len(format.APIAddresses) > 0 {
		config.apiDetails = &connectionDetails{
			format.APIAddresses,
			format.APIPassword,
		}
	}
	if len(format.ControllerKey) != 0 {
		config.servingInfo = &params.StateServingInfo{
			Cert:           format.ControllerCert,
			PrivateKey:     format.ControllerKey,
			CAPrivateKey:   format.CAPrivateKey,
			APIPort:        format.APIPort,
			StatePort:      format.StatePort,
			SharedSecret:   format.SharedSecret,
			SystemIdentity: format.SystemIdentity,
		}
		// There's a private key, then we need the state port,
		// which wasn't always in the  1.18 format. If it's not present
		// we can infer it from the ports in the state addresses.
		if config.servingInfo.StatePort == 0 {
			if len(format.StateAddresses) == 0 {
				return nil, fmt.Errorf("server key found but no state port")
			}

			_, portString, err := net.SplitHostPort(format.StateAddresses[0])
			if err != nil {
				return nil, err
			}
			statePort, err := strconv.Atoi(portString)
			if err != nil {
				return nil, err
			}
			config.servingInfo.StatePort = statePort
		}

	}
	// Mongo version is set, we might be running a version other than default.
	if format.MongoVersion != "" {
		config.mongoVersion = format.MongoVersion
	}
	return config, nil
}
Example #16
0
// AddUser adds a user with a username, and either a password or
// a randomly generated secret key which will be returned.
func (api *UserManagerAPI) AddUser(args params.AddUsers) (params.AddUserResults, error) {
	result := params.AddUserResults{
		Results: make([]params.AddUserResult, len(args.Users)),
	}
	if err := api.check.ChangeAllowed(); err != nil {
		return result, errors.Trace(err)
	}

	if len(args.Users) == 0 {
		return result, nil
	}
	loggedInUser, err := api.getLoggedInUser()
	if err != nil {
		return result, errors.Wrap(err, common.ErrPerm)
	}
	// TODO(thumper): PERMISSIONS Change this permission check when we have
	// real permissions. For now, only the owner of the initial model is
	// able to add users.
	if err := api.permissionCheck(loggedInUser); err != nil {
		return result, errors.Trace(err)
	}
	for i, arg := range args.Users {
		var user *state.User
		if arg.Password != "" {
			user, err = api.state.AddUser(arg.Username, arg.DisplayName, arg.Password, loggedInUser.Id())
		} else {
			user, err = api.state.AddUserWithSecretKey(arg.Username, arg.DisplayName, loggedInUser.Id())
		}
		if err != nil {
			err = errors.Annotate(err, "failed to create user")
			result.Results[i].Error = common.ServerError(err)
			continue
		} else {
			result.Results[i] = params.AddUserResult{
				Tag:       user.Tag().String(),
				SecretKey: user.SecretKey(),
			}
		}

		if len(arg.SharedModelTags) > 0 {
			modelAccess, err := modelmanager.FromModelAccessParam(arg.ModelAccess)
			if err != nil {
				err = errors.Annotatef(err, "user %q created but models not shared", arg.Username)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
			userTag := user.Tag().(names.UserTag)
			for _, modelTagStr := range arg.SharedModelTags {
				modelTag, err := names.ParseModelTag(modelTagStr)
				if err != nil {
					err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr)
					result.Results[i].Error = common.ServerError(err)
					break
				}
				err = modelmanager.ChangeModelAccess(api.state, modelTag, loggedInUser, userTag, params.GrantModelAccess, modelAccess)
				if err != nil {
					err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr)
					result.Results[i].Error = common.ServerError(err)
					break
				}
			}
		}
	}
	return result, nil
}
Example #17
0
// ControllerTag returns the tag of the server we are connected to.
func (s *state) ControllerTag() (names.ModelTag, error) {
	return names.ParseModelTag(s.controllerTag)
}
Example #18
0
// ModelTag returns the tag of the model we are connected to.
func (s *state) ModelTag() (names.ModelTag, error) {
	return names.ParseModelTag(s.modelTag)
}
Example #19
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
}
Example #20
0
// AddUser adds a user with a username, and either a password or
// a randomly generated secret key which will be returned.
func (api *UserManagerAPI) AddUser(args params.AddUsers) (params.AddUserResults, error) {
	result := params.AddUserResults{
		Results: make([]params.AddUserResult, len(args.Users)),
	}
	if err := api.check.ChangeAllowed(); err != nil {
		return result, errors.Trace(err)
	}

	if len(args.Users) == 0 {
		return result, nil
	}
	if !api.isAdmin {
		return result, common.ErrPerm
	}

	for i, arg := range args.Users {
		var user *state.User
		var err error
		if arg.Password != "" {
			user, err = api.state.AddUser(arg.Username, arg.DisplayName, arg.Password, api.apiUser.Id())
		} else {
			user, err = api.state.AddUserWithSecretKey(arg.Username, arg.DisplayName, api.apiUser.Id())
		}
		if err != nil {
			err = errors.Annotate(err, "failed to create user")
			result.Results[i].Error = common.ServerError(err)
			continue
		} else {
			result.Results[i] = params.AddUserResult{
				Tag:       user.Tag().String(),
				SecretKey: user.SecretKey(),
			}
		}

		if len(arg.SharedModelTags) > 0 {
			modelAccess, err := modelmanager.FromModelAccessParam(arg.ModelAccess)
			if err != nil {
				err = errors.Annotatef(err, "user %q created but models not shared", arg.Username)
				result.Results[i].Error = common.ServerError(err)
				continue
			}
			userTag := user.Tag().(names.UserTag)
			for _, modelTagStr := range arg.SharedModelTags {
				modelTag, err := names.ParseModelTag(modelTagStr)
				if err != nil {
					err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr)
					result.Results[i].Error = common.ServerError(err)
					break
				}
				err = modelmanager.ChangeModelAccess(
					modelmanager.NewStateBackend(api.state), modelTag, api.apiUser,
					userTag, params.GrantModelAccess, modelAccess, api.isAdmin)
				if err != nil {
					err = errors.Annotatef(err, "user %q created but model %q not shared", arg.Username, modelTagStr)
					result.Results[i].Error = common.ServerError(err)
					break
				}
			}
		}
	}
	return result, nil
}