From b6f140d7e383caf3bdf770203a4b74eae84d227c Mon Sep 17 00:00:00 2001 From: Michael Tewoldemedhin Date: Mon, 29 Jul 2024 16:35:20 -0700 Subject: [PATCH 1/2] Added tests to event_source_mapping and alias_ref for namespace reference check --- apis/v1alpha1/ack-generate-metadata.yaml | 6 +- .../lambda.services.k8s.aws_aliases.yaml | 2 + ....services.k8s.aws_eventsourcemappings.yaml | 6 + .../lambda.services.k8s.aws_functions.yaml | 10 + ...a.services.k8s.aws_functionurlconfigs.yaml | 2 + .../lambda.services.k8s.aws_versions.yaml | 2 + go.mod | 2 +- go.sum | 4 +- .../crds/lambda.services.k8s.aws_aliases.yaml | 2 + ....services.k8s.aws_eventsourcemappings.yaml | 6 + .../lambda.services.k8s.aws_functions.yaml | 10 + ...a.services.k8s.aws_functionurlconfigs.yaml | 2 + .../lambda.services.k8s.aws_versions.yaml | 2 + helm/templates/_helpers.tpl | 11 +- helm/templates/deployment.yaml | 8 + helm/values.schema.json | 7 + helm/values.yaml | 7 + pkg/resource/alias/references.go | 8 +- .../event_source_mapping/references.go | 22 +- pkg/resource/function/references.go | 36 +++- .../function_url_config/references.go | 8 +- pkg/resource/version/references.go | 8 +- test/e2e/conftest.py | 3 + test/e2e/resources/alias-ref-namespace.yaml | 14 ++ ...vent_source_mapping_sqs_ref_namespace.yaml | 15 ++ test/e2e/resources/function_namespace.yaml | 18 ++ test/e2e/tests/test_alias.py | 94 +++++++- test/e2e/tests/test_event_source_mapping.py | 200 +++++++++++++++--- 28 files changed, 444 insertions(+), 71 deletions(-) create mode 100644 test/e2e/resources/alias-ref-namespace.yaml create mode 100644 test/e2e/resources/event_source_mapping_sqs_ref_namespace.yaml create mode 100644 test/e2e/resources/function_namespace.yaml diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 28cd4cf3..bceaec78 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,8 +1,8 @@ ack_generate_info: - build_date: "2024-07-19T23:01:33Z" - build_hash: f0a0f42d507c550c2b063a192b3b43e4522bdd9c + build_date: "2024-07-30T00:06:18Z" + build_hash: 49afe38983d285f926b51b6d34e39a4d9aeffb85 go_version: go1.22.5 - version: v0.35.0 + version: v0.35.0-2-g49afe38 api_directory_checksum: 93229b2f11a89ef43fc0ef07ea1beb425e9aaf17 api_version: v1alpha1 aws_sdk_go_version: v1.44.181 diff --git a/config/crd/bases/lambda.services.k8s.aws_aliases.yaml b/config/crd/bases/lambda.services.k8s.aws_aliases.yaml index cb2bcba6..dc032fb1 100644 --- a/config/crd/bases/lambda.services.k8s.aws_aliases.yaml +++ b/config/crd/bases/lambda.services.k8s.aws_aliases.yaml @@ -127,6 +127,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object functionVersion: diff --git a/config/crd/bases/lambda.services.k8s.aws_eventsourcemappings.yaml b/config/crd/bases/lambda.services.k8s.aws_eventsourcemappings.yaml index 6165f161..1e9853a9 100644 --- a/config/crd/bases/lambda.services.k8s.aws_eventsourcemappings.yaml +++ b/config/crd/bases/lambda.services.k8s.aws_eventsourcemappings.yaml @@ -138,6 +138,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object filterCriteria: @@ -193,6 +195,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object functionResponseTypes: @@ -255,6 +259,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array diff --git a/config/crd/bases/lambda.services.k8s.aws_functions.yaml b/config/crd/bases/lambda.services.k8s.aws_functions.yaml index c866c409..cb5d051a 100644 --- a/config/crd/bases/lambda.services.k8s.aws_functions.yaml +++ b/config/crd/bases/lambda.services.k8s.aws_functions.yaml @@ -64,6 +64,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object s3Key: @@ -221,6 +223,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object layers: @@ -289,6 +293,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object runtime: @@ -353,6 +359,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array @@ -375,6 +383,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array diff --git a/config/crd/bases/lambda.services.k8s.aws_functionurlconfigs.yaml b/config/crd/bases/lambda.services.k8s.aws_functionurlconfigs.yaml index 61488213..096703ab 100644 --- a/config/crd/bases/lambda.services.k8s.aws_functionurlconfigs.yaml +++ b/config/crd/bases/lambda.services.k8s.aws_functionurlconfigs.yaml @@ -110,6 +110,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object qualifier: diff --git a/config/crd/bases/lambda.services.k8s.aws_versions.yaml b/config/crd/bases/lambda.services.k8s.aws_versions.yaml index 9a6173cd..19b525cf 100644 --- a/config/crd/bases/lambda.services.k8s.aws_versions.yaml +++ b/config/crd/bases/lambda.services.k8s.aws_versions.yaml @@ -115,6 +115,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object provisionedConcurrencyConfig: diff --git a/go.mod b/go.mod index c9eb61a6..9a74730f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/aws-controllers-k8s/kafka-controller v0.0.0-20230615185632-102279061de1 github.com/aws-controllers-k8s/kms-controller v0.1.2 github.com/aws-controllers-k8s/mq-controller v0.0.22 - github.com/aws-controllers-k8s/runtime v0.35.0 + github.com/aws-controllers-k8s/runtime v0.35.1-0.20240719172343-a132c887e8d4 github.com/aws-controllers-k8s/s3-controller v0.1.5 github.com/aws/aws-sdk-go v1.49.0 github.com/go-logr/logr v1.4.1 diff --git a/go.sum b/go.sum index 4cac218a..16ad633a 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/aws-controllers-k8s/kms-controller v0.1.2 h1:9lb98jspqOpFpmIFHOJ6pRnO github.com/aws-controllers-k8s/kms-controller v0.1.2/go.mod h1:6CoV0UMFd03EUF9dXgOTTScGdBhJzsWn9W0dw2n0kA4= github.com/aws-controllers-k8s/mq-controller v0.0.22 h1:XxFSQL9yaaiiuZ6E/fh/+Y9C+3DG2c5oXWG/4ZNwd1w= github.com/aws-controllers-k8s/mq-controller v0.0.22/go.mod h1:p+YVFjpwlgRC+1cPeCabk1xTB1hTCU+RwYtFzrTnJmE= -github.com/aws-controllers-k8s/runtime v0.35.0 h1:kLRLFOAcaFJRv/aEiWtb0qhlxFpwvmx6shCWNc1Tuas= -github.com/aws-controllers-k8s/runtime v0.35.0/go.mod h1:gI2pWb20UGLP2SnHf1a1VzTd7iVVy+/I9VAzT0Y+Dew= +github.com/aws-controllers-k8s/runtime v0.35.1-0.20240719172343-a132c887e8d4 h1:CW58T4qFJpoF37hCPlV1NHCc6mdxNf6jdvLobVolSY0= +github.com/aws-controllers-k8s/runtime v0.35.1-0.20240719172343-a132c887e8d4/go.mod h1:gI2pWb20UGLP2SnHf1a1VzTd7iVVy+/I9VAzT0Y+Dew= github.com/aws-controllers-k8s/s3-controller v0.1.5 h1:5zb7jsh0fgbPM8cIvcsuH1dta1dKzaAnlwgvb6u3hOc= github.com/aws-controllers-k8s/s3-controller v0.1.5/go.mod h1:8Z8JlO5Hc1dZX2YELu94+lnOgKM0FioAHJBsyaWvtx8= github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY= diff --git a/helm/crds/lambda.services.k8s.aws_aliases.yaml b/helm/crds/lambda.services.k8s.aws_aliases.yaml index 81ed6a58..e6d6fd20 100644 --- a/helm/crds/lambda.services.k8s.aws_aliases.yaml +++ b/helm/crds/lambda.services.k8s.aws_aliases.yaml @@ -127,6 +127,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object functionVersion: diff --git a/helm/crds/lambda.services.k8s.aws_eventsourcemappings.yaml b/helm/crds/lambda.services.k8s.aws_eventsourcemappings.yaml index b477a2a0..971bde5d 100644 --- a/helm/crds/lambda.services.k8s.aws_eventsourcemappings.yaml +++ b/helm/crds/lambda.services.k8s.aws_eventsourcemappings.yaml @@ -138,6 +138,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object filterCriteria: @@ -193,6 +195,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object functionResponseTypes: @@ -255,6 +259,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array diff --git a/helm/crds/lambda.services.k8s.aws_functions.yaml b/helm/crds/lambda.services.k8s.aws_functions.yaml index 6fed3bb6..e51b8f36 100644 --- a/helm/crds/lambda.services.k8s.aws_functions.yaml +++ b/helm/crds/lambda.services.k8s.aws_functions.yaml @@ -64,6 +64,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object s3Key: @@ -221,6 +223,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object layers: @@ -289,6 +293,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object runtime: @@ -353,6 +359,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array @@ -375,6 +383,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object type: array diff --git a/helm/crds/lambda.services.k8s.aws_functionurlconfigs.yaml b/helm/crds/lambda.services.k8s.aws_functionurlconfigs.yaml index 51f127f6..eaa31263 100644 --- a/helm/crds/lambda.services.k8s.aws_functionurlconfigs.yaml +++ b/helm/crds/lambda.services.k8s.aws_functionurlconfigs.yaml @@ -110,6 +110,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object qualifier: diff --git a/helm/crds/lambda.services.k8s.aws_versions.yaml b/helm/crds/lambda.services.k8s.aws_versions.yaml index a4eccf13..af43332d 100644 --- a/helm/crds/lambda.services.k8s.aws_versions.yaml +++ b/helm/crds/lambda.services.k8s.aws_versions.yaml @@ -115,6 +115,8 @@ spec: properties: name: type: string + namespace: + type: string type: object type: object provisionedConcurrencyConfig: diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 12fc99ca..5f57acb4 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -355,4 +355,13 @@ rules: - get - patch - update -{{- end }} \ No newline at end of file +{{- end }} + +{{/* Convert k/v map to string like: "key1=value1,key2=value2,..." */}} +{{- define "ack-lambda-controller.feature-gates" -}} +{{- $list := list -}} +{{- range $k, $v := .Values.featureGates -}} +{{- $list = append $list (printf "%s=%s" $k ( $v | toString)) -}} +{{- end -}} +{{ join "," $list }} +{{- end -}} diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml index 8a4411f1..6fc470d2 100644 --- a/helm/templates/deployment.yaml +++ b/helm/templates/deployment.yaml @@ -79,6 +79,10 @@ spec: {{- range $key, $value := .Values.reconcile.resourceMaxConcurrentSyncs }} - --reconcile-resource-max-concurrent-syncs - "$(RECONCILE_RESOURCE_MAX_CONCURRENT_SYNCS_{{ $key | upper }})" +{{- end }} +{{- if .Values.featureGates}} + - --feature-gates + - "$(FEATURE_GATES)" {{- end }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} @@ -122,6 +126,10 @@ spec: {{- range $key, $value := .Values.reconcile.resourceMaxConcurrentSyncs }} - name: RECONCILE_RESOURCE_MAX_CONCURRENT_SYNCS_{{ $key | upper }} value: {{ $key }}={{ $value }} +{{- end }} +{{- if .Values.featureGates}} + - name: FEATURE_GATES + value: {{ include "ack-lambda-controller.feature-gates" . }} {{- end }} {{- if .Values.aws.credentials.secretName }} - name: AWS_SHARED_CREDENTIALS_FILE diff --git a/helm/values.schema.json b/helm/values.schema.json index 742163eb..7ccb485d 100644 --- a/helm/values.schema.json +++ b/helm/values.schema.json @@ -268,6 +268,13 @@ "type": "object" } }, + "featureGates": { + "description": "Feature gates settings", + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, "required": [ "image", "deployment", diff --git a/helm/values.yaml b/helm/values.yaml index 9a842a00..c67355a8 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -153,3 +153,10 @@ leaderElection: # will attempt to use the namespace of the service account mounted to the Controller # pod. namespace: "" + +# Configuration for feature gates. These are optional controller features that +# can be individually enabled ("true") or disabled ("false") by adding key/value +# pairs below. +featureGates: {} + # featureGate1: true + # featureGate2: false diff --git a/pkg/resource/alias/references.go b/pkg/resource/alias/references.go index c6c685eb..ee0dd3c8 100644 --- a/pkg/resource/alias/references.go +++ b/pkg/resource/alias/references.go @@ -56,12 +56,11 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, bool, error) { - namespace := res.MetaObject().GetNamespace() ko := rm.concreteResource(res).ko resourceHasReferences := false err := validateReferenceFields(ko) - if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences @@ -90,7 +89,6 @@ func validateReferenceFields(ko *svcapitypes.Alias) error { func (rm *resourceManager) resolveReferenceForFunctionName( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Alias, ) (hasReferences bool, err error) { if ko.Spec.FunctionRef != nil && ko.Spec.FunctionRef.From != nil { @@ -99,6 +97,10 @@ func (rm *resourceManager) resolveReferenceForFunctionName( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: FunctionRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &svcapitypes.Function{} if err := getReferencedResourceState_Function(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err diff --git a/pkg/resource/event_source_mapping/references.go b/pkg/resource/event_source_mapping/references.go index 6795d3f3..c96f194e 100644 --- a/pkg/resource/event_source_mapping/references.go +++ b/pkg/resource/event_source_mapping/references.go @@ -72,24 +72,23 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, bool, error) { - namespace := res.MetaObject().GetNamespace() ko := rm.concreteResource(res).ko resourceHasReferences := false err := validateReferenceFields(ko) - if fieldHasReferences, err := rm.resolveReferenceForEventSourceARN(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForEventSourceARN(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForQueues(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForQueues(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences @@ -126,7 +125,6 @@ func validateReferenceFields(ko *svcapitypes.EventSourceMapping) error { func (rm *resourceManager) resolveReferenceForEventSourceARN( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.EventSourceMapping, ) (hasReferences bool, err error) { if ko.Spec.EventSourceRef != nil && ko.Spec.EventSourceRef.From != nil { @@ -135,6 +133,10 @@ func (rm *resourceManager) resolveReferenceForEventSourceARN( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: EventSourceRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &kafkaapitypes.Cluster{} if err := getReferencedResourceState_Cluster(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -203,7 +205,6 @@ func getReferencedResourceState_Cluster( func (rm *resourceManager) resolveReferenceForFunctionName( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.EventSourceMapping, ) (hasReferences bool, err error) { if ko.Spec.FunctionRef != nil && ko.Spec.FunctionRef.From != nil { @@ -212,6 +213,10 @@ func (rm *resourceManager) resolveReferenceForFunctionName( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: FunctionRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &svcapitypes.Function{} if err := getReferencedResourceState_Function(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -280,7 +285,6 @@ func getReferencedResourceState_Function( func (rm *resourceManager) resolveReferenceForQueues( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.EventSourceMapping, ) (hasReferences bool, err error) { for _, f0iter := range ko.Spec.QueueRefs { @@ -290,6 +294,10 @@ func (rm *resourceManager) resolveReferenceForQueues( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: QueueRefs") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &mqapitypes.Broker{} if err := getReferencedResourceState_Broker(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err diff --git a/pkg/resource/function/references.go b/pkg/resource/function/references.go index 1a1da07e..1ae0f7ba 100644 --- a/pkg/resource/function/references.go +++ b/pkg/resource/function/references.go @@ -97,36 +97,35 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, bool, error) { - namespace := res.MetaObject().GetNamespace() ko := rm.concreteResource(res).ko resourceHasReferences := false err := validateReferenceFields(ko) - if fieldHasReferences, err := rm.resolveReferenceForCode_S3Bucket(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForCode_S3Bucket(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForKMSKeyARN(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForKMSKeyARN(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForRole(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForRole(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForVPCConfig_SecurityGroupIDs(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForVPCConfig_SecurityGroupIDs(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences } - if fieldHasReferences, err := rm.resolveReferenceForVPCConfig_SubnetIDs(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForVPCConfig_SubnetIDs(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences @@ -177,7 +176,6 @@ func validateReferenceFields(ko *svcapitypes.Function) error { func (rm *resourceManager) resolveReferenceForCode_S3Bucket( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Function, ) (hasReferences bool, err error) { if ko.Spec.Code != nil { @@ -187,6 +185,10 @@ func (rm *resourceManager) resolveReferenceForCode_S3Bucket( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: Code.S3BucketRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &s3apitypes.Bucket{} if err := getReferencedResourceState_Bucket(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -256,7 +258,6 @@ func getReferencedResourceState_Bucket( func (rm *resourceManager) resolveReferenceForKMSKeyARN( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Function, ) (hasReferences bool, err error) { if ko.Spec.KMSKeyRef != nil && ko.Spec.KMSKeyRef.From != nil { @@ -265,6 +266,10 @@ func (rm *resourceManager) resolveReferenceForKMSKeyARN( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: KMSKeyRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &kmsapitypes.Key{} if err := getReferencedResourceState_Key(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -333,7 +338,6 @@ func getReferencedResourceState_Key( func (rm *resourceManager) resolveReferenceForRole( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Function, ) (hasReferences bool, err error) { if ko.Spec.RoleRef != nil && ko.Spec.RoleRef.From != nil { @@ -342,6 +346,10 @@ func (rm *resourceManager) resolveReferenceForRole( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: RoleRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &iamapitypes.Role{} if err := getReferencedResourceState_Role(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -410,7 +418,6 @@ func getReferencedResourceState_Role( func (rm *resourceManager) resolveReferenceForVPCConfig_SecurityGroupIDs( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Function, ) (hasReferences bool, err error) { if ko.Spec.VPCConfig != nil { @@ -421,6 +428,10 @@ func (rm *resourceManager) resolveReferenceForVPCConfig_SecurityGroupIDs( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: VPCConfig.SecurityGroupRefs") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &ec2apitypes.SecurityGroup{} if err := getReferencedResourceState_SecurityGroup(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err @@ -494,7 +505,6 @@ func getReferencedResourceState_SecurityGroup( func (rm *resourceManager) resolveReferenceForVPCConfig_SubnetIDs( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Function, ) (hasReferences bool, err error) { if ko.Spec.VPCConfig != nil { @@ -505,6 +515,10 @@ func (rm *resourceManager) resolveReferenceForVPCConfig_SubnetIDs( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: VPCConfig.SubnetRefs") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &ec2apitypes.Subnet{} if err := getReferencedResourceState_Subnet(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err diff --git a/pkg/resource/function_url_config/references.go b/pkg/resource/function_url_config/references.go index ebcb090a..8fa33d59 100644 --- a/pkg/resource/function_url_config/references.go +++ b/pkg/resource/function_url_config/references.go @@ -56,12 +56,11 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, bool, error) { - namespace := res.MetaObject().GetNamespace() ko := rm.concreteResource(res).ko resourceHasReferences := false err := validateReferenceFields(ko) - if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences @@ -90,7 +89,6 @@ func validateReferenceFields(ko *svcapitypes.FunctionURLConfig) error { func (rm *resourceManager) resolveReferenceForFunctionName( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.FunctionURLConfig, ) (hasReferences bool, err error) { if ko.Spec.FunctionRef != nil && ko.Spec.FunctionRef.From != nil { @@ -99,6 +97,10 @@ func (rm *resourceManager) resolveReferenceForFunctionName( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: FunctionRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &svcapitypes.Function{} if err := getReferencedResourceState_Function(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err diff --git a/pkg/resource/version/references.go b/pkg/resource/version/references.go index c5d69788..8c41afaf 100644 --- a/pkg/resource/version/references.go +++ b/pkg/resource/version/references.go @@ -56,12 +56,11 @@ func (rm *resourceManager) ResolveReferences( apiReader client.Reader, res acktypes.AWSResource, ) (acktypes.AWSResource, bool, error) { - namespace := res.MetaObject().GetNamespace() ko := rm.concreteResource(res).ko resourceHasReferences := false err := validateReferenceFields(ko) - if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, namespace, ko); err != nil { + if fieldHasReferences, err := rm.resolveReferenceForFunctionName(ctx, apiReader, ko); err != nil { return &resource{ko}, (resourceHasReferences || fieldHasReferences), err } else { resourceHasReferences = resourceHasReferences || fieldHasReferences @@ -90,7 +89,6 @@ func validateReferenceFields(ko *svcapitypes.Version) error { func (rm *resourceManager) resolveReferenceForFunctionName( ctx context.Context, apiReader client.Reader, - namespace string, ko *svcapitypes.Version, ) (hasReferences bool, err error) { if ko.Spec.FunctionRef != nil && ko.Spec.FunctionRef.From != nil { @@ -99,6 +97,10 @@ func (rm *resourceManager) resolveReferenceForFunctionName( if arr.Name == nil || *arr.Name == "" { return hasReferences, fmt.Errorf("provided resource reference is nil or empty: FunctionRef") } + namespace := ko.ObjectMeta.GetNamespace() + if arr.Namespace != nil && *arr.Namespace != "" { + namespace = *arr.Namespace + } obj := &svcapitypes.Function{} if err := getReferencedResourceState_Function(ctx, apiReader, obj, *arr.Name, namespace); err != nil { return hasReferences, err diff --git a/test/e2e/conftest.py b/test/e2e/conftest.py index d3275a15..1e2ab49b 100644 --- a/test/e2e/conftest.py +++ b/test/e2e/conftest.py @@ -32,6 +32,9 @@ def pytest_configure(config): config.addinivalue_line( "markers", "slow: mark test as slow to run" ) + config.addinivalue_line( + "markers", "resource_data: mark test with data to use when creating fixture" + ) def pytest_collection_modifyitems(config, items): if config.getoption("--runslow"): diff --git a/test/e2e/resources/alias-ref-namespace.yaml b/test/e2e/resources/alias-ref-namespace.yaml new file mode 100644 index 00000000..09db57e9 --- /dev/null +++ b/test/e2e/resources/alias-ref-namespace.yaml @@ -0,0 +1,14 @@ +apiVersion: lambda.services.k8s.aws/v1alpha1 +kind: Alias +metadata: + name: $ALIAS_NAME + annotations: + services.k8s.aws/region: $AWS_REGION +spec: + name: $ALIAS_NAME + functionRef: + from: + name: $FUNCTION_REF_NAME + namespace: $FUNCTION_REF_NAMESPACE + functionVersion: $FUNCTION_VERSION + description: alias created by ACK lambda-controller e2e tests \ No newline at end of file diff --git a/test/e2e/resources/event_source_mapping_sqs_ref_namespace.yaml b/test/e2e/resources/event_source_mapping_sqs_ref_namespace.yaml new file mode 100644 index 00000000..550c6d60 --- /dev/null +++ b/test/e2e/resources/event_source_mapping_sqs_ref_namespace.yaml @@ -0,0 +1,15 @@ +apiVersion: lambda.services.k8s.aws/v1alpha1 +kind: EventSourceMapping +metadata: + name: $EVENT_SOURCE_MAPPING_NAME + annotations: + services.k8s.aws/region: $AWS_REGION +spec: + functionRef: + from: + name: $FUNCTION_REF_NAME + namespace: $FUNCTION_REF_NAMESPACE + eventSourceARN: $EVENT_SOURCE_ARN + batchSize: $BATCH_SIZE + maximumBatchingWindowInSeconds: $MAXIMUM_BATCHING_WINDOW_IN_SECONDS + enabled: false \ No newline at end of file diff --git a/test/e2e/resources/function_namespace.yaml b/test/e2e/resources/function_namespace.yaml new file mode 100644 index 00000000..6ccb390b --- /dev/null +++ b/test/e2e/resources/function_namespace.yaml @@ -0,0 +1,18 @@ +apiVersion: lambda.services.k8s.aws/v1alpha1 +kind: Function +metadata: + name: $FUNCTION_NAME + namespace: $FUNCTION_NAMESPACE + annotations: + services.k8s.aws/region: $AWS_REGION +spec: + name: $FUNCTION_NAME + code: + s3Bucket: $BUCKET_NAME + s3Key: $LAMBDA_FILE_NAME + role: $LAMBDA_ROLE + runtime: python3.9 + handler: main + description: function created by ACK lambda-controller e2e tests + reservedConcurrentExecutions: $RESERVED_CONCURRENT_EXECUTIONS + codeSigningConfigARN: "$CODE_SIGNING_CONFIG_ARN" \ No newline at end of file diff --git a/test/e2e/tests/test_alias.py b/test/e2e/tests/test_alias.py index 1b2c72fb..3b146b5a 100644 --- a/test/e2e/tests/test_alias.py +++ b/test/e2e/tests/test_alias.py @@ -28,17 +28,35 @@ from e2e.service_bootstrap import LAMBDA_FUNCTION_FILE_ZIP from e2e.tests.helper import LambdaValidator +log = logging.getLogger() RESOURCE_PLURAL = "aliases" CREATE_WAIT_AFTER_SECONDS = 30 UPDATE_WAIT_AFTER_SECONDS = 30 DELETE_WAIT_AFTER_SECONDS = 30 +TESTING_NAMESPACE = "custom_namespace" @pytest.fixture(scope="module") -def lambda_function(): +def lambda_function(request): resource_name = random_suffix_name("lambda-function", 24) resources = get_bootstrap_resources() + marker = request.node.get_closest_marker("resource_data") + filename = "function" + namespace = "default" + + if marker is not None: + data = marker.args[0] + if 'withNamespace' in data and data['withNamespace']: + filename = "function_namespace" + namespace = TESTING_NAMESPACE + replacements['FUNCTION_NAMESPACE'] = namespace + k8s.create_k8s_namespace( + namespace + ) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + log.error("WE HAVE REACHED HERE") + replacements = REPLACEMENT_VALUES.copy() replacements["FUNCTION_NAME"] = resource_name replacements["BUCKET_NAME"] = resources.FunctionsBucket.name @@ -50,7 +68,7 @@ def lambda_function(): # Load function CR resource_data = load_lambda_resource( - "function", + filename, additional_replacements=replacements, ) logging.debug(resource_data) @@ -58,7 +76,7 @@ def lambda_function(): # Create k8s resource function_reference = k8s.CustomResourceReference( CRD_GROUP, CRD_VERSION, "functions", - resource_name, namespace="default", + resource_name, namespace=namespace, ) # Create lambda function @@ -68,7 +86,7 @@ def lambda_function(): assert function_resource is not None assert k8s.get_resource_exists(function_reference) - time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) yield (function_reference, function_resource) @@ -78,6 +96,7 @@ def lambda_function(): @service_marker @pytest.mark.canary class TestAlias: + @pytest.mark.resource_data({'withNamespace': False}) def test_smoke(self, lambda_client, lambda_function): (_, function_resource) = lambda_function lambda_function_name = function_resource["spec"]["name"] @@ -137,6 +156,7 @@ def test_smoke(self, lambda_client, lambda_function): # Check alias doesn't exist assert not lambda_validator.alias_exists(resource_name, lambda_function_name) + @pytest.mark.resource_data({'withNamespace': False}) def test_smoke_ref(self, lambda_client, lambda_function): (_, function_resource) = lambda_function function_resource_name = function_resource["metadata"]["name"] @@ -195,7 +215,72 @@ def test_smoke_ref(self, lambda_client, lambda_function): # Check alias doesn't exist assert not lambda_validator.alias_exists(resource_name, function_resource_name) + + @pytest.mark.resource_data({'withNamespace': True}) + def test_smoke_namespace_ref(self, lambda_client, lambda_function): + (_, function_resource) = lambda_function + function_resource_name = function_resource["metadata"]["name"] + + resource_name = random_suffix_name("lambda-alias", 24) + + replacements = REPLACEMENT_VALUES.copy() + replacements["AWS_REGION"] = get_region() + replacements["ALIAS_NAME"] = resource_name + replacements["FUNCTION_REF_NAME"] = function_resource_name + replacements["FUNCTION_VERSION"] = "$LATEST" + replacements["FUNCTION_REF_NAMESPACE"] = TESTING_NAMESPACE + + # Load alias CR + resource_data = load_lambda_resource( + "alias-ref-namespace", + additional_replacements=replacements, + ) + logging.debug(resource_data) + + # Create k8s resource + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + resource_name, namespace="default", + ) + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) + + assert cr is not None + assert k8s.get_resource_exists(ref) + + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + lambda_validator = LambdaValidator(lambda_client) + # Check alias exists + + log.error(lambda_validator.function_exists(function_resource_name)) + + assert lambda_validator.alias_exists(resource_name, function_resource_name) + + cr = k8s.wait_resource_consumed_by_controller(ref) + + # Update cr + cr["spec"]["description"] = "" + + # Patch k8s resource + k8s.patch_custom_resource(ref, cr) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check alias description + alias = lambda_validator.get_alias(resource_name, function_resource_name) + assert alias is not None + assert alias["Description"] == "" + + # Delete k8s resource + _, deleted = k8s.delete_custom_resource(ref) + assert deleted + + time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # Check alias doesn't exist + assert not lambda_validator.alias_exists(resource_name, function_resource_name) + @pytest.mark.resource_data({'withNamespace': False}) def test_provisioned_concurrency_config(self, lambda_client, lambda_function): (_, function_resource) = lambda_function lambda_function_name = function_resource["spec"]["name"] @@ -276,6 +361,7 @@ def test_provisioned_concurrency_config(self, lambda_client, lambda_function): # Check alias doesn't exist assert not lambda_validator.alias_exists(resource_name, lambda_function_name) + @pytest.mark.resource_data({'withNamespace': False}) def test_function_event_invoke_config(self, lambda_client, lambda_function): (_, function_resource) = lambda_function lambda_function_name = function_resource["spec"]["name"] diff --git a/test/e2e/tests/test_event_source_mapping.py b/test/e2e/tests/test_event_source_mapping.py index 70a696ec..e7e190fd 100644 --- a/test/e2e/tests/test_event_source_mapping.py +++ b/test/e2e/tests/test_event_source_mapping.py @@ -33,54 +33,182 @@ CREATE_WAIT_AFTER_SECONDS = 20 UPDATE_WAIT_AFTER_SECONDS = 20 DELETE_WAIT_AFTER_SECONDS = 20 +TESTING_NAMESPACE = "custom_namespace" + +log = logging.getLogger() + + +@pytest.fixture(scope="module") +def referred_function_name(): + return random_suffix_name("lambda-function", 24) @pytest.fixture(scope="module") -def lambda_function(): - resource_name = random_suffix_name("lambda-function", 24) +def stupid_function(request): + marker = request.node.get_closest_marker("resource_data") + if marker is None: + return "SAD" + log.error("THIS IS A STUPID FUNCTION") + return "happy" + +@pytest.fixture(scope="module") +def lambda_function(request, referred_function_name): + resource_name = referred_function_name + resources = get_bootstrap_resources() + + marker = request.node.get_closest_marker("resource_data") + filename = "function" + namespace = "default" + + replacements = REPLACEMENT_VALUES.copy() + replacements["FUNCTION_NAME"] = resource_name + replacements["BUCKET_NAME"] = resources.FunctionsBucket.name + replacements["LAMBDA_ROLE"] = resources.ESMRole.arn + replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP + replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "10" + replacements["CODE_SIGNING_CONFIG_ARN"] = "" + replacements["AWS_REGION"] = get_region() + + log.error(request) + log.error(request.node) + log.error(request.node.get_closest_marker("resource_data")) + if marker is not None: + data = marker.args[0] + log.error(data) + if 'withNamespace' in data and data['withNamespace']: + k8s.create_k8s_namespace( + namespace + ) + filename = "function_namespace" + namespace = TESTING_NAMESPACE + replacements['FUNCTION_NAMESPACE'] = namespace + log.error(replacements) + log.error(filename) + + # Load function CR + resource_data = load_lambda_resource( + filename, + additional_replacements=replacements, + ) + logging.debug(resource_data) + + # Create k8s resource + function_reference = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, "functions", + resource_name, namespace=namespace, + ) + + # Create lambda function + k8s.create_custom_resource(function_reference, resource_data) + function_resource = k8s.wait_resource_consumed_by_controller(function_reference) + + assert function_resource is not None + assert k8s.get_resource_exists(function_reference) + + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + yield (function_reference, function_resource) + + _, deleted = k8s.delete_custom_resource(function_reference) + assert deleted + +@service_marker +@pytest.mark.canary +class TestEventSourceMapping: + @pytest.mark.resource_data({'withNamespace': False}) + def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): + (_, function_resource) = lambda_function + lambda_function_name = function_resource["spec"]["name"] + + resource_name = random_suffix_name("lambda-esm", 24) resources = get_bootstrap_resources() replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.ESMRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "10" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" replacements["AWS_REGION"] = get_region() + replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name + replacements["BATCH_SIZE"] = "10" + replacements["FUNCTION_NAME"] = lambda_function_name + replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn + replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" - # Load function CR + # Load ESM CR resource_data = load_lambda_resource( - "function", + "event_source_mapping_sqs", additional_replacements=replacements, ) logging.debug(resource_data) # Create k8s resource - function_reference = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, "functions", + ref = k8s.CustomResourceReference( + CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, resource_name, namespace="default", ) + k8s.create_custom_resource(ref, resource_data) + cr = k8s.wait_resource_consumed_by_controller(ref) - # Create lambda function - k8s.create_custom_resource(function_reference, resource_data) - function_resource = k8s.wait_resource_consumed_by_controller(function_reference) - - assert function_resource is not None - assert k8s.get_resource_exists(function_reference) + assert cr is not None + assert k8s.get_resource_exists(ref) time.sleep(CREATE_WAIT_AFTER_SECONDS) - yield (function_reference, function_resource) + esm_uuid = cr['status']['uuid'] + + lambda_validator = LambdaValidator(lambda_client) + # Check ESM exists + assert lambda_validator.event_source_mapping_exists(esm_uuid) + + # Update cr + cr["spec"]["batchSize"] = 20 + cr["spec"]["filterCriteria"] = { + "filters": [ + { + "pattern": "{\"controller-version\":[\"v1\"]}" + }, + ] + } + cr["spec"]["scalingConfig"] = {"maximumConcurrency": 4} + + # Patch k8s resource + k8s.patch_custom_resource(ref, cr) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # Check ESM batch size & filters + esm = lambda_validator.get_event_source_mapping(esm_uuid) + assert esm is not None + assert esm["BatchSize"] == 20 + assert esm["FilterCriteria"]["Filters"] == [ + { + "Pattern": "{\"controller-version\":[\"v1\"]}" + }, + ] + assert esm["ScalingConfig"]["MaximumConcurrency"] == 4 + + + # Delete the filterCriteria field + cr = k8s.wait_resource_consumed_by_controller(ref) + cr["spec"]["filterCriteria"] = None + + # Patch k8s resource + k8s.patch_custom_resource(ref, cr) + time.sleep(UPDATE_WAIT_AFTER_SECONDS) - _, deleted = k8s.delete_custom_resource(function_reference) + # Check filters have been deleted + esm = lambda_validator.get_event_source_mapping(esm_uuid) + assert esm is not None + assert "FilterCriteria" not in esm + + # Delete k8s resource + _, deleted = k8s.delete_custom_resource(ref) assert deleted -@service_marker -@pytest.mark.canary -class TestEventSourceMapping: - def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): + time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # Check ESM doesn't exist + assert not lambda_validator.event_source_mapping_exists(esm_uuid) + + @pytest.mark.resource_data({'withNamespace': False}) + def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] + function_resource_name = function_resource["metadata"]["name"] resource_name = random_suffix_name("lambda-esm", 24) resources = get_bootstrap_resources() @@ -89,13 +217,13 @@ def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): replacements["AWS_REGION"] = get_region() replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name replacements["BATCH_SIZE"] = "10" - replacements["FUNCTION_NAME"] = lambda_function_name + replacements["FUNCTION_REF_NAME"] = function_resource_name replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" # Load ESM CR resource_data = load_lambda_resource( - "event_source_mapping_sqs", + "event_source_mapping_sqs_ref", additional_replacements=replacements, ) logging.debug(resource_data) @@ -128,7 +256,6 @@ def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): }, ] } - cr["spec"]["scalingConfig"] = {"maximumConcurrency": 4} # Patch k8s resource k8s.patch_custom_resource(ref, cr) @@ -143,8 +270,6 @@ def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): "Pattern": "{\"controller-version\":[\"v1\"]}" }, ] - assert esm["ScalingConfig"]["MaximumConcurrency"] == 4 - # Delete the filterCriteria field cr = k8s.wait_resource_consumed_by_controller(ref) @@ -167,10 +292,13 @@ def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): # Check ESM doesn't exist assert not lambda_validator.event_source_mapping_exists(esm_uuid) - - def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): + + @pytest.mark.resource_data({'withNamespace': True}) + def test_smoke_sqs_queue_stream_namespace_ref(self, lambda_client, lambda_function, stupid_function): (_, function_resource) = lambda_function function_resource_name = function_resource["metadata"]["name"] + something = stupid_function + log.error(something) resource_name = random_suffix_name("lambda-esm", 24) resources = get_bootstrap_resources() @@ -182,10 +310,11 @@ def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): replacements["FUNCTION_REF_NAME"] = function_resource_name replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" + replacements["FUNCTION_REF_NAMESPACE"] = TESTING_NAMESPACE # Load ESM CR resource_data = load_lambda_resource( - "event_source_mapping_sqs_ref", + "event_source_mapping_sqs_ref_namespace", additional_replacements=replacements, ) logging.debug(resource_data) @@ -202,6 +331,10 @@ def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): assert k8s.get_resource_exists(ref) time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + log.error(cr['status']) esm_uuid = cr['status']['uuid'] @@ -255,6 +388,7 @@ def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): # Check ESM doesn't exist assert not lambda_validator.event_source_mapping_exists(esm_uuid) + @pytest.mark.resource_data({'withNamespace': False}) def test_smoke_dynamodb_table_stream(self, lambda_client, lambda_function): (_, function_resource) = lambda_function lambda_function_name = function_resource["spec"]["name"] From 3b496eddead980639c8e2581696720fffc4f18ef Mon Sep 17 00:00:00 2001 From: Michael Tewoldemedhin Date: Tue, 30 Jul 2024 14:36:19 -0700 Subject: [PATCH 2/2] Testing --- test/e2e/tests/test_alias.py | 470 ++++----- test/e2e/tests/test_code_signing_config.py | 94 -- test/e2e/tests/test_event_source_mapping.py | 552 +++++----- test/e2e/tests/test_function.py | 1039 ------------------- test/e2e/tests/test_function_url_config.py | 224 ---- test/e2e/tests/test_layer_version.py | 114 -- test/e2e/tests/test_version.py | 438 -------- 7 files changed, 502 insertions(+), 2429 deletions(-) delete mode 100644 test/e2e/tests/test_code_signing_config.py delete mode 100644 test/e2e/tests/test_function.py delete mode 100644 test/e2e/tests/test_function_url_config.py delete mode 100644 test/e2e/tests/test_layer_version.py delete mode 100644 test/e2e/tests/test_version.py diff --git a/test/e2e/tests/test_alias.py b/test/e2e/tests/test_alias.py index 3b146b5a..8eb43748 100644 --- a/test/e2e/tests/test_alias.py +++ b/test/e2e/tests/test_alias.py @@ -28,15 +28,14 @@ from e2e.service_bootstrap import LAMBDA_FUNCTION_FILE_ZIP from e2e.tests.helper import LambdaValidator -log = logging.getLogger() RESOURCE_PLURAL = "aliases" CREATE_WAIT_AFTER_SECONDS = 30 UPDATE_WAIT_AFTER_SECONDS = 30 DELETE_WAIT_AFTER_SECONDS = 30 -TESTING_NAMESPACE = "custom_namespace" +TESTING_NAMESPACE = random_suffix_name("testing-alias-namespace", 28) -@pytest.fixture(scope="module") +@pytest.fixture(scope="function") def lambda_function(request): resource_name = random_suffix_name("lambda-function", 24) resources = get_bootstrap_resources() @@ -45,6 +44,8 @@ def lambda_function(request): filename = "function" namespace = "default" + replacements = REPLACEMENT_VALUES.copy() + if marker is not None: data = marker.args[0] if 'withNamespace' in data and data['withNamespace']: @@ -55,9 +56,10 @@ def lambda_function(request): namespace ) time.sleep(CREATE_WAIT_AFTER_SECONDS) - log.error("WE HAVE REACHED HERE") - - replacements = REPLACEMENT_VALUES.copy() + time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + logging.info("function-namespace-is: "+ namespace) + replacements["FUNCTION_NAME"] = resource_name replacements["BUCKET_NAME"] = resources.FunctionsBucket.name replacements["LAMBDA_ROLE"] = resources.EICRole.arn @@ -96,125 +98,125 @@ def lambda_function(request): @service_marker @pytest.mark.canary class TestAlias: - @pytest.mark.resource_data({'withNamespace': False}) - def test_smoke(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-alias", 24) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["ALIAS_NAME"] = resource_name - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["FUNCTION_VERSION"] = "$LATEST" - - # Load alias CR - resource_data = load_lambda_resource( - "alias", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - lambda_validator = LambdaValidator(lambda_client) - # Check alias exists - assert lambda_validator.alias_exists(resource_name, lambda_function_name) - - cr = k8s.wait_resource_consumed_by_controller(ref) + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_smoke(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # lambda_function_name = function_resource["spec"]["name"] + + # resource_name = random_suffix_name("lambda-alias", 24) + + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["ALIAS_NAME"] = resource_name + # replacements["FUNCTION_NAME"] = lambda_function_name + # replacements["FUNCTION_VERSION"] = "$LATEST" + + # # Load alias CR + # resource_data = load_lambda_resource( + # "alias", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) + + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # assert cr is not None + # assert k8s.get_resource_exists(ref) + + # time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # lambda_validator = LambdaValidator(lambda_client) + # # Check alias exists + # assert lambda_validator.alias_exists(resource_name, lambda_function_name) + + # cr = k8s.wait_resource_consumed_by_controller(ref) - # Update cr - cr["spec"]["description"] = "" + # # Update cr + # cr["spec"]["description"] = "" - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - # Check alias description - alias = lambda_validator.get_alias(resource_name, lambda_function_name) - assert alias is not None - assert alias["Description"] == "" + # # Check alias description + # alias = lambda_validator.get_alias(resource_name, lambda_function_name) + # assert alias is not None + # assert alias["Description"] == "" - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted - time.sleep(DELETE_WAIT_AFTER_SECONDS) + # time.sleep(DELETE_WAIT_AFTER_SECONDS) - # Check alias doesn't exist - assert not lambda_validator.alias_exists(resource_name, lambda_function_name) + # # Check alias doesn't exist + # assert not lambda_validator.alias_exists(resource_name, lambda_function_name) - @pytest.mark.resource_data({'withNamespace': False}) - def test_smoke_ref(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - function_resource_name = function_resource["metadata"]["name"] + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_smoke_ref(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # function_resource_name = function_resource["metadata"]["name"] - resource_name = random_suffix_name("lambda-alias", 24) + # resource_name = random_suffix_name("lambda-alias", 24) - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["ALIAS_NAME"] = resource_name - replacements["FUNCTION_REF_NAME"] = function_resource_name - replacements["FUNCTION_VERSION"] = "$LATEST" + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["ALIAS_NAME"] = resource_name + # replacements["FUNCTION_REF_NAME"] = function_resource_name + # replacements["FUNCTION_VERSION"] = "$LATEST" - # Load alias CR - resource_data = load_lambda_resource( - "alias-ref", - additional_replacements=replacements, - ) - logging.debug(resource_data) + # # Load alias CR + # resource_data = load_lambda_resource( + # "alias-ref", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) - assert cr is not None - assert k8s.get_resource_exists(ref) + # assert cr is not None + # assert k8s.get_resource_exists(ref) - time.sleep(CREATE_WAIT_AFTER_SECONDS) + # time.sleep(CREATE_WAIT_AFTER_SECONDS) - lambda_validator = LambdaValidator(lambda_client) - # Check alias exists - assert lambda_validator.alias_exists(resource_name, function_resource_name) + # lambda_validator = LambdaValidator(lambda_client) + # # Check alias exists + # assert lambda_validator.alias_exists(resource_name, function_resource_name) - cr = k8s.wait_resource_consumed_by_controller(ref) + # cr = k8s.wait_resource_consumed_by_controller(ref) - # Update cr - cr["spec"]["description"] = "" + # # Update cr + # cr["spec"]["description"] = "" - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - # Check alias description - alias = lambda_validator.get_alias(resource_name, function_resource_name) - assert alias is not None - assert alias["Description"] == "" + # # Check alias description + # alias = lambda_validator.get_alias(resource_name, function_resource_name) + # assert alias is not None + # assert alias["Description"] == "" - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted - time.sleep(DELETE_WAIT_AFTER_SECONDS) + # time.sleep(DELETE_WAIT_AFTER_SECONDS) - # Check alias doesn't exist - assert not lambda_validator.alias_exists(resource_name, function_resource_name) + # # Check alias doesn't exist + # assert not lambda_validator.alias_exists(resource_name, function_resource_name) @pytest.mark.resource_data({'withNamespace': True}) def test_smoke_namespace_ref(self, lambda_client, lambda_function): @@ -253,8 +255,6 @@ def test_smoke_namespace_ref(self, lambda_client, lambda_function): lambda_validator = LambdaValidator(lambda_client) # Check alias exists - log.error(lambda_validator.function_exists(function_resource_name)) - assert lambda_validator.alias_exists(resource_name, function_resource_name) cr = k8s.wait_resource_consumed_by_controller(ref) @@ -280,163 +280,163 @@ def test_smoke_namespace_ref(self, lambda_client, lambda_function): # Check alias doesn't exist assert not lambda_validator.alias_exists(resource_name, function_resource_name) - @pytest.mark.resource_data({'withNamespace': False}) - def test_provisioned_concurrency_config(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_provisioned_concurrency_config(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # lambda_function_name = function_resource["spec"]["name"] - resource_name = random_suffix_name("lambda-alias", 24) + # resource_name = random_suffix_name("lambda-alias", 24) - resources = get_bootstrap_resources() - logging.debug(resources) + # resources = get_bootstrap_resources() + # logging.debug(resources) - resp = lambda_client.publish_version( - FunctionName = lambda_function_name - ) - version = resp['Version'] + # resp = lambda_client.publish_version( + # FunctionName = lambda_function_name + # ) + # version = resp['Version'] - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["ALIAS_NAME"] = resource_name - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["FUNCTION_VERSION"] = f"\'{version}\'" - replacements["PROVISIONED_CONCURRENT_EXECUTIONS"] = "1" + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["ALIAS_NAME"] = resource_name + # replacements["FUNCTION_NAME"] = lambda_function_name + # replacements["FUNCTION_VERSION"] = f"\'{version}\'" + # replacements["PROVISIONED_CONCURRENT_EXECUTIONS"] = "1" - # Load alias CR - resource_data = load_lambda_resource( - "alias_provisioned_concurrency", - additional_replacements=replacements, - ) - logging.debug(resource_data) + # # Load alias CR + # resource_data = load_lambda_resource( + # "alias_provisioned_concurrency", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) - assert cr is not None - assert k8s.get_resource_exists(ref) + # assert cr is not None + # assert k8s.get_resource_exists(ref) - time.sleep(CREATE_WAIT_AFTER_SECONDS) + # time.sleep(CREATE_WAIT_AFTER_SECONDS) - cr = k8s.wait_resource_consumed_by_controller(ref) + # cr = k8s.wait_resource_consumed_by_controller(ref) - lambda_validator = LambdaValidator(lambda_client) + # lambda_validator = LambdaValidator(lambda_client) - # Check alias exists - assert lambda_validator.alias_exists(resource_name, lambda_function_name) + # # Check alias exists + # assert lambda_validator.alias_exists(resource_name, lambda_function_name) - # Update provisioned_concurrency - cr["spec"]["provisionedConcurrencyConfig"]["provisionedConcurrentExecutions"] = 2 + # # Update provisioned_concurrency + # cr["spec"]["provisionedConcurrencyConfig"]["provisionedConcurrentExecutions"] = 2 - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - #Check provisioned_concurrency_config update fields - provisioned_concurrency_config = lambda_validator.get_provisioned_concurrency_config(lambda_function_name,resource_name) - assert provisioned_concurrency_config["RequestedProvisionedConcurrentExecutions"] == 2 + # #Check provisioned_concurrency_config update fields + # provisioned_concurrency_config = lambda_validator.get_provisioned_concurrency_config(lambda_function_name,resource_name) + # assert provisioned_concurrency_config["RequestedProvisionedConcurrentExecutions"] == 2 - # Delete provisioned_concurrency from alias - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["provisionedConcurrencyConfig"] = None + # # Delete provisioned_concurrency from alias + # cr = k8s.wait_resource_consumed_by_controller(ref) + # cr["spec"]["provisionedConcurrencyConfig"] = None - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - #Check provisioned_concurrency_config is deleted - assert not lambda_validator.get_provisioned_concurrency_config(lambda_function_name, resource_name) + # #Check provisioned_concurrency_config is deleted + # assert not lambda_validator.get_provisioned_concurrency_config(lambda_function_name, resource_name) - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted - time.sleep(DELETE_WAIT_AFTER_SECONDS) + # time.sleep(DELETE_WAIT_AFTER_SECONDS) - # Check alias doesn't exist - assert not lambda_validator.alias_exists(resource_name, lambda_function_name) + # # Check alias doesn't exist + # assert not lambda_validator.alias_exists(resource_name, lambda_function_name) - @pytest.mark.resource_data({'withNamespace': False}) - def test_function_event_invoke_config(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-alias", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["ALIAS_NAME"] = resource_name - replacements["FUNCTION_VERSION"] = "$LATEST" - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["MAXIMUM_EVENT_AGE_IN_SECONDS"] = "100" - replacements["MAXIMUM_RETRY_ATTEMPTS"] = "1" - replacements["ON_SUCCESS_DESTINATION"] = resources.EICQueueOnSuccess.arn - replacements["ON_FAILURE_DESTINATION"] = resources.EICQueueOnFailure.arn - - # Load alias CR - resource_data = load_lambda_resource( - "alias_event_invoke_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check alias exists - assert lambda_validator.alias_exists(resource_name, lambda_function_name) + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_function_event_invoke_config(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # lambda_function_name = function_resource["spec"]["name"] + + # resource_name = random_suffix_name("lambda-alias", 24) + + # resources = get_bootstrap_resources() + # logging.debug(resources) + + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["ALIAS_NAME"] = resource_name + # replacements["FUNCTION_VERSION"] = "$LATEST" + # replacements["FUNCTION_NAME"] = lambda_function_name + # replacements["MAXIMUM_EVENT_AGE_IN_SECONDS"] = "100" + # replacements["MAXIMUM_RETRY_ATTEMPTS"] = "1" + # replacements["ON_SUCCESS_DESTINATION"] = resources.EICQueueOnSuccess.arn + # replacements["ON_FAILURE_DESTINATION"] = resources.EICQueueOnFailure.arn + + # # Load alias CR + # resource_data = load_lambda_resource( + # "alias_event_invoke_config", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) + + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # assert cr is not None + # assert k8s.get_resource_exists(ref) + + # time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # lambda_validator = LambdaValidator(lambda_client) + + # # Check alias exists + # assert lambda_validator.alias_exists(resource_name, lambda_function_name) - # Update cr - cr["spec"]["functionEventInvokeConfig"]["maximumEventAgeInSeconds"] = 200 - cr["spec"]["functionEventInvokeConfig"]["maximumRetryAttempts"] = 2 + # # Update cr + # cr["spec"]["functionEventInvokeConfig"]["maximumEventAgeInSeconds"] = 200 + # cr["spec"]["functionEventInvokeConfig"]["maximumRetryAttempts"] = 2 - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - #Check function_event_invoke_config update fields - function_event_invoke_config = lambda_validator.get_function_event_invoke_config_alias(lambda_function_name,resource_name) - assert function_event_invoke_config["MaximumEventAgeInSeconds"] == 200 - assert function_event_invoke_config["MaximumRetryAttempts"] == 2 + # #Check function_event_invoke_config update fields + # function_event_invoke_config = lambda_validator.get_function_event_invoke_config_alias(lambda_function_name,resource_name) + # assert function_event_invoke_config["MaximumEventAgeInSeconds"] == 200 + # assert function_event_invoke_config["MaximumRetryAttempts"] == 2 - # Delete FunctionEventInvokeConfig - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["functionEventInvokeConfig"] = None + # # Delete FunctionEventInvokeConfig + # cr = k8s.wait_resource_consumed_by_controller(ref) + # cr["spec"]["functionEventInvokeConfig"] = None - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) - # Check if FunctionEventInvokeConfig is deleted - assert not lambda_validator.get_function_event_invoke_config_alias(lambda_function_name,resource_name) + # # Check if FunctionEventInvokeConfig is deleted + # assert not lambda_validator.get_function_event_invoke_config_alias(lambda_function_name,resource_name) - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted - time.sleep(DELETE_WAIT_AFTER_SECONDS) + # time.sleep(DELETE_WAIT_AFTER_SECONDS) - # Check alias doesn't exist - assert not lambda_validator.alias_exists(resource_name, lambda_function_name) \ No newline at end of file + # # Check alias doesn't exist + # assert not lambda_validator.alias_exists(resource_name, lambda_function_name) \ No newline at end of file diff --git a/test/e2e/tests/test_code_signing_config.py b/test/e2e/tests/test_code_signing_config.py deleted file mode 100644 index bf83a77c..00000000 --- a/test/e2e/tests/test_code_signing_config.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may -# not use this file except in compliance with the License. A copy of the -# License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -"""Integration tests for the Lambda code signing config API. -""" - -import pytest -import time -import logging - -from acktest.resources import random_suffix_name -from acktest.aws.identity import get_region -from acktest.k8s import resource as k8s - -from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_lambda_resource -from e2e.replacement_values import REPLACEMENT_VALUES -from e2e.bootstrap_resources import get_bootstrap_resources -from e2e.tests.helper import LambdaValidator - -RESOURCE_PLURAL = "codesigningconfigs" - -CREATE_WAIT_AFTER_SECONDS = 10 -UPDATE_WAIT_AFTER_SECONDS = 10 -DELETE_WAIT_AFTER_SECONDS = 10 - -@service_marker -@pytest.mark.canary -class TestCodeSigningConfig: - def test_smoke(self, lambda_client): - resource_name = random_suffix_name("lambda-csc", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["CODE_SIGNING_CONFIG_NAME"] = resource_name - replacements["SIGNING_PROFILE_VERSION_ARN"] = resources.SigningProfile.signing_profile_arn - - # Load Lambda CR - resource_data = load_lambda_resource( - "code_signing_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - codeSigningConfigARN = cr['status']['ackResourceMetadata']['arn'] - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda code signing config exists - assert lambda_validator.code_signing_config_exists(codeSigningConfigARN) - - # Update cr - cr["spec"]["description"] = "new description" - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check code signing config description - csc = lambda_validator.get_code_signing_config(codeSigningConfigARN) - assert csc is not None - assert csc["Description"] == "new description" - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - # Check Lambda code signing config doesn't exist - assert not lambda_validator.code_signing_config_exists(codeSigningConfigARN) diff --git a/test/e2e/tests/test_event_source_mapping.py b/test/e2e/tests/test_event_source_mapping.py index e7e190fd..f86ff04f 100644 --- a/test/e2e/tests/test_event_source_mapping.py +++ b/test/e2e/tests/test_event_source_mapping.py @@ -33,26 +33,13 @@ CREATE_WAIT_AFTER_SECONDS = 20 UPDATE_WAIT_AFTER_SECONDS = 20 DELETE_WAIT_AFTER_SECONDS = 20 -TESTING_NAMESPACE = "custom_namespace" +TESTING_NAMESPACE = random_suffix_name("testing-esm-namespace", 28) log = logging.getLogger() - -@pytest.fixture(scope="module") -def referred_function_name(): - return random_suffix_name("lambda-function", 24) - -@pytest.fixture(scope="module") -def stupid_function(request): - marker = request.node.get_closest_marker("resource_data") - if marker is None: - return "SAD" - log.error("THIS IS A STUPID FUNCTION") - return "happy" - -@pytest.fixture(scope="module") -def lambda_function(request, referred_function_name): - resource_name = referred_function_name +@pytest.fixture(scope="function") +def lambda_function(request): + resource_name = random_suffix_name("lambda-function", 24) resources = get_bootstrap_resources() marker = request.node.get_closest_marker("resource_data") @@ -60,29 +47,27 @@ def lambda_function(request, referred_function_name): namespace = "default" replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.ESMRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "10" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - log.error(request) - log.error(request.node) - log.error(request.node.get_closest_marker("resource_data")) if marker is not None: data = marker.args[0] - log.error(data) if 'withNamespace' in data and data['withNamespace']: - k8s.create_k8s_namespace( - namespace - ) filename = "function_namespace" namespace = TESTING_NAMESPACE replacements['FUNCTION_NAMESPACE'] = namespace - log.error(replacements) - log.error(filename) + k8s.create_k8s_namespace( + namespace + ) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + time.sleep(CREATE_WAIT_AFTER_SECONDS) + + replacements["FUNCTION_NAME"] = resource_name + replacements["BUCKET_NAME"] = resources.FunctionsBucket.name + replacements["LAMBDA_ROLE"] = resources.ESMRole.arn + replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP + replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "10" + replacements["CODE_SIGNING_CONFIG_ARN"] = "" + replacements["AWS_REGION"] = get_region() # Load function CR resource_data = load_lambda_resource( @@ -111,194 +96,193 @@ def lambda_function(request, referred_function_name): _, deleted = k8s.delete_custom_resource(function_reference) assert deleted + @service_marker @pytest.mark.canary class TestEventSourceMapping: - @pytest.mark.resource_data({'withNamespace': False}) - def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-esm", 24) - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name - replacements["BATCH_SIZE"] = "10" - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn - replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" - - # Load ESM CR - resource_data = load_lambda_resource( - "event_source_mapping_sqs", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - esm_uuid = cr['status']['uuid'] - - lambda_validator = LambdaValidator(lambda_client) - # Check ESM exists - assert lambda_validator.event_source_mapping_exists(esm_uuid) - - # Update cr - cr["spec"]["batchSize"] = 20 - cr["spec"]["filterCriteria"] = { - "filters": [ - { - "pattern": "{\"controller-version\":[\"v1\"]}" - }, - ] - } - cr["spec"]["scalingConfig"] = {"maximumConcurrency": 4} - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check ESM batch size & filters - esm = lambda_validator.get_event_source_mapping(esm_uuid) - assert esm is not None - assert esm["BatchSize"] == 20 - assert esm["FilterCriteria"]["Filters"] == [ - { - "Pattern": "{\"controller-version\":[\"v1\"]}" - }, - ] - assert esm["ScalingConfig"]["MaximumConcurrency"] == 4 - - - # Delete the filterCriteria field - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["filterCriteria"] = None - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check filters have been deleted - esm = lambda_validator.get_event_source_mapping(esm_uuid) - assert esm is not None - assert "FilterCriteria" not in esm - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check ESM doesn't exist - assert not lambda_validator.event_source_mapping_exists(esm_uuid) + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_smoke_sqs_queue_stream(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # lambda_function_name = function_resource["spec"]["name"] + + # resource_name = random_suffix_name("lambda-esm", 24) + # resources = get_bootstrap_resources() + + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name + # replacements["BATCH_SIZE"] = "10" + # replacements["FUNCTION_NAME"] = lambda_function_name + # replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn + # replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" + + # # Load ESM CR + # resource_data = load_lambda_resource( + # "event_source_mapping_sqs", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) + + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # assert cr is not None + # assert k8s.get_resource_exists(ref) + + # time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # esm_uuid = cr['status']['uuid'] + + # lambda_validator = LambdaValidator(lambda_client) + # # Check ESM exists + # assert lambda_validator.event_source_mapping_exists(esm_uuid) + + # # Update cr + # cr["spec"]["batchSize"] = 20 + # cr["spec"]["filterCriteria"] = { + # "filters": [ + # { + # "pattern": "{\"controller-version\":[\"v1\"]}" + # }, + # ] + # } + # cr["spec"]["scalingConfig"] = {"maximumConcurrency": 4} + + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # # Check ESM batch size & filters + # esm = lambda_validator.get_event_source_mapping(esm_uuid) + # assert esm is not None + # assert esm["BatchSize"] == 20 + # assert esm["FilterCriteria"]["Filters"] == [ + # { + # "Pattern": "{\"controller-version\":[\"v1\"]}" + # }, + # ] + # assert esm["ScalingConfig"]["MaximumConcurrency"] == 4 + + + # # Delete the filterCriteria field + # cr = k8s.wait_resource_consumed_by_controller(ref) + # cr["spec"]["filterCriteria"] = None + + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # # Check filters have been deleted + # esm = lambda_validator.get_event_source_mapping(esm_uuid) + # assert esm is not None + # assert "FilterCriteria" not in esm + + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted + + # time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # # Check ESM doesn't exist + # assert not lambda_validator.event_source_mapping_exists(esm_uuid) - @pytest.mark.resource_data({'withNamespace': False}) - def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - function_resource_name = function_resource["metadata"]["name"] - - resource_name = random_suffix_name("lambda-esm", 24) - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name - replacements["BATCH_SIZE"] = "10" - replacements["FUNCTION_REF_NAME"] = function_resource_name - replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn - replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" - - # Load ESM CR - resource_data = load_lambda_resource( - "event_source_mapping_sqs_ref", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - esm_uuid = cr['status']['uuid'] - - lambda_validator = LambdaValidator(lambda_client) - # Check ESM exists - assert lambda_validator.event_source_mapping_exists(esm_uuid) - - # Update cr - cr["spec"]["batchSize"] = 20 - cr["spec"]["filterCriteria"] = { - "filters": [ - { - "pattern": "{\"controller-version\":[\"v1\"]}" - }, - ] - } - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check ESM batch size & filters - esm = lambda_validator.get_event_source_mapping(esm_uuid) - assert esm is not None - assert esm["BatchSize"] == 20 - assert esm["FilterCriteria"]["Filters"] == [ - { - "Pattern": "{\"controller-version\":[\"v1\"]}" - }, - ] - - # Delete the filterCriteria field - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["filterCriteria"] = None - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check filters have been deleted - esm = lambda_validator.get_event_source_mapping(esm_uuid) - assert esm is not None - assert "FilterCriteria" not in esm - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check ESM doesn't exist - assert not lambda_validator.event_source_mapping_exists(esm_uuid) + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_smoke_sqs_queue_stream_ref(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # function_resource_name = function_resource["metadata"]["name"] + + # resource_name = random_suffix_name("lambda-esm", 24) + # resources = get_bootstrap_resources() + + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name + # replacements["BATCH_SIZE"] = "10" + # replacements["FUNCTION_REF_NAME"] = function_resource_name + # replacements["EVENT_SOURCE_ARN"] = resources.ESMQueue.arn + # replacements["MAXIMUM_BATCHING_WINDOW_IN_SECONDS"] = "1" + + # # Load ESM CR + # resource_data = load_lambda_resource( + # "event_source_mapping_sqs_ref", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) + + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # assert cr is not None + # assert k8s.get_resource_exists(ref) + + # time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # esm_uuid = cr['status']['uuid'] + + # lambda_validator = LambdaValidator(lambda_client) + # # Check ESM exists + # assert lambda_validator.event_source_mapping_exists(esm_uuid) + + # # Update cr + # cr["spec"]["batchSize"] = 20 + # cr["spec"]["filterCriteria"] = { + # "filters": [ + # { + # "pattern": "{\"controller-version\":[\"v1\"]}" + # }, + # ] + # } + + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # # Check ESM batch size & filters + # esm = lambda_validator.get_event_source_mapping(esm_uuid) + # assert esm is not None + # assert esm["BatchSize"] == 20 + # assert esm["FilterCriteria"]["Filters"] == [ + # { + # "Pattern": "{\"controller-version\":[\"v1\"]}" + # }, + # ] + + # # Delete the filterCriteria field + # cr = k8s.wait_resource_consumed_by_controller(ref) + # cr["spec"]["filterCriteria"] = None + + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # # Check filters have been deleted + # esm = lambda_validator.get_event_source_mapping(esm_uuid) + # assert esm is not None + # assert "FilterCriteria" not in esm + + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted + + # time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # # Check ESM doesn't exist + # assert not lambda_validator.event_source_mapping_exists(esm_uuid) @pytest.mark.resource_data({'withNamespace': True}) - def test_smoke_sqs_queue_stream_namespace_ref(self, lambda_client, lambda_function, stupid_function): + def test_smoke_sqs_queue_stream_namespace_ref(self, lambda_client, lambda_function): (_, function_resource) = lambda_function function_resource_name = function_resource["metadata"]["name"] - something = stupid_function - log.error(something) resource_name = random_suffix_name("lambda-esm", 24) resources = get_bootstrap_resources() @@ -330,11 +314,9 @@ def test_smoke_sqs_queue_stream_namespace_ref(self, lambda_client, lambda_functi assert cr is not None assert k8s.get_resource_exists(ref) - time.sleep(CREATE_WAIT_AFTER_SECONDS) - time.sleep(CREATE_WAIT_AFTER_SECONDS) time.sleep(CREATE_WAIT_AFTER_SECONDS) - log.error(cr['status']) + logging.error("THISISSOMETHING "+ cr['status']) esm_uuid = cr['status']['uuid'] @@ -388,72 +370,72 @@ def test_smoke_sqs_queue_stream_namespace_ref(self, lambda_client, lambda_functi # Check ESM doesn't exist assert not lambda_validator.event_source_mapping_exists(esm_uuid) - @pytest.mark.resource_data({'withNamespace': False}) - def test_smoke_dynamodb_table_stream(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-esm", 24) - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name - replacements["BATCH_SIZE"] = "10" - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["EVENT_SOURCE_ARN"] = resources.ESMTable.latest_stream_arn - replacements["STARTING_POSITION"] = "LATEST" - replacements["MAXIMUM_RETRY_ATTEMPTS"] = "-1" - - # Load ESM CR - resource_data = load_lambda_resource( - "event_source_mapping_dynamodb", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - esm_uuid = cr['status']['uuid'] - - lambda_validator = LambdaValidator(lambda_client) - # Check ESM exists - assert lambda_validator.event_source_mapping_exists(esm_uuid) - - # Update cr - cr["spec"]["maximumRetryAttempts"] = 3 - cr["spec"]["destinationConfig"] = { - 'onFailure': { - 'destination': resources.ESMQueue.arn, - } - } - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check ESM maximum retry attempts - esm = lambda_validator.get_event_source_mapping(esm_uuid) - assert esm is not None - logging.info(esm) - assert esm["MaximumRetryAttempts"] == 3 - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check ESM doesn't exist - assert not lambda_validator.event_source_mapping_exists(esm_uuid) \ No newline at end of file + # @pytest.mark.resource_data({'withNamespace': False}) + # def test_smoke_dynamodb_table_stream(self, lambda_client, lambda_function): + # (_, function_resource) = lambda_function + # lambda_function_name = function_resource["spec"]["name"] + + # resource_name = random_suffix_name("lambda-esm", 24) + # resources = get_bootstrap_resources() + + # replacements = REPLACEMENT_VALUES.copy() + # replacements["AWS_REGION"] = get_region() + # replacements["EVENT_SOURCE_MAPPING_NAME"] = resource_name + # replacements["BATCH_SIZE"] = "10" + # replacements["FUNCTION_NAME"] = lambda_function_name + # replacements["EVENT_SOURCE_ARN"] = resources.ESMTable.latest_stream_arn + # replacements["STARTING_POSITION"] = "LATEST" + # replacements["MAXIMUM_RETRY_ATTEMPTS"] = "-1" + + # # Load ESM CR + # resource_data = load_lambda_resource( + # "event_source_mapping_dynamodb", + # additional_replacements=replacements, + # ) + # logging.debug(resource_data) + + # # Create k8s resource + # ref = k8s.CustomResourceReference( + # CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, + # resource_name, namespace="default", + # ) + # k8s.create_custom_resource(ref, resource_data) + # cr = k8s.wait_resource_consumed_by_controller(ref) + + # assert cr is not None + # assert k8s.get_resource_exists(ref) + + # time.sleep(CREATE_WAIT_AFTER_SECONDS) + + # esm_uuid = cr['status']['uuid'] + + # lambda_validator = LambdaValidator(lambda_client) + # # Check ESM exists + # assert lambda_validator.event_source_mapping_exists(esm_uuid) + + # # Update cr + # cr["spec"]["maximumRetryAttempts"] = 3 + # cr["spec"]["destinationConfig"] = { + # 'onFailure': { + # 'destination': resources.ESMQueue.arn, + # } + # } + + # # Patch k8s resource + # k8s.patch_custom_resource(ref, cr) + # time.sleep(UPDATE_WAIT_AFTER_SECONDS) + + # # Check ESM maximum retry attempts + # esm = lambda_validator.get_event_source_mapping(esm_uuid) + # assert esm is not None + # logging.info(esm) + # assert esm["MaximumRetryAttempts"] == 3 + + # # Delete k8s resource + # _, deleted = k8s.delete_custom_resource(ref) + # assert deleted + + # time.sleep(DELETE_WAIT_AFTER_SECONDS) + + # # Check ESM doesn't exist + # assert not lambda_validator.event_source_mapping_exists(esm_uuid) \ No newline at end of file diff --git a/test/e2e/tests/test_function.py b/test/e2e/tests/test_function.py deleted file mode 100644 index 92390ab6..00000000 --- a/test/e2e/tests/test_function.py +++ /dev/null @@ -1,1039 +0,0 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may -# not use this file except in compliance with the License. A copy of the -# License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -"""Integration tests for the Lambda function API. -""" - -import pytest -import time -import logging -import hashlib -import base64 - -from acktest import tags -from acktest.resources import random_suffix_name -from acktest.aws.identity import get_region, get_account_id -from acktest.k8s import resource as k8s - -from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_lambda_resource -from e2e.replacement_values import REPLACEMENT_VALUES -from e2e.bootstrap_resources import get_bootstrap_resources -from e2e.service_bootstrap import LAMBDA_FUNCTION_FILE_ZIP, LAMBDA_FUNCTION_FILE_PATH_ZIP -from e2e.service_bootstrap import LAMBDA_FUNCTION_UPDATED_FILE_ZIP, LAMBDA_FUNCTION_UPDATED_FILE_PATH_ZIP -from e2e.tests.helper import LambdaValidator - -RESOURCE_PLURAL = "functions" - -CREATE_WAIT_AFTER_SECONDS = 30 -UPDATE_WAIT_AFTER_SECONDS = 30 -DELETE_WAIT_AFTER_SECONDS = 30 - -def get_testing_image_url(): - aws_region = get_region() - account_id = get_account_id() - return f"{account_id}.dkr.ecr.{aws_region}.amazonaws.com/ack-e2e-testing-lambda-controller:v1" - -@pytest.fixture(scope="module") -def code_signing_config(): - resource_name = random_suffix_name("lambda-csc", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["CODE_SIGNING_CONFIG_NAME"] = resource_name - replacements["SIGNING_PROFILE_VERSION_ARN"] = resources.SigningProfile.signing_profile_arn - - # Load Lambda CR - resource_data = load_lambda_resource( - "code_signing_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, "codesigningconfigs", - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - yield (ref, cr) - - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - -@service_marker -@pytest.mark.canary -class TestFunction: - - def test_smoke(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Assert that the original code.s3Bucket and code.s3Key is still part of - # the function's CR - assert cr["spec"]["code"]["s3Bucket"] == resources.FunctionsBucket.name - assert cr["spec"]["code"]["s3Key"] == LAMBDA_FUNCTION_FILE_ZIP - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - update_tags = { - "v1": "k1", - "v2": "k2", - "v3": "k3", - } - cr["spec"]["description"] = "Updated description" - cr["spec"]["timeout"] = 10 - cr["spec"]["tags"] = update_tags - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check function updated fields - function = lambda_validator.get_function(resource_name) - assert function is not None - assert function["Configuration"]["Description"] == "Updated description" - assert function["Configuration"]["Timeout"] == 10 - - function_tags = function["Tags"] - tags.assert_ack_system_tags( - tags=function_tags, - ) - tags.assert_equal_without_ack_tags( - expected=update_tags, - actual=function_tags, - ) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_reserved_concurrent_executions(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "2" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - reservedConcurrentExecutions = lambda_validator.get_function_concurrency(resource_name) - assert reservedConcurrentExecutions == 2 - - # Update cr - cr["spec"]["reservedConcurrentExecutions"] = 0 - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check function updated fields - reservedConcurrentExecutions = lambda_validator.get_function_concurrency(resource_name) - assert reservedConcurrentExecutions == 0 - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_code_signing_config(self, lambda_client, code_signing_config): - (_, csc_resource) = code_signing_config - code_signing_config_arn = csc_resource["status"]["ackResourceMetadata"]["arn"] - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "2" - replacements["CODE_SIGNING_CONFIG_ARN"] = code_signing_config_arn - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Check function code signing config is correct - function_csc_arn = lambda_validator.get_function_code_signing_config(resource_name) - assert function_csc_arn == code_signing_config_arn - - # Delete function code signing config - cr["spec"]["codeSigningConfigARN"] = "" - k8s.patch_custom_resource(ref, cr) - - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - function_csc_arn = lambda_validator.get_function_code_signing_config(resource_name) - assert function_csc_arn is None - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_package_type_image(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["AWS_REGION"] = get_region() - replacements["IMAGE_URL"] = get_testing_image_url() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_package_type_image", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - cr["spec"]["timeout"] = 10 - cr["spec"]["ephemeralStorage"] = { "size" : 1024 } - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check function updated fields - function = lambda_validator.get_function(resource_name) - assert function["Configuration"]["Timeout"] == 10 - assert function["Configuration"]["EphemeralStorage"]["Size"] == 1024 - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_package_type_image_with_signing_config(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["AWS_REGION"] = get_region() - replacements["IMAGE_URL"] = get_testing_image_url() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_package_type_image", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Add signing configuration - cr["spec"]["codeSigningConfigARN"] = "random-csc" - k8s.patch_custom_resource(ref, cr) - - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - # assert condition - assert k8s.assert_condition_state_message( - ref, - "ACK.Terminal", - "True", - "cannot set function code signing config when package type is Image", - ) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - # Remove signing configuration - cr["spec"]["codeSigningConfigARN"] = "" - k8s.patch_custom_resource(ref, cr) - - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_is_synced(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS*3) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - assert cr["status"]["state"] == "Active" - - function = lambda_validator.get_function(resource_name) - assert function is not None - assert function["Configuration"]["State"] == "Active" - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_snapstart(self, lambda_client): - resource_name = random_suffix_name("functionsnapstart", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_snapstart", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["snapStart"] = { "applyOn" : "PublishedVersions" } - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_snapstart update fields - function = lambda_validator.get_function(resource_name) - assert function["Configuration"]["SnapStart"]["ApplyOn"] == "PublishedVersions" - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_architecture(self, lambda_client): - resource_name = random_suffix_name("functionsarchitecture", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - replacements["ARCHITECTURES"] = 'x86_64' - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_architectures", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["architectures"] = ['arm64'] - cr["spec"]["code"]["s3Bucket"] = resources.FunctionsBucket.name - cr["spec"]["code"]["s3Key"] = LAMBDA_FUNCTION_FILE_ZIP - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_snapstart update fields - function = lambda_validator.get_function(resource_name) - assert function["Configuration"]["Architectures"] == ['arm64'] - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_features(self, lambda_client): - resource_name = random_suffix_name("functionfeatures", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.EICRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["AWS_REGION"] = get_region() - replacements["DEAD_LETTER_CONFIG_TARGET_ARN"] = resources.EICQueueOnSuccess.arn - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_features", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["deadLetterConfig"]["targetARN"] = resources.EICQueueOnFailure.arn - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_snapstart update fields - function = lambda_validator.get_function(resource_name) - assert function["Configuration"]["DeadLetterConfig"]["TargetArn"] == resources.EICQueueOnFailure.arn - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_runtime(self, lambda_client): - resource_name = random_suffix_name("function", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load Lambda CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["runtime"] = "java21" - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_snapstart update fields - function = lambda_validator.get_function(resource_name) - assert function["Configuration"]["Runtime"] == "java21" - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_layers(self, lambda_client): - resource_name = random_suffix_name("functionlayers", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.EICRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["AWS_REGION"] = get_region() - replacements["LAYERS"] = "arn:aws:lambda:us-west-2:336392948345:layer:AWSSDKPandas-Python310:14" - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_layers", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - layers_list = ["arn:aws:lambda:us-west-2:017000801446:layer:AWSLambdaPowertoolsPythonV2:68", "arn:aws:lambda:us-west-2:580247275435:layer:LambdaInsightsExtension:52"] - cr["spec"]["layers"] = layers_list - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_snapstart update fields - function = lambda_validator.get_function(resource_name) - for i in range(len(function["Configuration"]["Layers"])) : - assert function["Configuration"]["Layers"][i]["Arn"] == layers_list[i] - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_event_invoke_config(self, lambda_client): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.EICRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["AWS_REGION"] = get_region() - replacements["MAXIMUM_EVENT_AGE_IN_SECONDS"] = "100" - replacements["MAXIMUM_RETRY_ATTEMPTS"] = "1" - replacements["ON_SUCCESS_DESTINATION"] = resources.EICQueueOnSuccess.arn - replacements["ON_FAILURE_DESTINATION"] = resources.EICQueueOnFailure.arn - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_event_invoke_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["functionEventInvokeConfig"]["maximumEventAgeInSeconds"] = 200 - cr["spec"]["functionEventInvokeConfig"]["maximumRetryAttempts"] = 2 - - #Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_event_invoke_config update fields - function_event_invoke_config = lambda_validator.get_function_event_invoke_config(resource_name) - assert function_event_invoke_config["MaximumEventAgeInSeconds"] == 200 - assert function_event_invoke_config["MaximumRetryAttempts"] == 2 - - # Delete FunctionEventInvokeConfig - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["functionEventInvokeConfig"] = None - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check if FunctionEventInvokeConfig is deleted - assert not lambda_validator.get_function_event_invoke_config(resource_name) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_code_s3(self, lambda_client): - resource_name = random_suffix_name("functioncodes3", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - archive_1 = open(LAMBDA_FUNCTION_FILE_PATH_ZIP, 'rb') - readFile_1 = archive_1.read() - hash_1 = hashlib.sha256(readFile_1) - binary_hash_1 = hash_1.digest() - base64_hash_1 = base64.b64encode(binary_hash_1).decode('utf-8') - - archive_2 = open(LAMBDA_FUNCTION_UPDATED_FILE_PATH_ZIP, 'rb') - readFile_2 = archive_2.read() - hash_2 = hashlib.sha256(readFile_2) - binary_hash_2 = hash_2.digest() - base64_hash_2 = base64.b64encode(binary_hash_2).decode('utf-8') - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - replacements["ARCHITECTURES"] = 'x86_64' - replacements["HASH"] = base64_hash_1 - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_code_s3", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Assert that the original code.s3Bucket and code.s3Key is still part of - # the function's CR - assert cr["spec"]["code"]["s3Bucket"] == resources.FunctionsBucket.name - assert cr["spec"]["code"]["s3Key"] == LAMBDA_FUNCTION_FILE_ZIP - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["code"]["sha256"] = base64_hash_2 - cr["spec"]["code"]["s3Key"] = LAMBDA_FUNCTION_UPDATED_FILE_ZIP - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check function updated fields - function = lambda_validator.get_function(resource_name) - assert function is not None - assert function["Configuration"]["CodeSha256"] == base64_hash_2 - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) - - def test_function_update_code_and_architecture(self, lambda_client): - resource_name = random_suffix_name("functionupdatecode", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - archive_1 = open(LAMBDA_FUNCTION_FILE_PATH_ZIP, 'rb') - readFile_1 = archive_1.read() - hash_1 = hashlib.sha256(readFile_1) - binary_hash_1 = hash_1.digest() - base64_hash_1 = base64.b64encode(binary_hash_1).decode('utf-8') - - archive_2 = open(LAMBDA_FUNCTION_UPDATED_FILE_PATH_ZIP, 'rb') - readFile_2 = archive_2.read() - hash_2 = hashlib.sha256(readFile_2) - binary_hash_2 = hash_2.digest() - base64_hash_2 = base64.b64encode(binary_hash_2).decode('utf-8') - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "0" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - replacements["ARCHITECTURES"] = 'x86_64' - replacements["HASH"] = base64_hash_1 - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_code_s3", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Assert that the original code.s3Bucket and code.s3Key is still part of - # the function's CR - assert cr["spec"]["code"]["s3Bucket"] == resources.FunctionsBucket.name - assert cr["spec"]["code"]["s3Key"] == LAMBDA_FUNCTION_FILE_ZIP - - # Check Lambda function exists - assert lambda_validator.function_exists(resource_name) - - # Update cr - cr["spec"]["code"]["sha256"] = base64_hash_2 - cr["spec"]["code"]["s3Key"] = LAMBDA_FUNCTION_UPDATED_FILE_ZIP - cr["spec"]["architectures"] = ['arm64'] - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check function updated fields - function = lambda_validator.get_function(resource_name) - assert function is not None - assert function["Configuration"]["CodeSha256"] == base64_hash_2 - assert function["Configuration"]["Architectures"] == ['arm64'] - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check Lambda function doesn't exist - assert not lambda_validator.function_exists(resource_name) \ No newline at end of file diff --git a/test/e2e/tests/test_function_url_config.py b/test/e2e/tests/test_function_url_config.py deleted file mode 100644 index 859a5332..00000000 --- a/test/e2e/tests/test_function_url_config.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may -# not use this file except in compliance with the License. A copy of the -# License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -"""Integration tests for the Lambda FunctionURLConfig API. -""" - -import boto3 -import pytest -import time -import logging -from typing import Dict, Tuple - -from acktest.resources import random_suffix_name -from acktest.aws.identity import get_region, get_account_id -from acktest.k8s import resource as k8s -from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_lambda_resource -from e2e.replacement_values import REPLACEMENT_VALUES -from e2e.bootstrap_resources import get_bootstrap_resources -from e2e.tests.helper import LambdaValidator - -RESOURCE_PLURAL = "functionurlconfigs" - -CREATE_WAIT_AFTER_SECONDS = 30 -UPDATE_WAIT_AFTER_SECONDS = 10 -DELETE_WAIT_AFTER_SECONDS = 10 - -def get_testing_image_url(): - aws_region = get_region() - account_id = get_account_id() - return f"{account_id}.dkr.ecr.{aws_region}.amazonaws.com/ack-e2e-testing-lambda-controller:v1" - -@pytest.fixture(scope="module") -def lambda_client(): - return boto3.client("lambda") - -@pytest.fixture(scope="module") -def lambda_function(): - resource_name = random_suffix_name("lambda-function", 24) - - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["AWS_REGION"] = get_region() - replacements["IMAGE_URL"] = get_testing_image_url() - replacements["LAMBDA_ROLE"] = resources.BasicRole.arn - - # Load Lambda CR - resource_data = load_lambda_resource( - "function_package_type_image", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, "functions", - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - logging.debug(cr) - - yield (ref, cr) - - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - -@service_marker -@pytest.mark.canary -class TestFunctionURLConfig: - def test_smoke(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("functionurlconfig", 24) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_URL_CONFIG_NAME"] = resource_name - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["AUTH_TYPE"] = "NONE" - - # Load FunctionURLConfig CR - resource_data = load_lambda_resource( - "function_url_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig exists - lambda_validator = LambdaValidator(lambda_client) - - # Check function url config exists - function_url_config = lambda_validator.get_function_url_config(lambda_function_name) - assert function_url_config is not None - assert function_url_config["AuthType"] == "NONE" - - cr = k8s.wait_resource_consumed_by_controller(ref) - - # Update cr - cr["spec"]["cors"] = { - "maxAge": 10, - "allowOrigins": ["https://*"], - } - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig MaxAge and AllowOrigins array - function_url_config = lambda_validator.get_function_url_config(lambda_function_name) - assert function_url_config is not None - assert function_url_config["Cors"] is not None - assert function_url_config["Cors"]["MaxAge"] == 10 - assert function_url_config["Cors"]["AllowOrigins"] == ["https://*"] - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig doesn't exist - assert not lambda_validator.function_url_config_exists(lambda_function_name) - - def test_smoke_ref(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - function_resource_name = function_resource["metadata"]["name"] - - resource_name = random_suffix_name("functionurlconfig", 24) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_URL_CONFIG_NAME"] = resource_name - replacements["FUNCTION_REF_NAME"] = function_resource_name - replacements["AUTH_TYPE"] = "NONE" - - # Load FunctionURLConfig CR - resource_data = load_lambda_resource( - "function_url_config_ref", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig exists - lambda_validator = LambdaValidator(lambda_client) - - # Check function url config exists - function_url_config = lambda_validator.get_function_url_config(function_resource_name) - assert function_url_config is not None - assert function_url_config["AuthType"] == "NONE" - - cr = k8s.wait_resource_consumed_by_controller(ref) - - # Update cr - cr["spec"]["cors"] = { - "maxAge": 10, - "allowOrigins": ["https://*"], - } - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig MaxAge and AllowOrigins array - function_url_config = lambda_validator.get_function_url_config(function_resource_name) - assert function_url_config is not None - assert function_url_config["Cors"] is not None - assert function_url_config["Cors"]["MaxAge"] == 10 - assert function_url_config["Cors"]["AllowOrigins"] == ["https://*"] - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check FunctionURLConfig doesn't exist - assert not lambda_validator.function_url_config_exists(function_resource_name) \ No newline at end of file diff --git a/test/e2e/tests/test_layer_version.py b/test/e2e/tests/test_layer_version.py deleted file mode 100644 index 96710183..00000000 --- a/test/e2e/tests/test_layer_version.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may -# not use this file except in compliance with the License. A copy of the -# License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -"""Integration tests for the Lambda layer version API. -""" - -import pytest -import time -import logging - -from acktest.resources import random_suffix_name -from acktest.aws.identity import get_region -from acktest.k8s import resource as k8s - -from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_lambda_resource -from e2e.replacement_values import REPLACEMENT_VALUES -from e2e.bootstrap_resources import get_bootstrap_resources -from e2e.service_bootstrap import LAMBDA_FUNCTION_FILE_ZIP -from e2e.tests.helper import LambdaValidator - -RESOURCE_PLURAL = "layerversions" - -CREATE_WAIT_AFTER_SECONDS = 10 -UPDATE_WAIT_AFTER_SECONDS = 10 -DELETE_WAIT_AFTER_SECONDS = 10 - -@service_marker -@pytest.mark.canary -class TestLayerVersion: - - def test_smoke(self, lambda_client): - resource_name = random_suffix_name("lambda-lv", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["LAYER_VERSION"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - - # Load Lambda CR - resource_data = load_lambda_resource( - "layer_version", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - version_number = cr['status']['versionNumber'] - - # Check layer version exists - assert lambda_validator.layer_version_exists(resource_name, version_number) - - # Update cr - new_description = "new description" - updates = { - "spec": { - "description": new_description - }, - } - - #Patch k8s resource - k8s.patch_custom_resource(ref, updates) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - version_number = cr['status']['versionNumber'] - - #Check layer version description - layer_version = lambda_validator.get_layer_version(resource_name, version_number) - assert layer_version is not None - assert layer_version['Description'] == 'new description' - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - # Check if all versions are deleted - layer_name = cr['spec']['layerName'] - list = lambda_validator.list_layer_versions(layer_name) - assert len(list["LayerVersions"]) == 0 - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check layer version doesn't exist - assert not lambda_validator.layer_version_exists(resource_name, version_number) diff --git a/test/e2e/tests/test_version.py b/test/e2e/tests/test_version.py deleted file mode 100644 index 32d26399..00000000 --- a/test/e2e/tests/test_version.py +++ /dev/null @@ -1,438 +0,0 @@ -# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). You may -# not use this file except in compliance with the License. A copy of the -# License is located at -# -# http://aws.amazon.com/apache2.0/ -# -# or in the "license" file accompanying this file. This file 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. - -"""Integration tests for the Lambda version API. -""" - -import pytest -import time -import logging -import hashlib -import base64 - -from acktest.resources import random_suffix_name -from acktest.aws.identity import get_region -from acktest.k8s import resource as k8s - -from e2e import service_marker, CRD_GROUP, CRD_VERSION, load_lambda_resource -from e2e.replacement_values import REPLACEMENT_VALUES -from e2e.bootstrap_resources import get_bootstrap_resources -from e2e.service_bootstrap import LAMBDA_FUNCTION_FILE_ZIP, LAMBDA_FUNCTION_FILE_PATH_ZIP -from e2e.tests.helper import LambdaValidator - -RESOURCE_PLURAL = "versions" - -CREATE_WAIT_AFTER_SECONDS = 10 -UPDATE_WAIT_AFTER_SECONDS = 10 -DELETE_WAIT_AFTER_SECONDS = 10 - -@pytest.fixture(scope="module") -def lambda_function(): - resource_name = random_suffix_name("lambda-function", 24) - resources = get_bootstrap_resources() - - replacements = REPLACEMENT_VALUES.copy() - replacements["FUNCTION_NAME"] = resource_name - replacements["BUCKET_NAME"] = resources.FunctionsBucket.name - replacements["LAMBDA_ROLE"] = resources.EICRole.arn - replacements["LAMBDA_FILE_NAME"] = LAMBDA_FUNCTION_FILE_ZIP - replacements["RESERVED_CONCURRENT_EXECUTIONS"] = "3" - replacements["CODE_SIGNING_CONFIG_ARN"] = "" - replacements["AWS_REGION"] = get_region() - - # Load function CR - resource_data = load_lambda_resource( - "function", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - function_reference = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, "functions", - resource_name, namespace="default", - ) - - # Create lambda function - k8s.create_custom_resource(function_reference, resource_data) - function_resource = k8s.wait_resource_consumed_by_controller(function_reference) - - assert function_resource is not None - assert k8s.get_resource_exists(function_reference) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - yield (function_reference, function_resource) - - _, deleted = k8s.delete_custom_resource(function_reference) - assert deleted - -@service_marker -@pytest.mark.canary -class TestVersion: - def test_smoke(self, lambda_client, lambda_function): - (function_reference, function_resource) = lambda_function - - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-version", 24) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["VERSION_NAME"] = resource_name - - # Load Lambda CR - resource_data = load_lambda_resource( - "version", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - version_number = cr['status']['version'] - - # Check version exists - assert lambda_validator.version_exists(lambda_function_name, version_number) - - # Updating Function code - update = { - "spec": { - "description": "Updated descriptionsss" - } - } - - # Patch k8s resource for Function - k8s.patch_custom_resource(function_reference,update) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Publishing new version - resource_name_v2 = random_suffix_name("lambda-version", 24) - replacements["VERSION_NAME"] = resource_name_v2 - - resource_data_v2 = load_lambda_resource( - "version", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Creating new Version resource - ref_v2 = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name_v2, namespace="default", - ) - k8s.create_custom_resource(ref_v2, resource_data_v2) - cr_v2 = k8s.wait_resource_consumed_by_controller(ref_v2) - - assert cr_v2 is not None - assert k8s.get_resource_exists(ref_v2) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr_v2 = k8s.wait_resource_consumed_by_controller(ref_v2) - - lambda_validator = LambdaValidator(lambda_client) - - version_number_2 = cr_v2['status']['version'] - - assert version_number_2 == "2" - assert lambda_validator.version_exists(lambda_function_name, version_number_2) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - _, deleted_2 = k8s.delete_custom_resource(ref_v2) - assert deleted_2 is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check function version doesn't exist - assert not lambda_validator.version_exists(lambda_function_name, version_number) - assert not lambda_validator.version_exists(lambda_function_name, version_number_2) - - def test_version_with_revision_hash(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-version", 24) - - archive_1 = open(LAMBDA_FUNCTION_FILE_PATH_ZIP, 'rb') - readFile_1 = archive_1.read() - hash_1 = hashlib.sha256(readFile_1) - binary_hash_1 = hash_1.digest() - base64_hash_1 = base64.b64encode(binary_hash_1).decode('utf-8') - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["VERSION_NAME"] = resource_name - replacements["HASH"] = base64_hash_1 - replacements["REVISION_ID"] = "" - - # Load Lambda CR - resource_data = load_lambda_resource( - "version_with_revision_hash", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - version_number = cr['status']['version'] - - # Check version exists - assert lambda_validator.version_exists(lambda_function_name, version_number) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check function version doesn't exist - assert not lambda_validator.version_exists(lambda_function_name, version_number) - - def test_smoke_ref(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - function_resource_name = function_resource["metadata"]["name"] - - resource_name = random_suffix_name("lambda-version", 24) - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["VERSION_NAME"] = resource_name - replacements["FUNCTION_REF_NAME"] = function_resource_name - - # Load alias CR - resource_data = load_lambda_resource( - "version_ref", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - # Check version exists - version_number = cr['status']['version'] - assert lambda_validator.version_exists(function_resource_name, version_number) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted is True - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check alias doesn't exist - assert not lambda_validator.version_exists(function_resource_name, version_number) - - def test_function_event_invoke_config(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-version", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["VERSION_NAME"] = resource_name - replacements["MAXIMUM_EVENT_AGE_IN_SECONDS"] = "100" - replacements["MAXIMUM_RETRY_ATTEMPTS"] = "1" - replacements["ON_SUCCESS_DESTINATION"] = resources.EICQueueOnSuccess.arn - replacements["ON_FAILURE_DESTINATION"] = resources.EICQueueOnFailure.arn - - # Load version CR - resource_data = load_lambda_resource( - "version_event_invoke_config", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - version_number = cr['status']['version'] - - # Check version exists - assert lambda_validator.version_exists(lambda_function_name, version_number) - - # Update cr - cr["spec"]["functionEventInvokeConfig"]["maximumEventAgeInSeconds"] = 200 - cr["spec"]["functionEventInvokeConfig"]["maximumRetryAttempts"] = 2 - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check function_event_invoke_config update fields - function_event_invoke_config = lambda_validator.get_function_event_invoke_config_alias(lambda_function_name, version_number) - assert function_event_invoke_config["MaximumEventAgeInSeconds"] == 200 - assert function_event_invoke_config["MaximumRetryAttempts"] == 2 - - # Delete FunctionEventInvokeConfig - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["functionEventInvokeConfig"] = None - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - # Check if FunctionEventInvokeConfig is deleted - assert not lambda_validator.get_function_event_invoke_config_alias(lambda_function_name, version_number) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check version doesn't exist - assert not lambda_validator.version_exists(lambda_function_name, version_number) - - def test_provisioned_concurrency_config(self, lambda_client, lambda_function): - (_, function_resource) = lambda_function - lambda_function_name = function_resource["spec"]["name"] - - resource_name = random_suffix_name("lambda-version", 24) - - resources = get_bootstrap_resources() - logging.debug(resources) - - replacements = REPLACEMENT_VALUES.copy() - replacements["AWS_REGION"] = get_region() - replacements["FUNCTION_NAME"] = lambda_function_name - replacements["VERSION_NAME"] = resource_name - replacements["PROVISIONED_CONCURRENT_EXECUTIONS"] = "1" - - # Load version CR - resource_data = load_lambda_resource( - "version_provisioned_concurrency", - additional_replacements=replacements, - ) - logging.debug(resource_data) - - # Create k8s resource - ref = k8s.CustomResourceReference( - CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL, - resource_name, namespace="default", - ) - k8s.create_custom_resource(ref, resource_data) - cr = k8s.wait_resource_consumed_by_controller(ref) - - assert cr is not None - assert k8s.get_resource_exists(ref) - - time.sleep(CREATE_WAIT_AFTER_SECONDS) - - cr = k8s.wait_resource_consumed_by_controller(ref) - - lambda_validator = LambdaValidator(lambda_client) - - version_number = cr['status']['version'] - - # Check version exists - assert lambda_validator.version_exists(lambda_function_name, version_number) - - # Update provisioned_concurrency - cr["spec"]["provisionedConcurrencyConfig"]["provisionedConcurrentExecutions"] = 2 - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check provisioned_concurrency_config update fields - provisioned_concurrency_config = lambda_validator.get_provisioned_concurrency_config(lambda_function_name, version_number) - assert provisioned_concurrency_config["RequestedProvisionedConcurrentExecutions"] == 2 - - # Delete provisioned_concurrency from version - cr = k8s.wait_resource_consumed_by_controller(ref) - cr["spec"]["provisionedConcurrencyConfig"] = None - - # Patch k8s resource - k8s.patch_custom_resource(ref, cr) - time.sleep(UPDATE_WAIT_AFTER_SECONDS) - - #Check provisioned_concurrency_config is deleted - assert not lambda_validator.get_provisioned_concurrency_config(lambda_function_name, version_number) - - # Delete k8s resource - _, deleted = k8s.delete_custom_resource(ref) - assert deleted - - time.sleep(DELETE_WAIT_AFTER_SECONDS) - - # Check version doesn't exist - assert not lambda_validator.version_exists(lambda_function_name, version_number) - \ No newline at end of file