func NewUserManagerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*UserManagerAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } resource, ok := resources.Get("createLocalLoginMacaroon").(common.ValueResource) if !ok { return nil, errors.NotFoundf("userAuth resource") } createLocalLoginMacaroon, ok := resource.Value.(func(names.UserTag) (*macaroon.Macaroon, error)) if !ok { return nil, errors.NotValidf("userAuth resource") } return &UserManagerAPI{ state: st, authorizer: authorizer, createLocalLoginMacaroon: createLocalLoginMacaroon, check: common.NewBlockChecker(st), }, nil }
// 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 NewUserManagerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*UserManagerAPI, 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) } return &UserManagerAPI{ state: st, authorizer: authorizer, check: common.NewBlockChecker(st), apiUser: apiUser, isAdmin: isAdmin, }, nil }
func (s *blockCheckerSuite) SetUpTest(c *gc.C) { s.FakeJujuHomeSuite.SetUpTest(c) s.destroy = mockBlock{t: state.DestroyBlock, m: "Mock BLOCK testing: DESTROY"} s.remove = mockBlock{t: state.RemoveBlock, m: "Mock BLOCK testing: REMOVE"} s.change = mockBlock{t: state.ChangeBlock, m: "Mock BLOCK testing: CHANGE"} s.blockchecker = common.NewBlockChecker(s) }
// NewModelConfigAPI creates a new instance of the ModelConfig Facade. func NewModelConfigAPI(backend Backend, authorizer facade.Authorizer) (*ModelConfigAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } client := &ModelConfigAPI{ backend: backend, auth: authorizer, check: common.NewBlockChecker(backend), } return client, nil }
// NewActionAPI returns an initialized ActionAPI func NewActionAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ActionAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } return &ActionAPI{ state: st, resources: resources, authorizer: authorizer, check: common.NewBlockChecker(st), }, nil }
// NewImageManagerAPI creates a new server-side imagemanager API end point. func NewImageManagerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*ImageManagerAPI, error) { // Only clients can access the image manager service. if !authorizer.AuthClient() { return nil, common.ErrPerm } return &ImageManagerAPI{ state: getState(st), resources: resources, authorizer: authorizer, check: common.NewBlockChecker(st), }, nil }
func NewUserManagerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*UserManagerAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } return &UserManagerAPI{ state: st, authorizer: authorizer, check: common.NewBlockChecker(st), }, nil }
func newAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*API, error) { backend := NewStateBackend(st) blockChecker := common.NewBlockChecker(st) stateCharm := CharmToStateCharm return NewAPI( backend, authorizer, blockChecker, stateCharm, ) }
func (s *getSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) s.authorizer = apiservertesting.FakeAuthorizer{ Tag: s.AdminUserTag(c), } var err error backend := application.NewStateBackend(s.State) blockChecker := common.NewBlockChecker(s.State) s.serviceAPI, err = application.NewAPI( backend, s.authorizer, blockChecker, application.CharmToStateCharm, ) c.Assert(err, jc.ErrorIsNil) }
// 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 }
// AddToUnit validates and creates additional storage instances for units. // This method handles bulk add operations and // a failure on one individual storage instance does not block remaining // instances from being processed. // A "CHANGE" block can block this operation. func (a *API) AddToUnit(args params.StoragesAddParams) (params.ErrorResults, error) { // Check if changes are allowed and the operation may proceed. blockChecker := common.NewBlockChecker(a.storage) if err := blockChecker.ChangeAllowed(); err != nil { return params.ErrorResults{}, errors.Trace(err) } if len(args.Storages) == 0 { return params.ErrorResults{}, nil } serverErr := func(err error) params.ErrorResult { if errors.IsNotFound(err) { err = common.ErrPerm } return params.ErrorResult{Error: common.ServerError(err)} } paramsToState := func(p params.StorageConstraints) state.StorageConstraints { s := state.StorageConstraints{Pool: p.Pool} if p.Size != nil { s.Size = *p.Size } if p.Count != nil { s.Count = *p.Count } return s } result := make([]params.ErrorResult, len(args.Storages)) for i, one := range args.Storages { u, err := names.ParseUnitTag(one.UnitTag) if err != nil { result[i] = serverErr( errors.Annotatef(err, "parsing unit tag %v", one.UnitTag)) continue } err = a.storage.AddStorageForUnit(u, one.StorageName, paramsToState(one.Constraints)) if err != nil { result[i] = serverErr( errors.Annotatef(err, "adding storage %v for %v", one.StorageName, one.UnitTag)) } } return params.ErrorResults{Results: result}, nil }
// EnsureAvailabilitySingle applies a single StateServersSpec specification to the current environment. // Exported so it can be called by the legacy client API in the client package. func EnsureAvailabilitySingle(st *state.State, spec params.StateServersSpec) (params.StateServersChanges, error) { if !st.IsStateServer() { return params.StateServersChanges{}, errors.New("unsupported with hosted environments") } // Check if changes are allowed and the command may proceed. blockChecker := common.NewBlockChecker(st) if err := blockChecker.ChangeAllowed(); err != nil { return params.StateServersChanges{}, errors.Trace(err) } // Validate the environment tag if present. if spec.EnvironTag != "" { tag, err := names.ParseEnvironTag(spec.EnvironTag) if err != nil { return params.StateServersChanges{}, errors.Errorf("invalid environment tag: %v", err) } if _, err := st.FindEntity(tag); err != nil { return params.StateServersChanges{}, err } } series := spec.Series if series == "" { ssi, err := st.StateServerInfo() if err != nil { return params.StateServersChanges{}, 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.StateServersChanges{}, fmt.Errorf("internal error, failed to find any voting machines") } templateMachine, err := st.Machine(ssi.VotingMachineIds[0]) if err != nil { return params.StateServersChanges{}, err } series = templateMachine.Series() } changes, err := st.EnsureAvailability(spec.NumStateServers, spec.Constraints, series, spec.Placement) if err != nil { return params.StateServersChanges{}, err } return stateServersChanges(changes), nil }
// NewMachineManagerAPI creates a new server-side MachineManager API facade. func NewMachineManagerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*MachineManagerAPI, error) { if !authorizer.AuthClient() { return nil, common.ErrPerm } s := getState(st) return &MachineManagerAPI{ st: s, authorizer: authorizer, check: common.NewBlockChecker(s), }, 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 }
// handleUpload uploads the tools data from the reader to env storage as the specified version. func (h *toolsUploadHandler) handleUpload(r io.Reader, toolsVersions []version.Binary, serverRoot string, st *state.State) (*tools.Tools, error) { // Check if changes are allowed and the command may proceed. blockChecker := common.NewBlockChecker(st) if err := blockChecker.ChangeAllowed(); err != nil { return nil, errors.Trace(err) } storage, err := st.ToolsStorage() if err != nil { return nil, err } defer storage.Close() // Read the tools tarball from the request, calculating the sha256 along the way. data, sha256, err := readAndHash(r) if err != nil { return nil, err } if len(data) == 0 { return nil, errors.BadRequestf("no tools uploaded") } // TODO(wallyworld): check integrity of tools tarball. // Store tools and metadata in tools storage. for _, v := range toolsVersions { metadata := binarystorage.Metadata{ Version: v.String(), Size: int64(len(data)), SHA256: sha256, } logger.Debugf("uploading tools %+v to storage", metadata) if err := storage.Add(bytes.NewReader(data), metadata); err != nil { return nil, err } } tools := &tools.Tools{ Version: toolsVersions[0], Size: int64(len(data)), SHA256: sha256, URL: common.ToolsURL(serverRoot, toolsVersions[0]), } return tools, nil }
// NewKeyManagerAPI creates a new server-side keyupdater API end point. func NewKeyManagerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*KeyManagerAPI, error) { // Only clients and environment managers can access the key manager service. if !authorizer.AuthClient() && !authorizer.AuthEnvironManager() { return nil, common.ErrPerm } env, err := st.Environment() if err != nil { return nil, errors.Trace(err) } // For gccgo interface comparisons, we need a Tag. owner := names.Tag(env.Owner()) // TODO(wallyworld) - replace stub with real canRead function // For now, only admins can read authorised ssh keys. canRead := func(user string) bool { // Are we a machine agent operating as the system identity? if user == config.JujuSystemKey { _, ismachinetag := authorizer.GetAuthTag().(names.MachineTag) return ismachinetag } return authorizer.GetAuthTag() == owner } // TODO(wallyworld) - replace stub with real canWrite function // For now, only admins can write authorised ssh keys for users. // Machine agents can write the juju-system-key. canWrite := func(user string) bool { // Are we a machine agent writing the Juju system key. if user == config.JujuSystemKey { _, ismachinetag := authorizer.GetAuthTag().(names.MachineTag) return ismachinetag } // No point looking to see if the user exists as we are not // yet storing keys on the user. return authorizer.GetAuthTag() == owner } return &KeyManagerAPI{ state: st, resources: resources, authorizer: authorizer, canRead: canRead, canWrite: canWrite, check: common.NewBlockChecker(st), }, nil }
func NewUserManagerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*UserManagerAPI, 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) } resource, ok := resources.Get("createLocalLoginMacaroon").(common.ValueResource) if !ok { return nil, errors.NotFoundf("userAuth resource") } createLocalLoginMacaroon, ok := resource.Value.(func(names.UserTag) (*macaroon.Macaroon, error)) if !ok { return nil, errors.NotValidf("userAuth resource") } return &UserManagerAPI{ state: st, authorizer: authorizer, createLocalLoginMacaroon: createLocalLoginMacaroon, check: common.NewBlockChecker(st), 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, ) }
// 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 }