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 }