-
Notifications
You must be signed in to change notification settings - Fork 1.2k
sam pipeline bootstrap #2811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
sam pipeline bootstrap #2811
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
83fc54a
two-stages-pipeline plugin
elbayaaa 9f0147a
typos
elbayaaa 3946009
add docstring
elbayaaa d3db05b
make mypy happy
elbayaaa 201de2e
removing swap file
elbayaaa 1d2cc06
delete the two_stages_pipeline plugin as the pipeline-bootstrap comma…
elbayaaa 588d4ab
remove 'get_template_function_runtimes' function as the decision is m…
elbayaaa 46402f0
sam pipeline bootstrap command
elbayaaa 9747413
move the pipelineconfig.toml file to .aws-sam
elbayaaa 8a7404e
UX - rewriting
elbayaaa 6e3f21d
UX improvements
elbayaaa 58e48a2
make black happy
elbayaaa 206b7e3
apply review comments
elbayaaa 23148ff
UX - rewriting
elbayaaa 37a4f5f
refactor
elbayaaa 8ea4153
Apply review comments
elbayaaa 99c91c8
use python way of array elements assignments
elbayaaa b4c248f
Update samcli/lib/pipeline/bootstrap/stage.py
elbayaaa 3acea8c
apply review comments
elbayaaa 99bef0b
typo
elbayaaa eacfe9c
read using utf-8
elbayaaa 5fdd32a
create and user a safe version of the save_config method
elbayaaa 83712cd
apply review comments
elbayaaa 2c3ad8b
rename _get_command_name to _get_command_names
elbayaaa d184e16
don't save generated ARNs for now, will save during init
elbayaaa 6d9fb34
Revert "don't save generated ARNs for now, will save during init"
elbayaaa 0f1152c
Notify the user to rotate periodically rotate the IAM credentials
elbayaaa 1721c35
typo
elbayaaa 15b64d9
Use AES instead of KMS for S3 SSE
elbayaaa b1e31c0
rename Ecr to ECR and Iam to IAM
elbayaaa 050827a
Grant lambda service explicit permissions to thhe ECR instead of rely…
elbayaaa 0444e0c
Merge branch 'sam-pipelines' into sam-pipelines
elbayaaa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,216 @@ | ||
| """ | ||
| CLI command for "pipeline bootstrap", which sets up the require pipeline infrastructure resources | ||
| """ | ||
| import os | ||
| from typing import Any, Dict, List, Optional | ||
|
|
||
| import click | ||
|
|
||
| from samcli.cli.cli_config_file import configuration_option, TomlProvider | ||
| from samcli.cli.context import get_cmd_names | ||
| from samcli.cli.main import pass_context, common_options, aws_creds_options, print_cmdline_args | ||
| from samcli.lib.config.samconfig import SamConfig | ||
| from samcli.lib.pipeline.bootstrap.stage import Stage | ||
| from samcli.lib.telemetry.metric import track_command | ||
| from samcli.lib.utils.version_checker import check_newer_version | ||
| from .guided_context import GuidedContext | ||
|
|
||
| SHORT_HELP = "Sets up infrastructure resources for AWS SAM CI/CD pipelines." | ||
|
|
||
| HELP_TEXT = """Sets up the following infrastructure resources for AWS SAM CI/CD pipelines: | ||
elbayaaa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| \n\t - Pipeline IAM user with access key ID and secret access key credentials to be shared with the CI/CD provider | ||
| \n\t - Pipeline execution IAM role assumed by the pipeline user to obtain access to the AWS account | ||
| \n\t - CloudFormation execution IAM role assumed by CloudFormation to deploy the AWS SAM application | ||
| \n\t - Artifacts S3 bucket to hold the AWS SAM build artifacts | ||
| \n\t - Optionally, an ECR repository to hold container image Lambda deployment packages | ||
| """ | ||
|
|
||
| PIPELINE_CONFIG_DIR = os.path.join(".aws-sam", "pipeline") | ||
| PIPELINE_CONFIG_FILENAME = "pipelineconfig.toml" | ||
|
|
||
|
|
||
| @click.command("bootstrap", short_help=SHORT_HELP, help=HELP_TEXT, context_settings=dict(max_content_width=120)) | ||
| @configuration_option(provider=TomlProvider(section="parameters")) | ||
| @click.option( | ||
| "--interactive/--no-interactive", | ||
elbayaaa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| is_flag=True, | ||
| default=True, | ||
| help="Disable interactive prompting for bootstrap parameters, and fail if any required arguments are missing.", | ||
| ) | ||
| @click.option( | ||
| "--stage-name", | ||
| help="The name of the corresponding pipeline stage. It is used as a suffix for the created resources.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--pipeline-user", | ||
| help="The ARN of the IAM user having its access key ID and secret access key shared with the CI/CD provider. " | ||
| "It is used to grant this IAM user the permissions to access the corresponding AWS account. " | ||
| "If not provided, the command will create one along with access key ID and secret access key credentials.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--pipeline-execution-role", | ||
| help="The ARN of an IAM role to be assumed by the pipeline user to operate on this stage. " | ||
| "Provide it only if you want to user your own role, otherwise, the command will create one", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--cloudformation-execution-role", | ||
| help="The ARN of an IAM role to be assumed by the CloudFormation service while deploying the application's stack. " | ||
| "Provide it only if you want to user your own role, otherwise, the command will create one.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--artifacts-bucket", | ||
| help="The ARN of an S3 bucket to hold the AWS SAM build artifacts. " | ||
| "Provide it only if you want to user your own S3 bucket, otherwise, the command will create one.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--create-ecr-repo/--no-create-ecr-repo", | ||
elbayaaa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| is_flag=True, | ||
| default=False, | ||
| help="If set to true and no ECR repository is provided, this command will create an ECR repository to hold the" | ||
| " container images of Lambda functions having an Image package type.", | ||
| ) | ||
| @click.option( | ||
| "--ecr-repo", | ||
| help="The ARN of an ECR repository to hold the containers images of Lambda functions of Image package type. " | ||
| "If provided, the --create-ecr-repo argument is ignored. If not provided and --create-ecr-repo is set to true, " | ||
| "the command will create one.", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--pipeline-ip-range", | ||
| help="If provided, all requests coming from outside of the given range are denied. Example: 10.24.34.0/24", | ||
| required=False, | ||
| ) | ||
| @click.option( | ||
| "--confirm-changeset/--no-confirm-changeset", | ||
elbayaaa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| default=True, | ||
| is_flag=True, | ||
| help="Prompt to confirm if the resources is to be deployed by SAM CLI.", | ||
| ) | ||
| @common_options | ||
| @aws_creds_options | ||
| @pass_context | ||
| @track_command | ||
| @check_newer_version | ||
| @print_cmdline_args | ||
| def cli( | ||
| ctx: Any, | ||
| interactive: bool, | ||
| stage_name: Optional[str], | ||
| pipeline_user: Optional[str], | ||
| pipeline_execution_role: Optional[str], | ||
| cloudformation_execution_role: Optional[str], | ||
| artifacts_bucket: Optional[str], | ||
| create_ecr_repo: bool, | ||
| ecr_repo: Optional[str], | ||
| pipeline_ip_range: Optional[str], | ||
| confirm_changeset: bool, | ||
| config_file: Optional[str], | ||
| config_env: Optional[str], | ||
| ) -> None: | ||
| """ | ||
| `sam pipeline bootstrap` command entry point | ||
| """ | ||
| do_cli( | ||
| region=ctx.region, | ||
| profile=ctx.profile, | ||
| interactive=interactive, | ||
| stage_name=stage_name, | ||
| pipeline_user_arn=pipeline_user, | ||
| pipeline_execution_role_arn=pipeline_execution_role, | ||
| cloudformation_execution_role_arn=cloudformation_execution_role, | ||
| artifacts_bucket_arn=artifacts_bucket, | ||
| create_ecr_repo=create_ecr_repo, | ||
| ecr_repo_arn=ecr_repo, | ||
| pipeline_ip_range=pipeline_ip_range, | ||
| confirm_changeset=confirm_changeset, | ||
| config_file=config_env, | ||
| config_env=config_file, | ||
| ) # pragma: no cover | ||
|
|
||
|
|
||
| def do_cli( | ||
| region: Optional[str], | ||
| profile: Optional[str], | ||
| interactive: bool, | ||
| stage_name: Optional[str], | ||
| pipeline_user_arn: Optional[str], | ||
| pipeline_execution_role_arn: Optional[str], | ||
| cloudformation_execution_role_arn: Optional[str], | ||
| artifacts_bucket_arn: Optional[str], | ||
| create_ecr_repo: bool, | ||
| ecr_repo_arn: Optional[str], | ||
| pipeline_ip_range: Optional[str], | ||
| confirm_changeset: bool, | ||
| config_file: Optional[str], | ||
| config_env: Optional[str], | ||
| ) -> None: | ||
| """ | ||
| implementation of `sam pipeline bootstrap` command | ||
| """ | ||
| if not pipeline_user_arn: | ||
| pipeline_user_arn = _load_saved_pipeline_user_arn() | ||
|
|
||
| if interactive: | ||
| guided_context = GuidedContext( | ||
| stage_name=stage_name, | ||
| pipeline_user_arn=pipeline_user_arn, | ||
| pipeline_execution_role_arn=pipeline_execution_role_arn, | ||
| cloudformation_execution_role_arn=cloudformation_execution_role_arn, | ||
| artifacts_bucket_arn=artifacts_bucket_arn, | ||
| create_ecr_repo=create_ecr_repo, | ||
| ecr_repo_arn=ecr_repo_arn, | ||
| pipeline_ip_range=pipeline_ip_range, | ||
| ) | ||
| guided_context.run() | ||
| stage_name = guided_context.stage_name | ||
| pipeline_user_arn = guided_context.pipeline_user_arn | ||
| pipeline_execution_role_arn = guided_context.pipeline_execution_role_arn | ||
| pipeline_ip_range = guided_context.pipeline_ip_range | ||
| cloudformation_execution_role_arn = guided_context.cloudformation_execution_role_arn | ||
| artifacts_bucket_arn = guided_context.artifacts_bucket_arn | ||
| create_ecr_repo = guided_context.create_ecr_repo | ||
| ecr_repo_arn = guided_context.ecr_repo_arn | ||
|
|
||
| if not stage_name: | ||
| raise click.UsageError("Missing required parameter '--stage-name'") | ||
|
|
||
| stage: Stage = Stage( | ||
| name=stage_name, | ||
| aws_profile=profile, | ||
| aws_region=region, | ||
| pipeline_user_arn=pipeline_user_arn, | ||
| pipeline_execution_role_arn=pipeline_execution_role_arn, | ||
| pipeline_ip_range=pipeline_ip_range, | ||
| cloudformation_execution_role_arn=cloudformation_execution_role_arn, | ||
| artifacts_bucket_arn=artifacts_bucket_arn, | ||
| create_ecr_repo=create_ecr_repo, | ||
| ecr_repo_arn=ecr_repo_arn, | ||
| ) | ||
|
|
||
| bootstrapped: bool = stage.bootstrap(confirm_changeset=confirm_changeset) | ||
|
|
||
| if bootstrapped: | ||
| stage.print_resources_summary() | ||
|
|
||
| stage.save_config_safe( | ||
| config_dir=PIPELINE_CONFIG_DIR, filename=PIPELINE_CONFIG_FILENAME, cmd_names=_get_command_names() | ||
| ) | ||
|
|
||
|
|
||
| def _load_saved_pipeline_user_arn() -> Optional[str]: | ||
| samconfig: SamConfig = SamConfig(config_dir=PIPELINE_CONFIG_DIR, filename=PIPELINE_CONFIG_FILENAME) | ||
| if not samconfig.exists(): | ||
| return None | ||
| config: Dict[str, str] = samconfig.get_all(cmd_names=_get_command_names(), section="parameters") | ||
| return config.get("pipeline_user") | ||
|
|
||
|
|
||
| def _get_command_names() -> List[str]: | ||
| ctx = click.get_current_context() | ||
| return get_cmd_names(ctx.info_name, ctx) # ["pipeline", "bootstrap"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| """ | ||
| An interactive flow that prompt the user for required information to bootstrap the AWS account of a pipeline stage | ||
| with the required infrastructure | ||
| """ | ||
| from typing import Optional | ||
|
|
||
| import click | ||
|
|
||
|
|
||
| class GuidedContext: | ||
| def __init__( | ||
| self, | ||
| stage_name: Optional[str] = None, | ||
| pipeline_user_arn: Optional[str] = None, | ||
| pipeline_execution_role_arn: Optional[str] = None, | ||
| cloudformation_execution_role_arn: Optional[str] = None, | ||
| artifacts_bucket_arn: Optional[str] = None, | ||
| create_ecr_repo: bool = False, | ||
| ecr_repo_arn: Optional[str] = None, | ||
| pipeline_ip_range: Optional[str] = None, | ||
| ) -> None: | ||
| self.stage_name = stage_name | ||
| self.pipeline_user_arn = pipeline_user_arn | ||
| self.pipeline_execution_role_arn = pipeline_execution_role_arn | ||
| self.cloudformation_execution_role_arn = cloudformation_execution_role_arn | ||
| self.artifacts_bucket_arn = artifacts_bucket_arn | ||
| self.create_ecr_repo = create_ecr_repo | ||
| self.ecr_repo_arn = ecr_repo_arn | ||
| self.pipeline_ip_range = pipeline_ip_range | ||
|
|
||
| def run(self) -> None: | ||
| """ | ||
| Runs an interactive questionnaire to prompt the user for the ARNs of the AWS resources(infrastructure) required | ||
| for the pipeline to work. Users can provide all, none or some resources' ARNs and leave the remaining empty | ||
| and it will be created by the bootstrap command | ||
| """ | ||
| if not self.stage_name: | ||
| self.stage_name = click.prompt("Stage Name", type=click.STRING) | ||
|
|
||
| if not self.pipeline_user_arn: | ||
| click.echo( | ||
| "\nThere must be exactly one pipeline user across all of the pipeline stages. " | ||
| "If you have ran this command before to bootstrap a previous pipeline stage, please " | ||
| "provide the ARN of the created pipeline user, otherwise, we will create a new user for you. " | ||
| "Please make sure to store the credentials safely with the CI/CD provider." | ||
| ) | ||
| self.pipeline_user_arn = click.prompt( | ||
| "Pipeline user [leave blank to create one]", default="", type=click.STRING | ||
| ) | ||
|
|
||
| if not self.pipeline_execution_role_arn: | ||
| self.pipeline_execution_role_arn = click.prompt( | ||
| "\nPipeline execution role (an IAM role assumed by the pipeline user to operate on this stage) " | ||
| "[leave blank to create one]", | ||
| default="", | ||
| type=click.STRING, | ||
| ) | ||
|
|
||
| if not self.cloudformation_execution_role_arn: | ||
| self.cloudformation_execution_role_arn = click.prompt( | ||
| "\nCloudFormation execution role (an IAM role assumed by CloudFormation to deploy " | ||
| "the application's stack) [leave blank to create one]", | ||
| default="", | ||
| type=click.STRING, | ||
| ) | ||
|
|
||
| if not self.artifacts_bucket_arn: | ||
| self.artifacts_bucket_arn = click.prompt( | ||
| "\nArtifacts bucket (S3 bucket to hold the AWS SAM build artifacts) [leave blank to create one]", | ||
| default="", | ||
| type=click.STRING, | ||
| ) | ||
| if not self.ecr_repo_arn: | ||
| click.echo( | ||
| "\nIf your SAM template includes (or going to include) Lambda functions of Image package type, " | ||
| "then an ECR repository is required. Should we create one?" | ||
| ) | ||
| click.echo("\t1 - No, My SAM template won't include Lambda functions of Image package type") | ||
| click.echo("\t2 - Yes, I need help creating one") | ||
| click.echo("\t3 - I already have an ECR repository") | ||
| choice = click.prompt(text="Choice", show_choices=False, type=click.Choice(["1", "2", "3"])) | ||
| if choice == "1": | ||
| self.create_ecr_repo = False | ||
| elif choice == "2": | ||
| self.create_ecr_repo = True | ||
| else: # choice == "3" | ||
| self.create_ecr_repo = False | ||
| self.ecr_repo_arn = click.prompt("ECR repo", type=click.STRING) | ||
aahung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if not self.pipeline_ip_range: | ||
| click.echo("\nWe can deny requests not coming from a recognized IP address range.") | ||
| self.pipeline_ip_range = click.prompt( | ||
| "Pipeline IP address range (using CIDR notation) [leave blank if you don't know]", | ||
| default="", | ||
| type=click.STRING, | ||
| ) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """ | ||
| Command group for "pipeline" suite for commands. It provides common CLI arguments, template parsing capabilities, | ||
| setting up stdin/stdout etc | ||
| """ | ||
|
|
||
| import click | ||
|
|
||
| from .bootstrap.cli import cli as bootstrap_cli | ||
|
|
||
|
|
||
| @click.group() | ||
| def cli() -> None: | ||
| """ | ||
| Manage the continuous delivery of the application | ||
| """ | ||
|
|
||
|
|
||
| # Add individual commands under this group | ||
| cli.add_command(bootstrap_cli) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.