-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathimage_repository_validation.py
More file actions
141 lines (121 loc) · 5.87 KB
/
image_repository_validation.py
File metadata and controls
141 lines (121 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""
Image Repository Option Validation.
This is to be run last after all CLI options have been processed.
"""
import click
from samcli.commands._utils.option_validator import Validator
from samcli.commands._utils.template import get_template_artifacts_format
from samcli.lib.providers.provider import (
ResourceIdentifier,
get_resource_full_path_by_id,
)
from samcli.lib.providers.sam_function_provider import SamFunctionProvider
from samcli.lib.providers.sam_stack_provider import SamLocalStackProvider
from samcli.lib.utils.packagetype import IMAGE
def image_repository_validation(support_resolve_image_repos=True):
"""
Wrapper Validation function that will run last after the all cli parmaters have been loaded
to check for conditions surrounding `--image-repository`, `--image-repositories`, and `--resolve-image-repos`. The
reason they are done last instead of in callback functions, is because the options depend
on each other, and this breaks cyclic dependencies.
Parameters
----------
support_resolve_image_repos: bool
If it is True, it will be adding `--resolve-image-repos` related error messages below. Default is True.
"""
def decorator(func):
"""
Actual decorator implementation for the validation functionality
:param func: Click command function
:return: Click command function after validation
"""
def wrapped(*args, **kwargs):
ctx = click.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 {}
resolve_image_repos = ctx.params.get("resolve_image_repos", False)
parameters_overrides = ctx.params.get("parameters_overrides", {})
template_file = (
ctx.params.get("t", False)
or ctx.params.get("template_file", False)
or ctx.params.get("template", False)
)
# Check if `--image-repository`, `--image-repositories`, or `--resolve-image-repos` 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)
]
)
available_options = "'--image-repositories', '--image-repository'"
if support_resolve_image_repos:
available_options += ", '--resolve-image-repos'"
image_repos_error_msg = "Incomplete list of function logical ids specified for '--image-repositories'."
if support_resolve_image_repos:
image_repos_error_msg += (
"You can also add --resolve-image-repos to automatically create missing " "repositories."
)
validators = [
Validator(
validation_function=lambda: bool(image_repository)
+ bool(image_repositories)
+ bool(resolve_image_repos)
> 1,
exception=click.BadOptionUsage(
option_name="--image-repositories",
ctx=ctx,
message=f"Only one of the following can be provided: {available_options}. "
"Do you have multiple specified in the command or in a configuration file?",
),
),
Validator(
validation_function=lambda: not guided
and not (image_repository or image_repositories or resolve_image_repos)
and required,
exception=click.BadOptionUsage(
option_name="--image-repositories",
ctx=ctx,
message=f"Missing option {available_options}",
),
),
Validator(
validation_function=lambda: not guided
and (
image_repositories
and not resolve_image_repos
and not _is_all_image_funcs_provided(template_file, image_repositories, parameters_overrides)
),
exception=click.BadOptionUsage(
option_name="--image-repositories", ctx=ctx, message=image_repos_error_msg
),
),
]
for validator in validators:
validator.validate()
# Call Original function after validation.
return func(*args, **kwargs)
return wrapped
return decorator
def _is_all_image_funcs_provided(template_file, image_repositories, parameters_overrides):
"""
Validate that the customer provides ECR repository for every available Lambda function with image package type
"""
image_repositories = image_repositories if image_repositories else {}
global_parameter_overrides = {}
stacks, _ = SamLocalStackProvider.get_stacks(
template_file,
parameter_overrides=parameters_overrides,
global_parameter_overrides=global_parameter_overrides,
)
# updated_repositories = map_resource_id_key_map_to_full_path(image_repositories, stacks)
function_provider = SamFunctionProvider(stacks, ignore_code_extraction_warnings=True)
function_full_paths = {
function.full_path for function in function_provider.get_all() if function.packagetype == IMAGE
}
image_repositories_full_paths = {
get_resource_full_path_by_id(stacks, ResourceIdentifier(image_repository_id))
for image_repository_id in image_repositories
}
return function_full_paths == image_repositories_full_paths