Skip to content

Commit

Permalink
[DFSM][Test] Add unit tests to cover dna.json and iam permissions for…
Browse files Browse the repository at this point in the history
… compute nodes.

Signed-off-by: Giacomo Marciani <[email protected]>
  • Loading branch information
gmarciani committed Jan 16, 2024
1 parent cab5ff5 commit f22c6d0
Show file tree
Hide file tree
Showing 10 changed files with 359 additions and 6 deletions.
4 changes: 2 additions & 2 deletions cli/tests/pcluster/aws/dummy_aws_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,13 @@ def get_instance_profile(self, instance_profile_name):
"CreateDate": "2024-01-10T06:33:26Z",
"RoleName": "Mocked-RoleName",
"Path": "/",
"Arn": "arn:aws:iam::XXXXXXXXXXXX:role/Mocked-RoleName"
"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"
"Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/instance_profile_name",
}
}

Expand Down
8 changes: 4 additions & 4 deletions cli/tests/pcluster/templates/test_cluster_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -130,7 +129,7 @@ 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.
# 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
Expand Down Expand Up @@ -407,8 +406,9 @@ def test_compute_launch_template_properties(
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]
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,
Expand Down
181 changes: 181 additions & 0 deletions cli/tests/pcluster/templates/test_queues_stack.py
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Loading

0 comments on commit f22c6d0

Please sign in to comment.