github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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  const bootstrapMessage = `To configure your system to better support LXD containers, please see: https://github.com/lxc/lxd/blob/master/doc/production-setup.md`
    22  
    23  type baseProvider interface {
    24  	// BootstrapEnv bootstraps a Juju environment.
    25  	BootstrapEnv(environs.BootstrapContext, environs.BootstrapParams) (*environs.BootstrapResult, error)
    26  
    27  	// DestroyEnv destroys the provided Juju environment.
    28  	DestroyEnv() error
    29  }
    30  
    31  type environ struct {
    32  	name string
    33  	uuid string
    34  	raw  *rawProvider
    35  	base baseProvider
    36  
    37  	// namespace is used to create the machine and device hostnames.
    38  	namespace instance.Namespace
    39  
    40  	lock sync.Mutex
    41  	ecfg *environConfig
    42  }
    43  
    44  type newRawProviderFunc func(environs.CloudSpec) (*rawProvider, error)
    45  
    46  func newEnviron(spec environs.CloudSpec, cfg *config.Config, newRawProvider newRawProviderFunc) (*environ, error) {
    47  	ecfg, err := newValidConfig(cfg)
    48  	if err != nil {
    49  		return nil, errors.Annotate(err, "invalid config")
    50  	}
    51  
    52  	namespace, err := instance.NewNamespace(cfg.UUID())
    53  	if err != nil {
    54  		return nil, errors.Trace(err)
    55  	}
    56  
    57  	raw, err := newRawProvider(spec)
    58  	if err != nil {
    59  		return nil, errors.Trace(err)
    60  	}
    61  
    62  	env := &environ{
    63  		name:      ecfg.Name(),
    64  		uuid:      ecfg.UUID(),
    65  		raw:       raw,
    66  		namespace: namespace,
    67  		ecfg:      ecfg,
    68  	}
    69  	env.base = common.DefaultProvider{Env: env}
    70  
    71  	//TODO(wwitzel3) make sure we are also cleaning up profiles during destroy
    72  	if err := env.initProfile(); err != nil {
    73  		return nil, errors.Trace(err)
    74  	}
    75  
    76  	return env, nil
    77  }
    78  
    79  var defaultProfileConfig = map[string]string{
    80  	"boot.autostart":   "true",
    81  	"security.nesting": "true",
    82  }
    83  
    84  func (env *environ) initProfile() error {
    85  	hasProfile, err := env.raw.HasProfile(env.profileName())
    86  	if err != nil {
    87  		return errors.Trace(err)
    88  	}
    89  
    90  	if hasProfile {
    91  		return nil
    92  	}
    93  
    94  	return env.raw.CreateProfile(env.profileName(), defaultProfileConfig)
    95  }
    96  
    97  func (env *environ) profileName() string {
    98  	return "juju-" + env.ecfg.Name()
    99  }
   100  
   101  // Name returns the name of the environment.
   102  func (env *environ) Name() string {
   103  	return env.name
   104  }
   105  
   106  // Provider returns the environment provider that created this env.
   107  func (*environ) Provider() environs.EnvironProvider {
   108  	return providerInstance
   109  }
   110  
   111  // SetConfig updates the env's configuration.
   112  func (env *environ) SetConfig(cfg *config.Config) error {
   113  	env.lock.Lock()
   114  	defer env.lock.Unlock()
   115  	ecfg, err := newValidConfig(cfg)
   116  	if err != nil {
   117  		return errors.Trace(err)
   118  	}
   119  	env.ecfg = ecfg
   120  	return nil
   121  }
   122  
   123  // Config returns the configuration data with which the env was created.
   124  func (env *environ) Config() *config.Config {
   125  	env.lock.Lock()
   126  	cfg := env.ecfg.Config
   127  	env.lock.Unlock()
   128  	return cfg
   129  }
   130  
   131  // PrepareForBootstrap implements environs.Environ.
   132  func (env *environ) PrepareForBootstrap(ctx environs.BootstrapContext) error {
   133  	if err := lxdclient.EnableHTTPSListener(env.raw); err != nil {
   134  		return errors.Annotate(err, "enabling HTTPS listener")
   135  	}
   136  	return nil
   137  }
   138  
   139  // Create implements environs.Environ.
   140  func (env *environ) Create(environs.CreateParams) error {
   141  	return nil
   142  }
   143  
   144  // Bootstrap implements environs.Environ.
   145  func (env *environ) Bootstrap(ctx environs.BootstrapContext, params environs.BootstrapParams) (*environs.BootstrapResult, error) {
   146  	// Using the Bootstrap func from provider/common should be fine.
   147  	// Local provider does its own thing because it has to deal directly
   148  	// with localhost rather than using SSH.
   149  	return env.base.BootstrapEnv(ctx, params)
   150  }
   151  
   152  // BootstrapMessage is part of the Environ interface.
   153  func (env *environ) BootstrapMessage() string {
   154  	return bootstrapMessage
   155  }
   156  
   157  // Destroy shuts down all known machines and destroys the rest of the
   158  // known environment.
   159  func (env *environ) Destroy() error {
   160  	ports, err := env.Ports()
   161  	if err != nil {
   162  		return errors.Trace(err)
   163  	}
   164  	if len(ports) > 0 {
   165  		if err := env.ClosePorts(ports); err != nil {
   166  			return errors.Trace(err)
   167  		}
   168  	}
   169  	if err := env.base.DestroyEnv(); err != nil {
   170  		return errors.Trace(err)
   171  	}
   172  	return nil
   173  }
   174  
   175  // DestroyController implements the Environ interface.
   176  func (env *environ) DestroyController(controllerUUID string) error {
   177  	if err := env.Destroy(); err != nil {
   178  		return errors.Trace(err)
   179  	}
   180  	return env.destroyHostedModelResources(controllerUUID)
   181  }
   182  
   183  func (env *environ) destroyHostedModelResources(controllerUUID string) error {
   184  	// Destroy all instances with juju-controller-uuid
   185  	// matching the specified UUID.
   186  	const prefix = "juju-"
   187  	instances, err := env.prefixedInstances(prefix)
   188  	if err != nil {
   189  		return errors.Annotate(err, "listing instances")
   190  	}
   191  	logger.Debugf("instances: %v", instances)
   192  	var names []string
   193  	for _, inst := range instances {
   194  		metadata := inst.raw.Metadata()
   195  		if metadata[tags.JujuModel] == env.uuid {
   196  			continue
   197  		}
   198  		if metadata[tags.JujuController] != controllerUUID {
   199  			continue
   200  		}
   201  		names = append(names, string(inst.Id()))
   202  	}
   203  	if err := removeInstances(env.raw, prefix, names); err != nil {
   204  		return errors.Annotate(err, "removing hosted model instances")
   205  	}
   206  	return nil
   207  }