def _assert_successful(self, mocker, client, image_id, force, region, image, stack, expected_response): if image: mocker.patch("pcluster.aws.ec2.Ec2Client.describe_image_by_id_tag", return_value=image) else: mocker.patch( "pcluster.aws.ec2.Ec2Client.describe_image_by_id_tag", side_effect=ImageNotFoundError("describe_image_by_id_tag"), ) if stack: mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", return_value=stack) else: mocker.patch( "pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError("describe_stack", "stack_name"), ) mocker.patch("pcluster.models.imagebuilder.ImageBuilder.delete", return_value=None) # Ensure we don't hit AWS when creating ImageBuilderStack(s) mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack_resource", return_value=None) response = self._send_test_request(client, image_id, region, force) with soft_assertions(): assert_that(response.status_code).is_equal_to(202) assert_that(response.get_json()).is_equal_to(expected_response)
def _mock_cluster_stack(cluster_found=True, cluster_valid=True, logging_enabled=True): if not cluster_found: mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError("func", "stack")) else: edits = {} if not cluster_valid: edits.update({"Tags": [{"Key": "parallelcluster:version", "Value": "2.0.0"}]}) if not logging_enabled: edits.update({"Parameters": []}) mocker.patch( "pcluster.aws.cfn.CfnClient.describe_stack", return_value=cfn_describe_stack_mock_response(edits=edits) )
def describe_stack(self, stack_name: str): """Get information for the given stack.""" try: return self._client.describe_stacks( StackName=stack_name).get("Stacks")[0] except ClientError as e: if e.response["Error"][ "Code"] == AWSClientError.ErrorCode.VALIDATION_ERROR.value: LOGGER.info("Could not describe CloudFormation stack %s: %s", stack_name, e) raise StackNotFoundError(function_name="describe_stack", stack_name=stack_name) raise
def test_stack_not_exist_request(self, mocker, client): mocker.patch( "pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError(function_name="describestack", stack_name="stack_name"), ) response = self._send_test_request(client) with soft_assertions(): assert_that(response.status_code).is_equal_to(404) assert_that(response.get_json()).is_equal_to({ "message": "Cluster 'clustername' does not exist or belongs to an " "incompatible ParallelCluster major version." })
def test_delete_image_with_no_available_image_or_stack_throws_not_found_exception( self, mocker, client): mocker.patch( "pcluster.aws.ec2.Ec2Client.describe_image_by_id_tag", side_effect=ImageNotFoundError("describe_image_by_id_tag"), ) mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError("describe_stack", "stack_name")) response = self._send_test_request(client, "nonExistentImage") with soft_assertions(): assert_that(response.status_code).is_equal_to(404) assert_that(response.get_json()).is_equal_to({ "message": "No image or stack associated with ParallelCluster image id: nonExistentImage." })
def test_successful_request(self, mocker, client, stack_exists, force): if stack_exists: mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", return_value=cfn_describe_stack_mock_response()) else: mocker.patch( "pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError(function_name="describestack", stack_name="stack_name"), ) instance_ids = ["fakeinstanceid1", "fakeinstanceid2"] mocker.patch("pcluster.aws.ec2.Ec2Client.list_instance_ids", return_value=instance_ids) terminate_instance_mock = mocker.patch( "pcluster.aws.ec2.Ec2Client.terminate_instances") response = self._send_test_request(client, force=force) with soft_assertions(): assert_that(response.status_code).is_equal_to(202) terminate_instance_mock.assert_called_with(tuple(instance_ids))
def _mock_image_stack(image_id: str = "image", stack_exists: bool = True): uid = "00000000-ffff-1111-9999-000000000000" stack_data = { "Capabilities": ["CAPABILITY_NAMED_IAM"], "CreationTime": datetime(2021, 1, 1, 0, 0, 0, 0, tzinfo=tz.tzutc()), "NotificationARNs": [], "Parameters": [], "RollbackConfiguration": {}, "StackId": f"arn:aws:cloudformation:us-east-1:000000000000:stack/{image_id}/{uid}", "StackName": image_id, "StackStatus": "CREATE_COMPLETE", "Tags": [ {"Key": "parallelcluster:version", "Value": "3.0.0"}, {"Key": "parallelcluster:image_name", "Value": image_id}, {"Key": "parallelcluster:image_id", "Value": image_id}, {"Key": "parallelcluster:s3_bucket", "Value": "parallelcluster-0000000000000000-v1-do-not-delete"}, { "Key": "parallelcluster:s3_image_dir", "Value": f"parallelcluster/3.0.0/images/{image_id}-aaaaaaaaaaaaaaaa", }, { "Key": "parallelcluster:build_log", "Value": ( "arn:aws:logs:us-east-1:000000000000:log-group:" "/aws/imagebuilder/ParallelClusterImage-{image_id}" ), }, { "Key": "parallelcluster:build_config", "Value": ( "s3://parallelcluster-0cd54f8004a2e0af-v1-do-not-delete/parallelcluster/" "3.0.0/images/custom-image-0-pgdlow92odu5dbvv/configs/image-config.yaml" ), }, ], } if not stack_exists: mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", side_effect=StackNotFoundError("func", "stack")) else: mocker.patch("pcluster.aws.cfn.CfnClient.describe_stack", return_value=stack_data)
from tests.utils import MockedBoto3Request FAKE_STACK_NAME = "parallelcluster-name" FAKE_IMAGE_ID = "ami-1234567" @pytest.fixture() def boto3_stubber_path(): return "pcluster.aws.common.boto3" @pytest.mark.parametrize( "response,is_error", [ ( StackNotFoundError(function_name="describe_stack", stack_name=FAKE_STACK_NAME), True, ), ({ "Stacks": [{ "StackName": FAKE_STACK_NAME, "CreationTime": 0, "StackStatus": "CREATED" }] }, False), ], ) def test_stack_exists(mocker, response, is_error): """Verify that CfnClient.stack_exists behaves as expected.""" should_exist = not is_error mock_aws_api(mocker)