-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Delete methods for CF stacks and S3 files #2981
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
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
1263735
Added methods for cf and s3 files and init UI
hnnasit ba47369
Added unit tests for utils methods and s3_uploader
hnnasit d77f7c4
Removed s3_bucket and s3_prefix click options
hnnasit 3f6f070
Fixed lint errors and added few unit tests
hnnasit af2f929
Make black happy
hnnasit 99f7db4
Added LOG statements
hnnasit e7304ec
Added and updated changes based on CR
hnnasit c2e43db
Fixed the unit tests in artifact_exporter.py
hnnasit dd35d53
Update HELP_TEXT in delete/command.py
hnnasit f43e763
Updated code based on Chris' comments
hnnasit bc9db14
Small changes and fixes based on the comments
hnnasit 401a950
Removed region prompt
hnnasit 46c8bdb
Update SAM context values for profile and region in delete_context.py
hnnasit 3ac180e
Added typing for get_cf_template_name method
hnnasit fb332fd
Added stack_name prompt if the stack_name is not present in samconfig…
hnnasit bf2d4f4
Replace [] with get() for stack-name in delete_context.py
hnnasit 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| """ | ||
| `sam delete` command | ||
| """ | ||
|
|
||
| # Expose the cli object here | ||
| from .command import cli # noqa |
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,90 @@ | ||
| """ | ||
| CLI command for "delete" command | ||
| """ | ||
|
|
||
| import logging | ||
|
|
||
| import click | ||
| from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args | ||
|
|
||
| from samcli.lib.utils.version_checker import check_newer_version | ||
|
|
||
| SHORT_HELP = "Delete an AWS SAM application and the artifacts created by sam deploy." | ||
|
|
||
| HELP_TEXT = """The sam delete command deletes the CloudFormation | ||
| stack and all the artifacts which were created using sam deploy. | ||
|
|
||
| \b | ||
| e.g. sam delete | ||
|
|
||
| \b | ||
| """ | ||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| @click.command( | ||
| "delete", | ||
| short_help=SHORT_HELP, | ||
| context_settings={"ignore_unknown_options": False, "allow_interspersed_args": True, "allow_extra_args": True}, | ||
| help=HELP_TEXT, | ||
| ) | ||
| @click.option( | ||
| "--stack-name", | ||
| required=False, | ||
| help="The name of the AWS CloudFormation stack you want to delete. ", | ||
| ) | ||
| @click.option( | ||
| "--config-file", | ||
| help=( | ||
| "The path and file name of the configuration file containing default parameter values to use. " | ||
| "Its default value is 'samconfig.toml' in project directory. For more information about configuration files, " | ||
| "see: " | ||
| "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." | ||
| ), | ||
| type=click.STRING, | ||
| default="samconfig.toml", | ||
| show_default=True, | ||
| ) | ||
| @click.option( | ||
| "--config-env", | ||
| help=( | ||
| "The environment name specifying the default parameter values in the configuration file to use. " | ||
| "Its default value is 'default'. For more information about configuration files, see: " | ||
| "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html." | ||
| ), | ||
| type=click.STRING, | ||
| default="default", | ||
| show_default=True, | ||
| ) | ||
| @aws_creds_options | ||
| @common_options | ||
| @pass_context | ||
| @check_newer_version | ||
| @print_cmdline_args | ||
| def cli( | ||
| ctx, | ||
| stack_name: str, | ||
| config_file: str, | ||
| config_env: str, | ||
| ): | ||
| """ | ||
| `sam delete` command entry point | ||
| """ | ||
|
|
||
| # All logic must be implemented in the ``do_cli`` method. This helps with easy unit testing | ||
| do_cli( | ||
| stack_name=stack_name, region=ctx.region, config_file=config_file, config_env=config_env, profile=ctx.profile | ||
| ) # pragma: no cover | ||
|
|
||
|
|
||
| def do_cli(stack_name: str, region: str, config_file: str, config_env: str, profile: str): | ||
| """ | ||
| Implementation of the ``cli`` method | ||
| """ | ||
| from samcli.commands.delete.delete_context import DeleteContext | ||
|
|
||
| with DeleteContext( | ||
| stack_name=stack_name, region=region, profile=profile, config_file=config_file, config_env=config_env | ||
| ) as delete_context: | ||
| delete_context.run() | ||
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,144 @@ | ||
| """ | ||
| Delete a SAM stack | ||
| """ | ||
|
|
||
| import boto3 | ||
|
|
||
| import click | ||
| from click import confirm | ||
| from click import prompt | ||
| from samcli.cli.cli_config_file import TomlProvider | ||
| from samcli.lib.utils.botoconfig import get_boto_config_with_user_agent | ||
| from samcli.lib.delete.cf_utils import CfUtils | ||
| from samcli.lib.package.s3_uploader import S3Uploader | ||
| from samcli.lib.package.artifact_exporter import mktempfile, get_cf_template_name | ||
|
|
||
| CONFIG_COMMAND = "deploy" | ||
| CONFIG_SECTION = "parameters" | ||
| TEMPLATE_STAGE = "Original" | ||
|
|
||
|
|
||
| class DeleteContext: | ||
| def __init__(self, stack_name: str, region: str, profile: str, config_file: str, config_env: str): | ||
| self.stack_name = stack_name | ||
| self.region = region | ||
| self.profile = profile | ||
| self.config_file = config_file | ||
| self.config_env = config_env | ||
| self.s3_bucket = None | ||
| self.s3_prefix = None | ||
| self.cf_utils = None | ||
| self.s3_uploader = None | ||
| self.cf_template_file_name = None | ||
| self.delete_artifacts_folder = None | ||
| self.delete_cf_template_file = None | ||
|
|
||
| def __enter__(self): | ||
| self.parse_config_file() | ||
| if not self.stack_name: | ||
| self.stack_name = prompt( | ||
| click.style("\tEnter stack name you want to delete:", bold=True), type=click.STRING | ||
| ) | ||
|
|
||
| return self | ||
|
|
||
| def __exit__(self, *args): | ||
| pass | ||
|
|
||
| def parse_config_file(self): | ||
| """ | ||
| Read the provided config file if it exists and assign the options values. | ||
| """ | ||
| toml_provider = TomlProvider(CONFIG_SECTION, [CONFIG_COMMAND]) | ||
| config_options = toml_provider( | ||
| config_path=self.config_file, config_env=self.config_env, cmd_names=[CONFIG_COMMAND] | ||
| ) | ||
| if config_options: | ||
| if not self.stack_name: | ||
| self.stack_name = config_options.get("stack_name", None) | ||
|
|
||
| # If the stack_name is same as the one present in samconfig file, | ||
| # get the information about parameters if not specified by customer. | ||
| if self.stack_name and self.stack_name == config_options.get("stack_name", None): | ||
| if not self.region: | ||
| self.region = config_options.get("region", None) | ||
| click.get_current_context().region = self.region | ||
| if not self.profile: | ||
| self.profile = config_options.get("profile", None) | ||
| click.get_current_context().profile = self.profile | ||
| self.s3_bucket = config_options.get("s3_bucket", None) | ||
| self.s3_prefix = config_options.get("s3_prefix", None) | ||
|
|
||
| def delete(self): | ||
| """ | ||
| Delete method calls for Cloudformation stacks and S3 and ECR artifacts | ||
| """ | ||
| template = self.cf_utils.get_stack_template(self.stack_name, TEMPLATE_STAGE) | ||
| template_str = template.get("TemplateBody", None) | ||
|
|
||
| if self.s3_bucket and self.s3_prefix and template_str: | ||
| self.delete_artifacts_folder = confirm( | ||
| click.style( | ||
| "\tAre you sure you want to delete the folder" | ||
| + f" {self.s3_prefix} in S3 which contains the artifacts?", | ||
| bold=True, | ||
| ), | ||
| default=False, | ||
| ) | ||
| if not self.delete_artifacts_folder: | ||
| with mktempfile() as temp_file: | ||
| self.cf_template_file_name = get_cf_template_name( | ||
| temp_file=temp_file, template_str=template_str, extension="template" | ||
| ) | ||
| self.delete_cf_template_file = confirm( | ||
| click.style( | ||
| "\tDo you want to delete the template file" + f" {self.cf_template_file_name} in S3?", bold=True | ||
| ), | ||
| default=False, | ||
| ) | ||
|
|
||
| # Delete the primary stack | ||
| self.cf_utils.delete_stack(stack_name=self.stack_name) | ||
|
|
||
| click.echo(f"\n\t- Deleting Cloudformation stack {self.stack_name}") | ||
|
|
||
| # Delete the CF template file in S3 | ||
| if self.delete_cf_template_file: | ||
| self.s3_uploader.delete_artifact(remote_path=self.cf_template_file_name) | ||
|
|
||
| # Delete the folder of artifacts if s3_bucket and s3_prefix provided | ||
| elif self.delete_artifacts_folder: | ||
| self.s3_uploader.delete_prefix_artifacts() | ||
|
|
||
| def run(self): | ||
| """ | ||
| Delete the stack based on the argument provided by customers and samconfig.toml. | ||
| """ | ||
| delete_stack = confirm( | ||
| click.style( | ||
| f"\tAre you sure you want to delete the stack {self.stack_name}" + f" in the region {self.region} ?", | ||
| bold=True, | ||
| ), | ||
| default=False, | ||
| ) | ||
| # Fetch the template using the stack-name | ||
| if delete_stack and self.region: | ||
| boto_config = get_boto_config_with_user_agent() | ||
|
|
||
| # Define cf_client based on the region as different regions can have same stack-names | ||
| cloudformation_client = boto3.client( | ||
| "cloudformation", region_name=self.region if self.region else None, config=boto_config | ||
| ) | ||
|
|
||
| s3_client = boto3.client("s3", region_name=self.region if self.region else None, config=boto_config) | ||
|
|
||
| self.s3_uploader = S3Uploader(s3_client=s3_client, bucket_name=self.s3_bucket, prefix=self.s3_prefix) | ||
| self.cf_utils = CfUtils(cloudformation_client) | ||
|
|
||
| is_deployed = self.cf_utils.has_stack(stack_name=self.stack_name) | ||
|
|
||
| if is_deployed: | ||
| self.delete() | ||
| click.echo("\nDeleted successfully") | ||
| else: | ||
| click.echo(f"Error: The input stack {self.stack_name} does not exist on Cloudformation") |
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,24 @@ | ||
| """ | ||
| Exceptions that are raised by sam delete | ||
| """ | ||
| from samcli.commands.exceptions import UserException | ||
|
|
||
|
|
||
| class DeleteFailedError(UserException): | ||
| def __init__(self, stack_name, msg): | ||
| self.stack_name = stack_name | ||
| self.msg = msg | ||
|
|
||
| message_fmt = "Failed to delete the stack: {stack_name}, {msg}" | ||
|
|
||
| super().__init__(message=message_fmt.format(stack_name=self.stack_name, msg=msg)) | ||
|
|
||
|
|
||
| class FetchTemplateFailedError(UserException): | ||
| def __init__(self, stack_name, msg): | ||
| self.stack_name = stack_name | ||
| self.msg = msg | ||
|
|
||
| message_fmt = "Failed to fetch the template for the stack: {stack_name}, {msg}" | ||
|
|
||
| super().__init__(message=message_fmt.format(stack_name=self.stack_name, msg=msg)) |
Empty file.
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.