// RefreshModels refreshes the local models cache for the current user // on the specified controller. func (c *JujuCommandBase) RefreshModels(store jujuclient.ClientStore, controllerName string) error { modelManager, err := c.modelAPI(store, controllerName) if err != nil { return errors.Trace(err) } defer modelManager.Close() accountDetails, err := store.AccountDetails(controllerName) if err != nil { return errors.Trace(err) } models, err := modelManager.ListModels(accountDetails.User) if err != nil { return errors.Trace(err) } for _, model := range models { modelDetails := jujuclient.ModelDetails{model.UUID} owner := names.NewUserTag(model.Owner) modelName := jujuclient.JoinOwnerModelName(owner, model.Name) if err := store.UpdateModel(controllerName, modelName, modelDetails); err != nil { return errors.Trace(err) } } return nil }
// decorateAndWriteInfo decorates the info struct with information // from the given cfg, and the writes that out to the filesystem. func decorateAndWriteInfo( store jujuclient.ClientStore, details prepareDetails, controllerName, modelName string, ) error { qualifiedModelName := jujuclient.JoinOwnerModelName( names.NewUserTag(details.AccountDetails.User), modelName, ) if err := store.AddController(controllerName, details.ControllerDetails); err != nil { return errors.Trace(err) } if err := store.UpdateBootstrapConfig(controllerName, details.BootstrapConfig); err != nil { return errors.Trace(err) } if err := store.UpdateAccount(controllerName, details.AccountDetails); err != nil { return errors.Trace(err) } if err := store.UpdateModel(controllerName, qualifiedModelName, details.ModelDetails); err != nil { return errors.Trace(err) } if err := store.SetCurrentModel(controllerName, qualifiedModelName); err != nil { return errors.Trace(err) } return nil }
// QualifiedModelName returns a Qualified model name, given either // an unqualified or qualified model name. If the input is a // fully qualified name, it is returned untouched; otherwise it is // return qualified with the logged-in user name. func (s QualifyingClientStore) QualifiedModelName(controllerName, modelName string) (string, error) { if !jujuclient.IsQualifiedModelName(modelName) { details, err := s.ClientStore.AccountDetails(controllerName) if err != nil { return "", errors.Annotate(err, "getting account details for qualifying model name") } owner := names.NewUserTag(details.User) modelName = jujuclient.JoinOwnerModelName(owner, modelName) } else { unqualifiedModelName, owner, err := jujuclient.SplitModelName(modelName) if err != nil { return "", errors.Trace(err) } owner = names.NewUserTag(owner.Id()) modelName = jujuclient.JoinOwnerModelName(owner, unqualifiedModelName) } return modelName, nil }
func (c *registerCommand) run(ctx *cmd.Context) error { store := modelcmd.QualifyingClientStore{c.store} registrationParams, err := c.getParameters(ctx, store) if err != nil { return errors.Trace(err) } controllerDetails, accountDetails, err := c.controllerDetails(ctx, registrationParams) if err != nil { return errors.Trace(err) } controllerName, err := c.updateController( ctx, store, registrationParams.defaultControllerName, controllerDetails, accountDetails, ) if err != nil { return errors.Trace(err) } // Log into the controller to verify the credentials, and // list the models available. models, err := c.listModelsFunc(store, controllerName, accountDetails.User) if err != nil { return errors.Trace(err) } for _, model := range models { owner := names.NewUserTag(model.Owner) if err := store.UpdateModel( controllerName, jujuclient.JoinOwnerModelName(owner, model.Name), jujuclient.ModelDetails{model.UUID}, ); err != nil { return errors.Annotate(err, "storing model details") } } if err := store.SetCurrentController(controllerName); err != nil { return errors.Trace(err) } fmt.Fprintf( ctx.Stderr, "\nWelcome, %s. You are now logged into %q.\n", friendlyUserName(accountDetails.User), controllerName, ) return c.maybeSetCurrentModel(ctx, store, controllerName, accountDetails.User, models) }
func (c *registerCommand) maybeSetCurrentModel(ctx *cmd.Context, store jujuclient.ClientStore, controllerName, userName string, models []base.UserModel) error { if len(models) == 0 { fmt.Fprintf(ctx.Stderr, "\n%s\n\n", errNoModels.Error()) return nil } // If we get to here, there is at least one model. if len(models) == 1 { // There is exactly one model shared, // so set it as the current model. model := models[0] owner := names.NewUserTag(model.Owner) modelName := jujuclient.JoinOwnerModelName(owner, model.Name) err := store.SetCurrentModel(controllerName, modelName) if err != nil { return errors.Trace(err) } fmt.Fprintf(ctx.Stderr, "\nCurrent model set to %q.\n\n", modelName) } else { fmt.Fprintf(ctx.Stderr, ` There are %d models available. Use "juju switch" to select one of them: `, len(models)) user := names.NewUserTag(userName) ownerModelNames := make(set.Strings) otherModelNames := make(set.Strings) for _, model := range models { if model.Owner == userName { ownerModelNames.Add(model.Name) continue } owner := names.NewUserTag(model.Owner) modelName := common.OwnerQualifiedModelName(model.Name, owner, user) otherModelNames.Add(modelName) } for _, modelName := range ownerModelNames.SortedValues() { fmt.Fprintf(ctx.Stderr, " - juju switch %s\n", modelName) } for _, modelName := range otherModelNames.SortedValues() { fmt.Fprintf(ctx.Stderr, " - juju switch %s\n", modelName) } fmt.Fprintln(ctx.Stderr) } return nil }
// formatTabular takes an interface{} to adhere to the cmd.Formatter interface func (c *modelsCommand) formatTabular(writer io.Writer, value interface{}) error { modelSet, ok := value.(ModelSet) if !ok { return errors.Errorf("expected value of type %T, got %T", modelSet, value) } // We need the tag of the user for which we're listing models, // and for the logged-in user. We use these below when formatting // the model display names. loggedInUser := names.NewUserTag(c.loggedInUser) userForLastConn := loggedInUser var userForListing names.UserTag if c.user != "" { userForListing = names.NewUserTag(c.user) userForLastConn = userForListing } tw := output.TabWriter(writer) w := output.Wrapper{tw} w.Println("Controller: " + c.ControllerName()) w.Println() w.Print("Model") if c.listUUID { w.Print("UUID") } // Only owners, or users with write access or above get to see machines and cores. haveMachineInfo := false for _, m := range modelSet.Models { if haveMachineInfo = len(m.Machines) > 0; haveMachineInfo { break } } if haveMachineInfo { w.Println("Owner", "Status", "Machines", "Cores", "Access", "Last connection") offset := 0 if c.listUUID { offset++ } tw.SetColumnAlignRight(3 + offset) tw.SetColumnAlignRight(4 + offset) } else { w.Println("Owner", "Status", "Access", "Last connection") } for _, model := range modelSet.Models { owner := names.NewUserTag(model.Owner) name := common.OwnerQualifiedModelName(model.Name, owner, userForListing) if jujuclient.JoinOwnerModelName(owner, model.Name) == modelSet.CurrentModelQualified { name += "*" w.PrintColor(output.CurrentHighlight, name) } else { w.Print(name) } if c.listUUID { w.Print(model.UUID) } lastConnection := model.Users[userForLastConn.Id()].LastConnection if lastConnection == "" { lastConnection = "never connected" } userForAccess := loggedInUser if c.user != "" { userForAccess = names.NewUserTag(c.user) } access := model.Users[userForAccess.Id()].Access w.Print(model.Owner, model.Status.Current) if haveMachineInfo { machineInfo := fmt.Sprintf("%d", len(model.Machines)) cores := uint64(0) for _, m := range model.Machines { cores += m.Cores } coresInfo := "-" if cores > 0 { coresInfo = fmt.Sprintf("%d", cores) } w.Print(machineInfo, coresInfo) } w.Println(access, lastConnection) } tw.Flush() return nil }
func (c *registerCommand) Run(ctx *cmd.Context) error { store := modelcmd.QualifyingClientStore{c.store} registrationParams, err := c.getParameters(ctx, store) if err != nil { return errors.Trace(err) } _, err = store.ControllerByName(registrationParams.controllerName) if err == nil { return errors.AlreadyExistsf("controller %q", registrationParams.controllerName) } else if !errors.IsNotFound(err) { return errors.Trace(err) } // During registration we must set a new password. This has to be done // atomically with the clearing of the secret key. payloadBytes, err := json.Marshal(params.SecretKeyLoginRequestPayload{ registrationParams.newPassword, }) if err != nil { return errors.Trace(err) } // Make the registration call. If this is successful, the client's // cookie jar will be populated with a macaroon that may be used // to log in below without the user having to type in the password // again. req := params.SecretKeyLoginRequest{ Nonce: registrationParams.nonce[:], User: registrationParams.userTag.String(), PayloadCiphertext: secretbox.Seal( nil, payloadBytes, ®istrationParams.nonce, ®istrationParams.key, ), } resp, err := c.secretKeyLogin(registrationParams.controllerAddrs, req) if err != nil { return errors.Trace(err) } // Decrypt the response to authenticate the controller and // obtain its CA certificate. if len(resp.Nonce) != len(registrationParams.nonce) { return errors.NotValidf("response nonce") } var respNonce [24]byte copy(respNonce[:], resp.Nonce) payloadBytes, ok := secretbox.Open(nil, resp.PayloadCiphertext, &respNonce, ®istrationParams.key) if !ok { return errors.NotValidf("response payload") } var responsePayload params.SecretKeyLoginResponsePayload if err := json.Unmarshal(payloadBytes, &responsePayload); err != nil { return errors.Annotate(err, "unmarshalling response payload") } // Store the controller and account details. controllerDetails := jujuclient.ControllerDetails{ APIEndpoints: registrationParams.controllerAddrs, ControllerUUID: responsePayload.ControllerUUID, CACert: responsePayload.CACert, } if err := store.AddController(registrationParams.controllerName, controllerDetails); err != nil { return errors.Trace(err) } accountDetails := jujuclient.AccountDetails{ User: registrationParams.userTag.Canonical(), LastKnownAccess: string(permission.LoginAccess), } if err := store.UpdateAccount(registrationParams.controllerName, accountDetails); err != nil { return errors.Trace(err) } // Log into the controller to verify the credentials, and // list the models available. models, err := c.listModelsFunc(store, registrationParams.controllerName, accountDetails.User) if err != nil { return errors.Trace(err) } for _, model := range models { owner := names.NewUserTag(model.Owner) if err := store.UpdateModel( registrationParams.controllerName, jujuclient.JoinOwnerModelName(owner, model.Name), jujuclient.ModelDetails{model.UUID}, ); err != nil { return errors.Annotate(err, "storing model details") } } if err := store.SetCurrentController(registrationParams.controllerName); err != nil { return errors.Trace(err) } fmt.Fprintf( ctx.Stderr, "\nWelcome, %s. You are now logged into %q.\n", registrationParams.userTag.Id(), registrationParams.controllerName, ) return c.maybeSetCurrentModel(ctx, store, registrationParams.controllerName, accountDetails.User, models) }