github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/gce/environ.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package gce
     5  
     6  import (
     7  	"sync"
     8  
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/environs"
    12  	"github.com/juju/juju/environs/config"
    13  	"github.com/juju/juju/environs/simplestreams"
    14  	"github.com/juju/juju/network"
    15  	"github.com/juju/juju/provider/common"
    16  	"github.com/juju/juju/provider/gce/google"
    17  )
    18  
    19  type gceConnection interface {
    20  	VerifyCredentials() error
    21  
    22  	// Instance gets the up-to-date info about the given instance
    23  	// and returns it.
    24  	Instance(id, zone string) (google.Instance, error)
    25  	Instances(prefix string, statuses ...string) ([]google.Instance, error)
    26  	AddInstance(spec google.InstanceSpec, zones ...string) (*google.Instance, error)
    27  	RemoveInstances(prefix string, ids ...string) error
    28  
    29  	Ports(fwname string) ([]network.PortRange, error)
    30  	OpenPorts(fwname string, ports ...network.PortRange) error
    31  	ClosePorts(fwname string, ports ...network.PortRange) error
    32  
    33  	AvailabilityZones(region string) ([]google.AvailabilityZone, error)
    34  
    35  	// Storage related methods.
    36  
    37  	// CreateDisks will attempt to create the disks described by <disks> spec and
    38  	// return a slice of Disk representing the created disks or error if one of them failed.
    39  	CreateDisks(zone string, disks []google.DiskSpec) ([]*google.Disk, error)
    40  	// Disks will return a list of Disk found the passed <zone>.
    41  	Disks(zone string) ([]*google.Disk, error)
    42  	// Disk will return a Disk representing the disk identified by the
    43  	// passed <name> or error.
    44  	Disk(zone, id string) (*google.Disk, error)
    45  	// RemoveDisk will destroy the disk identified by <name> in <zone>.
    46  	RemoveDisk(zone, id string) error
    47  	// AttachDisk will attach the volume identified by <volumeName> into the instance
    48  	// <instanceId> and return an AttachedDisk representing it or error.
    49  	AttachDisk(zone, volumeName, instanceId string, mode google.DiskMode) (*google.AttachedDisk, error)
    50  	// DetachDisk will detach <volumeName> disk from <instanceId> if possible
    51  	// and return error.
    52  	DetachDisk(zone, instanceId, volumeName string) error
    53  	// InstanceDisks returns a list of the disks attached to the passed instance.
    54  	InstanceDisks(zone, instanceId string) ([]*google.AttachedDisk, error)
    55  }
    56  
    57  type environ struct {
    58  	common.SupportsUnitPlacementPolicy
    59  
    60  	name string
    61  	uuid string
    62  	gce  gceConnection
    63  
    64  	lock sync.Mutex
    65  	ecfg *environConfig
    66  
    67  	archLock               sync.Mutex
    68  	supportedArchitectures []string
    69  }
    70  
    71  func newEnviron(cfg *config.Config) (*environ, error) {
    72  	ecfg, err := newValidConfig(cfg, configDefaults)
    73  	if err != nil {
    74  		return nil, errors.Annotate(err, "invalid config")
    75  	}
    76  
    77  	uuid, ok := ecfg.UUID()
    78  	if !ok {
    79  		return nil, errors.New("UUID not set")
    80  	}
    81  
    82  	// Connect and authenticate.
    83  	conn, err := newConnection(ecfg)
    84  	if err != nil {
    85  		return nil, errors.Trace(err)
    86  	}
    87  
    88  	env := &environ{
    89  		name: ecfg.Name(),
    90  		uuid: uuid,
    91  		ecfg: ecfg,
    92  		gce:  conn,
    93  	}
    94  	return env, nil
    95  }
    96  
    97  // Name returns the name of the environment.
    98  func (env *environ) Name() string {
    99  	return env.name
   100  }
   101  
   102  // Provider returns the environment provider that created this env.
   103  func (*environ) Provider() environs.EnvironProvider {
   104  	return providerInstance
   105  }
   106  
   107  // Region returns the CloudSpec to use for the provider, as configured.
   108  func (env *environ) Region() (simplestreams.CloudSpec, error) {
   109  	return env.cloudSpec(env.ecfg.region()), nil
   110  }
   111  
   112  func (env *environ) cloudSpec(region string) simplestreams.CloudSpec {
   113  	return simplestreams.CloudSpec{
   114  		Region:   region,
   115  		Endpoint: env.ecfg.imageEndpoint(),
   116  	}
   117  }
   118  
   119  // SetConfig updates the env's configuration.
   120  func (env *environ) SetConfig(cfg *config.Config) error {
   121  	env.lock.Lock()
   122  	defer env.lock.Unlock()
   123  
   124  	if env.ecfg == nil {
   125  		return errors.New("cannot set config on uninitialized env")
   126  	}
   127  
   128  	if err := env.ecfg.update(cfg); err != nil {
   129  		return errors.Annotate(err, "invalid config change")
   130  	}
   131  	return nil
   132  }
   133  
   134  var newConnection = func(ecfg *environConfig) (gceConnection, error) {
   135  	connCfg := ecfg.newConnection()
   136  	auth := ecfg.auth()
   137  	return google.Connect(connCfg, auth)
   138  }
   139  
   140  // getSnapshot returns a copy of the environment. This is useful for
   141  // ensuring the env you are using does not get changed by other code
   142  // while you are using it.
   143  func (env environ) getSnapshot() *environ {
   144  	return &env
   145  }
   146  
   147  // Config returns the configuration data with which the env was created.
   148  func (env *environ) Config() *config.Config {
   149  	return env.getSnapshot().ecfg.Config
   150  }
   151  
   152  var bootstrap = common.Bootstrap
   153  
   154  // Bootstrap creates a new instance, chosing the series and arch out of
   155  // available tools. The series and arch are returned along with a func
   156  // that must be called to finalize the bootstrap process by transferring
   157  // the tools and installing the initial juju state server.
   158  func (env *environ) Bootstrap(ctx environs.BootstrapContext, params environs.BootstrapParams) (arch, series string, _ environs.BootstrapFinalizer, _ error) {
   159  	return bootstrap(ctx, env, params)
   160  }
   161  
   162  var destroyEnv = common.Destroy
   163  
   164  // Destroy shuts down all known machines and destroys the rest of the
   165  // known environment.
   166  func (env *environ) Destroy() error {
   167  	ports, err := env.Ports()
   168  	if err != nil {
   169  		return errors.Trace(err)
   170  	}
   171  
   172  	if len(ports) > 0 {
   173  		if err := env.ClosePorts(ports); err != nil {
   174  			return errors.Trace(err)
   175  		}
   176  	}
   177  
   178  	return destroyEnv(env)
   179  }