func (*agentEntityWatcherSuite) TestWatch(c *gc.C) { st := &fakeState{ entities: map[names.Tag]entityWithError{ u("x/0"): &fakeAgentEntityWatcher{fetchError: "x0 fails"}, u("x/1"): &fakeAgentEntityWatcher{}, u("x/2"): &fakeAgentEntityWatcher{}, }, } getCanWatch := func() (common.AuthFunc, error) { x0 := u("x/0") x1 := u("x/1") return func(tag names.Tag) bool { return tag == x0 || tag == x1 }, nil } resources := common.NewResources() a := common.NewAgentEntityWatcher(st, resources, getCanWatch) entities := params.Entities{[]params.Entity{ {"unit-x-0"}, {"unit-x-1"}, {"unit-x-2"}, {"unit-x-3"}, }} result, err := a.Watch(entities) c.Assert(err, jc.ErrorIsNil) c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ Results: []params.NotifyWatchResult{ {Error: ¶ms.Error{Message: "x0 fails"}}, {"1", nil}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, }, }) }
func (*agentEntityWatcherSuite) TestWatchError(c *gc.C) { getCanWatch := func() (common.AuthFunc, error) { return nil, fmt.Errorf("pow") } resources := common.NewResources() a := common.NewAgentEntityWatcher( &fakeState{}, resources, getCanWatch, ) _, err := a.Watch(params.Entities{[]params.Entity{{"x0"}}}) c.Assert(err, gc.ErrorMatches, "pow") }
func (*agentEntityWatcherSuite) TestWatchNoArgsNoError(c *gc.C) { getCanWatch := func() (common.AuthFunc, error) { return nil, fmt.Errorf("pow") } resources := common.NewResources() a := common.NewAgentEntityWatcher( &fakeState{}, resources, getCanWatch, ) result, err := a.Watch(params.Entities{}) c.Assert(err, jc.ErrorIsNil) c.Assert(result.Results, gc.HasLen, 0) }
func NewFacade(backend Backend, resources *common.Resources, authorizer common.Authorizer) (*Facade, error) { if !authorizer.AuthModelManager() { return nil, common.ErrPerm } expect := names.NewModelTag(backend.ModelUUID()) getCanAccess := func() (common.AuthFunc, error) { return func(tag names.Tag) bool { return tag == expect }, nil } life := common.NewLifeGetter(backend, getCanAccess) watch := common.NewAgentEntityWatcher(backend, resources, getCanAccess) return &Facade{ LifeGetter: life, AgentEntityWatcher: watch, }, 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 }
// NewUniterAPIV4 creates a new instance of the Uniter API, version 3. func NewUniterAPIV4(st *state.State, resources facade.Resources, authorizer facade.Authorizer) (*UniterAPIV3, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } var unit *state.Unit var err error switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: unit, err = st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } 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) } applicationName := entity.ApplicationName() applicationTag := names.NewApplicationTag(applicationName) return func(tag names.Tag) bool { return tag == applicationTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } accessMachine := 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) } machineId, err := entity.AssignedMachineId() if err != nil { return nil, errors.Trace(err) } machineTag := names.NewMachineTag(machineId) return func(tag names.Tag) bool { return tag == machineTag }, nil default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } } storageAPI, err := newStorageAPI(getStorageState(st), resources, accessUnit) if err != nil { return nil, err } msAPI, err := meterstatus.NewMeterStatusAPI(st, resources, authorizer) if err != nil { return nil, errors.Annotate(err, "could not create meter status API handler") } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &UniterAPIV3{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), ModelWatcher: common.NewModelWatcher(st, resources, authorizer), RebootRequester: common.NewRebootRequester(st, accessMachine), LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), MeterStatus: msAPI, // TODO(fwereade): so *every* unit should be allowed to get/set its // own status *and* its service's? This is not a pleasing arrangement. StatusAPI: NewStatusAPI(st, accessUnitOrService), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, unit: unit, StorageAPI: *storageAPI, }, 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 }
// newUniterBaseAPI creates a new instance of the uniter base API. func newUniterBaseAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*uniterBaseAPI, error) { if !authorizer.AuthUnitAgent() { return nil, common.ErrPerm } var unit *state.Unit var err error switch tag := authorizer.GetAuthTag().(type) { case names.UnitTag: unit, err = st.Unit(tag.Id()) if err != nil { return nil, errors.Trace(err) } default: return nil, errors.Errorf("expected names.UnitTag, got %T", tag) } 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) } } accessMachine := func() (common.AuthFunc, error) { machineId, err := unit.AssignedMachineId() if err != nil { return nil, errors.Trace(err) } machine, err := st.Machine(machineId) if err != nil { return nil, errors.Trace(err) } return func(tag names.Tag) bool { return tag == machine.Tag() }, nil } accessUnitOrService := common.AuthEither(accessUnit, accessService) return &uniterBaseAPI{ LifeGetter: common.NewLifeGetter(st, accessUnitOrService), DeadEnsurer: common.NewDeadEnsurer(st, accessUnit), AgentEntityWatcher: common.NewAgentEntityWatcher(st, resources, accessUnitOrService), APIAddresser: common.NewAPIAddresser(st, resources), EnvironWatcher: common.NewEnvironWatcher(st, resources, authorizer), RebootRequester: common.NewRebootRequester(st, accessMachine), LeadershipSettingsAccessor: leadershipSettingsAccessorFactory(st, resources, authorizer), // TODO(fwereade): so *every* unit should be allowed to get/set its // own status *and* its service's? This is not a pleasing arrangement. StatusAPI: NewStatusAPI(st, accessUnitOrService), st: st, auth: authorizer, resources: resources, accessUnit: accessUnit, accessService: accessService, unit: unit, }, nil }
// NewFirewallerAPI creates a new server-side FirewallerAPI facade. func NewFirewallerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*FirewallerAPI, error) { if !authorizer.AuthEnvironManager() { // Firewaller must run as environment manager. return nil, common.ErrPerm } // Set up the various authorization checkers. accessEnviron := common.AuthFuncForTagKind(names.EnvironTagKind) accessUnit := common.AuthFuncForTagKind(names.UnitTagKind) accessService := common.AuthFuncForTagKind(names.ServiceTagKind) 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, ) // EnvironConfig() and WatchForEnvironConfigChanges() are allowed // with unrestriced access. environWatcher := common.NewEnvironWatcher( st, resources, authorizer, ) // Watch() is supported for services only. entityWatcher := common.NewAgentEntityWatcher( st, resources, accessService, ) // WatchUnits() is supported for machines. unitsWatcher := common.NewUnitsWatcher(st, resources, accessMachine, ) // WatchEnvironMachines() is allowed with unrestricted access. machinesWatcher := common.NewEnvironMachinesWatcher( st, resources, authorizer, ) // InstanceId() is supported for machines. instanceIdGetter := common.NewInstanceIdGetter( st, accessMachine, ) return &FirewallerAPI{ LifeGetter: lifeGetter, EnvironWatcher: environWatcher, AgentEntityWatcher: entityWatcher, UnitsWatcher: unitsWatcher, EnvironMachinesWatcher: machinesWatcher, InstanceIdGetter: instanceIdGetter, st: st, resources: resources, authorizer: authorizer, accessUnit: accessUnit, accessService: accessService, accessMachine: accessMachine, accessEnviron: accessEnviron, }, nil }