func (s *storageSuite) TestUnitStorageAttachments(c *gc.C) { storageAttachmentIds := []params.StorageAttachmentId{{ StorageTag: "storage-whatever-0", UnitTag: "unit-mysql-0", }} var called bool apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { c.Check(objType, gc.Equals, "Uniter") c.Check(version, gc.Equals, 2) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, "UnitStorageAttachments") c.Check(arg, gc.DeepEquals, params.Entities{ Entities: []params.Entity{{Tag: "unit-mysql-0"}}, }) c.Assert(result, gc.FitsTypeOf, ¶ms.StorageAttachmentIdsResults{}) *(result.(*params.StorageAttachmentIdsResults)) = params.StorageAttachmentIdsResults{ Results: []params.StorageAttachmentIdsResult{{ Result: params.StorageAttachmentIds{storageAttachmentIds}, }}, } called = true return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) attachmentIds, err := st.UnitStorageAttachments(names.NewUnitTag("mysql/0")) c.Check(err, jc.ErrorIsNil) c.Check(called, jc.IsTrue) c.Assert(attachmentIds, gc.DeepEquals, storageAttachmentIds) }
func (s *storageSuite) TestStorageAttachmentLife(c *gc.C) { apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { c.Check(objType, gc.Equals, "Uniter") c.Check(version, gc.Equals, 2) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, "StorageAttachmentLife") c.Check(arg, gc.DeepEquals, params.StorageAttachmentIds{ Ids: []params.StorageAttachmentId{{ StorageTag: "storage-data-0", UnitTag: "unit-mysql-0", }}, }) c.Assert(result, gc.FitsTypeOf, ¶ms.LifeResults{}) *(result.(*params.LifeResults)) = params.LifeResults{ Results: []params.LifeResult{{ Life: params.Dying, }}, } return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) results, err := st.StorageAttachmentLife([]params.StorageAttachmentId{{ StorageTag: "storage-data-0", UnitTag: "unit-mysql-0", }}) c.Check(err, jc.ErrorIsNil) c.Assert(results, jc.DeepEquals, []params.LifeResult{{Life: params.Dying}}) }
// Uniter returns a version of the state that provides functionality // required by the uniter worker. func (st *State) Uniter() (*uniter.State, error) { unitTag, ok := st.authTag.(names.UnitTag) if !ok { return nil, errors.Errorf("expected UnitTag, got %T %v", st.authTag, st.authTag) } return uniter.NewState(st, unitTag), nil }
func (s *storageSuite) TestWatchStorageAttachments(c *gc.C) { var called bool apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { c.Check(objType, gc.Equals, "Uniter") c.Check(version, gc.Equals, 2) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, "WatchStorageAttachments") c.Check(arg, gc.DeepEquals, params.StorageAttachmentIds{ Ids: []params.StorageAttachmentId{{ StorageTag: "storage-data-0", UnitTag: "unit-mysql-0", }}, }) c.Assert(result, gc.FitsTypeOf, ¶ms.NotifyWatchResults{}) *(result.(*params.NotifyWatchResults)) = params.NotifyWatchResults{ Results: []params.NotifyWatchResult{{ Error: ¶ms.Error{Message: "FAIL"}, }}, } called = true return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) _, err := st.WatchStorageAttachment(names.NewStorageTag("data/0"), names.NewUnitTag("mysql/0")) c.Check(err, gc.ErrorMatches, "FAIL") c.Check(called, jc.IsTrue) }
func (s *relationsSuite) TestNextOpNothing(c *gc.C) { unitTag := names.NewUnitTag("wordpress/0") abort := make(chan struct{}) var numCalls int32 unitEntity := params.Entities{Entities: []params.Entity{params.Entity{Tag: "unit-wordpress-0"}}} apiCaller := mockAPICaller(c, &numCalls, uniterApiCall("Life", unitEntity, params.LifeResults{Results: []params.LifeResult{{Life: params.Alive}}}, nil), uniterApiCall("JoinedRelations", unitEntity, params.StringsResults{Results: []params.StringsResult{{Result: []string{}}}}, nil), uniterApiCall("GetPrincipal", unitEntity, params.StringBoolResults{Results: []params.StringBoolResult{{Result: "", Ok: false}}}, nil), ) st := uniter.NewState(apiCaller, unitTag) r, err := relation.NewRelations(st, unitTag, s.stateDir, s.relationsDir, abort) c.Assert(err, jc.ErrorIsNil) assertNumCalls(c, &numCalls, 2) localState := resolver.LocalState{ State: operation.State{ Kind: operation.Continue, }, } remoteState := remotestate.Snapshot{} relationsResolver := relation.NewRelationsResolver(r) _, err = relationsResolver.NextOp(localState, remoteState, &mockOperations{}) c.Assert(errors.Cause(err), gc.Equals, resolver.ErrNoOperation) }
func (s *uniterLeadershipSuite) TestMergeLeadershipSettings(c *gc.C) { // First, the unit must be elected leader; otherwise merges will be denied. leaderClient := leadership.NewClient(s.apiState) err := leaderClient.ClaimLeadership(s.serviceId, s.unitId, 10*time.Second) c.Assert(err, jc.ErrorIsNil) client := uniter.NewState(s.apiState, names.NewUnitTag(s.unitId)) // Grab what settings exist. settings, err := client.LeadershipSettings.Read(s.serviceId) c.Assert(err, jc.ErrorIsNil) // Double check that it's empty so that we don't pass the test by // happenstance. c.Assert(settings, gc.HasLen, 0) // Toss a few settings in. settings["foo"] = "bar" settings["baz"] = "biz" err = client.LeadershipSettings.Merge(s.serviceId, settings) c.Assert(err, jc.ErrorIsNil) settings, err = client.LeadershipSettings.Read(s.serviceId) c.Assert(err, jc.ErrorIsNil) c.Check(settings["foo"], gc.Equals, "bar") c.Check(settings["baz"], gc.Equals, "biz") }
func (s *storageSuite) TestRemoveStorageAttachment(c *gc.C) { apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { c.Check(objType, gc.Equals, "Uniter") c.Check(version, gc.Equals, 2) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, "RemoveStorageAttachments") c.Check(arg, gc.DeepEquals, params.StorageAttachmentIds{ Ids: []params.StorageAttachmentId{{ StorageTag: "storage-data-0", UnitTag: "unit-mysql-0", }}, }) c.Assert(result, gc.FitsTypeOf, ¶ms.ErrorResults{}) *(result.(*params.ErrorResults)) = params.ErrorResults{ Results: []params.ErrorResult{{ Error: ¶ms.Error{Message: "yoink"}, }}, } return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) err := st.RemoveStorageAttachment(names.NewStorageTag("data/0"), names.NewUnitTag("mysql/0")) c.Check(err, gc.ErrorMatches, "yoink") }
func (s *storageSuite) TestAPIErrors(c *gc.C) { apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { return errors.New("bad") }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) _, err := st.UnitStorageAttachments(names.NewUnitTag("mysql/0")) c.Check(err, gc.ErrorMatches, "bad") }
// Manifold returns a dependency manifold that runs a uniter worker, // using the resource names defined in the supplied config. func Manifold(config ManifoldConfig) dependency.Manifold { return dependency.Manifold{ Inputs: []string{ config.AgentName, config.APICallerName, config.LeadershipTrackerName, config.MachineLockName, config.CharmDirName, }, Start: func(getResource dependency.GetResourceFunc) (worker.Worker, error) { // Collect all required resources. var agent agent.Agent if err := getResource(config.AgentName, &agent); err != nil { return nil, err } var apiCaller base.APICaller if err := getResource(config.APICallerName, &apiCaller); err != nil { // TODO(fwereade): absence of an APICaller shouldn't be the end of // the world -- we ought to return a type that can at least run the // leader-deposed hook -- but that's not done yet. return nil, err } var machineLock *fslock.Lock if err := getResource(config.MachineLockName, &machineLock); err != nil { return nil, err } var leadershipTracker leadership.Tracker if err := getResource(config.LeadershipTrackerName, &leadershipTracker); err != nil { return nil, err } var charmDirGuard fortress.Guard if err := getResource(config.CharmDirName, &charmDirGuard); err != nil { return nil, err } // Configure and start the uniter. config := agent.CurrentConfig() tag := config.Tag() unitTag, ok := tag.(names.UnitTag) if !ok { return nil, errors.Errorf("expected a unit tag, got %v", tag) } uniterFacade := uniter.NewState(apiCaller, unitTag) return NewUniter(&UniterParams{ UniterFacade: uniterFacade, UnitTag: unitTag, LeadershipTracker: leadershipTracker, DataDir: config.DataDir(), MachineLock: machineLock, CharmDirGuard: charmDirGuard, UpdateStatusSignal: NewUpdateStatusTimer(), NewOperationExecutor: operation.NewExecutor, Clock: clock.WallClock, }), nil }, } }
func (s *relationsSuite) TestImplicitRelationNoHooks(c *gc.C) { unitTag := names.NewUnitTag("wordpress/0") abort := make(chan struct{}) unitEntity := params.Entities{Entities: []params.Entity{params.Entity{Tag: "unit-wordpress-0"}}} relationResults := params.RelationResults{ Results: []params.RelationResult{ { Id: 1, Key: "wordpress:juju-info juju-info:juju-info", Life: params.Alive, Endpoint: multiwatcher.Endpoint{ ApplicationName: "wordpress", Relation: multiwatcher.CharmRelation{Name: "juju-info", Role: string(charm.RoleProvider), Interface: "juju-info", Scope: "global"}, }}, }, } relationUnits := params.RelationUnits{RelationUnits: []params.RelationUnit{ {Relation: "relation-wordpress.juju-info#juju-info.juju-info", Unit: "unit-wordpress-0"}, }} apiCalls := []apiCall{ uniterApiCall("Life", unitEntity, params.LifeResults{Results: []params.LifeResult{{Life: params.Alive}}}, nil), uniterApiCall("JoinedRelations", unitEntity, params.StringsResults{Results: []params.StringsResult{{Result: []string{}}}}, nil), uniterApiCall("RelationById", params.RelationIds{RelationIds: []int{1}}, relationResults, nil), uniterApiCall("Relation", relationUnits, relationResults, nil), uniterApiCall("Relation", relationUnits, relationResults, nil), uniterApiCall("Watch", unitEntity, params.NotifyWatchResults{Results: []params.NotifyWatchResult{{NotifyWatcherId: "1"}}}, nil), uniterApiCall("EnterScope", relationUnits, params.ErrorResults{Results: []params.ErrorResult{{}}}, nil), uniterApiCall("GetPrincipal", unitEntity, params.StringBoolResults{Results: []params.StringBoolResult{{Result: "", Ok: false}}}, nil), } var numCalls int32 apiCaller := mockAPICaller(c, &numCalls, apiCalls...) st := uniter.NewState(apiCaller, unitTag) r, err := relation.NewRelations(st, unitTag, s.stateDir, s.relationsDir, abort) c.Assert(err, jc.ErrorIsNil) localState := resolver.LocalState{ State: operation.State{ Kind: operation.Continue, }, } remoteState := remotestate.Snapshot{ Relations: map[int]remotestate.RelationSnapshot{ 1: remotestate.RelationSnapshot{ Life: params.Alive, Members: map[string]int64{ "wordpress": 1, }, }, }, } relationsResolver := relation.NewRelationsResolver(r) _, err = relationsResolver.NextOp(localState, remoteState, &mockOperations{}) c.Assert(errors.Cause(err), gc.Equals, resolver.ErrNoOperation) }
func (s *storageSuite) TestStorageAttachmentResultCountMismatch(c *gc.C) { apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { *(result.(*params.StorageAttachmentIdsResults)) = params.StorageAttachmentIdsResults{ []params.StorageAttachmentIdsResult{{}, {}}, } return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) c.Assert(func() { st.UnitStorageAttachments(names.NewUnitTag("mysql/0")) }, gc.PanicMatches, "expected 1 result, got 2") }
func (s *relationsSuite) setupRelations(c *gc.C) relation.Relations { unitTag := names.NewUnitTag("wordpress/0") abort := make(chan struct{}) var numCalls int32 unitEntity := params.Entities{Entities: []params.Entity{params.Entity{Tag: "unit-wordpress-0"}}} apiCaller := mockAPICaller(c, &numCalls, uniterApiCall("Life", unitEntity, params.LifeResults{Results: []params.LifeResult{{Life: params.Alive}}}, nil), uniterApiCall("JoinedRelations", unitEntity, params.StringsResults{Results: []params.StringsResult{{Result: []string{}}}}, nil), ) st := uniter.NewState(apiCaller, unitTag) r, err := relation.NewRelations(st, unitTag, s.stateDir, s.relationsDir, abort) c.Assert(err, jc.ErrorIsNil) assertNumCalls(c, &numCalls, 2) return r }
func (s *relationsSuite) TestNewRelationsWithExistingRelations(c *gc.C) { unitTag := names.NewUnitTag("wordpress/0") abort := make(chan struct{}) var numCalls int32 unitEntity := params.Entities{Entities: []params.Entity{params.Entity{Tag: "unit-wordpress-0"}}} relationUnits := params.RelationUnits{RelationUnits: []params.RelationUnit{ {Relation: "relation-wordpress.db#mysql.db", Unit: "unit-wordpress-0"}, }} relationResults := params.RelationResults{ Results: []params.RelationResult{ { Id: 1, Key: "wordpress:db mysql:db", Life: params.Alive, Endpoint: multiwatcher.Endpoint{ ApplicationName: "wordpress", Relation: multiwatcher.CharmRelation{Name: "mysql", Role: string(charm.RoleProvider), Interface: "db"}, }}, }, } apiCaller := mockAPICaller(c, &numCalls, uniterApiCall("Life", unitEntity, params.LifeResults{Results: []params.LifeResult{{Life: params.Alive}}}, nil), uniterApiCall("JoinedRelations", unitEntity, params.StringsResults{Results: []params.StringsResult{{Result: []string{"relation-wordpress:db mysql:db"}}}}, nil), uniterApiCall("Relation", relationUnits, relationResults, nil), uniterApiCall("Relation", relationUnits, relationResults, nil), uniterApiCall("Watch", unitEntity, params.NotifyWatchResults{Results: []params.NotifyWatchResult{{NotifyWatcherId: "1"}}}, nil), uniterApiCall("EnterScope", relationUnits, params.ErrorResults{Results: []params.ErrorResult{{}}}, nil), ) st := uniter.NewState(apiCaller, unitTag) r, err := relation.NewRelations(st, unitTag, s.stateDir, s.relationsDir, abort) c.Assert(err, jc.ErrorIsNil) assertNumCalls(c, &numCalls, 6) info := r.GetInfo() c.Assert(info, gc.HasLen, 1) oneInfo := info[1] c.Assert(oneInfo.RelationUnit.Relation().Tag(), gc.Equals, names.NewRelationTag("wordpress:db mysql:db")) c.Assert(oneInfo.RelationUnit.Endpoint(), jc.DeepEquals, uniter.Endpoint{ Relation: charm.Relation{Name: "mysql", Role: "provider", Interface: "db", Optional: false, Limit: 0, Scope: ""}, }) c.Assert(oneInfo.MemberNames, gc.HasLen, 0) }
// validateMigration is called by the migrationminion to help check // that the agent will be ok when connected to a new controller. func (a *UnitAgent) validateMigration(apiCaller base.APICaller) error { // TODO(mjs) - more extensive checks to come. unitTag := names.NewUnitTag(a.UnitName) facade := uniter.NewState(apiCaller, unitTag) _, err := facade.Unit(unitTag) if err != nil { return errors.Trace(err) } model, err := facade.Model() if err != nil { return errors.Trace(err) } curModelUUID := a.CurrentConfig().Model().Id() newModelUUID := model.UUID() if newModelUUID != curModelUUID { return errors.Errorf("model mismatch when validating: got %q, expected %q", newModelUUID, curModelUUID) } return nil }
func (s *uniterLeadershipSuite) TestReadLeadershipSettings(c *gc.C) { // First, the unit must be elected leader; otherwise merges will be denied. leaderClient := leadership.NewClient(s.apiState) err := leaderClient.ClaimLeadership(s.serviceId, s.unitId, 10*time.Second) c.Assert(err, jc.ErrorIsNil) client := uniter.NewState(s.apiState, names.NewUnitTag(s.unitId)) // Toss a few settings in. desiredSettings := map[string]string{ "foo": "bar", "baz": "biz", } err = client.LeadershipSettings.Merge(s.serviceId, desiredSettings) c.Assert(err, jc.ErrorIsNil) settings, err := client.LeadershipSettings.Read(s.serviceId) c.Assert(err, jc.ErrorIsNil) c.Check(settings, gc.DeepEquals, desiredSettings) }
func (s *relationsSuite) assertHookRelationJoined(c *gc.C, numCalls *int32, apiCalls ...apiCall) relation.Relations { unitTag := names.NewUnitTag("wordpress/0") abort := make(chan struct{}) apiCaller := mockAPICaller(c, numCalls, apiCalls...) st := uniter.NewState(apiCaller, unitTag) r, err := relation.NewRelations(st, unitTag, s.stateDir, s.relationsDir, abort) c.Assert(err, jc.ErrorIsNil) assertNumCalls(c, numCalls, 2) localState := resolver.LocalState{ State: operation.State{ Kind: operation.Continue, }, } remoteState := remotestate.Snapshot{ Relations: map[int]remotestate.RelationSnapshot{ 1: remotestate.RelationSnapshot{ Life: params.Alive, Members: map[string]int64{ "wordpress": 1, }, }, }, } relationsResolver := relation.NewRelationsResolver(r) op, err := relationsResolver.NextOp(localState, remoteState, &mockOperations{}) c.Assert(err, jc.ErrorIsNil) assertNumCalls(c, numCalls, 8) c.Assert(op.String(), gc.Equals, "run hook relation-joined on unit with relation 1") // Commit the operation so we save local state for any next operation. _, err = r.PrepareHook(op.(*mockOperation).hookInfo) c.Assert(err, jc.ErrorIsNil) err = r.CommitHook(op.(*mockOperation).hookInfo) c.Assert(err, jc.ErrorIsNil) return r }
func (s *uniterLeadershipSuite) TestSettingsChangeNotifier(c *gc.C) { // First, the unit must be elected leader; otherwise merges will be denied. leaderClient := leadership.NewClient(s.apiState) err := leaderClient.ClaimLeadership(s.serviceId, s.unitId, 10*time.Second) c.Assert(err, jc.ErrorIsNil) client := uniter.NewState(s.apiState, names.NewUnitTag(s.unitId)) // Listen for changes watcher, err := client.LeadershipSettings.WatchLeadershipSettings(s.serviceId) c.Assert(err, jc.ErrorIsNil) defer statetesting.AssertStop(c, watcher) leadershipC := statetesting.NewNotifyWatcherC(c, s.BackingState, watcher) // Inital event leadershipC.AssertOneChange() // Make some changes err = client.LeadershipSettings.Merge(s.serviceId, map[string]string{"foo": "bar"}) c.Assert(err, jc.ErrorIsNil) leadershipC.AssertOneChange() // And check that the changes were actually applied settings, err := client.LeadershipSettings.Read(s.serviceId) c.Assert(err, jc.ErrorIsNil) c.Check(settings["foo"], gc.Equals, "bar") // Make a couple of changes, and then check that they have been // coalesced into a single event err = client.LeadershipSettings.Merge(s.serviceId, map[string]string{"foo": "baz"}) c.Assert(err, jc.ErrorIsNil) err = client.LeadershipSettings.Merge(s.serviceId, map[string]string{"bing": "bong"}) c.Assert(err, jc.ErrorIsNil) leadershipC.AssertOneChange() }
func (s *storageSuite) TestStorageAttachments(c *gc.C) { storageAttachment := params.StorageAttachment{ StorageTag: "storage-whatever-0", OwnerTag: "service-mysql", UnitTag: "unit-mysql-0", Kind: params.StorageKindBlock, Location: "/dev/sda", } var called bool apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { c.Check(objType, gc.Equals, "Uniter") c.Check(version, gc.Equals, 2) c.Check(id, gc.Equals, "") c.Check(request, gc.Equals, "StorageAttachments") c.Check(arg, gc.DeepEquals, params.StorageAttachmentIds{ Ids: []params.StorageAttachmentId{{ StorageTag: "storage-data-0", UnitTag: "unit-mysql-0", }}, }) c.Assert(result, gc.FitsTypeOf, ¶ms.StorageAttachmentResults{}) *(result.(*params.StorageAttachmentResults)) = params.StorageAttachmentResults{ Results: []params.StorageAttachmentResult{{ Result: storageAttachment, }}, } called = true return nil }) st := uniter.NewState(apiCaller, names.NewUnitTag("mysql/0")) attachment, err := st.StorageAttachment(names.NewStorageTag("data/0"), names.NewUnitTag("mysql/0")) c.Check(err, jc.ErrorIsNil) c.Check(called, jc.IsTrue) c.Assert(attachment, gc.DeepEquals, storageAttachment) }
) // ManifoldConfig defines the names of the manifolds on which a Manifold will depend. type ManifoldConfig util.AgentApiManifoldConfig // Manifold returns a dependency manifold that runs an API address updater worker, // using the resource names defined in the supplied config. func Manifold(config ManifoldConfig) dependency.Manifold { return util.AgentApiManifold(util.AgentApiManifoldConfig(config), newWorker) } // newWorker trivially wraps NewAPIAddressUpdater for use in a util.AgentApiManifold. // It's not tested at the moment, because the scaffolding necessary is too // unwieldy/distracting to introduce at this point. var newWorker = func(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) { // TODO(fwereade): why on *earth* do we use the *uniter* facade for this // worker? This code really ought to work anywhere... tag := a.CurrentConfig().Tag() unitTag, ok := tag.(names.UnitTag) if !ok { return nil, errors.Errorf("expected a unit tag; got %q", tag) } facade := uniter.NewState(apiCaller, unitTag) setter := agent.APIHostPortsSetter{a} w, err := NewAPIAddressUpdater(facade, setter) if err != nil { return nil, errors.Trace(err) } return w, nil }
var agent agent.Agent if err := getResource(config.AgentName, &agent); err != nil { return nil, err } tag := agent.CurrentConfig().Tag() unitTag, ok := tag.(names.UnitTag) if !ok { return nil, errors.Errorf("expected a unit tag, got %v", tag) } var apiCaller base.APICaller if err := getResource(config.APICallerName, &apiCaller); err != nil { return nil, err } uniterFacade := uniterapi.NewState(apiCaller, unitTag) var metricFactory spool.MetricFactory err := getResource(config.MetricSpoolName, &metricFactory) if err != nil { return nil, err } var charmdir fortress.Guest err = getResource(config.CharmDirName, &charmdir) if err != nil { return nil, err } collector := &collect{ period: period,
// Uniter returns a version of the state that provides functionality // required by the uniter worker. func (st *State) Uniter() *uniter.State { // TODO(dfc) yes, this can panic, we never checked before return uniter.NewState(st, st.authTag.(names.UnitTag)) }
func (s *unitStorageSuite) createTestUnit(c *gc.C, t string, apiCaller basetesting.APICallerFunc) *uniter.Unit { tag := names.NewUnitTag(t) st := uniter.NewState(apiCaller, tag) return uniter.CreateUnit(st, tag) }
// using the resource names defined in the supplied config. func Manifold(config ManifoldConfig) dependency.Manifold { typedConfig := util.AgentApiManifoldConfig(config) return util.AgentApiManifold(typedConfig, newWorker) } // newWorker trivially wraps NewAPIAddressUpdater for use in a util.AgentApiManifold. // It's not tested at the moment, because the scaffolding necessary is too // unwieldy/distracting to introduce at this point. var newWorker = func(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) { tag := a.CurrentConfig().Tag() // TODO(fwereade): use appropriate facade! var facade APIAddresser switch apiTag := tag.(type) { case names.UnitTag: facade = uniter.NewState(apiCaller, apiTag) case names.MachineTag: facade = machiner.NewState(apiCaller) default: return nil, errors.Errorf("expected a unit or machine tag; got %q", tag) } setter := agent.APIHostPortsSetter{a} w, err := NewAPIAddressUpdater(facade, setter) if err != nil { return nil, errors.Trace(err) } return w, nil }
"github.com/juju/juju/api/uniter" "github.com/juju/juju/worker" "github.com/juju/juju/worker/dependency" "github.com/juju/juju/worker/util" ) // ManifoldConfig defines the names of the manifolds on which a Manifold will depend. type ManifoldConfig util.AgentApiManifoldConfig // Manifold returns a dependency manifold that runs an API address updater worker, // using the resource names defined in the supplied config. func Manifold(config ManifoldConfig) dependency.Manifold { return util.AgentApiManifold(util.AgentApiManifoldConfig(config), newWorker) } // newWorker trivially wraps NewAPIAddressUpdater for use in a util.AgentApiManifold. // It's not tested at the moment, because the scaffolding necessary to test these 5 // lines outweighs them by several times for very little confirmatory power; in the // long term, all APIAddressUpdaters should be constructed via a manifold, and the // tests can be updated to reflect that. var newWorker = func(a agent.Agent, apiCaller base.APICaller) (worker.Worker, error) { // TODO(fwereade): why on *earth* do we use the *uniter* facade for this // worker? This code really ought to work anywhere... tag := a.CurrentConfig().Tag() unitTag, ok := tag.(names.UnitTag) if !ok { return nil, errors.Errorf("expected a unit tag; got %q", tag) } return NewAPIAddressUpdater(uniter.NewState(apiCaller, unitTag), agent.APIHostPortsSetter{a}), nil }