From b64ee9843f8d6029eddbffa532a6587a1b877eda Mon Sep 17 00:00:00 2001 From: hasheddan Date: Thu, 6 Feb 2020 12:15:45 -0600 Subject: [PATCH 1/4] Allow stack-aws to use web identity tokens via IAM roles for ServiceAccounts Signed-off-by: hasheddan --- apis/v1alpha3/types.go | 5 ++ apis/v1alpha3/zz_generated.deepcopy.go | 7 +- config/crd/aws.crossplane.io_providers.yaml | 5 ++ go.sum | 4 ++ pkg/clients/aws.go | 45 +++++++++++++ pkg/clients/cloudformation/cloudformation.go | 9 +-- pkg/clients/eks/eks.go | 13 ++-- pkg/clients/elasticache/elasticache.go | 2 +- pkg/clients/elasticache/fake/fake.go | 4 +- pkg/clients/iam/iam.go | 31 ++++----- pkg/clients/rds/rds.go | 16 +++-- pkg/clients/s3/operations/requests.go | 16 +++-- pkg/clients/s3/operations/s3_operations.go | 4 +- pkg/clients/s3/s3.go | 11 ++-- pkg/controller/cache/managed.go | 14 ++-- .../database/dbsubnetgroup/controller.go | 9 +-- pkg/controller/database/rdsinstance.go | 24 +++---- pkg/controller/database/rdsinstance_test.go | 64 +++++++++++++++---- pkg/controller/identity/iamrole/controller.go | 9 +-- .../iamrolepolicyattachment/controller.go | 15 ++--- .../network/internetgateway/controller.go | 15 ++--- .../network/routetable/controller.go | 21 ++---- .../network/securitygroup/controller.go | 20 ++---- pkg/controller/network/subnet/controller.go | 9 +-- pkg/controller/network/vpc/controller.go | 12 ++-- 25 files changed, 227 insertions(+), 157 deletions(-) diff --git a/apis/v1alpha3/types.go b/apis/v1alpha3/types.go index 05788c8111..ad74b35ce0 100644 --- a/apis/v1alpha3/types.go +++ b/apis/v1alpha3/types.go @@ -28,6 +28,11 @@ type ProviderSpec struct { // Region for managed resources created using this AWS provider. Region string `json:"region"` + + // UseServiceAccount indicates to use an IAM Role associated Kubernetes + // ServiceAccount for authentication instead of a credentials Secret. + // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html + UseServiceAccount *bool `json:"useServiceAccount,omitempty"` } // +kubebuilder:object:root=true diff --git a/apis/v1alpha3/zz_generated.deepcopy.go b/apis/v1alpha3/zz_generated.deepcopy.go index 979495a836..569546be2b 100644 --- a/apis/v1alpha3/zz_generated.deepcopy.go +++ b/apis/v1alpha3/zz_generated.deepcopy.go @@ -29,7 +29,7 @@ func (in *Provider) DeepCopyInto(out *Provider) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Provider. @@ -86,6 +86,11 @@ func (in *ProviderList) DeepCopyObject() runtime.Object { func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) { *out = *in out.ProviderSpec = in.ProviderSpec + if in.UseServiceAccount != nil { + in, out := &in.UseServiceAccount, &out.UseServiceAccount + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpec. diff --git a/config/crd/aws.crossplane.io_providers.yaml b/config/crd/aws.crossplane.io_providers.yaml index 1eee5700fb..4a28e96c06 100644 --- a/config/crd/aws.crossplane.io_providers.yaml +++ b/config/crd/aws.crossplane.io_providers.yaml @@ -68,6 +68,11 @@ spec: region: description: Region for managed resources created using this AWS provider. type: string + useServiceAccount: + description: UseServiceAccount indicates to use an IAM Role associated + Kubernetes ServiceAccount for authentication instead of a credentials + Secret. https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html + type: boolean required: - credentialsSecretRef - region diff --git a/go.sum b/go.sum index f8068f9040..02be5f887b 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tv github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= github.com/aws/aws-sdk-go-v2 v0.5.0 h1:EYMvJVajBzaGlPb8z761lkejQKsz0FM6+78lfQ/UexA= github.com/aws/aws-sdk-go-v2 v0.5.0/go.mod h1:5/URWM5KZOrZ0sp9aiPT0FrXgFJFPJ143F6SGgnTfXY= +github.com/aws/aws-sdk-go-v2 v0.19.0 h1:jVKVeRBQah2OwqXRoy8bnWWgpo2sXk/bWf2J2tog+lk= +github.com/aws/aws-sdk-go-v2 v0.19.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -229,6 +231,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= diff --git a/pkg/clients/aws.go b/pkg/clients/aws.go index 4583e389fd..8a4ef882fd 100644 --- a/pkg/clients/aws.go +++ b/pkg/clients/aws.go @@ -17,10 +17,16 @@ limitations under the License. package aws import ( + "context" "encoding/json" + "io/ioutil" + "os" + "strconv" + "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/external" + "github.com/aws/aws-sdk-go-v2/service/sts" jsonpatch "github.com/evanphx/json-patch" "github.com/go-ini/ini" ) @@ -92,6 +98,45 @@ func LoadConfig(data []byte, profile, region string) (*aws.Config, error) { return &config, err } +// LoadSAConfig assumes an IAM role configured via a ServiceAccount. +// https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html +func LoadSAConfig(ctx context.Context, region string) (*aws.Config, error) { + cfg, err := external.LoadDefaultAWSConfig() + if err != nil { + return nil, err + } + cfg.Region = region + svc := sts.New(cfg) + + b, err := ioutil.ReadFile(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")) + if err != nil { + return nil, err + } + token := string(b) + sess := strconv.FormatInt(time.Now().UnixNano(), 10) + role := os.Getenv("AWS_ROLE_ARN") + resp, err := svc.AssumeRoleWithWebIdentityRequest( + &sts.AssumeRoleWithWebIdentityInput{ + RoleSessionName: &sess, + WebIdentityToken: &token, + RoleArn: &role, + }).Send(ctx) + if err != nil { + return nil, err + } + creds := aws.Credentials{ + AccessKeyID: aws.StringValue(resp.Credentials.AccessKeyId), + SecretAccessKey: aws.StringValue(resp.Credentials.SecretAccessKey), + SessionToken: aws.StringValue(resp.Credentials.SessionToken), + } + shared := external.SharedConfig{ + Credentials: creds, + Region: region, + } + config, err := external.LoadDefaultAWSConfig(shared) + return &config, err +} + // TODO(muvaf): All the types that use CreateJSONPatch are known during // development time. In order to avoid unnecessary panic checks, we can generate // the code that creates a patch between two objects that share the same type. diff --git a/pkg/clients/cloudformation/cloudformation.go b/pkg/clients/cloudformation/cloudformation.go index c49e2cc9b8..916fd01d70 100644 --- a/pkg/clients/cloudformation/cloudformation.go +++ b/pkg/clients/cloudformation/cloudformation.go @@ -17,6 +17,7 @@ limitations under the License. package cloudformation import ( + "context" "fmt" "github.com/aws/aws-sdk-go-v2/aws" @@ -33,7 +34,7 @@ type Client interface { } type cloudFormationClient struct { - cloudformation cfiface.CloudFormationAPI + cloudformation cfiface.ClientAPI } // NewClient return new instance of the crossplane client for a specific AWS configuration @@ -50,7 +51,7 @@ func (c *cloudFormationClient) CreateStack(stackName *string, templateBody *stri } } - createStackResponse, err := c.cloudformation.CreateStackRequest(&cf.CreateStackInput{Capabilities: []cf.Capability{cf.CapabilityCapabilityIam}, StackName: stackName, TemplateBody: templateBody, Parameters: cfParams}).Send() + createStackResponse, err := c.cloudformation.CreateStackRequest(&cf.CreateStackInput{Capabilities: []cf.Capability{cf.CapabilityCapabilityIam}, StackName: stackName, TemplateBody: templateBody, Parameters: cfParams}).Send(context.TODO()) if err != nil { return nil, err } @@ -59,7 +60,7 @@ func (c *cloudFormationClient) CreateStack(stackName *string, templateBody *stri // GetStack info func (c *cloudFormationClient) GetStack(stackID *string) (stack *cf.Stack, err error) { - describeStackResponse, err := c.cloudformation.DescribeStacksRequest(&cf.DescribeStacksInput{StackName: stackID}).Send() + describeStackResponse, err := c.cloudformation.DescribeStacksRequest(&cf.DescribeStacksInput{StackName: stackID}).Send(context.TODO()) if err != nil { return nil, err } @@ -75,7 +76,7 @@ func (c *cloudFormationClient) GetStack(stackID *string) (stack *cf.Stack, err e // DeleteStack deletes a stack func (c *cloudFormationClient) DeleteStack(stackID *string) error { - _, err := c.cloudformation.DeleteStackRequest(&cf.DeleteStackInput{StackName: stackID}).Send() + _, err := c.cloudformation.DeleteStackRequest(&cf.DeleteStackInput{StackName: stackID}).Send(context.TODO()) return err } diff --git a/pkg/clients/eks/eks.go b/pkg/clients/eks/eks.go index e875a3acc6..40cf63e787 100644 --- a/pkg/clients/eks/eks.go +++ b/pkg/clients/eks/eks.go @@ -17,6 +17,7 @@ limitations under the License. package eks import ( + "context" "encoding/base64" "errors" "fmt" @@ -105,9 +106,9 @@ type AMIClient interface { } type eksClient struct { - eks eksiface.EKSAPI + eks eksiface.ClientAPI amiClient AMIClient - sts *sts.STS + sts *sts.Client cloudformation cfc.Client } @@ -131,7 +132,7 @@ func (e *eksClient) Create(name string, spec awscomputev1alpha3.EKSClusterSpec) input.Version = aws.String(spec.ClusterVersion) } - output, err := e.eks.CreateClusterRequest(input).Send() + output, err := e.eks.CreateClusterRequest(input).Send(context.TODO()) if err != nil { return nil, err } @@ -184,7 +185,7 @@ func (e *eksClient) CreateWorkerNodes(name string, clusterVersion string, spec a // Get an existing EKS cluster func (e *eksClient) Get(name string) (*Cluster, error) { input := &eks.DescribeClusterInput{Name: aws.String(name)} - output, err := e.eks.DescribeClusterRequest(input).Send() + output, err := e.eks.DescribeClusterRequest(input).Send(context.TODO()) if err != nil { return nil, err } @@ -215,7 +216,7 @@ func (e *eksClient) GetWorkerNodes(stackID string) (*ClusterWorkers, error) { // Delete a EKS cluster func (e *eksClient) Delete(name string) error { input := &eks.DeleteClusterInput{Name: aws.String(name)} - _, err := e.eks.DeleteClusterRequest(input).Send() + _, err := e.eks.DeleteClusterRequest(input).Send(context.TODO()) return err } @@ -286,7 +287,7 @@ func (e *eksClient) getAvailableImages(clusterVersion string) ([]*ec2.Image, err request := e.amiClient.DescribeImagesRequest(&ec2.DescribeImagesInput{ Filters: ec2Filters, }) - out, err := request.Send() + out, err := request.Send(context.TODO()) if err != nil { return nil, err diff --git a/pkg/clients/elasticache/elasticache.go b/pkg/clients/elasticache/elasticache.go index 07f5a7c5b0..11f38a8643 100644 --- a/pkg/clients/elasticache/elasticache.go +++ b/pkg/clients/elasticache/elasticache.go @@ -34,7 +34,7 @@ import ( // A Client handles CRUD operations for ElastiCache resources. This interface is // compatible with the upstream AWS redis client. -type Client elasticacheiface.ElastiCacheAPI +type Client elasticacheiface.ClientAPI // NewClient returns a new ElastiCache client. Credentials must be passed as // JSON encoded data. diff --git a/pkg/clients/elasticache/fake/fake.go b/pkg/clients/elasticache/fake/fake.go index 8940018e57..28378e8ca0 100644 --- a/pkg/clients/elasticache/fake/fake.go +++ b/pkg/clients/elasticache/fake/fake.go @@ -21,11 +21,11 @@ import ( "github.com/aws/aws-sdk-go-v2/service/elasticache/elasticacheiface" ) -var _ elasticacheiface.ElastiCacheAPI = &MockClient{} +var _ elasticacheiface.ClientAPI = &MockClient{} // MockClient is a fake implementation of cloudmemorystore.Client. type MockClient struct { - elasticacheiface.ElastiCacheAPI + elasticacheiface.ClientAPI MockDescribeReplicationGroupsRequest func(*elasticache.DescribeReplicationGroupsInput) elasticache.DescribeReplicationGroupsRequest MockCreateReplicationGroupRequest func(*elasticache.CreateReplicationGroupInput) elasticache.CreateReplicationGroupRequest diff --git a/pkg/clients/iam/iam.go b/pkg/clients/iam/iam.go index 177b024d99..a578b55fd6 100644 --- a/pkg/clients/iam/iam.go +++ b/pkg/clients/iam/iam.go @@ -1,6 +1,7 @@ package iam import ( + "context" "fmt" "github.com/aws/aws-sdk-go-v2/aws" @@ -27,7 +28,7 @@ type Client interface { type iamClient struct { accountID *string - iam iamiface.IAMAPI + iam iamiface.ClientAPI } // NewClient creates new AWS Client with provided AWS Configurations/Credentials @@ -74,7 +75,7 @@ func (c *iamClient) GetPolicyVersion(username string) (string, error) { policyResponse, err := c.iam.GetPolicyRequest(&iam.GetPolicyInput{ PolicyArn: aws.String(policyARN), - }).Send() + }).Send(context.TODO()) if err != nil { return "", err @@ -90,21 +91,21 @@ func (c *iamClient) UpdatePolicy(policyName string, policyDocument string) (stri return "", err } // Create a new policy version - policyVersionResponse, err := c.iam.CreatePolicyVersionRequest(&iam.CreatePolicyVersionInput{PolicyArn: aws.String(policyARN), PolicyDocument: aws.String(policyDocument), SetAsDefault: aws.Bool(true)}).Send() + policyVersionResponse, err := c.iam.CreatePolicyVersionRequest(&iam.CreatePolicyVersionInput{PolicyArn: aws.String(policyARN), PolicyDocument: aws.String(policyDocument), SetAsDefault: aws.Bool(true)}).Send(context.TODO()) if err != nil { return "", err } currentPolicyVersion := policyVersionResponse.PolicyVersion.VersionId // Delete old versions of policy - Max 5 allowed - policyVersions, err := c.iam.ListPolicyVersionsRequest(&iam.ListPolicyVersionsInput{PolicyArn: aws.String(policyARN)}).Send() + policyVersions, err := c.iam.ListPolicyVersionsRequest(&iam.ListPolicyVersionsInput{PolicyArn: aws.String(policyARN)}).Send(context.TODO()) if err != nil { return "", err } for _, policy := range policyVersions.Versions { if aws.StringValue(policy.VersionId) != aws.StringValue(currentPolicyVersion) { - _, err := c.iam.DeletePolicyVersionRequest(&iam.DeletePolicyVersionInput{PolicyArn: aws.String(policyARN), VersionId: policy.VersionId}).Send() + _, err := c.iam.DeletePolicyVersionRequest(&iam.DeletePolicyVersionInput{PolicyArn: aws.String(policyARN), VersionId: policy.VersionId}).Send(context.TODO()) if err != nil { return "", err } @@ -121,12 +122,12 @@ func (c *iamClient) DeletePolicyAndDetach(username string, policyName string) er return err } - _, err = c.iam.DetachUserPolicyRequest(&iam.DetachUserPolicyInput{PolicyArn: aws.String(policyARN), UserName: aws.String(username)}).Send() + _, err = c.iam.DetachUserPolicyRequest(&iam.DetachUserPolicyInput{PolicyArn: aws.String(policyARN), UserName: aws.String(username)}).Send(context.TODO()) if err != nil && !IsErrorNotFound(err) { return err } - _, err = c.iam.DeletePolicyRequest(&iam.DeletePolicyInput{PolicyArn: aws.String(policyARN)}).Send() + _, err = c.iam.DeletePolicyRequest(&iam.DeletePolicyInput{PolicyArn: aws.String(policyARN)}).Send(context.TODO()) if err != nil && !IsErrorNotFound(err) { return err } @@ -135,19 +136,19 @@ func (c *iamClient) DeletePolicyAndDetach(username string, policyName string) er // DeleteUser Policy and IAM User func (c *iamClient) DeleteUser(username string) error { - keys, err := c.iam.ListAccessKeysRequest(&iam.ListAccessKeysInput{UserName: aws.String(username)}).Send() + keys, err := c.iam.ListAccessKeysRequest(&iam.ListAccessKeysInput{UserName: aws.String(username)}).Send(context.TODO()) if err != nil { return err } for _, key := range keys.AccessKeyMetadata { - _, err = c.iam.DeleteAccessKeyRequest(&iam.DeleteAccessKeyInput{AccessKeyId: key.AccessKeyId, UserName: aws.String(username)}).Send() + _, err = c.iam.DeleteAccessKeyRequest(&iam.DeleteAccessKeyInput{AccessKeyId: key.AccessKeyId, UserName: aws.String(username)}).Send(context.TODO()) if err != nil { return err } } - _, err = c.iam.DeleteUserRequest(&iam.DeleteUserInput{UserName: aws.String(username)}).Send() + _, err = c.iam.DeleteUserRequest(&iam.DeleteUserInput{UserName: aws.String(username)}).Send(context.TODO()) if err != nil && !IsErrorNotFound(err) { return err } @@ -158,7 +159,7 @@ func (c *iamClient) DeleteUser(username string) error { // getAccountID - Gets the accountID of the authenticated session. func (c *iamClient) getAccountID() (string, error) { if c.accountID == nil { - user, err := c.iam.GetUserRequest(&iam.GetUserInput{}).Send() + user, err := c.iam.GetUserRequest(&iam.GetUserInput{}).Send(context.TODO()) if err != nil { return "", err } @@ -183,7 +184,7 @@ func (c *iamClient) getPolicyARN(policyName string) (string, error) { } func (c *iamClient) createUser(username string) error { - _, err := c.iam.CreateUserRequest(&iam.CreateUserInput{UserName: aws.String(username)}).Send() + _, err := c.iam.CreateUserRequest(&iam.CreateUserInput{UserName: aws.String(username)}).Send(context.TODO()) if err != nil && isErrorAlreadyExists(err) { return nil } @@ -191,7 +192,7 @@ func (c *iamClient) createUser(username string) error { } func (c *iamClient) createAccessKey(username string) (*iam.AccessKey, error) { - keysResponse, err := c.iam.CreateAccessKeyRequest(&iam.CreateAccessKeyInput{UserName: aws.String(username)}).Send() + keysResponse, err := c.iam.CreateAccessKeyRequest(&iam.CreateAccessKeyInput{UserName: aws.String(username)}).Send(context.TODO()) if err != nil { return nil, err } @@ -200,7 +201,7 @@ func (c *iamClient) createAccessKey(username string) (*iam.AccessKey, error) { } func (c *iamClient) createPolicy(policyName string, policyDocument string) (string, error) { - response, err := c.iam.CreatePolicyRequest(&iam.CreatePolicyInput{PolicyName: aws.String(policyName), PolicyDocument: aws.String(policyDocument)}).Send() + response, err := c.iam.CreatePolicyRequest(&iam.CreatePolicyInput{PolicyName: aws.String(policyName), PolicyDocument: aws.String(policyDocument)}).Send(context.TODO()) if err != nil { if isErrorAlreadyExists(err) { return c.UpdatePolicy(policyName, policyDocument) @@ -215,7 +216,7 @@ func (c *iamClient) attachPolicyToUser(policyName string, username string) error if err != nil { return err } - _, err = c.iam.AttachUserPolicyRequest(&iam.AttachUserPolicyInput{PolicyArn: aws.String(policyArn), UserName: aws.String(username)}).Send() + _, err = c.iam.AttachUserPolicyRequest(&iam.AttachUserPolicyInput{PolicyArn: aws.String(policyArn), UserName: aws.String(username)}).Send(context.TODO()) return err } diff --git a/pkg/clients/rds/rds.go b/pkg/clients/rds/rds.go index 22a55e7259..642b344d43 100644 --- a/pkg/clients/rds/rds.go +++ b/pkg/clients/rds/rds.go @@ -17,6 +17,7 @@ limitations under the License. package rds import ( + "context" "encoding/json" "strconv" "strings" @@ -44,12 +45,17 @@ type Client interface { } // NewClient creates new RDS RDSClient with provided AWS Configurations/Credentials -func NewClient(credentials []byte, region string) (Client, error) { - cfg, err := awsclients.LoadConfig(credentials, awsclients.DefaultSection, region) - if err != nil { - return nil, err +func NewClient(ctx context.Context, credentials []byte, region string, useSA bool) (Client, error) { + if useSA { + cfg, err := awsclients.LoadSAConfig(ctx, region) + if cfg == nil { + return nil, err + } + return rds.New(*cfg), err } - return rds.New(*cfg), nil + + cfg, err := awsclients.LoadConfig(credentials, awsclients.DefaultSection, region) + return rds.New(*cfg), err } // IsErrorAlreadyExists returns true if the supplied error indicates an instance diff --git a/pkg/clients/s3/operations/requests.go b/pkg/clients/s3/operations/requests.go index bda40578ca..d279827c44 100644 --- a/pkg/clients/s3/operations/requests.go +++ b/pkg/clients/s3/operations/requests.go @@ -16,31 +16,35 @@ limitations under the License. package operations -import "github.com/aws/aws-sdk-go-v2/service/s3" +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/s3" +) // mockery -case snake -all -output fake -outpkg fake // CreateBucketRequest is a API request type for the CreateBucket API operation. type CreateBucketRequest interface { - Send() (*s3.CreateBucketOutput, error) + Send(context.Context) (*s3.CreateBucketResponse, error) } // GetBucketVersioningRequest is a API request type for the GetBucketVersioning API operation. type GetBucketVersioningRequest interface { - Send() (*s3.GetBucketVersioningOutput, error) + Send(context.Context) (*s3.GetBucketVersioningResponse, error) } // PutBucketACLRequest is a API request type for the PutBucketAcl API operation. type PutBucketACLRequest interface { - Send() (*s3.PutBucketAclOutput, error) + Send(context.Context) (*s3.PutBucketAclResponse, error) } // PutBucketVersioningRequest is a API request type for the PutBucketVersioning API operation. type PutBucketVersioningRequest interface { - Send() (*s3.PutBucketVersioningOutput, error) + Send(context.Context) (*s3.PutBucketVersioningResponse, error) } // DeleteBucketRequest is a API request type for the DeleteBucket API operation. type DeleteBucketRequest interface { - Send() (*s3.DeleteBucketOutput, error) + Send(context.Context) (*s3.DeleteBucketResponse, error) } diff --git a/pkg/clients/s3/operations/s3_operations.go b/pkg/clients/s3/operations/s3_operations.go index 9eea7a5877..8a8824d313 100644 --- a/pkg/clients/s3/operations/s3_operations.go +++ b/pkg/clients/s3/operations/s3_operations.go @@ -23,11 +23,11 @@ import ( // S3Operations provides methods for common S3 operations type S3Operations struct { - s3 s3iface.S3API + s3 s3iface.ClientAPI } // NewS3Operations creates a new instance of S3Operations -func NewS3Operations(s3 s3iface.S3API) *S3Operations { +func NewS3Operations(s3 s3iface.ClientAPI) *S3Operations { return &S3Operations{s3: s3} } diff --git a/pkg/clients/s3/s3.go b/pkg/clients/s3/s3.go index ba9b37279e..a596cb302b 100644 --- a/pkg/clients/s3/s3.go +++ b/pkg/clients/s3/s3.go @@ -17,6 +17,7 @@ limitations under the License. package s3 import ( + "context" "encoding/json" "fmt" @@ -68,7 +69,7 @@ func NewClient(config *aws.Config) Service { // specification, and returns access keys with permissions of localPermission func (c *Client) CreateOrUpdateBucket(bucket *v1alpha3.S3Bucket) error { input := CreateBucketInput(bucket) - _, err := c.s3.CreateBucketRequest(input).Send() + _, err := c.s3.CreateBucketRequest(input).Send(context.TODO()) if err != nil { if isErrorAlreadyExists(err) { return c.UpdateBucketACL(bucket) @@ -86,7 +87,7 @@ type Bucket struct { // GetBucketInfo returns the status of key bucket settings including user's policy version for permission status func (c *Client) GetBucketInfo(username string, bucket *v1alpha3.S3Bucket) (*Bucket, error) { b := Bucket{} - bucketVersioning, err := c.s3.GetBucketVersioningRequest(&s3.GetBucketVersioningInput{Bucket: aws.String(bucket.GetBucketName())}).Send() + bucketVersioning, err := c.s3.GetBucketVersioningRequest(&s3.GetBucketVersioningInput{Bucket: aws.String(bucket.GetBucketName())}).Send(context.TODO()) if err != nil { return nil, err } @@ -128,7 +129,7 @@ func (c *Client) UpdateBucketACL(bucket *v1alpha3.S3Bucket) error { ACL: *bucket.Spec.CannedACL, Bucket: &name, } - _, err = c.s3.PutBucketACLRequest(input).Send() + _, err = c.s3.PutBucketACLRequest(input).Send(context.TODO()) } return err @@ -142,7 +143,7 @@ func (c *Client) UpdateVersioning(bucket *v1alpha3.S3Bucket) error { } name := bucket.GetBucketName() input := &s3.PutBucketVersioningInput{Bucket: &name, VersioningConfiguration: &s3.VersioningConfiguration{Status: versioningStatus}} - _, err := c.s3.PutBucketVersioningRequest(input).Send() + _, err := c.s3.PutBucketVersioningRequest(input).Send(context.TODO()) if err != nil { return err } @@ -168,7 +169,7 @@ func (c *Client) DeleteBucket(bucket *v1alpha3.S3Bucket) error { input := &s3.DeleteBucketInput{ Bucket: &name, } - _, err := c.s3.DeleteBucketRequest(input).Send() + _, err := c.s3.DeleteBucketRequest(input).Send(context.TODO()) if err != nil && !isErrorNotFound(err) { return err } diff --git a/pkg/controller/cache/managed.go b/pkg/controller/cache/managed.go index 5d0e20c5c9..46b7119b68 100644 --- a/pkg/controller/cache/managed.go +++ b/pkg/controller/cache/managed.go @@ -107,8 +107,7 @@ func (e *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex } dr := e.client.DescribeReplicationGroupsRequest(elasticache.NewDescribeReplicationGroupsInput(meta.GetExternalName(cr))) - dr.SetContext(ctx) - rsp, err := dr.Send() + rsp, err := dr.Send(ctx) if err != nil { return managed.ExternalObservation{ResourceExists: false}, errors.Wrap(resource.Ignore(elasticache.IsNotFound, err), errDescribeReplicationGroup) } @@ -169,8 +168,7 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext token = &t } r := e.client.CreateReplicationGroupRequest(elasticache.NewCreateReplicationGroupInput(cr.Spec.ForProvider, meta.GetExternalName(cr), token)) - r.SetContext(ctx) - if _, err := r.Send(); err != nil { + if _, err := r.Send(ctx); err != nil { return managed.ExternalCreation{}, errors.Wrap(resource.Ignore(elasticache.IsAlreadyExists, err), errCreateReplicationGroup) } if token != nil { @@ -194,8 +192,7 @@ func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalUpdate{}, nil } mr := e.client.ModifyReplicationGroupRequest(elasticache.NewModifyReplicationGroupInput(cr.Spec.ForProvider, meta.GetExternalName(cr))) - mr.SetContext(ctx) - _, err := mr.Send() + _, err := mr.Send(ctx) return managed.ExternalUpdate{}, errors.Wrap(err, errModifyReplicationGroup) } @@ -209,8 +206,7 @@ func (e *external) Delete(ctx context.Context, mg resource.Managed) error { return nil } req := e.client.DeleteReplicationGroupRequest(elasticache.NewDeleteReplicationGroupInput(meta.GetExternalName(cr))) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) return errors.Wrap(resource.Ignore(elasticache.IsNotFound, err), errDeleteReplicationGroup) } @@ -219,7 +215,7 @@ func getCacheClusterList(ctx context.Context, client elasticache.Client, idList for i, cc := range idList { dcc := client.DescribeCacheClustersRequest(elasticache.NewDescribeCacheClustersInput(cc)) dcc.SetContext(ctx) - rsp, err := dcc.Send() + rsp, err := dcc.Send(ctx) if err != nil { return nil, err } diff --git a/pkg/controller/database/dbsubnetgroup/controller.go b/pkg/controller/database/dbsubnetgroup/controller.go index 4487438cbe..f6fdc02aad 100644 --- a/pkg/controller/database/dbsubnetgroup/controller.go +++ b/pkg/controller/database/dbsubnetgroup/controller.go @@ -98,9 +98,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeDBSubnetGroupsRequest(&awsrds.DescribeDBSubnetGroupsInput{ DBSubnetGroupName: aws.String(cr.Spec.DBSubnetGroupName), }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if err != nil { if rds.IsDBSubnetGroupNotFoundErr(err) { @@ -152,9 +151,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex } req := e.client.CreateDBSubnetGroupRequest(input) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrapf(err, errCreate, cr.Spec.DBSubnetGroupName) @@ -183,9 +181,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteDBSubnetGroupRequest(&awsrds.DeleteDBSubnetGroupInput{ DBSubnetGroupName: aws.String(cr.Spec.DBSubnetGroupName), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if rds.IsDBSubnetGroupNotFoundErr(err) { return nil diff --git a/pkg/controller/database/rdsinstance.go b/pkg/controller/database/rdsinstance.go index 6b57bd622e..6d3222778a 100644 --- a/pkg/controller/database/rdsinstance.go +++ b/pkg/controller/database/rdsinstance.go @@ -73,7 +73,7 @@ func SetupRDSInstance(mgr ctrl.Manager, l logging.Logger) error { type connector struct { kube client.Client - newClientFn func(credentials []byte, region string) (rds.Client, error) + newClientFn func(ctx context.Context, credentials []byte, region string, useSA bool) (rds.Client, error) } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -87,13 +87,18 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetProvider) } + if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + rdsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, true) + return &external{client: rdsClient, kube: c.kube}, errors.Wrap(err, errCreateRDSClient) + } + s := &corev1.Secret{} n := types.NamespacedName{Namespace: p.Spec.CredentialsSecretRef.Namespace, Name: p.Spec.CredentialsSecretRef.Name} if err := c.kube.Get(ctx, n, s); err != nil { return nil, errors.Wrap(err, errGetProviderSecret) } - rdsClient, err := c.newClientFn(s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region) + rdsClient, err := c.newClientFn(ctx, s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region, false) return &external{client: rdsClient, kube: c.kube}, errors.Wrap(err, errCreateRDSClient) } @@ -111,8 +116,7 @@ func (e *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex // for retrieval. For example, DescribeDBInstancesOutput does not expose // the tags map of the RDS instance, you have to make ListTagsForResourceRequest req := e.client.DescribeDBInstancesRequest(&awsrds.DescribeDBInstancesInput{DBInstanceIdentifier: aws.String(meta.GetExternalName(cr))}) - req.SetContext(ctx) - rsp, err := req.Send() + rsp, err := req.Send(ctx) if err != nil { return managed.ExternalObservation{}, errors.Wrap(resource.Ignore(rds.IsErrorNotFound, err), errDescribeFailed) } @@ -167,8 +171,7 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalCreation{}, err } req := e.client.CreateDBInstanceRequest(rds.GenerateCreateDBInstanceInput(meta.GetExternalName(cr), pw, &cr.Spec.ForProvider)) - req.SetContext(ctx) - _, err = req.Send() + _, err = req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreateFailed) } @@ -195,8 +198,7 @@ func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext // we lose the current state after a change is made to spec, which forces us // to make a DescribeDBInstancesRequest to get the current state. describe := e.client.DescribeDBInstancesRequest(&awsrds.DescribeDBInstancesInput{DBInstanceIdentifier: aws.String(meta.GetExternalName(cr))}) - describe.SetContext(ctx) - rsp, err := describe.Send() + rsp, err := describe.Send(ctx) if err != nil { return managed.ExternalUpdate{}, errors.Wrap(err, errDescribeFailed) } @@ -205,8 +207,7 @@ func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalUpdate{}, errors.Wrap(err, errPatchCreationFailed) } modify := e.client.ModifyDBInstanceRequest(rds.GenerateModifyDBInstanceInput(meta.GetExternalName(cr), patch)) - modify.SetContext(ctx) - _, err = modify.Send() + _, err = modify.Send(ctx) return managed.ExternalUpdate{}, errors.Wrap(err, errModifyFailed) } @@ -232,7 +233,6 @@ func (e *external) Delete(ctx context.Context, mg resource.Managed) error { SkipFinalSnapshot: cr.Spec.ForProvider.SkipFinalSnapshotBeforeDeletion, } req := e.client.DeleteDBInstanceRequest(&input) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) return errors.Wrap(resource.Ignore(rds.IsErrorNotFound, err), errDeleteFailed) } diff --git a/pkg/controller/database/rdsinstance_test.go b/pkg/controller/database/rdsinstance_test.go index 2961410d97..85c41e7444 100644 --- a/pkg/controller/database/rdsinstance_test.go +++ b/pkg/controller/database/rdsinstance_test.go @@ -112,23 +112,27 @@ func TestConnect(t *testing.T) { secretKey: []byte(credData), }, } - provider := awsv1alpha3.Provider{ - Spec: awsv1alpha3.ProviderSpec{ - Region: testRegion, - ProviderSpec: runtimev1alpha1.ProviderSpec{ - CredentialsSecretRef: runtimev1alpha1.SecretKeySelector{ - SecretReference: runtimev1alpha1.SecretReference{ - Namespace: secretNamespace, - Name: connectionSecretName, + + providerSA := func(saVal bool) awsv1alpha3.Provider { + return awsv1alpha3.Provider{ + Spec: awsv1alpha3.ProviderSpec{ + Region: testRegion, + UseServiceAccount: &saVal, + ProviderSpec: runtimev1alpha1.ProviderSpec{ + CredentialsSecretRef: runtimev1alpha1.SecretKeySelector{ + SecretReference: runtimev1alpha1.SecretReference{ + Namespace: secretNamespace, + Name: connectionSecretName, + }, + Key: secretKey, }, - Key: secretKey, }, }, - }, + } } type args struct { kube client.Client - newClientFn func(credentials []byte, region string) (rds.Client, error) + newClientFn func(ctx context.Context, credentials []byte, region string, useSA bool) (rds.Client, error) cr *v1beta1.RDSInstance } type want struct { @@ -145,7 +149,8 @@ func TestConnect(t *testing.T) { MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { switch key { case client.ObjectKey{Name: providerName}: - provider.DeepCopyInto(obj.(*awsv1alpha3.Provider)) + p := providerSA(false) + p.DeepCopyInto(obj.(*awsv1alpha3.Provider)) return nil case client.ObjectKey{Namespace: secretNamespace, Name: connectionSecretName}: secret.DeepCopyInto(obj.(*corev1.Secret)) @@ -154,13 +159,43 @@ func TestConnect(t *testing.T) { return errBoom }, }, - newClientFn: func(credentials []byte, region string) (i rds.Client, e error) { + newClientFn: func(ctx context.Context, credentials []byte, region string, useSA bool) (i rds.Client, e error) { if diff := cmp.Diff(credData, string(credentials)); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } if diff := cmp.Diff(testRegion, region); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } + if diff := cmp.Diff(false, useSA); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + return nil, nil + }, + cr: instance(), + }, + }, + "SuccessfulUseSA": { + args: args{ + kube: &test.MockClient{ + MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { + if key == (client.ObjectKey{Name: providerName}) { + p := providerSA(true) + p.DeepCopyInto(obj.(*awsv1alpha3.Provider)) + return nil + } + return errBoom + }, + }, + newClientFn: func(ctx context.Context, credentials []byte, region string, useSA bool) (i rds.Client, e error) { + if diff := cmp.Diff("", string(credentials)); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(testRegion, region); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } + if diff := cmp.Diff(true, useSA); diff != "" { + t.Errorf("r: -want, +got:\n%s", diff) + } return nil, nil }, cr: instance(), @@ -185,7 +220,8 @@ func TestConnect(t *testing.T) { MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { switch key { case client.ObjectKey{Name: providerName}: - provider.DeepCopyInto(obj.(*awsv1alpha3.Provider)) + p := providerSA(false) + p.DeepCopyInto(obj.(*awsv1alpha3.Provider)) return nil case client.ObjectKey{Namespace: secretNamespace, Name: connectionSecretName}: return errBoom diff --git a/pkg/controller/identity/iamrole/controller.go b/pkg/controller/identity/iamrole/controller.go index 741685f832..80ab398699 100644 --- a/pkg/controller/identity/iamrole/controller.go +++ b/pkg/controller/identity/iamrole/controller.go @@ -97,9 +97,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.GetRoleRequest(&awsiam.GetRoleInput{ RoleName: aws.String(cr.Spec.RoleName), }) - req.SetContext(ctx) - observed, err := req.Send() + observed, err := req.Send(ctx) if iam.IsErrorNotFound(err) { return managed.ExternalObservation{ @@ -133,9 +132,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex AssumeRolePolicyDocument: aws.String(cr.Spec.AssumeRolePolicyDocument), Description: aws.String(cr.Spec.Description), }) - req.SetContext(ctx) - result, err := req.Send() + result, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -163,9 +161,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteRoleRequest(&awsiam.DeleteRoleInput{ RoleName: aws.String(cr.Spec.RoleName), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if iam.IsErrorNotFound(err) { return nil diff --git a/pkg/controller/identity/iamrolepolicyattachment/controller.go b/pkg/controller/identity/iamrolepolicyattachment/controller.go index df05348403..a255c366c8 100644 --- a/pkg/controller/identity/iamrolepolicyattachment/controller.go +++ b/pkg/controller/identity/iamrolepolicyattachment/controller.go @@ -99,9 +99,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.ListAttachedRolePoliciesRequest(&awsiam.ListAttachedRolePoliciesInput{ RoleName: aws.String(cr.Spec.RoleName), }) - req.SetContext(ctx) - observed, err := req.Send() + observed, err := req.Send(ctx) if err != nil { if iam.IsErrorNotFound(err) { return managed.ExternalObservation{ @@ -147,9 +146,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex PolicyArn: aws.String(cr.Spec.PolicyARN), RoleName: aws.String(cr.Spec.RoleName), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) return managed.ExternalCreation{}, errors.Wrapf(err, errAttach, cr.Spec.PolicyARN, cr.Spec.RoleName) } @@ -177,8 +175,7 @@ func (e *external) Update(ctx context.Context, mgd resource.Managed) (managed.Ex PolicyArn: aws.String(cr.Spec.PolicyARN), RoleName: aws.String(cr.Spec.RoleName), }) - aReq.SetContext(ctx) - if _, err := aReq.Send(); err != nil { + if _, err := aReq.Send(ctx); err != nil { return managed.ExternalUpdate{}, errors.Wrapf(err, errAttach, cr.Spec.PolicyARN, cr.Spec.RoleName) } @@ -186,9 +183,8 @@ func (e *external) Update(ctx context.Context, mgd resource.Managed) (managed.Ex PolicyArn: aws.String(cr.Status.AttachedPolicyARN), RoleName: aws.String(cr.Spec.RoleName), }) - dReq.SetContext(ctx) - if _, err := dReq.Send(); err != nil { + if _, err := dReq.Send(ctx); err != nil { return managed.ExternalUpdate{}, errors.Wrapf(err, errDetach, cr.Status.AttachedPolicyARN, cr.Spec.RoleName) } @@ -207,9 +203,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { PolicyArn: aws.String(cr.Spec.PolicyARN), RoleName: aws.String(cr.Spec.RoleName), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if iam.IsErrorNotFound(err) { return nil diff --git a/pkg/controller/network/internetgateway/controller.go b/pkg/controller/network/internetgateway/controller.go index 77e512cd42..f6ef173bde 100644 --- a/pkg/controller/network/internetgateway/controller.go +++ b/pkg/controller/network/internetgateway/controller.go @@ -110,9 +110,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeInternetGatewaysRequest(&awsec2.DescribeInternetGatewaysInput{ InternetGatewayIds: []string{cr.Status.InternetGatewayID}, }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if ec2.IsInternetGatewayNotFoundErr(err) { return managed.ExternalObservation{ @@ -161,9 +160,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex cr.Status.SetConditions(runtimev1alpha1.Creating()) req := e.client.CreateInternetGatewayRequest(&awsec2.CreateInternetGatewayInput{}) - req.SetContext(ctx) - ig, err := req.Send() + ig, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -175,9 +173,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex InternetGatewayId: ig.InternetGateway.InternetGatewayId, VpcId: aws.String(cr.Spec.VPCID), }) - aReq.SetContext(ctx) - _, err = aReq.Send() + _, err = aReq.Send(ctx) return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -208,9 +205,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { InternetGatewayId: aws.String(cr.Status.InternetGatewayID), VpcId: aws.String(a.VPCID), }) - dReq.SetContext(ctx) - if _, err := dReq.Send(); err != nil { + if _, err := dReq.Send(ctx); err != nil { if ec2.IsInternetGatewayNotFoundErr(err) { continue } @@ -222,9 +218,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteInternetGatewayRequest(&awsec2.DeleteInternetGatewayInput{ InternetGatewayId: aws.String(cr.Status.InternetGatewayID), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if ec2.IsInternetGatewayNotFoundErr(err) { return nil } diff --git a/pkg/controller/network/routetable/controller.go b/pkg/controller/network/routetable/controller.go index 51e1c0fec5..20c9f471b5 100644 --- a/pkg/controller/network/routetable/controller.go +++ b/pkg/controller/network/routetable/controller.go @@ -113,9 +113,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeRouteTablesRequest(&awsec2.DescribeRouteTablesInput{ RouteTableIds: []string{cr.Status.RouteTableID}, }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if ec2.IsRouteTableNotFoundErr(err) { return managed.ExternalObservation{ @@ -164,8 +163,7 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex req := e.client.CreateRouteTableRequest(&awsec2.CreateRouteTableInput{ VpcId: aws.String(cr.Spec.VPCID), }) - req.SetContext(ctx) - result, err := req.Send() + result, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -220,9 +218,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteRouteTableRequest(&awsec2.DeleteRouteTableInput{ RouteTableId: aws.String(cr.Status.RouteTableID), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if ec2.IsRouteTableNotFoundErr(err) { return nil @@ -247,9 +244,8 @@ func (e *external) createRoutes(ctx context.Context, tableID string, desired []v DestinationCidrBlock: aws.String(rt.DestinationCIDRBlock), GatewayId: aws.String(rt.GatewayID), }) - req.SetContext(ctx) - if _, err := req.Send(); err != nil { + if _, err := req.Send(ctx); err != nil { return errors.Wrap(err, errCreateRoute) } } @@ -269,9 +265,8 @@ func (e *external) deleteRoutes(ctx context.Context, tableID string, observed [] RouteTableId: aws.String(tableID), DestinationCidrBlock: aws.String(rt.DestinationCIDRBlock), }) - req.SetContext(ctx) - if _, err := req.Send(); err != nil { + if _, err := req.Send(ctx); err != nil { if ec2.IsRouteNotFoundErr(err) { continue } @@ -297,9 +292,8 @@ func (e *external) createAssociations(ctx context.Context, tableID string, desir RouteTableId: aws.String(tableID), SubnetId: aws.String(asc.SubnetID), }) - req.SetContext(ctx) - if _, err := req.Send(); err != nil { + if _, err := req.Send(ctx); err != nil { return errors.Wrapf(err, errAssociateSubnet, asc.SubnetID) } } @@ -313,9 +307,8 @@ func (e *external) deleteAssociations(ctx context.Context, observed []v1alpha3.A req := e.client.DisassociateRouteTableRequest(&awsec2.DisassociateRouteTableInput{ AssociationId: aws.String(asc.AssociationID), }) - req.SetContext(ctx) - if _, err := req.Send(); err != nil { + if _, err := req.Send(ctx); err != nil { if ec2.IsAssociationIDNotFoundErr(err) { continue } diff --git a/pkg/controller/network/securitygroup/controller.go b/pkg/controller/network/securitygroup/controller.go index 462fc2f922..86bbbce59b 100644 --- a/pkg/controller/network/securitygroup/controller.go +++ b/pkg/controller/network/securitygroup/controller.go @@ -111,9 +111,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeSecurityGroupsRequest(&awsec2.DescribeSecurityGroupsInput{ GroupIds: []string{cr.Status.SecurityGroupID}, }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if ec2.IsSecurityGroupNotFoundErr(err) { return managed.ExternalObservation{ @@ -158,19 +157,14 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex VpcId: aws.String(cr.Spec.VPCID), Description: aws.String(cr.Spec.Description), }) - req.SetContext(ctx) - result, err := req.Send() + result, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } cr.UpdateExternalStatus(awsec2.SecurityGroup{GroupId: result.GroupId}) - if err != nil { - return managed.ExternalCreation{}, errors.Wrap(err, errCreate) - } - // Authorizing Ingress permissions for the SecurityGroup ingressPerms := v1alpha3.BuildEC2Permissions(cr.Spec.IngressPermissions) if len(ingressPerms) > 0 { @@ -178,9 +172,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex GroupId: aws.String(cr.Status.SecurityGroupID), IpPermissions: ingressPerms, }) - air.SetContext(ctx) - _, err = air.Send() + _, err = air.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errAuthorizeIngress) } @@ -193,9 +186,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex GroupId: aws.String(cr.Status.SecurityGroupID), IpPermissions: egressPerms, }) - aer.SetContext(ctx) - _, err = aer.Send() + _, err = aer.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errAuthorizeEgress) } @@ -227,9 +219,7 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { GroupId: aws.String(cr.Status.SecurityGroupID), }) - req.SetContext(ctx) - - _, err := req.Send() + _, err := req.Send(ctx) if ec2.IsSecurityGroupNotFoundErr(err) { return nil diff --git a/pkg/controller/network/subnet/controller.go b/pkg/controller/network/subnet/controller.go index 66e0424810..cfe581bd00 100644 --- a/pkg/controller/network/subnet/controller.go +++ b/pkg/controller/network/subnet/controller.go @@ -108,9 +108,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeSubnetsRequest(&awsec2.DescribeSubnetsInput{ SubnetIds: []string{cr.Status.SubnetID}, }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if ec2.IsSubnetNotFoundErr(err) { return managed.ExternalObservation{ @@ -156,9 +155,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex AvailabilityZone: aws.String(cr.Spec.AvailabilityZone), CidrBlock: aws.String(cr.Spec.CIDRBlock), }) - req.SetContext(ctx) - result, err := req.Send() + result, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -190,9 +188,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteSubnetRequest(&awsec2.DeleteSubnetInput{ SubnetId: aws.String(cr.Status.SubnetID), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if ec2.IsSubnetNotFoundErr(err) { return nil diff --git a/pkg/controller/network/vpc/controller.go b/pkg/controller/network/vpc/controller.go index abe775acb9..bfe76d291c 100644 --- a/pkg/controller/network/vpc/controller.go +++ b/pkg/controller/network/vpc/controller.go @@ -108,9 +108,8 @@ func (e *external) Observe(ctx context.Context, mgd resource.Managed) (managed.E req := e.client.DescribeVpcsRequest(&awsec2.DescribeVpcsInput{ VpcIds: []string{cr.Status.VPCID}, }) - req.SetContext(ctx) - response, err := req.Send() + response, err := req.Send(ctx) if ec2.IsVPCNotFoundErr(err) { return managed.ExternalObservation{ @@ -156,9 +155,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex req := e.client.CreateVpcRequest(&awsec2.CreateVpcInput{ CidrBlock: aws.String(cr.Spec.CIDRBlock), }) - req.SetContext(ctx) - result, err := req.Send() + result, err := req.Send(ctx) if err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errCreate) } @@ -178,9 +176,8 @@ func (e *external) Create(ctx context.Context, mgd resource.Managed) (managed.Ex }, } { attrReq := e.client.ModifyVpcAttributeRequest(input) - attrReq.SetContext(ctx) - if _, err := attrReq.Send(); err != nil { + if _, err := attrReq.Send(ctx); err != nil { return managed.ExternalCreation{}, errors.Wrap(err, errModifyVPCAttributes) } } @@ -210,9 +207,8 @@ func (e *external) Delete(ctx context.Context, mgd resource.Managed) error { req := e.client.DeleteVpcRequest(&awsec2.DeleteVpcInput{ VpcId: aws.String(cr.Status.VPCID), }) - req.SetContext(ctx) - _, err := req.Send() + _, err := req.Send(ctx) if ec2.IsVPCNotFoundErr(err) { return nil From 7965ed51d6b50e285663ce5468ce72322918a1d0 Mon Sep 17 00:00:00 2001 From: hasheddan Date: Thu, 6 Feb 2020 13:41:40 -0600 Subject: [PATCH 2/4] fix s3 operations Signed-off-by: hasheddan --- .../operations/fake/create_bucket_request.go | 20 +++++++------ .../operations/fake/delete_bucket_request.go | 20 +++++++------ .../fake/get_bucket_versioning_request.go | 20 +++++++------ pkg/clients/s3/operations/fake/operations.go | 3 +- .../operations/fake/put_bucket_acl_request.go | 20 +++++++------ .../fake/put_bucket_versioning_request.go | 20 +++++++------ pkg/clients/s3/s3_test.go | 28 +++++++++++-------- 7 files changed, 73 insertions(+), 58 deletions(-) diff --git a/pkg/clients/s3/operations/fake/create_bucket_request.go b/pkg/clients/s3/operations/fake/create_bucket_request.go index 27069491ec..c683b48a2a 100644 --- a/pkg/clients/s3/operations/fake/create_bucket_request.go +++ b/pkg/clients/s3/operations/fake/create_bucket_request.go @@ -3,6 +3,8 @@ package fake import ( + context "context" + mock "github.com/stretchr/testify/mock" s3 "github.com/aws/aws-sdk-go-v2/service/s3" @@ -13,22 +15,22 @@ type CreateBucketRequest struct { mock.Mock } -// Send provides a mock function with given fields: -func (_m *CreateBucketRequest) Send() (*s3.CreateBucketOutput, error) { - ret := _m.Called() +// Send provides a mock function with given fields: _a0 +func (_m *CreateBucketRequest) Send(_a0 context.Context) (*s3.CreateBucketResponse, error) { + ret := _m.Called(_a0) - var r0 *s3.CreateBucketOutput - if rf, ok := ret.Get(0).(func() *s3.CreateBucketOutput); ok { - r0 = rf() + var r0 *s3.CreateBucketResponse + if rf, ok := ret.Get(0).(func(context.Context) *s3.CreateBucketResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*s3.CreateBucketOutput) + r0 = ret.Get(0).(*s3.CreateBucketResponse) } } var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/clients/s3/operations/fake/delete_bucket_request.go b/pkg/clients/s3/operations/fake/delete_bucket_request.go index cc77de7203..8b3b27dd14 100644 --- a/pkg/clients/s3/operations/fake/delete_bucket_request.go +++ b/pkg/clients/s3/operations/fake/delete_bucket_request.go @@ -3,6 +3,8 @@ package fake import ( + context "context" + mock "github.com/stretchr/testify/mock" s3 "github.com/aws/aws-sdk-go-v2/service/s3" @@ -13,22 +15,22 @@ type DeleteBucketRequest struct { mock.Mock } -// Send provides a mock function with given fields: -func (_m *DeleteBucketRequest) Send() (*s3.DeleteBucketOutput, error) { - ret := _m.Called() +// Send provides a mock function with given fields: _a0 +func (_m *DeleteBucketRequest) Send(_a0 context.Context) (*s3.DeleteBucketResponse, error) { + ret := _m.Called(_a0) - var r0 *s3.DeleteBucketOutput - if rf, ok := ret.Get(0).(func() *s3.DeleteBucketOutput); ok { - r0 = rf() + var r0 *s3.DeleteBucketResponse + if rf, ok := ret.Get(0).(func(context.Context) *s3.DeleteBucketResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*s3.DeleteBucketOutput) + r0 = ret.Get(0).(*s3.DeleteBucketResponse) } } var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/clients/s3/operations/fake/get_bucket_versioning_request.go b/pkg/clients/s3/operations/fake/get_bucket_versioning_request.go index 541fbdefde..deeec1b2a3 100644 --- a/pkg/clients/s3/operations/fake/get_bucket_versioning_request.go +++ b/pkg/clients/s3/operations/fake/get_bucket_versioning_request.go @@ -3,6 +3,8 @@ package fake import ( + context "context" + mock "github.com/stretchr/testify/mock" s3 "github.com/aws/aws-sdk-go-v2/service/s3" @@ -13,22 +15,22 @@ type GetBucketVersioningRequest struct { mock.Mock } -// Send provides a mock function with given fields: -func (_m *GetBucketVersioningRequest) Send() (*s3.GetBucketVersioningOutput, error) { - ret := _m.Called() +// Send provides a mock function with given fields: _a0 +func (_m *GetBucketVersioningRequest) Send(_a0 context.Context) (*s3.GetBucketVersioningResponse, error) { + ret := _m.Called(_a0) - var r0 *s3.GetBucketVersioningOutput - if rf, ok := ret.Get(0).(func() *s3.GetBucketVersioningOutput); ok { - r0 = rf() + var r0 *s3.GetBucketVersioningResponse + if rf, ok := ret.Get(0).(func(context.Context) *s3.GetBucketVersioningResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*s3.GetBucketVersioningOutput) + r0 = ret.Get(0).(*s3.GetBucketVersioningResponse) } } var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/clients/s3/operations/fake/operations.go b/pkg/clients/s3/operations/fake/operations.go index 9119fa02ed..7e9b629e34 100644 --- a/pkg/clients/s3/operations/fake/operations.go +++ b/pkg/clients/s3/operations/fake/operations.go @@ -4,9 +4,8 @@ package fake import ( s3 "github.com/aws/aws-sdk-go-v2/service/s3" - mock "github.com/stretchr/testify/mock" - operations "github.com/crossplaneio/stack-aws/pkg/clients/s3/operations" + mock "github.com/stretchr/testify/mock" ) // Operations is an autogenerated mock type for the Operations type diff --git a/pkg/clients/s3/operations/fake/put_bucket_acl_request.go b/pkg/clients/s3/operations/fake/put_bucket_acl_request.go index 72d1353539..ca39215157 100644 --- a/pkg/clients/s3/operations/fake/put_bucket_acl_request.go +++ b/pkg/clients/s3/operations/fake/put_bucket_acl_request.go @@ -3,6 +3,8 @@ package fake import ( + context "context" + mock "github.com/stretchr/testify/mock" s3 "github.com/aws/aws-sdk-go-v2/service/s3" @@ -13,22 +15,22 @@ type PutBucketACLRequest struct { mock.Mock } -// Send provides a mock function with given fields: -func (_m *PutBucketACLRequest) Send() (*s3.PutBucketAclOutput, error) { - ret := _m.Called() +// Send provides a mock function with given fields: _a0 +func (_m *PutBucketACLRequest) Send(_a0 context.Context) (*s3.PutBucketAclResponse, error) { + ret := _m.Called(_a0) - var r0 *s3.PutBucketAclOutput - if rf, ok := ret.Get(0).(func() *s3.PutBucketAclOutput); ok { - r0 = rf() + var r0 *s3.PutBucketAclResponse + if rf, ok := ret.Get(0).(func(context.Context) *s3.PutBucketAclResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*s3.PutBucketAclOutput) + r0 = ret.Get(0).(*s3.PutBucketAclResponse) } } var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/clients/s3/operations/fake/put_bucket_versioning_request.go b/pkg/clients/s3/operations/fake/put_bucket_versioning_request.go index d256307339..68a4884954 100644 --- a/pkg/clients/s3/operations/fake/put_bucket_versioning_request.go +++ b/pkg/clients/s3/operations/fake/put_bucket_versioning_request.go @@ -3,6 +3,8 @@ package fake import ( + context "context" + mock "github.com/stretchr/testify/mock" s3 "github.com/aws/aws-sdk-go-v2/service/s3" @@ -13,22 +15,22 @@ type PutBucketVersioningRequest struct { mock.Mock } -// Send provides a mock function with given fields: -func (_m *PutBucketVersioningRequest) Send() (*s3.PutBucketVersioningOutput, error) { - ret := _m.Called() +// Send provides a mock function with given fields: _a0 +func (_m *PutBucketVersioningRequest) Send(_a0 context.Context) (*s3.PutBucketVersioningResponse, error) { + ret := _m.Called(_a0) - var r0 *s3.PutBucketVersioningOutput - if rf, ok := ret.Get(0).(func() *s3.PutBucketVersioningOutput); ok { - r0 = rf() + var r0 *s3.PutBucketVersioningResponse + if rf, ok := ret.Get(0).(func(context.Context) *s3.PutBucketVersioningResponse); ok { + r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*s3.PutBucketVersioningOutput) + r0 = ret.Get(0).(*s3.PutBucketVersioningResponse) } } var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } diff --git a/pkg/clients/s3/s3_test.go b/pkg/clients/s3/s3_test.go index 9d720628c1..2b73d8c98c 100644 --- a/pkg/clients/s3/s3_test.go +++ b/pkg/clients/s3/s3_test.go @@ -17,6 +17,7 @@ limitations under the License. package s3 import ( + "context" "errors" "testing" @@ -68,10 +69,10 @@ func TestClient_CreateOrUpdateBucket(t *testing.T) { // Set up mocks createBucketReq := new(fakeops.CreateBucketRequest) - createBucketReq.On("Send").Return(vals.createBucketRet...) + createBucketReq.On("Send", context.TODO()).Return(vals.createBucketRet...) putBucketACLReq := new(fakeops.PutBucketACLRequest) - putBucketACLReq.On("Send").Return(vals.putBucketACLRet...) + putBucketACLReq.On("Send", context.TODO()).Return(vals.putBucketACLRet...) ops := new(fakeops.Operations) ops.On("CreateBucketRequest", mock.Anything).Return(createBucketReq) @@ -93,7 +94,12 @@ func TestClient_GetBucketInfo(t *testing.T) { // Set up args name := "han" s3Bucket := &awsstorage.S3Bucket{} - versioningOut := new(s3.GetBucketVersioningOutput) + versioningRes := &s3.GetBucketVersioningResponse{ + GetBucketVersioningOutput: &s3.GetBucketVersioningOutput{ + MFADelete: s3.MFADeleteStatusEnabled, + Status: s3.BucketVersioningStatusEnabled, + }, + } boom := errors.New("boom") // Define test cases @@ -129,7 +135,7 @@ func TestClient_GetBucketInfo(t *testing.T) { // Set up mocks versioningReq := new(fakeops.GetBucketVersioningRequest) - versioningReq.On("Send").Return(versioningOut, vals.sendErr) + versioningReq.On("Send", context.TODO()).Return(versioningRes, vals.sendErr) ops := new(fakeops.Operations) ops.On("GetBucketVersioningRequest", mock.Anything).Return(versioningReq) @@ -232,7 +238,7 @@ func TestClient_UpdateBucketACL(t *testing.T) { }{ "HappyPath": { bucket: &awsstorage.S3Bucket{}, - sendRet: []interface{}{&s3.PutBucketAclOutput{}, nil}, + sendRet: []interface{}{&s3.PutBucketAclResponse{}, nil}, ret: []types.GomegaMatcher{gomega.BeNil()}, }, "WithACL": { @@ -243,7 +249,7 @@ func TestClient_UpdateBucketACL(t *testing.T) { }, }, }, - sendRet: []interface{}{&s3.PutBucketAclOutput{}, nil}, + sendRet: []interface{}{&s3.PutBucketAclResponse{}, nil}, ret: []types.GomegaMatcher{gomega.BeNil()}, }, } @@ -254,7 +260,7 @@ func TestClient_UpdateBucketACL(t *testing.T) { // Set up mocks putBucketACL := new(fakeops.PutBucketACLRequest) - putBucketACL.On("Send").Return(vals.sendRet...) + putBucketACL.On("Send", context.TODO()).Return(vals.sendRet...) ops := new(fakeops.Operations) ops.On("PutBucketACLRequest", mock.Anything).Return(putBucketACL) @@ -287,12 +293,12 @@ func TestClient_UpdateVersioning(t *testing.T) { }, }, }, - sendRet: []interface{}{&s3.PutBucketVersioningOutput{}, nil}, + sendRet: []interface{}{&s3.PutBucketVersioningResponse{}, nil}, ret: []types.GomegaMatcher{gomega.BeNil()}, }, "SendError": { bucket: &awsstorage.S3Bucket{}, - sendRet: []interface{}{&s3.PutBucketVersioningOutput{}, boom}, + sendRet: []interface{}{&s3.PutBucketVersioningResponse{}, boom}, ret: []types.GomegaMatcher{gomega.Equal(boom)}, }, } @@ -303,7 +309,7 @@ func TestClient_UpdateVersioning(t *testing.T) { // Set up mocks putBucketVer := new(fakeops.PutBucketVersioningRequest) - putBucketVer.On("Send").Return(vals.sendRet...) + putBucketVer.On("Send", context.TODO()).Return(vals.sendRet...) ops := new(fakeops.Operations) ops.On("PutBucketVersioningRequest", mock.Anything).Return(putBucketVer) @@ -424,7 +430,7 @@ func TestClient_DeleteBucket(t *testing.T) { // Set up mocks delBucketReq := new(fakeops.DeleteBucketRequest) - delBucketReq.On("Send").Return(vals.deleteBucketRet...) + delBucketReq.On("Send", context.TODO()).Return(vals.deleteBucketRet...) ops := new(fakeops.Operations) ops.On("DeleteBucketRequest", mock.Anything).Return(delBucketReq) From 937e184bb2fa698a49f8066b982d6054d0ea6a30 Mon Sep 17 00:00:00 2001 From: hasheddan Date: Fri, 14 Feb 2020 13:52:41 -0600 Subject: [PATCH 3/4] Update Provider with optional credentialsSecretRef Signed-off-by: hasheddan --- apis/v1alpha3/types.go | 3 + apis/v1alpha3/zz_generated.deepcopy.go | 2 +- apis/v1alpha3/zz_generated.provider.go | 4 +- config/crd/aws.crossplane.io_providers.yaml | 4 +- go.mod | 10 ++- go.sum | 29 ++++++--- pkg/clients/aws.go | 18 +++--- pkg/clients/aws_test.go | 5 +- pkg/clients/elasticache/elasticache.go | 12 ++-- pkg/clients/elasticache/elasticache_test.go | 3 - pkg/clients/rds/dbsubnetgroup.go | 16 +++++ pkg/clients/rds/rds.go | 13 ++-- pkg/clients/rds/rds_test.go | 16 +++++ pkg/controller/cache/managed.go | 20 ++++-- pkg/controller/cache/managed_test.go | 67 +++++++++++++++++++-- pkg/controller/database/rdsinstance.go | 11 +++- pkg/controller/database/rdsinstance_test.go | 38 +++++++++--- pkg/controller/utils/utils.go | 11 +++- pkg/controller/utils/utils_test.go | 2 +- 19 files changed, 217 insertions(+), 67 deletions(-) diff --git a/apis/v1alpha3/types.go b/apis/v1alpha3/types.go index ad74b35ce0..fa5dd6c305 100644 --- a/apis/v1alpha3/types.go +++ b/apis/v1alpha3/types.go @@ -32,6 +32,9 @@ type ProviderSpec struct { // UseServiceAccount indicates to use an IAM Role associated Kubernetes // ServiceAccount for authentication instead of a credentials Secret. // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html + // + // If set to true, credentialsSecretRef will be ignored. + // +optional UseServiceAccount *bool `json:"useServiceAccount,omitempty"` } diff --git a/apis/v1alpha3/zz_generated.deepcopy.go b/apis/v1alpha3/zz_generated.deepcopy.go index 569546be2b..8d4b548b0e 100644 --- a/apis/v1alpha3/zz_generated.deepcopy.go +++ b/apis/v1alpha3/zz_generated.deepcopy.go @@ -85,7 +85,7 @@ func (in *ProviderList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) { *out = *in - out.ProviderSpec = in.ProviderSpec + in.ProviderSpec.DeepCopyInto(&out.ProviderSpec) if in.UseServiceAccount != nil { in, out := &in.UseServiceAccount, &out.UseServiceAccount *out = new(bool) diff --git a/apis/v1alpha3/zz_generated.provider.go b/apis/v1alpha3/zz_generated.provider.go index cceb757aea..46fe0fa6a6 100644 --- a/apis/v1alpha3/zz_generated.provider.go +++ b/apis/v1alpha3/zz_generated.provider.go @@ -21,11 +21,11 @@ package v1alpha3 import runtimev1alpha1 "github.com/crossplaneio/crossplane-runtime/apis/core/v1alpha1" // GetCredentialsSecretReference of this Provider. -func (p *Provider) GetCredentialsSecretReference() runtimev1alpha1.SecretKeySelector { +func (p *Provider) GetCredentialsSecretReference() *runtimev1alpha1.SecretKeySelector { return p.Spec.CredentialsSecretRef } // SetCredentialsSecretReference of this Provider. -func (p *Provider) SetCredentialsSecretReference(r runtimev1alpha1.SecretKeySelector) { +func (p *Provider) SetCredentialsSecretReference(r *runtimev1alpha1.SecretKeySelector) { p.Spec.CredentialsSecretRef = r } diff --git a/config/crd/aws.crossplane.io_providers.yaml b/config/crd/aws.crossplane.io_providers.yaml index 4a28e96c06..cc01f897c9 100644 --- a/config/crd/aws.crossplane.io_providers.yaml +++ b/config/crd/aws.crossplane.io_providers.yaml @@ -69,12 +69,12 @@ spec: description: Region for managed resources created using this AWS provider. type: string useServiceAccount: - description: UseServiceAccount indicates to use an IAM Role associated + description: "UseServiceAccount indicates to use an IAM Role associated Kubernetes ServiceAccount for authentication instead of a credentials Secret. https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html + \n If set to true, credentialsSecretRef will be ignored." type: boolean required: - - credentialsSecretRef - region type: object required: diff --git a/go.mod b/go.mod index 43f29e7ea0..8d63339ddf 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,20 @@ module github.com/crossplaneio/stack-aws go 1.13 require ( - github.com/aws/aws-sdk-go-v2 v0.5.0 + github.com/aws/aws-sdk-go-v2 v0.19.0 github.com/crossplaneio/crossplane v0.7.0-rc.0.20200211212229-e3c5715e39d8 - github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200201005410-a6bb086be888 - github.com/crossplaneio/crossplane-tools v0.0.0-20191220202319-9033bd8a02ce + github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200213015649-e59980916293 + github.com/crossplaneio/crossplane-tools v0.0.0-20200214190114-c7c4365eeb95 github.com/evanphx/json-patch v4.5.0+incompatible github.com/ghodss/yaml v1.0.0 github.com/go-ini/ini v1.46.0 github.com/google/go-cmp v0.3.1 + github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c // indirect + github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/onsi/gomega v1.7.0 github.com/pkg/errors v0.8.1 + github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect + github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/stretchr/testify v1.4.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/ini.v1 v1.47.0 // indirect diff --git a/go.sum b/go.sum index 02be5f887b..175d25bcfc 100644 --- a/go.sum +++ b/go.sum @@ -9,15 +9,20 @@ cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbf cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.2 h1:6AWuh3uWrsZJcNoCHrCF/+g4aKPCU39kaMO6/qrnK/4= github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0 h1:CxTzQrySOxDnKpLjFJeZAS5Qrv/qFPkgLjx5bOAi//I= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -39,8 +44,6 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tvY= github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= -github.com/aws/aws-sdk-go-v2 v0.5.0 h1:EYMvJVajBzaGlPb8z761lkejQKsz0FM6+78lfQ/UexA= -github.com/aws/aws-sdk-go-v2 v0.5.0/go.mod h1:5/URWM5KZOrZ0sp9aiPT0FrXgFJFPJ143F6SGgnTfXY= github.com/aws/aws-sdk-go-v2 v0.19.0 h1:jVKVeRBQah2OwqXRoy8bnWWgpo2sXk/bWf2J2tog+lk= github.com/aws/aws-sdk-go-v2 v0.19.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= @@ -48,6 +51,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= @@ -67,8 +71,12 @@ github.com/crossplaneio/crossplane v0.7.0-rc.0.20200211212229-e3c5715e39d8 h1:uP github.com/crossplaneio/crossplane v0.7.0-rc.0.20200211212229-e3c5715e39d8/go.mod h1:w1DahP4gWrRfZgRDc4jKLZsA3vyRLOmBevk03xdW/5g= github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200201005410-a6bb086be888 h1:vO/7jO4Vz1+1IxNximywy5Sr/dj5vwFKhii9x4pyz+Q= github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200201005410-a6bb086be888/go.mod h1:97hx6LIBkjI0fjfMGPRCOGI7Pm6qUhoN9zTCWrP4XvU= +github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200213015649-e59980916293 h1:PrJDg3nwP2GUfuubTe0CA1qn+SBLZDnBCS+UhwjwUhs= +github.com/crossplaneio/crossplane-runtime v0.4.1-0.20200213015649-e59980916293/go.mod h1:97hx6LIBkjI0fjfMGPRCOGI7Pm6qUhoN9zTCWrP4XvU= github.com/crossplaneio/crossplane-tools v0.0.0-20191220202319-9033bd8a02ce h1:V7cUPRBxbJr0siRHn459gb6hfMXaEA+pGm0Yt5aXdhQ= github.com/crossplaneio/crossplane-tools v0.0.0-20191220202319-9033bd8a02ce/go.mod h1:fzQeWDvZvzaC4N8vPjTubQocGnwzQ4cuZM6949+T43U= +github.com/crossplaneio/crossplane-tools v0.0.0-20200214190114-c7c4365eeb95 h1:PizQdqEoP9nHU3oCO6/1DrqNHaCPANPHBwaGTVi0Wqk= +github.com/crossplaneio/crossplane-tools v0.0.0-20200214190114-c7c4365eeb95/go.mod h1:fzQeWDvZvzaC4N8vPjTubQocGnwzQ4cuZM6949+T43U= github.com/dave/jennifer v1.3.0 h1:p3tl41zjjCZTNBytMwrUuiAnherNUZktlhPTKoF/sEk= github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -76,6 +84,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -99,7 +108,6 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.46.0 h1:hDJFfs/9f75875scvqLkhNB5Jz5/DybKEOZ5MLF+ng4= github.com/go-ini/ini v1.46.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -163,7 +171,6 @@ github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+A github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -201,6 +208,7 @@ github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsC github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gophercloud/gophercloud v0.6.0 h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU= github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -210,10 +218,13 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/gucumber/gucumber v0.0.0-20180127021336-7d5c79e832a2/go.mod h1:YbdHRK9ViqwGMS0rtRY+1I6faHvVyyurKPIPwifihxI= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw= github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -273,7 +284,9 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -331,7 +344,6 @@ github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURm github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co= @@ -340,6 +352,7 @@ github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbm github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= @@ -363,6 +376,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= @@ -398,7 +412,6 @@ golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -410,7 +423,6 @@ golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -586,6 +598,7 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kubectl v0.17.0 h1:xD4EWlL+epc/JTO1gvSjmV9yiYF0Z2wiHK2DIek6URY= k8s.io/kubectl v0.17.0/go.mod h1:jIPrUAW656Vzn9wZCCe0PC+oTcu56u2HgFD21Xbfk1s= k8s.io/metrics v0.17.0/go.mod h1:EH1D3YAwN6d7bMelrElnLhLg72l/ERStyv2SIQVt6Do= k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= diff --git a/pkg/clients/aws.go b/pkg/clients/aws.go index 8a4ef882fd..756aecc536 100644 --- a/pkg/clients/aws.go +++ b/pkg/clients/aws.go @@ -29,6 +29,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/sts" jsonpatch "github.com/evanphx/json-patch" "github.com/go-ini/ini" + "github.com/pkg/errors" ) // DefaultSection for INI files. @@ -77,11 +78,14 @@ func CredentialsIDSecret(data []byte, profile string) (string, string, error) { return id.Value(), secret.Value(), err } -// LoadConfig - AWS configuration which can be used to issue requests against AWS API -func LoadConfig(data []byte, profile, region string) (*aws.Config, error) { +// AuthMethod is a method of authenticating to the AWS API +type AuthMethod func(context.Context, []byte, string, string) (*aws.Config, error) + +// UseProviderSecret - AWS configuration which can be used to issue requests against AWS API +func UseProviderSecret(_ context.Context, data []byte, profile, region string) (*aws.Config, error) { id, secret, err := CredentialsIDSecret(data, profile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to parse credentials") } creds := aws.Credentials{ @@ -98,19 +102,19 @@ func LoadConfig(data []byte, profile, region string) (*aws.Config, error) { return &config, err } -// LoadSAConfig assumes an IAM role configured via a ServiceAccount. +// UsePodServiceAccount assumes an IAM role configured via a ServiceAccount. // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html -func LoadSAConfig(ctx context.Context, region string) (*aws.Config, error) { +func UsePodServiceAccount(ctx context.Context, _ []byte, _, region string) (*aws.Config, error) { cfg, err := external.LoadDefaultAWSConfig() if err != nil { - return nil, err + return nil, errors.Wrap(err, "failed to load default AWS config") } cfg.Region = region svc := sts.New(cfg) b, err := ioutil.ReadFile(os.Getenv("AWS_WEB_IDENTITY_TOKEN_FILE")) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to read web identity token file in pod") } token := string(b) sess := strconv.FormatInt(time.Now().UnixNano(), 10) diff --git a/pkg/clients/aws_test.go b/pkg/clients/aws_test.go index 5eb28a3355..5aeee259c8 100644 --- a/pkg/clients/aws_test.go +++ b/pkg/clients/aws_test.go @@ -17,6 +17,7 @@ limitations under the License. package aws import ( + "context" "fmt" "testing" @@ -48,7 +49,7 @@ func TestCredentialsIdSecret(t *testing.T) { g.Expect(secret).To(Equal("")) } -func TestLoadConfig(t *testing.T) { +func TestUseProviderSecret(t *testing.T) { g := NewGomegaWithT(t) testProfile := "default" @@ -57,7 +58,7 @@ func TestLoadConfig(t *testing.T) { testRegion := "us-west-2" credentials := []byte(fmt.Sprintf(awsCredentialsFileFormat, testProfile, testID, testSecret)) - config, err := LoadConfig(credentials, testProfile, testRegion) + config, err := UseProviderSecret(context.TODO(), credentials, testProfile, testRegion) g.Expect(err).NotTo(HaveOccurred()) g.Expect(config).NotTo(BeNil()) } diff --git a/pkg/clients/elasticache/elasticache.go b/pkg/clients/elasticache/elasticache.go index 11f38a8643..18aa1019d2 100644 --- a/pkg/clients/elasticache/elasticache.go +++ b/pkg/clients/elasticache/elasticache.go @@ -17,6 +17,7 @@ limitations under the License. package elasticache import ( + "context" "reflect" "strconv" @@ -26,7 +27,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/elasticache" "github.com/aws/aws-sdk-go-v2/service/elasticache/elasticacheiface" - "github.com/pkg/errors" "github.com/crossplaneio/stack-aws/apis/cache/v1beta1" clients "github.com/crossplaneio/stack-aws/pkg/clients" @@ -38,12 +38,12 @@ type Client elasticacheiface.ClientAPI // NewClient returns a new ElastiCache client. Credentials must be passed as // JSON encoded data. -func NewClient(credentials []byte, region string) (Client, error) { - cfg, err := clients.LoadConfig(credentials, clients.DefaultSection, region) - if err != nil { - return nil, errors.Wrap(err, "cannot create new AWS configuration") +func NewClient(ctx context.Context, credentials []byte, region string, auth clients.AuthMethod) (Client, error) { + cfg, err := auth(ctx, credentials, clients.DefaultSection, region) + if cfg == nil { + return nil, err } - return elasticache.New(*cfg), nil + return elasticache.New(*cfg), err } // TODO(negz): Determine whether we have to handle converting zero values to diff --git a/pkg/clients/elasticache/elasticache_test.go b/pkg/clients/elasticache/elasticache_test.go index 017ddfaa78..9525803974 100644 --- a/pkg/clients/elasticache/elasticache_test.go +++ b/pkg/clients/elasticache/elasticache_test.go @@ -17,7 +17,6 @@ limitations under the License. package elasticache import ( - "fmt" "strconv" "testing" @@ -610,8 +609,6 @@ func TestReplicationGroupNeedsUpdate(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - name := tc.name - fmt.Println(name) got := ReplicationGroupNeedsUpdate(tc.kube, tc.rg, tc.ccList) if got != tc.want { t.Errorf("ReplicationGroupNeedsUpdate(...): want %t, got %t", tc.want, got) diff --git a/pkg/clients/rds/dbsubnetgroup.go b/pkg/clients/rds/dbsubnetgroup.go index cdbb304f8d..d72c03ad2b 100644 --- a/pkg/clients/rds/dbsubnetgroup.go +++ b/pkg/clients/rds/dbsubnetgroup.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package rds import ( diff --git a/pkg/clients/rds/rds.go b/pkg/clients/rds/rds.go index 642b344d43..ba5c188b62 100644 --- a/pkg/clients/rds/rds.go +++ b/pkg/clients/rds/rds.go @@ -45,16 +45,11 @@ type Client interface { } // NewClient creates new RDS RDSClient with provided AWS Configurations/Credentials -func NewClient(ctx context.Context, credentials []byte, region string, useSA bool) (Client, error) { - if useSA { - cfg, err := awsclients.LoadSAConfig(ctx, region) - if cfg == nil { - return nil, err - } - return rds.New(*cfg), err +func NewClient(ctx context.Context, credentials []byte, region string, auth awsclients.AuthMethod) (Client, error) { + cfg, err := auth(ctx, credentials, awsclients.DefaultSection, region) + if cfg == nil { + return nil, err } - - cfg, err := awsclients.LoadConfig(credentials, awsclients.DefaultSection, region) return rds.New(*cfg), err } diff --git a/pkg/clients/rds/rds_test.go b/pkg/clients/rds/rds_test.go index 76d5f464e8..43012a94d7 100644 --- a/pkg/clients/rds/rds_test.go +++ b/pkg/clients/rds/rds_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package rds import ( diff --git a/pkg/controller/cache/managed.go b/pkg/controller/cache/managed.go index 46b7119b68..de6e10c3e0 100644 --- a/pkg/controller/cache/managed.go +++ b/pkg/controller/cache/managed.go @@ -38,6 +38,7 @@ import ( "github.com/crossplaneio/stack-aws/apis/cache/v1beta1" awsv1alpha3 "github.com/crossplaneio/stack-aws/apis/v1alpha3" + awsclients "github.com/crossplaneio/stack-aws/pkg/clients" "github.com/crossplaneio/stack-aws/pkg/clients/elasticache" ) @@ -45,6 +46,8 @@ import ( const ( errUpdateReplicationGroupCR = "cannot update ReplicationGroup Custom Resource" errGetCacheClusterList = "cannot get cache cluster list" + errGetProvider = "cannot get provider" + errGetProviderSecret = "cannot get provider secret" errNewClient = "cannot create new ElastiCache client" errNotReplicationGroup = "managed resource is not an ElastiCache replication group" @@ -72,7 +75,7 @@ func SetupReplicationGroup(mgr ctrl.Manager, l logging.Logger) error { type connecter struct { client client.Client - newClientFn func(credentials []byte, region string) (elasticache.Client, error) + newClientFn func(ctx context.Context, credentials []byte, region string, auth awsclients.AuthMethod) (elasticache.Client, error) } func (c *connecter) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -83,15 +86,24 @@ func (c *connecter) Connect(ctx context.Context, mg resource.Managed) (managed.E p := &awsv1alpha3.Provider{} if err := c.client.Get(ctx, meta.NamespacedNameOf(g.Spec.ProviderReference), p); err != nil { - return nil, errors.Wrap(err, "cannot get provider") + return nil, errors.Wrap(err, errGetProvider) + } + + if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + awsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, awsclients.UsePodServiceAccount) + return &external{client: awsClient, kube: c.client}, errors.Wrap(err, errNewClient) + } + + if p.GetCredentialsSecretReference() == nil { + return nil, errors.New(errGetProviderSecret) } s := &corev1.Secret{} n := types.NamespacedName{Namespace: p.Spec.CredentialsSecretRef.Namespace, Name: p.Spec.CredentialsSecretRef.Name} if err := c.client.Get(ctx, n, s); err != nil { - return nil, errors.Wrap(err, "cannot get provider secret") + return nil, errors.Wrap(err, errGetProviderSecret) } - awsClient, err := c.newClientFn(s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region) + awsClient, err := c.newClientFn(ctx, s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region, awsclients.UseProviderSecret) return &external{client: awsClient, kube: c.client}, errors.Wrap(err, errNewClient) } diff --git a/pkg/controller/cache/managed_test.go b/pkg/controller/cache/managed_test.go index df88248a0e..90598cbc76 100644 --- a/pkg/controller/cache/managed_test.go +++ b/pkg/controller/cache/managed_test.go @@ -39,6 +39,7 @@ import ( "github.com/crossplaneio/stack-aws/apis/cache/v1beta1" awsv1alpha3 "github.com/crossplaneio/stack-aws/apis/v1alpha3" + awsclients "github.com/crossplaneio/stack-aws/pkg/clients" elasticacheclient "github.com/crossplaneio/stack-aws/pkg/clients/elasticache" "github.com/crossplaneio/stack-aws/pkg/clients/elasticache/fake" @@ -81,7 +82,7 @@ var ( ObjectMeta: metav1.ObjectMeta{Name: providerName}, Spec: awsv1alpha3.ProviderSpec{ ProviderSpec: runtimev1alpha1.ProviderSpec{ - CredentialsSecretRef: runtimev1alpha1.SecretKeySelector{ + CredentialsSecretRef: &runtimev1alpha1.SecretKeySelector{ SecretReference: runtimev1alpha1.SecretReference{ Namespace: namespace, Name: providerSecretName, @@ -652,6 +653,15 @@ func TestDelete(t *testing.T) { } func TestConnect(t *testing.T) { + providerSA := func(saVal bool) awsv1alpha3.Provider { + return awsv1alpha3.Provider{ + Spec: awsv1alpha3.ProviderSpec{ + UseServiceAccount: &saVal, + ProviderSpec: runtimev1alpha1.ProviderSpec{}, + }, + } + } + cases := []struct { name string conn *connecter @@ -672,7 +682,29 @@ func TestConnect(t *testing.T) { return nil }, }, - newClientFn: func(_ []byte, _ string) (elasticacheclient.Client, error) { return &fake.MockClient{}, nil }, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return &fake.MockClient{}, nil + }, + }, + i: replicationGroup(), + }, + { + name: "SuccessfulConnectSA", + conn: &connecter{ + client: &test.MockClient{ + MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { + switch key { + case client.ObjectKey{Name: providerName}: + *obj.(*awsv1alpha3.Provider) = providerSA(true) + case client.ObjectKey{Namespace: namespace, Name: providerSecretName}: + *obj.(*corev1.Secret) = providerSecret + } + return nil + }, + }, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return &fake.MockClient{}, nil + }, }, i: replicationGroup(), }, @@ -682,7 +714,9 @@ func TestConnect(t *testing.T) { client: &test.MockClient{MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { return kerrors.NewNotFound(schema.GroupResource{}, providerName) }}, - newClientFn: func(_ []byte, _ string) (elasticacheclient.Client, error) { return &fake.MockClient{}, nil }, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return &fake.MockClient{}, nil + }, }, i: replicationGroup(), wantErr: errors.WithStack(errors.Errorf("cannot get provider: \"%s\" not found", providerName)), @@ -699,11 +733,32 @@ func TestConnect(t *testing.T) { } return nil }}, - newClientFn: func(_ []byte, _ string) (elasticacheclient.Client, error) { return &fake.MockClient{}, nil }, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return &fake.MockClient{}, nil + }, }, i: replicationGroup(), wantErr: errors.WithStack(errors.Errorf("cannot get provider secret: \"%s\" not found", providerSecretName)), }, + { + name: "FailedToGetProviderSecretNil", + conn: &connecter{ + client: &test.MockClient{MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { + switch key { + case client.ObjectKey{Name: providerName}: + *obj.(*awsv1alpha3.Provider) = providerSA(false) + case client.ObjectKey{Namespace: namespace, Name: providerSecretName}: + return kerrors.NewNotFound(schema.GroupResource{}, providerSecretName) + } + return nil + }}, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return &fake.MockClient{}, nil + }, + }, + i: replicationGroup(), + wantErr: errors.New("cannot get provider secret"), + }, { name: "FailedToCreateElastiCacheClient", conn: &connecter{ @@ -716,7 +771,9 @@ func TestConnect(t *testing.T) { } return nil }}, - newClientFn: func(_ []byte, _ string) (elasticacheclient.Client, error) { return nil, errorBoom }, + newClientFn: func(_ context.Context, _ []byte, _ string, _ awsclients.AuthMethod) (elasticacheclient.Client, error) { + return nil, errorBoom + }, }, i: replicationGroup(), wantErr: errors.Wrap(errorBoom, errNewClient), diff --git a/pkg/controller/database/rdsinstance.go b/pkg/controller/database/rdsinstance.go index 6d3222778a..aa91d0632b 100644 --- a/pkg/controller/database/rdsinstance.go +++ b/pkg/controller/database/rdsinstance.go @@ -38,6 +38,7 @@ import ( "github.com/crossplaneio/stack-aws/apis/database/v1beta1" awsv1alpha3 "github.com/crossplaneio/stack-aws/apis/v1alpha3" + awsclients "github.com/crossplaneio/stack-aws/pkg/clients" "github.com/crossplaneio/stack-aws/pkg/clients/rds" ) @@ -73,7 +74,7 @@ func SetupRDSInstance(mgr ctrl.Manager, l logging.Logger) error { type connector struct { kube client.Client - newClientFn func(ctx context.Context, credentials []byte, region string, useSA bool) (rds.Client, error) + newClientFn func(ctx context.Context, credentials []byte, region string, auth awsclients.AuthMethod) (rds.Client, error) } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -88,17 +89,21 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E } if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { - rdsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, true) + rdsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, awsclients.UsePodServiceAccount) return &external{client: rdsClient, kube: c.kube}, errors.Wrap(err, errCreateRDSClient) } + if p.GetCredentialsSecretReference() == nil { + return nil, errors.New(errGetProviderSecret) + } + s := &corev1.Secret{} n := types.NamespacedName{Namespace: p.Spec.CredentialsSecretRef.Namespace, Name: p.Spec.CredentialsSecretRef.Name} if err := c.kube.Get(ctx, n, s); err != nil { return nil, errors.Wrap(err, errGetProviderSecret) } - rdsClient, err := c.newClientFn(ctx, s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region, false) + rdsClient, err := c.newClientFn(ctx, s.Data[p.Spec.CredentialsSecretRef.Key], p.Spec.Region, awsclients.UseProviderSecret) return &external{client: rdsClient, kube: c.kube}, errors.Wrap(err, errCreateRDSClient) } diff --git a/pkg/controller/database/rdsinstance_test.go b/pkg/controller/database/rdsinstance_test.go index 85c41e7444..cdfa68b8d8 100644 --- a/pkg/controller/database/rdsinstance_test.go +++ b/pkg/controller/database/rdsinstance_test.go @@ -35,6 +35,7 @@ import ( "github.com/crossplaneio/stack-aws/apis/database/v1beta1" awsv1alpha3 "github.com/crossplaneio/stack-aws/apis/v1alpha3" + awsclients "github.com/crossplaneio/stack-aws/pkg/clients" "github.com/crossplaneio/stack-aws/pkg/clients/rds" "github.com/crossplaneio/stack-aws/pkg/clients/rds/fake" ) @@ -119,7 +120,7 @@ func TestConnect(t *testing.T) { Region: testRegion, UseServiceAccount: &saVal, ProviderSpec: runtimev1alpha1.ProviderSpec{ - CredentialsSecretRef: runtimev1alpha1.SecretKeySelector{ + CredentialsSecretRef: &runtimev1alpha1.SecretKeySelector{ SecretReference: runtimev1alpha1.SecretReference{ Namespace: secretNamespace, Name: connectionSecretName, @@ -132,7 +133,7 @@ func TestConnect(t *testing.T) { } type args struct { kube client.Client - newClientFn func(ctx context.Context, credentials []byte, region string, useSA bool) (rds.Client, error) + newClientFn func(ctx context.Context, credentials []byte, region string, auth awsclients.AuthMethod) (rds.Client, error) cr *v1beta1.RDSInstance } type want struct { @@ -159,16 +160,13 @@ func TestConnect(t *testing.T) { return errBoom }, }, - newClientFn: func(ctx context.Context, credentials []byte, region string, useSA bool) (i rds.Client, e error) { + newClientFn: func(_ context.Context, credentials []byte, region string, _ awsclients.AuthMethod) (i rds.Client, e error) { if diff := cmp.Diff(credData, string(credentials)); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } if diff := cmp.Diff(testRegion, region); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } - if diff := cmp.Diff(false, useSA); diff != "" { - t.Errorf("r: -want, +got:\n%s", diff) - } return nil, nil }, cr: instance(), @@ -186,16 +184,13 @@ func TestConnect(t *testing.T) { return errBoom }, }, - newClientFn: func(ctx context.Context, credentials []byte, region string, useSA bool) (i rds.Client, e error) { + newClientFn: func(_ context.Context, credentials []byte, region string, _ awsclients.AuthMethod) (i rds.Client, e error) { if diff := cmp.Diff("", string(credentials)); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } if diff := cmp.Diff(testRegion, region); diff != "" { t.Errorf("r: -want, +got:\n%s", diff) } - if diff := cmp.Diff(true, useSA); diff != "" { - t.Errorf("r: -want, +got:\n%s", diff) - } return nil, nil }, cr: instance(), @@ -236,6 +231,29 @@ func TestConnect(t *testing.T) { err: errors.Wrap(errBoom, errGetProviderSecret), }, }, + "SecretGetFailedNil": { + args: args{ + kube: &test.MockClient{ + MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { + switch key { + case client.ObjectKey{Name: providerName}: + p := providerSA(false) + p.SetCredentialsSecretReference(nil) + p.DeepCopyInto(obj.(*awsv1alpha3.Provider)) + return nil + case client.ObjectKey{Namespace: secretNamespace, Name: connectionSecretName}: + return errBoom + default: + return nil + } + }, + }, + cr: instance(), + }, + want: want{ + err: errors.New(errGetProviderSecret), + }, + }, } for name, tc := range cases { diff --git a/pkg/controller/utils/utils.go b/pkg/controller/utils/utils.go index a61103ad82..bbcbbdd987 100644 --- a/pkg/controller/utils/utils.go +++ b/pkg/controller/utils/utils.go @@ -42,6 +42,15 @@ func RetrieveAwsConfigFromProvider(ctx context.Context, client client.Reader, pr return nil, errors.Wrapf(err, "cannot get provider %s", n) } + if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + cfg, err := awsclients.UsePodServiceAccount(ctx, []byte{}, awsclients.DefaultSection, p.Spec.Region) + return cfg, errors.Wrap(err, "cannot create new AWS configuration using IAM roles for ServiceAccount") + } + + if p.GetCredentialsSecretReference() == nil { + return nil, errors.New("provider does not have a secret reference") + } + secret := &corev1.Secret{} n = types.NamespacedName{Namespace: p.Spec.CredentialsSecretRef.Namespace, Name: p.Spec.CredentialsSecretRef.Name} err := client.Get(ctx, n, secret) @@ -49,7 +58,7 @@ func RetrieveAwsConfigFromProvider(ctx context.Context, client client.Reader, pr return nil, errors.Wrapf(err, "cannot get provider secret %s", n) } - cfg, err := awsclients.LoadConfig(secret.Data[p.Spec.CredentialsSecretRef.Key], awsclients.DefaultSection, p.Spec.Region) + cfg, err := awsclients.UseProviderSecret(ctx, secret.Data[p.Spec.CredentialsSecretRef.Key], awsclients.DefaultSection, p.Spec.Region) return cfg, errors.Wrap(err, "cannot create new AWS configuration") } diff --git a/pkg/controller/utils/utils_test.go b/pkg/controller/utils/utils_test.go index 432c634607..d300db736b 100644 --- a/pkg/controller/utils/utils_test.go +++ b/pkg/controller/utils/utils_test.go @@ -66,7 +66,7 @@ aws_secret_access_key = mock_aws_secret_access_key`), Spec: awsv1alpha3.ProviderSpec{ Region: "mock-region", ProviderSpec: runtimev1alpha1.ProviderSpec{ - CredentialsSecretRef: runtimev1alpha1.SecretKeySelector{ + CredentialsSecretRef: &runtimev1alpha1.SecretKeySelector{ SecretReference: runtimev1alpha1.SecretReference{}, Key: "mockawskey", }, From 5680d65ec37d585a3fc5c8f8112d3680b38cccfd Mon Sep 17 00:00:00 2001 From: hasheddan Date: Sat, 15 Feb 2020 10:41:40 -0600 Subject: [PATCH 4/4] Use AWS bool value check for UseServiceAccount instead of check for nil Signed-off-by: hasheddan --- pkg/clients/aws.go | 4 ++++ pkg/controller/cache/managed.go | 2 +- pkg/controller/cache/managed_test.go | 2 +- pkg/controller/database/rdsinstance.go | 2 +- pkg/controller/database/rdsinstance_test.go | 2 +- pkg/controller/utils/utils.go | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pkg/clients/aws.go b/pkg/clients/aws.go index 756aecc536..b679627659 100644 --- a/pkg/clients/aws.go +++ b/pkg/clients/aws.go @@ -104,6 +104,10 @@ func UseProviderSecret(_ context.Context, data []byte, profile, region string) ( // UsePodServiceAccount assumes an IAM role configured via a ServiceAccount. // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html +// +// TODO(hasheddan): This should be replaced by the implementation of the Web +// Identity Token Provider in the following PR after merge and subsequent +// release of AWS SDK: https://github.com/aws/aws-sdk-go-v2/pull/488 func UsePodServiceAccount(ctx context.Context, _ []byte, _, region string) (*aws.Config, error) { cfg, err := external.LoadDefaultAWSConfig() if err != nil { diff --git a/pkg/controller/cache/managed.go b/pkg/controller/cache/managed.go index de6e10c3e0..ada4d0a3f3 100644 --- a/pkg/controller/cache/managed.go +++ b/pkg/controller/cache/managed.go @@ -89,7 +89,7 @@ func (c *connecter) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetProvider) } - if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + if commonaws.BoolValue(p.Spec.UseServiceAccount) { awsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, awsclients.UsePodServiceAccount) return &external{client: awsClient, kube: c.client}, errors.Wrap(err, errNewClient) } diff --git a/pkg/controller/cache/managed_test.go b/pkg/controller/cache/managed_test.go index 90598cbc76..8f8366da46 100644 --- a/pkg/controller/cache/managed_test.go +++ b/pkg/controller/cache/managed_test.go @@ -689,7 +689,7 @@ func TestConnect(t *testing.T) { i: replicationGroup(), }, { - name: "SuccessfulConnectSA", + name: "SuccessfulConnectWithServiceAccount", conn: &connecter{ client: &test.MockClient{ MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { diff --git a/pkg/controller/database/rdsinstance.go b/pkg/controller/database/rdsinstance.go index aa91d0632b..f949f5d1b7 100644 --- a/pkg/controller/database/rdsinstance.go +++ b/pkg/controller/database/rdsinstance.go @@ -88,7 +88,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetProvider) } - if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + if aws.BoolValue(p.Spec.UseServiceAccount) { rdsClient, err := c.newClientFn(ctx, []byte{}, p.Spec.Region, awsclients.UsePodServiceAccount) return &external{client: rdsClient, kube: c.kube}, errors.Wrap(err, errCreateRDSClient) } diff --git a/pkg/controller/database/rdsinstance_test.go b/pkg/controller/database/rdsinstance_test.go index cdfa68b8d8..7434b419fc 100644 --- a/pkg/controller/database/rdsinstance_test.go +++ b/pkg/controller/database/rdsinstance_test.go @@ -172,7 +172,7 @@ func TestConnect(t *testing.T) { cr: instance(), }, }, - "SuccessfulUseSA": { + "SuccessfulUseServiceAccount": { args: args{ kube: &test.MockClient{ MockGet: func(_ context.Context, key client.ObjectKey, obj runtime.Object) error { diff --git a/pkg/controller/utils/utils.go b/pkg/controller/utils/utils.go index bbcbbdd987..ecc325bd98 100644 --- a/pkg/controller/utils/utils.go +++ b/pkg/controller/utils/utils.go @@ -42,7 +42,7 @@ func RetrieveAwsConfigFromProvider(ctx context.Context, client client.Reader, pr return nil, errors.Wrapf(err, "cannot get provider %s", n) } - if p.Spec.UseServiceAccount != nil && *p.Spec.UseServiceAccount { + if aws.BoolValue(p.Spec.UseServiceAccount) { cfg, err := awsclients.UsePodServiceAccount(ctx, []byte{}, awsclients.DefaultSection, p.Spec.Region) return cfg, errors.Wrap(err, "cannot create new AWS configuration using IAM roles for ServiceAccount") }