Skip to content
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

fix: Skip image-repository validation of ECR images (#2934) #3015

Closed
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
18 changes: 18 additions & 0 deletions samcli/commands/_utils/parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
Template parameters utilities shared by various commands
"""

from typing import Dict, Union, Optional


def sanitize_parameter_overrides(
parameter_overrides: Dict[str, Union[Dict[str, str], str]]
) -> Dict[str, Optional[str]]:
"""
Get sanitized parameter override values based on if the workflow went via a guided deploy to set the
parameter overrides for deployment. If a guided deploy was followed the parameter overrides consists
of additional information such as if a given parameter's value is hidden or not.
:param parameter_overrides: dictionary of parameter key values.
:return:
"""
return {key: value.get("Value") if isinstance(value, dict) else value for key, value in parameter_overrides.items()}
2 changes: 1 addition & 1 deletion samcli/commands/deploy/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
signing_profiles_option,
image_repositories_callback,
)
from samcli.commands.deploy.utils import sanitize_parameter_overrides
from samcli.commands._utils.parameters import sanitize_parameter_overrides
from samcli.lib.telemetry.metric import track_command
from samcli.lib.cli_validation.image_repository_validation import image_repository_validation
from samcli.lib.utils import osutils
Expand Down
2 changes: 1 addition & 1 deletion samcli/commands/deploy/deploy_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

from samcli.commands.deploy import exceptions as deploy_exceptions
from samcli.commands.deploy.auth_utils import auth_per_resource
from samcli.commands._utils.parameters import sanitize_parameter_overrides
from samcli.commands.deploy.utils import (
sanitize_parameter_overrides,
print_deploy_args,
hide_noecho_parameter_overrides,
)
Expand Down
63 changes: 31 additions & 32 deletions samcli/commands/deploy/guided_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@
from click.types import FuncParamType

from samcli.commands._utils.options import _space_separated_list_func_type
from samcli.commands._utils.template import (
get_template_parameters,
get_template_artifacts_format,
get_template_function_resource_ids,
)
from samcli.commands._utils.template import get_template_parameters
from samcli.commands.deploy.auth_utils import auth_per_resource
from samcli.commands.deploy.code_signer_utils import (
signer_config_per_function,
Expand All @@ -26,7 +22,7 @@
)
from samcli.commands.deploy.exceptions import GuidedDeployFailedError
from samcli.commands.deploy.guided_config import GuidedConfig
from samcli.commands.deploy.utils import sanitize_parameter_overrides
from samcli.commands._utils.parameters import sanitize_parameter_overrides
from samcli.lib.bootstrap.bootstrap import manage_stack
from samcli.lib.config.samconfig import DEFAULT_ENV, DEFAULT_CONFIG_FILE_NAME
from samcli.lib.intrinsic_resolver.intrinsics_symbol_table import IntrinsicsSymbolTable
Expand Down Expand Up @@ -305,33 +301,36 @@ def prompt_image_repository(self, stacks: List[Stack]):
A dictionary contains image function logical ID as key, image repository as value.
"""
image_repositories = {}
artifacts_format = get_template_artifacts_format(template_file=self.template_file)
if IMAGE in artifacts_format:
self.function_provider = SamFunctionProvider(stacks, ignore_code_extraction_warnings=True)
function_resources = get_template_function_resource_ids(template_file=self.template_file, artifact=IMAGE)
for resource_id in function_resources:
image_repositories[resource_id] = prompt(
f"\t{self.start_bold}Image Repository for {resource_id}{self.end_bold}",
default=self.image_repositories.get(resource_id, "")
if isinstance(self.image_repositories, dict)
else "" or self.image_repository,

self.function_provider = SamFunctionProvider(stacks, ignore_code_extraction_warnings=True)

for resource_id in (
resource_id
for resource_id, function in self.function_provider.functions.items()
if function.packagetype == IMAGE
):
image_repositories[resource_id] = prompt(
f"\t{self.start_bold}Image Repository for {resource_id}{self.end_bold}",
default=self.image_repositories.get(resource_id, "")
if isinstance(self.image_repositories, dict)
else "" or self.image_repository,
)
if resource_id not in image_repositories or not is_ecr_url(image_repositories[resource_id]):
raise GuidedDeployFailedError(
f"Invalid Image Repository ECR URI: {image_repositories.get(resource_id)}"
)
if resource_id not in image_repositories or not is_ecr_url(str(image_repositories[resource_id])):
raise GuidedDeployFailedError(
f"Invalid Image Repository ECR URI: {image_repositories.get(resource_id)}"
)
for resource_id, function_prop in self.function_provider.functions.items():
if function_prop.packagetype == IMAGE:
image = function_prop.imageuri
try:
tag = tag_translation(image)
except NonLocalImageException:
pass
except NoImageFoundException as ex:
raise GuidedDeployFailedError("No images found to deploy, try running sam build") from ex
else:
click.secho(f"\t {image} to be pushed to {image_repositories.get(resource_id)}:{tag}")
click.secho(nl=True)
for resource_id, function_prop in self.function_provider.functions.items():
if function_prop.packagetype == IMAGE:
image = function_prop.imageuri
try:
tag = tag_translation(image)
except NonLocalImageException:
pass
except NoImageFoundException as ex:
raise GuidedDeployFailedError("No images found to deploy, try running sam build") from ex
else:
click.secho(f"\t {image} to be pushed to {image_repositories.get(resource_id)}:{tag}")
click.secho(nl=True)

return image_repositories

Expand Down
11 changes: 0 additions & 11 deletions samcli/commands/deploy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,6 @@ def print_deploy_args(
click.secho("\nInitiating deployment\n=====================", fg="yellow")


def sanitize_parameter_overrides(parameter_overrides):
"""
Get sanitized parameter override values based on if the workflow went via a guided deploy to set the
parameter overrides for deployment. If a guided deploy was followed the parameter overrides consists
of additional information such as if a given parameter's value is hidden or not.
:param parameter_overrides: dictionary of parameter key values.
:return:
"""
return {key: value.get("Value") if isinstance(value, dict) else value for key, value in parameter_overrides.items()}


def hide_noecho_parameter_overrides(template_parameters, parameter_overrides):
hidden_params = copy.deepcopy(parameter_overrides)
params = template_parameters.get("Parameters", None)
Expand Down
39 changes: 27 additions & 12 deletions samcli/lib/cli_validation/image_repository_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
import click

from samcli.commands._utils.option_validator import Validator
from samcli.commands._utils.template import get_template_function_resource_ids, get_template_artifacts_format
from samcli.lib.utils.packagetype import IMAGE
from samcli.lib.providers.sam_stack_provider import SamLocalStackProvider
from samcli.lib.providers.sam_function_provider import SamFunctionProvider
from samcli.lib.intrinsic_resolver.intrinsics_symbol_table import IntrinsicsSymbolTable
from samcli.commands._utils.parameters import sanitize_parameter_overrides
from samcli.cli.context import Context


def image_repository_validation(func):
Expand All @@ -22,22 +26,34 @@ def image_repository_validation(func):

def wrapped(*args, **kwargs):
ctx = click.get_current_context()
cli_ctx = Context.get_current_context()

guided = ctx.params.get("guided", False) or ctx.params.get("g", False)
image_repository = ctx.params.get("image_repository", False)
image_repositories = ctx.params.get("image_repositories", False) or {}
template_file = (
ctx.params.get("t", False) or ctx.params.get("template_file", False) or ctx.params.get("template", False)
)
parameter_overrides = ctx.params.get("parameter_overrides", {})

stacks, _ = SamLocalStackProvider.get_stacks(
template_file,
parameter_overrides=sanitize_parameter_overrides(parameter_overrides),
global_parameter_overrides={IntrinsicsSymbolTable.AWS_REGION: cli_ctx.region}
if cli_ctx is not None
else {},
)

# Check if `--image-repository` or `--image-repositories` are required by
# looking for resources that have an IMAGE based packagetype.

required = any(
[
_template_artifact == IMAGE
for _template_artifact in get_template_artifacts_format(template_file=template_file)
]
)
packageable_function_ids = [
resource_id
for resource_id, function in SamFunctionProvider(
stacks, ignore_code_extraction_warnings=True
).functions.items()
if function.packagetype == IMAGE
]

validators = [
Validator(
Expand All @@ -50,7 +66,9 @@ def wrapped(*args, **kwargs):
),
),
Validator(
validation_function=lambda: not guided and not (image_repository or image_repositories) and required,
validation_function=lambda: not guided
and not (image_repository or image_repositories)
and packageable_function_ids,
exception=click.BadOptionUsage(
option_name="--image-repositories",
ctx=ctx,
Expand All @@ -59,10 +77,7 @@ def wrapped(*args, **kwargs):
),
Validator(
validation_function=lambda: not guided
and (
set(image_repositories.keys()) != set(get_template_function_resource_ids(template_file, IMAGE))
and image_repositories
),
and (set(image_repositories.keys()) != set(packageable_function_ids) and image_repositories),
exception=click.BadOptionUsage(
option_name="--image-repositories",
ctx=ctx,
Expand Down
6 changes: 4 additions & 2 deletions samcli/lib/providers/sam_function_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,10 @@ def _extract_functions(
SamFunctionProvider._warn_code_extraction(resource_type, name, code_property_key)
continue

if resource_package_type == IMAGE and SamBaseProvider._is_ecr_uri(
resource_properties.get(image_property_key)
if (
resource_package_type == IMAGE
and ("DockerContext" not in (resource_metadata or {}))
and SamBaseProvider._is_ecr_uri(resource_properties.get(image_property_key))
):
# ImageUri can be an ECR uri, which is not supported
if not ignore_code_extraction_warnings:
Expand Down