func (s *apiclientSuite) TestOpenHonorsEnvironTag(c *gc.C) { info := s.APIInfo(c) // TODO(jam): 2014-06-05 http://pad.lv/1326802 // we want to test this eventually, but for now s.APIInfo uses // conn.StateInfo() which doesn't know about EnvironTag. // c.Check(info.EnvironTag, gc.Equals, env.Tag()) // c.Assert(info.EnvironTag, gc.Not(gc.Equals), "") // We start by ensuring we have an invalid tag, and Open should fail. info.EnvironTag = names.NewEnvironTag("bad-tag") _, err := api.Open(info, api.DialOpts{}) c.Check(err, gc.ErrorMatches, `unknown environment: "bad-tag"`) c.Check(params.ErrCode(err), gc.Equals, params.CodeNotFound) // Now set it to the right tag, and we should succeed. info.EnvironTag = s.State.EnvironTag() st, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) st.Close() // Backwards compatibility, we should succeed if we do not set an // environ tag info.EnvironTag = names.NewEnvironTag("") st, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) st.Close() }
func (s *PresenceSuite) setup(c *gc.C, key string) (*presence.Watcher, *presence.Pinger, <-chan presence.Change) { uuid, err := utils.NewUUID() c.Assert(err, jc.ErrorIsNil) envUUID := uuid.String() w := presence.NewWatcher(s.presence, names.NewEnvironTag(envUUID)) p := presence.NewPinger(s.presence, names.NewEnvironTag(envUUID), key) ch := make(chan presence.Change) w.Watch(key, ch) assertChange(c, ch, presence.Change{key, false}) return w, p, ch }
// NewAPIAuthenticator gets the state and api info once from the // provisioner API. func NewAPIAuthenticator(st *apiprovisioner.State) (AuthenticationProvider, error) { stateAddresses, err := st.StateAddresses() if err != nil { return nil, errors.Trace(err) } apiAddresses, err := st.APIAddresses() if err != nil { return nil, errors.Trace(err) } caCert, err := st.CACert() if err != nil { return nil, errors.Trace(err) } envUUID, err := st.EnvironUUID() if err != nil { return nil, errors.Trace(err) } stateInfo := &mongo.MongoInfo{ Info: mongo.Info{ Addrs: stateAddresses, CACert: caCert, }, } apiInfo := &api.Info{ Addrs: apiAddresses, CACert: caCert, EnvironTag: names.NewEnvironTag(envUUID), } return &simpleAuth{stateInfo, apiInfo}, nil }
// EnvironmentsForUser returns a list of enviroments that the user // is able to access. func (st *State) EnvironmentsForUser(user names.UserTag) ([]*UserEnvironment, error) { // Since there are no groups at this stage, the simplest way to get all // the environments that a particular user can see is to look through the // environment user collection. A raw collection is required to support // queries across multiple environments. envUsers, userCloser := st.getRawCollection(envUsersC) defer userCloser() // TODO: consider adding an index to the envUsers collection on the username. var userSlice []envUserDoc err := envUsers.Find(bson.D{{"user", user.Username()}}).All(&userSlice) if err != nil { return nil, err } var result []*UserEnvironment for _, doc := range userSlice { envTag := names.NewEnvironTag(doc.EnvUUID) env, err := st.GetEnvironment(envTag) if err != nil { return nil, errors.Trace(err) } result = append(result, &UserEnvironment{Environment: env, LastConnection: doc.LastConnection}) } return result, nil }
func (s *PresenceSuite) SetUpSuite(c *gc.C) { s.BaseSuite.SetUpSuite(c) s.MgoSuite.SetUpSuite(c) uuid, err := utils.NewUUID() c.Assert(err, jc.ErrorIsNil) s.envTag = names.NewEnvironTag(uuid.String()) }
// AddLeadsershipSettingsDocs creates service leadership documents in // the settings collection for all services in all environments. func AddLeadershipSettingsDocs(st *State) error { environments, closer := st.getCollection(environmentsC) defer closer() var envDocs []bson.M err := environments.Find(nil).Select(bson.M{"_id": 1}).All(&envDocs) if err != nil { return errors.Annotate(err, "failed to read environments") } for _, envDoc := range envDocs { envUUID := envDoc["_id"].(string) envSt, err := st.ForEnviron(names.NewEnvironTag(envUUID)) if err != nil { return errors.Annotatef(err, "failed to open environment %q", envUUID) } defer envSt.Close() services, err := envSt.AllServices() if err != nil { return errors.Annotatef(err, "failed to retrieve services for environment %q", envUUID) } for _, service := range services { // The error from this is intentionally ignored as the // transaction will fail if the service already has a // leadership settings doc. envSt.runTransaction([]txn.Op{ addLeadershipSettingsOp(service.Name()), }) } } return nil }
// apiInfoConnect looks for endpoint on the given environment and // tries to connect to it, sending the result on the returned channel. func apiInfoConnect(info configstore.EnvironInfo, apiOpen api.OpenFunc, stop <-chan struct{}, bClient *httpbakery.Client) (api.Connection, error) { endpoint := info.APIEndpoint() if info == nil || len(endpoint.Addresses) == 0 { return nil, &infoConnectError{fmt.Errorf("no cached addresses")} } logger.Infof("connecting to API addresses: %v", endpoint.Addresses) var environTag names.EnvironTag if names.IsValidEnvironment(endpoint.EnvironUUID) { environTag = names.NewEnvironTag(endpoint.EnvironUUID) } apiInfo := &api.Info{ Addrs: endpoint.Addresses, CACert: endpoint.CACert, Tag: environInfoUserTag(info), Password: info.APICredentials().Password, EnvironTag: environTag, } if apiInfo.Tag == nil { apiInfo.UseMacaroons = true } dialOpts := api.DefaultDialOpts() dialOpts.BakeryClient = bClient st, err := apiOpen(apiInfo, dialOpts) if err != nil { return nil, &infoConnectError{err} } return st, nil }
// APIInfo returns an api.Info for the environment. The result is populated // with addresses and CA certificate, but no tag or password. func APIInfo(env Environ) (*api.Info, error) { instanceIds, err := env.StateServerInstances() if err != nil { return nil, err } logger.Debugf("StateServerInstances returned: %v", instanceIds) addrs, err := waitAnyInstanceAddresses(env, instanceIds) if err != nil { return nil, err } config := env.Config() cert, hasCert := config.CACert() if !hasCert { return nil, errors.New("config has no CACert") } apiPort := config.APIPort() apiAddrs := network.HostPortsToStrings( network.AddressesWithPort(addrs, apiPort), ) uuid, uuidSet := config.UUID() if !uuidSet { return nil, errors.New("config has no UUID") } envTag := names.NewEnvironTag(uuid) apiInfo := &api.Info{Addrs: apiAddrs, CACert: cert, EnvironTag: envTag} return apiInfo, nil }
// AddDefaultBlockDevicesDocs creates block devices documents // for all existing machines in all environments. func AddDefaultBlockDevicesDocs(st *State) error { environments, closer := st.getCollection(environmentsC) defer closer() var envDocs []bson.M err := environments.Find(nil).Select(bson.M{"_id": 1}).All(&envDocs) if err != nil { return errors.Annotate(err, "failed to read environments") } for _, envDoc := range envDocs { envUUID := envDoc["_id"].(string) envSt, err := st.ForEnviron(names.NewEnvironTag(envUUID)) if err != nil { return errors.Annotatef(err, "failed to open environment %q", envUUID) } defer envSt.Close() machines, err := envSt.AllMachines() if err != nil { return errors.Annotatef(err, "failed to retrieve machines for environment %q", envUUID) } for _, machine := range machines { // If a txn fails because the doc already exists, that's ok. if err := envSt.runTransaction([]txn.Op{ createMachineBlockDevicesOp(machine.Id()), }); err != nil && err != txn.ErrAborted { return err } } } return nil }
// apiInfoConnect looks for endpoint on the given environment and // tries to connect to it, sending the result on the returned channel. func apiInfoConnect(store configstore.Storage, info configstore.EnvironInfo, apiOpen apiOpenFunc, stop <-chan struct{}) (apiState, error) { endpoint := info.APIEndpoint() if info == nil || len(endpoint.Addresses) == 0 { return nil, &infoConnectError{fmt.Errorf("no cached addresses")} } logger.Infof("connecting to API addresses: %v", endpoint.Addresses) var environTag names.Tag if endpoint.EnvironUUID != "" { // Note: we should be validating that EnvironUUID contains a // valid UUID. environTag = names.NewEnvironTag(endpoint.EnvironUUID) } username := info.APICredentials().User if username == "" { username = "******" } apiInfo := &api.Info{ Addrs: endpoint.Addresses, CACert: endpoint.CACert, Tag: names.NewUserTag(username), Password: info.APICredentials().Password, EnvironTag: environTag, } st, err := apiOpen(apiInfo, api.DefaultDialOpts()) if err != nil { return nil, &infoConnectError{err} } return st, nil }
// apiInfoConnect looks for endpoint on the given environment and // tries to connect to it, sending the result on the returned channel. func apiInfoConnect(store configstore.Storage, info configstore.EnvironInfo, apiOpen apiOpenFunc, stop <-chan struct{}) (apiState, error) { endpoint := info.APIEndpoint() if info == nil || len(endpoint.Addresses) == 0 { return nil, &infoConnectError{fmt.Errorf("no cached addresses")} } logger.Infof("connecting to API addresses: %v", endpoint.Addresses) var environTag names.EnvironTag if names.IsValidEnvironment(endpoint.EnvironUUID) { environTag = names.NewEnvironTag(endpoint.EnvironUUID) } else { // For backwards-compatibility, we have to allow connections // with an empty UUID. Login will work for the same reasons. logger.Warningf("ignoring invalid API endpoint environment UUID %v", endpoint.EnvironUUID) } apiInfo := &api.Info{ Addrs: endpoint.Addresses, CACert: endpoint.CACert, Tag: environInfoUserTag(info), Password: info.APICredentials().Password, EnvironTag: environTag, } st, err := apiOpen(apiInfo, api.DefaultDialOpts()) if err != nil { return nil, &infoConnectError{err} } return st, nil }
// validateEnvironUUID is the common validator for the various // apiserver components that need to check for a valid environment // UUID. An empty envUUID means that the connection has come in at // the root of the URL space and refers to the state server // environment. // // It returns the validated environment UUID. func validateEnvironUUID(args validateArgs) (string, error) { ssState := args.statePool.SystemState() if args.envUUID == "" { // We allow the environUUID to be empty for 2 cases // 1) Compatibility with older clients // 2) TODO: server a limited API at the root (empty envUUID) // with just the user manager and environment manager // if the connection comes over a sufficiently up to date // login command. if args.strict { return "", errors.Trace(common.UnknownEnvironmentError(args.envUUID)) } logger.Debugf("validate env uuid: empty envUUID") return ssState.EnvironUUID(), nil } if args.envUUID == ssState.EnvironUUID() { logger.Debugf("validate env uuid: state server environment - %s", args.envUUID) return args.envUUID, nil } if args.stateServerEnvOnly { return "", errors.Unauthorizedf("requested environment %q is not the state server environment", args.envUUID) } if !names.IsValidEnvironment(args.envUUID) { return "", errors.Trace(common.UnknownEnvironmentError(args.envUUID)) } envTag := names.NewEnvironTag(args.envUUID) if _, err := ssState.GetEnvironment(envTag); err != nil { return "", errors.Wrap(err, common.UnknownEnvironmentError(args.envUUID)) } logger.Debugf("validate env uuid: %s", args.envUUID) return args.envUUID, nil }
func (s *systemManagerSuite) TestAllEnvironments(c *gc.C) { admin := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar"}) s.Factory.MakeEnvironment(c, &factory.EnvParams{ Name: "owned", Owner: admin.UserTag()}).Close() remoteUserTag := names.NewUserTag("user@remote") st := s.Factory.MakeEnvironment(c, &factory.EnvParams{ Name: "user", Owner: remoteUserTag}) defer st.Close() st.AddEnvironmentUser(admin.UserTag(), remoteUserTag, "Foo Bar") s.Factory.MakeEnvironment(c, &factory.EnvParams{ Name: "no-access", Owner: remoteUserTag}).Close() response, err := s.systemManager.AllEnvironments() c.Assert(err, jc.ErrorIsNil) // The results are sorted. expected := []string{"dummyenv", "no-access", "owned", "user"} var obtained []string for _, env := range response.UserEnvironments { obtained = append(obtained, env.Name) stateEnv, err := s.State.GetEnvironment(names.NewEnvironTag(env.UUID)) c.Assert(err, jc.ErrorIsNil) s.checkEnvironmentMatches(c, env.Environment, stateEnv) } c.Assert(obtained, jc.DeepEquals, expected) }
func (s *apiclientSuite) TestConnectWebsocketToRoot(c *gc.C) { info := s.APIInfo(c) info.EnvironTag = names.NewEnvironTag("") conn, _, err := api.ConnectWebsocket(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer conn.Close() assertConnAddrForRoot(c, conn, info.Addrs[0]) }
func (*tagsSuite) TestResourceTagsUUID(c *gc.C) { testResourceTags(c, testing.EnvironmentTag, nil, map[string]string{ "juju-env-uuid": testing.EnvironmentTag.Id(), }) testResourceTags(c, names.NewEnvironTag(""), nil, map[string]string{ "juju-env-uuid": "", }) }
// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(cfg *config.Config, jobs []multiwatcher.MachineJob) map[string]string { uuid, _ := cfg.UUID() instanceTags := tags.ResourceTags(names.NewEnvironTag(uuid), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuStateServer] = "true" } return instanceTags }
// Initialize sets up an initial empty state and returns it. // This needs to be performed only once for a given environment. // It returns unauthorizedError if access is unauthorized. func Initialize(info *mongo.MongoInfo, cfg *config.Config, opts mongo.DialOpts, policy Policy) (rst *State, err error) { st, err := open(info, opts, policy) if err != nil { return nil, err } defer func() { if err != nil { st.Close() } }() // A valid environment is used as a signal that the // state has already been initalized. If this is the case // do nothing. if _, err := st.Environment(); err == nil { return st, nil } else if !errors.IsNotFound(err) { return nil, err } logger.Infof("initializing environment") if err := checkEnvironConfig(cfg); err != nil { return nil, err } uuid, ok := cfg.UUID() if !ok { return nil, errors.Errorf("environment uuid was not supplied") } st.environTag = names.NewEnvironTag(uuid) ops := []txn.Op{ createConstraintsOp(st, environGlobalKey, constraints.Value{}), createSettingsOp(st, environGlobalKey, cfg.AllAttrs()), createEnvironmentOp(st, cfg.Name(), uuid), { C: stateServersC, Id: environGlobalKey, Assert: txn.DocMissing, Insert: &stateServersDoc{ EnvUUID: uuid, }, }, { C: stateServersC, Id: apiHostPortsKey, Assert: txn.DocMissing, Insert: &apiHostPortsDoc{}, }, { C: stateServersC, Id: stateServingInfoKey, Assert: txn.DocMissing, Insert: ¶ms.StateServingInfo{}, }, } if err := st.runTransaction(ops); err == txn.ErrAborted { // The config was created in the meantime. return st, nil } else if err != nil { return nil, err } return st, nil }
func (s *commonSuite) TestAuthFuncForTagKind(c *gc.C) { // TODO(dimitern): This list of all supported tags and kinds needs // to live in juju/names. uuid, err := utils.NewUUID() c.Assert(err, jc.ErrorIsNil) allTags := []names.Tag{ nil, // invalid tag names.NewActionTag(uuid.String()), names.NewCharmTag("cs:precise/missing"), names.NewEnvironTag(uuid.String()), names.NewFilesystemTag("20/20"), names.NewLocalUserTag("user"), names.NewMachineTag("42"), names.NewNetworkTag("public"), names.NewRelationTag("wordpress:mysql mysql:db"), names.NewServiceTag("wordpress"), names.NewSpaceTag("apps"), names.NewStorageTag("foo/42"), names.NewUnitTag("wordpress/5"), names.NewUserTag("joe"), names.NewVolumeTag("80/20"), } for i, allowedTag := range allTags { c.Logf("test #%d: allowedTag: %v", i, allowedTag) var allowedKind string if allowedTag != nil { allowedKind = allowedTag.Kind() } getAuthFunc := common.AuthFuncForTagKind(allowedKind) authFunc, err := getAuthFunc() if allowedKind == "" { c.Check(err, gc.ErrorMatches, "tag kind cannot be empty") c.Check(authFunc, gc.IsNil) continue } else if !c.Check(err, jc.ErrorIsNil) { continue } for j, givenTag := range allTags { c.Logf("test #%d.%d: givenTag: %v", i, j, givenTag) var givenKind string if givenTag != nil { givenKind = givenTag.Kind() } if allowedKind == givenKind { c.Check(authFunc(givenTag), jc.IsTrue) } else { c.Check(authFunc(givenTag), jc.IsFalse) } } } }
// resourceGroupName returns the name of the environment's resource group. func resourceGroupName(cfg *config.Config) string { uuid, _ := cfg.UUID() // UUID is always available for azure environments, since the (new) // provider was introduced after environment UUIDs. envTag := names.NewEnvironTag(uuid) return fmt.Sprintf( "juju-%s-%s", cfg.Name(), resourceName(envTag), ) }
func (s *EnvironSuite) TestControllerEnvironment(c *gc.C) { env, err := s.State.ControllerEnvironment() c.Assert(err, jc.ErrorIsNil) expectedTag := names.NewEnvironTag(env.UUID()) c.Assert(env.Tag(), gc.Equals, expectedTag) c.Assert(env.ControllerTag(), gc.Equals, expectedTag) c.Assert(env.Name(), gc.Equals, "testenv") c.Assert(env.Owner(), gc.Equals, s.Owner) c.Assert(env.Life(), gc.Equals, state.Alive) }
// storageTags returns the tags that should be set on a volume or filesystem, // if the provider supports them. func storageTags( storageInstance state.StorageInstance, cfg *config.Config, ) (map[string]string, error) { uuid, _ := cfg.UUID() storageTags := tags.ResourceTags(names.NewEnvironTag(uuid), cfg) if storageInstance != nil { storageTags[tags.JujuStorageInstance] = storageInstance.Tag().Id() storageTags[tags.JujuStorageOwner] = storageInstance.Owner().Id() } return storageTags, nil }
func (s *loginSuite) TestInvalidEnvironment(c *gc.C) { info, cleanup := s.setupServerWithValidator(c, nil) defer cleanup() info.EnvironTag = names.NewEnvironTag("rubbish") st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer st.Close() adminUser := s.AdminUserTag(c) err = st.Login(adminUser, "dummy-secret", "") c.Assert(err, gc.ErrorMatches, `unknown environment: "rubbish"`) }
func (s *provisionerSuite) TestNewState(c *gc.C) { apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error { return nil }) st := storageprovisioner.NewState(apiCaller, names.NewMachineTag("123")) c.Assert(st, gc.NotNil) st = storageprovisioner.NewState(apiCaller, names.NewEnvironTag("87927ace-9e41-4fd5-8103-1a6fb5ff7eb4")) c.Assert(st, gc.NotNil) c.Assert(func() { storageprovisioner.NewState(apiCaller, names.NewUnitTag("mysql/0")) }, gc.PanicMatches, "expected EnvironTag or MachineTag, got names.UnitTag") }
func (m *envWorkerManager) envHasChanged(uuid string) error { envTag := names.NewEnvironTag(uuid) envAlive, err := m.isEnvAlive(envTag) if err != nil { return errors.Trace(err) } if envAlive { err = m.envIsAlive(envTag) } else { err = m.envIsDead(envTag) } return errors.Trace(err) }
func (s *clientSuite) TestOpenUsesEnvironUUIDPaths(c *gc.C) { info := s.APIInfo(c) // Backwards compatibility, passing EnvironTag = "" should just work info.EnvironTag = names.NewEnvironTag("") apistate, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in the correct environment UUID should also work environ, err := s.State.Environment() c.Assert(err, jc.ErrorIsNil) info.EnvironTag = environ.EnvironTag() apistate, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in a bad environment UUID should fail with a known error info.EnvironTag = names.NewEnvironTag("dead-beef-123456") apistate, err = api.Open(info, api.DialOpts{}) c.Check(err, gc.ErrorMatches, `unknown environment: "dead-beef-123456"`) c.Check(err, jc.Satisfies, params.IsCodeNotFound) c.Assert(apistate, gc.IsNil) }
func (s *clientSuite) TestConnectStreamRootPath(c *gc.C) { s.PatchValue(api.WebsocketDialConfig, echoURL(c)) // If the server is old, we connect to /path. info := s.APIInfo(c) info.EnvironTag = names.NewEnvironTag("") apistate, err := api.OpenWithVersion(info, api.DialOpts{}, 1) c.Assert(err, jc.ErrorIsNil) defer apistate.Close() reader, err := apistate.ConnectStream("/path", nil) c.Assert(err, jc.ErrorIsNil) connectURL := connectURLFromReader(c, reader) c.Assert(connectURL.Path, gc.Matches, "/path") }
func (s *clientSuite) TestDebugLogRootPath(c *gc.C) { s.PatchValue(api.WebsocketDialConfig, echoURL(c)) // If the server is old, we log at "/log" info := s.APIInfo(c) info.EnvironTag = names.NewEnvironTag("") apistate, err := api.OpenWithVersion(info, api.DialOpts{}, 1) c.Assert(err, jc.ErrorIsNil) defer apistate.Close() reader, err := apistate.Client().WatchDebugLog(api.DebugLogParams{}) c.Assert(err, jc.ErrorIsNil) connectURL := connectURLFromReader(c, reader) c.Assert(connectURL.Path, gc.Matches, "/log") }
func (s *loginSuite) TestNonExistentEnvironment(c *gc.C) { info, cleanup := s.setupServerWithValidator(c, nil) defer cleanup() uuid, err := utils.NewUUID() c.Assert(err, jc.ErrorIsNil) info.EnvironTag = names.NewEnvironTag(uuid.String()) st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer st.Close() adminUser := s.AdminUserTag(c) err = st.Login(adminUser, "dummy-secret", "") expectedError := fmt.Sprintf("unknown environment: %q", uuid) c.Assert(err, gc.ErrorMatches, expectedError) }
func (s *NewAPIClientSuite) TestNoEnvironTagDoesntOverwriteCached(c *gc.C) { store := newConfigStore("noconfig", dummyStoreInfo) called := 0 // State returns a new set of APIHostPorts but not a new EnvironTag. We // shouldn't override the cached value with environ tag of "". expectState := mockedAPIState(mockedHostPort) apiOpen := func(apiInfo *api.Info, opts api.DialOpts) (juju.APIState, error) { checkCommonAPIInfoAttrs(c, apiInfo, opts) c.Check(apiInfo.EnvironTag, gc.Equals, names.NewEnvironTag(fakeUUID)) called++ return expectState, nil } mockStore := &storageWithWriteNotify{store: store} st, err := juju.NewAPIFromStore("noconfig", mockStore, apiOpen) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.Equals, expectState) c.Assert(called, gc.Equals, 1) c.Assert(mockStore.written, jc.IsTrue) info, err := store.ReadInfo("noconfig") c.Assert(err, jc.ErrorIsNil) ep := info.APIEndpoint() c.Check(ep.Addresses, gc.DeepEquals, []string{ "0.1.2.3:1234", "[2001:db8::1]:1234", }) c.Check(ep.EnvironUUID, gc.Equals, fakeUUID) // Now simulate prefer-ipv6: true s.PatchValue(juju.MaybePreferIPv6, func(_ configstore.EnvironInfo) bool { return true }) expectState = mockedAPIState(mockedHostPort | mockedPreferIPv6) st, err = juju.NewAPIFromStore("noconfig", mockStore, apiOpen) c.Assert(err, jc.ErrorIsNil) c.Assert(st, gc.Equals, expectState) c.Assert(called, gc.Equals, 2) c.Assert(mockStore.written, jc.IsTrue) info, err = store.ReadInfo("noconfig") c.Assert(err, jc.ErrorIsNil) ep = info.APIEndpoint() c.Check(ep.Addresses, gc.DeepEquals, []string{ "[2001:db8::1]:1234", "0.1.2.3:1234", }) c.Check(ep.EnvironUUID, gc.Equals, fakeUUID) }
func (s *firewallerSuite) TestWatchOpenedPorts(c *gc.C) { c.Assert(s.resources.Count(), gc.Equals, 0) s.openPorts(c) expectChanges := []string{ "0:juju-public", "2:juju-public", } fakeEnvTag := names.NewEnvironTag("deadbeef-deaf-face-feed-0123456789ab") args := addFakeEntities(params.Entities{Entities: []params.Entity{ {Tag: fakeEnvTag.String()}, {Tag: s.machines[0].Tag().String()}, {Tag: s.service.Tag().String()}, {Tag: s.units[0].Tag().String()}, }}) result, err := s.firewaller.WatchOpenedPorts(args) sort.Strings(result.Results[0].Changes) c.Assert(err, jc.ErrorIsNil) c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ Results: []params.StringsWatchResult{ {Changes: expectChanges, StringsWatcherId: "1"}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, {Error: apiservertesting.ErrUnauthorized}, }, }) // Verify the resource was registered and stop when done c.Assert(s.resources.Count(), gc.Equals, 1) c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") resource := s.resources.Get("1") defer statetesting.AssertStop(c, resource) // Check that the Watch has consumed the initial event ("returned" in // the Watch call) wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) wc.AssertNoChange() }