Beispiel #1
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 #2
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)
	}
}
Beispiel #3
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 environment info storage")
	}

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

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

	if !c.assumeYes {
		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.envName)

		if err := jujucmd.UserConfirmYes(ctx); err != nil {
			return errors.Annotate(err, "environment destruction")
		}
	}

	// Attempt to connect to the API.  If we can't, fail the destroy.
	api, err := c.getAPI()
	if err != nil {
		return errors.Annotate(err, "cannot connect to API")
	}
	defer api.Close()

	// Attempt to destroy the environment.
	err = api.DestroyEnvironment()
	if err != nil {
		return c.handleError(errors.Annotate(err, "cannot destroy environment"))
	}

	return environs.DestroyInfo(c.envName, store)
}
Beispiel #4
0
func (c *destroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) {
	store, err := configstore.Default()
	if err != nil {
		return errors.Annotate(err, "cannot open environment info storage")
	}

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

	var hasBootstrapCfg bool
	var serverEnviron environs.Environ
	if bootstrapCfg := cfgInfo.BootstrapConfig(); bootstrapCfg != nil {
		hasBootstrapCfg = true
		serverEnviron, err = getServerEnv(bootstrapCfg)
		if err != nil {
			return errors.Trace(err)
		}
	}

	if c.force {
		if hasBootstrapCfg {
			// If --force is supplied on a server environment, then don't
			// attempt to use the API. This is necessary to destroy broken
			// environments, where the API server is inaccessible or faulty.
			return environs.Destroy(serverEnviron, store)
		} else {
			// Force only makes sense on the server environment.
			return errors.Errorf("cannot force destroy environment without bootstrap information")
		}
	}

	apiclient, err := c.NewAPIClient()
	if err != nil {
		if errors.IsNotFound(err) {
			logger.Warningf("environment not found, removing config file")
			ctx.Infof("environment not found, removing config file")
			return environs.DestroyInfo(c.EnvName(), store)
		}
		return errors.Annotate(err, "cannot connect to API")
	}
	defer apiclient.Close()
	info, err := apiclient.EnvironmentInfo()
	if err != nil {
		return errors.Annotate(err, "cannot get information for environment")
	}

	if !c.assumeYes {
		fmt.Fprintf(ctx.Stdout, destroyEnvMsg, c.EnvName(), info.ProviderType)

		scanner := bufio.NewScanner(ctx.Stdin)
		scanner.Scan()
		err := scanner.Err()
		if err != nil && err != io.EOF {
			return errors.Annotate(err, "environment destruction aborted")
		}
		answer := strings.ToLower(scanner.Text())
		if answer != "y" && answer != "yes" {
			return stderrors.New("environment destruction aborted")
		}
	}

	if info.UUID == info.ServerUUID {
		if !hasBootstrapCfg {
			// serverEnviron will be nil as we didn't have the jenv bootstrap
			// config to build it. But we do have a connection to the API
			// server, so get the config from there.
			bootstrapCfg, err := apiclient.EnvironmentGet()
			if err != nil {
				return errors.Annotate(err, "environment destruction failed")
			}
			serverEnviron, err = getServerEnv(bootstrapCfg)
			if err != nil {
				return errors.Annotate(err, "environment destruction failed")
			}
		}

		if err := c.destroyEnv(apiclient); err != nil {
			return errors.Annotate(err, "environment destruction failed")
		}
		if err := environs.Destroy(serverEnviron, store); err != nil {
			return errors.Annotate(err, "environment destruction failed")
		}
		return environs.DestroyInfo(c.EnvName(), store)
	}

	// If this is not the server environment, there is no bootstrap info and
	// we do not call Destroy on the provider. Destroying the environment via
	// the API and cleaning up the jenv file is sufficient.
	if err := c.destroyEnv(apiclient); err != nil {
		errors.Annotate(err, "cannot destroy environment")
	}
	return environs.DestroyInfo(c.EnvName(), store)
}