// NewMetricsManagerAPI creates a new API endpoint for calling metrics manager functions. func NewMetricsManagerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, clock clock.Clock, ) (*MetricsManagerAPI, error) { if !(authorizer.AuthMachineAgent() && authorizer.AuthModelManager()) { return nil, common.ErrPerm } // Allow access only to the current environment. accessEnviron := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if tag == nil { return false } return tag == st.ModelTag() }, nil } return &MetricsManagerAPI{ state: st, accessEnviron: accessEnviron, clock: clock, }, nil }
// UserAccess returns the access the user has on the model state // and the host controller. func UserAccess(st *state.State, utag names.UserTag) (modelUser, controllerUser permission.UserAccess, err error) { var none permission.UserAccess modelUser, err = st.UserAccess(utag, st.ModelTag()) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } controllerUser, err = state.ControllerAccess(st, utag) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } // TODO(perrito666) remove the following section about everyone group // when groups are implemented, this accounts only for the lack of a local // ControllerUser when logging in from an external user that has not been granted // permissions on the controller but there are permissions for the special // everyone group. if !utag.IsLocal() { controllerUser, err = maybeUseGroupPermission(st.UserAccess, controllerUser, st.ControllerTag(), utag) if err != nil { return none, none, errors.Annotatef(err, "obtaining ControllerUser for everyone group") } } if permission.IsEmptyUserAccess(modelUser) && permission.IsEmptyUserAccess(controllerUser) { return none, none, errors.NotFoundf("model or controller user") } return modelUser, controllerUser, nil }
func transmitVendorMetrics(st *state.State) (bool, error) { cfg, err := st.ModelConfig() if err != nil { return false, errors.Annotatef(err, "failed to get model config for %s", st.ModelTag()) } return cfg.TransmitVendorMetrics(), nil }
func destroyModel(st *state.State, modelTag names.ModelTag, destroyHostedModels bool) error { var err error if modelTag != st.ModelTag() { if st, err = st.ForModel(modelTag); err != nil { return errors.Trace(err) } defer st.Close() } if destroyHostedModels { envs, err := st.AllModels() if err != nil { return errors.Trace(err) } for _, env := range envs { envSt, err := st.ForModel(env.ModelTag()) defer envSt.Close() if err != nil { return errors.Trace(err) } check := NewBlockChecker(envSt) if err = check.DestroyAllowed(); err != nil { return errors.Trace(err) } } } else { check := NewBlockChecker(st) if err = check.DestroyAllowed(); err != nil { return errors.Trace(err) } } env, err := st.Model() if err != nil { return errors.Trace(err) } if destroyHostedModels { if err := env.DestroyIncludingHosted(); err != nil { return err } } else { if err = env.Destroy(); err != nil { return errors.Trace(err) } } err = sendMetrics(st) if err != nil { logger.Warningf("failed to send leftover metrics: %v", err) } // Return to the caller. If it's the CLI, it will finish up by calling the // provider's Destroy method, which will destroy the controllers, any // straggler instances, and other provider-specific resources. Once all // resources are torn down, the Undertaker worker handles the removal of // the environment. return nil }
func assertEnvHasBlock(c *gc.C, st *state.State, t state.BlockType, msg string) { dBlock, found, err := st.GetBlockForType(t) c.Assert(err, jc.ErrorIsNil) c.Assert(found, jc.IsTrue) c.Assert(dBlock, gc.NotNil) c.Assert(dBlock.Type(), gc.DeepEquals, t) tag, err := dBlock.Tag() c.Assert(err, jc.ErrorIsNil) c.Assert(tag, gc.DeepEquals, st.ModelTag()) c.Assert(dBlock.Message(), gc.DeepEquals, msg) }
func (s *blockSuite) assertModelHasBlock(c *gc.C, st *state.State, t state.BlockType, msg string) { block, found, err := st.GetBlockForType(t) c.Assert(err, jc.ErrorIsNil) c.Assert(found, jc.IsTrue) c.Assert(block, gc.NotNil) c.Assert(block.Type(), gc.Equals, t) tag, err := block.Tag() c.Assert(err, jc.ErrorIsNil) c.Assert(tag, gc.Equals, st.ModelTag()) c.Assert(block.Message(), gc.Equals, msg) }
func addModelUsers(c *gc.C, st *state.State) (expected []permission.UserAccess) { // get the model owner testAdmin := names.NewUserTag("test-admin") owner, err := st.UserAccess(testAdmin, st.ModelTag()) c.Assert(err, jc.ErrorIsNil) f := factory.NewFactory(st) return []permission.UserAccess{ // we expect the owner to be an existing model user owner, // add new users to the model f.MakeModelUser(c, nil), f.MakeModelUser(c, nil), f.MakeModelUser(c, nil), } }
// NewControllerAPI creates a new api server endpoint for managing // environments. func NewControllerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*ControllerAPI, error) { if !authorizer.AuthClient() { return nil, errors.Trace(common.ErrPerm) } // Since we know this is a user tag (because AuthClient is true), // we just do the type assertion to the UserTag. apiUser, _ := authorizer.GetAuthTag().(names.UserTag) environConfigGetter := stateenvirons.EnvironConfigGetter{st} return &ControllerAPI{ ControllerConfigAPI: common.NewControllerConfig(st), ModelStatusAPI: common.NewModelStatusAPI(common.NewModelManagerBackend(st), authorizer, apiUser), CloudSpecAPI: cloudspec.NewCloudSpec(environConfigGetter.CloudSpec, common.AuthFuncForTag(st.ModelTag())), state: st, authorizer: authorizer, apiUser: apiUser, resources: resources, }, nil }
// NewFirewallerAPI creates a new server-side FirewallerAPI facade. func NewFirewallerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*FirewallerAPI, error) { if !authorizer.AuthModelManager() { // Firewaller must run as environment manager. return nil, common.ErrPerm } // Set up the various authorization checkers. accessEnviron := common.AuthFuncForTagKind(names.ModelTagKind) accessUnit := common.AuthFuncForTagKind(names.UnitTagKind) accessService := common.AuthFuncForTagKind(names.ApplicationTagKind) accessMachine := common.AuthFuncForTagKind(names.MachineTagKind) accessUnitOrService := common.AuthEither(accessUnit, accessService) accessUnitServiceOrMachine := common.AuthEither(accessUnitOrService, accessMachine) // Life() is supported for units, services or machines. lifeGetter := common.NewLifeGetter( st, accessUnitServiceOrMachine, ) // ModelConfig() and WatchForModelConfigChanges() are allowed // with unrestriced access. modelWatcher := common.NewModelWatcher( st, resources, authorizer, ) // Watch() is supported for applications only. entityWatcher := common.NewAgentEntityWatcher( st, resources, accessService, ) // WatchUnits() is supported for machines. unitsWatcher := common.NewUnitsWatcher(st, resources, accessMachine, ) // WatchModelMachines() is allowed with unrestricted access. machinesWatcher := common.NewModelMachinesWatcher( st, resources, authorizer, ) // InstanceId() is supported for machines. instanceIdGetter := common.NewInstanceIdGetter( st, accessMachine, ) environConfigGetter := stateenvirons.EnvironConfigGetter{st} cloudSpecAPI := cloudspec.NewCloudSpec(environConfigGetter.CloudSpec, common.AuthFuncForTag(st.ModelTag())) return &FirewallerAPI{ LifeGetter: lifeGetter, ModelWatcher: modelWatcher, AgentEntityWatcher: entityWatcher, UnitsWatcher: unitsWatcher, ModelMachinesWatcher: machinesWatcher, InstanceIdGetter: instanceIdGetter, CloudSpecAPI: cloudSpecAPI, st: st, resources: resources, authorizer: authorizer, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, accessEnviron: accessEnviron, }, nil }
func getBackupDBWrapper(st *state.State) *storageDBWrapper { modelUUID := st.ModelTag().Id() db := st.MongoSession().DB(storageDBName) return newStorageDBWrapper(db, storageMetaName, modelUUID) }
// InstanceConfig returns information from the environment config that // is needed for machine cloud-init (for non-controllers only). It // is exposed for testing purposes. // TODO(rog) fix environs/manual tests so they do not need to call this, or move this elsewhere. func InstanceConfig(st *state.State, machineId, nonce, dataDir string) (*instancecfg.InstanceConfig, error) { environConfig, err := st.ModelConfig() if err != nil { return nil, errors.Annotate(err, "getting model config") } // Get the machine so we can get its series and arch. // If the Arch is not set in hardware-characteristics, // an error is returned. machine, err := st.Machine(machineId) if err != nil { return nil, errors.Annotate(err, "getting machine") } hc, err := machine.HardwareCharacteristics() if err != nil { return nil, errors.Annotate(err, "getting machine hardware characteristics") } if hc.Arch == nil { return nil, fmt.Errorf("arch is not set for %q", machine.Tag()) } // Find the appropriate tools information. agentVersion, ok := environConfig.AgentVersion() if !ok { return nil, errors.New("no agent version set in model configuration") } environment, err := st.Model() if err != nil { return nil, errors.Annotate(err, "getting state model") } urlGetter := common.NewToolsURLGetter(environment.UUID(), st) toolsFinder := common.NewToolsFinder(st, st, urlGetter) findToolsResult, err := toolsFinder.FindTools(params.FindToolsParams{ Number: agentVersion, MajorVersion: -1, MinorVersion: -1, Series: machine.Series(), Arch: *hc.Arch, }) if err != nil { return nil, errors.Annotate(err, "finding tools") } if findToolsResult.Error != nil { return nil, errors.Annotate(findToolsResult.Error, "finding tools") } tools := findToolsResult.List[0] // Get the API connection info; attempt all API addresses. apiHostPorts, err := st.APIHostPorts() if err != nil { return nil, errors.Annotate(err, "getting API addresses") } apiAddrs := make(set.Strings) for _, hostPorts := range apiHostPorts { for _, hp := range hostPorts { apiAddrs.Add(hp.NetAddr()) } } apiInfo := &api.Info{ Addrs: apiAddrs.SortedValues(), CACert: st.CACert(), ModelTag: st.ModelTag(), } auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo) mongoInfo, apiInfo, err := auth.SetupAuthentication(machine) if err != nil { return nil, errors.Annotate(err, "setting up machine authentication") } // Find requested networks. networks, err := machine.RequestedNetworks() if err != nil { return nil, errors.Annotate(err, "getting requested networks for machine") } // Figure out if secure connections are supported. info, err := st.StateServingInfo() if err != nil { return nil, errors.Annotate(err, "getting state serving info") } secureServerConnection := info.CAPrivateKey != "" icfg, err := instancecfg.NewInstanceConfig(machineId, nonce, environConfig.ImageStream(), machine.Series(), "", secureServerConnection, networks, mongoInfo, apiInfo, ) if err != nil { return nil, errors.Annotate(err, "initializing instance config") } if dataDir != "" { icfg.DataDir = dataDir } icfg.Tools = tools err = instancecfg.FinishInstanceConfig(icfg, environConfig) if err != nil { return nil, errors.Annotate(err, "finishing instance config") } return icfg, nil }
// NewStorageProvisionerAPI creates a new server-side StorageProvisionerAPI facade. func NewStorageProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*StorageProvisionerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } canAccessStorageMachine := func(tag names.MachineTag, allowEnvironManager bool) bool { authEntityTag := authorizer.GetAuthTag() if tag == authEntityTag { // Machine agents can access volumes // scoped to their own machine. return true } parentId := state.ParentId(tag.Id()) if parentId == "" { return allowEnvironManager && authorizer.AuthModelManager() } // All containers with the authenticated // machine as a parent are accessible by it. return names.NewMachineTag(parentId) == authEntityTag } getScopeAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { switch tag := tag.(type) { case names.ModelTag: // Environment managers can access all volumes // and filesystems scoped to the environment. isModelManager := authorizer.AuthModelManager() return isModelManager && tag == st.ModelTag() case names.MachineTag: return canAccessStorageMachine(tag, false) default: return false } }, nil } canAccessStorageEntity := func(tag names.Tag, allowMachines bool) bool { switch tag := tag.(type) { case names.VolumeTag: machineTag, ok := names.VolumeMachine(tag) if ok { return canAccessStorageMachine(machineTag, false) } return authorizer.AuthModelManager() case names.FilesystemTag: machineTag, ok := names.FilesystemMachine(tag) if ok { return canAccessStorageMachine(machineTag, false) } return authorizer.AuthModelManager() case names.MachineTag: return allowMachines && canAccessStorageMachine(tag, true) default: return false } } getStorageEntityAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { return canAccessStorageEntity(tag, false) }, nil } getLifeAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { return canAccessStorageEntity(tag, true) }, nil } getAttachmentAuthFunc := func() (func(names.MachineTag, names.Tag) bool, error) { // getAttachmentAuthFunc returns a function that validates // access by the authenticated user to an attachment. return func(machineTag names.MachineTag, attachmentTag names.Tag) bool { // Machine agents can access their own machine, and // machines contained. Environment managers can access // top-level machines. if !canAccessStorageMachine(machineTag, true) { return false } // Environment managers can access model-scoped // volumes and volumes scoped to their own machines. // Other machine agents can access volumes regardless // of their scope. if !authorizer.AuthModelManager() { return true } var machineScope names.MachineTag var hasMachineScope bool switch attachmentTag := attachmentTag.(type) { case names.VolumeTag: machineScope, hasMachineScope = names.VolumeMachine(attachmentTag) case names.FilesystemTag: machineScope, hasMachineScope = names.FilesystemMachine(attachmentTag) } return !hasMachineScope || machineScope == authorizer.GetAuthTag() }, nil } getMachineAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if tag, ok := tag.(names.MachineTag); ok { return canAccessStorageMachine(tag, true) } return false }, nil } getBlockDevicesAuthFunc := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if tag, ok := tag.(names.MachineTag); ok { return canAccessStorageMachine(tag, false) } return false }, nil } stateInterface := getState(st) settings := getSettingsManager(st) return &StorageProvisionerAPI{ LifeGetter: common.NewLifeGetter(stateInterface, getLifeAuthFunc), DeadEnsurer: common.NewDeadEnsurer(stateInterface, getStorageEntityAuthFunc), ModelWatcher: common.NewModelWatcher(stateInterface, resources, authorizer), InstanceIdGetter: common.NewInstanceIdGetter(st, getMachineAuthFunc), StatusSetter: common.NewStatusSetter(st, getStorageEntityAuthFunc), st: stateInterface, settings: settings, resources: resources, authorizer: authorizer, getScopeAuthFunc: getScopeAuthFunc, getStorageEntityAuthFunc: getStorageEntityAuthFunc, getAttachmentAuthFunc: getAttachmentAuthFunc, getMachineAuthFunc: getMachineAuthFunc, getBlockDevicesAuthFunc: getBlockDevicesAuthFunc, }, nil }
func (s *modelManagerStateSuite) assertModelAccess(c *gc.C, st *state.State) { result, err := s.modelmanager.ModelInfo(params.Entities{Entities: []params.Entity{{Tag: st.ModelTag().String()}}}) c.Assert(err, jc.ErrorIsNil) c.Assert(result.Results, gc.HasLen, 1) c.Assert(result.Results[0].Error, gc.IsNil) }