// NewStatusAPI creates a new server-side Status setter API facade. func NewStatusAPI(st *state.State, getCanModify common.GetAuthFunc) *StatusAPI { unitSetter := common.NewStatusSetter(st, getCanModify) unitGetter := common.NewStatusGetter(st, getCanModify) serviceSetter := common.NewServiceStatusSetter(st, getCanModify) serviceGetter := common.NewServiceStatusGetter(st, getCanModify) agentSetter := common.NewStatusSetter(&unitAgentFinder{st}, getCanModify) return &StatusAPI{ agentSetter: agentSetter, unitSetter: unitSetter, unitGetter: unitGetter, serviceSetter: serviceSetter, serviceGetter: serviceGetter, getCanModify: getCanModify, } }
func newUndertakerAPI(st State, resources facade.Resources, authorizer facade.Authorizer) (*UndertakerAPI, error) { if !authorizer.AuthMachineAgent() || !authorizer.AuthModelManager() { return nil, common.ErrPerm } model, err := st.Model() if err != nil { return nil, errors.Trace(err) } getCanModifyModel := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { if st.IsController() { return true } // Only the agent's model can be modified. modelTag, ok := tag.(names.ModelTag) if !ok { return false } return modelTag.Id() == model.UUID() }, nil } return &UndertakerAPI{ st: st, resources: resources, StatusSetter: common.NewStatusSetter(st, getCanModifyModel), }, nil }
func (s *statusSetterSuite) SetUpTest(c *gc.C) { s.statusBaseSuite.SetUpTest(c) s.setter = common.NewStatusSetter(s.State, func() (common.AuthFunc, error) { return s.authFunc, nil }) }
// NewStatusAPI creates a new server-side Status setter API facade. func NewStatusAPI(st *state.State, getCanModify common.GetAuthFunc) *StatusAPI { // TODO(fwereade): so *all* of these have exactly the same auth // characteristics? I think not. unitSetter := common.NewStatusSetter(st, getCanModify) unitGetter := common.NewStatusGetter(st, getCanModify) serviceSetter := common.NewServiceStatusSetter(st, getCanModify) serviceGetter := common.NewServiceStatusGetter(st, getCanModify) agentSetter := common.NewStatusSetter(&common.UnitAgentFinder{st}, getCanModify) return &StatusAPI{ agentSetter: agentSetter, unitSetter: unitSetter, unitGetter: unitGetter, serviceSetter: serviceSetter, serviceGetter: serviceGetter, getCanModify: getCanModify, } }
// New returns a new unitAssigner api instance. func New(st *state.State, res *common.Resources, _ common.Authorizer) (*API, error) { setter := common.NewStatusSetter(&common.UnitAgentFinder{st}, common.AuthAlways()) return &API{ st: st, res: res, statusSetter: setter, }, 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 (*statusSetterSuite) TestSetStatusNoArgsNoError(c *gc.C) { getCanModify := func() (common.AuthFunc, error) { return nil, fmt.Errorf("pow") } s := common.NewStatusSetter(&fakeState{}, getCanModify) result, err := s.SetStatus(params.SetStatus{}) c.Assert(err, gc.IsNil) c.Assert(result.Results, gc.HasLen, 0) }
func (*statusSetterSuite) TestUpdateStatus(c *gc.C) { st := &fakeState{ entities: map[names.Tag]entityWithError{ m("0"): &fakeStatusSetter{status: params.StatusPending, info: "blah", err: fmt.Errorf("x0 fails")}, m("1"): &fakeStatusSetter{status: params.StatusError, info: "foo", data: map[string]interface{}{"foo": "blah"}}, m("2"): &fakeStatusSetter{status: params.StatusError, info: "some info"}, m("3"): &fakeStatusSetter{fetchError: "x3 error"}, m("4"): &fakeStatusSetter{status: params.StatusStarted}, m("5"): &fakeStatusSetter{status: params.StatusStopped, info: ""}, }, } getCanModify := func() (common.AuthFunc, error) { x0 := m("0") x1 := m("1") x2 := m("2") x3 := m("3") x4 := m("4") return func(tag names.Tag) bool { return tag == x0 || tag == x1 || tag == x2 || tag == x3 || tag == x4 }, nil } s := common.NewStatusSetter(st, getCanModify) args := params.SetStatus{ Entities: []params.EntityStatus{ {Tag: "machine-0", Data: nil}, {Tag: "machine-1", Data: nil}, {Tag: "machine-2", Data: map[string]interface{}{"foo": "bar"}}, {Tag: "machine-3", Data: map[string]interface{}{"foo": "bar"}}, {Tag: "machine-4", Data: map[string]interface{}{"foo": "bar"}}, {Tag: "machine-5", Data: map[string]interface{}{"foo": "bar"}}, {Tag: "machine-6", Data: nil}, }, } result, err := s.UpdateStatus(args) c.Assert(err, gc.IsNil) c.Assert(result, gc.DeepEquals, params.ErrorResults{ Results: []params.ErrorResult{ {¶ms.Error{Message: "x0 fails"}}, {nil}, {nil}, {¶ms.Error{Message: "x3 error"}}, {¶ms.Error{Message: `"machine-4" is not in an error state`}}, {apiservertesting.ErrUnauthorized}, {apiservertesting.ErrUnauthorized}, }, }) get := func(tag names.Tag) *fakeStatusSetter { return st.entities[tag].(*fakeStatusSetter) } c.Assert(get(m("1")).status, gc.Equals, params.StatusError) c.Assert(get(m("1")).info, gc.Equals, "foo") c.Assert(get(m("1")).data, gc.DeepEquals, map[string]interface{}{"foo": "blah"}) c.Assert(get(m("2")).status, gc.Equals, params.StatusError) c.Assert(get(m("2")).info, gc.Equals, "some info") c.Assert(get(m("2")).data, gc.DeepEquals, map[string]interface{}{"foo": "bar"}) }
// 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 } return &Client{api: &API{ state: st, auth: authorizer, resources: resources, statusSetter: common.NewStatusSetter(st, common.AuthAlways()), }}, nil }
func (*statusSetterSuite) TestSetStatusError(c *gc.C) { getCanModify := func() (common.AuthFunc, error) { return nil, fmt.Errorf("pow") } s := common.NewStatusSetter(&fakeState{}, getCanModify) args := params.SetStatus{ Entities: []params.EntityStatus{{"x0", "", "", nil}}, } _, err := s.SetStatus(args) c.Assert(err, gc.ErrorMatches, "pow") }
func (*statusSetterSuite) TestSetStatus(c *gc.C) { st := &fakeState{ entities: map[names.Tag]entityWithError{ u("x/0"): &fakeStatusSetter{status: params.StatusPending, info: "blah", err: fmt.Errorf("x0 fails")}, u("x/1"): &fakeStatusSetter{status: params.StatusStarted, info: "foo"}, u("x/2"): &fakeStatusSetter{status: params.StatusError, info: "some info"}, u("x/3"): &fakeStatusSetter{fetchError: "x3 error"}, u("x/4"): &fakeStatusSetter{status: params.StatusStopped, info: ""}, }, } getCanModify := func() (common.AuthFunc, error) { x0 := u("x/0") x1 := u("x/1") x2 := u("x/2") x3 := u("x/3") return func(tag names.Tag) bool { return tag == x0 || tag == x1 || tag == x2 || tag == x3 }, nil } s := common.NewStatusSetter(st, getCanModify) args := params.SetStatus{ Entities: []params.EntityStatus{ {"unit-x-0", params.StatusStarted, "bar", nil}, {"unit-x-1", params.StatusStopped, "", nil}, {"unit-x-2", params.StatusPending, "not really", nil}, {"unit-x-3", params.StatusStopped, "", nil}, {"unit-x-4", params.StatusError, "blarg", nil}, {"unit-x-5", params.StatusStarted, "42", nil}, }, } result, err := s.SetStatus(args) c.Assert(err, gc.IsNil) c.Assert(result, gc.DeepEquals, params.ErrorResults{ Results: []params.ErrorResult{ {¶ms.Error{Message: "x0 fails"}}, {nil}, {nil}, {¶ms.Error{Message: "x3 error"}}, {apiservertesting.ErrUnauthorized}, {apiservertesting.ErrUnauthorized}, }, }) get := func(tag names.Tag) *fakeStatusSetter { return st.entities[tag].(*fakeStatusSetter) } c.Assert(get(u("x/1")).status, gc.Equals, params.StatusStopped) c.Assert(get(u("x/1")).info, gc.Equals, "") c.Assert(get(u("x/2")).status, gc.Equals, params.StatusPending) c.Assert(get(u("x/2")).info, gc.Equals, "not really") }
// 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 }
// 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 }
// 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 }
// NewDeployerAPI creates a new server-side DeployerAPI facade. func NewDeployerAPI( st *state.State, resources facade.Resources, authorizer facade.Authorizer, ) (*DeployerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { // Get all units of the machine and cache them. thisMachineTag := authorizer.GetAuthTag() units, err := getAllUnits(st, thisMachineTag) if err != nil { return nil, err } // Then we just check if the unit is already known. return func(tag names.Tag) bool { for _, unit := range units { // TODO (thumper): remove the names.Tag conversion when gccgo // implements concrete-type-to-interface comparison correctly. if names.Tag(names.NewUnitTag(unit)) == tag { return true } } return false }, nil } getCanWatch := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } return &DeployerAPI{ Remover: common.NewRemover(st, true, getAuthFunc), PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), LifeGetter: common.NewLifeGetter(st, getAuthFunc), StateAddresser: common.NewStateAddresser(st), APIAddresser: common.NewAPIAddresser(st, resources), UnitsWatcher: common.NewUnitsWatcher(st, resources, getCanWatch), StatusSetter: common.NewStatusSetter(st, getAuthFunc), st: st, resources: resources, authorizer: authorizer, }, nil }
// NewMachinerAPI creates a new instance of the Machiner API. func NewMachinerAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*MachinerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getCanModify := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } getCanRead := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } return &MachinerAPI{ LifeGetter: common.NewLifeGetter(st, getCanRead), StatusSetter: common.NewStatusSetter(st, getCanModify), DeadEnsurer: common.NewDeadEnsurer(st, getCanModify), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, getCanRead), APIAddresser: common.NewAPIAddresser(st, resources), st: st, auth: authorizer, getCanModify: getCanModify, }, nil }
// NewUniterAPI creates a new instance of the Uniter API. func NewUniterAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*UniterAPI, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } accessUnit := func() (common.AuthFunc, error) { return authorizer.AuthOwner, nil } accessService := func() (common.AuthFunc, error) { switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: entity, err := st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } serviceName := entity.ServiceName() serviceTag := names.NewServiceTag(serviceName) return func(tag names.Tag) bool { return tag == serviceTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &UniterAPI{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), StatusSetter: common.NewStatusSetter(st, accessUnit), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, }, nil }
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 *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) }
// 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.AuthEnvironManager() } // 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.EnvironTag: // Environment managers can access all volumes // and filesystems scoped to the environment. isEnvironManager := authorizer.AuthEnvironManager() return isEnvironManager && tag == st.EnvironTag() 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.AuthEnvironManager() case names.FilesystemTag: machineTag, ok := names.FilesystemMachine(tag) if ok { return canAccessStorageMachine(machineTag, false) } return authorizer.AuthEnvironManager() 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 environment-scoped // volumes and volumes scoped to their own machines. // Other machine agents can access volumes regardless // of their scope. if !authorizer.AuthEnvironManager() { 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), EnvironWatcher: common.NewEnvironWatcher(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 }