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  }