CF - Create-support for AWS::EMR::Cluster (#7384)

This commit is contained in:
Bert Blommers 2024-02-23 08:14:20 +00:00 committed by GitHub
parent e2529697c7
commit 082e6c2fc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 694 additions and 7 deletions

View File

@ -121,6 +121,8 @@ Please let us know if you'd like support for a resource not yet listed here.
+---------------------------------------+--------+--------+--------+ - [ ] Id |
| | | | | |
+---------------------------------------+--------+--------+--------+----------------------------------------+
|AWS::EMR::Cluster | x | | | - [ ] MasterPublicDNS |
+---------------------------------------+--------+--------+--------+----------------------------------------+
|AWS::Events::Archive | x | x | | - [x] Arn |
+---------------------------------------+--------+--------+--------+----------------------------------------+
|AWS::Events::EventBus | x | x | x | - [x] Arn |

View File

@ -33,8 +33,6 @@ from moto.awslambda import models as lambda_models # noqa # pylint: disable=al
from moto.batch import models as batch_models # noqa # pylint: disable=all
from moto.cloudformation.custom_model import CustomModel
from moto.cloudwatch import models as cw_models # noqa # pylint: disable=all
# End ugly list of imports
from moto.core.common_models import CloudFormationModel
from moto.datapipeline import models as data_models # noqa # pylint: disable=all
from moto.dynamodb import models as ddb_models # noqa # pylint: disable=all
@ -45,6 +43,7 @@ from moto.ecs import models as ecs_models # noqa # pylint: disable=all
from moto.efs import models as efs_models # noqa # pylint: disable=all
from moto.elb import models as elb_models # noqa # pylint: disable=all
from moto.elbv2 import models as elbv2_models # noqa # pylint: disable=all
from moto.emr import models as emr_models # noqa # pylint: disable=all
from moto.events import models as events_models # noqa # pylint: disable=all
from moto.iam import models as iam_models # noqa # pylint: disable=all
from moto.kinesis import models as kinesis_models # noqa # pylint: disable=all
@ -62,6 +61,7 @@ from moto.ssm import models as ssm_models # noqa # pylint: disable=all
from moto.ssm import ssm_backends
from moto.stepfunctions import models as sfn_models # noqa # pylint: disable=all
# End ugly list of imports
from .exceptions import (
ExportNotFound,
MissingParameterError,

View File

@ -4,7 +4,7 @@ from typing import Any, Dict, List, Optional, Tuple
from dateutil.parser import parse as dtparse
from moto.core.base_backend import BackendDict, BaseBackend
from moto.core.common_models import BaseModel
from moto.core.common_models import BaseModel, CloudFormationModel
from moto.emr.exceptions import (
InvalidRequestException,
ResourceNotFoundException,
@ -151,7 +151,7 @@ class FakeStep(BaseModel):
self.start_datetime = datetime.now(timezone.utc)
class FakeCluster(BaseModel):
class FakeCluster(CloudFormationModel):
def __init__(
self,
emr_backend: "ElasticMapReduceBackend",
@ -384,6 +384,71 @@ class FakeCluster(BaseModel):
def set_visibility(self, visibility: str) -> None:
self.visible_to_all_users = visibility
@property
def physical_resource_id(self) -> str:
return self.id
@staticmethod
def cloudformation_type() -> str:
return "AWS::EMR::Cluster"
@classmethod
def has_cfn_attr(cls, attr: str) -> bool:
return attr in ["Id"]
def get_cfn_attribute(self, attribute_name: str) -> str:
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
if attribute_name == "Id":
return self.id
raise UnformattedGetAttTemplateException()
@classmethod
def create_from_cloudformation_json( # type: ignore[misc]
cls,
resource_name: str,
cloudformation_json: Any,
account_id: str,
region_name: str,
**kwargs: Any,
) -> "FakeCluster":
properties = cloudformation_json["Properties"]
instance_attrs = properties.get("Instances", {})
instance_attrs["ec2_subnet_id"] = instance_attrs.get("Ec2SubnetId")
instance_attrs["emr_managed_master_security_group"] = instance_attrs.get(
"EmrManagedMasterSecurityGroup"
)
instance_attrs["emr_managed_slave_security_group"] = instance_attrs.get(
"EmrManagedSlaveSecurityGroup"
)
instance_attrs["service_access_security_group"] = instance_attrs.get(
"ServiceAccessSecurityGroup"
)
instance_attrs["additional_master_security_groups"] = instance_attrs.get(
"AdditionalMasterSecurityGroups", []
)
instance_attrs["additional_slave_security_groups"] = instance_attrs.get(
"AdditionalSlaveSecurityGroups", []
)
emr_backend: ElasticMapReduceBackend = emr_backends[account_id][region_name]
cluster = emr_backend.run_job_flow(
name=properties["Name"],
log_uri=properties.get("LogUri"),
job_flow_role=properties["JobFlowRole"],
service_role=properties["ServiceRole"],
steps=[],
instance_attrs=instance_attrs,
kerberos_attributes=properties.get("KerberosAttributes", {}),
release_label=properties.get("ReleaseLabel"),
custom_ami_id=properties.get("CustomAmiId"),
)
tags = {item["Key"]: item["Value"] for item in properties.get("Tags", [])}
cluster.add_tags(tags)
return cluster
class FakeSecurityConfiguration(BaseModel):
def __init__(self, name: str, security_configuration: str):

View File

@ -233,11 +233,11 @@ class Key(CloudFormationModel):
policy=properties["KeyPolicy"],
key_usage="ENCRYPT_DECRYPT",
key_spec="SYMMETRIC_DEFAULT",
description=properties["Description"],
description=properties.get("Description"),
tags=properties.get("Tags", []),
)
key.key_rotation_status = properties["EnableKeyRotation"]
key.enabled = properties["Enabled"]
key.key_rotation_status = properties.get("EnableKeyRotation", False)
key.enabled = properties.get("Enabled", True)
return key

View File

@ -0,0 +1,620 @@
import json
import boto3
from moto import mock_aws
from tests import EXAMPLE_AMI_ID
template = """{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application",
"Resources": {
"Cluster1": {
"Type" : "AWS::EMR::Cluster",
"Properties" : {
"Instances" : {
"CoreInstanceGroup": {
"InstanceCount": 3,
"InstanceType": "m3g",
}
},
"JobFlowRole" : "EMR_EC2_DefaultRole",
"Name" : "my cluster",
"ServiceRole" : "EMR_DefaultRole",
}
},
},
"Outputs": {
"ClusterId": {
"Description": "Cluster info",
"Value": {
"Fn::GetAtt": ["Cluster1", "Id"]
},
}
}
}"""
@mock_aws
def test_create_simple_cluster__using_cloudformation():
region = "us-east-1"
cf = boto3.client("cloudformation", region_name=region)
emr = boto3.client("emr", region_name=region)
cf.create_stack(StackName="teststack", TemplateBody=template)
# Verify resources
res = cf.describe_stack_resources(StackName="teststack")["StackResources"][0]
cluster_id = res["PhysicalResourceId"]
assert res["LogicalResourceId"] == "Cluster1"
assert res["ResourceType"] == "AWS::EMR::Cluster"
assert cluster_id.startswith("j-")
# Verify outputs
stack = cf.describe_stacks(StackName="teststack")["Stacks"][0]
assert {"OutputKey": "ClusterId", "OutputValue": cluster_id} in stack["Outputs"]
# Verify EMR Cluster
cl = emr.describe_cluster(ClusterId=cluster_id)["Cluster"]
assert cl["Name"] == "my cluster"
assert cl["Ec2InstanceAttributes"]["IamInstanceProfile"] == "EMR_EC2_DefaultRole"
assert cl["ServiceRole"] == "EMR_DefaultRole"
assert cl["Tags"] == []
template_with_tags = {
"Resources": {
"Cluster1": {
"Type": "AWS::EMR::Cluster",
"Properties": {
"Instances": {
"CoreInstanceGroup": {
"InstanceCount": 3,
"InstanceType": "m3g",
}
},
"JobFlowRole": "EMR_EC2_DefaultRole",
"Name": "my cluster",
"ServiceRole": "EMR_DefaultRole",
"Tags": [
{"Key": "k1", "Value": "v1"},
{"Key": "k2", "Value": "v2"},
],
},
},
},
}
@mock_aws
def test_create_simple_cluster_with_tags():
region = "us-east-1"
cf = boto3.client("cloudformation", region_name=region)
emr = boto3.client("emr", region_name=region)
cf.create_stack(StackName="teststack", TemplateBody=json.dumps(template_with_tags))
# Verify resources
res = cf.describe_stack_resources(StackName="teststack")["StackResources"][0]
cluster_id = res["PhysicalResourceId"]
# Verify EMR Cluster
cl = emr.describe_cluster(ClusterId=cluster_id)["Cluster"]
assert cl["Tags"] == [{"Key": "k1", "Value": "v1"}, {"Key": "k2", "Value": "v2"}]
template_with_custom_ami = {
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"SubnetId": {"Type": "String"},
"InstanceType": {"Type": "String"},
"TerminationProtected": {"Type": "String", "Default": "false"},
"ElasticMapReducePrincipal": {"Type": "String"},
"Ec2Principal": {"Type": "String"},
},
"Resources": {
"cluster": {
"Type": "AWS::EMR::Cluster",
"Properties": {
"CustomAmiId": EXAMPLE_AMI_ID,
"Instances": {
"MasterInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnMaster",
},
"CoreInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnCore",
},
"TaskInstanceGroups": [
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-1",
},
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-2",
},
],
"TerminationProtected": {"Ref": "TerminationProtected"},
"Ec2SubnetId": {"Ref": "SubnetId"},
},
"Name": "CFNtest",
"JobFlowRole": {"Ref": "emrEc2InstanceProfile"},
"ServiceRole": {"Ref": "emrRole"},
"ReleaseLabel": "release_2024",
"VisibleToAllUsers": True,
"Tags": [{"Key": "key1", "Value": "value1"}],
},
},
"emrRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": {"Ref": "ElasticMapReducePrincipal"}
},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceRole"
],
},
},
"emrEc2Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {"Service": {"Ref": "Ec2Principal"}},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role"
],
},
},
"emrEc2InstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {"Path": "/", "Roles": [{"Ref": "emrEc2Role"}]},
},
},
}
@mock_aws
def test_create_cluster_with_custom_ami():
ec2 = boto3.resource("ec2", region_name="us-east-1")
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
params = [
{"ParameterKey": "InstanceType", "ParameterValue": "i4s"},
{"ParameterKey": "SubnetId", "ParameterValue": subnet.id},
{
"ParameterKey": "ElasticMapReducePrincipal",
"ParameterValue": "emr_principal",
},
{"ParameterKey": "Ec2Principal", "ParameterValue": "ec2_principal"},
]
region = "us-east-1"
cf = boto3.client("cloudformation", region_name=region)
emr = boto3.client("emr", region_name=region)
cf.create_stack(
StackName="teststack",
TemplateBody=json.dumps(template_with_custom_ami),
Parameters=params,
)
# Verify resources
res = cf.describe_stack_resources(StackName="teststack")["StackResources"]
cluster = [r for r in res if r["ResourceType"] == "AWS::EMR::Cluster"][0]
cluster_id = cluster["PhysicalResourceId"]
instance_profile = [
r for r in res if r["ResourceType"] == "AWS::IAM::InstanceProfile"
][0]
instance_profile_id = instance_profile["PhysicalResourceId"]
role = [r for r in res if r["ResourceType"] == "AWS::IAM::Role"][0]
role_id = role["PhysicalResourceId"]
# Verify EMR Cluster
cl = emr.describe_cluster(ClusterId=cluster_id)["Cluster"]
assert cl["Name"] == "CFNtest"
assert cl["Ec2InstanceAttributes"]["Ec2SubnetId"] == subnet.id
assert cl["Ec2InstanceAttributes"]["IamInstanceProfile"] == instance_profile_id
assert cl["ServiceRole"] == role_id
assert cl["ReleaseLabel"] == "release_2024"
assert cl["CustomAmiId"] == EXAMPLE_AMI_ID
template_with_root_volume = {
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"InstanceType": {"Type": "String"},
"ReleaseLabel": {"Type": "String"},
"SubnetId": {"Type": "String"},
"TerminationProtected": {"Type": "String", "Default": "false"},
"EbsRootVolumeSize": {"Type": "String"},
},
"Resources": {
"cluster": {
"Type": "AWS::EMR::Cluster",
"Properties": {
"EbsRootVolumeSize": {"Ref": "EbsRootVolumeSize"},
"Instances": {
"MasterInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnMaster",
},
"CoreInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnCore",
},
"TaskInstanceGroups": [
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-1",
},
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-2",
},
],
"TerminationProtected": {"Ref": "TerminationProtected"},
"Ec2SubnetId": {"Ref": "SubnetId"},
},
"Name": "CFNtest",
"JobFlowRole": {"Ref": "emrEc2InstanceProfile"},
"ServiceRole": {"Ref": "emrRole"},
"ReleaseLabel": {"Ref": "ReleaseLabel"},
"VisibleToAllUsers": True,
"Tags": [{"Key": "key1", "Value": "value1"}],
},
},
"emrRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {"Service": "elasticmapreduce.amazonaws.com"},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceRole"
],
},
},
"emrEc2Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role"
],
},
},
"emrEc2InstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {"Path": "/", "Roles": [{"Ref": "emrEc2Role"}]},
},
},
}
@mock_aws
def test_create_cluster_with_root_volume():
ec2 = boto3.resource("ec2", region_name="us-east-1")
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
params = [
{"ParameterKey": "InstanceType", "ParameterValue": "i4s"},
{"ParameterKey": "ReleaseLabel", "ParameterValue": "latest"},
{"ParameterKey": "EbsRootVolumeSize", "ParameterValue": "15"},
{"ParameterKey": "SubnetId", "ParameterValue": subnet.id},
{
"ParameterKey": "ElasticMapReducePrincipal",
"ParameterValue": "emr_principal",
},
{"ParameterKey": "Ec2Principal", "ParameterValue": "ec2_principal"},
]
region = "us-east-1"
cf = boto3.client("cloudformation", region_name=region)
emr = boto3.client("emr", region_name=region)
cf.create_stack(
StackName="teststack",
TemplateBody=json.dumps(template_with_root_volume),
Parameters=params,
)
# Verify resources
res = cf.describe_stack_resources(StackName="teststack")["StackResources"]
cluster = [r for r in res if r["ResourceType"] == "AWS::EMR::Cluster"][0]
cluster_id = cluster["PhysicalResourceId"]
instance_profile = [
r for r in res if r["ResourceType"] == "AWS::IAM::InstanceProfile"
][0]
instance_profile_id = instance_profile["PhysicalResourceId"]
role = [r for r in res if r["ResourceType"] == "AWS::IAM::Role"][0]
role_id = role["PhysicalResourceId"]
# Verify EMR Cluster
cl = emr.describe_cluster(ClusterId=cluster_id)["Cluster"]
assert cl["Name"] == "CFNtest"
assert cl["Ec2InstanceAttributes"]["Ec2SubnetId"] == subnet.id
assert cl["Ec2InstanceAttributes"]["IamInstanceProfile"] == instance_profile_id
assert cl["ServiceRole"] == role_id
template_with_kerberos_attrs = {
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"CrossRealmTrustPrincipalPassword": {"Type": "String"},
"KdcAdminPassword": {"Type": "String"},
"InstanceType": {"Type": "String"},
"ReleaseLabel": {"Type": "String"},
"SubnetId": {"Type": "String"},
},
"Resources": {
"cluster": {
"Type": "AWS::EMR::Cluster",
"Properties": {
"Instances": {
"MasterInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnMaster",
},
"CoreInstanceGroup": {
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnCore",
},
"TaskInstanceGroups": [
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-1",
},
{
"InstanceCount": 1,
"InstanceType": {"Ref": "InstanceType"},
"Market": "ON_DEMAND",
"Name": "cfnTask-2",
},
],
"Ec2SubnetId": {"Ref": "SubnetId"},
},
"Name": "CFNtest",
"JobFlowRole": {"Ref": "emrEc2InstanceProfile"},
"KerberosAttributes": {
"CrossRealmTrustPrincipalPassword": {
"Ref": "CrossRealmTrustPrincipalPassword"
},
"KdcAdminPassword": {"Ref": "KdcAdminPassword"},
"Realm": "EC2.INTERNAL",
},
"ServiceRole": {"Ref": "emrRole"},
"ReleaseLabel": {"Ref": "ReleaseLabel"},
"SecurityConfiguration": {"Ref": "securityConfiguration"},
"VisibleToAllUsers": True,
"Tags": [{"Key": "key1", "Value": "value1"}],
},
},
"key": {
"Type": "AWS::KMS::Key",
"Properties": {
"KeyPolicy": {
"Version": "2012-10-17",
"Id": "key-default-1",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {"AWS": {"Fn::GetAtt": ["emrEc2Role", "Arn"]}},
"Action": "kms:*",
"Resource": "*",
},
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:aws:iam::",
{"Ref": "AWS::AccountId"},
":root",
],
]
}
},
"Action": "kms:*",
"Resource": "*",
},
],
}
},
},
"securityConfiguration": {
"Type": "AWS::EMR::SecurityConfiguration",
"Properties": {
"SecurityConfiguration": {
"AuthenticationConfiguration": {
"KerberosConfiguration": {
"Provider": "ClusterDedicatedKdc",
"ClusterDedicatedKdcConfiguration": {
"TicketLifetimeInHours": 24,
"CrossRealmTrustConfiguration": {
"Realm": "AD.DOMAIN.COM",
"Domain": "ad.domain.com",
"AdminServer": "ad.domain.com",
"KdcServer": "ad.domain.com",
},
},
}
}
}
},
},
"emrRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {"Service": "elasticmapreduce.amazonaws.com"},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceRole"
],
},
},
"emrEc2Role": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2008-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole",
}
],
},
"Path": "/",
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role"
],
},
},
"emrEc2InstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {"Path": "/", "Roles": [{"Ref": "emrEc2Role"}]},
},
},
"Outputs": {"keyArn": {"Value": {"Fn::GetAtt": ["key", "Arn"]}}},
}
@mock_aws
def test_create_cluster_with_kerberos_attrs():
ec2 = boto3.resource("ec2", region_name="us-east-1")
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18")
params = [
{"ParameterKey": "CrossRealmTrustPrincipalPassword", "ParameterValue": "p2ss"},
{"ParameterKey": "KdcAdminPassword", "ParameterValue": "adminp2ss"},
{"ParameterKey": "InstanceType", "ParameterValue": "i4s"},
{"ParameterKey": "ReleaseLabel", "ParameterValue": "latest"},
{"ParameterKey": "EbsRootVolumeSize", "ParameterValue": "15"},
{"ParameterKey": "SubnetId", "ParameterValue": subnet.id},
{
"ParameterKey": "ElasticMapReducePrincipal",
"ParameterValue": "emr_principal",
},
{"ParameterKey": "Ec2Principal", "ParameterValue": "ec2_principal"},
]
region = "us-east-1"
cf = boto3.client("cloudformation", region_name=region)
emr = boto3.client("emr", region_name=region)
cf.create_stack(
StackName="teststack",
TemplateBody=json.dumps(template_with_kerberos_attrs),
Parameters=params,
)
# Verify resources
res = cf.describe_stack_resources(StackName="teststack")["StackResources"]
cluster = [r for r in res if r["ResourceType"] == "AWS::EMR::Cluster"][0]
cluster_id = cluster["PhysicalResourceId"]
instance_profile = [
r for r in res if r["ResourceType"] == "AWS::IAM::InstanceProfile"
][0]
instance_profile_id = instance_profile["PhysicalResourceId"]
role = [r for r in res if r["ResourceType"] == "AWS::IAM::Role"][0]
role_id = role["PhysicalResourceId"]
# Verify EMR Cluster
cl = emr.describe_cluster(ClusterId=cluster_id)["Cluster"]
assert cl["Name"] == "CFNtest"
assert cl["Ec2InstanceAttributes"]["Ec2SubnetId"] == subnet.id
assert cl["Ec2InstanceAttributes"]["IamInstanceProfile"] == instance_profile_id
assert cl["ServiceRole"] == role_id
kerberos = cl["KerberosAttributes"]
assert kerberos == {
"Realm": "EC2.INTERNAL",
"KdcAdminPassword": "adminp2ss",
"CrossRealmTrustPrincipalPassword": "p2ss",
}