Beispiel #1
0
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed
// in a user-friendly manner with readable and digestable error message.
func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error {
	if destroyErr == nil {
		return nil
	}
	if params.IsCodeOperationBlocked(destroyErr) {
		logger.Errorf(destroyControllerBlockedMsg)
		if api != nil {
			models, err := api.ListBlockedModels()
			out := &bytes.Buffer{}
			if err == nil {
				var info interface{}
				info, err = block.FormatModelBlockInfo(models)
				if err != nil {
					return errors.Trace(err)
				}
				err = block.FormatTabularBlockedModels(out, info)
			}
			if err != nil {
				logger.Errorf("Unable to list models: %s", err)
				return cmd.ErrSilent
			}
			ctx.Infof(out.String())
		}
		return cmd.ErrSilent
	}
	if params.IsCodeHasHostedModels(destroyErr) {
		return destroyErr
	}
	logger.Errorf(stdFailureMsg, c.ControllerName())
	return destroyErr
}
Beispiel #2
0
func (c *setDefaultRegionCommand) Run(ctxt *cmd.Context) error {
	cloudDetails, err := cloudOrProvider(c.cloud, jujucloud.CloudByName)
	if err != nil {
		return err
	}
	if len(cloudDetails.Regions) == 0 {
		return errors.Errorf("cloud %s has no regions", c.cloud)
	}
	if !hasRegion(c.region, cloudDetails.Regions) {
		var regionNames []string
		for _, r := range cloudDetails.Regions {
			regionNames = append(regionNames, r.Name)
		}
		return errors.NewNotValid(
			nil,
			fmt.Sprintf("region %q for cloud %s not valid, valid regions are %s",
				c.region, c.cloud, strings.Join(regionNames, ", ")))
	}
	var cred *jujucloud.CloudCredential
	cred, err = c.store.CredentialForCloud(c.cloud)
	if errors.IsNotFound(err) {
		cred = &jujucloud.CloudCredential{}
	} else if err != nil {
		return err
	}
	cred.DefaultRegion = c.region
	if err := c.store.UpdateCredential(c.cloud, *cred); err != nil {
		return err
	}
	ctxt.Infof("Default region in %s set to %q.", c.cloud, c.region)
	return nil
}
Beispiel #3
0
func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) {
	store, err := configstore.Default()
	if err != nil {
		return fmt.Errorf("cannot open environment info storage: %v", err)
	}
	environ, err := environs.NewFromName(c.envName, store)
	if err != nil {
		if environs.IsEmptyConfig(err) {
			// Delete the .jenv file and call it done.
			ctx.Infof("removing empty environment file")
			return environs.DestroyInfo(c.envName, store)
		}
		return err
	}
	if !c.assumeYes {
		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, environ.Name(), environ.Config().Type())

		scanner := bufio.NewScanner(ctx.Stdin)
		scanner.Scan()
		err := scanner.Err()
		if err != nil && err != io.EOF {
			return fmt.Errorf("Environment destruction aborted: %s", err)
		}
		answer := strings.ToLower(scanner.Text())
		if answer != "y" && answer != "yes" {
			return errors.New("environment destruction aborted")
		}
	}
	// If --force is supplied, then don't attempt to use the API.
	// This is necessary to destroy broken environments, where the
	// API server is inaccessible or faulty.
	if !c.force {
		defer func() {
			if result == nil {
				return
			}
			logger.Errorf(`failed to destroy environment %q
        
If the environment is unusable, then you may run

    juju destroy-environment --force

to forcefully destroy the environment. Upon doing so, review
your environment provider console for any resources that need
to be cleaned up.

`, c.envName)
		}()
		apiclient, err := juju.NewAPIClientFromName(c.envName)
		if err != nil {
			return fmt.Errorf("cannot connect to API: %v", err)
		}
		defer apiclient.Close()
		err = apiclient.DestroyEnvironment()
		if err != nil && !params.IsCodeNotImplemented(err) {
			return fmt.Errorf("destroying environment: %v", err)
		}
	}
	return environs.Destroy(environ, store)
}
Beispiel #4
0
// Run implements Command.Run.
func (c *changePasswordCommand) Run(ctx *cmd.Context) error {
	if c.api == nil {
		api, err := c.NewUserManagerAPIClient()
		if err != nil {
			return errors.Trace(err)
		}
		c.api = api
		defer c.api.Close()
	}

	password, err := c.generateOrReadPassword(ctx, c.Generate)
	if err != nil {
		return errors.Trace(err)
	}

	var writer EnvironInfoCredsWriter

	var creds configstore.APICredentials

	if c.User == "" {
		// We get the creds writer before changing the password just to
		// minimise the things that could go wrong after changing the password
		// in the server.
		if c.writer == nil {
			writer, err = c.ConnectionInfo()
			if err != nil {
				return errors.Trace(err)
			}
		} else {
			writer = c.writer
		}

		creds = writer.APICredentials()
	} else {
		creds.User = c.User
	}

	oldPassword := creds.Password
	creds.Password = password
	if err = c.api.SetPassword(creds.User, password); err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}

	if c.User != "" {
		return writeServerFile(c, ctx, c.User, password, c.OutPath)
	}

	writer.SetAPICredentials(creds)
	if err := writer.Write(); err != nil {
		logger.Errorf("updating the cached credentials failed, reverting to original password")
		setErr := c.api.SetPassword(creds.User, oldPassword)
		if setErr != nil {
			logger.Errorf("failed to set password back, you will need to edit your environments file by hand to specify the password: %q", password)
			return errors.Annotate(setErr, "failed to set password back")
		}
		return errors.Annotate(err, "failed to write new password to environments file")
	}
	ctx.Infof("Your password has been updated.")
	return nil
}
Beispiel #5
0
// Run implements Command.Run.
func (c *listKeysCommand) Run(context *cmd.Context) error {
	client, err := c.NewKeyManagerClient()
	if err != nil {
		return err
	}
	defer client.Close()

	mode := ssh.Fingerprints
	if c.showFullKey {
		mode = ssh.FullKeys
	}
	// TODO(alexisb) - currently keys are global which is not ideal.
	// keymanager needs to be updated to allow keys per user
	c.user = "******"
	results, err := client.ListKeys(mode, c.user)
	if err != nil {
		return err
	}
	result := results[0]
	if result.Error != nil {
		return result.Error
	}
	if len(result.Result) == 0 {
		context.Infof("No keys to display.")
		return nil
	}
	fmt.Fprintf(context.Stdout, "Keys used in model: %s\n", c.ConnectionName())
	fmt.Fprintln(context.Stdout, strings.Join(result.Result, "\n"))
	return nil
}
Beispiel #6
0
Datei: add.go Projekt: bac/juju
// Run implements Command.Run.
func (c *addCommand) Run(ctx *cmd.Context) error {
	return c.RunWithAPI(ctx, func(api SpaceAPI, ctx *cmd.Context) error {
		// Prepare a nicer message and proper arguments to use in case
		// there are not CIDRs given.
		var subnetIds []string
		msgSuffix := "no subnets"
		if !c.CIDRs.IsEmpty() {
			subnetIds = c.CIDRs.SortedValues()
			msgSuffix = fmt.Sprintf("subnets %s", strings.Join(subnetIds, ", "))
		}

		// Add the new space.
		// TODO(dimitern): Accept --public|--private and pass it here.
		err := api.AddSpace(c.Name, subnetIds, true)
		if err != nil {
			if errors.IsNotSupported(err) {
				ctx.Infof("cannot add space %q: %v", c.Name, err)
			}
			if params.IsCodeUnauthorized(err) {
				common.PermissionsMessage(ctx.Stderr, "add a space")
			}
			return errors.Annotatef(err, "cannot add space %q", c.Name)
		}

		ctx.Infof("added space %q with %s", c.Name, msgSuffix)
		return nil
	})
}
Beispiel #7
0
// addCharmViaAPI calls the appropriate client API calls to add the
// given charm URL to state. Also displays the charm URL of the added
// charm on stdout.
func addCharmViaAPI(client *api.Client, ctx *cmd.Context, curl *charm.URL, repo charm.Repository) (*charm.URL, error) {
	if curl.Revision < 0 {
		latest, err := charm.Latest(repo, curl)
		if err != nil {
			return nil, err
		}
		curl = curl.WithRevision(latest)
	}
	switch curl.Schema {
	case "local":
		ch, err := repo.Get(curl)
		if err != nil {
			return nil, err
		}
		stateCurl, err := client.AddLocalCharm(curl, ch)
		if err != nil {
			return nil, err
		}
		curl = stateCurl
	case "cs":
		err := client.AddCharm(curl)
		if err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("unsupported charm URL schema: %q", curl.Schema)
	}
	ctx.Infof("Added charm %q to the environment.", curl)
	return curl, nil
}
Beispiel #8
0
// Run implements Command.Run.
func (c *listAgreementsCommand) Run(ctx *cmd.Context) error {
	client, err := c.BakeryClient()
	if err != nil {
		return errors.Annotate(err, "failed to create an http client")
	}

	apiClient, err := newClient(client)
	if err != nil {
		return errors.Annotate(err, "failed to create a terms API client")
	}

	agreements, err := apiClient.GetUsersAgreements()
	if err != nil {
		return errors.Annotate(err, "failed to list user agreements")
	}
	if len(agreements) == 0 {
		ctx.Infof("No agreements to display.")
		return nil
	}
	err = c.out.Write(ctx, agreements)
	if err != nil {
		return errors.Mask(err)
	}
	return nil
}
Beispiel #9
0
func writeServerFile(endpointProvider EndpointProvider, ctx *cmd.Context, username, password, outPath string) error {
	outPath = ctx.AbsPath(outPath)
	endpoint, err := endpointProvider.ConnectionEndpoint()
	if err != nil {
		return errors.Trace(err)
	}
	if !names.IsValidUser(username) {
		return errors.Errorf("%q is not a valid username", username)
	}
	outputInfo := modelcmd.ServerFile{
		Username:  username,
		Password:  password,
		Addresses: endpoint.Addresses,
		CACert:    endpoint.CACert,
	}
	yaml, err := cmd.FormatYaml(outputInfo)
	if err != nil {
		return errors.Trace(err)
	}
	if err := ioutil.WriteFile(outPath, yaml, 0644); err != nil {
		return errors.Trace(err)
	}
	serverFileNotify(outPath)
	ctx.Infof("server file written to %s", outPath)
	return nil
}
Beispiel #10
0
func (c *ImageMetadataCommand) Run(context *cmd.Context) error {
	if err := c.setParams(context); err != nil {
		return err
	}
	out := context.Stdout
	im := &imagemetadata.ImageMetadata{
		Id:   c.ImageId,
		Arch: c.Arch,
	}
	cloudSpec := simplestreams.CloudSpec{
		Region:   c.Region,
		Endpoint: c.Endpoint,
	}
	targetStorage, err := filestorage.NewFileStorageWriter(c.Dir)
	if err != nil {
		return err
	}
	err = imagemetadata.MergeAndWriteMetadata(c.Series, []*imagemetadata.ImageMetadata{im}, &cloudSpec, targetStorage)
	if err != nil {
		return fmt.Errorf("image metadata files could not be created: %v", err)
	}
	dir := context.AbsPath(c.Dir)
	dest := filepath.Join(dir, storage.BaseImagesPath, "streams", "v1")
	fmt.Fprintf(out, fmt.Sprintf(helpDoc, dest, dir, dir))
	return nil
}
Beispiel #11
0
// addCharmViaAPI calls the appropriate client API calls to add the
// given charm URL to state. For non-public charm URLs, this function also
// handles the macaroon authorization process using the given csClient.
// The resulting charm URL of the added charm is displayed on stdout.
func addCharmViaAPI(client *api.Client, ctx *cmd.Context, curl *charm.URL, repo charmrepo.Interface, csclient *csClient) (*charm.URL, error) {
	switch curl.Schema {
	case "local":
		ch, err := repo.Get(curl)
		if err != nil {
			return nil, err
		}
		stateCurl, err := client.AddLocalCharm(curl, ch)
		if err != nil {
			return nil, err
		}
		curl = stateCurl
	case "cs":
		if err := client.AddCharm(curl); err != nil {
			if !params.IsCodeUnauthorized(err) {
				return nil, errors.Mask(err)
			}
			m, err := csclient.authorize(curl)
			if err != nil {
				return nil, errors.Mask(err)
			}
			if err := client.AddCharmWithAuthorization(curl, m); err != nil {
				return nil, errors.Mask(err)
			}
		}
	default:
		return nil, fmt.Errorf("unsupported charm URL schema: %q", curl.Schema)
	}
	ctx.Infof("Added charm %q to the environment.", curl)
	return curl, nil
}
Beispiel #12
0
Datei: list.go Projekt: bac/juju
func (c *ListCommand) Run(ctx *cmd.Context) error {
	apiclient, err := c.newAPIClient(c)
	if err != nil {
		return errors.Trace(err)
	}
	defer apiclient.Close()

	payloads, err := apiclient.ListFull(c.patterns...)
	if err != nil {
		if payloads == nil {
			// List call completely failed; there is nothing to report.
			return errors.Trace(err)
		}
		// Display any error, but continue to print info if some was returned.
		fmt.Fprintf(ctx.Stderr, "%v\n", err)
	}

	if len(payloads) == 0 {
		ctx.Infof("No payloads to display.")
		return nil
	}

	// Note that we do not worry about c.CompatVersion for payloads...
	formatter := newListFormatter(payloads)
	formatted := formatter.format()
	return c.out.Write(ctx, formatted)
}
Beispiel #13
0
func (c *ShowServiceCommand) formatUnitResources(ctx *cmd.Context, unit, service string, sr resource.ServiceResources) error {
	if len(sr.UnitResources) == 0 {
		ctx.Infof(noResources)
		return nil
	}

	if c.details {
		formatted, err := detailedResources(unit, sr)
		if err != nil {
			return errors.Trace(err)
		}
		return c.out.Write(ctx, FormattedUnitDetails(formatted))
	}

	resources, err := unitResources(unit, service, sr)
	if err != nil {
		return errors.Trace(err)
	}

	res := make([]FormattedUnitResource, len(resources))

	for i, r := range resources {
		res[i] = FormattedUnitResource(FormatSvcResource(r))
	}

	return c.out.Write(ctx, res)

}
Beispiel #14
0
// waitForAgentInitialisation polls the bootstrapped state server with a read-only
// command which will fail until the state server is fully initialised.
// TODO(wallyworld) - add a bespoke command to maybe the admin facade for this purpose.
func (c *BootstrapCommand) waitForAgentInitialisation(ctx *cmd.Context) (err error) {
	attempts := utils.AttemptStrategy{
		Min:   bootstrapReadyPollCount,
		Delay: bootstrapReadyPollDelay,
	}
	var client block.BlockListAPI
	for attempt := attempts.Start(); attempt.Next(); {
		client, err = blockAPI(&c.EnvCommandBase)
		if err != nil {
			return err
		}
		_, err = client.List()
		client.Close()
		if err == nil {
			ctx.Infof("Bootstrap complete")
			return nil
		}
		if strings.Contains(err.Error(), apiserver.UpgradeInProgressError.Error()) {
			ctx.Infof("Waiting for API to become available")
			continue
		}
		return err
	}
	return err
}
Beispiel #15
0
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed
// in a user-friendly manner with readable and digestable error message.
func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error {
	if destroyErr == nil {
		return nil
	}
	if params.IsCodeOperationBlocked(destroyErr) {
		logger.Errorf(destroyControllerBlockedMsg)
		if api != nil {
			models, err := api.ListBlockedModels()
			var bytes []byte
			if err == nil {
				bytes, err = formatTabularBlockedModels(models)
			}
			if err != nil {
				logger.Errorf("Unable to list blocked models: %s", err)
				return cmd.ErrSilent
			}
			ctx.Infof(string(bytes))
		}
		return cmd.ErrSilent
	}
	if params.IsCodeHasHostedModels(destroyErr) {
		return destroyErr
	}
	logger.Errorf(stdFailureMsg, c.ControllerName())
	return destroyErr
}
Beispiel #16
0
func logSwitch(ctx *cmd.Context, oldName string, newName *string) {
	if *newName == oldName {
		ctx.Infof("%s (no change)", oldName)
	} else {
		ctx.Infof("%s -> %s", oldName, *newName)
	}
}
Beispiel #17
0
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
}
Beispiel #18
0
// Run implements Command.Run.
func (c *ListCommand) Run(ctx *cmd.Context) error {
	return c.RunWithAPI(ctx, func(api SubnetAPI, ctx *cmd.Context) error {
		// Validate space and/or zone, if given to display a nicer error
		// message.
		// Get the list of subnets, filtering them as requested.
		subnets, err := api.ListSubnets(c.spaceTag, c.ZoneName)
		if err != nil {
			return errors.Annotate(err, "cannot list subnets")
		}

		// Display a nicer message in case no subnets were found.
		if len(subnets) == 0 {
			if c.SpaceName != "" || c.ZoneName != "" {
				ctx.Infof("no subnets found matching requested criteria")
			} else {
				ctx.Infof("no subnets to display")
			}
			return nil
		}

		// Construct the output list for displaying with the chosen
		// format.
		result := formattedList{
			Subnets: make(map[string]formattedSubnet),
		}
		for _, sub := range subnets {
			subResult := formattedSubnet{
				ProviderId: sub.ProviderId,
				Zones:      sub.Zones,
			}

			// Use the CIDR to determine the subnet type.
			if ip, _, err := net.ParseCIDR(sub.CIDR); err != nil {
				return errors.Errorf("subnet %q has invalid CIDR", sub.CIDR)
			} else if ip.To4() != nil {
				subResult.Type = typeIPv4
			} else if ip.To16() != nil {
				subResult.Type = typeIPv6
			}
			// Space must be valid, but verify anyway.
			spaceTag, err := names.ParseSpaceTag(sub.SpaceTag)
			if err != nil {
				return errors.Annotatef(err, "subnet %q has invalid space", sub.CIDR)
			}
			subResult.Space = spaceTag.Id()

			// Display correct status according to the life cycle value.
			switch sub.Life {
			case params.Alive:
				subResult.Status = statusInUse
			case params.Dying, params.Dead:
				subResult.Status = statusTerminating
			}

			result.Subnets[sub.CIDR] = subResult
		}

		return c.out.Write(ctx, result)
	})
}
Beispiel #19
0
// Run implements Command.Run.
func (c *addCommand) Run(ctx *cmd.Context) error {
	if c.api == nil {
		api, err := c.NewUserManagerAPIClient()
		if err != nil {
			return errors.Trace(err)
		}
		c.api = api
		defer c.api.Close()
	}

	password, err := utils.RandomPassword()
	if err != nil {
		return errors.Annotate(err, "failed to generate random password")
	}
	randomPasswordNotify(password)

	if _, err := c.api.AddUser(c.User, c.DisplayName, password); err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}

	displayName := c.User
	if c.DisplayName != "" {
		displayName = fmt.Sprintf("%s (%s)", c.DisplayName, c.User)
	}

	ctx.Infof("user %q added", displayName)

	return writeServerFile(c, ctx, c.User, password, c.OutPath)
}
Beispiel #20
0
// ensureUserFriendlyErrorLog ensures that error will be logged and displayed
// in a user-friendly manner with readable and digestable error message.
func (c *destroyCommand) ensureUserFriendlyErrorLog(destroyErr error, ctx *cmd.Context, api destroyControllerAPI) error {
	if destroyErr == nil {
		return nil
	}
	if params.IsCodeOperationBlocked(destroyErr) {
		logger.Errorf(`there are blocks preventing controller destruction
To remove all blocks in the controller, please run:

    juju controller remove-blocks

`)
		if api != nil {
			envs, err := api.ListBlockedEnvironments()
			var bytes []byte
			if err == nil {
				bytes, err = formatTabularBlockedEnvironments(envs)
			}

			if err != nil {
				logger.Errorf("Unable to list blocked environments: %s", err)
				return cmd.ErrSilent
			}
			ctx.Infof(string(bytes))
		}
		return cmd.ErrSilent
	}
	logger.Errorf(stdFailureMsg, c.EnvName())
	return destroyErr
}
Beispiel #21
0
// Run implements Command.Run
func (c *destroyCommand) Run(ctx *cmd.Context) error {
	store, err := configstore.Default()
	if err != nil {
		return errors.Annotate(err, "cannot open controller info storage")
	}

	cfgInfo, err := store.ReadInfo(c.ModelName())
	if err != nil {
		return errors.Annotate(err, "cannot read controller info")
	}

	// Verify that we're destroying a controller
	apiEndpoint := cfgInfo.APIEndpoint()
	if apiEndpoint.ServerUUID != "" && apiEndpoint.ModelUUID != apiEndpoint.ServerUUID {
		return errors.Errorf("%q is not a controller; use juju model destroy to destroy it", c.ModelName())
	}

	if !c.assumeYes {
		if err = confirmDestruction(ctx, c.ModelName()); err != nil {
			return err
		}
	}

	// Attempt to connect to the API.  If we can't, fail the destroy.  Users will
	// need to use the controller kill command if we can't connect.
	api, err := c.getControllerAPI()
	if err != nil {
		return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot connect to API"), ctx, nil)
	}
	defer api.Close()

	// Obtain bootstrap / controller environ information
	controllerEnviron, err := c.getControllerEnviron(cfgInfo, api)
	if err != nil {
		return errors.Annotate(err, "cannot obtain bootstrap information")
	}

	// Attempt to destroy the controller.
	err = api.DestroyController(c.destroyEnvs)
	if err != nil {
		return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot destroy controller"), ctx, api)
	}

	ctx.Infof("Destroying controller %q", c.ModelName())
	if c.destroyEnvs {
		ctx.Infof("Waiting for hosted model resources to be reclaimed.")

		updateStatus := newTimedStatusUpdater(ctx, api, apiEndpoint.ModelUUID)
		for ctrStatus, envsStatus := updateStatus(0); hasUnDeadEnvirons(envsStatus); ctrStatus, envsStatus = updateStatus(2 * time.Second) {
			ctx.Infof(fmtCtrStatus(ctrStatus))
			for _, envStatus := range envsStatus {
				ctx.Verbosef(fmtEnvStatus(envStatus))
			}
		}

		ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
	}
	return environs.Destroy(controllerEnviron, store)
}
Beispiel #22
0
func (c *listCredentialsCommand) Run(ctxt *cmd.Context) error {
	var credentials map[string]jujucloud.CloudCredential
	credentials, err := c.store.AllCredentials()
	if err != nil && !errors.IsNotFound(err) {
		return err
	}
	if c.cloudName != "" {
		for cloudName := range credentials {
			if cloudName != c.cloudName {
				delete(credentials, cloudName)
			}
		}
	}

	// Find local cloud names.
	personalClouds, err := c.personalClouds()
	if err != nil {
		return err
	}
	var personalCloudNames []string
	for name := range personalClouds {
		personalCloudNames = append(personalCloudNames, name)
	}

	displayCredentials := make(map[string]CloudCredential)
	var missingClouds []string
	for cloudName, cred := range credentials {
		if !c.showSecrets {
			if err := c.removeSecrets(cloudName, &cred); err != nil {
				if errors.IsNotValid(err) {
					missingClouds = append(missingClouds, cloudName)
					continue
				}
				return errors.Annotatef(err, "removing secrets from credentials for cloud %v", cloudName)
			}
		}
		displayCredential := CloudCredential{
			DefaultCredential: cred.DefaultCredential,
			DefaultRegion:     cred.DefaultRegion,
		}
		if len(cred.AuthCredentials) != 0 {
			displayCredential.Credentials = make(map[string]Credential, len(cred.AuthCredentials))
			for credName, credDetails := range cred.AuthCredentials {
				displayCredential.Credentials[credName] = Credential{
					string(credDetails.AuthType()),
					credDetails.Attributes(),
					credDetails.Revoked,
					credDetails.Label,
				}
			}
		}
		displayCredentials[cloudName] = displayCredential
	}
	if c.out.Name() == "tabular" && len(missingClouds) > 0 {
		fmt.Fprintf(ctxt.GetStdout(), "The following clouds have been removed and are omitted from the results to avoid leaking secrets.\n"+
			"Run with --show-secrets to display these clouds' credentials: %v\n\n", strings.Join(missingClouds, ", "))
	}
	return c.out.Write(ctxt, credentialsMap{displayCredentials})
}
Beispiel #23
0
// Run connects to the specified environment and starts the charm
// upgrade process.
func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error {
	client, err := c.NewAPIClient()
	if err != nil {
		return err
	}
	defer client.Close()
	oldURL, err := client.ServiceGetCharmURL(c.ServiceName)
	if err != nil {
		return err
	}

	conf, err := service.GetClientConfig(client)
	if err != nil {
		return errors.Trace(err)
	}

	var newRef *charm.Reference
	if c.SwitchURL != "" {
		newRef, err = charm.ParseReference(c.SwitchURL)
		if err != nil {
			return err
		}
	} else {
		// No new URL specified, but revision might have been.
		newRef = oldURL.WithRevision(c.Revision).Reference()
	}

	httpClient, err := c.HTTPClient()
	if err != nil {
		return errors.Trace(err)
	}
	csClient := newCharmStoreClient(httpClient)
	newURL, repo, err := resolveCharmStoreEntityURL(newRef.String(), csClient.params, ctx.AbsPath(c.RepoPath), conf)
	if err != nil {
		return errors.Trace(err)
	}

	// If no explicit revision was set with either SwitchURL
	// or Revision flags, discover the latest.
	if *newURL == *oldURL {
		if newRef.Revision != -1 {
			return fmt.Errorf("already running specified charm %q", newURL)
		}
		if newURL.Schema == "cs" {
			// No point in trying to upgrade a charm store charm when
			// we just determined that's the latest revision
			// available.
			return fmt.Errorf("already running latest charm %q", newURL)
		}
	}

	addedURL, err := addCharmViaAPI(client, newURL, repo, csClient)
	if err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}
	ctx.Infof("Added charm %q to the environment.", addedURL)

	return block.ProcessBlockedError(client.ServiceSetCharm(c.ServiceName, addedURL.String(), c.Force), block.BlockChange)
}
Beispiel #24
0
// Run implements Command.Run.
func (c *ChangePasswordCommand) Run(ctx *cmd.Context) error {
	var err error

	c.Password, err = c.generateOrReadPassword(ctx, c.Generate)
	if err != nil {
		return errors.Trace(err)
	}

	var credsWriter EnvironInfoCredsWriter
	var creds configstore.APICredentials

	if c.User == "" {
		// We get the creds writer before changing the password just to
		// minimise the things that could go wrong after changing the password
		// in the server.
		credsWriter, err = getEnvironInfoWriter(c)
		if err != nil {
			return errors.Trace(err)
		}

		creds, err = getConnectionCredentials(c)
		if err != nil {
			return errors.Trace(err)
		}
	} else {
		creds.User = c.User
	}

	client, err := getChangePasswordAPI(c)
	if err != nil {
		return err
	}
	defer client.Close()

	oldPassword := creds.Password
	creds.Password = c.Password
	err = client.SetPassword(creds.User, c.Password)
	if err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}

	if c.User != "" {
		return c.writeEnvironmentFile(ctx)
	}

	credsWriter.SetAPICredentials(creds)
	if err := credsWriter.Write(); err != nil {
		logger.Errorf("updating the environments file failed, reverting to original password")
		setErr := client.SetPassword(creds.User, oldPassword)
		if setErr != nil {
			logger.Errorf("failed to set password back, you will need to edit your environments file by hand to specify the password: %q", c.Password)
			return errors.Annotate(setErr, "failed to set password back")
		}
		return errors.Annotate(err, "failed to write new password to environments file")
	}
	ctx.Infof("Your password has been updated.")
	return nil
}
Beispiel #25
0
// Run connects to the specified environment and starts the charm
// upgrade process.
func (c *upgradeCharmCommand) Run(ctx *cmd.Context) error {
	client, err := c.NewAPIClient()
	if err != nil {
		return err
	}
	defer client.Close()

	serviceClient, err := c.newServiceAPIClient()
	if err != nil {
		return err
	}

	oldURL, err := serviceClient.GetCharmURL(c.ServiceName)
	if err != nil {
		return err
	}

	newRef := c.SwitchURL
	if newRef == "" {
		newRef = c.CharmPath
	}
	if c.SwitchURL == "" && c.CharmPath == "" {
		// No new URL specified, but revision might have been.
		newRef = oldURL.WithRevision(c.Revision).String()
	}

	bakeryClient, err := c.BakeryClient()
	if err != nil {
		return errors.Trace(err)
	}
	csClient := newCharmStoreClient(bakeryClient).WithChannel(c.Channel)

	conf, err := getClientConfig(client)
	if err != nil {
		return errors.Trace(err)
	}
	resolver := newCharmURLResolver(conf, csClient, ctx.AbsPath(c.RepoPath))
	chID, csMac, err := c.addCharm(oldURL, newRef, client, resolver)
	if err != nil {
		return block.ProcessBlockedError(err, block.BlockChange)
	}
	ctx.Infof("Added charm %q to the model.", chID.URL)

	ids, err := c.upgradeResources(client, chID, csMac)
	if err != nil {
		return errors.Trace(err)
	}

	cfg := apiservice.SetCharmConfig{
		ServiceName: c.ServiceName,
		CharmID:     chID,
		ForceSeries: c.ForceSeries,
		ForceUnits:  c.ForceUnits,
		ResourceIDs: ids,
	}

	return block.ProcessBlockedError(serviceClient.SetCharm(cfg), block.BlockChange)
}
Beispiel #26
0
// destroyPreparedEnviron destroys the environment and logs an error if it fails.
func destroyPreparedEnviron(ctx *cmd.Context, env environs.Environ, store configstore.Storage, err *error, action string) {
	if *err == nil {
		return
	}
	ctx.Infof("%s failed, destroying environment", action)
	if err := environs.Destroy(env, store); err != nil {
		logger.Errorf("%s failed, and the environment could not be destroyed: %v", action, err)
	}
}
Beispiel #27
0
func (c *signMetadataCommand) Run(context *cmd.Context) error {
	loggo.RegisterWriter("signmetadata", cmd.NewCommandLogWriter("juju.plugins.metadata", context.Stdout, context.Stderr), loggo.INFO)
	defer loggo.RemoveWriter("signmetadata")
	keyData, err := ioutil.ReadFile(c.keyFile)
	if err != nil {
		return err
	}
	dir := context.AbsPath(c.dir)
	return process(dir, string(keyData), c.passphrase)
}
Beispiel #28
0
// Run implements Command.Run.
func (c *renameCommand) Run(ctx *cmd.Context) error {
	return c.RunWithAPI(ctx, func(api SpaceAPI, ctx *cmd.Context) error {
		err := api.RenameSpace(c.Name, c.NewName)
		if err != nil {
			return errors.Annotatef(err, "cannot rename space %q", c.Name)
		}

		ctx.Infof("renamed space %q to %q", c.Name, c.NewName)
		return nil
	})
}
Beispiel #29
0
func destroyPreparedEnvironProductionFunc(
	ctx *cmd.Context,
	env environs.Environ,
	store configstore.Storage,
	action string,
) {
	ctx.Infof("%s failed, destroying environment", action)
	if err := environs.Destroy(env, store); err != nil {
		logger.Errorf("the environment could not be destroyed: %v", err)
	}
}
Beispiel #30
0
func destroyEnvInfoProductionFunc(
	ctx *cmd.Context,
	cfgName string,
	store configstore.Storage,
	action string,
) {
	ctx.Infof("%s failed, cleaning up the environment.", action)
	if err := environs.DestroyInfo(cfgName, store); err != nil {
		logger.Errorf("the environment jenv file could not be cleaned up: %v", err)
	}
}