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)
Exemple #3
0
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))
Exemple #6
0
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))
Exemple #10
0
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))