github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/rackspace/environ_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package rackspace_test 5 6 import ( 7 "io" 8 "os" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils/ssh" 13 "github.com/juju/version" 14 gc "gopkg.in/check.v1" 15 gooseerrors "gopkg.in/goose.v2/errors" 16 17 "github.com/juju/juju/cloudconfig/instancecfg" 18 "github.com/juju/juju/core/constraints" 19 "github.com/juju/juju/core/instance" 20 "github.com/juju/juju/core/status" 21 "github.com/juju/juju/environs" 22 "github.com/juju/juju/environs/config" 23 "github.com/juju/juju/environs/context" 24 "github.com/juju/juju/environs/instances" 25 "github.com/juju/juju/network" 26 "github.com/juju/juju/provider/common" 27 "github.com/juju/juju/provider/rackspace" 28 "github.com/juju/juju/storage" 29 "github.com/juju/juju/testing" 30 "github.com/juju/juju/tools" 31 ) 32 33 type environSuite struct { 34 testing.BaseSuite 35 environ environs.Environ 36 innerEnviron *fakeEnviron 37 38 callCtx *context.CloudCallContext 39 invalidCredential bool 40 } 41 42 var _ = gc.Suite(&environSuite{}) 43 44 func (s *environSuite) SetUpTest(c *gc.C) { 45 s.BaseSuite.SetUpTest(c) 46 s.innerEnviron = new(fakeEnviron) 47 s.environ = rackspace.NewEnviron(s.innerEnviron) 48 s.callCtx = &context.CloudCallContext{ 49 InvalidateCredentialFunc: func(string) error { 50 s.invalidCredential = true 51 return nil 52 }, 53 } 54 } 55 56 func (s *environSuite) TearDownTest(c *gc.C) { 57 s.invalidCredential = false 58 s.BaseSuite.TearDownTest(c) 59 } 60 61 func (s *environSuite) TestBootstrap(c *gc.C) { 62 s.PatchValue(rackspace.Bootstrap, func(ctx environs.BootstrapContext, env environs.Environ, callCtx context.ProviderCallContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) { 63 return s.innerEnviron.Bootstrap(ctx, callCtx, args) 64 }) 65 s.environ.Bootstrap(nil, s.callCtx, environs.BootstrapParams{ 66 ControllerConfig: testing.FakeControllerConfig(), 67 }) 68 c.Check(s.innerEnviron.Pop().name, gc.Equals, "Bootstrap") 69 } 70 71 func (s *environSuite) TestStartInstance(c *gc.C) { 72 configurator := &fakeConfigurator{} 73 s.PatchValue(rackspace.WaitSSH, func( 74 stdErr io.Writer, 75 interrupted <-chan os.Signal, 76 client ssh.Client, 77 checkHostScript string, 78 inst common.InstanceRefresher, 79 callCtx context.ProviderCallContext, 80 timeout environs.BootstrapDialOpts, 81 hostSSHOptions common.HostSSHOptionsFunc, 82 ) (addr string, err error) { 83 addresses, err := inst.Addresses(s.callCtx) 84 if err != nil { 85 return "", err 86 } 87 return addresses[0].Value, nil 88 }) 89 s.PatchValue(rackspace.NewInstanceConfigurator, func(host string) common.InstanceConfigurator { 90 return configurator 91 }) 92 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 93 "name": "some-name", 94 "type": "some-type", 95 "uuid": testing.ModelTag.Id(), 96 "controller-uuid": testing.ControllerTag.Id(), 97 "authorized-keys": "key", 98 }) 99 c.Assert(err, gc.IsNil) 100 err = s.environ.SetConfig(cfg) 101 c.Assert(err, gc.IsNil) 102 _, err = s.environ.StartInstance(s.callCtx, environs.StartInstanceParams{ 103 InstanceConfig: &instancecfg.InstanceConfig{}, 104 Tools: tools.List{&tools.Tools{ 105 Version: version.Binary{Series: "trusty"}, 106 }}, 107 }) 108 c.Check(err, gc.IsNil) 109 c.Check(s.innerEnviron.Pop().name, gc.Equals, "StartInstance") 110 dropParams := configurator.Pop() 111 c.Check(dropParams.name, gc.Equals, "DropAllPorts") 112 c.Check(dropParams.params[1], gc.Equals, "1.1.1.1") 113 } 114 115 var testUnauthorisedGooseError = gooseerrors.NewUnauthorisedf(nil, "", "invalid auth") 116 117 func (s *environSuite) TestStartInstanceInvalidCredential(c *gc.C) { 118 configurator := &fakeConfigurator{ 119 dropAllPortsF: func(exceptPorts []int, addr string) error { 120 return testUnauthorisedGooseError 121 }, 122 } 123 s.PatchValue(rackspace.WaitSSH, func( 124 stdErr io.Writer, 125 interrupted <-chan os.Signal, 126 client ssh.Client, 127 checkHostScript string, 128 inst common.InstanceRefresher, 129 callCtx context.ProviderCallContext, 130 timeout environs.BootstrapDialOpts, 131 hostSSHOptions common.HostSSHOptionsFunc, 132 ) (addr string, err error) { 133 addresses, err := inst.Addresses(s.callCtx) 134 if err != nil { 135 return "", err 136 } 137 return addresses[0].Value, nil 138 }) 139 s.PatchValue(rackspace.NewInstanceConfigurator, func(host string) common.InstanceConfigurator { 140 return configurator 141 }) 142 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 143 "name": "some-name", 144 "type": "some-type", 145 "uuid": testing.ModelTag.Id(), 146 "controller-uuid": testing.ControllerTag.Id(), 147 "authorized-keys": "key", 148 }) 149 c.Assert(err, gc.IsNil) 150 err = s.environ.SetConfig(cfg) 151 c.Assert(err, gc.IsNil) 152 153 c.Assert(s.invalidCredential, jc.IsFalse) 154 _, err = s.environ.StartInstance(s.callCtx, environs.StartInstanceParams{ 155 InstanceConfig: &instancecfg.InstanceConfig{}, 156 Tools: tools.List{&tools.Tools{ 157 Version: version.Binary{Series: "trusty"}, 158 }}, 159 }) 160 c.Assert(s.invalidCredential, jc.IsTrue) 161 c.Check(err, gc.ErrorMatches, "invalid auth") 162 c.Check(s.innerEnviron.Pop().name, gc.Equals, "StartInstance") 163 dropParams := configurator.Pop() 164 c.Check(dropParams.name, gc.Equals, "DropAllPorts") 165 c.Check(dropParams.params[1], gc.Equals, "1.1.1.1") 166 } 167 168 type methodCall struct { 169 name string 170 params []interface{} 171 } 172 173 type fakeEnviron struct { 174 config *config.Config 175 methodCalls []methodCall 176 } 177 178 func (p *fakeEnviron) Push(name string, params ...interface{}) { 179 p.methodCalls = append(p.methodCalls, methodCall{name, params}) 180 } 181 182 func (p *fakeEnviron) Pop() methodCall { 183 m := p.methodCalls[0] 184 p.methodCalls = p.methodCalls[1:] 185 return m 186 } 187 188 func (p *fakeEnviron) Open(cfg *config.Config) (environs.Environ, error) { 189 p.Push("Open", cfg) 190 return nil, nil 191 } 192 193 func (e *fakeEnviron) Create(callCtx context.ProviderCallContext, args environs.CreateParams) error { 194 e.Push("Create", callCtx, args) 195 return nil 196 } 197 198 func (e *fakeEnviron) PrepareForBootstrap(ctx environs.BootstrapContext) error { 199 e.Push("PrepareForBootstrap", ctx) 200 return nil 201 } 202 203 func (e *fakeEnviron) Bootstrap(ctx environs.BootstrapContext, callCtx context.ProviderCallContext, params environs.BootstrapParams) (*environs.BootstrapResult, error) { 204 e.Push("Bootstrap", ctx, callCtx, params) 205 return nil, nil 206 } 207 208 func (e *fakeEnviron) StartInstance(callCtx context.ProviderCallContext, args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { 209 e.Push("StartInstance", callCtx, args) 210 return &environs.StartInstanceResult{ 211 Instance: &fakeInstance{}, 212 }, nil 213 } 214 215 func (e *fakeEnviron) StopInstances(callCtx context.ProviderCallContext, ids ...instance.Id) error { 216 e.Push("StopInstances", callCtx, ids) 217 return nil 218 } 219 220 func (e *fakeEnviron) AllInstances(callCtx context.ProviderCallContext) ([]instances.Instance, error) { 221 e.Push("AllInstances", callCtx) 222 return nil, nil 223 } 224 225 func (e *fakeEnviron) MaintainInstance(callCtx context.ProviderCallContext, args environs.StartInstanceParams) error { 226 e.Push("MaintainInstance", callCtx, args) 227 return nil 228 } 229 230 func (e *fakeEnviron) Config() *config.Config { 231 return e.config 232 } 233 234 func (e *fakeEnviron) ConstraintsValidator(ctx context.ProviderCallContext) (constraints.Validator, error) { 235 e.Push("ConstraintsValidator", ctx) 236 return nil, nil 237 } 238 239 func (e *fakeEnviron) SetConfig(cfg *config.Config) error { 240 e.config = cfg 241 return nil 242 } 243 244 func (e *fakeEnviron) Instances(callCtx context.ProviderCallContext, ids []instance.Id) ([]instances.Instance, error) { 245 e.Push("Instances", callCtx, ids) 246 return []instances.Instance{&fakeInstance{}}, nil 247 } 248 249 func (e *fakeEnviron) ControllerInstances(callCtx context.ProviderCallContext, st string) ([]instance.Id, error) { 250 e.Push("ControllerInstances", callCtx, st) 251 return nil, nil 252 } 253 254 func (e *fakeEnviron) AdoptResources(callCtx context.ProviderCallContext, controllerUUID string, fromVersion version.Number) error { 255 e.Push("AdoptResources", callCtx, controllerUUID, fromVersion) 256 return nil 257 } 258 259 func (e *fakeEnviron) Destroy(callCtx context.ProviderCallContext) error { 260 e.Push("Destroy", callCtx) 261 return nil 262 } 263 264 func (e *fakeEnviron) DestroyController(callCtx context.ProviderCallContext, controllerUUID string) error { 265 e.Push("Destroy", callCtx, controllerUUID) 266 return nil 267 } 268 269 func (e *fakeEnviron) OpenPorts(callCtx context.ProviderCallContext, rules []network.IngressRule) error { 270 e.Push("OpenPorts", callCtx, rules) 271 return nil 272 } 273 274 func (e *fakeEnviron) ClosePorts(callCtx context.ProviderCallContext, rules []network.IngressRule) error { 275 e.Push("ClosePorts", callCtx, rules) 276 return nil 277 } 278 279 func (e *fakeEnviron) IngressRules(callCtx context.ProviderCallContext) ([]network.IngressRule, error) { 280 e.Push("Ports", callCtx) 281 return nil, nil 282 } 283 284 func (e *fakeEnviron) Provider() environs.EnvironProvider { 285 e.Push("Provider") 286 return nil 287 } 288 289 func (e *fakeEnviron) PrecheckInstance(callCtx context.ProviderCallContext, args environs.PrecheckInstanceParams) error { 290 e.Push("PrecheckInstance", callCtx, args) 291 return nil 292 } 293 294 func (e *fakeEnviron) StorageProviderTypes() ([]storage.ProviderType, error) { 295 e.Push("StorageProviderTypes") 296 return nil, nil 297 } 298 299 func (e *fakeEnviron) StorageProvider(t storage.ProviderType) (storage.Provider, error) { 300 e.Push("StorageProvider", t) 301 return nil, errors.NotImplementedf("StorageProvider") 302 } 303 304 func (e *fakeEnviron) InstanceTypes(context.ProviderCallContext, constraints.Value) (instances.InstanceTypesWithCostMetadata, error) { 305 return instances.InstanceTypesWithCostMetadata{}, nil 306 } 307 308 type fakeConfigurator struct { 309 methodCalls []methodCall 310 311 dropAllPortsF func(exceptPorts []int, addr string) error 312 } 313 314 func (p *fakeConfigurator) Push(name string, params ...interface{}) { 315 p.methodCalls = append(p.methodCalls, methodCall{name, params}) 316 } 317 318 func (p *fakeConfigurator) Pop() methodCall { 319 m := p.methodCalls[0] 320 p.methodCalls = p.methodCalls[1:] 321 return m 322 } 323 324 func (e *fakeConfigurator) DropAllPorts(exceptPorts []int, addr string) error { 325 e.Push("DropAllPorts", exceptPorts, addr) 326 if e.dropAllPortsF != nil { 327 return e.dropAllPortsF(exceptPorts, addr) 328 } 329 return nil 330 } 331 332 func (e *fakeConfigurator) ConfigureExternalIpAddress(apiPort int) error { 333 e.Push("ConfigureExternalIpAddress", apiPort) 334 return nil 335 } 336 337 func (e *fakeConfigurator) ChangeIngressRules(ipAddress string, insert bool, rules []network.IngressRule) error { 338 e.Push("ChangeIngressRules", ipAddress, insert, rules) 339 return nil 340 } 341 342 func (e *fakeConfigurator) FindIngressRules() ([]network.IngressRule, error) { 343 e.Push("FindIngressRules") 344 return nil, nil 345 } 346 347 type fakeInstance struct { 348 methodCalls []methodCall 349 } 350 351 func (p *fakeInstance) Push(name string, params ...interface{}) { 352 p.methodCalls = append(p.methodCalls, methodCall{name, params}) 353 } 354 355 func (p *fakeInstance) Pop() methodCall { 356 m := p.methodCalls[0] 357 p.methodCalls = p.methodCalls[1:] 358 return m 359 } 360 361 func (e *fakeInstance) Id() instance.Id { 362 e.Push("Id") 363 return instance.Id("") 364 } 365 366 func (e *fakeInstance) Status(callCtx context.ProviderCallContext) instance.Status { 367 e.Push("Status", callCtx) 368 return instance.Status{ 369 Status: status.Provisioning, 370 Message: "a message", 371 } 372 } 373 374 func (e *fakeInstance) Refresh(callCtx context.ProviderCallContext) error { 375 e.Push("Refresh", callCtx) 376 return nil 377 } 378 379 func (e *fakeInstance) Addresses(callCtx context.ProviderCallContext) ([]network.Address, error) { 380 e.Push("Addresses", callCtx) 381 return []network.Address{{ 382 Value: "1.1.1.1", 383 Type: network.IPv4Address, 384 Scope: network.ScopePublic, 385 }}, nil 386 } 387 388 func (e *fakeInstance) OpenPorts(callCtx context.ProviderCallContext, machineId string, ports []network.IngressRule) error { 389 e.Push("OpenPorts", callCtx, machineId, ports) 390 return nil 391 } 392 393 func (e *fakeInstance) ClosePorts(callCtx context.ProviderCallContext, machineId string, ports []network.IngressRule) error { 394 e.Push("ClosePorts", callCtx, machineId, ports) 395 return nil 396 } 397 398 func (e *fakeInstance) IngressRules(callCtx context.ProviderCallContext, machineId string) ([]network.IngressRule, error) { 399 e.Push("Ports", callCtx, machineId) 400 return nil, nil 401 }