github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 "strings" 9 "sync" 10 11 "github.com/joyent/gosdc/cloudapi" 12 "github.com/juju/errors" 13 14 "github.com/juju/juju/constraints" 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/environs/simplestreams" 18 "github.com/juju/juju/environs/tags" 19 "github.com/juju/juju/instance" 20 "github.com/juju/juju/provider/common" 21 ) 22 23 // This file contains the core of the Joyent Environ implementation. 24 25 type joyentEnviron struct { 26 name string 27 cloud environs.CloudSpec 28 compute *joyentCompute 29 30 lock sync.Mutex // protects ecfg 31 ecfg *environConfig 32 } 33 34 // newEnviron create a new Joyent environ instance from config. 35 func newEnviron(cloud environs.CloudSpec, cfg *config.Config) (*joyentEnviron, error) { 36 env := &joyentEnviron{ 37 name: cfg.Name(), 38 cloud: cloud, 39 } 40 if err := env.SetConfig(cfg); err != nil { 41 return nil, err 42 } 43 var err error 44 env.compute, err = newCompute(cloud) 45 if err != nil { 46 return nil, err 47 } 48 return env, nil 49 } 50 51 func (env *joyentEnviron) SetName(envName string) { 52 env.name = envName 53 } 54 55 func (*joyentEnviron) Provider() environs.EnvironProvider { 56 return providerInstance 57 } 58 59 // PrecheckInstance is defined on the state.Prechecker interface. 60 func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error { 61 if placement != "" { 62 return fmt.Errorf("unknown placement directive: %s", placement) 63 } 64 if !cons.HasInstanceType() { 65 return nil 66 } 67 // Constraint has an instance-type constraint so let's see if it is valid. 68 instanceTypes, err := env.listInstanceTypes() 69 if err != nil { 70 return err 71 } 72 for _, instanceType := range instanceTypes { 73 if instanceType.Name == *cons.InstanceType { 74 return nil 75 } 76 } 77 return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType) 78 } 79 80 func (env *joyentEnviron) SetConfig(cfg *config.Config) error { 81 env.lock.Lock() 82 defer env.lock.Unlock() 83 ecfg, err := providerInstance.newConfig(cfg) 84 if err != nil { 85 return err 86 } 87 env.ecfg = ecfg 88 return nil 89 } 90 91 func (env *joyentEnviron) Config() *config.Config { 92 return env.Ecfg().Config 93 } 94 95 // Create is part of the Environ interface. 96 func (env *joyentEnviron) Create(environs.CreateParams) error { 97 if err := verifyCredentials(env); err != nil { 98 return errors.Trace(err) 99 } 100 return nil 101 } 102 103 func (env *joyentEnviron) PrepareForBootstrap(ctx environs.BootstrapContext) error { 104 if ctx.ShouldVerifyCredentials() { 105 if err := verifyCredentials(env); err != nil { 106 return errors.Trace(err) 107 } 108 } 109 return nil 110 } 111 112 func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) { 113 return common.Bootstrap(ctx, env, args) 114 } 115 116 func (env *joyentEnviron) ControllerInstances(controllerUUID string) ([]instance.Id, error) { 117 instanceIds := []instance.Id{} 118 119 filter := cloudapi.NewFilter() 120 filter.Set(tagKey("group"), "juju") 121 filter.Set(tagKey(tags.JujuModel), controllerUUID) 122 filter.Set(tagKey(tags.JujuIsController), "true") 123 124 machines, err := env.compute.cloudapi.ListMachines(filter) 125 if err != nil || len(machines) == 0 { 126 return nil, environs.ErrNotBootstrapped 127 } 128 129 for _, m := range machines { 130 if strings.EqualFold(m.State, "provisioning") || strings.EqualFold(m.State, "running") { 131 copy := m 132 ji := &joyentInstance{machine: ©, env: env} 133 instanceIds = append(instanceIds, ji.Id()) 134 } 135 } 136 137 return instanceIds, nil 138 } 139 140 func (env *joyentEnviron) Destroy() error { 141 return errors.Trace(common.Destroy(env)) 142 } 143 144 // DestroyController implements the Environ interface. 145 func (env *joyentEnviron) DestroyController(controllerUUID string) error { 146 // TODO(wallyworld): destroy hosted model resources 147 return env.Destroy() 148 } 149 150 func (env *joyentEnviron) Ecfg() *environConfig { 151 env.lock.Lock() 152 defer env.lock.Unlock() 153 return env.ecfg 154 } 155 156 // MetadataLookupParams returns parameters which are used to query simplestreams metadata. 157 func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) { 158 if region == "" { 159 region = env.cloud.Region 160 } 161 return &simplestreams.MetadataLookupParams{ 162 Series: config.PreferredSeries(env.Ecfg()), 163 Region: region, 164 Endpoint: env.cloud.Endpoint, 165 }, nil 166 } 167 168 // Region is specified in the HasRegion interface. 169 func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) { 170 return simplestreams.CloudSpec{ 171 Region: env.cloud.Region, 172 Endpoint: env.cloud.Endpoint, 173 }, nil 174 }