github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/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  }