예제 #1
0
def test_setup_bucket_with_bucket_configuration_failure(
    mocker,
    check_bucket_is_bootstrapped_error,
    bucket_configure_error,
    upload_bootstrapped_file_error,
    cluster_action_error,
):
    """Verify that create_bucket_with_batch_resources behaves as expected in case of bucket configuration failure."""
    mock_aws_api(mocker)

    # mock bucket initialization
    mock_bucket(mocker)

    # mock bucket utils
    mock_bucket_utils(mocker,
                      configure_bucket_side_effect=bucket_configure_error)
    cluster = _mock_cluster(mocker, "slurm")

    # mock bucket object utils
    mock_bucket_object_utils(
        mocker,
        check_bucket_is_bootstrapped_side_effect=
        check_bucket_is_bootstrapped_error,
        upload_bootstrapped_file_side_effect=upload_bootstrapped_file_error,
    )

    with pytest.raises(ClusterActionError, match=cluster_action_error):
        bucket_name = cluster.bucket.name
        assert_that(bucket_name).is_equal_to(
            "parallelcluster-a69601b5ee1fc2f2-v1-do-not-delete")
예제 #2
0
    def test_persist_stack_resources(self, cluster, mocker, template):
        """Verify that _persist_stack_resources behaves as expected."""
        mocker.patch("pcluster.models.cluster.Cluster._get_artifact_dir")
        mocker.patch("pcluster.models.cluster.Cluster._get_stack_template",
                     return_value=template)
        update_stack_template_mock = mocker.patch(
            "pcluster.models.cluster.Cluster._update_stack_template")
        mock_aws_api(mocker)
        mocker.patch("pcluster.aws.cfn.CfnClient.update_stack_from_url")
        mock_bucket(mocker)
        mock_bucket_utils(mocker)
        mock_bucket_object_utils(mocker)

        if "Resources" not in template:
            expected_error_message = "Resources"
        elif "key" not in template.get("Resources"):
            expected_error_message = "key"
        else:
            expected_error_message = None

        if expected_error_message:
            with pytest.raises(KeyError, match=expected_error_message):
                cluster._persist_stack_resources(["key"])
            assert_that(update_stack_template_mock.called).is_false()
        else:
            cluster._persist_stack_resources(["key"])
            assert_that(update_stack_template_mock.called).is_true()
            assert_that(cluster._get_stack_template()["Resources"]["key"]
                        ["DeletionPolicy"]).is_equal_to("Retain")
    def test_persist_cloudwatch_log_groups(self, cluster, mocker, caplog, template, expected_retain, fail_on_persist):
        """Verify that _persist_cloudwatch_log_groups behaves as expected."""
        mocker.patch("pcluster.models.cluster.Cluster._get_artifact_dir")
        mocker.patch("pcluster.models.cluster.Cluster._get_stack_template", return_value=template)

        client_error = AWSClientError("function", "Generic error.")
        update_template_mock = mocker.patch.object(
            cluster, "_update_stack_template", side_effect=client_error if fail_on_persist else None
        )
        mock_aws_api(mocker)
        mocker.patch("pcluster.aws.cfn.CfnClient.update_stack_from_url")
        mock_bucket(mocker)
        mock_bucket_utils(mocker)
        mock_bucket_object_utils(mocker)

        if expected_retain:
            keys = ["key"]
        else:
            keys = []
        get_unretained_cw_log_group_resource_keys_mock = mocker.patch.object(
            cluster, "_get_unretained_cw_log_group_resource_keys", return_value=keys
        )

        if fail_on_persist:
            with pytest.raises(ClusterActionError) as e:
                cluster._persist_cloudwatch_log_groups()
            assert_that(str(e)).contains("Unable to persist logs")
        else:
            cluster._persist_cloudwatch_log_groups()

        assert_that(get_unretained_cw_log_group_resource_keys_mock.call_count).is_equal_to(1)
        assert_that(update_template_mock.call_count).is_equal_to(1 if expected_retain else 0)
예제 #4
0
def test_setup_bucket_with_resources_upload_failure(mocker, cluster_name,
                                                    scheduler,
                                                    mock_generated_bucket_name,
                                                    expected_bucket_name,
                                                    provided_bucket_name):
    """Verify that create_bucket_with_batch_resources behaves as expected in case of upload failure."""
    upload_config_cluster_action_error = "Unable to upload cluster config to the S3 bucket"
    upload_resource_cluster_action_error = "Unable to upload cluster resources to the S3 bucket"
    upload_awsclient_error = AWSClientError(
        function_name="put_object",
        message="Unable to put file to the S3 bucket")
    upload_fileobj_awsclient_error = AWSClientError(
        function_name="upload_fileobj",
        message="Unable to upload file to the S3 bucket")

    mock_aws_api(mocker)

    # mock bucket initialization
    mock_bucket(mocker)

    # mock bucket utils
    check_bucket_mock = mock_bucket_utils(
        mocker,
        bucket_name=provided_bucket_name,
        root_service_dir=f"{cluster_name}-abc123",
    )["check_bucket_exists"]

    # mock bucket object utils
    mock_bucket_object_utils(
        mocker,
        upload_config_side_effect=upload_awsclient_error,
        upload_template_side_effect=upload_awsclient_error,
        upload_resources_side_effect=upload_fileobj_awsclient_error,
    )

    if provided_bucket_name:
        cluster = _mock_cluster(mocker, scheduler, provided_bucket_name)
        cluster.config.cluster_s3_bucket = provided_bucket_name
    else:
        cluster = _mock_cluster(mocker, scheduler)

    with pytest.raises(ClusterActionError,
                       match=upload_config_cluster_action_error):
        cluster._upload_config()

    with pytest.raises(ClusterActionError,
                       match=upload_resource_cluster_action_error):
        cluster._upload_artifacts()

    check_bucket_mock.assert_called_with()
예제 #5
0
def test_setup_bucket_with_resources_success(
    mocker,
    scheduler,
    cluster_name,
    expected_config,
    expected_template,
    expected_dirs,
    mock_generated_bucket_name,
    expected_bucket_name,
    provided_bucket_name,
):
    """Verify that create_bucket_with_batch_resources behaves as expected."""
    # mock calls for bucket property in cluster object
    artifact_dir = f"parallelcluster/clusters/{cluster_name}-abc123"

    mock_aws_api(mocker)

    # mock bucket initialization
    mock_bucket(mocker)

    # mock bucket object utils
    mock_dict = mock_bucket_object_utils(mocker)
    upload_config_mock = mock_dict.get("upload_config")
    upload_template_mock = mock_dict.get("upload_cfn_template")
    upload_custom_resources_mock = mock_dict.get("upload_resources")
    # mock bucket utils
    check_bucket_mock = mock_bucket_utils(
        mocker,
        root_service_dir=f"{cluster_name}-abc123")["check_bucket_exists"]

    if provided_bucket_name:
        cluster = _mock_cluster(mocker,
                                scheduler,
                                bucket_name=provided_bucket_name,
                                artifact_directory=artifact_dir)
        cluster.config.custom_s3_bucket = provided_bucket_name
    else:
        cluster = _mock_cluster(mocker,
                                scheduler,
                                bucket_name=mock_generated_bucket_name,
                                artifact_directory=artifact_dir)

    cluster.bucket.upload_config(expected_config, "fake_config_name")
    cluster.bucket.upload_cfn_template(expected_template, "fake_template_name")
    for dir in expected_dirs:
        cluster.bucket.upload_resources(dir)

    check_bucket_mock.assert_called_with()

    # assert upload has been called
    upload_config_mock.assert_called_with(expected_config, "fake_config_name")
    upload_template_mock.assert_called_with(expected_template,
                                            "fake_template_name")
    upload_custom_resources_mock.assert_has_calls(
        [mocker.call(dir) for dir in expected_dirs])

    # assert bucket properties
    assert_that(cluster.bucket.name).is_equal_to(expected_bucket_name)
    assert_that(cluster.bucket.artifact_directory).is_equal_to(artifact_dir)
    assert_that(cluster.bucket._root_directory).is_equal_to("parallelcluster")
예제 #6
0
    def test_update_stack_template(self, cluster, mocker, error_message):
        """Verify that _update_stack_template behaves as expected."""
        template_body = {"TemplateKey": "TemplateValue"}
        template_url = "https://{bucket_name}.s3.{region}.amazonaws.com{partition_suffix}/{template_key}"
        response = error_message or {"StackId": "stack ID"}

        mock_aws_api(mocker)
        mocker.patch("pcluster.aws.cfn.CfnClient.get_stack_template",
                     return_value=template_body)
        mocker.patch(
            "pcluster.aws.cfn.CfnClient.update_stack_from_url",
            return_value=response,
            expected_params={
                "stack_name": FAKE_NAME,
                "template_url": template_url,
            },
            side_effect=AWSClientError(function_name="update_stack_from_url",
                                       message=error_message)
            if error_message is not None else None,
        )

        # mock bucket initialize
        mock_bucket(mocker)
        # mock bucket utils
        mock_bucket_utils(mocker)
        # mock bucket object utils
        mock_bucket_object_utils(mocker)

        wait_for_update_mock = mocker.patch.object(cluster,
                                                   "_wait_for_stack_update")

        if error_message is None or "no updates are to be performed" in error_message.lower(
        ):
            cluster._update_stack_template(template_body)
            if error_message is None or "no updates are to be performed" not in error_message.lower(
            ):
                assert_that(wait_for_update_mock.called).is_true()
            else:
                assert_that(wait_for_update_mock.called).is_false()
        else:
            full_error_message = "Unable to update stack template for stack {stack_name}: {emsg}".format(
                stack_name=FAKE_NAME, emsg=error_message)
            with pytest.raises(AWSClientError,
                               match=full_error_message) as sysexit:
                cluster._update_stack_template(template_url)
            assert_that(sysexit.value.code).is_not_equal_to(0)