github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/common.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package main
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  	"gopkg.in/juju/charm.v4"
    12  
    13  	"github.com/juju/juju/api"
    14  	"github.com/juju/juju/cmd/envcmd"
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/environs/configstore"
    18  )
    19  
    20  // destroyPreparedEnviron destroys the environment and logs an error
    21  // if it fails.
    22  var destroyPreparedEnviron = destroyPreparedEnvironProductionFunc
    23  
    24  func destroyPreparedEnvironProductionFunc(
    25  	ctx *cmd.Context,
    26  	env environs.Environ,
    27  	store configstore.Storage,
    28  	action string,
    29  ) {
    30  	ctx.Infof("%s failed, destroying environment", action)
    31  	if err := environs.Destroy(env, store); err != nil {
    32  		logger.Errorf("the environment could not be destroyed: %v", err)
    33  	}
    34  }
    35  
    36  var destroyEnvInfo = destroyEnvInfoProductionFunc
    37  
    38  func destroyEnvInfoProductionFunc(
    39  	ctx *cmd.Context,
    40  	cfgName string,
    41  	store configstore.Storage,
    42  	action string,
    43  ) {
    44  	ctx.Infof("%s failed, cleaning up the environment.", action)
    45  	if err := environs.DestroyInfo(cfgName, store); err != nil {
    46  		logger.Errorf("the environment jenv file could not be cleaned up: %v", err)
    47  	}
    48  }
    49  
    50  // environFromName loads an existing environment or prepares a new
    51  // one. If there are no errors, it returns the environ and a closure to
    52  // clean up in case we need to further up the stack. If an error has
    53  // occurred, the environment and cleanup function will be nil, and the
    54  // error will be filled in.
    55  var environFromName = environFromNameProductionFunc
    56  
    57  func environFromNameProductionFunc(
    58  	ctx *cmd.Context,
    59  	envName string,
    60  	action string,
    61  	ensureNotBootstrapped func(environs.Environ) error,
    62  ) (env environs.Environ, cleanup func(), err error) {
    63  
    64  	store, err := configstore.Default()
    65  	if err != nil {
    66  		return nil, nil, err
    67  	}
    68  
    69  	envExisted := false
    70  	if environInfo, err := store.ReadInfo(envName); err == nil {
    71  		envExisted = true
    72  		logger.Warningf(
    73  			"ignoring environments.yaml: using bootstrap config in %s",
    74  			environInfo.Location(),
    75  		)
    76  	} else if !errors.IsNotFound(err) {
    77  		return nil, nil, err
    78  	}
    79  
    80  	cleanup = func() {
    81  		// Distinguish b/t removing the jenv file or tearing down the
    82  		// environment. We want to remove the jenv file if preparation
    83  		// was not successful. We want to tear down the environment
    84  		// only in the case where the environment didn't already
    85  		// exist.
    86  		if env == nil {
    87  			logger.Debugf("Destroying environment info.")
    88  			destroyEnvInfo(ctx, envName, store, action)
    89  		} else if !envExisted && ensureNotBootstrapped(env) != environs.ErrAlreadyBootstrapped {
    90  			logger.Debugf("Destroying environment.")
    91  			destroyPreparedEnviron(ctx, env, store, action)
    92  		}
    93  	}
    94  
    95  	if env, err = environs.PrepareFromName(envName, envcmd.BootstrapContext(ctx), store); err != nil {
    96  		return nil, cleanup, err
    97  	}
    98  
    99  	return env, cleanup, err
   100  }
   101  
   102  // resolveCharmURL returns a resolved charm URL, given a charm location string.
   103  // If the series is not resolved, the environment default-series is used, or if
   104  // not set, the series is resolved with the state server.
   105  func resolveCharmURL(url string, client *api.Client, conf *config.Config) (*charm.URL, error) {
   106  	ref, err := charm.ParseReference(url)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	// If series is not set, use configured default series
   111  	if ref.Series == "" {
   112  		if defaultSeries, ok := conf.DefaultSeries(); ok {
   113  			ref.Series = defaultSeries
   114  		}
   115  	}
   116  	if ref.Series != "" {
   117  		return ref.URL("")
   118  	}
   119  	// Otherwise, look up the best supported series for this charm
   120  	if ref.Schema != "local" {
   121  		return client.ResolveCharm(ref)
   122  	}
   123  	possibleURL := *ref
   124  	possibleURL.Series = "precise"
   125  	logger.Errorf("The series is not specified in the environment (default-series) or with the charm. Did you mean:\n\t%s", &possibleURL)
   126  	return nil, fmt.Errorf("cannot resolve series for charm: %q", ref)
   127  }