def hub_client(self, service): if self.is_running_in_spoke(): return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.executor_account_id), f"{self.executor_account_id}-{config.get_puppet_role_name()}", ) else: return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.puppet_account_id), f"{self.puppet_account_id}-{config.get_puppet_role_name()}", )
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 get_provisioning_artifact_id_for(portfolio_name, product_name, version_name, account_id, region): logger.info( "Getting provisioning artifact id for: {} {} {} in the region: {} of account: {}" .format(portfolio_name, product_name, version_name, region, account_id)) role = "arn:aws:iam::{}:role/{}".format( account_id, 'servicecatalog-puppet/PuppetRole') with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', role, "-".join([account_id, region]), region_name=region) as cross_account_servicecatalog: product_id = None version_id = None portfolio_id = None args = {} while True: response = cross_account_servicecatalog.list_accepted_portfolio_shares( ) assert response.get( 'NextPageToken') is None, "Pagination not supported" for portfolio_detail in response.get('PortfolioDetails'): if portfolio_detail.get('DisplayName') == portfolio_name: portfolio_id = portfolio_detail.get('Id') break if portfolio_id is None: response = cross_account_servicecatalog.list_portfolios() for portfolio_detail in response.get('PortfolioDetails', []): if portfolio_detail.get('DisplayName') == portfolio_name: portfolio_id = portfolio_detail.get('Id') break assert portfolio_id is not None, "Could not find portfolio" logger.info("Found portfolio: {}".format(portfolio_id)) args['PortfolioId'] = portfolio_id response = cross_account_servicecatalog.search_products_as_admin( **args) for product_view_details in response.get('ProductViewDetails'): product_view = product_view_details.get('ProductViewSummary') if product_view.get('Name') == product_name: logger.info('Found product: {}'.format(product_view)) product_id = product_view.get('ProductId') if response.get('NextPageToken', None) is not None: args['PageToken'] = response.get('NextPageToken') else: break assert product_id is not None, "Did not find product looking for" response = cross_account_servicecatalog.list_provisioning_artifacts( ProductId=product_id) assert response.get('NextPageToken') is None, "Pagination not support" for provisioning_artifact_detail in response.get( 'ProvisioningArtifactDetails'): if provisioning_artifact_detail.get('Name') == version_name: version_id = provisioning_artifact_detail.get('Id') assert version_id is not None, "Did not find version looking for" return product_id, version_id
def hub_regional_client(self, service, region_name=None): region = region_name or self.region if self.is_running_in_spoke(): return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.executor_account_id), f"{self.executor_account_id}-{config.get_puppet_role_name()}", region_name=region, ) else: return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.puppet_account_id), f"{self.puppet_account_id}-{region}-{config.get_puppet_role_name()}", region_name=region, )
def run(self): home_region = config.get_home_region(self.puppet_account_id) with betterboto_client.CrossAccountClientContextManager( "lambda", f"arn:aws:iam::{self.puppet_account_id}:role/servicecatalog-puppet/PuppetRole", f"sc-{home_region}-{self.puppet_account_id}", region_name=home_region, ) as lambda_client: payload = dict( account_id=self.account_id, region=self.region, parameters=self.get_all_params(), ) response = lambda_client.invoke( FunctionName=self.function_name, InvocationType=self.invocation_type, Payload=json.dumps(payload), Qualifier=self.qualifier, ) success_results = dict(RequestResponse=200, Event=202, DryRun=204) if success_results.get(self.invocation_type) != response.get('StatusCode'): raise Exception(f"{self.lambda_invocation_name} failed for {self.account_id}, {self.region}") else: if response.get('FunctionError'): error_payload = response.get('Payload').read() raise Exception(error_payload) else: output = dict(**self.params_for_results_display(), payload=payload, response=response) self.write_output(output)
def run(self): logger.info( f"[{self.launch_name}] {self.account_id}:{self.region} :: " f"starting terminate try {self.try_count} of {self.retry_count}") role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole" with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', role, f'sc-{self.region}-{self.account_id}', region_name=self.region) as service_catalog: logger.info( f"[{self.launch_name}] {self.account_id}:{self.region} :: looking for previous failures" ) provisioned_product_id, provisioning_artifact_id = aws.ensure_is_terminated( service_catalog, self.launch_name, self.product_id) log_output = self.to_str_params() log_output.update({ "provisioned_product_id": provisioned_product_id, }) f = self.output().open('w') f.write(json.dumps( log_output, indent=4, default=str, )) f.close() logger.info( f"[{self.launch_name}] {self.account_id}:{self.region} :: finished terminating" )
def run(self): logger.info(f"[{self.launch_name}] {self.account_id}:{self.region} :: " f"starting dry run terminate try {self.try_count} of {self.retry_count}") role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole" with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', role, f'sc-{self.region}-{self.account_id}', region_name=self.region ) as service_catalog: logger.info(f"[{self.launch_name}] {self.account_id}:{self.region} :: looking for previous failures") r = aws.get_provisioned_product_details(self.product_id, self.launch_name, service_catalog) if r is None: self.write_result( '-', '-', constants.NO_CHANGE, notes='There is nothing to terminate' ) else: provisioned_product_name = service_catalog.describe_provisioning_artifact( ProvisioningArtifactId=r.get('ProvisioningArtifactId'), ProductId=self.product_id, ).get('ProvisioningArtifactDetail').get('Name') if r.get('Status') != "TERMINATED": self.write_result( provisioned_product_name, '-', constants.CHANGE, notes='The product would be terminated' ) else: self.write_result( '-', '-', constants.CHANGE, notes='The product is already terminated' )
def spoke_regional_client(self, service): return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.account_id), f"{self.account_id}-{self.region}-{config.get_puppet_role_name()}", region_name=self.region, )
def apply_migration_policies(role_arn): click.echo("Updating state file") with betterboto_client.CrossAccountClientContextManager( "organizations", role_arn, f"organizations", ) as organizations: list_accounts_response = organizations.list_accounts_single_page() list_roots_response = organizations.list_roots_single_page() root_id = list_roots_response.get("Roots")[0].get("Id") org_path = SEP.join(["environment", root_id]) all_files_in_environment_list = helper.getListOfFiles(org_path) # Step 1 Save Attached policies accounts = { account.get("Id"): account.get("Name") for account in list_accounts_response.get("Accounts") } ous = get_organizational_units(root_id) # list all OUs in org org_ids_map = accounts | ous policy_ids_map = dict() # map SCP name to Ids for file_path in os.listdir(service_control_policies_path): policy = helper.read_json( SEP.join([service_control_policies_path, file_path]))["PolicySummary"] policy_ids_map[helper.get_valid_filename( policy["Name"])] = policy["Id"] # TODO make this in accordance with Eamonn's AWS Organized general way of doing things # so the user will be able to type in the file name and the migration wil be applied reverse_org_ids_map = dict((v, k) for k, v in org_ids_map.items()) for migration_policy in os.listdir( make_individual_migration_policies_path): policy = helper.read_json( SEP.join( [make_individual_migration_policies_path, migration_policy])).get("Migration") policy_id = policy.get("Policy_Id") policy_name = policy.get("Policy_Name") target_name = policy.get("Target") target_id = reverse_org_ids_map[target_name] policy_type = policy.get("Migration_Type") try: org.attach_policy( PolicyId=policy_id, TargetId=target_id ) if policy_type == ATTACH_POLICY else org.detach_policy( PolicyId=policy_id, TargetId=target_id) except: print( f"Error when attempting to {policy_type} {policy_name} on target {target_name}." ) else: print( f"Successfully performed {policy_type} {policy_name} on target {target_name}." )
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 get_portfolio_for(portfolio_name, account_id, region): logger.info(f"Getting portfolio id for: {portfolio_name}") role = f"arn:aws:iam::{account_id}:role/servicecatalog-puppet/PuppetRole" with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', role, "-".join([account_id, region]), region_name=region) as cross_account_servicecatalog: portfolio = None while True: response = cross_account_servicecatalog.list_accepted_portfolio_shares( ) assert response.get( 'NextPageToken') is None, "Pagination not supported" for portfolio_detail in response.get('PortfolioDetails'): if portfolio_detail.get('DisplayName') == portfolio_name: portfolio = portfolio_detail break if portfolio is None: response = cross_account_servicecatalog.list_portfolios() for portfolio_detail in response.get('PortfolioDetails', []): if portfolio_detail.get('DisplayName') == portfolio_name: portfolio = portfolio_detail break assert portfolio is not None, "Could not find portfolio" logger.info(f"Found portfolio: {portfolio}") return portfolio
def run(self): with self.input().get('portfolio').open('r') as f: portfolio_details = json.loads(f.read()) with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole", f"{self.account_id}-{self.region}", region_name=self.region) as cross_account_servicecatalog: product_id = aws.get_product_id_for( cross_account_servicecatalog, portfolio_details.get('portfolio_id'), self.product, ) with self.output().open('w') as f: f.write( json.dumps( { 'product_name': self.product, 'product_id': product_id, 'portfolio_name': portfolio_details.get('portfolio_name'), 'portfolio_id': portfolio_details.get('portfolio_id'), }, indent=4, default=str, ))
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 run(self): all_params = {} for param_name, param_details in self.parameters.items(): if param_details.get('ssm'): with self.input().get('ssm_params').get( param_name).open() as f: all_params[param_name] = json.loads(f.read()).get('Value') if param_details.get('default'): all_params[param_name] = param_details.get('default') logger.info( f"[{self.uid}] :: finished collecting all_params: {all_params}") environmentVariablesOverride = [{ 'name': param_name, 'value': param_details, 'type': 'PLAINTEXT' } for param_name, param_details in all_params.items()] role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole" with betterboto_client.CrossAccountClientContextManager( 'codebuild', role, f'sc-{self.region}-{self.account_id}', region_name=self.region) as codebuild: build = codebuild.start_build_and_wait_for_completion( projectName=self.project_name, environmentVariablesOverride=environmentVariablesOverride, ) if build.get('buildStatus') != 'SUCCEEDED': raise Exception( f"{self.uid}: Build failed: {build.get('buildStatus')}") self.write_output(self.param_kwargs)
def run(self): logger.info( f"[{self.portfolio}] {self.account_id}:{self.region} :: starting creating portfolio" ) role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole" with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', role, f'sc-{self.account_id}-{self.region}', region_name=self.region) as spoke_service_catalog: spoke_portfolio = aws.ensure_portfolio( spoke_service_catalog, self.portfolio, self.provider_name, self.description, ) with self.output().open('w') as f: f.write(json.dumps( spoke_portfolio, indent=4, default=str, )) logger.info( f"[{self.portfolio}] {self.account_id}:{self.region} :: finished creating portfolio" )
def get_required_params(region_name, portfolio, product, version, account_id): logging.info( f"get_required_params for {region_name} {portfolio} {product} {version} {account_id}" ) with betterboto_client.CrossAccountClientContextManager( 'servicecatalog', f"arn:aws:iam::{account_id}:role/servicecatalog-puppet/PuppetRole", f"{account_id}-{region_name}", region_name=region_name) as service_catalog: portfolio_id = aws.get_portfolio_id_for(service_catalog, portfolio) product_id = aws.get_product_id_for(service_catalog, portfolio_id, product) version_id = aws.get_version_id_for(service_catalog, product_id, version) required_parameters = {} response = service_catalog.describe_provisioning_parameters( ProductId=product_id, ProvisioningArtifactId=version_id, PathId=aws.get_path_for_product(service_catalog, product_id, portfolio), ) for provisioning_artifact_parameters in response.get( 'ProvisioningArtifactParameters', []): parameter_key = provisioning_artifact_parameters.get( 'ParameterKey') required_parameters[parameter_key] = True return required_parameters
def hub_regional_client(self, service, region_name=None): region = region_name or self.region return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.puppet_account_id), f"{self.puppet_account_id}-{region}-{config.get_puppet_role_name()}", region_name=region, )
def get_provisioning_artifact_id_for(portfolio_name, product_name, version_name, account_id, region): logger.info( "Getting provisioning artifact id for: {} {} {} in the region: {} of account: {}" .format(portfolio_name, product_name, version_name, region, account_id)) role = "arn:aws:iam::{}:role/{}".format( account_id, "servicecatalog-puppet/PuppetRole") with betterboto_client.CrossAccountClientContextManager( "servicecatalog", role, "-".join([account_id, region]), region_name=region) as cross_account_servicecatalog: product_id = None version_id = None portfolio_id = None response = cross_account_servicecatalog.list_accepted_portfolio_shares( ) assert response.get( "NextPageToken") is None, "Pagination not supported" for portfolio_detail in response.get("PortfolioDetails"): if portfolio_detail.get("DisplayName") == portfolio_name: portfolio_id = portfolio_detail.get("Id") break if portfolio_id is None: response = cross_account_servicecatalog.list_portfolios_single_page( ) for portfolio_detail in response.get("PortfolioDetails", []): if portfolio_detail.get("DisplayName") == portfolio_name: portfolio_id = portfolio_detail.get("Id") break assert portfolio_id is not None, "Could not find portfolio" logger.info( f"Found portfolio: {portfolio_id}, looking for product: {product_name}" ) response = cross_account_servicecatalog.search_products_as_admin_single_page( PortfolioId=portfolio_id) for product_view_details in response.get("ProductViewDetails"): product_view = product_view_details.get("ProductViewSummary") logging.info(f"looking at {product_view.get('Name')}") if product_view.get("Name") == product_name: logger.info("Found product: {}".format(product_view)) product_id = product_view.get("ProductId") assert product_id is not None, "Did not find product looking for" response = cross_account_servicecatalog.list_provisioning_artifacts_single_page( ProductId=product_id) for provisioning_artifact_detail in response.get( "ProvisioningArtifactDetails"): if provisioning_artifact_detail.get("Name") == version_name: version_id = provisioning_artifact_detail.get("Id") assert version_id is not None, "Did not find version looking for" return product_id, version_id
def make_migrations(role_arn) -> None: os.makedirs(SEP.join(["environment", "migrations"]), exist_ok=True) with betterboto_client.CrossAccountClientContextManager( "organizations", role_arn, f"organizations", ) as organizations: make_migrations_for_organizational_units(organizations) make_migrations_for_accounts(organizations)
def on_task_processing_time(task, duration): print_stats() record_event("processing_time", task, {"duration": duration}) task_params = dict(**task.param_kwargs) task_params.update(task.params_for_results_display()) with betterboto_client.CrossAccountClientContextManager( "cloudwatch", config.get_puppet_role_arn(config.get_puppet_account_id()), "cloudwatch-puppethub", ) as cloudwatch: dimensions = [dict( Name="task_type", Value=task.__class__.__name__, )] for note_worthy in [ "launch_name", "region", "account_id", "puppet_account_id", "sharing_mode", "portfolio", "product", "version", "execution", ]: if task_params.get(note_worthy): dimensions.append( dict(Name=note_worthy, Value=task_params.get(note_worthy))) cloudwatch.put_metric_data( Namespace= f"ServiceCatalogTools/Puppet/v1/ProcessingTime/{task.__class__.__name__}", MetricData=[ dict( MetricName=task.__class__.__name__, Dimensions=dimensions, Value=duration, Unit="Seconds", ), ], ) cloudwatch.put_metric_data( Namespace=f"ServiceCatalogTools/Puppet/v1/ProcessingTime/Tasks", MetricData=[ dict( MetricName="Tasks", Dimensions=[ dict(Name="TaskType", Value=task.__class__.__name__) ], Value=duration, Unit="Seconds", ), ], )
def get_home_region(puppet_account_id): if get_local_config("home_region"): return get_local_config("home_region") with betterboto_client.CrossAccountClientContextManager( "ssm", f"arn:aws:iam::{puppet_account_id}:role/servicecatalog-puppet/PuppetRole", f"{puppet_account_id}-PuppetRole", ) as ssm: response = ssm.get_parameter(Name=constants.HOME_REGION_PARAM_NAME) return response.get("Parameter").get("Value")
def run(self): with betterboto_client.CrossAccountClientContextManager( "cloudformation", config.get_puppet_role_arn(self.account_id), f"{self.account_id}-{self.region}-{config.get_puppet_role_name()}", region_name=self.region, ) as cloudformation: self.info(f"About to delete the stack: {self.stack_name}") cloudformation.ensure_deleted(StackName=self.stack_name) self.write_output(self.params_for_results_display())
def hub_client(self, service): kwargs = dict() if os.environ.get(f"CUSTOM_ENDPOINT_{service}"): kwargs["endpoint_url"] = os.environ.get( f"CUSTOM_ENDPOINT_{service}") if self.is_running_in_spoke(): return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.executor_account_id), f"{self.executor_account_id}-{config.get_puppet_role_name()}", **kwargs, ) else: return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.puppet_account_id), f"{self.puppet_account_id}-{config.get_puppet_role_name()}", **kwargs, )
def get_home_region(puppet_account_id): if get_local_config("home_region"): return get_local_config("home_region") with betterboto_client.CrossAccountClientContextManager( "ssm", get_puppet_role_arn(puppet_account_id), f"{puppet_account_id}-{get_puppet_role_name()}", ) as ssm: response = ssm.get_parameter(Name=constants.HOME_REGION_PARAM_NAME) return response.get("Parameter").get("Value")
def run(self): with betterboto_client.CrossAccountClientContextManager( "cloudformation", f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole", f"{self.account_id}-{self.region}-PuppetRole", region_name=self.region, ) as cloudformation: self.info(f"About to delete the stack: {self.stack_name}") cloudformation.ensure_deleted(StackName=self.stack_name) self.write_output(self.params_for_results_display())
def spoke_client(self, service): kwargs = dict() if os.environ.get(f"CUSTOM_ENDPOINT_{service}"): kwargs["endpoint_url"] = os.environ.get( f"CUSTOM_ENDPOINT_{service}") return betterboto_client.CrossAccountClientContextManager( service, config.get_puppet_role_arn(self.account_id), f"{self.account_id}-{config.get_puppet_role_name()}", **kwargs, )
def handler(event, context): request_type = event["RequestType"] try: logger.info(request_type) assumable_role_in_root_account_arn = os.environ.get( "ASSUMABLE_ROLE_IN_ROOT_ACCOUNT_ARN" ) with betterboto_client.CrossAccountClientContextManager( "organizations", assumable_role_in_root_account_arn, "assumable_org_role" ) as organizations: if request_type in ["Create", "Update"]: target_ou = event.get("ResourceProperties").get("TargetOU") account_id = event.get("ResourceProperties").get("AccountId") result = organizations.list_parents_single_page(ChildId=account_id) if len(result.get("Parents", [])) != 1: raise Exception( f"There were unexpected parents for the account_id {account_id}: {json.dumps(result)}" ) current_ou = result.get("Parents")[0].get('Id') if str(target_ou) != "None" and current_ou != target_ou: logger.info("Moving account to new OU") response = organizations.list_roots() if len(response.get("Roots")) != 1: raise Exception("nRoots: {}".format(len(response.get("Roots")))) if str(target_ou).startswith("/"): target = organizations.convert_path_to_ou(target_ou) else: target = target_ou organizations.move_account( AccountId=account_id, SourceParentId=current_ou, DestinationParentId=target, ) send_response( event, context, "SUCCESS", { "Message": f"Moved to {target}", "account_id": account_id, }, ) elif request_type == "Delete": send_response(event, context, "SUCCESS", {"Message": "Deleted"}) else: send_response(event, context, "FAILED", {"Message": "Unexpected"}) except Exception as ex: logger.error(ex) send_response(event, context, "FAILED", {"Message": "Exception"})
def run(self): self.info("Starting") with betterboto_client.CrossAccountClientContextManager( 'cloudformation', f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole", f"{self.account_id}-{self.region}-PuppetRole", region_name=self.region, ) as cloudformation: self.info(f"About to delete the stack: {self.stack_name}") cloudformation.ensure_deleted(StackName=self.stack_name) self.write_output({}) self.info("Finished")
def make_migrations(role_arn: str, root_id: str) -> None: with betterboto_client.CrossAccountClientContextManager( "organizations", role_arn, f"organizations", ) as orgs_client: progress = bar.IncrementalBar("Making migrations", max=2) progress.next() make_migrations_for_organizational_units(orgs_client, root_id) progress.next() make_migrations_for_accounts(orgs_client, root_id) progress.finish()
def import_organization_policies(role_arn, root_id) -> None: with betterboto_client.CrossAccountClientContextManager( "organizations", role_arn, f"organizations" ) as organizations: progress = bar.IncrementalBar("Importing SCPs", max=4) progress.next() remove_any_existing_policy_records(root_id) progress.next() save_all_policies_from_org(root_id, organizations) progress.next() save_targets_for_policy(root_id, organizations) progress.next() progress.finish()