github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/ec2/provider_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	"gopkg.in/amz.v3/aws"
    13  	ec2cloud "gopkg.in/amz.v3/ec2"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/cloud"
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/environs/context"
    19  	"github.com/juju/juju/provider/common"
    20  	"github.com/juju/juju/provider/ec2"
    21  	coretesting "github.com/juju/juju/testing"
    22  )
    23  
    24  type ProviderSuite struct {
    25  	testing.IsolationSuite
    26  	spec     environs.CloudSpec
    27  	provider environs.EnvironProvider
    28  }
    29  
    30  var _ = gc.Suite(&ProviderSuite{})
    31  
    32  func (s *ProviderSuite) SetUpTest(c *gc.C) {
    33  	s.IsolationSuite.SetUpTest(c)
    34  
    35  	credential := cloud.NewCredential(
    36  		cloud.AccessKeyAuthType,
    37  		map[string]string{
    38  			"access-key": "foo",
    39  			"secret-key": "bar",
    40  		},
    41  	)
    42  	s.spec = environs.CloudSpec{
    43  		Type:       "ec2",
    44  		Name:       "aws",
    45  		Region:     "us-east-1",
    46  		Credential: &credential,
    47  	}
    48  
    49  	provider, err := environs.Provider("ec2")
    50  	c.Assert(err, jc.ErrorIsNil)
    51  	s.provider = provider
    52  }
    53  
    54  func (s *ProviderSuite) TestOpen(c *gc.C) {
    55  	env, err := environs.Open(s.provider, environs.OpenParams{
    56  		Cloud:  s.spec,
    57  		Config: coretesting.ModelConfig(c),
    58  	})
    59  	c.Assert(err, jc.ErrorIsNil)
    60  	c.Assert(env, gc.NotNil)
    61  }
    62  
    63  func (s *ProviderSuite) TestOpenUnknownRegion(c *gc.C) {
    64  	// This test shows that we do *not* check the region names against
    65  	// anything in the client. That means that when new regions are
    66  	// added to AWS, we'll be able to support them.
    67  	s.spec.Region = "foobar"
    68  	_, err := environs.Open(s.provider, environs.OpenParams{
    69  		Cloud:  s.spec,
    70  		Config: coretesting.ModelConfig(c),
    71  	})
    72  	c.Assert(err, jc.ErrorIsNil)
    73  }
    74  
    75  func (s *ProviderSuite) TestOpenKnownRegionInvalidEndpoint(c *gc.C) {
    76  	s.PatchValue(&aws.Regions, map[string]aws.Region{
    77  		"us-east-1": {
    78  			EC2Endpoint: "https://testing.invalid",
    79  		},
    80  	})
    81  	s.spec.Endpoint = "https://us-east-1.aws.amazon.com/v1.2/"
    82  
    83  	env, err := environs.Open(s.provider, environs.OpenParams{
    84  		Cloud:  s.spec,
    85  		Config: coretesting.ModelConfig(c),
    86  	})
    87  	c.Assert(err, jc.ErrorIsNil)
    88  
    89  	ec2Client := ec2.EnvironEC2(env)
    90  	c.Assert(ec2Client.Region.EC2Endpoint, gc.Equals, "https://testing.invalid")
    91  }
    92  
    93  func (s *ProviderSuite) TestOpenKnownRegionValidEndpoint(c *gc.C) {
    94  	// If the endpoint in the cloudspec is not known to be invalid,
    95  	// we ignore whatever is in aws.Regions. This way, if the AWS
    96  	// endpoints do ever change, we can update public-clouds.yaml
    97  	// and have it picked up.
    98  	s.PatchValue(&aws.Regions, map[string]aws.Region{
    99  		"us-east-1": {
   100  			EC2Endpoint: "https://testing.invalid",
   101  		},
   102  	})
   103  	s.spec.Endpoint = "https://ec2.us-east-1.amazonaws.com"
   104  
   105  	env, err := environs.Open(s.provider, environs.OpenParams{
   106  		Cloud:  s.spec,
   107  		Config: coretesting.ModelConfig(c),
   108  	})
   109  	c.Assert(err, jc.ErrorIsNil)
   110  
   111  	ec2Client := ec2.EnvironEC2(env)
   112  	c.Assert(ec2Client.Region.EC2Endpoint, gc.Equals, "https://ec2.us-east-1.amazonaws.com")
   113  }
   114  
   115  func (s *ProviderSuite) TestOpenMissingCredential(c *gc.C) {
   116  	s.spec.Credential = nil
   117  	s.testOpenError(c, s.spec, `validating cloud spec: missing credential not valid`)
   118  }
   119  
   120  func (s *ProviderSuite) TestOpenUnsupportedCredential(c *gc.C) {
   121  	credential := cloud.NewCredential(cloud.UserPassAuthType, map[string]string{})
   122  	s.spec.Credential = &credential
   123  	s.testOpenError(c, s.spec, `validating cloud spec: "userpass" auth-type not supported`)
   124  }
   125  
   126  func (s *ProviderSuite) testOpenError(c *gc.C, spec environs.CloudSpec, expect string) {
   127  	_, err := environs.Open(s.provider, environs.OpenParams{
   128  		Cloud:  spec,
   129  		Config: coretesting.ModelConfig(c),
   130  	})
   131  	c.Assert(err, gc.ErrorMatches, expect)
   132  }
   133  
   134  func (s *ProviderSuite) TestVerifyCredentialsErrs(c *gc.C) {
   135  	env, err := environs.Open(s.provider, environs.OpenParams{
   136  		Cloud:  s.spec,
   137  		Config: coretesting.ModelConfig(c),
   138  	})
   139  	c.Assert(err, jc.ErrorIsNil)
   140  	c.Assert(env, gc.NotNil)
   141  
   142  	err = ec2.VerifyCredentials(env, context.NewCloudCallContext())
   143  	c.Assert(err, gc.Not(jc.ErrorIsNil))
   144  	c.Assert(err, gc.Not(jc.Satisfies), common.IsCredentialNotValid)
   145  }
   146  
   147  func (s *ProviderSuite) TestMaybeConvertCredentialErrorIgnoresNil(c *gc.C) {
   148  	err := ec2.MaybeConvertCredentialError(nil, context.NewCloudCallContext())
   149  	c.Assert(err, jc.ErrorIsNil)
   150  }
   151  
   152  func (s *ProviderSuite) TestMaybeConvertCredentialErrorConvertsCredentialRelatedFailures(c *gc.C) {
   153  	for _, code := range []string{
   154  		"AuthFailure",
   155  		"InvalidClientTokenId",
   156  		"MissingAuthenticationToken",
   157  		"Blocked",
   158  		"CustomerKeyHasBeenRevoked",
   159  		"PendingVerification",
   160  		"SignatureDoesNotMatch",
   161  	} {
   162  		err := ec2.MaybeConvertCredentialError(&ec2cloud.Error{Code: code}, context.NewCloudCallContext())
   163  		c.Assert(err, gc.NotNil)
   164  		c.Assert(err, jc.Satisfies, common.IsCredentialNotValid)
   165  	}
   166  }
   167  
   168  func (s *ProviderSuite) TestMaybeConvertCredentialErrorAppendsAuthorisationFailureMessage(c *gc.C) {
   169  	for _, code := range []string{
   170  		"OptInRequired",
   171  		"UnauthorizedOperation",
   172  	} {
   173  		err := ec2.MaybeConvertCredentialError(&ec2cloud.Error{Code: code}, context.NewCloudCallContext())
   174  		c.Assert(err, gc.NotNil)
   175  		c.Assert(err, gc.Not(jc.Satisfies), common.IsCredentialNotValid)
   176  		c.Assert(err.Error(), jc.Contains, fmt.Sprintf("\nPlease subscribe to the requested Amazon service. \n"+
   177  			"You are currently not authorized to use it.\n"+
   178  			"New Amazon accounts might take some time to be activated while \n"+
   179  			"your details are being verified.:  (%v)", code))
   180  	}
   181  }
   182  
   183  func (s *ProviderSuite) TestMaybeConvertCredentialErrorHandlesOtherProviderErrors(c *gc.C) {
   184  	// Any other ec2.Error is returned unwrapped.
   185  	err := ec2.MaybeConvertCredentialError(&ec2cloud.Error{Code: "DryRunOperation"}, context.NewCloudCallContext())
   186  	c.Assert(err, gc.Not(jc.ErrorIsNil))
   187  	c.Assert(err, gc.Not(jc.Satisfies), common.IsCredentialNotValid)
   188  }
   189  
   190  func (s *ProviderSuite) TestConvertedCredentialError(c *gc.C) {
   191  	// Trace() will keep error type
   192  	inner := ec2.MaybeConvertCredentialError(&ec2cloud.Error{Code: "Blocked"}, context.NewCloudCallContext())
   193  	traced := errors.Trace(inner)
   194  	c.Assert(traced, gc.NotNil)
   195  	c.Assert(traced, jc.Satisfies, common.IsCredentialNotValid)
   196  
   197  	// Annotate() will keep error type
   198  	annotated := errors.Annotate(inner, "annotation")
   199  	c.Assert(annotated, gc.NotNil)
   200  	c.Assert(annotated, jc.Satisfies, common.IsCredentialNotValid)
   201  
   202  	// Running a CredentialNotValid through conversion call again is a no-op.
   203  	again := ec2.MaybeConvertCredentialError(inner, context.NewCloudCallContext())
   204  	c.Assert(again, gc.NotNil)
   205  	c.Assert(again, jc.Satisfies, common.IsCredentialNotValid)
   206  	c.Assert(again.Error(), jc.Contains, "\nYour Amazon account is currently blocked.:  (Blocked)")
   207  
   208  	// Running an annotated CredentialNotValid through conversion call again is a no-op too.
   209  	againAnotated := ec2.MaybeConvertCredentialError(annotated, context.NewCloudCallContext())
   210  	c.Assert(againAnotated, gc.NotNil)
   211  	c.Assert(againAnotated, jc.Satisfies, common.IsCredentialNotValid)
   212  	c.Assert(againAnotated.Error(), jc.Contains, "\nYour Amazon account is currently blocked.:  (Blocked)")
   213  }