github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/lxd/environ.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build go1.3 5 6 package lxd 7 8 import ( 9 "sync" 10 11 "github.com/juju/errors" 12 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/environs/tags" 16 "github.com/juju/juju/provider/common" 17 ) 18 19 type baseProvider interface { 20 // BootstrapEnv bootstraps a Juju environment. 21 BootstrapEnv(environs.BootstrapContext, environs.BootstrapParams) (*environs.BootstrapResult, error) 22 23 // DestroyEnv destroys the provided Juju environment. 24 DestroyEnv() error 25 } 26 27 type environ struct { 28 common.SupportsUnitPlacementPolicy 29 30 name string 31 uuid string 32 raw *rawProvider 33 base baseProvider 34 35 lock sync.Mutex 36 ecfg *environConfig 37 } 38 39 type newRawProviderFunc func(*environConfig) (*rawProvider, error) 40 41 func newEnviron(cfg *config.Config, newRawProvider newRawProviderFunc) (*environ, error) { 42 ecfg, err := newValidConfig(cfg, configDefaults) 43 if err != nil { 44 return nil, errors.Annotate(err, "invalid config") 45 } 46 47 // Connect and authenticate. 48 raw, err := newRawProvider(ecfg) 49 if err != nil { 50 return nil, errors.Trace(err) 51 } 52 53 env, err := newEnvironRaw(ecfg, raw) 54 if err != nil { 55 return nil, errors.Trace(err) 56 } 57 58 //TODO(wwitzel3) make sure we are also cleaning up profiles during destroy 59 if err := env.initProfile(); err != nil { 60 return nil, errors.Trace(err) 61 } 62 63 return env, nil 64 } 65 66 func newEnvironRaw(ecfg *environConfig, raw *rawProvider) (*environ, error) { 67 env := &environ{ 68 name: ecfg.Name(), 69 uuid: ecfg.UUID(), 70 ecfg: ecfg, 71 raw: raw, 72 } 73 env.base = common.DefaultProvider{Env: env} 74 return env, nil 75 } 76 77 var defaultProfileConfig = map[string]string{ 78 "boot.autostart": "true", 79 "security.nesting": "true", 80 } 81 82 func (env *environ) initProfile() error { 83 hasProfile, err := env.raw.HasProfile(env.profileName()) 84 if err != nil { 85 return errors.Trace(err) 86 } 87 88 if hasProfile { 89 return nil 90 } 91 92 return env.raw.CreateProfile(env.profileName(), defaultProfileConfig) 93 } 94 95 func (env *environ) profileName() string { 96 return "juju-" + env.ecfg.Name() 97 } 98 99 // Name returns the name of the environment. 100 func (env *environ) Name() string { 101 return env.name 102 } 103 104 // Provider returns the environment provider that created this env. 105 func (*environ) Provider() environs.EnvironProvider { 106 return providerInstance 107 } 108 109 // SetConfig updates the env's configuration. 110 func (env *environ) SetConfig(cfg *config.Config) error { 111 env.lock.Lock() 112 defer env.lock.Unlock() 113 114 if env.ecfg == nil { 115 return errors.New("cannot set config on uninitialized env") 116 } 117 118 if err := env.ecfg.update(cfg); err != nil { 119 return errors.Annotate(err, "invalid config change") 120 } 121 return nil 122 } 123 124 // Config returns the configuration data with which the env was created. 125 func (env *environ) Config() *config.Config { 126 env.lock.Lock() 127 cfg := env.ecfg.Config 128 env.lock.Unlock() 129 return cfg 130 } 131 132 // Bootstrap creates a new instance, chosing the series and arch out of 133 // available tools. The series and arch are returned along with a func 134 // that must be called to finalize the bootstrap process by transferring 135 // the tools and installing the initial juju controller. 136 func (env *environ) Bootstrap(ctx environs.BootstrapContext, params environs.BootstrapParams) (*environs.BootstrapResult, error) { 137 // TODO(ericsnow) Ensure currently not the root user 138 // if remote is local host? 139 140 // Using the Bootstrap func from provider/common should be fine. 141 // Local provider does its own thing because it has to deal directly 142 // with localhost rather than using SSH. 143 return env.base.BootstrapEnv(ctx, params) 144 } 145 146 // Destroy shuts down all known machines and destroys the rest of the 147 // known environment. 148 func (env *environ) Destroy() error { 149 ports, err := env.Ports() 150 if err != nil { 151 return errors.Trace(err) 152 } 153 if len(ports) > 0 { 154 if err := env.ClosePorts(ports); err != nil { 155 return errors.Trace(err) 156 } 157 } 158 cfg := env.Config() 159 if cfg.UUID() == cfg.ControllerUUID() { 160 // This is the controller model, so we'll make sure 161 // there are no resources for hosted models remaining. 162 if err := env.destroyHostedModelResources(); err != nil { 163 return errors.Trace(err) 164 } 165 } 166 if err := env.base.DestroyEnv(); err != nil { 167 return errors.Trace(err) 168 } 169 return nil 170 } 171 172 func (env *environ) destroyHostedModelResources() error { 173 // Destroy all instances where juju-controller-uuid, 174 // but not juju-model-uuid, matches env.uuid. 175 prefix := common.EnvFullName("") 176 instances, err := env.prefixedInstances(prefix) 177 if err != nil { 178 return errors.Annotate(err, "listing instances") 179 } 180 logger.Debugf("instances: %v", instances) 181 var names []string 182 for _, inst := range instances { 183 metadata := inst.raw.Metadata() 184 if metadata[tags.JujuModel] == env.uuid { 185 continue 186 } 187 if metadata[tags.JujuController] != env.uuid { 188 continue 189 } 190 names = append(names, string(inst.Id())) 191 } 192 if err := env.raw.RemoveInstances(prefix, names...); err != nil { 193 return errors.Annotate(err, "removing hosted model instances") 194 } 195 return nil 196 } 197 198 func (env *environ) verifyCredentials() error { 199 // TODO(ericsnow) Do something here? 200 return nil 201 }