// 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 }
// NewUpgraderAPI creates a new server-side UpgraderAPI facade. func NewUpgraderAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*UpgraderAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getCanReadWrite := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } env, err := st.Model() if err != nil { return nil, err } urlGetter := common.NewToolsURLGetter(env.UUID(), st) configGetter := stateenvirons.EnvironConfigGetter{st} return &UpgraderAPI{ ToolsGetter: common.NewToolsGetter(st, configGetter, st, urlGetter, getCanReadWrite), ToolsSetter: common.NewToolsSetter(st, getCanReadWrite), st: st, resources: resources, authorizer: authorizer, }, nil }
// 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) TestToolsURLGetter(c *gc.C) { g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{ hostPorts: [][]network.HostPort{ network.NewHostPorts(1234, "0.1.2.3"), }, }) url, err := g.ToolsURL(current) c.Assert(err, jc.ErrorIsNil) c.Assert(url, gc.Equals, "https://0.1.2.3:1234/model/my-uuid/tools/"+current.String()) }
func (s *toolsSuite) TestToolsURLGetter(c *gc.C) { g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{ hostPorts: [][]network.HostPort{ network.AddressesWithPort( network.NewAddresses("0.1.2.3"), 1234, ), }, }) url, err := g.ToolsURL(version.Current) c.Assert(err, gc.IsNil) c.Assert(url, gc.Equals, "https://0.1.2.3:1234/environment/my-uuid/tools/"+version.Current.String()) }
// 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 }
// 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, ) }
func (s *toolsSuite) TestToolsURLGetterNoAPIHostPorts(c *gc.C) { g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{}) _, err := g.ToolsURL(current) c.Assert(err, gc.ErrorMatches, "no API host ports") }
func (s *toolsSuite) TestToolsURLGetterNoAPIHostPorts(c *gc.C) { g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{}) _, err := g.ToolsURLs(current) c.Assert(err, gc.ErrorMatches, "no suitable API server address to pick from") }
func (s *toolsSuite) TestToolsURLGetterAPIHostPortsError(c *gc.C) { g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{err: errors.New("oh noes")}) _, err := g.ToolsURL(current) c.Assert(err, gc.ErrorMatches, "oh noes") }
// 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 }
// 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 }