github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/instance" 17 "github.com/juju/juju/provider/common" 18 "github.com/juju/juju/tools/lxdclient" 19 ) 20 21 type baseProvider interface { 22 // BootstrapEnv bootstraps a Juju environment. 23 BootstrapEnv(environs.BootstrapContext, environs.BootstrapParams) (*environs.BootstrapResult, error) 24 25 // DestroyEnv destroys the provided Juju environment. 26 DestroyEnv() error 27 } 28 29 type environ struct { 30 name string 31 uuid string 32 raw *rawProvider 33 base baseProvider 34 35 // namespace is used to create the machine and device hostnames. 36 namespace instance.Namespace 37 38 lock sync.Mutex 39 ecfg *environConfig 40 } 41 42 type newRawProviderFunc func(environs.CloudSpec) (*rawProvider, error) 43 44 func newEnviron(spec environs.CloudSpec, cfg *config.Config, newRawProvider newRawProviderFunc) (*environ, error) { 45 ecfg, err := newValidConfig(cfg) 46 if err != nil { 47 return nil, errors.Annotate(err, "invalid config") 48 } 49 50 namespace, err := instance.NewNamespace(cfg.UUID()) 51 if err != nil { 52 return nil, errors.Trace(err) 53 } 54 55 raw, err := newRawProvider(spec) 56 if err != nil { 57 return nil, errors.Trace(err) 58 } 59 60 env := &environ{ 61 name: ecfg.Name(), 62 uuid: ecfg.UUID(), 63 raw: raw, 64 namespace: namespace, 65 ecfg: ecfg, 66 } 67 env.base = common.DefaultProvider{Env: env} 68 69 //TODO(wwitzel3) make sure we are also cleaning up profiles during destroy 70 if err := env.initProfile(); err != nil { 71 return nil, errors.Trace(err) 72 } 73 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 ecfg, err := newValidConfig(cfg) 114 if err != nil { 115 return errors.Trace(err) 116 } 117 env.ecfg = ecfg 118 return nil 119 } 120 121 // Config returns the configuration data with which the env was created. 122 func (env *environ) Config() *config.Config { 123 env.lock.Lock() 124 cfg := env.ecfg.Config 125 env.lock.Unlock() 126 return cfg 127 } 128 129 // PrepareForBootstrap implements environs.Environ. 130 func (env *environ) PrepareForBootstrap(ctx environs.BootstrapContext) error { 131 if err := lxdclient.EnableHTTPSListener(env.raw); err != nil { 132 return errors.Annotate(err, "enabling HTTPS listener") 133 } 134 return nil 135 } 136 137 // Create implements environs.Environ. 138 func (env *environ) Create(environs.CreateParams) error { 139 return nil 140 } 141 142 // Bootstrap implements environs.Environ. 143 func (env *environ) Bootstrap(ctx environs.BootstrapContext, params environs.BootstrapParams) (*environs.BootstrapResult, error) { 144 // Using the Bootstrap func from provider/common should be fine. 145 // Local provider does its own thing because it has to deal directly 146 // with localhost rather than using SSH. 147 return env.base.BootstrapEnv(ctx, params) 148 } 149 150 // Destroy shuts down all known machines and destroys the rest of the 151 // known environment. 152 func (env *environ) Destroy() error { 153 ports, err := env.Ports() 154 if err != nil { 155 return errors.Trace(err) 156 } 157 if len(ports) > 0 { 158 if err := env.ClosePorts(ports); err != nil { 159 return errors.Trace(err) 160 } 161 } 162 if err := env.base.DestroyEnv(); err != nil { 163 return errors.Trace(err) 164 } 165 return nil 166 } 167 168 // DestroyController implements the Environ interface. 169 func (env *environ) DestroyController(controllerUUID string) error { 170 if err := env.Destroy(); err != nil { 171 return errors.Trace(err) 172 } 173 return env.destroyHostedModelResources(controllerUUID) 174 } 175 176 func (env *environ) destroyHostedModelResources(controllerUUID string) error { 177 // Destroy all instances where juju-controller-uuid, 178 // but not juju-model-uuid, matches env.uuid. 179 prefix := env.namespace.Prefix() 180 instances, err := env.prefixedInstances(prefix) 181 if err != nil { 182 return errors.Annotate(err, "listing instances") 183 } 184 logger.Debugf("instances: %v", instances) 185 var names []string 186 for _, inst := range instances { 187 metadata := inst.raw.Metadata() 188 if metadata[tags.JujuModel] == env.uuid { 189 continue 190 } 191 if metadata[tags.JujuController] != controllerUUID { 192 continue 193 } 194 names = append(names, string(inst.Id())) 195 } 196 if err := env.raw.RemoveInstances(prefix, names...); err != nil { 197 return errors.Annotate(err, "removing hosted model instances") 198 } 199 return nil 200 }