// NewModelManagerAPI creates a new api server endpoint for managing // models. func NewModelManagerAPI( st common.ModelManagerBackend, configGetter environs.EnvironConfigGetter, authorizer facade.Authorizer, ) (*ModelManagerAPI, error) { if !authorizer.AuthClient() { return nil, 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) // Pretty much all of the user manager methods have special casing for admin // users, so look once when we start and remember if the user is an admin. isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag()) if err != nil { return nil, errors.Trace(err) } urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st) return &ModelManagerAPI{ ModelStatusAPI: common.NewModelStatusAPI(st, authorizer, apiUser), state: st, check: common.NewBlockChecker(st), authorizer: authorizer, toolsFinder: common.NewToolsFinder(configGetter, st, urlGetter), apiUser: apiUser, isAdmin: isAdmin, }, nil }
func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool, develVersion bool) { var called bool s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { called = true c.Assert(filter.Number, gc.Equals, version.Current) c.Assert(filter.Series, gc.Equals, series.HostSeries()) c.Assert(filter.Arch, gc.Equals, arch.HostArch()) if develVersion { c.Assert(stream, gc.Equals, "devel") } else { c.Assert(stream, gc.Equals, "released") } return nil, errors.NotFoundf("tools") }) toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s")) result, err := toolsFinder.FindTools(params.FindToolsParams{ Number: version.Current, MajorVersion: -1, MinorVersion: -1, Series: series.HostSeries(), Arch: arch.HostArch(), }) c.Assert(err, jc.ErrorIsNil) if inStorage { c.Assert(result.Error, gc.IsNil) c.Assert(called, jc.IsFalse) } else { c.Assert(result.Error, gc.ErrorMatches, "tools not found") c.Assert(called, jc.IsTrue) } }
func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool) { var called bool s.PatchValue(common.EnvtoolsFindTools, func(g environs.ConfigGetter, major, minor int, filter coretools.Filter, allowRetry bool) (list coretools.List, err error) { called = true c.Assert(filter.Number, gc.Equals, version.Current.Number) c.Assert(filter.Series, gc.Equals, version.Current.Series) c.Assert(filter.Arch, gc.Equals, version.Current.Arch) return nil, errors.NotFoundf("tools") }) toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s")) result, err := toolsFinder.FindTools(params.FindToolsParams{ Number: version.Current.Number, MajorVersion: -1, MinorVersion: -1, Series: version.Current.Series, Arch: version.Current.Arch, }) c.Assert(err, gc.IsNil) if inStorage { c.Assert(result.Error, gc.IsNil) c.Assert(called, jc.IsFalse) } else { c.Assert(result.Error, gc.ErrorMatches, "tools not found") c.Assert(called, jc.IsTrue) } }
func (s *toolsSuite) TestFindToolsNotFound(c *gc.C) { s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { return nil, errors.NotFoundf("tools") }) toolsFinder := common.NewToolsFinder(s.State, s.State, sprintfURLGetter("%s")) result, err := toolsFinder.FindTools(params.FindToolsParams{}) c.Assert(err, jc.ErrorIsNil) c.Assert(result.Error, jc.Satisfies, params.IsCodeNotFound) }
// NewProvisionerAPI creates a new server-side ProvisionerAPI facade. func NewProvisionerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ProvisionerAPI, error) { if !authorizer.AuthMachineAgent() && !authorizer.AuthEnvironManager() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { isEnvironManager := authorizer.AuthEnvironManager() isMachineAgent := authorizer.AuthMachineAgent() authEntityTag := authorizer.GetAuthTag() return func(tag names.Tag) bool { if isMachineAgent && tag == authEntityTag { // A machine agent can always access its own machine. return true } switch tag := tag.(type) { case names.MachineTag: parentId := state.ParentId(tag.Id()) if parentId == "" { // All top-level machines are accessible by the // environment manager. return isEnvironManager } // All containers with the authenticated machine as a // parent are accessible by it. // TODO(dfc) sometimes authEntity tag is nil, which is fine because nil is // only equal to nil, but it suggests someone is passing an authorizer // with a nil tag. return isMachineAgent && names.NewMachineTag(parentId) == authEntityTag default: return false } }, nil } env, err := st.Environment() if err != nil { return nil, err } urlGetter := common.NewToolsURLGetter(env.UUID(), st) return &ProvisionerAPI{ Remover: common.NewRemover(st, false, getAuthFunc), StatusSetter: common.NewStatusSetter(st, getAuthFunc), StatusGetter: common.NewStatusGetter(st, getAuthFunc), DeadEnsurer: common.NewDeadEnsurer(st, getAuthFunc), PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), LifeGetter: common.NewLifeGetter(st, getAuthFunc), StateAddresser: common.NewStateAddresser(st), APIAddresser: common.NewAPIAddresser(st, resources), EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), EnvironMachinesWatcher: common.NewEnvironMachinesWatcher(st, resources, authorizer), InstanceIdGetter: common.NewInstanceIdGetter(st, getAuthFunc), ToolsFinder: common.NewToolsFinder(st, st, urlGetter), st: st, resources: resources, authorizer: authorizer, getAuthFunc: getAuthFunc, }, nil }
func (s *toolsSuite) TestFindTools(c *gc.C) { envtoolsList := coretools.List{ &coretools.Tools{ Version: version.MustParseBinary("123.456.0-win81-alpha"), Size: 2048, SHA256: "badf00d", }, &coretools.Tools{ Version: version.MustParseBinary("123.456.1-win81-alpha"), }, } storageMetadata := []binarystorage.Metadata{{ Version: "123.456.0-win81-alpha", Size: 1024, SHA256: "feedface", }} s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (coretools.List, error) { c.Assert(major, gc.Equals, 123) c.Assert(minor, gc.Equals, 456) c.Assert(stream, gc.Equals, "released") c.Assert(filter.Series, gc.Equals, "win81") c.Assert(filter.Arch, gc.Equals, "alpha") return envtoolsList, nil }) toolsFinder := common.NewToolsFinder( stateenvirons.EnvironConfigGetter{s.State}, &mockToolsStorage{metadata: storageMetadata}, sprintfURLGetter("tools:%s"), ) result, err := toolsFinder.FindTools(params.FindToolsParams{ MajorVersion: 123, MinorVersion: 456, Series: "win81", Arch: "alpha", }) c.Assert(err, jc.ErrorIsNil) c.Assert(result.Error, gc.IsNil) c.Check(result.List, jc.DeepEquals, coretools.List{ &coretools.Tools{ Version: version.MustParseBinary(storageMetadata[0].Version), Size: storageMetadata[0].Size, SHA256: storageMetadata[0].SHA256, URL: "tools:" + storageMetadata[0].Version, }, &coretools.Tools{ Version: version.MustParseBinary("123.456.1-win81-alpha"), URL: "tools:123.456.1-win81-alpha", }, }) }
// NewClient creates a new instance of the Client Facade. func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } urlGetter := common.NewToolsURLGetter(st.EnvironUUID(), st) return &Client{ api: &API{ state: st, auth: authorizer, resources: resources, statusSetter: common.NewStatusSetter(st, common.AuthAlways()), toolsFinder: common.NewToolsFinder(st, st, urlGetter), }, check: common.NewBlockChecker(st)}, nil }
// NewEnvironmentManagerAPI creates a new api server endpoint for managing // environments. func NewEnvironmentManagerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*EnvironmentManagerAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } urlGetter := common.NewToolsURLGetter(st.EnvironUUID(), st) return &EnvironmentManagerAPI{ state: getState(st), authorizer: authorizer, toolsFinder: common.NewToolsFinder(st, st, urlGetter), }, nil }
// NewClient creates a new instance of the Client Facade. func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } apiState := getState(st) urlGetter := common.NewToolsURLGetter(apiState.ModelUUID(), apiState) client := &Client{ api: &API{ stateAccessor: apiState, auth: authorizer, resources: resources, statusSetter: common.NewStatusSetter(st, common.AuthAlways()), toolsFinder: common.NewToolsFinder(st, st, urlGetter), }, check: common.NewBlockChecker(st)} return client, nil }
// NewClient creates a new instance of the Client Facade. func NewClient(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*Client, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } env, err := st.Environment() if err != nil { return nil, err } urlGetter := common.NewToolsURLGetter(env.UUID(), st) return &Client{api: &API{ state: st, auth: authorizer, resources: resources, statusSetter: common.NewStatusSetter(st, common.AuthAlways()), toolsFinder: common.NewToolsFinder(st, st, urlGetter), }}, nil }
func (s *toolsSuite) TestFindToolsToolsStorageError(c *gc.C) { var called bool s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { called = true return nil, errors.NotFoundf("tools") }) toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{ err: errors.New("AllMetadata failed"), }, sprintfURLGetter("tools:%s")) result, err := toolsFinder.FindTools(params.FindToolsParams{ MajorVersion: 1, MinorVersion: -1, }) c.Assert(err, jc.ErrorIsNil) // ToolsStorage errors always cause FindTools to bail. Only // if AllMetadata succeeds but returns nothing that matches // do we continue on to searching simplestreams. c.Assert(result.Error, gc.ErrorMatches, "AllMetadata failed") c.Assert(called, jc.IsFalse) }
// NewModelManagerAPI creates a new api server endpoint for managing // models. func NewModelManagerAPI(st Backend, authorizer common.Authorizer) (*ModelManagerAPI, error) { if !authorizer.AuthClient() { return nil, 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) // Pretty much all of the user manager methods have special casing for admin // users, so look once when we start and remember if the user is an admin. isAdmin, err := st.IsControllerAdministrator(apiUser) if err != nil { return nil, errors.Trace(err) } urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st) return &ModelManagerAPI{ state: st, authorizer: authorizer, toolsFinder: common.NewToolsFinder(st, st, urlGetter), apiUser: apiUser, isAdmin: isAdmin, }, nil }
func (s *serverSuite) SetUpTest(c *gc.C) { s.ConfigAttrs = map[string]interface{}{ "authorized-keys": coretesting.FakeAuthKeys, } s.baseSuite.SetUpTest(c) var err error auth := testing.FakeAuthorizer{ Tag: s.AdminUserTag(c), EnvironManager: true, } urlGetter := common.NewToolsURLGetter(s.State.ModelUUID(), s.State) configGetter := stateenvirons.EnvironConfigGetter{s.State} statusSetter := common.NewStatusSetter(s.State, common.AuthAlways()) toolsFinder := common.NewToolsFinder(configGetter, s.State, urlGetter) s.newEnviron = func() (environs.Environ, error) { return environs.GetEnviron(configGetter, environs.New) } newEnviron := func() (environs.Environ, error) { return s.newEnviron() } blockChecker := common.NewBlockChecker(s.State) modelConfigAPI, err := modelconfig.NewModelConfigAPI(s.State, auth) c.Assert(err, jc.ErrorIsNil) s.client, err = client.NewClient( client.NewStateBackend(s.State), modelConfigAPI, common.NewResources(), auth, statusSetter, toolsFinder, newEnviron, blockChecker, ) c.Assert(err, jc.ErrorIsNil) }
func newClient(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*Client, error) { urlGetter := common.NewToolsURLGetter(st.ModelUUID(), st) configGetter := stateenvirons.EnvironConfigGetter{st} statusSetter := common.NewStatusSetter(st, common.AuthAlways()) toolsFinder := common.NewToolsFinder(configGetter, st, urlGetter) newEnviron := func() (environs.Environ, error) { return environs.GetEnviron(configGetter, environs.New) } blockChecker := common.NewBlockChecker(st) modelConfigAPI, err := modelconfig.NewModelConfigAPI(st, authorizer) if err != nil { return nil, errors.Trace(err) } return NewClient( NewStateBackend(st), modelConfigAPI, resources, authorizer, statusSetter, toolsFinder, newEnviron, blockChecker, ) }
// 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, err } // 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, err } hc, err := machine.HardwareCharacteristics() if err != nil { return nil, err } 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, err } 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, err } if findToolsResult.Error != nil { return nil, findToolsResult.Error } tools := findToolsResult.List[0] // Find the API endpoints. env, err := environs.New(environConfig) if err != nil { return nil, err } apiInfo, err := environs.APIInfo(env) if err != nil { return nil, err } auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo) mongoInfo, apiInfo, err := auth.SetupAuthentication(machine) if err != nil { return nil, err } // Find requested networks. networks, err := machine.RequestedNetworks() if err != nil { return nil, err } // Figure out if secure connections are supported. info, err := st.StateServingInfo() if err != nil { return nil, err } secureServerConnection := info.CAPrivateKey != "" icfg, err := instancecfg.NewInstanceConfig(machineId, nonce, env.Config().ImageStream(), machine.Series(), "", secureServerConnection, networks, mongoInfo, apiInfo, ) if err != nil { return nil, err } if dataDir != "" { icfg.DataDir = dataDir } icfg.Tools = tools err = instancecfg.FinishInstanceConfig(icfg, environConfig) if err != nil { return nil, err } return icfg, nil }
// 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 }