Skip to content

feat: Add flag for import existing resources #8114

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

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions samcli/commands/deploy/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@
is_flag=True,
help="Prompt to confirm if the computed changeset is to be deployed by SAM CLI.",
)
@click.option(
"--import-existing-resources/--no-import-existing-resources",
default=False,
required=False,
is_flag=True,
help="Requests CloudFormation to import any existing referenced by the template when creating the changeset.",
)
@click.option(
"--disable-rollback/--no-disable-rollback",
default=False,
Expand Down Expand Up @@ -198,6 +205,7 @@ def cli(
config_file,
config_env,
disable_rollback,
import_existing_resources,
on_failure,
max_wait_duration,
):
Expand Down Expand Up @@ -234,6 +242,7 @@ def cli(
config_env,
resolve_image_repos,
disable_rollback,
import_existing_resources,
on_failure,
max_wait_duration,
) # pragma: no cover
Expand Down Expand Up @@ -268,6 +277,7 @@ def do_cli(
config_env,
resolve_image_repos,
disable_rollback,
import_existing_resources,
on_failure,
max_wait_duration,
):
Expand Down Expand Up @@ -373,6 +383,7 @@ def do_cli(
signing_profiles=guided_context.signing_profiles if guided else signing_profiles,
use_changeset=True,
disable_rollback=guided_context.disable_rollback if guided else disable_rollback,
import_existing_resources=import_existing_resources,
poll_delay=poll_delay,
on_failure=on_failure,
max_wait_duration=max_wait_duration,
Expand Down
1 change: 1 addition & 0 deletions samcli/commands/deploy/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"fail_on_empty_changeset",
"confirm_changeset",
"disable_rollback",
"import_existing_resources",
"on_failure",
"force_upload",
"max_wait_duration",
Expand Down
8 changes: 8 additions & 0 deletions samcli/commands/deploy/deploy_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def __init__(
signing_profiles,
use_changeset,
disable_rollback,
import_existing_resources,
poll_delay,
on_failure,
max_wait_duration,
Expand Down Expand Up @@ -104,6 +105,7 @@ def __init__(
self.signing_profiles = signing_profiles
self.use_changeset = use_changeset
self.disable_rollback = disable_rollback
self.import_existing_resources = import_existing_resources
self.poll_delay = poll_delay
self.on_failure = FailureMode(on_failure) if on_failure else FailureMode.ROLLBACK
self._max_template_size = 51200
Expand Down Expand Up @@ -164,6 +166,7 @@ def run(self):
self.signing_profiles,
self.use_changeset,
self.disable_rollback,
self.import_existing_resources,
)
return self.deploy(
self.stack_name,
Expand All @@ -180,6 +183,7 @@ def run(self):
self.confirm_changeset,
self.use_changeset,
self.disable_rollback,
self.import_existing_resources,
)

def deploy(
Expand All @@ -198,6 +202,7 @@ def deploy(
confirm_changeset: bool = False,
use_changeset: bool = True,
disable_rollback: bool = False,
import_existing_resources: bool = False,
):
"""
Deploy the stack to cloudformation.
Expand Down Expand Up @@ -234,6 +239,8 @@ def deploy(
Involve creation of changesets, false when using sam sync
disable_rollback : bool
Preserves the state of previously provisioned resources when an operation fails
import_existing_resources : bool
Changeset should attempt to import existing resources as supported by cloudformation
"""
stacks, _ = SamLocalStackProvider.get_stacks(
self.template_file,
Expand All @@ -257,6 +264,7 @@ def deploy(
notification_arns=notification_arns,
s3_uploader=s3_uploader,
tags=tags,
import_existing_resources=import_existing_resources,
)
click.echo(self.MSG_SHOWCASE_CHANGESET.format(changeset_id=result["Id"]))

Expand Down
3 changes: 3 additions & 0 deletions samcli/commands/deploy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def print_deploy_args(
signing_profiles,
use_changeset,
disable_rollback,
import_existing_resources,
):
"""
Print a table of the values that are used during a sam deploy.
Expand All @@ -33,6 +34,7 @@ def print_deploy_args(
Region : us-east-1
Confirm changeset : False
Disable rollback : False
Import Existing Resources : False
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-abcdef
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {'MyParamater': '***', 'Parameter2': 'dd'}
Expand Down Expand Up @@ -70,6 +72,7 @@ def print_deploy_args(
if use_changeset:
click.echo(f"\tConfirm changeset : {confirm_changeset}")
click.echo(f"\tDisable rollback : {disable_rollback}")
click.echo(f"\tImport Existing Resources : {import_existing_resources}")
if image_repository:
msg = "Deployment image repository : "
# NOTE(sriram-mv): tab length is 8 spaces.
Expand Down
1 change: 1 addition & 0 deletions samcli/commands/sync/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ def do_cli(
force_upload=True,
signing_profiles=None,
disable_rollback=False,
import_existing_resources=False,
poll_delay=poll_delay,
on_failure=None,
max_wait_duration=60,
Expand Down
38 changes: 33 additions & 5 deletions samcli/lib/deploy/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,16 @@ def has_stack(self, stack_name):
raise e

def create_changeset(
self, stack_name, cfn_template, parameter_values, capabilities, role_arn, notification_arns, s3_uploader, tags
self,
stack_name,
cfn_template,
parameter_values,
capabilities,
role_arn,
notification_arns,
s3_uploader,
tags,
import_existing_resources,
):
"""
Call Cloudformation to create a changeset and wait for it to complete
Expand All @@ -154,6 +163,7 @@ def create_changeset(
:param notification_arns: Arns for sending notifications
:param s3_uploader: S3Uploader object to upload files to S3 buckets
:param tags: Array of tags passed to CloudFormation
:param import_existing_resources: Argument passed to CloudFormation
:return:
"""
if not self.has_stack(stack_name):
Expand Down Expand Up @@ -183,6 +193,7 @@ def create_changeset(
"Parameters": parameter_values,
"Description": "Created by SAM CLI at {0} UTC".format(datetime.utcnow().isoformat()),
"Tags": tags,
"ImportExistingResources": import_existing_resources,
}

kwargs = self._process_kwargs(kwargs, s3_uploader, capabilities, role_arn, notification_arns)
Expand Down Expand Up @@ -245,8 +256,8 @@ def describe_changeset(self, change_set_id, stack_name, **kwargs):
"""
paginator = self._client.get_paginator("describe_change_set")
response_iterator = paginator.paginate(ChangeSetName=change_set_id, StackName=stack_name)
changes = {"Add": [], "Modify": [], "Remove": []}
changes_showcase = {"Add": "+ Add", "Modify": "* Modify", "Remove": "- Delete"}
changes = {"Add": [], "Modify": [], "Remove": [], "Import": []}
changes_showcase = {"Add": "+ Add", "Modify": "* Modify", "Remove": "- Delete", "Import": "~ Import"}
changeset = False
for item in response_iterator:
cf_changes = item.get("Changes")
Expand Down Expand Up @@ -556,11 +567,28 @@ def wait_for_execute(
raise ex

def create_and_wait_for_changeset(
self, stack_name, cfn_template, parameter_values, capabilities, role_arn, notification_arns, s3_uploader, tags
self,
stack_name,
cfn_template,
parameter_values,
capabilities,
role_arn,
notification_arns,
s3_uploader,
tags,
import_existing_resources,
):
try:
result, changeset_type = self.create_changeset(
stack_name, cfn_template, parameter_values, capabilities, role_arn, notification_arns, s3_uploader, tags
stack_name,
cfn_template,
parameter_values,
capabilities,
role_arn,
notification_arns,
s3_uploader,
tags,
import_existing_resources,
)
self.wait_for_changeset(result["Id"], stack_name)
self.describe_changeset(result["Id"], stack_name)
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/commands/deploy/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def setUp(self):
self.use_changeset = True
self.resolve_image_repos = False
self.disable_rollback = False
self.import_existing_resources = False
self.on_failure = None
self.max_wait_duration = 480
MOCK_SAM_CONFIG.reset_mock()
Expand Down Expand Up @@ -103,6 +104,7 @@ def test_all_args(self, mock_deploy_context, mock_deploy_click, mock_package_con
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -130,6 +132,7 @@ def test_all_args(self, mock_deploy_context, mock_deploy_click, mock_package_con
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
poll_delay=os.getenv("SAM_CLI_POLL_DELAY"),
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -221,6 +224,7 @@ def test_all_args_guided_no_to_authorization_confirmation_prompt(
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -323,6 +327,7 @@ def test_all_args_guided_use_defaults(
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -350,6 +355,7 @@ def test_all_args_guided_use_defaults(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=True,
import_existing_resources=False,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -469,6 +475,7 @@ def test_all_args_guided(
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -496,6 +503,7 @@ def test_all_args_guided(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=True,
import_existing_resources=False,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -618,6 +626,7 @@ def test_all_args_guided_no_save_echo_param_to_config(
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -649,6 +658,7 @@ def test_all_args_guided_no_save_echo_param_to_config(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=True,
import_existing_resources=False,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -778,6 +788,7 @@ def test_all_args_guided_no_params_save_config(
signing_profiles=self.signing_profiles,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -805,6 +816,7 @@ def test_all_args_guided_no_params_save_config(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=True,
import_existing_resources=False,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -918,6 +930,7 @@ def test_all_args_guided_no_params_no_save_config(
signing_profiles=self.signing_profiles,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -945,6 +958,7 @@ def test_all_args_guided_no_params_no_save_config(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -996,6 +1010,7 @@ def test_all_args_resolve_s3(
signing_profiles=self.signing_profiles,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -1023,6 +1038,7 @@ def test_all_args_resolve_s3(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -1062,6 +1078,7 @@ def test_resolve_s3_and_s3_bucket_both_set(self):
signing_profiles=self.signing_profiles,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -1114,6 +1131,7 @@ def test_all_args_resolve_image_repos(
signing_profiles=self.signing_profiles,
resolve_image_repos=True,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -1141,6 +1159,7 @@ def test_all_args_resolve_image_repos(
signing_profiles=self.signing_profiles,
use_changeset=True,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
poll_delay=5,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down Expand Up @@ -1189,6 +1208,7 @@ def test_passing_parameter_overrides_to_context(
config_file=self.config_file,
resolve_image_repos=self.resolve_image_repos,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
)
Expand Down Expand Up @@ -1216,6 +1236,7 @@ def test_passing_parameter_overrides_to_context(
signing_profiles=self.signing_profiles,
use_changeset=self.use_changeset,
disable_rollback=self.disable_rollback,
import_existing_resources=self.import_existing_resources,
poll_delay=os.getenv("SAM_CLI_POLL_DELAY"),
on_failure=self.on_failure,
max_wait_duration=self.max_wait_duration,
Expand Down
Loading
Loading