Path: blob/develop/awscli/customizations/emr/createcluster.py
2639 views
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.1#2# Licensed under the Apache License, Version 2.0 (the "License"). You3# may not use this file except in compliance with the License. A copy of4# the License is located at5#6# http://aws.amazon.com/apache2.0/7#8# or in the "license" file accompanying this file. This file is9# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF10# ANY KIND, either express or implied. See the License for the specific11# language governing permissions and limitations under the License.1213import re1415from botocore.compat import json1617from awscli.customizations.commands import BasicCommand18from awscli.customizations.emr import (19applicationutils,20argumentschema,21constants,22emrfsutils,23emrutils,24exceptions,25hbaseutils,26helptext,27instancefleetsutils,28instancegroupsutils,29steputils,30)31from awscli.customizations.emr.command import Command32from awscli.customizations.emr.constants import EC2_ROLE_NAME, EMR_ROLE_NAME333435class CreateCluster(Command):36NAME = 'create-cluster'37DESCRIPTION = helptext.CREATE_CLUSTER_DESCRIPTION38ARG_TABLE = [39{'name': 'release-label', 'help_text': helptext.RELEASE_LABEL},40{'name': 'os-release-label', 'help_text': helptext.OS_RELEASE_LABEL},41{'name': 'ami-version', 'help_text': helptext.AMI_VERSION},42{43'name': 'instance-groups',44'schema': argumentschema.INSTANCE_GROUPS_SCHEMA,45'help_text': helptext.INSTANCE_GROUPS,46},47{'name': 'instance-type', 'help_text': helptext.INSTANCE_TYPE},48{'name': 'instance-count', 'help_text': helptext.INSTANCE_COUNT},49{50'name': 'auto-terminate',51'action': 'store_true',52'group_name': 'auto_terminate',53'help_text': helptext.AUTO_TERMINATE,54},55{56'name': 'no-auto-terminate',57'action': 'store_true',58'group_name': 'auto_terminate',59},60{61'name': 'instance-fleets',62'schema': argumentschema.INSTANCE_FLEETS_SCHEMA,63'help_text': helptext.INSTANCE_FLEETS,64},65{66'name': 'name',67'default': 'Development Cluster',68'help_text': helptext.CLUSTER_NAME,69},70{'name': 'log-uri', 'help_text': helptext.LOG_URI},71{72'name': 'log-encryption-kms-key-id',73'help_text': helptext.LOG_ENCRYPTION_KMS_KEY_ID,74},75{'name': 'service-role', 'help_text': helptext.SERVICE_ROLE},76{'name': 'auto-scaling-role', 'help_text': helptext.AUTOSCALING_ROLE},77{78'name': 'use-default-roles',79'action': 'store_true',80'help_text': helptext.USE_DEFAULT_ROLES,81},82{'name': 'configurations', 'help_text': helptext.CONFIGURATIONS},83{84'name': 'ec2-attributes',85'help_text': helptext.EC2_ATTRIBUTES,86'schema': argumentschema.EC2_ATTRIBUTES_SCHEMA,87},88{89'name': 'termination-protected',90'action': 'store_true',91'group_name': 'termination_protected',92'help_text': helptext.TERMINATION_PROTECTED,93},94{95'name': 'no-termination-protected',96'action': 'store_true',97'group_name': 'termination_protected',98},99{100'name': 'unhealthy-node-replacement',101'action': 'store_true',102'group_name': 'unhealthy_node_replacement',103'help_text': helptext.UNHEALTHY_NODE_REPLACEMENT,104},105{106'name': 'no-unhealthy-node-replacement',107'action': 'store_true',108'group_name': 'unhealthy_node_replacement',109},110{111'name': 'scale-down-behavior',112'help_text': helptext.SCALE_DOWN_BEHAVIOR,113},114{115'name': 'visible-to-all-users',116'action': 'store_true',117'group_name': 'visibility',118'help_text': helptext.VISIBILITY,119},120{121'name': 'no-visible-to-all-users',122'action': 'store_true',123'group_name': 'visibility',124},125{126'name': 'enable-debugging',127'action': 'store_true',128'group_name': 'debug',129'help_text': helptext.DEBUGGING,130},131{132'name': 'no-enable-debugging',133'action': 'store_true',134'group_name': 'debug',135},136{137'name': 'tags',138'nargs': '+',139'help_text': helptext.TAGS,140'schema': argumentschema.TAGS_SCHEMA,141},142{143'name': 'bootstrap-actions',144'help_text': helptext.BOOTSTRAP_ACTIONS,145'schema': argumentschema.BOOTSTRAP_ACTIONS_SCHEMA,146},147{148'name': 'applications',149'help_text': helptext.APPLICATIONS,150'schema': argumentschema.APPLICATIONS_SCHEMA,151},152{153'name': 'emrfs',154'help_text': helptext.EMR_FS,155'schema': argumentschema.EMR_FS_SCHEMA,156},157{158'name': 'steps',159'schema': argumentschema.STEPS_SCHEMA,160'help_text': helptext.STEPS,161},162{'name': 'additional-info', 'help_text': helptext.ADDITIONAL_INFO},163{164'name': 'restore-from-hbase-backup',165'schema': argumentschema.HBASE_RESTORE_FROM_BACKUP_SCHEMA,166'help_text': helptext.RESTORE_FROM_HBASE,167},168{169'name': 'security-configuration',170'help_text': helptext.SECURITY_CONFIG,171},172{'name': 'custom-ami-id', 'help_text': helptext.CUSTOM_AMI_ID},173{174'name': 'ebs-root-volume-size',175'help_text': helptext.EBS_ROOT_VOLUME_SIZE,176},177{178'name': 'ebs-root-volume-iops',179'help_text': helptext.EBS_ROOT_VOLUME_IOPS,180},181{182'name': 'ebs-root-volume-throughput',183'help_text': helptext.EBS_ROOT_VOLUME_THROUGHPUT,184},185{186'name': 'repo-upgrade-on-boot',187'help_text': helptext.REPO_UPGRADE_ON_BOOT,188},189{190'name': 'kerberos-attributes',191'schema': argumentschema.KERBEROS_ATTRIBUTES_SCHEMA,192'help_text': helptext.KERBEROS_ATTRIBUTES,193},194{195'name': 'step-concurrency-level',196'cli_type_name': 'integer',197'help_text': helptext.STEP_CONCURRENCY_LEVEL,198},199{200'name': 'managed-scaling-policy',201'schema': argumentschema.MANAGED_SCALING_POLICY_SCHEMA,202'help_text': helptext.MANAGED_SCALING_POLICY,203},204{205'name': 'placement-group-configs',206'schema': argumentschema.PLACEMENT_GROUP_CONFIGS_SCHEMA,207'help_text': helptext.PLACEMENT_GROUP_CONFIGS,208},209{210'name': 'auto-termination-policy',211'schema': argumentschema.AUTO_TERMINATION_POLICY_SCHEMA,212'help_text': helptext.AUTO_TERMINATION_POLICY,213},214{215'name': 'monitoring-configuration',216'schema': argumentschema.MONITORING_CONFIGURATION_SCHEMA,217'help_text': helptext.MONITORING_CONFIGURATION,218},219{220'name': 'extended-support',221'action': 'store_true',222'group_name': 'extended-support',223'help_text': helptext.EXTENDED_SUPPORT,224},225{226'name': 'no-extended-support',227'action': 'store_true',228'group_name': 'extended-support',229},230]231SYNOPSIS = BasicCommand.FROM_FILE('emr', 'create-cluster-synopsis.txt')232EXAMPLES = BasicCommand.FROM_FILE('emr', 'create-cluster-examples.rst')233234def _run_main_command(self, parsed_args, parsed_globals):235params = {}236params['Name'] = parsed_args.name237238self._validate_release_label_ami_version(parsed_args)239240service_role_validation_message = (241" Either choose --use-default-roles or use both --service-role "242"<roleName> and --ec2-attributes InstanceProfile=<profileName>."243)244245if (246parsed_args.use_default_roles is True247and parsed_args.service_role is not None248):249raise exceptions.MutualExclusiveOptionError(250option1="--use-default-roles",251option2="--service-role",252message=service_role_validation_message,253)254255if (256parsed_args.use_default_roles is True257and parsed_args.ec2_attributes is not None258and 'InstanceProfile' in parsed_args.ec2_attributes259):260raise exceptions.MutualExclusiveOptionError(261option1="--use-default-roles",262option2="--ec2-attributes InstanceProfile",263message=service_role_validation_message,264)265266if (267parsed_args.instance_groups is not None268and parsed_args.instance_fleets is not None269):270raise exceptions.MutualExclusiveOptionError(271option1="--instance-groups", option2="--instance-fleets"272)273274instances_config = {}275if parsed_args.instance_fleets is not None:276instances_config['InstanceFleets'] = (277instancefleetsutils.validate_and_build_instance_fleets(278parsed_args.instance_fleets279)280)281else:282instances_config['InstanceGroups'] = (283instancegroupsutils.validate_and_build_instance_groups(284instance_groups=parsed_args.instance_groups,285instance_type=parsed_args.instance_type,286instance_count=parsed_args.instance_count,287)288)289290if parsed_args.release_label is not None:291params["ReleaseLabel"] = parsed_args.release_label292if parsed_args.configurations is not None:293try:294params["Configurations"] = json.loads(295parsed_args.configurations296)297except ValueError:298raise ValueError(299'aws: error: invalid json argument for '300'option --configurations'301)302303if (304parsed_args.release_label is None305and parsed_args.ami_version is not None306):307is_valid_ami_version = re.match(308r'\d?\..*', parsed_args.ami_version309)310if is_valid_ami_version is None:311raise exceptions.InvalidAmiVersionError(312ami_version=parsed_args.ami_version313)314params['AmiVersion'] = parsed_args.ami_version315emrutils.apply_dict(316params, 'AdditionalInfo', parsed_args.additional_info317)318emrutils.apply_dict(params, 'LogUri', parsed_args.log_uri)319320if parsed_args.os_release_label is not None:321emrutils.apply_dict(322params, 'OSReleaseLabel', parsed_args.os_release_label323)324325if parsed_args.log_encryption_kms_key_id is not None:326emrutils.apply_dict(327params,328'LogEncryptionKmsKeyId',329parsed_args.log_encryption_kms_key_id,330)331332if parsed_args.use_default_roles is True:333parsed_args.service_role = EMR_ROLE_NAME334if parsed_args.ec2_attributes is None:335parsed_args.ec2_attributes = {}336parsed_args.ec2_attributes['InstanceProfile'] = EC2_ROLE_NAME337338emrutils.apply_dict(params, 'ServiceRole', parsed_args.service_role)339340if parsed_args.instance_groups is not None:341for instance_group in instances_config['InstanceGroups']:342if 'AutoScalingPolicy' in instance_group.keys():343if parsed_args.auto_scaling_role is None:344raise exceptions.MissingAutoScalingRoleError()345346emrutils.apply_dict(347params, 'AutoScalingRole', parsed_args.auto_scaling_role348)349350if parsed_args.scale_down_behavior is not None:351emrutils.apply_dict(352params, 'ScaleDownBehavior', parsed_args.scale_down_behavior353)354355if (356parsed_args.no_auto_terminate is False357and parsed_args.auto_terminate is False358):359parsed_args.no_auto_terminate = True360361instances_config['KeepJobFlowAliveWhenNoSteps'] = (362emrutils.apply_boolean_options(363parsed_args.no_auto_terminate,364'--no-auto-terminate',365parsed_args.auto_terminate,366'--auto-terminate',367)368)369370instances_config['TerminationProtected'] = (371emrutils.apply_boolean_options(372parsed_args.termination_protected,373'--termination-protected',374parsed_args.no_termination_protected,375'--no-termination-protected',376)377)378379if (380parsed_args.unhealthy_node_replacement381or parsed_args.no_unhealthy_node_replacement382):383instances_config['UnhealthyNodeReplacement'] = (384emrutils.apply_boolean_options(385parsed_args.unhealthy_node_replacement,386'--unhealthy-node-replacement',387parsed_args.no_unhealthy_node_replacement,388'--no-unhealthy-node-replacement',389)390)391392if (393parsed_args.visible_to_all_users is False394and parsed_args.no_visible_to_all_users is False395):396parsed_args.visible_to_all_users = True397398params['VisibleToAllUsers'] = emrutils.apply_boolean_options(399parsed_args.visible_to_all_users,400'--visible-to-all-users',401parsed_args.no_visible_to_all_users,402'--no-visible-to-all-users',403)404405params['Tags'] = emrutils.parse_tags(parsed_args.tags)406params['Instances'] = instances_config407408if parsed_args.ec2_attributes is not None:409self._build_ec2_attributes(410cluster=params, parsed_attrs=parsed_args.ec2_attributes411)412413debugging_enabled = emrutils.apply_boolean_options(414parsed_args.enable_debugging,415'--enable-debugging',416parsed_args.no_enable_debugging,417'--no-enable-debugging',418)419420if parsed_args.log_uri is None and debugging_enabled is True:421raise exceptions.LogUriError422423if debugging_enabled is True:424self._update_cluster_dict(425cluster=params,426key='Steps',427value=[428self._build_enable_debugging(parsed_args, parsed_globals)429],430)431432if parsed_args.applications is not None:433if parsed_args.release_label is None:434app_list, ba_list, step_list = (435applicationutils.build_applications(436region=self.region,437parsed_applications=parsed_args.applications,438ami_version=params['AmiVersion'],439)440)441self._update_cluster_dict(442params, 'NewSupportedProducts', app_list443)444self._update_cluster_dict(params, 'BootstrapActions', ba_list)445self._update_cluster_dict(params, 'Steps', step_list)446else:447params["Applications"] = []448for application in parsed_args.applications:449params["Applications"].append(application)450451hbase_restore_config = parsed_args.restore_from_hbase_backup452if hbase_restore_config is not None:453args = hbaseutils.build_hbase_restore_from_backup_args(454dir=hbase_restore_config.get('Dir'),455backup_version=hbase_restore_config.get('BackupVersion'),456)457step_config = emrutils.build_step(458jar=constants.HBASE_JAR_PATH,459name=constants.HBASE_RESTORE_STEP_NAME,460action_on_failure=constants.CANCEL_AND_WAIT,461args=args,462)463self._update_cluster_dict(params, 'Steps', [step_config])464465if parsed_args.bootstrap_actions is not None:466self._build_bootstrap_actions(467cluster=params,468parsed_boostrap_actions=parsed_args.bootstrap_actions,469)470471if parsed_args.emrfs is not None:472self._handle_emrfs_parameters(473cluster=params,474emrfs_args=parsed_args.emrfs,475release_label=parsed_args.release_label,476)477478if parsed_args.steps is not None:479steps_list = steputils.build_step_config_list(480parsed_step_list=parsed_args.steps,481region=self.region,482release_label=parsed_args.release_label,483)484self._update_cluster_dict(485cluster=params, key='Steps', value=steps_list486)487488if parsed_args.security_configuration is not None:489emrutils.apply_dict(490params,491'SecurityConfiguration',492parsed_args.security_configuration,493)494495if parsed_args.custom_ami_id is not None:496emrutils.apply_dict(497params, 'CustomAmiId', parsed_args.custom_ami_id498)499if parsed_args.ebs_root_volume_size is not None:500emrutils.apply_dict(501params,502'EbsRootVolumeSize',503int(parsed_args.ebs_root_volume_size),504)505if parsed_args.ebs_root_volume_iops is not None:506emrutils.apply_dict(507params,508'EbsRootVolumeIops',509int(parsed_args.ebs_root_volume_iops),510)511if parsed_args.ebs_root_volume_throughput is not None:512emrutils.apply_dict(513params,514'EbsRootVolumeThroughput',515int(parsed_args.ebs_root_volume_throughput),516)517518if parsed_args.repo_upgrade_on_boot is not None:519emrutils.apply_dict(520params, 'RepoUpgradeOnBoot', parsed_args.repo_upgrade_on_boot521)522523if parsed_args.kerberos_attributes is not None:524emrutils.apply_dict(525params, 'KerberosAttributes', parsed_args.kerberos_attributes526)527528if parsed_args.step_concurrency_level is not None:529params['StepConcurrencyLevel'] = parsed_args.step_concurrency_level530531if parsed_args.extended_support or parsed_args.no_extended_support:532params['ExtendedSupport'] = emrutils.apply_boolean_options(533parsed_args.extended_support,534'--extended-support',535parsed_args.no_extended_support,536'--no-extended-support',537)538539if parsed_args.managed_scaling_policy is not None:540emrutils.apply_dict(541params,542'ManagedScalingPolicy',543parsed_args.managed_scaling_policy,544)545546if parsed_args.placement_group_configs is not None:547emrutils.apply_dict(548params,549'PlacementGroupConfigs',550parsed_args.placement_group_configs,551)552553if parsed_args.auto_termination_policy is not None:554emrutils.apply_dict(555params,556'AutoTerminationPolicy',557parsed_args.auto_termination_policy,558)559560if parsed_args.monitoring_configuration is not None:561emrutils.apply_dict(562params,563'MonitoringConfiguration',564parsed_args.monitoring_configuration,565)566567self._validate_required_applications(parsed_args)568569run_job_flow_response = emrutils.call(570self._session,571'run_job_flow',572params,573self.region,574parsed_globals.endpoint_url,575parsed_globals.verify_ssl,576)577578constructed_result = self._construct_result(run_job_flow_response)579emrutils.display_response(580self._session, 'run_job_flow', constructed_result, parsed_globals581)582583return 0584585def _construct_result(self, run_job_flow_result):586jobFlowId = None587clusterArn = None588if run_job_flow_result is not None:589jobFlowId = run_job_flow_result.get('JobFlowId')590clusterArn = run_job_flow_result.get('ClusterArn')591592if jobFlowId is not None:593return {'ClusterId': jobFlowId, 'ClusterArn': clusterArn}594else:595return {}596597def _build_ec2_attributes(self, cluster, parsed_attrs):598keys = parsed_attrs.keys()599instances = cluster['Instances']600601if 'SubnetId' in keys and 'SubnetIds' in keys:602raise exceptions.MutualExclusiveOptionError(603option1="SubnetId", option2="SubnetIds"604)605606if 'AvailabilityZone' in keys and 'AvailabilityZones' in keys:607raise exceptions.MutualExclusiveOptionError(608option1="AvailabilityZone", option2="AvailabilityZones"609)610611if ('SubnetId' in keys or 'SubnetIds' in keys) and (612'AvailabilityZone' in keys or 'AvailabilityZones' in keys613):614raise exceptions.SubnetAndAzValidationError615616emrutils.apply_params(617src_params=parsed_attrs,618src_key='KeyName',619dest_params=instances,620dest_key='Ec2KeyName',621)622emrutils.apply_params(623src_params=parsed_attrs,624src_key='SubnetId',625dest_params=instances,626dest_key='Ec2SubnetId',627)628emrutils.apply_params(629src_params=parsed_attrs,630src_key='SubnetIds',631dest_params=instances,632dest_key='Ec2SubnetIds',633)634635if 'AvailabilityZone' in keys:636instances['Placement'] = dict()637emrutils.apply_params(638src_params=parsed_attrs,639src_key='AvailabilityZone',640dest_params=instances['Placement'],641dest_key='AvailabilityZone',642)643644if 'AvailabilityZones' in keys:645instances['Placement'] = dict()646emrutils.apply_params(647src_params=parsed_attrs,648src_key='AvailabilityZones',649dest_params=instances['Placement'],650dest_key='AvailabilityZones',651)652653emrutils.apply_params(654src_params=parsed_attrs,655src_key='InstanceProfile',656dest_params=cluster,657dest_key='JobFlowRole',658)659660emrutils.apply_params(661src_params=parsed_attrs,662src_key='EmrManagedMasterSecurityGroup',663dest_params=instances,664dest_key='EmrManagedMasterSecurityGroup',665)666667emrutils.apply_params(668src_params=parsed_attrs,669src_key='EmrManagedSlaveSecurityGroup',670dest_params=instances,671dest_key='EmrManagedSlaveSecurityGroup',672)673674emrutils.apply_params(675src_params=parsed_attrs,676src_key='ServiceAccessSecurityGroup',677dest_params=instances,678dest_key='ServiceAccessSecurityGroup',679)680681emrutils.apply_params(682src_params=parsed_attrs,683src_key='AdditionalMasterSecurityGroups',684dest_params=instances,685dest_key='AdditionalMasterSecurityGroups',686)687688emrutils.apply_params(689src_params=parsed_attrs,690src_key='AdditionalSlaveSecurityGroups',691dest_params=instances,692dest_key='AdditionalSlaveSecurityGroups',693)694695emrutils.apply(params=cluster, key='Instances', value=instances)696697return cluster698699def _build_bootstrap_actions(self, cluster, parsed_boostrap_actions):700cluster_ba_list = cluster.get('BootstrapActions')701if cluster_ba_list is None:702cluster_ba_list = []703704bootstrap_actions = []705if (706len(cluster_ba_list) + len(parsed_boostrap_actions)707> constants.MAX_BOOTSTRAP_ACTION_NUMBER708):709raise ValueError(710'aws: error: maximum number of '711'bootstrap actions for a cluster exceeded.'712)713714for ba in parsed_boostrap_actions:715ba_config = {}716if ba.get('Name') is not None:717ba_config['Name'] = ba.get('Name')718else:719ba_config['Name'] = constants.BOOTSTRAP_ACTION_NAME720script_arg_config = {}721emrutils.apply_params(722src_params=ba,723src_key='Path',724dest_params=script_arg_config,725dest_key='Path',726)727emrutils.apply_params(728src_params=ba,729src_key='Args',730dest_params=script_arg_config,731dest_key='Args',732)733emrutils.apply(734params=ba_config,735key='ScriptBootstrapAction',736value=script_arg_config,737)738bootstrap_actions.append(ba_config)739740result = cluster_ba_list + bootstrap_actions741if result:742cluster['BootstrapActions'] = result743744return cluster745746def _build_enable_debugging(self, parsed_args, parsed_globals):747if parsed_args.release_label:748jar = constants.COMMAND_RUNNER749args = [constants.DEBUGGING_COMMAND]750else:751jar = emrutils.get_script_runner(self.region)752args = [753emrutils.build_s3_link(754relative_path=constants.DEBUGGING_PATH, region=self.region755)756]757758return emrutils.build_step(759name=constants.DEBUGGING_NAME,760action_on_failure=constants.TERMINATE_CLUSTER,761jar=jar,762args=args,763)764765def _update_cluster_dict(self, cluster, key, value):766if key in cluster:767cluster[key] += value768elif value:769cluster[key] = value770return cluster771772def _validate_release_label_ami_version(self, parsed_args):773if (774parsed_args.ami_version is not None775and parsed_args.release_label is not None776):777raise exceptions.MutualExclusiveOptionError(778option1="--ami-version", option2="--release-label"779)780781if (782parsed_args.ami_version is None783and parsed_args.release_label is None784):785raise exceptions.RequiredOptionsError(786option1="--ami-version", option2="--release-label"787)788789# Checks if the applications required by steps are specified790# using the --applications option.791def _validate_required_applications(self, parsed_args):792specified_apps = set([])793if parsed_args.applications is not None:794specified_apps = set(795[app['Name'].lower() for app in parsed_args.applications]796)797798missing_apps = self._get_missing_applications_for_steps(799specified_apps, parsed_args800)801# Check for HBase.802if parsed_args.restore_from_hbase_backup is not None:803if constants.HBASE not in specified_apps:804missing_apps.add(constants.HBASE.title())805806if missing_apps:807raise exceptions.MissingApplicationsError(808applications=missing_apps809)810811def _get_missing_applications_for_steps(self, specified_apps, parsed_args):812allowed_app_steps = set(813[constants.HIVE, constants.PIG, constants.IMPALA]814)815missing_apps = set()816if parsed_args.steps is not None:817for step in parsed_args.steps:818if len(missing_apps) == len(allowed_app_steps):819break820step_type = step.get('Type')821822if step_type is not None:823step_type = step_type.lower()824if (825step_type in allowed_app_steps826and step_type not in specified_apps827):828missing_apps.add(step['Type'].title())829return missing_apps830831def _filter_configurations_in_special_cases(832self, configurations, parsed_args, parsed_configs833):834if parsed_args.use_default_roles:835configurations = [836x837for x in configurations838if x.name != 'service_role' and x.name != 'instance_profile'839]840return configurations841842def _handle_emrfs_parameters(self, cluster, emrfs_args, release_label):843if release_label:844self.validate_no_emrfs_configuration(cluster)845emrfs_configuration = emrfsutils.build_emrfs_confiuration(846emrfs_args847)848849self._update_cluster_dict(850cluster=cluster,851key='Configurations',852value=[emrfs_configuration],853)854else:855emrfs_ba_config_list = emrfsutils.build_bootstrap_action_configs(856self.region, emrfs_args857)858self._update_cluster_dict(859cluster=cluster,860key='BootstrapActions',861value=emrfs_ba_config_list,862)863864def validate_no_emrfs_configuration(self, cluster):865if 'Configurations' in cluster:866for config in cluster['Configurations']:867if (868config is not None869and config.get('Classification') == constants.EMRFS_SITE870):871raise exceptions.DuplicateEmrFsConfigurationError872873874