diff --git a/cli/src/pcluster/resources/compute_node/user_data.sh b/cli/src/pcluster/resources/compute_node/user_data.sh index 920cdfc445..5553f44c8b 100644 --- a/cli/src/pcluster/resources/compute_node/user_data.sh +++ b/cli/src/pcluster/resources/compute_node/user_data.sh @@ -59,66 +59,29 @@ datasource_list: [ Ec2, None ] output: all: "| tee -a /var/log/cloud-init-output.log | logger -t user-data -s 2>/dev/console" write_files: - - path: /tmp/dna.json - permissions: '0644' - owner: root:root - content: | - { - "cluster": { - "cluster_name": "${ClusterName}", - "stack_name": "${AWS::StackName}", - "stack_arn": "${AWS::StackId}", - "enable_efa": "${EnableEfa}", - "raid_shared_dir": "${RAIDSharedDir}", - "raid_type": "${RAIDType}", - "base_os": "${BaseOS}", - "region": "${AWS::Region}", - "shared_storage_type": "${SharedStorageType}", - "efs_fs_ids": "${EFSIds}", - "efs_shared_dirs": "${EFSSharedDirs}", - "efs_encryption_in_transits": "${EFSEncryptionInTransits}", - "efs_iam_authorizations": "${EFSIamAuthorizations}", - "fsx_fs_ids": "${FSXIds}", - "fsx_mount_names": "${FSXMountNames}", - "fsx_dns_names": "${FSXDNSNames}", - "fsx_volume_junction_paths": "${FSXVolumeJunctionPaths}", - "fsx_fs_types": "${FSXFileSystemTypes}", - "fsx_shared_dirs": "${FSXSharedDirs}", - "scheduler": "${Scheduler}", - "ephemeral_dir": "${EphemeralDir}", - "ebs_shared_dirs": "${EbsSharedDirs}", - "proxy": "${ProxyServer}", - "slurm_ddb_table": "${SlurmDynamoDBTable}", - "log_group_name": "${LogGroupName}", - "dns_domain": "${ClusterDNSDomain}", - "hosted_zone": "${ClusterHostedZone}", - "node_type": "ComputeFleet", - "cluster_user": "${OSUser}", - "enable_intel_hpc_platform": "${IntelHPCPlatform}", - "cw_logging_enabled": "${CWLoggingEnabled}", - "log_rotation_enabled": "${LogRotationEnabled}", - "scheduler_queue_name": "${QueueName}", - "scheduler_compute_resource_name": "${ComputeResourceName}", - "enable_efa_gdr": "${EnableEfaGdr}", - "custom_node_package": "${CustomNodePackage}", - "custom_awsbatchcli_package": "${CustomAwsBatchCliPackage}", - "use_private_hostname": "${UsePrivateHostname}", - "head_node_private_ip": "${HeadNodePrivateIp}", - "directory_service": { - "enabled": "${DirectoryServiceEnabled}" - }, - "disable_sudo_access_for_default_user":"${DisableSudoAccessForDefault}" - } - } - path: /etc/chef/client.rb permissions: '0644' owner: root:root content: cookbook_path ['/etc/chef/cookbooks'] - - path: /tmp/extra.json - permissions: '0644' + - path: /etc/cfn/cfn-hup.conf + permissions: '0400' owner: root:root content: | - ${ExtraJson} + [main] + stack=${AWS::StackId} + region=${AWS::Region} + url=${CloudFormationUrl} + role=${CfnInitRole} + interval=2 + - path: /etc/cfn/hooks.d/parallelcluster-update.conf + permissions: '0400' + owner: root:root + content: | + [parallelcluster-update] + triggers=post.update + path=Resources.${LaunchTemplateResourceId}.Metadata.AWS::CloudFormation::Init + action=PATH=/usr/local/bin:/bin:/usr/bin:/opt/aws/bin; . /etc/profile.d/pcluster.sh; cfn-init -v --stack ${AWS::StackName} --resource ${LaunchTemplateResourceId} --configsets update --region ${AWS::Region} --url ${CloudFormationUrl} --role ${CfnInitRole} + runas=root - path: /tmp/bootstrap.sh permissions: '0744' owner: root:root @@ -161,6 +124,10 @@ write_files: fi } + export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/aws/bin + + cfn-init -s ${AWS::StackName} -v -c deployFiles -r ${LaunchTemplateResourceId} --region ${AWS::Region} --url ${CloudFormationUrl} --role ${CfnInitRole} || error_exit 'Failed to bootstrap the compute node. Please check /var/log/cfn-init.log in the compute node, or check the cfn-init.log in CloudWatch logs. Please refer to https://docs.aws.amazon.com/parallelcluster/latest/ug/troubleshooting-v3.html#troubleshooting-v3-get-logs for more details on ParallelCluster logs.' + [ -f /etc/profile.d/proxy.sh ] && . /etc/profile.d/proxy.sh # Configure AWS CLI using the expected overrides, if any. @@ -187,7 +154,6 @@ write_files: cookbook_url=${!custom_cookbook} fi fi - export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/aws/bin export parallelcluster_version=aws-parallelcluster-${ParallelClusterVersion} export cookbook_version=${CookbookVersion} export chef_version=${ChefVersion} @@ -208,13 +174,9 @@ write_files: fi cd /tmp - mkdir -p /etc/chef/ohai/hints - touch /etc/chef/ohai/hints/ec2.json - # measure start time start=$(date +%s) - jq --argfile f1 /tmp/dna.json --argfile f2 /tmp/extra.json -n '$f1 * $f2' > /etc/chef/dna.json || ( echo "jq not installed or invalid extra_json"; cp /tmp/dna.json /etc/chef/dna.json) { pushd /etc/chef && cinc-client --local-mode --config /etc/chef/client.rb --log_level info --force-formatter --no-color --chef-zero-port 8889 --json-attributes /etc/chef/dna.json --override-runlist aws-parallelcluster-entrypoints::init && diff --git a/cli/src/pcluster/templates/cdk_builder_utils.py b/cli/src/pcluster/templates/cdk_builder_utils.py index 1a82fd4a99..c1a05ac417 100644 --- a/cli/src/pcluster/templates/cdk_builder_utils.py +++ b/cli/src/pcluster/templates/cdk_builder_utils.py @@ -967,6 +967,27 @@ def _build_policy(self) -> List[iam.PolicyStatement]: ) ], ), + iam.PolicyStatement( + sid="CloudFormation", + actions=[ + "cloudformation:DescribeStackResource", + ], + effect=iam.Effect.ALLOW, + resources=[ + self._format_arn(service="cloudformation", resource=f"stack/{Stack.of(self).stack_name}-*/*"), + ], + ), + iam.PolicyStatement( + sid="DynamoDBTable", + actions=["dynamodb:UpdateItem", "dynamodb:PutItem", "dynamodb:GetItem"], + effect=iam.Effect.ALLOW, + resources=[ + self._format_arn( + service="dynamodb", + resource=f"table/{PCLUSTER_DYNAMODB_PREFIX}{Stack.of(self).stack_name}", + ) + ], + ), ] diff --git a/cli/src/pcluster/templates/cluster_stack.py b/cli/src/pcluster/templates/cluster_stack.py index 5224da1b04..f2abf4411f 100644 --- a/cli/src/pcluster/templates/cluster_stack.py +++ b/cli/src/pcluster/templates/cluster_stack.py @@ -449,6 +449,7 @@ def _add_fleet_and_scheduler_resources(self, cleanup_lambda, cleanup_lambda_role dynamodb_table=self.scheduler_resources.dynamodb_table if self.scheduler_resources else None, head_eni=self._head_eni, slurm_construct=self.scheduler_resources, + cluster_bucket=self.bucket, ) def _add_login_nodes_resources(self): diff --git a/cli/src/pcluster/templates/compute_fleet_stack.py b/cli/src/pcluster/templates/compute_fleet_stack.py index ce7fc9b609..fea488e0e0 100644 --- a/cli/src/pcluster/templates/compute_fleet_stack.py +++ b/cli/src/pcluster/templates/compute_fleet_stack.py @@ -47,6 +47,7 @@ def __init__( dynamodb_table, head_eni, slurm_construct: SlurmConstruct, + cluster_bucket, ): super().__init__(scope, id) self._cleanup_lambda = cleanup_lambda @@ -61,6 +62,7 @@ def __init__( self._dynamodb_table = dynamodb_table self._head_eni = head_eni self._slurm_construct = slurm_construct + self._cluster_bucket = cluster_bucket self.launch_templates = {} self.managed_compute_fleet_instance_roles = {} @@ -95,6 +97,7 @@ def _add_resources(self): head_eni=self._head_eni, slurm_construct=self._slurm_construct, compute_security_group=self._compute_security_group, + cluster_bucket=self._cluster_bucket, ) self.managed_compute_fleet_instance_roles.update(queues_stack.managed_compute_instance_roles) diff --git a/cli/src/pcluster/templates/queues_stack.py b/cli/src/pcluster/templates/queues_stack.py index aa2d135aa1..7caa17e9d8 100644 --- a/cli/src/pcluster/templates/queues_stack.py +++ b/cli/src/pcluster/templates/queues_stack.py @@ -1,3 +1,4 @@ +import json from typing import Dict, List from aws_cdk import aws_ec2 as ec2 @@ -13,6 +14,7 @@ OS_MAPPING, PCLUSTER_COMPUTE_RESOURCE_NAME_TAG, PCLUSTER_QUEUE_NAME_TAG, + PCLUSTER_S3_ARTIFACTS_DICT, ) from pcluster.templates.cdk_builder_utils import ( CdkLaunchTemplateBuilder, @@ -30,7 +32,7 @@ to_comma_separated_string, ) from pcluster.templates.slurm_builder import SlurmConstruct -from pcluster.utils import get_attr, get_http_tokens_setting +from pcluster.utils import get_attr, get_http_tokens_setting, get_resource_name_from_resource_arn, get_service_endpoint class QueuesStack(NestedStack): @@ -51,6 +53,7 @@ def __init__( cluster_hosted_zone, dynamodb_table, head_eni, + cluster_bucket, ): super().__init__(scope, id) self._queues = queues @@ -64,6 +67,7 @@ def __init__( self._cluster_hosted_zone = cluster_hosted_zone self._dynamodb_table = dynamodb_table self._head_eni = head_eni + self._cluster_bucket = cluster_bucket self._launch_template_builder = CdkLaunchTemplateBuilder() self._add_resources() @@ -178,9 +182,24 @@ def _add_compute_resource_launch_template( if isinstance(compute_resource, SlurmComputeResource): conditional_template_properties.update({"instance_type": compute_resource.instance_types[0]}) - return ec2.CfnLaunchTemplate( + if queue.instance_profile: + instance_profile_name = get_resource_name_from_resource_arn(queue.instance_profile) + instance_role_name = ( + AWSApi.instance() + .iam.get_instance_profile(instance_profile_name) + .get("InstanceProfile") + .get("Roles")[0] + .get("RoleName") + ) + elif queue.instance_role: + instance_role_name = get_resource_name_from_resource_arn(queue.instance_role) + else: + instance_role_name = self.managed_compute_instance_roles[queue.name].ref + + launch_template_id = f"LaunchTemplate{create_hash_suffix(queue.name + compute_resource.name)}" + launch_template = ec2.CfnLaunchTemplate( self, - f"LaunchTemplate{create_hash_suffix(queue.name + compute_resource.name)}", + launch_template_id, launch_template_name=f"{self.stack_name}-{queue.name}-{compute_resource.name}", launch_template_data=ec2.CfnLaunchTemplate.LaunchTemplateDataProperty( block_device_mappings=self._launch_template_builder.get_block_device_mappings( @@ -210,86 +229,12 @@ def _add_compute_resource_launch_template( get_user_data_content("../resources/compute_node/user_data.sh"), { **{ - "EnableEfa": "efa" if compute_resource.efa and compute_resource.efa.enabled else "NONE", - "RAIDSharedDir": to_comma_separated_string( - self._shared_storage_mount_dirs[SharedStorageType.RAID] - ), - "RAIDType": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.RAID]["Type"] - ), "DisableMultiThreadingManually": "true" if compute_resource.disable_simultaneous_multithreading_manually else "false", "BaseOS": self._config.image.os, - "SharedStorageType": self._config.head_node.shared_storage_type.lower(), # noqa: E501 pylint: disable=line-too-long - "EFSIds": get_shared_storage_ids_by_type( - self._shared_storage_infos, SharedStorageType.EFS - ), - "EFSSharedDirs": to_comma_separated_string( - self._shared_storage_mount_dirs[SharedStorageType.EFS] - ), - "EFSEncryptionInTransits": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.EFS]["EncryptionInTransits"], - use_lower_case=True, - ), - "EFSIamAuthorizations": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.EFS]["IamAuthorizations"], - use_lower_case=True, - ), - "FSXIds": get_shared_storage_ids_by_type( - self._shared_storage_infos, SharedStorageType.FSX - ), - "FSXMountNames": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.FSX]["MountNames"] - ), - "FSXDNSNames": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.FSX]["DNSNames"] - ), - "FSXVolumeJunctionPaths": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.FSX]["VolumeJunctionPaths"] - ), - "FSXFileSystemTypes": to_comma_separated_string( - self._shared_storage_attributes[SharedStorageType.FSX]["FileSystemTypes"] - ), - "FSXSharedDirs": to_comma_separated_string( - self._shared_storage_mount_dirs[SharedStorageType.FSX] - ), - "Scheduler": self._config.scheduling.scheduler, - "EphemeralDir": queue.compute_settings.local_storage.ephemeral_volume.mount_dir - if isinstance(queue, SlurmQueue) - and queue.compute_settings.local_storage.ephemeral_volume - else DEFAULT_EPHEMERAL_DIR, - "EbsSharedDirs": to_comma_separated_string( - self._shared_storage_mount_dirs[SharedStorageType.EBS] - ), - "ClusterDNSDomain": str(self._cluster_hosted_zone.name) - if self._cluster_hosted_zone - else "", - "ClusterHostedZone": str(self._cluster_hosted_zone.ref) - if self._cluster_hosted_zone - else "", "OSUser": OS_MAPPING[self._config.image.os]["user"], "ClusterName": self.stack_name, - "SlurmDynamoDBTable": self._dynamodb_table.ref if self._dynamodb_table else "NONE", - "LogGroupName": self._log_group.log_group_name - if self._config.monitoring.logs.cloud_watch.enabled - else "NONE", - "IntelHPCPlatform": "true" if self._config.is_intel_hpc_platform_enabled else "false", - "CWLoggingEnabled": "true" if self._config.is_cw_logging_enabled else "false", - "LogRotationEnabled": "true" if self._config.is_log_rotation_enabled else "false", - "QueueName": queue.name, - "ComputeResourceName": compute_resource.name, - "EnableEfaGdr": "compute" - if compute_resource.efa and compute_resource.efa.gdr_support - else "NONE", - "CustomNodePackage": self._config.custom_node_package or "", - "CustomAwsBatchCliPackage": self._config.custom_aws_batch_cli_package or "", - "ExtraJson": self._config.extra_chef_attributes, - "UsePrivateHostname": str( - get_attr(self._config, "scheduling.settings.dns.use_ec2_hostnames", default=False) - ).lower(), - "HeadNodePrivateIp": self._head_eni.attr_primary_private_ip_address, - "DirectoryServiceEnabled": str(self._config.directory_service is not None).lower(), "Timeout": str( get_attr( self._config, @@ -304,9 +249,9 @@ def _add_compute_resource_launch_template( default=False, ) ), - "DisableSudoAccessForDefault": "true" - if self._config.disable_sudo_access_default_user - else "false", + "LaunchTemplateResourceId": launch_template_id, + "CloudFormationUrl": get_service_endpoint("cloudformation", self._config.region), + "CfnInitRole": instance_role_name, }, **get_common_user_data_env(queue, self._config), }, @@ -334,3 +279,151 @@ def _add_compute_resource_launch_template( **conditional_template_properties, ), ) + + dna_json = json.dumps( + { + "cluster": { + "cluster_name": self.stack_name, + "stack_name": self.stack_name, + "stack_arn": self.stack_id, + "cluster_s3_bucket": self._cluster_bucket.name, + "cluster_config_s3_key": "{0}/configs/{1}".format( + self._cluster_bucket.artifact_directory, PCLUSTER_S3_ARTIFACTS_DICT.get("config_name") + ), + "cluster_config_version": self._config.config_version, + "enable_efa": "efa" if compute_resource.efa and compute_resource.efa.enabled else "NONE", + "raid_shared_dir": to_comma_separated_string( + self._shared_storage_mount_dirs[SharedStorageType.RAID] + ), + "raid_type": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.RAID]["Type"] + ), + "base_os": self._config.image.os, + "region": self._config.region, + "shared_storage_type": self._config.head_node.shared_storage_type.lower(), # noqa: E501 pylint: disable=line-too-long + "efs_fs_ids": get_shared_storage_ids_by_type(self._shared_storage_infos, SharedStorageType.EFS), + "efs_shared_dirs": to_comma_separated_string( + self._shared_storage_mount_dirs[SharedStorageType.EFS] + ), + "efs_encryption_in_transits": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.EFS]["EncryptionInTransits"], + use_lower_case=True, + ), + "efs_iam_authorizations": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.EFS]["IamAuthorizations"], + use_lower_case=True, + ), + "fsx_fs_ids": get_shared_storage_ids_by_type(self._shared_storage_infos, SharedStorageType.FSX), + "fsx_mount_names": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.FSX]["MountNames"] + ), + "fsx_dns_names": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.FSX]["DNSNames"] + ), + "fsx_volume_junction_paths": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.FSX]["VolumeJunctionPaths"] + ), + "fsx_fs_types": to_comma_separated_string( + self._shared_storage_attributes[SharedStorageType.FSX]["FileSystemTypes"] + ), + "fsx_shared_dirs": to_comma_separated_string( + self._shared_storage_mount_dirs[SharedStorageType.FSX] + ), + "scheduler": self._config.scheduling.scheduler, + "ephemeral_dir": queue.compute_settings.local_storage.ephemeral_volume.mount_dir + if isinstance(queue, SlurmQueue) and queue.compute_settings.local_storage.ephemeral_volume + else DEFAULT_EPHEMERAL_DIR, + "ebs_shared_dirs": to_comma_separated_string( + self._shared_storage_mount_dirs[SharedStorageType.EBS] + ), + "proxy": queue.networking.proxy.http_proxy_address if queue.networking.proxy else "NONE", + "slurm_ddb_table": self._dynamodb_table.ref if self._dynamodb_table else "NONE", + "log_group_name": self._log_group.log_group_name + if self._config.monitoring.logs.cloud_watch.enabled + else "NONE", + "dns_domain": str(self._cluster_hosted_zone.name) if self._cluster_hosted_zone else "", + "hosted_zone": str(self._cluster_hosted_zone.ref) if self._cluster_hosted_zone else "", + "node_type": "ComputeFleet", + "cluster_user": OS_MAPPING[self._config.image.os]["user"], + "enable_intel_hpc_platform": "true" if self._config.is_intel_hpc_platform_enabled else "false", + "cw_logging_enabled": "true" if self._config.is_cw_logging_enabled else "false", + "log_rotation_enabled": "true" if self._config.is_log_rotation_enabled else "false", + "scheduler_queue_name": queue.name, + "scheduler_compute_resource_name": compute_resource.name, + "enable_efa_gdr": "compute" + if compute_resource.efa and compute_resource.efa.gdr_support + else "NONE", + "custom_node_package": self._config.custom_node_package or "", + "custom_awsbatchcli_package": self._config.custom_aws_batch_cli_package or "", + "use_private_hostname": str( + get_attr(self._config, "scheduling.settings.dns.use_ec2_hostnames", default=False) + ).lower(), + "head_node_private_ip": self._head_eni.attr_primary_private_ip_address, + "directory_service": {"enabled": str(self._config.directory_service is not None).lower()}, + "disable_sudo_access_for_default_user": "true" + if self._config.disable_sudo_access_default_user + else "false", + } + }, + indent=4, + ) + + cfn_init = { + "configSets": { + "deployFiles": ["deployConfigFiles"], + "update": ["deployConfigFiles", "chefUpdate"], + }, + "deployConfigFiles": { + "files": { + # A nosec comment is appended to the following line in order to disable the B108 check. + # The file is needed by the product + # [B108:hardcoded_tmp_directory] Probable insecure usage of temp file/directory. + "/tmp/dna.json": { # nosec B108 + "content": dna_json, + "mode": "000644", + "owner": "root", + "group": "root", + "encoding": "plain", + }, + # A nosec comment is appended to the following line in order to disable the B108 check. + # The file is needed by the product + # [B108:hardcoded_tmp_directory] Probable insecure usage of temp file/directory. + "/tmp/extra.json": { # nosec B108 + "mode": "000644", + "owner": "root", + "group": "root", + "content": self._config.extra_chef_attributes, + }, + }, + "commands": { + "mkdir": {"command": "mkdir -p /etc/chef/ohai/hints"}, + "touch": {"command": "touch /etc/chef/ohai/hints/ec2.json"}, + "jq": { + "command": ( + "jq --argfile f1 /tmp/dna.json --argfile f2 /tmp/extra.json -n '$f1 * $f2' " + "> /etc/chef/dna.json " + '|| ( echo "jq not installed"; cp /tmp/dna.json /etc/chef/dna.json )' + ) + }, + }, + }, + "chefUpdate": { + "commands": { + "chef": { + "command": ( + ". /etc/profile.d/pcluster.sh; " + "cinc-client --local-mode --config /etc/chef/client.rb --log_level info" + " --logfile /var/log/chef-client.log --force-formatter --no-color" + " --chef-zero-port 8889 --json-attributes /etc/chef/dna.json" + " --override-runlist aws-parallelcluster-entrypoints::update &&" + " /opt/parallelcluster/scripts/fetch_and_run -postupdate" + ), + "cwd": "/etc/chef", + } + } + }, + } + + launch_template.add_metadata("AWS::CloudFormation::Init", cfn_init) + + return launch_template diff --git a/cli/tests/pcluster/aws/dummy_aws_api.py b/cli/tests/pcluster/aws/dummy_aws_api.py index 602288c131..797fedb995 100644 --- a/cli/tests/pcluster/aws/dummy_aws_api.py +++ b/cli/tests/pcluster/aws/dummy_aws_api.py @@ -326,6 +326,27 @@ def __init__(self): """Override Parent constructor. No real boto3 client is created.""" pass + def get_instance_profile(self, instance_profile_name): + return { + "InstanceProfile": { + "InstanceProfileId": "XXXXXXXXXX", + "Roles": [ + { + "AssumeRolePolicyDocument": "", + "RoleId": "XXXXXXXXXX", + "CreateDate": "2024-01-10T06:33:26Z", + "RoleName": "Mocked-RoleName", + "Path": "/", + "Arn": "arn:aws:iam::XXXXXXXXXXXX:role/Mocked-RoleName", + } + ], + "CreateDate": "2024-01-10T06:33:26Z", + "InstanceProfileName": instance_profile_name, + "Path": "/", + "Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/instance_profile_name", + } + } + class _DummyDynamoResource(DynamoResource): def __init__(self): diff --git a/cli/tests/pcluster/templates/test_cluster_stack.py b/cli/tests/pcluster/templates/test_cluster_stack.py index a8a0c12be8..0bcfba3c73 100644 --- a/cli/tests/pcluster/templates/test_cluster_stack.py +++ b/cli/tests/pcluster/templates/test_cluster_stack.py @@ -28,7 +28,6 @@ MAX_EXISTING_STORAGE_COUNT, MAX_NEW_STORAGE_COUNT, MAX_NUMBER_OF_COMPUTE_RESOURCES_PER_CLUSTER, - MAX_NUMBER_OF_QUEUES, ) from pcluster.models.s3_bucket import S3FileFormat, format_content from pcluster.schemas.cluster_schema import ClusterSchema @@ -130,11 +129,14 @@ def test_cluster_config_limits(mocker, capsys, tmpdir, pcluster_config_reader, t mock_bucket(mocker) mock_bucket_object_utils(mocker) + # TODO We must restore the actual maximum defined in constants.MAX_NUMBER_OF_QUEUES, which is 50. + max_number_of_queues = 46 + # The max number of queues cannot be used with the max number of compute resources # (it will exceed the max number of compute resources per cluster) # This workaround calculates the number of compute resources to use # as the quotient of dividing the max number of compute resources per cluster by the MAX_NUMBER_OF_QUEUES. - max_number_of_crs = MAX_NUMBER_OF_COMPUTE_RESOURCES_PER_CLUSTER // MAX_NUMBER_OF_QUEUES + max_number_of_crs = MAX_NUMBER_OF_COMPUTE_RESOURCES_PER_CLUSTER // max_number_of_queues # Try to search for jinja templates in the test_datadir, this is mainly to verify pcluster limits rendered_config_file = pcluster_config_reader( @@ -143,7 +145,7 @@ def test_cluster_config_limits(mocker, capsys, tmpdir, pcluster_config_reader, t max_new_storage_count=MAX_NEW_STORAGE_COUNT, max_existing_storage_count=MAX_EXISTING_STORAGE_COUNT, # number of queues, compute resources and security groups highly impacts the size of AWS resources - max_number_of_queues=MAX_NUMBER_OF_QUEUES, + max_number_of_queues=max_number_of_queues, max_number_of_ondemand_crs=max_number_of_crs, max_number_of_spot_crs=max_number_of_crs, number_of_sg_per_queue=1, @@ -403,6 +405,17 @@ def test_compute_launch_template_properties( for lt_assertion in lt_assertions: lt_assertion.assert_lt_properties(asset_content, launch_template_logical_id) + # Checking user data variables + user_data_variables = asset_content["Resources"][launch_template_logical_id]["Properties"]["LaunchTemplateData"][ + "UserData" + ]["Fn::Base64"]["Fn::Sub"][1] + expected_user_data_variables = { + "CloudFormationUrl": "https://cloudformation.us-east-1.amazonaws.com", + "LaunchTemplateResourceId": launch_template_logical_id, + } + for k, v in expected_user_data_variables.items(): + assert_that(user_data_variables[k]).is_equal_to(v) + class LoginNodeLTAssertion: def __init__( diff --git a/cli/tests/pcluster/templates/test_cluster_stack/test_cluster_config_limits/slurm.full_config.snapshot.yaml b/cli/tests/pcluster/templates/test_cluster_stack/test_cluster_config_limits/slurm.full_config.snapshot.yaml index 72cd176f8b..7f9f376fef 100644 --- a/cli/tests/pcluster/templates/test_cluster_stack/test_cluster_config_limits/slurm.full_config.snapshot.yaml +++ b/cli/tests/pcluster/templates/test_cluster_stack/test_cluster_config_limits/slurm.full_config.snapshot.yaml @@ -1932,162 +1932,6 @@ Scheduling: Tags: - Key: String0 Value: String0 - - CapacityReservationTarget: null - CapacityType: ONDEMAND - ComputeResources: - - CapacityReservationTarget: null - CustomSlurmSettings: {} - DisableSimultaneousMultithreading: false - DynamicNodePriority: 1000 - Efa: - Enabled: false - GdrSupport: false - HealthChecks: - Gpu: - Enabled: null - InstanceType: c5.xlarge - MaxCount: 10 - MinCount: 0 - Name: compute-resource-ondemand-230 - Networking: - PlacementGroup: - Enabled: null - Id: null - Name: null - SchedulableMemory: null - SpotPrice: null - StaticNodePriority: 1 - Tags: - - Key: computetag0 - Value: computetag0 - ComputeSettings: - LocalStorage: - EphemeralVolume: null - RootVolume: - Encrypted: true - Iops: 3000 - Size: null - Throughput: 125 - VolumeType: gp3 - CustomActions: - OnNodeConfigured: - Args: - - arg0 - Script: https://test.tgz - OnNodeStart: - Args: - - arg0 - Script: https://test.tgz - CustomSlurmSettings: {} - HealthChecks: - Gpu: - Enabled: null - Iam: - AdditionalIamPolicies: - - Policy: arn:aws:iam::aws:policy/AdministratorAccess - InstanceProfile: null - InstanceRole: null - S3Access: - - BucketName: string1 - EnableWriteAccess: false - KeyName: null - Image: - CustomAmi: ami-12345678 - JobExclusiveAllocation: false - Name: queue-ondemand-23 - Networking: - AdditionalSecurityGroups: null - AssignPublicIp: null - PlacementGroup: - Enabled: null - Id: null - Name: null - Proxy: null - SecurityGroups: - - sg-34567890 - SubnetIds: - - subnet-12345678 - Tags: - - Key: String0 - Value: String0 - - CapacityReservationTarget: null - CapacityType: ONDEMAND - ComputeResources: - - CapacityReservationTarget: null - CustomSlurmSettings: {} - DisableSimultaneousMultithreading: false - DynamicNodePriority: 1000 - Efa: - Enabled: false - GdrSupport: false - HealthChecks: - Gpu: - Enabled: null - InstanceType: c5.xlarge - MaxCount: 10 - MinCount: 0 - Name: compute-resource-ondemand-240 - Networking: - PlacementGroup: - Enabled: null - Id: null - Name: null - SchedulableMemory: null - SpotPrice: null - StaticNodePriority: 1 - Tags: - - Key: computetag0 - Value: computetag0 - ComputeSettings: - LocalStorage: - EphemeralVolume: null - RootVolume: - Encrypted: true - Iops: 3000 - Size: null - Throughput: 125 - VolumeType: gp3 - CustomActions: - OnNodeConfigured: - Args: - - arg0 - Script: https://test.tgz - OnNodeStart: - Args: - - arg0 - Script: https://test.tgz - CustomSlurmSettings: {} - HealthChecks: - Gpu: - Enabled: null - Iam: - AdditionalIamPolicies: - - Policy: arn:aws:iam::aws:policy/AdministratorAccess - InstanceProfile: null - InstanceRole: null - S3Access: - - BucketName: string1 - EnableWriteAccess: false - KeyName: null - Image: - CustomAmi: ami-12345678 - JobExclusiveAllocation: false - Name: queue-ondemand-24 - Networking: - AdditionalSecurityGroups: null - AssignPublicIp: null - PlacementGroup: - Enabled: null - Id: null - Name: null - Proxy: null - SecurityGroups: - - sg-34567890 - SubnetIds: - - subnet-12345678 - Tags: - - Key: String0 - Value: String0 - CapacityReservationTarget: null CapacityType: ONDEMAND ComputeResources: @@ -3652,142 +3496,6 @@ Scheduling: Tags: - Key: String0 Value: String0 - - CapacityReservationTarget: null - CapacityType: ONDEMAND - ComputeResources: - - CapacityReservationTarget: null - CustomSlurmSettings: {} - DisableSimultaneousMultithreading: true - DynamicNodePriority: 1000 - Efa: - Enabled: true - GdrSupport: false - HealthChecks: - Gpu: - Enabled: null - InstanceType: c5.2xlarge - MaxCount: 15 - MinCount: 1 - Name: compute-resource-spot-230 - Networking: - PlacementGroup: - Enabled: true - Id: String - Name: null - SchedulableMemory: null - SpotPrice: 1.1 - StaticNodePriority: 1 - Tags: - - Key: computetag0 - Value: computetag0 - ComputeSettings: - LocalStorage: - EphemeralVolume: - MountDir: /scratch - RootVolume: - Encrypted: true - Iops: 100 - Size: 35 - Throughput: null - VolumeType: gp2 - CustomActions: null - CustomSlurmSettings: {} - HealthChecks: - Gpu: - Enabled: null - Iam: - AdditionalIamPolicies: [] - InstanceProfile: arn:aws:iam::aws:instance-profile/CustomNodeInstanceProfile - InstanceRole: null - S3Access: null - Image: - CustomAmi: ami-23456789 - JobExclusiveAllocation: false - Name: queue-spot-23 - Networking: - AdditionalSecurityGroups: null - AssignPublicIp: true - PlacementGroup: - Enabled: true - Id: String - Name: null - Proxy: - HttpProxyAddress: https://proxy-address:port - SecurityGroups: - - sg-34567890 - SubnetIds: - - subnet-12345678 - Tags: - - Key: String0 - Value: String0 - - CapacityReservationTarget: null - CapacityType: ONDEMAND - ComputeResources: - - CapacityReservationTarget: null - CustomSlurmSettings: {} - DisableSimultaneousMultithreading: true - DynamicNodePriority: 1000 - Efa: - Enabled: true - GdrSupport: false - HealthChecks: - Gpu: - Enabled: null - InstanceType: c5.2xlarge - MaxCount: 15 - MinCount: 1 - Name: compute-resource-spot-240 - Networking: - PlacementGroup: - Enabled: true - Id: String - Name: null - SchedulableMemory: null - SpotPrice: 1.1 - StaticNodePriority: 1 - Tags: - - Key: computetag0 - Value: computetag0 - ComputeSettings: - LocalStorage: - EphemeralVolume: - MountDir: /scratch - RootVolume: - Encrypted: true - Iops: 100 - Size: 35 - Throughput: null - VolumeType: gp2 - CustomActions: null - CustomSlurmSettings: {} - HealthChecks: - Gpu: - Enabled: null - Iam: - AdditionalIamPolicies: [] - InstanceProfile: arn:aws:iam::aws:instance-profile/CustomNodeInstanceProfile - InstanceRole: null - S3Access: null - Image: - CustomAmi: ami-23456789 - JobExclusiveAllocation: false - Name: queue-spot-24 - Networking: - AdditionalSecurityGroups: null - AssignPublicIp: true - PlacementGroup: - Enabled: true - Id: String - Name: null - Proxy: - HttpProxyAddress: https://proxy-address:port - SecurityGroups: - - sg-34567890 - SubnetIds: - - subnet-12345678 - Tags: - - Key: String0 - Value: String0 SlurmSettings: CustomSlurmSettings: null CustomSlurmSettingsIncludeFile: null diff --git a/cli/tests/pcluster/templates/test_queues_stack.py b/cli/tests/pcluster/templates/test_queues_stack.py new file mode 100644 index 0000000000..7fafbb9560 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack.py @@ -0,0 +1,181 @@ +import json + +import pytest +from assertpy import assert_that +from freezegun import freeze_time + +from pcluster.schemas.cluster_schema import ClusterSchema +from pcluster.templates.cdk_builder import CDKTemplateBuilder +from pcluster.utils import load_json_dict, load_yaml_dict +from tests.pcluster.aws.dummy_aws_api import mock_aws_api +from tests.pcluster.models.dummy_s3_bucket import dummy_cluster_bucket, mock_bucket_object_utils +from tests.pcluster.templates.test_cluster_stack import IamPolicyAssertion, get_generated_template_and_cdk_assets +from tests.pcluster.utils import get_asset_content_with_resource_name + + +@pytest.mark.parametrize( + "config_file_name, iam_policy_assertions", + [ + ( + "config.yaml", + [ + IamPolicyAssertion( + expected_statements=[ + { + "Action": "ec2:DescribeInstanceAttribute", + "Effect": "Allow", + "Resource": "*", + "Sid": "Ec2", + }, + { + "Action": "s3:GetObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + {"Ref": "AWS::Partition"}, + ":s3:::", + {"Ref": "AWS::Region"}, + "-aws-parallelcluster/*", + ], + ] + }, + "Sid": "S3GetObj", + }, + { + "Action": "cloudformation:DescribeStackResource", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + {"Ref": "AWS::Partition"}, + ":cloudformation:", + {"Ref": "AWS::Region"}, + ":", + {"Ref": "AWS::AccountId"}, + ":stack/clustername-*/*", + ], + ] + }, + "Sid": "CloudFormation", + }, + { + "Action": [ + "dynamodb:UpdateItem", + "dynamodb:PutItem", + "dynamodb:GetItem", + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + {"Ref": "AWS::Partition"}, + ":dynamodb:", + {"Ref": "AWS::Region"}, + ":", + {"Ref": "AWS::AccountId"}, + ":table/parallelcluster-clustername", + ], + ] + }, + "Sid": "DynamoDBTable", + }, + ] + ), + ], + ), + ], +) +def test_compute_nodes_iam_permissions( + mocker, + config_file_name, + iam_policy_assertions, + test_datadir, +): + generated_template, cdk_assets = get_generated_template_and_cdk_assets( + mocker, + config_file_name, + test_datadir, + ) + + asset_content_iam_policies = get_asset_content_with_resource_name( + cdk_assets, + "ParallelClusterPolicies15b342af42246b70", + ) + for iam_policy_assertion in iam_policy_assertions: + iam_policy_assertion.assert_iam_policy_properties( + asset_content_iam_policies, "ParallelClusterPolicies15b342af42246b70" + ) + + +@freeze_time("2024-01-15T15:30:45") +@pytest.mark.parametrize( + "config_file_name, expected_compute_node_dna_json_file_name, expected_compute_node_extra_json_file_name", + [ + ("config-1.yaml", "dna-1.json", "extra-1.json"), + ("config-2.yaml", "dna-2.json", "extra-2.json"), + ], +) +def test_compute_nodes_dna_json( + mocker, + test_datadir, + config_file_name, + expected_compute_node_dna_json_file_name, + expected_compute_node_extra_json_file_name, +): + mock_aws_api(mocker) + mock_bucket_object_utils(mocker) + + # Read yaml and render CF Template + input_yaml = load_yaml_dict(test_datadir / config_file_name) + cluster_config = ClusterSchema(cluster_name="clustername").load(input_yaml) + _, cdk_assets = CDKTemplateBuilder().build_cluster_template( + cluster_config=cluster_config, bucket=dummy_cluster_bucket(), stack_name="clustername" + ) + + # Generated dna.json and extra.json + compute_node_lt_asset = get_asset_content_with_resource_name(cdk_assets, "LaunchTemplateA7211c84b953696f") + compute_node_lt = compute_node_lt_asset["Resources"]["LaunchTemplateA7211c84b953696f"] + compute_node_cfn_init_files = compute_node_lt["Metadata"]["AWS::CloudFormation::Init"]["deployConfigFiles"]["files"] + compute_node_dna_json = compute_node_cfn_init_files["/tmp/dna.json"] + compute_node_extra_json = compute_node_cfn_init_files["/tmp/extra.json"] + + # Expected dna.json and extra.json + expected_compute_node_dna_json = load_json_dict(test_datadir / expected_compute_node_dna_json_file_name) + expected_compute_node_extra_json = load_json_dict(test_datadir / expected_compute_node_extra_json_file_name) + expected_owner = expected_group = "root" + expected_mode = "000644" + + # Assertions on dna.json + rendered_dna_json_content = render_join(compute_node_dna_json["content"]["Fn::Join"]) + rendered_dna_json_content_as_json = json.loads(rendered_dna_json_content) + assert_that(compute_node_dna_json["owner"]).is_equal_to(expected_owner) + assert_that(compute_node_dna_json["group"]).is_equal_to(expected_group) + assert_that(compute_node_dna_json["mode"]).is_equal_to(expected_mode) + assert_that(rendered_dna_json_content_as_json).is_equal_to(expected_compute_node_dna_json) + + # Assertions on extra.json + assert_that(compute_node_extra_json["owner"]).is_equal_to(expected_owner) + assert_that(compute_node_extra_json["group"]).is_equal_to(expected_group) + assert_that(compute_node_extra_json["mode"]).is_equal_to(expected_mode) + assert_that(json.loads(compute_node_extra_json["content"])).is_equal_to(expected_compute_node_extra_json) + + +def render_join(elem: dict): + sep = str(elem[0]) + body = elem[1] + rendered_body = [] + for item in body: + if isinstance(item, str): + rendered_body.append(str(item).strip()) + elif isinstance(item, dict): + rendered_body.append(str(json.dumps(item).replace('"', '\\"')).strip()) + else: + raise ValueError("Found unsupported item type while rendering Fn::Join") + return sep.join(rendered_body) diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-1.yaml b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-1.yaml new file mode 100644 index 0000000000..091793b698 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-1.yaml @@ -0,0 +1,21 @@ +Region: eu-west-1 +Image: + Os: alinux2 +HeadNode: + InstanceType: t2.micro + Networking: + SubnetId: subnet-12345678 + Ssh: + KeyName: ec2-key-name +Scheduling: + Scheduler: slurm + SlurmQueues: + - Name: queue1 + ComputeResources: + - Name: cr1 + InstanceType: c4.xlarge + MinCount: 0 + MaxCount: 10 + Networking: + SubnetIds: + - subnet-12345678 diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-2.yaml b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-2.yaml new file mode 100644 index 0000000000..e1f61bf3e2 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/config-2.yaml @@ -0,0 +1,28 @@ +Region: eu-west-1 +Image: + Os: alinux2 +HeadNode: + InstanceType: t2.micro + Networking: + SubnetId: subnet-12345678 + Ssh: + KeyName: ec2-key-name +Scheduling: + Scheduler: slurm + SlurmQueues: + - Name: queue1 + ComputeResources: + - Name: cr1 + InstanceType: c4.xlarge + MinCount: 0 + MaxCount: 10 + Networking: + SubnetIds: + - subnet-12345678 +DirectoryService: + DomainName: corp.pcluster.com + DomainAddr: ldaps://corp.pcluster.com + PasswordSecretArn: arn:aws:secretsmanager:eu-west-1:XXXXXXXXXXXX:secret:XXXXXXXXXX + DomainReadOnlyUser: cn=ReadOnlyUser,ou=Users,ou=CORP,dc=corp,dc=pcluster,dc=com + LdapTlsReqCert: never + GenerateSshKeysForUsers: true \ No newline at end of file diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-1.json b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-1.json new file mode 100644 index 0000000000..07f7863b65 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-1.json @@ -0,0 +1,50 @@ +{ + "cluster": { + "cluster_name": "clustername", + "stack_name": "clustername", + "stack_arn": "{\"Ref\": \"AWS::StackId\"}", + "cluster_s3_bucket": "parallelcluster-a69601b5ee1fc2f2-v1-do-not-delete", + "cluster_config_s3_key": "parallelcluster/clusters/dummy-cluster-randomstring123/configs/cluster-config-with-implied-values.yaml", + "cluster_config_version": "", + "enable_efa": "NONE", + "raid_shared_dir": "", + "raid_type": "", + "base_os": "alinux2", + "region": "us-east-1", + "shared_storage_type": "ebs", + "efs_fs_ids": "", + "efs_shared_dirs": "", + "efs_encryption_in_transits": "", + "efs_iam_authorizations": "", + "fsx_fs_ids": "", + "fsx_mount_names": "", + "fsx_dns_names": "", + "fsx_volume_junction_paths": "", + "fsx_fs_types": "", + "fsx_shared_dirs": "", + "scheduler": "slurm", + "ephemeral_dir": "/scratch", + "ebs_shared_dirs": "", + "proxy": "NONE", + "slurm_ddb_table": "{\"Ref\": \"referencetoclusternameSlurmDynamoDBTable99119DBERef\"}", + "log_group_name": "/aws/parallelcluster/clustername-202401151530", + "dns_domain": "{\"Ref\": \"referencetoclusternameClusterDNSDomain8D0872E1Ref\"}", + "hosted_zone": "{\"Ref\": \"referencetoclusternameRoute53HostedZone2388733DRef\"}", + "node_type": "ComputeFleet", + "cluster_user": "ec2-user", + "enable_intel_hpc_platform": "false", + "cw_logging_enabled": "true", + "log_rotation_enabled": "true", + "scheduler_queue_name": "queue1", + "scheduler_compute_resource_name": "cr1", + "enable_efa_gdr": "NONE", + "custom_node_package": "", + "custom_awsbatchcli_package": "", + "use_private_hostname": "false", + "head_node_private_ip": "{\"Ref\": \"referencetoclusternameHeadNodeENI6497A502PrimaryPrivateIpAddress\"}", + "directory_service": { + "enabled": "false" + }, + "disable_sudo_access_for_default_user": "false" + } +} \ No newline at end of file diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-2.json b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-2.json new file mode 100644 index 0000000000..d27ffbdbd9 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/dna-2.json @@ -0,0 +1,50 @@ +{ + "cluster": { + "cluster_name": "clustername", + "stack_name": "clustername", + "stack_arn": "{\"Ref\": \"AWS::StackId\"}", + "cluster_s3_bucket": "parallelcluster-a69601b5ee1fc2f2-v1-do-not-delete", + "cluster_config_s3_key": "parallelcluster/clusters/dummy-cluster-randomstring123/configs/cluster-config-with-implied-values.yaml", + "cluster_config_version": "", + "enable_efa": "NONE", + "raid_shared_dir": "", + "raid_type": "", + "base_os": "alinux2", + "region": "us-east-1", + "shared_storage_type": "ebs", + "efs_fs_ids": "", + "efs_shared_dirs": "", + "efs_encryption_in_transits": "", + "efs_iam_authorizations": "", + "fsx_fs_ids": "", + "fsx_mount_names": "", + "fsx_dns_names": "", + "fsx_volume_junction_paths": "", + "fsx_fs_types": "", + "fsx_shared_dirs": "", + "scheduler": "slurm", + "ephemeral_dir": "/scratch", + "ebs_shared_dirs": "", + "proxy": "NONE", + "slurm_ddb_table": "{\"Ref\": \"referencetoclusternameSlurmDynamoDBTable99119DBERef\"}", + "log_group_name": "/aws/parallelcluster/clustername-202401151530", + "dns_domain": "{\"Ref\": \"referencetoclusternameClusterDNSDomain8D0872E1Ref\"}", + "hosted_zone": "{\"Ref\": \"referencetoclusternameRoute53HostedZone2388733DRef\"}", + "node_type": "ComputeFleet", + "cluster_user": "ec2-user", + "enable_intel_hpc_platform": "false", + "cw_logging_enabled": "true", + "log_rotation_enabled": "true", + "scheduler_queue_name": "queue1", + "scheduler_compute_resource_name": "cr1", + "enable_efa_gdr": "NONE", + "custom_node_package": "", + "custom_awsbatchcli_package": "", + "use_private_hostname": "false", + "head_node_private_ip": "{\"Ref\": \"referencetoclusternameHeadNodeENI6497A502PrimaryPrivateIpAddress\"}", + "directory_service": { + "enabled": "true" + }, + "disable_sudo_access_for_default_user": "false" + } +} \ No newline at end of file diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-1.json b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-1.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-1.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-2.json b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-2.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_dna_json/extra-2.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_iam_permissions/config.yaml b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_iam_permissions/config.yaml new file mode 100644 index 0000000000..091793b698 --- /dev/null +++ b/cli/tests/pcluster/templates/test_queues_stack/test_compute_nodes_iam_permissions/config.yaml @@ -0,0 +1,21 @@ +Region: eu-west-1 +Image: + Os: alinux2 +HeadNode: + InstanceType: t2.micro + Networking: + SubnetId: subnet-12345678 + Ssh: + KeyName: ec2-key-name +Scheduling: + Scheduler: slurm + SlurmQueues: + - Name: queue1 + ComputeResources: + - Name: cr1 + InstanceType: c4.xlarge + MinCount: 0 + MaxCount: 10 + Networking: + SubnetIds: + - subnet-12345678 diff --git a/cli/tests/pcluster/validators/test_iam_validators.py b/cli/tests/pcluster/validators/test_iam_validators.py index cb6c65c779..cf9e8e6ad0 100644 --- a/cli/tests/pcluster/validators/test_iam_validators.py +++ b/cli/tests/pcluster/validators/test_iam_validators.py @@ -73,7 +73,6 @@ def test_role_validator(mocker, role_arn, side_effect, expected_message): ], ) def test_instance_profile_validator(mocker, instance_profile_arn, side_effect, expected_message): - mock_aws_api(mocker) mocker.patch("pcluster.aws.iam.IamClient.get_instance_profile", side_effect=side_effect) actual_failures = InstanceProfileValidator().execute(instance_profile_arn=instance_profile_arn)