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