Beispiel #1
0
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,
			&registrationParams.nonce,
			&registrationParams.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, &registrationParams.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)
}
Beispiel #2
0
func (c *switchCommand) Run(ctx *cmd.Context) (resultErr error) {
	store := modelcmd.QualifyingClientStore{c.Store}

	// Get the current name for logging the transition or printing
	// the current controller/model.
	currentControllerName, err := store.CurrentController()
	if errors.IsNotFound(err) {
		currentControllerName = ""
	} else if err != nil {
		return errors.Trace(err)
	}
	if c.Target == "" {
		currentName, err := c.name(store, currentControllerName, true)
		if err != nil {
			return errors.Trace(err)
		}
		if currentName == "" {
			return errors.New("no currently specified model")
		}
		fmt.Fprintf(ctx.Stdout, "%s\n", currentName)
		return nil
	}
	currentName, err := c.name(store, currentControllerName, false)
	if err != nil {
		return errors.Trace(err)
	}

	var newName string
	defer func() {
		if resultErr != nil {
			return
		}
		logSwitch(ctx, currentName, &newName)
	}()

	// Switch is an alternative way of dealing with environments than using
	// the JUJU_MODEL environment setting, and as such, doesn't play too well.
	// If JUJU_MODEL is set we should report that as the current environment,
	// and not allow switching when it is set.
	if model := os.Getenv(osenv.JujuModelEnvKey); model != "" {
		return errors.Errorf("cannot switch when JUJU_MODEL is overriding the model (set to %q)", model)
	}

	// If the target identifies a controller, then set that as the current controller.
	var newControllerName = c.Target
	if _, err = store.ControllerByName(c.Target); err == nil {
		if newControllerName == currentControllerName {
			newName = currentName
			return nil
		} else {
			newName, err = c.name(store, newControllerName, false)
			if err != nil {
				return errors.Trace(err)
			}
			return errors.Trace(store.SetCurrentController(newControllerName))
		}
	} else if !errors.IsNotFound(err) {
		return errors.Trace(err)
	}

	// The target is not a controller, so check for a model with
	// the given name. The name can be qualified with the controller
	// name (<controller>:<model>), or unqualified; in the latter
	// case, the model must exist in the current controller.
	newControllerName, modelName := modelcmd.SplitModelName(c.Target)
	if newControllerName != "" {
		if _, err = store.ControllerByName(newControllerName); err != nil {
			return errors.Trace(err)
		}
	} else {
		if currentControllerName == "" {
			return unknownSwitchTargetError(c.Target)
		}
		newControllerName = currentControllerName
	}
	modelName, err = store.QualifiedModelName(newControllerName, modelName)
	if err != nil {
		return errors.Trace(err)
	}
	newName = modelcmd.JoinModelName(newControllerName, modelName)

	err = store.SetCurrentModel(newControllerName, modelName)
	if errors.IsNotFound(err) {
		// The model isn't known locally, so we must query the controller.
		if err := c.RefreshModels(store, newControllerName); err != nil {
			return errors.Annotate(err, "refreshing models cache")
		}
		err := store.SetCurrentModel(newControllerName, modelName)
		if errors.IsNotFound(err) {
			return unknownSwitchTargetError(c.Target)
		} else if err != nil {
			return errors.Trace(err)
		}
	} else if err != nil {
		return errors.Trace(err)
	}
	if currentControllerName != newControllerName {
		if err := store.SetCurrentController(newControllerName); err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}