// InitiateModelMigration attempts to start a migration for the // specified model, returning the migration's ID. // // The API server supports starting multiple migrations in one request // but we don't need that at the client side yet (and may never) so // this call just supports starting one migration at a time. func (c *Client) InitiateModelMigration(spec ModelMigrationSpec) (string, error) { if err := spec.Validate(); err != nil { return "", errors.Trace(err) } args := params.InitiateModelMigrationArgs{ Specs: []params.ModelMigrationSpec{{ ModelTag: names.NewModelTag(spec.ModelUUID).String(), TargetInfo: params.ModelMigrationTargetInfo{ ControllerTag: names.NewModelTag(spec.TargetControllerUUID).String(), Addrs: spec.TargetAddrs, CACert: spec.TargetCACert, AuthTag: names.NewUserTag(spec.TargetUser).String(), Password: spec.TargetPassword, }, }}, } response := params.InitiateModelMigrationResults{} if err := c.facade.FacadeCall("InitiateModelMigration", args, &response); err != nil { return "", errors.Trace(err) } if len(response.Results) != 1 { return "", errors.New("unexpected number of results returned") } result := response.Results[0] if result.Error != nil { return "", errors.Trace(result.Error) } return result.Id, nil }
func (s *apiclientSuite) TestOpenHonorsModelTag(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 ModelTag. // c.Check(info.ModelTag, gc.Equals, env.Tag()) // c.Assert(info.ModelTag, gc.Not(gc.Equals), "") // We start by ensuring we have an invalid tag, and Open should fail. info.ModelTag = names.NewModelTag("bad-tag") _, err := api.Open(info, api.DialOpts{}) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: `unknown model: "bad-tag"`, Code: "not found", }) c.Check(params.ErrCode(err), gc.Equals, params.CodeNotFound) // Now set it to the right tag, and we should succeed. info.ModelTag = s.State.ModelTag() 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 // model tag info.ModelTag = names.NewModelTag("") st, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) st.Close() }
func (s *clientSuite) TestOpenUsesEnvironUUIDPaths(c *gc.C) { info := s.APIInfo(c) // Backwards compatibility, passing ModelTag = "" should just work info.ModelTag = names.NewModelTag("") apistate, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in the correct model UUID should also work environ, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) info.ModelTag = environ.ModelTag() apistate, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in a bad model UUID should fail with a known error info.ModelTag = names.NewModelTag("dead-beef-123456") apistate, err = api.Open(info, api.DialOpts{}) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: `unknown model: "dead-beef-123456"`, Code: "not found", }) c.Check(err, jc.Satisfies, params.IsCodeNotFound) c.Assert(apistate, gc.IsNil) }
func (*tagsSuite) TestResourceTagsUUID(c *gc.C) { testResourceTags(c, testing.ModelTag, names.NewModelTag(""), nil, map[string]string{ "juju-model-uuid": testing.ModelTag.Id(), "juju-controller-uuid": "", }) testResourceTags(c, names.NewModelTag(""), testing.ModelTag, nil, map[string]string{ "juju-model-uuid": "", "juju-controller-uuid": testing.ModelTag.Id(), }) }
// 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 { instanceTags := tags.ResourceTags( names.NewModelTag(cfg.UUID()), names.NewModelTag(cfg.ControllerUUID()), cfg, ) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuIsController] = "true" } return instanceTags }
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) modelUUID := uuid.String() w := presence.NewWatcher(s.presence, names.NewModelTag(modelUUID)) p := presence.NewPinger(s.presence, names.NewModelTag(modelUUID), key) ch := make(chan presence.Change) w.Watch(key, ch) assertChange(c, ch, presence.Change{key, false}) return w, p, ch }
// initResourceGroup creates and initialises a resource group for this // environment. The resource group will have a storage account and a // subnet associated with it (but not necessarily contained within: // see subnet creation). func (env *azureEnviron) initResourceGroup() (*config.Config, error) { location := env.config.location tags := tags.ResourceTags( names.NewModelTag(env.config.Config.UUID()), names.NewModelTag(env.config.Config.ControllerUUID()), env.config, ) resourceGroupsClient := resources.GroupsClient{env.resources} logger.Debugf("creating resource group %q", env.resourceGroup) _, err := resourceGroupsClient.CreateOrUpdate(env.resourceGroup, resources.Group{ Location: to.StringPtr(location), Tags: toTagsPtr(tags), }) if err != nil { return nil, errors.Annotate(err, "creating resource group") } // Create an internal network for all VMs in the // resource group to connect to. vnetPtr, err := createInternalVirtualNetwork( env.network, env.resourceGroup, location, tags, ) if err != nil { return nil, errors.Annotate(err, "creating virtual network") } _, err = createInternalSubnet( env.network, env.resourceGroup, vnetPtr, location, tags, ) if err != nil { return nil, errors.Annotate(err, "creating subnet") } // Create a storage account for the resource group. storageAccountsClient := storage.AccountsClient{env.storage} storageAccountName, storageAccountKey, err := createStorageAccount( storageAccountsClient, env.config.storageAccountType, env.resourceGroup, location, tags, env.provider.config.StorageAccountNameGenerator, ) if err != nil { return nil, errors.Annotate(err, "creating storage account") } return env.config.Config.Apply(map[string]interface{}{ configAttrStorageAccount: storageAccountName, configAttrStorageAccountKey: storageAccountKey, }) }
// 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) { storageTags := tags.ResourceTags( names.NewModelTag(cfg.UUID()), names.NewModelTag(cfg.ControllerUUID()), cfg, ) if storageInstance != nil { storageTags[tags.JujuStorageInstance] = storageInstance.Tag().Id() storageTags[tags.JujuStorageOwner] = storageInstance.Owner().Id() } return storageTags, nil }
func (s *ModelMigrationSuite) SetUpTest(c *gc.C) { s.ConnSuite.SetUpTest(c) s.clock = coretesting.NewClock(time.Now().Truncate(time.Second)) s.PatchValue(&state.GetClock, func() clock.Clock { return s.clock }) // Create a hosted model to migrate. s.State2 = s.Factory.MakeModel(c, nil) s.AddCleanup(func(*gc.C) { s.State2.Close() }) targetControllerTag := names.NewModelTag(utils.MustNewUUID().String()) // Plausible migration arguments to test with. s.stdSpec = state.ModelMigrationSpec{ InitiatedBy: names.NewUserTag("admin"), TargetInfo: migration.TargetInfo{ ControllerTag: targetControllerTag, Addrs: []string{"1.2.3.4:5555", "4.3.2.1:6666"}, CACert: "cert", AuthTag: names.NewUserTag("user"), Password: "******", }, } }
func (s *ClientSuite) TestActivate(c *gc.C) { client, stub := s.getClientAndStub(c) uuid := "fake" err := client.Activate(uuid) s.AssertModelCall(c, stub, names.NewModelTag(uuid), "Activate", err) }
// newState returns a new State that uses the given environment. // The environment must have already been bootstrapped. func newState(environ environs.Environ, mongoInfo *mongo.MongoInfo) (*state.State, error) { config := environ.Config() password := config.AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect without admin-secret") } modelTag := names.NewModelTag(config.UUID()) mongoInfo.Password = password opts := mongo.DefaultDialOpts() st, err := state.Open(modelTag, mongoInfo, opts, environs.NewStatePolicy()) if errors.IsUnauthorized(errors.Cause(err)) { // We try for a while because we might succeed in // connecting to mongo before the state has been // initialized and the initial password set. for a := redialStrategy.Start(); a.Next(); { st, err = state.Open(modelTag, mongoInfo, opts, environs.NewStatePolicy()) if !errors.IsUnauthorized(errors.Cause(err)) { break } } if err != nil { return nil, err } } else if err != nil { return nil, err } if err := updateSecrets(environ, st); err != nil { st.Close() return nil, fmt.Errorf("unable to push secrets: %v", 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.ControllerInstances() if err != nil { return nil, err } logger.Debugf("ControllerInstances returned: %v", instanceIds) addrs, err := waitAnyInstanceAddresses(env, instanceIds) if err != nil { return nil, err } defaultSpaceAddr, ok := network.SelectAddressBySpace(addrs, network.DefaultSpace) if ok { addrs = []network.Address{defaultSpaceAddr} logger.Debugf("selected %q as API address in space %q", defaultSpaceAddr.Value, network.DefaultSpace) } else { logger.Warningf("using all API addresses (cannot pick by space %q): %+v", network.DefaultSpace, addrs) } 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") } modelTag := names.NewModelTag(uuid) apiInfo := &api.Info{Addrs: apiAddrs, CACert: cert, ModelTag: modelTag} return apiInfo, nil }
func (s *Suite) TestMigration(c *gc.C) { masterClient := newStubMasterClient(s.stub) w := migrationmaster.New(masterClient) // Trigger migration. masterClient.watcher.changes <- migration.TargetInfo{ ControllerTag: names.NewModelTag("uuid"), Addrs: []string{"1.2.3.4:5"}, CACert: "cert", AuthTag: names.NewUserTag("admin"), Password: "******", } // This error is temporary while migrationmaster is a WIP. runWorkerAndWait(c, w, "migration seen and aborted") // Observe that the migration was seen, the model exported, an API // connection to the target controller was made, the model was // imported and then the migration aborted. s.stub.CheckCalls(c, []jujutesting.StubCall{ {"masterClient.Watch", nil}, {"masterClient.Export", nil}, {"apiOpen", []interface{}{&api.Info{ Addrs: []string{"1.2.3.4:5"}, CACert: "cert", Tag: names.NewUserTag("admin"), Password: "******", }, api.DefaultDialOpts()}}, {"APICall:MigrationTarget.Import", []interface{}{params.SerializedModel{Bytes: fakeSerializedModel}}}, {"masterClient.SetPhase", []interface{}{migration.ABORT}}, {"Connection.Close", nil}, }) }
func (c *modelsCommand) getModelInfo(userModels []base.UserModel) ([]params.ModelInfo, error) { client, err := c.getModelManagerAPI() if err != nil { return nil, errors.Trace(err) } defer client.Close() tags := make([]names.ModelTag, len(userModels)) for i, m := range userModels { tags[i] = names.NewModelTag(m.UUID) } results, err := client.ModelInfo(tags) if err != nil { return nil, errors.Trace(err) } info := make([]params.ModelInfo, len(tags)) for i, result := range results { if result.Error != nil { if params.IsCodeUnauthorized(result.Error) { // If we get this, then the model was removed // between the initial listing and the call // to query its details. continue } return nil, errors.Annotatef( result.Error, "getting model %s (%q) info", userModels[i].UUID, userModels[i].Name, ) } info[i] = *result.Result } return info, nil }
// ModelsForUser returns a list of models that the user // is able to access. func (st *State) ModelsForUser(user names.UserTag) ([]*UserModel, error) { // Since there are no groups at this stage, the simplest way to get all // the models that a particular user can see is to look through the // model user collection. A raw collection is required to support // queries across multiple models. modelUsers, userCloser := st.getRawCollection(modelUsersC) defer userCloser() // TODO: consider adding an index to the modelUsers collection on the username. var userSlice []modelUserDoc err := modelUsers.Find(bson.D{{"user", user.Canonical()}}).Select(bson.D{{"model-uuid", 1}, {"_id", 1}}).All(&userSlice) if err != nil { return nil, err } var result []*UserModel for _, doc := range userSlice { modelTag := names.NewModelTag(doc.ModelUUID) env, err := st.GetModel(modelTag) if err != nil { return nil, errors.Trace(err) } result = append(result, &UserModel{Model: env, User: user}) } return result, nil }
// Run implements Command.Run. func (c *showModelCommand) Run(ctx *cmd.Context) (err error) { api, err := c.getAPI() if err != nil { return err } defer api.Close() store := c.ClientStore() modelDetails, err := store.ModelByName( c.ControllerName(), c.AccountName(), c.ModelName(), ) if err != nil { return errors.Annotate(err, "getting model details") } modelTag := names.NewModelTag(modelDetails.ModelUUID) results, err := api.ModelInfo([]names.ModelTag{modelTag}) if err != nil { return err } if results[0].Error != nil { return results[0].Error } infoMap, err := c.apiModelInfoToModelInfoMap([]params.ModelInfo{*results[0].Result}) if err != nil { return errors.Trace(err) } return c.out.Write(ctx, infoMap) }
func (s *controllerSuite) TestAllModels(c *gc.C) { admin := s.Factory.MakeUser(c, &factory.UserParams{Name: "foobar"}) s.Factory.MakeModel(c, &factory.ModelParams{ Name: "owned", Owner: admin.UserTag()}).Close() remoteUserTag := names.NewUserTag("user@remote") st := s.Factory.MakeModel(c, &factory.ModelParams{ Name: "user", Owner: remoteUserTag}) defer st.Close() st.AddModelUser(state.ModelUserSpec{ User: admin.UserTag(), CreatedBy: remoteUserTag, DisplayName: "Foo Bar"}) s.Factory.MakeModel(c, &factory.ModelParams{ Name: "no-access", Owner: remoteUserTag}).Close() response, err := s.controller.AllModels() c.Assert(err, jc.ErrorIsNil) // The results are sorted. expected := []string{"dummymodel", "no-access", "owned", "user"} var obtained []string for _, env := range response.UserModels { obtained = append(obtained, env.Name) stateEnv, err := s.State.GetModel(names.NewModelTag(env.UUID)) c.Assert(err, jc.ErrorIsNil) s.checkEnvironmentMatches(c, env.Model, stateEnv) } c.Assert(obtained, jc.DeepEquals, expected) }
// 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 modelTag names.ModelTag if names.IsValidModel(endpoint.ModelUUID) { modelTag = names.NewModelTag(endpoint.ModelUUID) } apiInfo := &api.Info{ Addrs: endpoint.Addresses, CACert: endpoint.CACert, Tag: environInfoUserTag(info), Password: info.APICredentials().Password, ModelTag: modelTag, } 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 }
func (c *MigrateCommand) exportModel(ctx *cmd.Context, st *state.State) error { ctx.Infof("\nexport %s", c.modelUUID) // first make sure the uuid is good enough tag := names.NewModelTag(c.modelUUID) _, err := st.GetModel(tag) if err != nil { return errors.Trace(err) } modelState, err := st.ForModel(tag) if err != nil { return errors.Trace(err) } defer modelState.Close() model, err := modelState.Export() if err != nil { return errors.Trace(err) } bytes, err := yaml.Marshal(model) if err != nil { return errors.Trace(err) } ctx.Stdout.Write(bytes) return 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.ControllerInstances() if err != nil { return nil, err } logger.Debugf("ControllerInstances 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") } modelTag := names.NewModelTag(uuid) apiInfo := &api.Info{Addrs: apiAddrs, CACert: cert, ModelTag: modelTag} return apiInfo, 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.modelTag = names.NewModelTag(uuid.String()) }
// validateModelUUID is the common validator for the various // apiserver components that need to check for a valid model // UUID. An empty modelUUID means that the connection has come in at // the root of the URL space and refers to the controller // model. // // It returns the validated model UUID. func validateModelUUID(args validateArgs) (string, error) { ssState := args.statePool.SystemState() if args.modelUUID == "" { // We allow the modelUUID to be empty for 2 cases // 1) Compatibility with older clients // 2) TODO: server a limited API at the root (empty modelUUID) // with just the user manager and model manager // if the connection comes over a sufficiently up to date // login command. if args.strict { return "", errors.Trace(common.UnknownModelError(args.modelUUID)) } logger.Debugf("validate model uuid: empty modelUUID") return ssState.ModelUUID(), nil } if args.modelUUID == ssState.ModelUUID() { logger.Debugf("validate model uuid: controller model - %s", args.modelUUID) return args.modelUUID, nil } if args.controllerModelOnly { return "", errors.Unauthorizedf("requested model %q is not the controller model", args.modelUUID) } if !names.IsValidModel(args.modelUUID) { return "", errors.Trace(common.UnknownModelError(args.modelUUID)) } modelTag := names.NewModelTag(args.modelUUID) if _, err := ssState.GetModel(modelTag); err != nil { return "", errors.Wrap(err, common.UnknownModelError(args.modelUUID)) } logger.Debugf("validate model uuid: %s", args.modelUUID) return args.modelUUID, nil }
// 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) } modelUUID, err := st.ModelUUID() 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, ModelTag: names.NewModelTag(modelUUID), } return &simpleAuth{stateInfo, apiInfo}, nil }
func (s *macaroonLoginSuite) SetUpTest(c *gc.C) { s.MacaroonSuite.SetUpTest(c) s.MacaroonSuite.AddModelUser(c, testUser) s.controllerName = "my-controller" s.accountName = "my@account" s.modelName = "my-model" modelTag := names.NewModelTag(s.State.ModelUUID()) apiInfo := s.APIInfo(c) s.store = jujuclienttesting.NewMemStore() s.store.Controllers[s.controllerName] = jujuclient.ControllerDetails{ APIEndpoints: apiInfo.Addrs, ControllerUUID: apiInfo.ModelTag.Id(), CACert: apiInfo.CACert, } s.store.Accounts[s.controllerName] = &jujuclient.ControllerAccounts{ Accounts: map[string]jujuclient.AccountDetails{ // Empty password forces use of macaroons. s.accountName: {User: s.accountName}, }, CurrentAccount: s.accountName, } s.store.Models[s.controllerName] = jujuclient.ControllerAccountModels{ AccountModels: map[string]*jujuclient.AccountModels{ s.accountName: { Models: map[string]jujuclient.ModelDetails{ s.modelName: {modelTag.Id()}, }, }, }, } }
func (s *migrationWatcherSuite) TestWatch(c *gc.C) { // Create a state server m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{ Jobs: []state.MachineJob{state.JobManageModel}, Nonce: "noncey", }) // Create a model to migrate. hostedState := s.Factory.MakeModel(c, nil) // Connect as a state server to the hosted environment. apiInfo := s.APIInfo(c) apiInfo.Tag = m.Tag() apiInfo.Password = password apiInfo.ModelTag = hostedState.ModelTag() apiInfo.Nonce = "noncey" apiConn, err := api.Open(apiInfo, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer apiConn.Close() // Start watching for a migration. client := migrationmaster.NewClient(apiConn) w, err := client.Watch() c.Assert(err, jc.ErrorIsNil) defer func() { c.Assert(worker.Stop(w), jc.ErrorIsNil) }() // Should be no initial events. select { case _, ok := <-w.Changes(): c.Fatalf("watcher sent unexpected change: (_, %v)", ok) case <-time.After(coretesting.ShortWait): } // Now create a migration. targetInfo := migration.TargetInfo{ ControllerTag: names.NewModelTag(utils.MustNewUUID().String()), Addrs: []string{"1.2.3.4:5"}, CACert: "trust me I'm an authority", AuthTag: names.NewUserTag("dog"), Password: "******", } _, err = hostedState.CreateModelMigration(state.ModelMigrationSpec{ InitiatedBy: names.NewUserTag("someone"), TargetInfo: targetInfo, }) c.Assert(err, jc.ErrorIsNil) // Event with correct target details should be emitted. select { case reportedTargetInfo, ok := <-w.Changes(): c.Assert(ok, jc.IsTrue) c.Assert(reportedTargetInfo, jc.DeepEquals, targetInfo) case <-time.After(coretesting.LongWait): c.Fatalf("watcher didn't emit an event") } }
// NewModel creates a new model with its own UUID and // prepares it for use. Model and State instances for the new // model are returned. // // The controller model's UUID is attached to the new // model's document. Having the server UUIDs stored with each // model document means that we have a way to represent external // models, perhaps for future use around cross model // relations. func (st *State) NewModel(cfg *config.Config, owner names.UserTag) (_ *Model, _ *State, err error) { if owner.IsLocal() { if _, err := st.User(owner); err != nil { return nil, nil, errors.Annotate(err, "cannot create model") } } ssEnv, err := st.ControllerModel() if err != nil { return nil, nil, errors.Annotate(err, "could not load controller model") } uuid := cfg.UUID() newState, err := st.ForModel(names.NewModelTag(uuid)) if err != nil { return nil, nil, errors.Annotate(err, "could not create state for new model") } defer func() { if err != nil { newState.Close() } }() ops, err := newState.envSetupOps(cfg, uuid, ssEnv.UUID(), owner) if err != nil { return nil, nil, errors.Annotate(err, "failed to create new model") } err = newState.runTransaction(ops) if err == txn.ErrAborted { // We have a unique key restriction on the "owner" and "name" fields, // which will cause the insert to fail if there is another record with // the same "owner" and "name" in the collection. If the txn is // aborted, check if it is due to the unique key restriction. models, closer := st.getCollection(modelsC) defer closer() envCount, countErr := models.Find(bson.D{ {"owner", owner.Canonical()}, {"name", cfg.Name()}}, ).Count() if countErr != nil { err = errors.Trace(countErr) } else if envCount > 0 { err = errors.AlreadyExistsf("model %q for %s", cfg.Name(), owner.Canonical()) } else { err = errors.New("model already exists") } } if err != nil { return nil, nil, errors.Trace(err) } newEnv, err := newState.Model() if err != nil { return nil, nil, errors.Trace(err) } return newEnv, newState, nil }
// 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.NewModelTag(uuid), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuStateServer] = "true" } return instanceTags }
// APIInfo is part of the agent.Config interface. This implementation always // replaces the target model tag with the configured model tag. func (c *modelAgentConfig) APIInfo() (*api.Info, bool) { info, ok := c.Config.APIInfo() if !ok { return nil, false } info.ModelTag = names.NewModelTag(c.uuid) return info, true }
func (s *apiclientSuite) TestConnectWebsocketToRoot(c *gc.C) { info := s.APIInfo(c) info.ModelTag = names.NewModelTag("") conn, _, err := api.ConnectWebsocket(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer conn.Close() assertConnAddrForRoot(c, conn, info.Addrs[0]) }
func (s *modelManagerSuite) TestGrantMissingModelFails(c *gc.C) { s.setAPIUser(c, s.AdminUserTag(c)) user := s.Factory.MakeModelUser(c, nil) model := names.NewModelTag("17e4bd2d-3e08-4f3d-b945-087be7ebdce4") err := s.grant(c, user.UserTag(), params.ModelReadAccess, model) expectedErr := `model not found` c.Assert(err, gc.ErrorMatches, expectedErr) }