def bootstrap_spokes_in_ou(ou_path_or_id, role_name, iam_role_arns, permission_boundary, num_workers=10): puppet_account_id = config.get_puppet_account_id() org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id) if org_iam_role_arn is None: click.echo("No org role set - not expanding") else: click.echo("Expanding using role: {}".format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( "organizations", org_iam_role_arn, "org-iam-role") as client: tasks = [] if ou_path_or_id.startswith("/"): ou_id = client.convert_path_to_ou(ou_path_or_id) else: ou_id = ou_path_or_id logging.info(f"ou_id is {ou_id}") response = client.list_children_nested(ParentId=ou_id, ChildType="ACCOUNT") for spoke in response: tasks.append( management_tasks.BootstrapSpokeAsTask( puppet_account_id=puppet_account_id, account_id=spoke.get("Id"), iam_role_arns=iam_role_arns, role_name=role_name, permission_boundary=permission_boundary, )) runner.run_tasks_for_bootstrap_spokes_in_ou(tasks, num_workers)
def bootstrap_spokes_in_ou(ou_path_or_id, role_name, iam_role_arns, permission_boundary): org_iam_role_arn = config.get_org_iam_role_arn() puppet_account_id = config.get_puppet_account_id() if org_iam_role_arn is None: click.echo('No org role set - not expanding') else: click.echo('Expanding using role: {}'.format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( 'organizations', org_iam_role_arn, 'org-iam-role') as client: tasks = [] if ou_path_or_id.startswith('/'): ou_id = client.convert_path_to_ou(ou_path_or_id) else: ou_id = ou_path_or_id logging.info(f"ou_id is {ou_id}") response = client.list_children_nested(ParentId=ou_id, ChildType='ACCOUNT') for spoke in response: tasks.append( management_tasks.BootstrapSpokeAsTask( puppet_account_id=puppet_account_id, account_id=spoke.get('Id'), iam_role_arns=iam_role_arns, role_name=role_name, permission_boundary=permission_boundary, )) runner.run_tasks_for_bootstrap_spokes_in_ou(tasks)
def expand(f, single_account): click.echo("Expanding") puppet_account_id = config.get_puppet_account_id() manifest = manifest_utils.load(f, puppet_account_id) org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id) if org_iam_role_arn is None: click.echo("No org role set - not expanding") new_manifest = manifest else: click.echo("Expanding using role: {}".format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( "organizations", org_iam_role_arn, "org-iam-role" ) as client: new_manifest = manifest_utils.expand_manifest(manifest, client) click.echo("Expanded") if single_account: click.echo(f"Filtering for single account: {single_account}") for account in new_manifest.get("accounts", []): if account.get("account_id") == single_account: click.echo(f"Found single account: {single_account}") new_manifest["accounts"] = [account] break click.echo("Filtered") new_name = f.name.replace(".yaml", "-expanded.yaml") logger.info("Writing new manifest: {}".format(new_name)) with open(new_name, "w") as output: output.write(yaml.safe_dump(new_manifest, default_flow_style=False))
def expand(f): click.echo('Expanding') manifest = manifest_utils.load(f) org_iam_role_arn = config.get_org_iam_role_arn() if org_iam_role_arn is None: click.echo('No org role set - not expanding') new_manifest = manifest else: click.echo('Expanding using role: {}'.format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( 'organizations', org_iam_role_arn, 'org-iam-role') as client: new_manifest = manifest_utils.expand_manifest(manifest, client) click.echo('Expanded') new_name = f.name.replace(".yaml", '-expanded.yaml') logger.info('Writing new manifest: {}'.format(new_name)) with open(new_name, 'w') as output: output.write(yaml.safe_dump(new_manifest, default_flow_style=False))
def expand(f, single_account, subset=None): click.echo("Expanding") puppet_account_id = config.get_puppet_account_id() manifest = manifest_utils.load(f, puppet_account_id) org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id) if org_iam_role_arn is None: click.echo("No org role set - not expanding") new_manifest = manifest else: click.echo("Expanding using role: {}".format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( "organizations", org_iam_role_arn, "org-iam-role") as client: new_manifest = manifest_utils.expand_manifest(manifest, client) click.echo("Expanded") if single_account: click.echo(f"Filtering for single account: {single_account}") for account in new_manifest.get("accounts", []): if str(account.get("account_id")) == str(single_account): click.echo(f"Found single account: {single_account}") new_manifest["accounts"] = [account] break click.echo("Filtered") new_manifest = manifest_utils.rewrite_depends_on(new_manifest) if subset: click.echo(f"Filtering for subset: {subset}") new_manifest = manifest_utils.isolate( manifest_utils.Manifest(new_manifest), subset) new_manifest = json.loads(json.dumps(new_manifest)) if new_manifest.get(constants.LAMBDA_INVOCATIONS) is None: new_manifest[constants.LAMBDA_INVOCATIONS] = dict() new_name = f.name.replace(".yaml", "-expanded.yaml") logger.info("Writing new manifest: {}".format(new_name)) with open(new_name, "w") as output: output.write(yaml.safe_dump(new_manifest, default_flow_style=False))
def test_get_org_iam_role_arn(mocked_betterboto_client): # setup from servicecatalog_puppet import config as sut expected_result = "some_fake_arn" mocked_response = {"Parameter": {"Value": expected_result}} mocked_betterboto_client.return_value.__enter__.return_value.get_parameter.return_value = ( mocked_response) mocked_get_home_region = mocker.patch.object(sut, "get_home_region") mocked_get_home_region.return_value = "us-east-9" puppet_account_id = "" # exercise actual_result = sut.get_org_iam_role_arn(puppet_account_id) # verify assert actual_result == expected_result args, kwargs = mocked_betterboto_client().__enter__( ).get_parameter.call_args assert args == () assert kwargs == {"Name": constants.CONFIG_PARAM_NAME_ORG_IAM_ROLE_ARN}
def _do_bootstrap(puppet_version, with_manual_approvals): click.echo('Starting bootstrap') should_use_eventbridge = config.get_should_use_eventbridge( os.environ.get("AWS_DEFAULT_REGION")) if should_use_eventbridge: with betterboto_client.ClientContextManager('events') as events: try: events.describe_event_bus(Name=constants.EVENT_BUS_NAME) except events.exceptions.ResourceNotFoundException: events.create_event_bus(Name=constants.EVENT_BUS_NAME, ) all_regions = config.get_regions(os.environ.get("AWS_DEFAULT_REGION")) with betterboto_client.MultiRegionClientContextManager( 'cloudformation', all_regions) as clients: click.echo('Creating {}-regional'.format( constants.BOOTSTRAP_STACK_NAME)) threads = [] template = asset_helpers.read_from_site_packages( '{}.template.yaml'.format('{}-regional'.format( constants.BOOTSTRAP_STACK_NAME))) template = Template(template).render(VERSION=puppet_version) args = { 'StackName': '{}-regional'.format(constants.BOOTSTRAP_STACK_NAME), 'TemplateBody': template, 'Capabilities': ['CAPABILITY_IAM'], 'Parameters': [ { 'ParameterKey': 'Version', 'ParameterValue': puppet_version, 'UsePreviousValue': False, }, { 'ParameterKey': 'DefaultRegionValue', 'ParameterValue': os.environ.get('AWS_DEFAULT_REGION'), 'UsePreviousValue': False, }, ], 'Tags': [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }] } for client_region, client in clients.items(): process = Thread(name=client_region, target=client.create_or_update, kwargs=args) process.start() threads.append(process) for process in threads: process.join() click.echo('Finished creating {}-regional'.format( constants.BOOTSTRAP_STACK_NAME)) with betterboto_client.ClientContextManager( 'cloudformation') as cloudformation: click.echo('Creating {}'.format(constants.BOOTSTRAP_STACK_NAME)) template = asset_helpers.read_from_site_packages( '{}.template.yaml'.format(constants.BOOTSTRAP_STACK_NAME)) template = Template(template).render(VERSION=puppet_version, ALL_REGIONS=all_regions) args = { 'StackName': constants.BOOTSTRAP_STACK_NAME, 'TemplateBody': template, 'Capabilities': ['CAPABILITY_NAMED_IAM'], 'Parameters': [ { 'ParameterKey': 'Version', 'ParameterValue': puppet_version, 'UsePreviousValue': False, }, { 'ParameterKey': 'OrgIamRoleArn', 'ParameterValue': str(config.get_org_iam_role_arn()), 'UsePreviousValue': False, }, { 'ParameterKey': 'WithManualApprovals', 'ParameterValue': "Yes" if with_manual_approvals else "No", 'UsePreviousValue': False, }, ], } cloudformation.create_or_update(**args) click.echo('Finished creating {}.'.format(constants.BOOTSTRAP_STACK_NAME)) with betterboto_client.ClientContextManager('codecommit') as codecommit: response = codecommit.get_repository( repositoryName=constants.SERVICE_CATALOG_PUPPET_REPO_NAME) clone_url = response.get('repositoryMetadata').get('cloneUrlHttp') clone_command = "git clone --config 'credential.helper=!aws codecommit credential-helper $@' " \ "--config 'credential.UseHttpPath=true' {}".format(clone_url) click.echo( 'You need to clone your newly created repo now and will then need to seed it: \n{}' .format(clone_command))
def bootstrap( puppet_account_id, with_manual_approvals, puppet_code_pipeline_role_permission_boundary, source_role_permissions_boundary, puppet_generate_role_permission_boundary, puppet_deploy_role_permission_boundary, puppet_provisioning_role_permissions_boundary, cloud_formation_deploy_role_permissions_boundary, deploy_environment_compute_type, spoke_deploy_environment_compute_type, deploy_num_workers, source_provider, owner, repo, branch, poll_for_source_changes, webhook_secret, puppet_role_name, puppet_role_path, scm_connection_arn, scm_full_repository_id, scm_branch_name, scm_bucket_name, scm_object_key, scm_skip_creation_of_repo, should_validate, custom_source_action_git_url, custom_source_action_git_web_hook_ip_address, custom_source_action_custom_action_type_version, custom_source_action_custom_action_type_provider, ): click.echo("Starting bootstrap") should_use_eventbridge = config.get_should_use_eventbridge( puppet_account_id, os.environ.get("AWS_DEFAULT_REGION") ) initialiser_stack_tags = config.get_initialiser_stack_tags() if should_use_eventbridge: with betterboto_client.ClientContextManager("events") as events: try: events.describe_event_bus(Name=constants.EVENT_BUS_NAME) except events.exceptions.ResourceNotFoundException: events.create_event_bus(Name=constants.EVENT_BUS_NAME,) all_regions = config.get_regions( puppet_account_id, os.environ.get("AWS_DEFAULT_REGION") ) with betterboto_client.MultiRegionClientContextManager( "cloudformation", all_regions ) as clients: click.echo("Creating {}-regional".format(constants.BOOTSTRAP_STACK_NAME)) threads = [] template = hub_bootstrap_region.get_template( constants.VERSION, os.environ.get("AWS_DEFAULT_REGION") ).to_yaml(clean_up=True) args = { "StackName": "{}-regional".format(constants.BOOTSTRAP_STACK_NAME), "TemplateBody": template, "Capabilities": ["CAPABILITY_IAM"], "Parameters": [ { "ParameterKey": "Version", "ParameterValue": constants.VERSION, "UsePreviousValue": False, }, { "ParameterKey": "DefaultRegionValue", "ParameterValue": os.environ.get("AWS_DEFAULT_REGION"), "UsePreviousValue": False, }, ], "Tags": [{"Key": "ServiceCatalogPuppet:Actor", "Value": "Framework",}] + initialiser_stack_tags, } for client_region, client in clients.items(): process = Thread( name=client_region, target=client.create_or_update, kwargs=args ) process.start() threads.append(process) for process in threads: process.join() click.echo( "Finished creating {}-regional".format(constants.BOOTSTRAP_STACK_NAME) ) source_args = {"Provider": source_provider} if source_provider == "CodeCommit": source_args.update( { "Configuration": { "RepositoryName": repo, "BranchName": branch, "PollForSourceChanges": poll_for_source_changes, }, } ) elif source_provider == "GitHub": source_args.update( { "Configuration": { "Owner": owner, "Repo": repo, "Branch": branch, "PollForSourceChanges": poll_for_source_changes, "SecretsManagerSecret": webhook_secret, }, } ) elif source_provider.lower() == "codestarsourceconnection": source_args.update( { "Configuration": { "ConnectionArn": scm_connection_arn, "FullRepositoryId": scm_full_repository_id, "BranchName": scm_branch_name, "OutputArtifactFormat": "CODE_ZIP", "DetectChanges": poll_for_source_changes, }, } ) elif source_provider.lower() == "s3": source_args.update( { "Configuration": { "S3Bucket": scm_bucket_name, "S3ObjectKey": scm_object_key, "PollForSourceChanges": poll_for_source_changes, }, } ) elif source_provider.lower() == "custom": source_args.update( { "Configuration": { "Owner": "Custom", "GitUrl": custom_source_action_git_url, "Branch": branch, "GitWebHookIpAddress": custom_source_action_git_web_hook_ip_address, "CustomActionTypeVersion": custom_source_action_custom_action_type_version, "CustomActionTypeProvider": custom_source_action_custom_action_type_provider, }, } ) template = hub_bootstrap.get_template( constants.VERSION, all_regions, source_args, config.is_caching_enabled( puppet_account_id, os.environ.get("AWS_DEFAULT_REGION") ), with_manual_approvals, scm_skip_creation_of_repo, should_validate, ).to_yaml(clean_up=True) args = { "StackName": constants.BOOTSTRAP_STACK_NAME, "TemplateBody": template, "Capabilities": ["CAPABILITY_NAMED_IAM"], "Parameters": [ { "ParameterKey": "Version", "ParameterValue": constants.VERSION, "UsePreviousValue": False, }, { "ParameterKey": "OrgIamRoleArn", "ParameterValue": str(config.get_org_iam_role_arn(puppet_account_id)), "UsePreviousValue": False, }, { "ParameterKey": "WithManualApprovals", "ParameterValue": "Yes" if with_manual_approvals else "No", "UsePreviousValue": False, }, { "ParameterKey": "PuppetCodePipelineRolePermissionBoundary", "ParameterValue": puppet_code_pipeline_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "SourceRolePermissionsBoundary", "ParameterValue": source_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetGenerateRolePermissionBoundary", "ParameterValue": puppet_generate_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetDeployRolePermissionBoundary", "ParameterValue": puppet_deploy_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetProvisioningRolePermissionsBoundary", "ParameterValue": puppet_provisioning_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "CloudFormationDeployRolePermissionsBoundary", "ParameterValue": cloud_formation_deploy_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "DeployEnvironmentComputeType", "ParameterValue": deploy_environment_compute_type, "UsePreviousValue": False, }, { "ParameterKey": "SpokeDeployEnvironmentComputeType", "ParameterValue": spoke_deploy_environment_compute_type, "UsePreviousValue": False, }, { "ParameterKey": "DeployNumWorkers", "ParameterValue": str(deploy_num_workers), "UsePreviousValue": False, }, { "ParameterKey": "PuppetRoleName", "ParameterValue": puppet_role_name, "UsePreviousValue": False, }, { "ParameterKey": "PuppetRolePath", "ParameterValue": puppet_role_path, "UsePreviousValue": False, }, ], "Tags": [{"Key": "ServiceCatalogPuppet:Actor", "Value": "Framework",}] + initialiser_stack_tags, } with betterboto_client.ClientContextManager("cloudformation") as cloudformation: click.echo("Creating {}".format(constants.BOOTSTRAP_STACK_NAME)) cloudformation.create_or_update(**args) buff = io.BytesIO() with zipfile.ZipFile(buff, mode="w", compression=zipfile.ZIP_DEFLATED) as z: z.writestr("parameters.yaml", 'single_account: "000000000000"') with betterboto_client.ClientContextManager("s3") as s3: try: s3.head_object( Bucket=f"sc-puppet-parameterised-runs-{puppet_account_id}", Key="parameters.zip", ) except botocore.exceptions.ClientError as ex: if ex.response["Error"]["Code"] == "404": s3.put_object( Bucket=f"sc-puppet-parameterised-runs-{puppet_account_id}", Key="parameters.zip", Body=buff.getvalue(), ) click.echo("Finished creating {}.".format(constants.BOOTSTRAP_STACK_NAME))
def _do_bootstrap( puppet_version, puppet_account_id, with_manual_approvals, puppet_code_pipeline_role_permission_boundary, source_role_permissions_boundary, puppet_generate_role_permission_boundary, puppet_deploy_role_permission_boundary, puppet_provisioning_role_permissions_boundary, cloud_formation_deploy_role_permissions_boundary, deploy_environment_compute_type="BUILD_GENERAL1_SMALL", deploy_num_workers=10, source_provider=None, owner=None, repo=None, branch=None, poll_for_source_changes=None, webhook_secret=None, ): click.echo("Starting bootstrap") should_use_eventbridge = config.get_should_use_eventbridge( puppet_account_id, os.environ.get("AWS_DEFAULT_REGION")) if should_use_eventbridge: with betterboto_client.ClientContextManager("events") as events: try: events.describe_event_bus(Name=constants.EVENT_BUS_NAME) except events.exceptions.ResourceNotFoundException: events.create_event_bus(Name=constants.EVENT_BUS_NAME, ) all_regions = config.get_regions(puppet_account_id, os.environ.get("AWS_DEFAULT_REGION")) with betterboto_client.MultiRegionClientContextManager( "cloudformation", all_regions) as clients: click.echo("Creating {}-regional".format( constants.BOOTSTRAP_STACK_NAME)) threads = [] template = asset_helpers.read_from_site_packages( "{}.template.yaml".format("{}-regional".format( constants.BOOTSTRAP_STACK_NAME))) template = Template(template).render(VERSION=puppet_version) args = { "StackName": "{}-regional".format(constants.BOOTSTRAP_STACK_NAME), "TemplateBody": template, "Capabilities": ["CAPABILITY_IAM"], "Parameters": [ { "ParameterKey": "Version", "ParameterValue": puppet_version, "UsePreviousValue": False, }, { "ParameterKey": "DefaultRegionValue", "ParameterValue": os.environ.get("AWS_DEFAULT_REGION"), "UsePreviousValue": False, }, ], "Tags": [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }], } for client_region, client in clients.items(): process = Thread(name=client_region, target=client.create_or_update, kwargs=args) process.start() threads.append(process) for process in threads: process.join() click.echo("Finished creating {}-regional".format( constants.BOOTSTRAP_STACK_NAME)) source_args = {"Provider": source_provider} if source_provider == "CodeCommit": source_args.update({ "Configuration": { "RepositoryName": repo, "BranchName": branch, }, }) elif source_provider == "GitHub": source_args.update({ "Configuration": { "Owner": owner, "Repo": repo, "Branch": branch, "PollForSourceChanges": poll_for_source_changes, "SecretsManagerSecret": webhook_secret, }, }) with betterboto_client.ClientContextManager( "cloudformation") as cloudformation: click.echo("Creating {}".format(constants.BOOTSTRAP_STACK_NAME)) template = asset_helpers.read_from_site_packages( "{}.template.yaml".format(constants.BOOTSTRAP_STACK_NAME)) template = Template(template).render(VERSION=puppet_version, ALL_REGIONS=all_regions, Source=source_args) template = Template(template).render(VERSION=puppet_version, ALL_REGIONS=all_regions, Source=source_args) args = { "StackName": constants.BOOTSTRAP_STACK_NAME, "TemplateBody": template, "Capabilities": ["CAPABILITY_NAMED_IAM"], "Parameters": [ { "ParameterKey": "Version", "ParameterValue": puppet_version, "UsePreviousValue": False, }, { "ParameterKey": "OrgIamRoleArn", "ParameterValue": str(config.get_org_iam_role_arn(puppet_account_id)), "UsePreviousValue": False, }, { "ParameterKey": "WithManualApprovals", "ParameterValue": "Yes" if with_manual_approvals else "No", "UsePreviousValue": False, }, { "ParameterKey": "PuppetCodePipelineRolePermissionBoundary", "ParameterValue": puppet_code_pipeline_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "SourceRolePermissionsBoundary", "ParameterValue": source_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetGenerateRolePermissionBoundary", "ParameterValue": puppet_generate_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetDeployRolePermissionBoundary", "ParameterValue": puppet_deploy_role_permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "PuppetProvisioningRolePermissionsBoundary", "ParameterValue": puppet_provisioning_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "CloudFormationDeployRolePermissionsBoundary", "ParameterValue": cloud_formation_deploy_role_permissions_boundary, "UsePreviousValue": False, }, { "ParameterKey": "DeployEnvironmentComputeType", "ParameterValue": deploy_environment_compute_type, "UsePreviousValue": False, }, { "ParameterKey": "DeployNumWorkers", "ParameterValue": str(deploy_num_workers), "UsePreviousValue": False, }, ], } cloudformation.create_or_update(**args) click.echo("Finished creating {}.".format(constants.BOOTSTRAP_STACK_NAME)) if source_provider == "CodeCommit": with betterboto_client.ClientContextManager( "codecommit") as codecommit: response = codecommit.get_repository(repositoryName=repo) clone_url = response.get("repositoryMetadata").get("cloneUrlHttp") clone_command = ( "git clone --config 'credential.helper=!aws codecommit credential-helper $@' " "--config 'credential.UseHttpPath=true' {}".format(clone_url)) click.echo( "You need to clone your newly created repo now and will then need to seed it: \n{}" .format(clone_command))
def expand(f, puppet_account_id, single_account, subset=None): click.echo("Expanding") manifest = manifest_utils.load(f, puppet_account_id) org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id) if org_iam_role_arn is None: click.echo("No org role set - not expanding") new_manifest = manifest else: click.echo("Expanding using role: {}".format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( "organizations", org_iam_role_arn, "org-iam-role" ) as client: new_manifest = manifest_utils.expand_manifest(manifest, client) click.echo("Expanded") if single_account: click.echo(f"Filtering for single account: {single_account}") for account in new_manifest.get("accounts", []): if str(account.get("account_id")) == str(single_account): click.echo(f"Found single account: {single_account}") new_manifest["accounts"] = [account] break click.echo("Filtered") new_manifest = manifest_utils.rewrite_depends_on(new_manifest) new_manifest = manifest_utils.rewrite_ssm_parameters(new_manifest) new_manifest = manifest_utils.rewrite_stacks(new_manifest, puppet_account_id) if subset: click.echo(f"Filtering for subset: {subset}") new_manifest = manifest_utils.isolate( manifest_utils.Manifest(new_manifest), subset ) new_manifest = json.loads(json.dumps(new_manifest)) if new_manifest.get(constants.LAMBDA_INVOCATIONS) is None: new_manifest[constants.LAMBDA_INVOCATIONS] = dict() home_region = config.get_home_region(puppet_account_id) with betterboto_client.ClientContextManager("ssm") as ssm: response = ssm.get_parameter(Name="service-catalog-puppet-version") version = response.get("Parameter").get("Value") new_manifest["config_cache"] = dict( home_region=home_region, regions=config.get_regions(puppet_account_id, home_region), should_collect_cloudformation_events=config.get_should_use_sns( puppet_account_id, home_region ), should_forward_events_to_eventbridge=config.get_should_use_eventbridge( puppet_account_id, home_region ), should_forward_failures_to_opscenter=config.get_should_forward_failures_to_opscenter( puppet_account_id, home_region ), puppet_version=version, ) new_name = f.name.replace(".yaml", "-expanded.yaml") logger.info("Writing new manifest: {}".format(new_name)) with open(new_name, "w") as output: output.write(yaml.safe_dump(new_manifest, default_flow_style=False))
def expand(f, puppet_account_id, single_account, subset=None): click.echo("Expanding") target_directory = os.path.sep.join([os.path.dirname(f.name), "manifests"]) assemble_manifest_from_ssm(target_directory) manifest = manifest_utils.load(f, puppet_account_id) org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id) if org_iam_role_arn is None: click.echo("No org role set - not expanding") new_manifest = manifest else: click.echo("Expanding using role: {}".format(org_iam_role_arn)) with betterboto_client.CrossAccountClientContextManager( "organizations", org_iam_role_arn, "org-iam-role" ) as client: new_manifest = manifest_utils.expand_manifest(manifest, client) click.echo("Expanded") new_manifest = manifest_utils.rewrite_deploy_as_share_to_for_spoke_local_portfolios( new_manifest ) if single_account: click.echo(f"Filtering for single account: {single_account}") for account in new_manifest.get("accounts", []): if str(account.get("account_id")) == str(single_account): click.echo(f"Found single account: {single_account}") new_manifest["accounts"] = [account] break items_to_delete = list() for section_name in constants.ALL_SECTION_NAMES: deploy_to_name = constants.DEPLOY_TO_NAMES[section_name] for item_name, item in new_manifest.get(section_name, {}).items(): accounts = list() for deploy_details in item.get(deploy_to_name, {}).get("accounts", []): if str(deploy_details.get("account_id")) == str(single_account): accounts.append(deploy_details) print(f"{item_name}: there are " + str(len(accounts))) if item.get(deploy_to_name).get("accounts"): if len(accounts) > 0: item[deploy_to_name]["accounts"] = accounts else: if item[deploy_to_name].get("tags") or item[deploy_to_name].get( "ous" ): del item[deploy_to_name]["accounts"] else: items_to_delete.append(f"{section_name}:{item_name}") for item_to_delete in items_to_delete: section_name, item_name = item_to_delete.split(":") del new_manifest[section_name][item_name] click.echo("Filtered") new_manifest = manifest_utils.rewrite_cfct(new_manifest) new_manifest = manifest_utils.rewrite_depends_on(new_manifest) new_manifest = manifest_utils.rewrite_ssm_parameters(new_manifest) new_manifest = manifest_utils.rewrite_stacks(new_manifest, puppet_account_id) new_manifest = manifest_utils.rewrite_scps(new_manifest, puppet_account_id) new_manifest = manifest_utils.parse_conditions(new_manifest) if subset and subset.get("section"): click.echo(f"Filtering for subset: {subset}") new_manifest = manifest_utils.isolate(new_manifest, subset) manifest_accounts_all = [ {"account_id": a.get("account_id"), "email": a.get("email")} for a in new_manifest.get("accounts", []) ] manifest_accounts_excluding = [ a for a in manifest_accounts_all if a.get("account_id") != puppet_account_id ] # handle all accounts sct_manifest_accounts = json.dumps(manifest_accounts_all) sct_manifest_spokes = json.dumps(manifest_accounts_excluding) regions = config.get_regions(puppet_account_id) sct_config_regions = json.dumps(regions) new_manifest["parameters"]["SCTManifestAccounts"] = dict( default=sct_manifest_accounts ) new_manifest["parameters"]["SCTManifestSpokes"] = dict(default=sct_manifest_spokes) new_manifest["parameters"]["SCTConfigRegions"] = dict(default=sct_config_regions) new_manifest["parameters"]["SCTAccountId"] = dict(default=puppet_account_id) if new_manifest.get(constants.LAMBDA_INVOCATIONS) is None: new_manifest[constants.LAMBDA_INVOCATIONS] = dict() home_region = config.get_home_region(puppet_account_id) with betterboto_client.ClientContextManager("ssm") as ssm: response = ssm.get_parameter(Name="service-catalog-puppet-version") version = response.get("Parameter").get("Value") new_manifest["config_cache"] = dict( home_region=home_region, regions=regions, should_collect_cloudformation_events=config.get_should_use_sns( puppet_account_id, home_region ), should_forward_events_to_eventbridge=config.get_should_use_eventbridge( puppet_account_id, home_region ), should_forward_failures_to_opscenter=config.get_should_forward_failures_to_opscenter( puppet_account_id, home_region ), puppet_version=version, ) new_name = f.name.replace(".yaml", "-expanded.yaml") logger.info("Writing new manifest: {}".format(new_name)) with open(new_name, "w") as output: output.write(yaml_utils.dump(new_manifest))