github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/joyent/environ.go (about) 1 // Copyright 2013 Joyent Inc. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package joyent 5 6 import ( 7 "fmt" 8 "sync" 9 10 "github.com/juju/errors" 11 12 "github.com/juju/juju/constraints" 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/environs/imagemetadata" 16 "github.com/juju/juju/environs/simplestreams" 17 "github.com/juju/juju/environs/storage" 18 "github.com/juju/juju/instance" 19 "github.com/juju/juju/provider/common" 20 "github.com/juju/juju/state" 21 ) 22 23 // This file contains the core of the Joyent Environ implementation. 24 25 type joyentEnviron struct { 26 common.SupportsUnitPlacementPolicy 27 28 name string 29 30 // supportedArchitectures caches the architectures 31 // for which images can be instantiated. 32 archLock sync.Mutex 33 supportedArchitectures []string 34 35 // All mutating operations should lock the mutex. Non-mutating operations 36 // should read all fields (other than name, which is immutable) from a 37 // shallow copy taken with getSnapshot(). 38 // This advice is predicated on the goroutine-safety of the values of the 39 // affected fields. 40 lock sync.Mutex 41 ecfg *environConfig 42 storage storage.Storage 43 compute *joyentCompute 44 } 45 46 var _ environs.Environ = (*joyentEnviron)(nil) 47 var _ state.Prechecker = (*joyentEnviron)(nil) 48 49 // newEnviron create a new Joyent environ instance from config. 50 func newEnviron(cfg *config.Config) (*joyentEnviron, error) { 51 env := new(joyentEnviron) 52 if err := env.SetConfig(cfg); err != nil { 53 return nil, err 54 } 55 env.name = cfg.Name() 56 var err error 57 env.storage, err = newStorage(env.ecfg, "") 58 if err != nil { 59 return nil, err 60 } 61 env.compute, err = newCompute(env.ecfg) 62 if err != nil { 63 return nil, err 64 } 65 return env, nil 66 } 67 68 func (env *joyentEnviron) SetName(envName string) { 69 env.name = envName 70 } 71 72 func (*joyentEnviron) Provider() environs.EnvironProvider { 73 return providerInstance 74 } 75 76 // PrecheckInstance is defined on the state.Prechecker interface. 77 func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error { 78 if placement != "" { 79 return fmt.Errorf("unknown placement directive: %s", placement) 80 } 81 if !cons.HasInstanceType() { 82 return nil 83 } 84 // Constraint has an instance-type constraint so let's see if it is valid. 85 instanceTypes, err := env.listInstanceTypes() 86 if err != nil { 87 return err 88 } 89 for _, instanceType := range instanceTypes { 90 if instanceType.Name == *cons.InstanceType { 91 return nil 92 } 93 } 94 return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType) 95 } 96 97 // SupportedArchitectures is specified on the EnvironCapability interface. 98 func (env *joyentEnviron) SupportedArchitectures() ([]string, error) { 99 env.archLock.Lock() 100 defer env.archLock.Unlock() 101 if env.supportedArchitectures != nil { 102 return env.supportedArchitectures, nil 103 } 104 cfg := env.Ecfg() 105 // Create a filter to get all images from our region and for the correct stream. 106 cloudSpec := simplestreams.CloudSpec{ 107 Region: cfg.Region(), 108 Endpoint: cfg.SdcUrl(), 109 } 110 imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{ 111 CloudSpec: cloudSpec, 112 Stream: cfg.ImageStream(), 113 }) 114 var err error 115 env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint) 116 return env.supportedArchitectures, err 117 } 118 119 func (env *joyentEnviron) SetConfig(cfg *config.Config) error { 120 env.lock.Lock() 121 defer env.lock.Unlock() 122 ecfg, err := providerInstance.newConfig(cfg) 123 if err != nil { 124 return err 125 } 126 env.ecfg = ecfg 127 return nil 128 } 129 130 func (env *joyentEnviron) getSnapshot() *joyentEnviron { 131 env.lock.Lock() 132 clone := *env 133 env.lock.Unlock() 134 clone.lock = sync.Mutex{} 135 return &clone 136 } 137 138 func (env *joyentEnviron) Config() *config.Config { 139 return env.getSnapshot().ecfg.Config 140 } 141 142 func (env *joyentEnviron) Storage() storage.Storage { 143 return env.getSnapshot().storage 144 } 145 146 func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (arch, series string, _ environs.BootstrapFinalizer, _ error) { 147 return common.Bootstrap(ctx, env, args) 148 } 149 150 func (env *joyentEnviron) StateServerInstances() ([]instance.Id, error) { 151 return common.ProviderStateInstances(env, env.Storage()) 152 } 153 154 func (env *joyentEnviron) Destroy() error { 155 if err := common.Destroy(env); err != nil { 156 return errors.Trace(err) 157 } 158 return env.Storage().RemoveAll() 159 } 160 161 func (env *joyentEnviron) Ecfg() *environConfig { 162 return env.getSnapshot().ecfg 163 } 164 165 // MetadataLookupParams returns parameters which are used to query simplestreams metadata. 166 func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) { 167 if region == "" { 168 region = env.Ecfg().Region() 169 } 170 return &simplestreams.MetadataLookupParams{ 171 Series: config.PreferredSeries(env.Ecfg()), 172 Region: region, 173 Endpoint: env.Ecfg().sdcUrl(), 174 Architectures: []string{"amd64", "armhf"}, 175 }, nil 176 } 177 178 // Region is specified in the HasRegion interface. 179 func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) { 180 return simplestreams.CloudSpec{ 181 Region: env.Ecfg().Region(), 182 Endpoint: env.Ecfg().sdcUrl(), 183 }, nil 184 }