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