def test_read_from_site_packages(mocked_open): # setup from servicecatalog_puppet import asset_helpers as sut expected_param = os.path.sep.join( [os.path.dirname(os.path.abspath(__file__)), "foo"]) # exercise sut.read_from_site_packages("foo") # verify assert mocked_open.call_count == 1 assert mocked_open.call_args == call(expected_param, "r")
def _do_bootstrap_spoke(puppet_account_id, cloudformation, puppet_version): logger.info('Starting bootstrap of spoke') template = asset_helpers.read_from_site_packages( '{}-spoke.template.yaml'.format(constants.BOOTSTRAP_STACK_NAME)) template = Template(template).render(VERSION=puppet_version) args = { 'StackName': "{}-spoke".format(constants.BOOTSTRAP_STACK_NAME), 'TemplateBody': template, 'Capabilities': ['CAPABILITY_NAMED_IAM'], 'Parameters': [ { 'ParameterKey': 'PuppetAccountId', 'ParameterValue': str(puppet_account_id), }, { 'ParameterKey': 'Version', 'ParameterValue': puppet_version, 'UsePreviousValue': False, }, ], 'Tags': [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }] } cloudformation.create_or_update(**args) logger.info('Finished bootstrap of spoke')
def _do_bootstrap_spoke(puppet_account_id, cloudformation, puppet_version, permission_boundary): logger.info("Starting bootstrap of spoke") template = asset_helpers.read_from_site_packages( "{}-spoke.template.yaml".format(constants.BOOTSTRAP_STACK_NAME)) template = Template(template).render(VERSION=puppet_version) args = { "StackName": "{}-spoke".format(constants.BOOTSTRAP_STACK_NAME), "TemplateBody": template, "Capabilities": ["CAPABILITY_NAMED_IAM"], "Parameters": [ { "ParameterKey": "PuppetAccountId", "ParameterValue": str(puppet_account_id), }, { "ParameterKey": "PermissionBoundary", "ParameterValue": permission_boundary, "UsePreviousValue": False, }, { "ParameterKey": "Version", "ParameterValue": puppet_version, "UsePreviousValue": False, }, ], "Tags": [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }], } cloudformation.create_or_update(**args) logger.info("Finished bootstrap of spoke")
def quick_start(): click.echo("Quick Start running...") puppet_version = cli_command_helpers.get_puppet_version() with betterboto_client.ClientContextManager('sts') as sts: puppet_account_id = sts.get_caller_identity().get('Account') click.echo( "Going to use puppet_account_id: {}".format(puppet_account_id)) click.echo("Bootstrapping account as a spoke") with betterboto_client.ClientContextManager( 'cloudformation') as cloudformation: cli_command_helpers._do_bootstrap_spoke(puppet_account_id, cloudformation, puppet_version) click.echo("Setting the config") content = yaml.safe_dump( {"regions": ['eu-west-1', 'eu-west-2', 'eu-west-3']}) with betterboto_client.ClientContextManager('ssm') as ssm: ssm.put_parameter( Name=constants.CONFIG_PARAM_NAME, Type='String', Value=content, Overwrite=True, ) click.echo("Bootstrapping account as the master") org_iam_role_arn = cli_command_helpers._do_bootstrap_org_master( puppet_account_id, cloudformation, puppet_version) ssm.put_parameter( Name=constants.CONFIG_PARAM_NAME_ORG_IAM_ROLE_ARN, Type='String', Value=org_iam_role_arn, Overwrite=True, ) click.echo("Bootstrapping the account now!") cli_command_helpers._do_bootstrap(puppet_version) if os.path.exists('ServiceCatalogPuppet'): click.echo("Found ServiceCatalogPuppet so not cloning or seeding") else: click.echo("Cloning for you") command = "git clone " \ "--config 'credential.helper=!aws codecommit credential-helper $@' " \ "--config 'credential.UseHttpPath=true' " \ "https://git-codecommit.{}.amazonaws.com/v1/repos/ServiceCatalogPuppet".format( os.environ.get("AWS_DEFAULT_REGION") ) os.system(command) click.echo("Seeding") manifest = Template( asset_helpers.read_from_site_packages( os.path.sep.join(["manifests", "manifest-quickstart.yaml" ]))).render(ACCOUNT_ID=puppet_account_id) open(os.path.sep.join(["ServiceCatalogPuppet", "manifest.yaml"]), 'w').write(manifest) click.echo("Pushing manifest") os.system( "cd ServiceCatalogPuppet && git add manifest.yaml && git commit -am 'initial add' && git push" ) click.echo("All done!")
def bootstrap_org_master(puppet_account_id): with betterboto_client.ClientContextManager( 'cloudformation', ) as cloudformation: org_iam_role_arn = None puppet_version = config.get_puppet_version() logger.info('Starting bootstrap of org master') stack_name = f"{constants.BOOTSTRAP_STACK_NAME}-org-master-{puppet_account_id}" template = asset_helpers.read_from_site_packages( f'{constants.BOOTSTRAP_STACK_NAME}-org-master.template.yaml') template = Template(template).render( VERSION=puppet_version, puppet_account_id=puppet_account_id) args = { 'StackName': stack_name, 'TemplateBody': template, 'Capabilities': ['CAPABILITY_NAMED_IAM'], 'Parameters': [ { 'ParameterKey': 'PuppetAccountId', 'ParameterValue': str(puppet_account_id), }, { 'ParameterKey': 'Version', 'ParameterValue': puppet_version, 'UsePreviousValue': False, }, ], 'Tags': [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }] } cloudformation.create_or_update(**args) response = cloudformation.describe_stacks(StackName=stack_name) if len(response.get('Stacks')) != 1: raise Exception( "Expected there to be only one {} stack".format(stack_name)) stack = response.get('Stacks')[0] for output in stack.get('Outputs'): if output.get( 'OutputKey') == constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN: logger.info('Finished bootstrap of org-master') org_iam_role_arn = output.get("OutputValue") if org_iam_role_arn is None: raise Exception("Could not find output: {} in stack: {}".format( constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN, stack_name)) click.echo("Bootstrapped org master, org-iam-role-arn: {}".format( org_iam_role_arn))
def bootstrap_org_master(puppet_account_id): with betterboto_client.ClientContextManager( "cloudformation", ) as cloudformation: org_iam_role_arn = None logger.info("Starting bootstrap of org master") stack_name = f"{constants.BOOTSTRAP_STACK_NAME}-org-master-{puppet_account_id}" template = asset_helpers.read_from_site_packages( f"{constants.BOOTSTRAP_STACK_NAME}-org-master.template.yaml") template = Template(template).render( VERSION=constants.VERSION, puppet_account_id=puppet_account_id) args = { "StackName": stack_name, "TemplateBody": template, "Capabilities": ["CAPABILITY_NAMED_IAM"], "Parameters": [ { "ParameterKey": "PuppetAccountId", "ParameterValue": str(puppet_account_id), }, { "ParameterKey": "Version", "ParameterValue": constants.VERSION, "UsePreviousValue": False, }, ], "Tags": [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }], } cloudformation.create_or_update(**args) response = cloudformation.describe_stacks(StackName=stack_name) if len(response.get("Stacks")) != 1: raise Exception( "Expected there to be only one {} stack".format(stack_name)) stack = response.get("Stacks")[0] for output in stack.get("Outputs"): if output.get( "OutputKey") == constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN: logger.info("Finished bootstrap of org-master") org_iam_role_arn = output.get("OutputValue") if org_iam_role_arn is None: raise Exception("Could not find output: {} in stack: {}".format( constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN, stack_name)) click.echo("Bootstrapped org master, org-iam-role-arn: {}".format( org_iam_role_arn))
def _do_bootstrap_org_master(puppet_account_id, cloudformation, puppet_version): logger.info('Starting bootstrap of org master') stack_name = "{}-org-master".format(constants.BOOTSTRAP_STACK_NAME) template = asset_helpers.read_from_site_packages( '{}.template.yaml'.format(stack_name)) template = Template(template).render(VERSION=puppet_version) args = { 'StackName': stack_name, 'TemplateBody': template, 'Capabilities': ['CAPABILITY_NAMED_IAM'], 'Parameters': [ { 'ParameterKey': 'PuppetAccountId', 'ParameterValue': str(puppet_account_id), }, { 'ParameterKey': 'Version', 'ParameterValue': puppet_version, 'UsePreviousValue': False, }, ], 'Tags': [{ "Key": "ServiceCatalogPuppet:Actor", "Value": "Framework", }] } cloudformation.create_or_update(**args) response = cloudformation.describe_stacks(StackName=stack_name) if len(response.get('Stacks')) != 1: raise Exception( "Expected there to be only one {} stack".format(stack_name)) stack = response.get('Stacks')[0] for output in stack.get('Outputs'): if output.get( 'OutputKey') == constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN: logger.info('Finished bootstrap of org-master') return output.get("OutputValue") raise Exception("Could not find output: {} in stack: {}".format( constants.PUPPET_ORG_ROLE_FOR_EXPANDS_ARN, stack_name))
def _do_bootstrap(puppet_version, with_manual_approvals): click.echo('Starting bootstrap') ALL_REGIONS = 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(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 _do_bootstrap( puppet_version, 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, ): 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, }, { '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)) 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 _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))