From d67d8111a3da078afe09dc00b6a614e090da2939 Mon Sep 17 00:00:00 2001 From: "D. Ferruzzi" Date: Wed, 18 Aug 2021 22:44:56 -0700 Subject: [PATCH] Fargate (#4185) --- moto/eks/models.py | 223 ++++++++++- moto/eks/responses.py | 71 ++++ moto/eks/urls.py | 2 + tests/test_eks/test_eks.py | 566 +++++++++++++++++++++++++++ tests/test_eks/test_eks_constants.py | 43 +- tests/test_eks/test_eks_utils.py | 32 +- tests/test_eks/test_server.py | 16 +- 7 files changed, 932 insertions(+), 21 deletions(-) diff --git a/moto/eks/models.py b/moto/eks/models.py index 28677cde6..c411aed3f 100644 --- a/moto/eks/models.py +++ b/moto/eks/models.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from datetime import datetime +from uuid import uuid4 from boto3 import Session @@ -20,6 +21,11 @@ from .utils import get_partition, validate_role_arn CLUSTER_ARN_TEMPLATE = ( "arn:{partition}:eks:{region}:" + str(ACCOUNT_ID) + ":cluster/{name}" ) +FARGATE_PROFILE_ARN_TEMPLATE = ( + "arn:{partition}:eks:{region}:" + + str(ACCOUNT_ID) + + ":fargateprofile/{cluster_name}/{fargate_profile_name}/{uuid}" +) NODEGROUP_ARN_TEMPLATE = ( "arn:{partition}:eks:{region}:" + str(ACCOUNT_ID) @@ -52,7 +58,7 @@ DEFAULT_LOGGING = { ] } DEFAULT_PLATFORM_VERSION = "eks.4" -DEFAULT_STATUS = "ACTIVE" +ACTIVE_STATUS = "ACTIVE" # Defaults used for creating a Managed Nodegroup DEFAULT_AMI_TYPE = "AL2_x86_64" @@ -64,11 +70,25 @@ DEFAULT_RELEASE_VERSION = "1.19.8-20210414" DEFAULT_REMOTE_ACCESS = {"ec2SshKey": "eksKeypair"} DEFAULT_SCALING_CONFIG = {"minSize": 2, "maxSize": 2, "desiredSize": 2} -# Exception messages, also imported into testing +# Exception messages, also imported into testing. +# Obtained through cURL responses from the actual APIs. CLUSTER_IN_USE_MSG = "Cluster has nodegroups attached" CLUSTER_EXISTS_MSG = "Cluster already exists with name: {clusterName}" CLUSTER_NOT_FOUND_MSG = "No cluster found for name: {clusterName}." CLUSTER_NOT_READY_MSG = "Cluster '{clusterName}' is not in ACTIVE status" +FARGATE_PROFILE_EXISTS_MSG = ( + "A Fargate Profile already exists with this name in this cluster." +) +FARGATE_PROFILE_NEEDS_SELECTOR_MSG = "Fargate Profile requires at least one selector." +FARGATE_PROFILE_NOT_FOUND_MSG = ( + "No Fargate Profile found with name: {fargateProfileName}." +) +FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE = ( + "Fargate Profile must have at least one selector with at least one namespace value." +) +FARGATE_PROFILE_TOO_MANY_LABELS = ( + "Request contains Selector with more than 5 Label pairs" +) LAUNCH_TEMPLATE_WITH_DISK_SIZE_MSG = ( "Disk size must be specified within the launch template." ) @@ -104,6 +124,9 @@ class Cluster: self.nodegroups = dict() self.nodegroup_count = 0 + self.fargate_profiles = dict() + self.fargate_profile_count = 0 + self.arn = CLUSTER_ARN_TEMPLATE.format( partition=aws_partition, region=region_name, name=name ) @@ -117,7 +140,7 @@ class Cluster: ) self.logging = logging or DEFAULT_LOGGING self.platformVersion = DEFAULT_PLATFORM_VERSION - self.status = DEFAULT_STATUS + self.status = ACTIVE_STATUS self.version = version or DEFAULT_KUBERNETES_VERSION self.client_request_token = client_request_token @@ -149,6 +172,55 @@ class Cluster: return self.status == "ACTIVE" +class FargateProfile: + def __init__( + self, + cluster_name, + fargate_profile_name, + pod_execution_role_arn, + selectors, + region_name, + aws_partition, + client_request_token=None, + subnets=None, + tags=None, + ): + if subnets is None: + subnets = list() + if tags is None: + tags = dict() + + self.created_at = iso_8601_datetime_without_milliseconds(datetime.now()) + self.uuid = str(uuid4()) + self.fargate_profile_arn = FARGATE_PROFILE_ARN_TEMPLATE.format( + partition=aws_partition, + region=region_name, + cluster_name=cluster_name, + fargate_profile_name=fargate_profile_name, + uuid=self.uuid, + ) + + self.status = ACTIVE_STATUS + self.cluster_name = cluster_name + self.fargate_profile_name = fargate_profile_name + self.pod_execution_role_arn = pod_execution_role_arn + self.client_request_token = client_request_token + self.selectors = selectors + self.subnets = subnets + self.tags = tags + + def __iter__(self): + yield "clusterName", self.cluster_name + yield "createdAt", self.created_at + yield "fargateProfileArn", self.fargate_profile_arn + yield "fargateProfileName", self.fargate_profile_name + yield "podExecutionRoleArn", self.pod_execution_role_arn + yield "selectors", self.selectors + yield "subnets", self.subnets + yield "status", self.status + yield "tags", self.tags + + class ManagedNodegroup: def __init__( self, @@ -179,7 +251,7 @@ class ManagedNodegroup: if taints is None: taints = dict() - self.uuid = "-".join([random_string(_) for _ in [8, 4, 4, 4, 12]]).lower() + self.uuid = str(uuid4()) self.arn = NODEGROUP_ARN_TEMPLATE.format( partition=aws_partition, region=region_name, @@ -202,7 +274,7 @@ class ManagedNodegroup: self.release_version = release_version or DEFAULT_RELEASE_VERSION self.remote_access = remote_access or DEFAULT_REMOTE_ACCESS self.scaling_config = scaling_config or DEFAULT_SCALING_CONFIG - self.status = DEFAULT_STATUS + self.status = ACTIVE_STATUS self.version = version or DEFAULT_KUBERNETES_VERSION self.client_request_token = client_request_token @@ -294,6 +366,59 @@ class EKSBackend(BaseBackend): self.cluster_count += 1 return cluster + def create_fargate_profile( + self, + fargate_profile_name, + cluster_name, + selectors, + pod_execution_role_arn, + subnets=None, + client_request_token=None, + tags=None, + ): + try: + # Cluster exists. + cluster = self.clusters[cluster_name] + except KeyError: + # Cluster does not exist. + raise ResourceNotFoundException( + clusterName=None, + nodegroupName=None, + fargateProfileName=None, + addonName=None, + message=CLUSTER_NOT_FOUND_MSG.format(clusterName=cluster_name), + ) + if fargate_profile_name in cluster.fargate_profiles: + # Fargate Profile already exists. + raise ResourceInUseException( + clusterName=None, + nodegroupName=None, + addonName=None, + message=FARGATE_PROFILE_EXISTS_MSG, + ) + if not cluster.isActive(): + raise InvalidRequestException( + message=CLUSTER_NOT_READY_MSG.format(clusterName=cluster_name,) + ) + + _validate_fargate_profile_selectors(selectors) + + fargate_profile = FargateProfile( + cluster_name=cluster_name, + fargate_profile_name=fargate_profile_name, + pod_execution_role_arn=pod_execution_role_arn, + client_request_token=client_request_token, + selectors=selectors, + subnets=subnets, + tags=tags, + region_name=self.region_name, + aws_partition=self.partition, + ) + + cluster.fargate_profiles[fargate_profile_name] = fargate_profile + cluster.fargate_profile_count += 1 + return fargate_profile + def create_nodegroup( self, cluster_name, @@ -365,7 +490,7 @@ class EKSBackend(BaseBackend): region_name=self.region_name, aws_partition=self.partition, ) - cluster = self.clusters[cluster_name] + cluster.nodegroups[nodegroup_name] = nodegroup cluster.nodegroup_count += 1 return nodegroup @@ -384,6 +509,34 @@ class EKSBackend(BaseBackend): message=CLUSTER_NOT_FOUND_MSG.format(clusterName=name), ) + def describe_fargate_profile(self, cluster_name, fargate_profile_name): + try: + # Cluster exists. + cluster = self.clusters[cluster_name] + except KeyError: + # Cluster does not exist. + raise ResourceNotFoundException( + clusterName=cluster_name, + nodegroupName=None, + fargateProfileName=None, + addonName=None, + message=CLUSTER_NOT_FOUND_MSG.format(clusterName=cluster_name), + ) + try: + # Fargate Profile exists. + return cluster.fargate_profiles[fargate_profile_name] + except KeyError: + # Fargate Profile does not exist. + raise ResourceNotFoundException( + clusterName=None, + nodegroupName=None, + fargateProfileName=None, + addonName=None, + message=FARGATE_PROFILE_NOT_FOUND_MSG.format( + fargateProfileName=fargate_profile_name + ), + ) + def describe_nodegroup(self, cluster_name, nodegroup_name): try: # Cluster exists. @@ -428,6 +581,37 @@ class EKSBackend(BaseBackend): self.cluster_count -= 1 return result + def delete_fargate_profile(self, cluster_name, fargate_profile_name): + try: + # Cluster exists. + cluster = self.clusters[cluster_name] + except KeyError: + # Cluster does not exist. + raise ResourceNotFoundException( + clusterName=cluster_name, + nodegroupName=None, + fargateProfileName=None, + addonName=None, + message=CLUSTER_NOT_FOUND_MSG.format(clusterName=cluster_name), + ) + try: + # Fargate Profile exists. + deleted_fargate_profile = cluster.fargate_profiles.pop(fargate_profile_name) + except KeyError: + # Fargate Profile does not exist. + raise ResourceNotFoundException( + clusterName=cluster_name, + nodegroupName=None, + fargateProfileName=fargate_profile_name, + addonName=None, + message=FARGATE_PROFILE_NOT_FOUND_MSG.format( + fargateProfileName=fargate_profile_name + ), + ) + + cluster.fargate_profile_count -= 1 + return deleted_fargate_profile + def delete_nodegroup(self, cluster_name, nodegroup_name): try: # Cluster exists. @@ -460,6 +644,10 @@ class EKSBackend(BaseBackend): def list_clusters(self, max_results, next_token): return paginated_list(self.clusters.keys(), max_results, next_token) + def list_fargate_profiles(self, cluster_name, max_results, next_token): + cluster = self.clusters[cluster_name] + return paginated_list(cluster.fargate_profiles.keys(), max_results, next_token) + def list_nodegroups(self, cluster_name, max_results, next_token): cluster = self.clusters[cluster_name] return paginated_list(cluster.nodegroups.keys(), max_results, next_token) @@ -506,6 +694,29 @@ def validate_launch_template_combination(disk_size, remote_access): ) +def _validate_fargate_profile_selectors(selectors): + def raise_exception(message): + raise InvalidParameterException( + clusterName=None, + nodegroupName=None, + fargateProfileName=None, + addonName=None, + message=message, + ) + + # At least one Selector must exist + if not selectors: + raise_exception(message=FARGATE_PROFILE_NEEDS_SELECTOR_MSG) + + for selector in selectors: + # Every existing Selector must have a namespace + if "namespace" not in selector: + raise_exception(message=FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE) + # If a selector has labels, it can not have more than 5 + if len(selector.get("labels", {})) > 5: + raise_exception(message=FARGATE_PROFILE_TOO_MANY_LABELS) + + eks_backends = {} for region in Session().get_available_regions("eks"): eks_backends[region] = EKSBackend(region) diff --git a/moto/eks/responses.py b/moto/eks/responses.py index 2bd875c25..231993b23 100644 --- a/moto/eks/responses.py +++ b/moto/eks/responses.py @@ -56,6 +56,35 @@ class EKSResponse(BaseResponse): # Backend will capture this and re-raise it as a ClientError. return e.response() + def create_fargate_profile(self): + fargate_profile_name = self._get_param("fargateProfileName") + cluster_name = self._get_param("name") + pod_execution_role_arn = self._get_param("podExecutionRoleArn") + subnets = self._get_param("subnets") + selectors = self._get_param("selectors") + client_request_token = self._get_param("clientRequestToken") + tags = self._get_param("tags") + + try: + fargate_profile = self.eks_backend.create_fargate_profile( + fargate_profile_name=fargate_profile_name, + cluster_name=cluster_name, + pod_execution_role_arn=pod_execution_role_arn, + subnets=subnets, + selectors=selectors, + client_request_token=client_request_token, + tags=tags, + ) + + return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)}) + except ( + ResourceNotFoundException, + ResourceInUseException, + InvalidParameterException, + InvalidRequestException, + ) as e: + return e.response() + def create_nodegroup(self): cluster_name = self._get_param("name") nodegroup_name = self._get_param("nodegroupName") @@ -113,6 +142,18 @@ class EKSResponse(BaseResponse): except (ResourceInUseException, ResourceNotFoundException) as e: return e.response() + def describe_fargate_profile(self): + cluster_name = self._get_param("name") + fargate_profile_name = self._get_param("fargateProfileName") + + try: + fargate_profile = self.eks_backend.describe_fargate_profile( + cluster_name=cluster_name, fargate_profile_name=fargate_profile_name, + ) + return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)}) + except (ResourceInUseException, ResourceNotFoundException) as e: + return e.response() + def describe_nodegroup(self): cluster_name = self._get_param("name") nodegroup_name = self._get_param("nodegroupName") @@ -136,6 +177,23 @@ class EKSResponse(BaseResponse): return 200, {}, json.dumps(dict(clusters=clusters, nextToken=next_token)) + def list_fargate_profiles(self): + cluster_name = self._get_param("name") + max_results = self._get_int_param("maxResults", DEFAULT_MAX_RESULTS) + next_token = self._get_param("nextToken", DEFAULT_NEXT_TOKEN) + + fargate_profile_names, next_token = self.eks_backend.list_fargate_profiles( + cluster_name=cluster_name, max_results=max_results, next_token=next_token, + ) + + return ( + 200, + {}, + json.dumps( + dict(fargateProfileNames=fargate_profile_names, nextToken=next_token) + ), + ) + def list_nodegroups(self): cluster_name = self._get_param("name") max_results = self._get_int_param("maxResults", DEFAULT_MAX_RESULTS) @@ -161,6 +219,19 @@ class EKSResponse(BaseResponse): except (ResourceInUseException, ResourceNotFoundException) as e: return e.response() + def delete_fargate_profile(self): + cluster_name = self._get_param("name") + fargate_profile_name = self._get_param("fargateProfileName") + + try: + fargate_profile = self.eks_backend.delete_fargate_profile( + cluster_name=cluster_name, fargate_profile_name=fargate_profile_name, + ) + + return 200, {}, json.dumps({"fargateProfile": dict(fargate_profile)}) + except ResourceNotFoundException as e: + return e.response() + def delete_nodegroup(self): cluster_name = self._get_param("name") nodegroup_name = self._get_param("nodegroupName") diff --git a/moto/eks/urls.py b/moto/eks/urls.py index c94b3f23e..36f0f679b 100644 --- a/moto/eks/urls.py +++ b/moto/eks/urls.py @@ -15,4 +15,6 @@ url_paths = { "{0}/clusters/(?P[^/]+)$": response.dispatch, "{0}/clusters/(?P[^/]+)/node-groups$": response.dispatch, "{0}/clusters/(?P[^/]+)/node-groups/(?P[^/]+)$": response.dispatch, + "{0}/clusters/(?P[^/]+)/fargate-profiles$": response.dispatch, + "{0}/clusters/(?P[^/]+)/fargate-profiles/(?P[^/]+)$": response.dispatch, } diff --git a/tests/test_eks/test_eks.py b/tests/test_eks/test_eks.py index 5eb8af0fd..40195c2fd 100644 --- a/tests/test_eks/test_eks.py +++ b/tests/test_eks/test_eks.py @@ -24,6 +24,11 @@ from moto.eks.models import ( CLUSTER_IN_USE_MSG, CLUSTER_NOT_FOUND_MSG, CLUSTER_NOT_READY_MSG, + FARGATE_PROFILE_EXISTS_MSG, + FARGATE_PROFILE_NEEDS_SELECTOR_MSG, + FARGATE_PROFILE_NOT_FOUND_MSG, + FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, + FARGATE_PROFILE_TOO_MANY_LABELS, LAUNCH_TEMPLATE_WITH_DISK_SIZE_MSG, LAUNCH_TEMPLATE_WITH_REMOTE_ACCESS_MSG, NODEGROUP_EXISTS_MSG, @@ -36,15 +41,20 @@ from .test_eks_constants import ( BatchCountSize, ClusterAttributes, ClusterInputs, + DEFAULT_NAMESPACE, DISK_SIZE, ErrorAttributes, + FargateProfileAttributes, + FargateProfileInputs, FROZEN_TIME, INSTANCE_TYPES, LAUNCH_TEMPLATE, + MAX_FARGATE_LABELS, NodegroupAttributes, NodegroupInputs, PageCount, PARTITIONS, + POD_EXECUTION_ROLE_ARN, PossibleTestResults, RegExTemplates, REGION, @@ -55,6 +65,8 @@ from .test_eks_constants import ( from .test_eks_utils import ( attributes_to_test, generate_clusters, + generate_dict, + generate_fargate_profiles, generate_nodegroups, is_valid_uri, random_names, @@ -94,6 +106,44 @@ def ClusterBuilder(): yield _execute +@pytest.fixture(scope="function") +def FargateProfileBuilder(ClusterBuilder): + class FargateProfileTestDataFactory: + def __init__(self, client, cluster, count, minimal): + self.cluster_name = cluster.existing_cluster_name + + # Generate 'count' number of random FargateProfile objects. + self.fargate_profile_names = generate_fargate_profiles( + client, self.cluster_name, count, minimal + ) + + # Get the name of the first generated profile. + first_name = self.fargate_profile_names[0] + + # Collect the output of describe_fargate_profiles() for the first profile. + self.fargate_describe_output = client.describe_fargate_profile( + clusterName=self.cluster_name, fargateProfileName=first_name + )[ResponseAttributes.FARGATE_PROFILE] + + # Pick a random profile name from the list and a name guaranteed not to be on the list. + ( + self.existing_fargate_profile_name, + self.nonexistent_fargate_profile_name, + ) = random_names(self.fargate_profile_names) + _, self.nonexistent_cluster_name = random_names(self.cluster_name) + + # Generate a list of the Fargate Profile attributes to be tested when validating results. + self.attributes_to_test = attributes_to_test( + FargateProfileInputs, self.existing_fargate_profile_name + ) + + def _execute(count=1, minimal=True): + client, cluster = ClusterBuilder() + return client, FargateProfileTestDataFactory(client, cluster, count, minimal) + + return _execute + + @pytest.fixture(scope="function") def NodegroupBuilder(ClusterBuilder): class NodegroupTestDataFactory: @@ -797,6 +847,490 @@ def test_create_nodegroup_handles_launch_template_combinations( assert_expected_exception(raised_exception, expected_exception, expected_msg) +@mock_eks +def test_list_fargate_profile_returns_empty_by_default(ClusterBuilder): + client, generated_test_data = ClusterBuilder() + + result = client.list_fargate_profiles( + clusterName=generated_test_data.existing_cluster_name + )[ResponseAttributes.FARGATE_PROFILE_NAMES] + + result.should.be.empty + + +@mock_eks +def test_list_fargate_profile_returns_sorted_fargate_profile_names( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.SMALL) + expected_result = sorted(generated_test_data.fargate_profile_names) + + result = client.list_fargate_profiles(clusterName=generated_test_data.cluster_name)[ + ResponseAttributes.FARGATE_PROFILE_NAMES + ] + + assert_result_matches_expected_list(result, expected_result, BatchCountSize.SMALL) + + +@mock_eks +def test_list_fargate_profile_returns_default_max_results(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.LARGE) + expected_len = DEFAULT_MAX_RESULTS + expected_result = (sorted(generated_test_data.fargate_profile_names))[:expected_len] + + result = client.list_fargate_profiles(clusterName=generated_test_data.cluster_name)[ + ResponseAttributes.FARGATE_PROFILE_NAMES + ] + + assert_result_matches_expected_list(result, expected_result, expected_len) + + +@mock_eks +def test_list_fargate_profile_returns_custom_max_results(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.LARGE) + expected_len = BatchCountSize.LARGE + expected_result = (sorted(generated_test_data.fargate_profile_names))[:expected_len] + + result = client.list_fargate_profiles( + clusterName=generated_test_data.cluster_name, maxResults=expected_len + )[ResponseAttributes.FARGATE_PROFILE_NAMES] + + assert_result_matches_expected_list(result, expected_result, expected_len) + + +@mock_eks +def test_list_fargate_profile_returns_second_page_results(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.MEDIUM) + page1_len = PageCount.LARGE + expected_len = BatchCountSize.MEDIUM - page1_len + expected_result = (sorted(generated_test_data.fargate_profile_names))[page1_len:] + token = client.list_fargate_profiles( + clusterName=generated_test_data.cluster_name, maxResults=page1_len + )[ResponseAttributes.NEXT_TOKEN] + + result = client.list_fargate_profiles( + clusterName=generated_test_data.cluster_name, nextToken=token + )[ResponseAttributes.FARGATE_PROFILE_NAMES] + + assert_result_matches_expected_list(result, expected_result, expected_len) + + +@mock_eks +def test_list_fargate_profile_returns_custom_second_page_results(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.MEDIUM) + page1_len = PageCount.LARGE + expected_len = PageCount.SMALL + expected_result = (sorted(generated_test_data.fargate_profile_names))[ + page1_len : page1_len + expected_len + ] + token = client.list_fargate_profiles( + clusterName=generated_test_data.cluster_name, maxResults=page1_len + )[ResponseAttributes.NEXT_TOKEN] + + result = client.list_fargate_profiles( + clusterName=generated_test_data.cluster_name, + maxResults=expected_len, + nextToken=token, + )[ResponseAttributes.FARGATE_PROFILE_NAMES] + + assert_result_matches_expected_list(result, expected_result, expected_len) + + +@mock_eks +def test_create_fargate_profile_throws_exception_when_cluster_not_found(): + client = boto3.client(SERVICE, region_name=REGION) + non_existent_cluster_name = random_string() + expected_exception = ResourceNotFoundException + expected_msg = CLUSTER_NOT_FOUND_MSG.format(clusterName=non_existent_cluster_name,) + + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile( + clusterName=non_existent_cluster_name, + fargateProfileName=random_string(), + **dict(FargateProfileInputs.REQUIRED) + ) + + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_create_fargate_profile_throws_exception_when_fargate_profile_already_exists( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.SMALL) + expected_exception = ResourceInUseException + expected_msg = FARGATE_PROFILE_EXISTS_MSG + + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=generated_test_data.existing_fargate_profile_name, + **dict(FargateProfileInputs.REQUIRED) + ) + count_profiles_after_test = len( + client.list_fargate_profiles(clusterName=generated_test_data.cluster_name)[ + ResponseAttributes.FARGATE_PROFILE_NAMES + ] + ) + + count_profiles_after_test.should.equal(BatchCountSize.SMALL) + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_create_fargate_profile_throws_exception_when_cluster_not_active( + FargateProfileBuilder, monkeypatch +): + if settings.TEST_SERVER_MODE: + raise SkipTest("Cant patch Cluster attributes in server mode.") + client, generated_test_data = FargateProfileBuilder(BatchCountSize.SMALL) + expected_exception = InvalidRequestException + expected_msg = CLUSTER_NOT_READY_MSG.format( + clusterName=generated_test_data.cluster_name, + ) + + with mock.patch("moto.eks.models.Cluster.isActive", return_value=False): + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=random_string(), + **dict(FargateProfileInputs.REQUIRED) + ) + count_fargate_profiles_after_test = len( + client.list_fargate_profiles(clusterName=generated_test_data.cluster_name)[ + ResponseAttributes.FARGATE_PROFILE_NAMES + ] + ) + + count_fargate_profiles_after_test.should.equal(BatchCountSize.SMALL) + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_create_fargate_profile_generates_valid_profile_arn(FargateProfileBuilder): + _, generated_test_data = FargateProfileBuilder() + expected_arn_values = [ + PARTITIONS, + REGION, + ACCOUNT_ID, + generated_test_data.cluster_name, + generated_test_data.fargate_profile_names, + None, + ] + + all_arn_values_should_be_valid( + expected_arn_values=expected_arn_values, + pattern=RegExTemplates.FARGATE_PROFILE_ARN, + arn_under_test=generated_test_data.fargate_describe_output[ + FargateProfileAttributes.ARN + ], + ) + + +@freeze_time(FROZEN_TIME) +@mock_eks +def test_create_fargate_profile_generates_valid_created_timestamp( + FargateProfileBuilder, +): + _, generated_test_data = FargateProfileBuilder() + + result_time = iso_8601_datetime_without_milliseconds( + generated_test_data.fargate_describe_output[FargateProfileAttributes.CREATED_AT] + ) + + if settings.TEST_SERVER_MODE: + RegExTemplates.ISO8601_FORMAT.match(result_time).should.be.true + else: + result_time.should.equal(FROZEN_TIME) + + +@mock_eks +def test_create_fargate_profile_saves_provided_parameters(FargateProfileBuilder): + _, generated_test_data = FargateProfileBuilder(minimal=False) + + for key, expected_value in generated_test_data.attributes_to_test: + generated_test_data.fargate_describe_output[key].should.equal(expected_value) + + +@mock_eks +def test_describe_fargate_profile_throws_exception_when_cluster_not_found( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder() + expected_exception = ResourceNotFoundException + expected_msg = CLUSTER_NOT_FOUND_MSG.format( + clusterName=generated_test_data.nonexistent_cluster_name, + ) + + with pytest.raises(ClientError) as raised_exception: + client.describe_fargate_profile( + clusterName=generated_test_data.nonexistent_cluster_name, + fargateProfileName=generated_test_data.existing_fargate_profile_name, + ) + + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_describe_fargate_profile_throws_exception_when_profile_not_found( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder() + expected_exception = ResourceNotFoundException + expected_msg = FARGATE_PROFILE_NOT_FOUND_MSG.format( + fargateProfileName=generated_test_data.nonexistent_fargate_profile_name, + ) + + with pytest.raises(ClientError) as raised_exception: + client.describe_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=generated_test_data.nonexistent_fargate_profile_name, + ) + + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_delete_fargate_profile_removes_deleted_fargate_profile(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.SMALL) + + client.delete_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=generated_test_data.existing_fargate_profile_name, + ) + result = client.list_fargate_profiles(clusterName=generated_test_data.cluster_name)[ + ResponseAttributes.FARGATE_PROFILE_NAMES + ] + + len(result).should.equal(BatchCountSize.SMALL - 1) + result.should_not.contain(generated_test_data.existing_fargate_profile_name) + + +@mock_eks +def test_delete_fargate_profile_returns_deleted_fargate_profile(FargateProfileBuilder): + client, generated_test_data = FargateProfileBuilder(BatchCountSize.SMALL, False) + + result = client.delete_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=generated_test_data.existing_fargate_profile_name, + )[ResponseAttributes.FARGATE_PROFILE] + + for key, expected_value in generated_test_data.attributes_to_test: + result[key].should.equal(expected_value) + + +@mock_eks +def test_delete_fargate_profile_throws_exception_when_cluster_not_found( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder() + expected_exception = ResourceNotFoundException + expected_msg = CLUSTER_NOT_FOUND_MSG.format( + clusterName=generated_test_data.nonexistent_cluster_name, + ) + + with pytest.raises(ClientError) as raised_exception: + client.delete_fargate_profile( + clusterName=generated_test_data.nonexistent_cluster_name, + fargateProfileName=generated_test_data.existing_fargate_profile_name, + ) + + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_delete_fargate_profile_throws_exception_when_fargate_profile_not_found( + FargateProfileBuilder, +): + client, generated_test_data = FargateProfileBuilder() + expected_exception = ResourceNotFoundException + expected_msg = FARGATE_PROFILE_NOT_FOUND_MSG.format( + fargateProfileName=generated_test_data.nonexistent_fargate_profile_name, + ) + + with pytest.raises(ClientError) as raised_exception: + client.delete_fargate_profile( + clusterName=generated_test_data.cluster_name, + fargateProfileName=generated_test_data.nonexistent_fargate_profile_name, + ) + + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +@mock_eks +def test_create_fargate_throws_exception_when_no_selectors_provided(ClusterBuilder): + client, generated_test_data = ClusterBuilder() + cluster_name = generated_test_data.existing_cluster_name + fargate_profile_name = random_string() + expected_exception = InvalidParameterException + expected_msg = FARGATE_PROFILE_NEEDS_SELECTOR_MSG + + test_inputs = dict( + deepcopy( + # Required Constants + [POD_EXECUTION_ROLE_ARN] + # Required Variables + + [ + (ClusterAttributes.CLUSTER_NAME, cluster_name), + (FargateProfileAttributes.FARGATE_PROFILE_NAME, fargate_profile_name), + ] + ) + ) + + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile(**test_inputs) + assert_expected_exception(raised_exception, expected_exception, expected_msg) + + +# The following Selector test cases have all been verified against the AWS API using cURL. +selector_formatting_test_cases = [ + # Format is ([Selector(s), expected_message, expected_result]) + # Happy Paths + # Selector with a Namespace and no Labels + ( + [{FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}], + None, + PossibleTestResults.SUCCESS, + ), + # Selector with a Namespace and an empty collection of Labels + ( + [ + { + FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE, + FargateProfileAttributes.LABELS: generate_dict("label", 0), + } + ], + None, + PossibleTestResults.SUCCESS, + ), + # Selector with a Namespace and one valid Label + ( + [ + { + FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE, + FargateProfileAttributes.LABELS: generate_dict("label", 1), + } + ], + None, + PossibleTestResults.SUCCESS, + ), + # Selector with a Namespace and the maximum number of Labels + ( + [ + { + FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE, + FargateProfileAttributes.LABELS: generate_dict( + "label", MAX_FARGATE_LABELS + ), + } + ], + None, + PossibleTestResults.SUCCESS, + ), + # Two valid Selectors + ( + [ + {FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}, + {FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}, + ], + None, + PossibleTestResults.SUCCESS, + ), + # Unhappy Cases + # No Selectors provided + ([], FARGATE_PROFILE_NEEDS_SELECTOR_MSG, PossibleTestResults.FAILURE), + # Empty Selector / Selector without a Namespace or Labels + ([{}], FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, PossibleTestResults.FAILURE), + # Selector with labels but no Namespace + ( + [{FargateProfileAttributes.LABELS: generate_dict("label", 1)}], + FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, + PossibleTestResults.FAILURE, + ), + # Selector with Namespace but too many Labels + ( + [ + { + FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE, + FargateProfileAttributes.LABELS: generate_dict( + "label", MAX_FARGATE_LABELS + 1 + ), + } + ], + FARGATE_PROFILE_TOO_MANY_LABELS, + PossibleTestResults.FAILURE, + ), + # Valid Selector followed by Empty Selector + ( + [{FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}, {}], + FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, + PossibleTestResults.FAILURE, + ), + # Empty Selector followed by Valid Selector + ( + [{}, {FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}], + FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, + PossibleTestResults.FAILURE, + ), + # Empty Selector followed by Empty Selector + ([{}, {}], FARGATE_PROFILE_SELECTOR_NEEDS_NAMESPACE, PossibleTestResults.FAILURE), + # Valid Selector followed by Selector with Namespace but too many Labels + ( + [ + {FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE}, + { + FargateProfileAttributes.NAMESPACE: DEFAULT_NAMESPACE, + FargateProfileAttributes.LABELS: generate_dict( + "label", MAX_FARGATE_LABELS + 1 + ), + }, + ], + FARGATE_PROFILE_TOO_MANY_LABELS, + PossibleTestResults.FAILURE, + ), +] + + +@pytest.mark.parametrize( + "selectors, expected_message, expected_result", selector_formatting_test_cases, +) +@mock_eks +def test_create_fargate_selectors( + ClusterBuilder, selectors, expected_message, expected_result +): + client, generated_test_data = ClusterBuilder() + cluster_name = generated_test_data.existing_cluster_name + fargate_profile_name = random_string() + expected_exception = InvalidParameterException + + test_inputs = dict( + deepcopy( + # Required Constants + [POD_EXECUTION_ROLE_ARN] + # Required Variables + + [ + (ClusterAttributes.CLUSTER_NAME, cluster_name), + (FargateProfileAttributes.FARGATE_PROFILE_NAME, fargate_profile_name), + ] + # Test Case Values + + [(FargateProfileAttributes.SELECTORS, selectors)] + ) + ) + + if expected_result == PossibleTestResults.SUCCESS: + result = client.create_fargate_profile(**test_inputs)[ + ResponseAttributes.FARGATE_PROFILE + ] + for key, expected_value in test_inputs.items(): + result[key].should.equal(expected_value) + else: + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile(**test_inputs) + assert_expected_exception( + raised_exception, expected_exception, expected_message + ) + + def all_arn_values_should_be_valid(expected_arn_values, pattern, arn_under_test): """ Applies regex `pattern` to `arn_under_test` and asserts @@ -826,3 +1360,35 @@ def assert_expected_exception(raised_exception, expected_exception, expected_msg def assert_result_matches_expected_list(result, expected_result, expected_len): assert result == expected_result assert len(result) == expected_len + + +def assert_valid_selectors(ClusterBuilder, expected_msg, expected_result, selectors): + client, generated_test_data = ClusterBuilder() + cluster_name = generated_test_data.existing_cluster_name + fargate_profile_name = random_string() + expected_exception = InvalidParameterException + + test_inputs = dict( + deepcopy( + # Required Constants + [POD_EXECUTION_ROLE_ARN] + # Required Variables + + [ + (ClusterAttributes.CLUSTER_NAME, cluster_name), + (FargateProfileAttributes.FARGATE_PROFILE_NAME, fargate_profile_name), + ] + # Test Case Values + + [(FargateProfileAttributes.SELECTORS, selectors)] + ) + ) + + if expected_result == PossibleTestResults.SUCCESS: + result = client.create_fargate_profile(**test_inputs)[ + ResponseAttributes.FARGATE_PROFILE + ] + for key, expected_value in test_inputs.items(): + result[key].should.equal(expected_value) + else: + with pytest.raises(ClientError) as raised_exception: + client.create_fargate_profile(**test_inputs) + assert_expected_exception(raised_exception, expected_exception, expected_msg) diff --git a/tests/test_eks/test_eks_constants.py b/tests/test_eks/test_eks_constants.py index 7ec482432..5b7dd2195 100644 --- a/tests/test_eks/test_eks_constants.py +++ b/tests/test_eks/test_eks_constants.py @@ -6,11 +6,14 @@ from enum import Enum from boto3 import Session +from moto.core import ACCOUNT_ID from moto.eks import REGION as DEFAULT_REGION DEFAULT_ENCODING = "utf-8" DEFAULT_HTTP_HEADERS = {"Content-type": "application/json"} +DEFAULT_NAMESPACE = "namespace_1" FROZEN_TIME = "2013-11-27T01:42:00Z" +MAX_FARGATE_LABELS = 5 PARTITIONS = Session().get_available_partitions() REGION = Session().region_name or DEFAULT_REGION SERVICE = "eks" @@ -47,7 +50,10 @@ LOGGING_KEY = "logging" LOGGING_VALUE = {"clusterLogging": [{"types": ["api"], "enabled": True}]} NODEROLE_ARN_KEY = "nodeRole" -NODEROLE_ARN_VALUE = "arn:aws:iam::123456789012:role/role_name" +NODEROLE_ARN_VALUE = "arn:aws:iam::" + str(ACCOUNT_ID) + ":role/role_name" + +POD_EXECUTION_ROLE_ARN_KEY = "podExecutionRoleArn" +POD_EXECUTION_ROLE_ARN_VALUE = "arn:aws:iam::" + str(ACCOUNT_ID) + ":role/role_name" REMOTE_ACCESS_KEY = "remoteAccess" REMOTE_ACCESS_VALUE = {"ec2SshKey": "eksKeypair"} @@ -60,11 +66,14 @@ RESOURCES_VPC_CONFIG_VALUE = { } ROLE_ARN_KEY = "roleArn" -ROLE_ARN_VALUE = "arn:aws:iam::123456789012:role/role_name" +ROLE_ARN_VALUE = "arn:aws:iam::" + str(ACCOUNT_ID) + ":role/role_name" SCALING_CONFIG_KEY = "scalingConfig" SCALING_CONFIG_VALUE = {"minSize": 2, "maxSize": 3, "desiredSize": 2} +SELECTORS_KEY = "selectors" +SELECTORS_VALUE = [{"namespace": "profile-namespace"}] + STATUS_KEY = "status" STATUS_VALUE = "ACTIVE" @@ -90,10 +99,12 @@ LABELS = (LABELS_KEY, LABELS_VALUE) LAUNCH_TEMPLATE = (LAUNCH_TEMPLATE_KEY, LAUNCH_TEMPLATE_VALUE) LOGGING = (LOGGING_KEY, LOGGING_VALUE) NODEROLE_ARN = (NODEROLE_ARN_KEY, NODEROLE_ARN_VALUE) +POD_EXECUTION_ROLE_ARN = (POD_EXECUTION_ROLE_ARN_KEY, POD_EXECUTION_ROLE_ARN_VALUE) REMOTE_ACCESS = (REMOTE_ACCESS_KEY, REMOTE_ACCESS_VALUE) RESOURCES_VPC_CONFIG = (RESOURCES_VPC_CONFIG_KEY, RESOURCES_VPC_CONFIG_VALUE) ROLE_ARN = (ROLE_ARN_KEY, ROLE_ARN_VALUE) SCALING_CONFIG = (SCALING_CONFIG_KEY, SCALING_CONFIG_VALUE) +SELECTORS = (SELECTORS_KEY, SELECTORS_VALUE) STATUS = (STATUS_KEY, STATUS_VALUE) SUBNETS = (SUBNETS_KEY, SUBNETS_VALUE) TAGS = (TAGS_KEY, TAGS_VALUE) @@ -103,6 +114,8 @@ VERSION = (VERSION_KEY, VERSION_VALUE) class ResponseAttributes: CLUSTER = "cluster" CLUSTERS = "clusters" + FARGATE_PROFILE_NAMES = "fargateProfileNames" + FARGATE_PROFILE = "fargateProfile" MESSAGE = "message" NEXT_TOKEN = "nextToken" NODEGROUP = "nodegroup" @@ -127,6 +140,11 @@ class ClusterInputs: ] +class FargateProfileInputs: + REQUIRED = [POD_EXECUTION_ROLE_ARN, SELECTORS] + OPTIONAL = [SUBNETS, TAGS] + + class NodegroupInputs: REQUIRED = [NODEROLE_ARN, SUBNETS] OPTIONAL = [ @@ -160,8 +178,13 @@ class ClusterAttributes: OIDC = "oidc" -class FargateAttributes: - PROFILE_NAME = "fargateProfileName" +class FargateProfileAttributes: + ARN = "fargateProfileArn" + CREATED_AT = "createdAt" + FARGATE_PROFILE_NAME = "fargateProfileName" + LABELS = "labels" + NAMESPACE = "namespace" + SELECTORS = "selectors" class NodegroupAttributes: @@ -187,6 +210,7 @@ class PageCount: LARGE = 10 +FARGATE_PROFILE_UUID_PATTERN = "(?P[-0-9a-z]{8}-[-0-9a-z]{4}-[-0-9a-z]{4}-[-0-9a-z]{4}-[-0-9a-z]{12})" NODEGROUP_UUID_PATTERN = "(?P[-0-9a-z]{8}-[-0-9a-z]{4}-[-0-9a-z]{4}-[-0-9a-z]{4}-[-0-9a-z]{12})" @@ -200,6 +224,17 @@ class RegExTemplates: + "cluster/" + "(?P.+)" ) + FARGATE_PROFILE_ARN = re.compile( + "arn:" + + "(?P.+):" + + "eks:" + + "(?P[-0-9a-zA-Z]+):" + + "(?P[0-9]{12}):" + + "fargateprofile/" + + "(?P.+)/" + + "(?P.+)/" + + FARGATE_PROFILE_UUID_PATTERN + ) ISO8601_FORMAT = re.compile( r"^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$" ) diff --git a/tests/test_eks/test_eks_utils.py b/tests/test_eks/test_eks_utils.py index 047f4eb2c..9ba361c05 100644 --- a/tests/test_eks/test_eks_utils.py +++ b/tests/test_eks/test_eks_utils.py @@ -6,18 +6,18 @@ try: except ImportError: from urlparse import urlparse -from moto.utilities.utils import random_string +from moto.utilities.utils import random_string as generate_random_name from tests.test_eks.test_eks_constants import ( ClusterAttributes, ClusterInputs, + FargateProfileAttributes, + FargateProfileInputs, NodegroupAttributes, NodegroupInputs, ResponseAttributes, STATUS, ) -generate_random_name = random_string - def attributes_to_test(inputs, name): """ @@ -46,6 +46,25 @@ def generate_clusters(client, num_clusters, minimal): ] +def generate_fargate_profiles(client, cluster_name, num_profiles, minimal): + """ + Generates 'num_profiles' number of fargate profiles with randomized data and adds them to + the mocked backend. + If 'minimal' is True, only the required values are generated; if False, all values are generated. + Returns a list of the names of the generated Fargate profiles. + """ + return [ + client.create_fargate_profile( + fargateProfileName=generate_random_name(), + clusterName=cluster_name, + **_input_builder(FargateProfileInputs, minimal) + )[ResponseAttributes.FARGATE_PROFILE][ + FargateProfileAttributes.FARGATE_PROFILE_NAME + ] + for _ in range(num_profiles) + ] + + def generate_nodegroups(client, cluster_name, num_nodegroups, minimal): """ Generates 'num_nodegroups' number of nodegroups with randomized data and adds them to the mocked backend. @@ -62,6 +81,13 @@ def generate_nodegroups(client, cluster_name, num_nodegroups, minimal): ] +def generate_dict(prefix, count): + return { + "{prefix}_{count}".format(prefix=prefix, count=_count): str(_count) + for _count in range(count) + } + + def is_valid_uri(value): """ Returns true if a provided string has the form of a valid uri. diff --git a/tests/test_eks/test_server.py b/tests/test_eks/test_server.py index ea3e7ba30..ad739691a 100644 --- a/tests/test_eks/test_server.py +++ b/tests/test_eks/test_server.py @@ -26,7 +26,7 @@ from tests.test_eks.test_eks_constants import ( DEFAULT_HTTP_HEADERS, DEFAULT_REGION, Endpoints, - FargateAttributes, + FargateProfileAttributes, HttpHeaders, NodegroupAttributes, NODEROLE_ARN_KEY, @@ -169,7 +169,7 @@ def test_eks_create_nodegroup_without_cluster(test_client): expected_data = { ClusterAttributes.CLUSTER_NAME: None, NodegroupAttributes.NODEGROUP_NAME: None, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -290,7 +290,7 @@ def test_eks_describe_nonexisting_cluster(test_client): expected_data = { ClusterAttributes.CLUSTER_NAME: None, NodegroupAttributes.NODEGROUP_NAME: None, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -340,7 +340,7 @@ def test_eks_describe_nonexisting_nodegroup(test_client, create_cluster): expected_data = { ClusterAttributes.CLUSTER_NAME: TestNodegroup.cluster_name, NodegroupAttributes.NODEGROUP_NAME: TestNodegroup.nodegroup_name, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -362,7 +362,7 @@ def test_eks_describe_nodegroup_nonexisting_cluster(test_client): expected_data = { ClusterAttributes.CLUSTER_NAME: TestNodegroup.cluster_name, NodegroupAttributes.NODEGROUP_NAME: TestNodegroup.nodegroup_name, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -404,7 +404,7 @@ def test_eks_delete_nonexisting_cluster(test_client): expected_data = { ClusterAttributes.CLUSTER_NAME: None, NodegroupAttributes.NODEGROUP_NAME: None, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -476,7 +476,7 @@ def test_eks_delete_nonexisting_nodegroup(test_client, create_cluster): expected_data = { ClusterAttributes.CLUSTER_NAME: TestNodegroup.cluster_name, NodegroupAttributes.NODEGROUP_NAME: TestNodegroup.nodegroup_name, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, } @@ -501,7 +501,7 @@ def test_eks_delete_nodegroup_nonexisting_cluster(test_client): expected_data = { ClusterAttributes.CLUSTER_NAME: None, NodegroupAttributes.NODEGROUP_NAME: None, - FargateAttributes.PROFILE_NAME: None, + FargateProfileAttributes.FARGATE_PROFILE_NAME: None, AddonAttributes.ADDON_NAME: None, ResponseAttributes.MESSAGE: expected_msg, }