1# --------------------------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for license information.
4# --------------------------------------------------------------------------------------------
5
6# pylint: disable=line-too-long
7import argparse
8import os.path
9import platform
10
11from argcomplete.completers import FilesCompleter
12from knack.arguments import CLIArgumentType
13
14from azure.cli.core.commands.parameters import (
15    tags_type,
16    get_resource_name_completion_list,
17    quotes,
18    get_three_state_flag,
19    get_enum_type
20)
21from azure.cli.core.commands.validators import get_default_location_from_resource_group
22from .policy import RetentionType
23
24from ._constants import (
25    REGISTRY_RESOURCE_TYPE,
26    WEBHOOK_RESOURCE_TYPE,
27    REPLICATION_RESOURCE_TYPE,
28    TASK_RESOURCE_TYPE,
29    TASKRUN_RESOURCE_TYPE
30)
31from ._validators import (
32    validate_headers,
33    validate_arg,
34    validate_secret_arg,
35    validate_set,
36    validate_set_secret,
37    validate_retention_days,
38    validate_registry_name,
39    validate_expiration_time
40)
41from .scope_map import RepoScopeMapActions, GatewayScopeMapActions
42
43image_by_tag_or_digest_type = CLIArgumentType(
44    options_list=['--image', '-t'],
45    help="The name of the image. May include a tag in the format 'name:tag' or digest in the format 'name@digest'."
46)
47
48
49def load_arguments(self, _):  # pylint: disable=too-many-statements
50    SkuName, PasswordName, DefaultAction, PolicyStatus, WebhookAction, WebhookStatus, \
51        TokenStatus, ZoneRedundancy = self.get_models(
52            'SkuName', 'PasswordName', 'DefaultAction', 'PolicyStatus', 'WebhookAction', 'WebhookStatus',
53            'TokenStatus', 'ZoneRedundancy')
54    TaskStatus, BaseImageTriggerType, SourceRegistryLoginMode, UpdateTriggerPayloadType = self.get_models(
55        'TaskStatus', 'BaseImageTriggerType', 'SourceRegistryLoginMode', 'UpdateTriggerPayloadType', operation_group='tasks')
56    RunStatus = self.get_models('RunStatus', operation_group='runs')
57
58    with self.argument_context('acr') as c:
59        c.argument('tags', arg_type=tags_type)
60        c.argument('registry_name', options_list=['--name', '-n'], help='The name of the container registry. You can configure the default registry name using `az configure --defaults acr=<registry name>`', completer=get_resource_name_completion_list(REGISTRY_RESOURCE_TYPE), configured_default='acr', validator=validate_registry_name)
61        c.argument('tenant_suffix', options_list=['--suffix'], help="The tenant suffix in registry login server. You may specify '--suffix tenant' if your registry login server is in the format 'registry-tenant.azurecr.io'. Applicable if you\'re accessing the registry from a different subscription or you have permission to access images but not the permission to manage the registry resource.")
62        c.argument('sku', help='The SKU of the container registry', arg_type=get_enum_type(SkuName))
63        c.argument('admin_enabled', help='Indicates whether the admin user is enabled', arg_type=get_three_state_flag())
64        c.argument('password_name', help='The name of password to regenerate', arg_type=get_enum_type(PasswordName))
65        c.argument('username', options_list=['--username', '-u'], help='The username used to log into a container registry')
66        c.argument('password', options_list=['--password', '-p'], help='The password used to log into a container registry')
67        c.argument('yes', options_list=['--yes', '-y'], help='Do not prompt for confirmation.', action='store_true')
68        c.argument('image_names', options_list=['--image', '-t'], help="The name and tag of the image using the format: '-t repo/image:tag'. Multiple tags are supported by passing -t multiple times.", action='append')
69        c.argument('timeout', type=int, help='The timeout in seconds.')
70        c.argument('docker_file_path', options_list=['--file', '-f'], help="The relative path of the the docker file to the source code root folder. Default to 'Dockerfile'.")
71        c.argument('no_logs', help="Do not show logs after successfully queuing the build.", action='store_true')
72        c.argument('no_wait', help="Do not wait for the run to complete and return immediately after queuing the run.", action='store_true')
73        c.argument('no_format', help="Indicates whether the logs should be displayed in raw format", action='store_true')
74        c.argument('platform', help="The platform where build/task is run, Eg, 'windows' and 'linux'. When it's used in build commands, it also can be specified in 'os/arch/variant' format for the resulting image. Eg, linux/arm/v7. The 'arch' and 'variant' parts are optional.")
75        c.argument('target', help='The name of the target build stage.')
76        c.argument('auth_mode', help='Auth mode of the source registry.', arg_type=get_enum_type(SourceRegistryLoginMode))
77        # Overwrite default shorthand of cmd to make availability for acr usage
78        c.argument('cmd', options_list=['--__cmd__'])
79        c.argument('cmd_value', help="Commands to execute.", options_list=['--cmd'])
80        c.argument('zone_redundancy', is_preview=True, arg_type=get_enum_type(ZoneRedundancy), help="Indicates whether or not zone redundancy should be enabled for this registry or replication. For more information, such as supported locations, please visit https://aka.ms/acr/az. Zone-redundancy cannot be updated. Defaults to 'Disabled'.")
81        c.argument('allow_exports', arg_type=get_three_state_flag(), is_preview=True, help="Configure exportPolicy to allow/disallow artifacts from being exported from this registry. Artifacts can be exported via import or transfer operations. For more information, please visit https://aka.ms/acr/export-policy.")
82
83    for scope in ['acr create', 'acr update']:
84        with self.argument_context(scope, arg_group='Network Rule') as c:
85            default_allow_suffix = " The Default is to allow." if "create" in scope else ""
86
87            c.argument('default_action', arg_type=get_enum_type(DefaultAction),
88                       help='Default action to apply when no rule matches. Only applicable to Premium SKU.')
89            c.argument('public_network_enabled', get_three_state_flag(), help="Allow public network access for the container registry.{suffix}".format(suffix=default_allow_suffix))
90            c.argument('allow_trusted_services', get_three_state_flag(), is_preview=True, help="Allow trusted Azure Services to access network restricted registries. For more information, please visit https://aka.ms/acr/trusted-services.{suffix}".format(suffix=default_allow_suffix))
91
92    with self.argument_context('acr create', arg_group="Customer managed key") as c:
93        c.argument('identity', help="Use assigned managed identity resource id or name if in the same resource group")
94        c.argument('key_encryption_key', help="Key vault key uri. To enable automated rotation, provide a version-less key uri. For manual rotation, provide a versioned key uri.")
95
96    with self.argument_context('acr update', arg_group='Network Rule') as c:
97        c.argument('data_endpoint_enabled', get_three_state_flag(), help="Enable dedicated data endpoint for client firewall configuration")
98
99    with self.argument_context('acr update') as c:
100        c.argument('anonymous_pull_enabled', get_three_state_flag(), help="Enable registry-wide pull from unauthenticated clients")
101
102    with self.argument_context('acr import') as c:
103        c.argument('source_image', options_list=['--source'], help="Source image name or fully qualified source containing the registry login server. If `--registry` is used, `--source` will always be interpreted as a source image, even if it contains the login server.")
104        c.argument('source_registry', options_list=['--registry', '-r'], help='The source Azure container registry. This can be name, login server or resource ID of the source registry.')
105        c.argument('source_registry_username', options_list=['--username', '-u'], help='The username of source container registry')
106        c.argument('source_registry_password', options_list=['--password', '-p'], help='The password of source container registry')
107        c.argument('target_tags', options_list=['--image', '-t'], help="The name and tag of the image using the format: '-t repo/image:tag'. Multiple tags are supported by passing -t multiple times.", action='append')
108        c.argument('repository', help='The repository name for a manifest-only copy of images. Multiple copies supported by passing --repository multiple times.', action='append')
109        c.argument('force', help='Overwrite the existing tag of the image to be imported.', action='store_true')
110        c.argument('no_wait', help="Do not wait for the import to complete and return immediately after queuing the import.", action='store_true')
111
112    with self.argument_context('acr config content-trust') as c:
113        c.argument('registry_name', options_list=['--registry', '-r', c.deprecate(target='-n', redirect='-r', hide=True), c.deprecate(target='--name', redirect='--registry', hide=True)])
114        c.argument('status', help="Indicates whether content-trust is enabled.", arg_type=get_enum_type(PolicyStatus))
115
116    with self.argument_context('acr config retention') as c:
117        c.argument('status', help="Indicates whether retention policy is enabled.", arg_type=get_enum_type(PolicyStatus))
118        c.argument('registry_name', options_list=['--registry', '-r'])
119        c.argument('days', type=int, help='The number of days to retain an untagged manifest after which it gets purged (Range: 0 to 365). Value "0" will delete untagged manifests immediately.', validator=validate_retention_days, default=7)
120        c.argument('policy_type', options_list=['--type'], help='The type of retention policy.', arg_type=get_enum_type(RetentionType))
121
122    with self.argument_context('acr login') as c:
123        c.argument('resource_group_name', deprecate_info=c.deprecate(hide=True))
124        c.argument('expose_token', options_list=['--expose-token', '-t'], help='Expose access token instead of automatically logging in through Docker CLI', action='store_true')
125
126    with self.argument_context('acr repository') as c:
127        c.argument('resource_group_name', deprecate_info=c.deprecate(hide=True))
128        c.argument('repository', help="The name of the repository.")
129        c.argument('image', arg_type=image_by_tag_or_digest_type)
130        c.argument('top', type=int, help='Limit the number of items in the results.')
131        c.argument('orderby', help='Order the items in the results. Default to alphabetical order of names.', arg_type=get_enum_type(['time_asc', 'time_desc']))
132        c.argument('detail', help='Show detailed information.', action='store_true')
133        c.argument('delete_enabled', help='Indicates whether delete operation is allowed.', arg_type=get_three_state_flag())
134        c.argument('list_enabled', help='Indicates whether this item shows in list operation results.', arg_type=get_three_state_flag())
135        c.argument('read_enabled', help='Indicates whether read operation is allowed.', arg_type=get_three_state_flag())
136        c.argument('write_enabled', help='Indicates whether write or delete operation is allowed.', arg_type=get_three_state_flag())
137
138    with self.argument_context('acr repository untag') as c:
139        c.argument('image', options_list=['--image', '-t'], help="The name of the image. May include a tag in the format 'name:tag'.")
140
141    with self.argument_context('acr create') as c:
142        c.argument('registry_name', completer=None, validator=None)
143        c.argument('deployment_name', validator=None)
144        c.argument('location', validator=get_default_location_from_resource_group)
145        c.argument('workspace', is_preview=True,
146                   help='Name or ID of the Log Analytics workspace to send registry diagnostic logs to. All events will be enabled. You can use "az monitor log-analytics workspace create" to create one. Extra billing may apply.')
147
148    with self.argument_context('acr check-name') as c:
149        c.argument('registry_name', completer=None, validator=None)
150
151    with self.argument_context('acr webhook') as c:
152        c.argument('registry_name', options_list=['--registry', '-r'])
153        c.argument('webhook_name', options_list=['--name', '-n'], help='The name of the webhook', completer=get_resource_name_completion_list(WEBHOOK_RESOURCE_TYPE))
154        c.argument('uri', help='The service URI for the webhook to post notifications.')
155        c.argument('headers', nargs='+', help="Space-separated custom headers in 'key[=value]' format that will be added to the webhook notifications. Use {} to clear existing headers.".format(quotes), validator=validate_headers)
156        c.argument('actions', nargs='+', help='Space-separated list of actions that trigger the webhook to post notifications.', arg_type=get_enum_type(WebhookAction))
157        c.argument('status', help='Indicates whether the webhook is enabled.', arg_type=get_enum_type(WebhookStatus))
158        c.argument('scope', help="The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means events for all repositories.")
159
160    with self.argument_context('acr webhook create') as c:
161        c.argument('webhook_name', completer=None)
162
163    with self.argument_context('acr replication') as c:
164        c.argument('registry_name', options_list=['--registry', '-r'])
165        c.argument('replication_name', options_list=['--name', '-n'], help='The name of the replication.', completer=get_resource_name_completion_list(REPLICATION_RESOURCE_TYPE))
166
167    with self.argument_context('acr replication create') as c:
168        c.argument('replication_name', help='The name of the replication. Default to the location name.', completer=None)
169
170    for scope in ['acr replication create', 'acr replication update']:
171        help_str = "Allow routing to this replication. Requests will not be routed to a disabled replication." \
172                   " Data syncing will continue regardless of the region endpoint status."
173        help_str += ' Default: true.' if 'create' in scope else ''  # suffix help with default if command is for create
174
175        with self.argument_context(scope) as c:
176            c.argument('region_endpoint_enabled', arg_type=get_three_state_flag(), help=help_str, is_preview=True)
177
178    with self.argument_context('acr run') as c:
179        c.argument('registry_name', options_list=['--registry', '-r'])
180        c.positional('source_location', help="The local source code directory path (e.g., './src'), or the URL to a git repository (e.g., 'https://github.com/Azure-Samples/acr-build-helloworld-node.git'), or a remote tarball (e.g., 'http://server/context.tar.gz'), or the repository of an OCI artifact in an Azure container registry (e.g., 'oci://myregistry.azurecr.io/myartifact:mytag'). If '/dev/null' is specified, the value will be set to None and ignored.", completer=FilesCompleter())
181        c.argument('file', options_list=['--file', '-f'], help="The task template/definition file path relative to the source context. It can be '-' to pipe a file from the standard input.")
182        c.argument('values', help="The task values file path relative to the source context.")
183        c.argument('set_value', options_list=['--set'], help="Value in 'name[=value]' format. Multiples supported by passing --set multiple times.", action='append', validator=validate_set)
184        c.argument('set_secret', help="Secret value in '--set name[=value]' format. Multiples supported by passing --set multiple times.", action='append', validator=validate_set_secret)
185        c.argument('agent_pool_name', options_list=['--agent-pool'], help='The name of the agent pool.', is_preview=True)
186        c.argument('log_template', options_list=['--log-template'], help="The repository and tag template for run log artifact using the format: 'log/repo:tag' (e.g., 'acr/logs:{{.Run.ID}}'). Only applicable to CMK enabled registry.", is_preview=True)
187
188    with self.argument_context('acr pack build') as c:
189        c.argument('registry_name', options_list=['--registry', '-r'])
190        c.argument('image_name', options_list=['--image', '-t'], help="The name and tag of the image using the format: '-t repo/image:tag'.")
191        c.argument('builder', options_list=['--builder', '-b'], help="The name and tag of a Buildpack builder image.")
192        c.argument('pack_image_tag', options_list=['--pack-image-tag'], help="The tag of the 'pack' runner image ('mcr.microsoft.com/oryx/pack').", is_preview=True)
193        c.argument('pull', options_list=['--pull'], help="Pull the latest builder and run images before use.", action='store_true')
194        c.positional('source_location', help="The local source code directory path (e.g., './src'), or the URL to a git repository (e.g., 'https://github.com/Azure-Samples/acr-build-helloworld-node.git') or a remote tarball (e.g., 'http://server/context.tar.gz'), or the repository of an OCI artifact in an Azure container registry (e.g., 'oci://myregistry.azurecr.io/myartifact:mytag').", completer=FilesCompleter())
195        c.argument('agent_pool_name', options_list=['--agent-pool'], help='The name of the agent pool.', is_preview=True)
196
197    with self.argument_context('acr build') as c:
198        c.argument('registry_name', options_list=['--registry', '-r'])
199        c.positional('source_location', help="The local source code directory path (e.g., './src'), or the URL to a git repository (e.g., 'https://github.com/Azure-Samples/acr-build-helloworld-node.git') or a remote tarball (e.g., 'http://server/context.tar.gz'), or the repository of an OCI artifact in an Azure container registry (e.g., 'oci://myregistry.azurecr.io/myartifact:mytag').", completer=FilesCompleter())
200        c.argument('no_push', help="Indicates whether the image built should be pushed to the registry.", action='store_true')
201        c.argument('no_wait', help="Do not wait for the build to complete and return immediately after queuing the build.", action='store_true')
202        c.argument('arg', options_list=['--build-arg'], help="Build argument in '--build-arg name[=value]' format. Multiples supported by passing --build-arg multiple times.", action='append', validator=validate_arg)
203        c.argument('secret_arg', options_list=['--secret-build-arg'], help="Secret build argument in '--secret-build-arg name[=value]' format. Multiples supported by passing '--secret-build-arg name[=value]' multiple times.", action='append', validator=validate_secret_arg)
204        c.argument('agent_pool_name', options_list=['--agent-pool'], help='The name of the agent pool.', is_preview=True)
205        c.argument('log_template', options_list=['--log-template'], help="The repository and tag template for run log artifact using the format: 'log/repo:tag' (e.g., 'acr/logs:{{.Run.ID}}'). Only applicable to CMK enabled registry.", is_preview=True)
206
207    with self.argument_context('acr task') as c:
208        c.argument('registry_name', options_list=['--registry', '-r'])
209        c.argument('task_name', options_list=['--name', '-n'], help='The name of the task.', completer=get_resource_name_completion_list(TASK_RESOURCE_TYPE))
210        c.argument('status', help='The current status of task.', arg_type=get_enum_type(TaskStatus))
211        c.argument('with_secure_properties', help="Indicates whether the secure properties of a task should be returned.", action='store_true')
212        c.argument('log_template', options_list=['--log-template'], help="The repository and tag template for run log artifact using the format: 'log/repo:tag' (e.g., 'acr/logs:{{.Run.ID}}'). Only applicable to CMK enabled registry.", is_preview=True)
213        c.argument('is_system_task', options_list=['--is-system-task'], help="Indicates whether the task resource is a system task. The name of the task must be 'quicktask'. Only applicable to CMK enabled registry.", action='store_true', is_preview=True)
214
215        # DockerBuildStep, FileTaskStep parameters
216        c.argument('file', options_list=['--file', '-f'], help="Relative path of the the task/docker file to the source code root folder. Task files must be suffixed with '.yaml' or piped from the standard input using '-'.")
217        c.argument('image', arg_type=image_by_tag_or_digest_type)
218        c.argument('no_push', help="Indicates whether the image built should be pushed to the registry.", arg_type=get_three_state_flag())
219        c.argument('no_cache', help='Indicates whether the image cache is enabled.', arg_type=get_three_state_flag())
220        c.argument('values', help="The task values/parameters file path relative to the source context.")
221
222        # common to DockerBuildStep, FileTaskStep and RunTaskStep
223        c.argument('context_path', options_list=['--context', '-c'], help="The full URL to the source code repository (Requires '.git' suffix for a github repo) or the repository of an OCI artifact in an Azure container registry (e.g., 'oci://myregistry.azurecr.io/myartifact:mytag'). If '/dev/null' is specified, the value will be set to None and ignored. This is a required argument if the task is not a system task.")
224        c.argument('arg', help="Build argument in '--arg name[=value]' format. Multiples supported by passing '--arg` multiple times.", action='append', validator=validate_arg)
225        c.argument('secret_arg', help="Secret build argument in '--secret-arg name[=value]' format. Multiples supported by passing --secret-arg multiple times.", action='append', validator=validate_secret_arg)
226        c.argument('set_value', options_list=['--set'], help="Task value in '--set name[=value]' format. Multiples supported by passing --set multiple times.", action='append', validator=validate_set)
227        c.argument('set_secret', help="Secret task value in '--set-secret name[=value]' format. Multiples supported by passing --set-secret multiple times.", action='append', validator=validate_set_secret)
228
229        # Trigger parameters
230        c.argument('source_trigger_name', arg_group='Trigger', help="The name of the source trigger.")
231        c.argument('commit_trigger_enabled', arg_group='Trigger', help="Indicates whether the source control commit trigger is enabled.", arg_type=get_three_state_flag())
232        c.argument('pull_request_trigger_enabled', arg_group='Trigger', help="Indicates whether the source control pull request trigger is enabled. The trigger is disabled by default.", arg_type=get_three_state_flag())
233        c.argument('schedule', arg_group='Trigger', help="Schedule for a timer trigger represented as a cron expression. An optional trigger name can be specified using `--schedule name:schedule` format. Multiples supported by passing --schedule multiple times.", action='append')
234        c.argument('git_access_token', arg_group='Trigger', help="The access token used to access the source control provider.")
235        c.argument('base_image_trigger_name', arg_group='Trigger', help="The name of the base image trigger.")
236        c.argument('base_image_trigger_enabled', arg_group='Trigger', help="Indicates whether the base image trigger is enabled.", arg_type=get_three_state_flag())
237        c.argument('base_image_trigger_type', arg_group='Trigger', help="The type of the auto trigger for base image dependency updates.", arg_type=get_enum_type(BaseImageTriggerType))
238        c.argument('update_trigger_endpoint', arg_group='Trigger', help="The full URL of the endpoint to receive base image update trigger notifications.", is_preview=True)
239        c.argument('update_trigger_payload_type', arg_group='Trigger', help="Indicates whether to include metadata about the base image trigger in the payload alongwith the update trigger token, when a notification is sent.", arg_type=get_enum_type(UpdateTriggerPayloadType), is_preview=True)
240
241        # Run related parameters
242        c.argument('run_id', help='The unique run identifier.')
243
244        # Run agent parameters
245        c.argument('cpu', type=int, help='The CPU configuration in terms of number of cores required for the run.')
246
247        # MSI parameter
248        c.argument('assign_identity', nargs='*', help="Assigns managed identities to the task. Use '[system]' to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity. Please see https://aka.ms/acr/tasks/task-create-managed-identity for more information.")
249
250        # Agent Pool Parameter
251        c.argument('agent_pool_name', options_list=['--agent-pool'], help='The name of the agent pool.', is_preview=True)
252
253    with self.argument_context('acr task create') as c:
254        c.argument('task_name', completer=None)
255
256    with self.argument_context('acr task identity') as c:
257        c.argument('identities', options_list=['--identities'], nargs='*', help="Assigns managed identities to the task. Use '[system]' to refer to the system-assigned identity or a resource ID to refer to a user-assigned identity.")
258
259    with self.argument_context('acr task credential') as c:
260        # Custom registry credentials
261        c.argument('login_server', help="The login server of the custom registry. For instance, 'myregistry.azurecr.io'.", required=True)
262
263    with self.argument_context('acr task run') as c:
264        # Update trigger token parameters
265        c.argument('update_trigger_token', help="The payload that will be passed back alongwith the base image trigger notification.", is_preview=True)
266
267    with self.argument_context('acr task list-runs') as c:
268        c.argument('run_status', help='The current status of run.', arg_type=get_enum_type(RunStatus))
269        c.argument('top', help='Limit the number of latest runs in the results.')
270
271    with self.argument_context('acr task update-run') as c:
272        c.argument('no_archive', help='Indicates whether the run should be archived.', arg_type=get_three_state_flag())
273
274    for scope in ['acr task credential add', 'acr task credential update']:
275        with self.argument_context(scope) as c:
276            c.argument('username', options_list=['--username', '-u'], help="The username to login to the custom registry. This can be plain text or a key vault secret URI.")
277            c.argument('password', options_list=['--password', '-p'], help="The password to login to the custom registry. This can be plain text or a key vault secret URI.")
278            c.argument('use_identity', help="The task managed identity used for the credential. Use '[system]' to refer to the system-assigned identity or a client id to refer to a user-assigned identity. Please see https://aka.ms/acr/tasks/cross-registry-authentication for more information.")
279
280    with self.argument_context('acr task timer') as c:
281        # Timer trigger parameters
282        c.argument('timer_name', help="The name of the timer trigger.", required=True)
283        c.argument('timer_schedule', options_list=['--schedule'], help="The schedule of the timer trigger represented as a cron expression.")
284        c.argument('enabled', help="Indicates whether the timer trigger is enabled.", arg_type=get_three_state_flag())
285
286    with self.argument_context('acr taskrun') as c:
287        c.argument('registry_name', options_list=['--registry', '-r'])
288        c.argument('taskrun_name', options_list=['--name', '-n'], help='The name of the taskrun.', completer=get_resource_name_completion_list(TASKRUN_RESOURCE_TYPE))
289
290    with self.argument_context('acr helm') as c:
291        c.argument('resource_group_name', deprecate_info=c.deprecate(hide=True))
292        c.argument('repository', help=argparse.SUPPRESS)
293        c.argument('version', help='The helm chart version.')
294
295    with self.argument_context('acr helm show') as c:
296        c.positional('chart', help='The helm chart name.')
297
298    with self.argument_context('acr helm delete') as c:
299        c.positional('chart', help='The helm chart name.')
300        c.argument('prov', help='Only delete the provenance file.', action='store_true')
301
302    with self.argument_context('acr helm push') as c:
303        c.positional('chart_package', help="The helm chart package.", completer=FilesCompleter())
304        c.argument('force', help='Overwrite the existing chart package.', action='store_true')
305
306    with self.argument_context('acr helm install-cli') as c:
307        c.argument('client_version', help='The target Helm CLI version. (Attention: Currently, Helm 3 does not work with "az acr helm" commands) ')
308        c.argument('install_location', help='Path at which to install Helm CLI (Existing one at the same path will be overwritten)', default=_get_helm_default_install_location())
309        c.argument('yes', help='Agree to the license of Helm, and do not prompt for confirmation.')
310
311    with self.argument_context('acr network-rule') as c:
312        c.argument('subnet', help='Name or ID of subnet. If name is supplied, `--vnet-name` must be supplied.')
313        c.argument('vnet_name', help='Name of a virtual network.')
314        c.argument('ip_address', help='IPv4 address or CIDR range.')
315
316    with self.argument_context('acr check-health') as c:
317        c.argument('ignore_errors', options_list=['--ignore-errors'], help='Provide all health checks, even if errors are found', action='store_true', required=False)
318        c.argument('vnet', options_list=['--vnet'],
319                   help="Virtual network ID so to run this command inside a VNET to verify the DNS routing to private endpoints", required=False)
320
321    with self.argument_context('acr scope-map') as c:
322        c.argument('registry_name', options_list=['--registry', '-r'])
323        c.argument('description', options_list=['--description'], help='Description for the scope map. Maximum 256 characters are allowed.', required=False)
324        c.argument('scope_map_name', options_list=['--name', '-n'], help='The name of the scope map.', required=True)
325
326    repo_valid_actions = "Valid actions are {}".format({action.value for action in RepoScopeMapActions})
327    gateway_valid_actions = "Valid actions are {}".format({action.value for action in GatewayScopeMapActions})
328    with self.argument_context('acr scope-map update') as c:
329        c.argument('add_repository', options_list=['--add-repository', c.deprecate(target='--add', redirect='--add-repository', hide=True)], nargs='+', action='append', required=False,
330                   help='repository permissions to be added. Use the format "--add-repository REPO [ACTION1 ACTION2 ...]" per flag. ' + repo_valid_actions)
331        c.argument('remove_repository', options_list=['--remove-repository', c.deprecate(target='--remove', redirect='--remove-repository', hide=True)], nargs='+', action='append', required=False,
332                   help='respsitory permissions to be removed. Use the format "--remove-repository REPO [ACTION1 ACTION2 ...]" per flag. ' + repo_valid_actions)
333        c.argument('add_gateway', options_list=['--add-gateway'], nargs='+', action='append', required=False,
334                   help='gateway permissions to be added. Use the format "--add-gateway GATEWAY [ACTION1 ACTION2 ...]" per flag. ' + gateway_valid_actions)
335        c.argument('remove_gateway', options_list=['--remove-gateway'], nargs='+', action='append', required=False,
336                   help='gateway permissions to be removed. Use the format "--remove-gateway GATEWAY [ACTION1 ACTION2 ...]" per flag. ' + gateway_valid_actions)
337
338    with self.argument_context('acr scope-map create') as c:
339        c.argument('repository_actions_list', options_list=['--repository'], nargs='+', action='append', required=False,
340                   help='repository permissions. Use the format "--repository REPO [ACTION1 ACTION2 ...]" per flag. ' + repo_valid_actions)
341        c.argument('gateway_actions_list', options_list=['--gateway'], nargs='+', action='append', required=False,
342                   help='gateway permissions. Use the format "--gateway GATEWAY [ACTION1 ACTION2 ...]" per flag. ' + gateway_valid_actions)
343
344    with self.argument_context('acr token') as c:
345        c.argument('registry_name', options_list=['--registry', '-r'])
346        c.argument('token_name', options_list=['--name', '-n'], help='The name of the token.', required=True)
347        c.argument('scope_map_name', options_list=['--scope-map'], help='The name of the scope map associated with the token', required=False)
348        c.argument('status', options_list=['--status'], arg_type=get_enum_type(TokenStatus),
349                   help='The status of the token', required=False, default="enabled")
350
351    with self.argument_context('acr token create') as c:
352        c.argument('scope_map_name', options_list=['--scope-map'],
353                   help='The name of the scope map with pre-configured repository permissions. Use "--repository" and/or "--gateway" if you would like CLI to configure one for you')
354        c.argument('repository_actions_list', options_list=['--repository'], nargs='+', action='append',
355                   help='repository permissions. Use the format "--repository REPO [ACTION1 ACTION2 ...]" per flag. ' + repo_valid_actions)
356        c.argument('gateway_actions_list', options_list=['--gateway'], nargs='+', action='append',
357                   help='gateway permissions. Use the format "--gateway GATEWAY [ACTION1 ACTION2 ...]" per flag. ' + gateway_valid_actions)
358        c.argument('no_passwords', arg_type=get_three_state_flag(), help='Do not generate passwords, instead use "az acr token credential generate"')
359        c.argument('expiration_in_days', help='Number of days for which the credentials will be valid. If not specified, the expiration will default to the max value "9999-12-31T23:59:59.999999+00:00"', type=int, required=False)
360
361    with self.argument_context('acr token update') as c:
362        c.argument('scope_map_name', options_list=['--scope-map'], help='The name of the scope map associated with the token. If not specified, running this command will disassociate the current scope map related to the token.', required=False)
363
364    with self.argument_context('acr token credential generate') as c:
365        c.argument('password1', options_list=['--password1'], help='Flag indicating if password1 should be generated.', action='store_true', required=False)
366        c.argument('password2', options_list=['--password2'], help='Flag indicating if password2 should be generated.', action='store_true', required=False)
367        c.argument('expiration_in_days', options_list=['--expiration-in-days', c.deprecate(target='--days', redirect='--expiration-in-days', hide=True)],
368                   help='Number of days for which the credentials will be valid. If not specified, the expiration will default to the max value "9999-12-31T23:59:59.999999+00:00"', type=int, required=False)
369
370    for scope in ['acr token create', 'acr token credential generate']:
371        with self.argument_context(scope) as c:
372            c.argument('expiration', validator=validate_expiration_time,
373                       help='UTC time for which the credentials will be valid. In the format of %Y-%m-%dT%H:%M:%SZ, e.g. 2025-12-31T12:59:59Z')
374
375    with self.argument_context('acr token credential delete') as c:
376        c.argument('password1', options_list=['--password1'], help='Flag indicating if first password should be deleted', action='store_true', required=False)
377        c.argument('password2', options_list=['--password2'], help='Flag indicating if second password should be deleted.', action='store_true', required=False)
378
379    with self.argument_context('acr agentpool') as c:
380        c.argument('registry_name', options_list=['--registry', '-r'])
381        c.argument('agent_pool_name', options_list=['--name', '-n'], help='The name of the agent pool.')
382        c.argument('count', options_list=['--count', '-c'], type=int, help='The count of the agent pool.')
383        c.argument('tier', help='Sets the VM your agent pool will run on. Valid values are: S1(2 vCPUs, 3 GiB RAM), S2(4 vCPUs, 8 GiB RAM), S3(8 vCPUs, 16 GiB RAM) or I6(64 vCPUs, 216 GiB RAM, Isolated)')
384        c.argument('os_type', options_list=['--os'], help='The os of the agent pool.', deprecate_info=c.deprecate(hide=True))
385        c.argument('subnet_id', options_list=['--subnet-id'], help='The Virtual Network Subnet Resource Id of the agent machine.')
386        c.argument('no_wait', help="Do not wait for the Agent Pool to complete action and return immediately after queuing the request.", action='store_true')
387
388    with self.argument_context('acr agentpool show') as c:
389        c.argument('queue_count', help="Get only the queue count", action='store_true')
390
391    with self.argument_context('acr private-endpoint-connection') as c:
392        # to match private_endpoint_connection_command_guideline.md guidelines
393        c.argument('registry_name', options_list=['--registry-name', '-r'], help='The name of the container registry. You can configure the default registry name using `az configure --defaults acr=<registry name>`', completer=get_resource_name_completion_list(REGISTRY_RESOURCE_TYPE), configured_default='acr')
394        c.argument('private_endpoint_connection_name', options_list=['--name', '-n'], help='The name of the private endpoint connection')
395
396        c.argument('approval_description', options_list=['--description'], help='Approval description. For example, the reason for approval.')
397        c.argument('rejection_description', options_list=['--description'], help='Rejection description. For example, the reason for rejection.')
398
399    with self.argument_context('acr identity') as c:
400        c.argument('identities', nargs='+', help="Space-separated identities. Use '[system]' to refer to the system assigned identity")
401
402    with self.argument_context('acr encryption') as c:
403        c.argument('key_encryption_key', help="Key vault key uri. To enable automated rotation, provide a version-less key uri. For manual rotation, provide a versioned key uri.")
404        c.argument('identity', help="client id of managed identity, resource name or id of user assigned identity. Use '[system]' to refer to the system assigned identity")
405
406    with self.argument_context('acr connected-registry') as c:
407        c.argument('registry_name', options_list=['--registry', '-r'], help='The login server of the Cloud ACR registry. Must be the FQDN to support also Azure Stack.', required=True)
408        c.argument('connected_registry_name', options_list=['--name', '-n'], help='Name for the connected registry. Name must be between 5 to 40 character long, start with a letter and contain only alphanumeric characters (including ‘_’ or ‘-’). Name must be unique under the Cloud ACR hierarchy.', required=True)
409        c.argument('parent_name', options_list=['--parent', '-p'], help='The name of the parent connected registry.', required=False)
410        c.argument('repositories', options_list=['--repository', c.deprecate(target='-t', redirect='--repository', hide=True)], nargs='+', help='Specifies the repositories that need to be sync to the connected registry. It can be in the format [REPO01] [REPO02]...', required=False)
411        c.argument('sync_token_name', options_list=['--sync-token'], help='Specifies the sync token used to synchronize the connected registry with its parent. It most have only repo permissions and at least the actions required for its mode. It can include access for multiple repositories.', required=False)
412        c.argument('cleanup', help='It will aslo delete the sync token and the scope map resources.', required=False)
413        c.argument('no_children', help='Used to remove all children from the list.', required=False, action='store_true')
414        c.argument('sync_audit_logs_enabled', options_list=['--audit-logs-enabled'], help='Indicates whether audit log synchronization is enabled. It is enabled by default.', required=False, arg_type=get_three_state_flag(), deprecate_info=c.deprecate(hide=True))
415
416    with self.argument_context('acr connected-registry create') as c:
417        c.argument('log_level', help='Sets the log level for logging on the instance. Accepted log levels are Debug, Information, Warning, Error, and None.', required=False, default="Information")
418        c.argument('mode', options_list=['--mode', '-m'], help='Can be one of the two operating modes: registry (read/write mode) or mirror (read-only mode).', required=False, default="Registry")
419        c.argument('client_token_list', options_list=['--client-tokens'], nargs='+', help='Specifies the client access to the repositories in the connected registry. It can be in the format [TOKEN_NAME01] [TOKEN_NAME02]...', required=False)
420        c.argument('sync_window', options_list=['--sync-window', '-w'], help='Required parameter if --sync-schedule is present. Used to determine the schedule duration. Uses ISO 8601 duration format.', required=False)
421        c.argument('sync_schedule', options_list=['--sync-schedule', '-s'], help='Optional parameter to define the sync schedule. Uses cron expression to determine the schedule. If not specified, the instance is considered always online and attempts to sync every minute.', required=False, default="* * * * *")
422        c.argument('sync_message_ttl', help='Determines how long the sync messages will be kept in the cloud. Uses ISO 8601 duration format.', required=False, default="P2D")
423
424    with self.argument_context('acr connected-registry update') as c:
425        c.argument('log_level', help='Sets the log level for logging on the instance. Accepted log levels are Debug, Information, Warning, Error, and None.', required=False)
426        c.argument('add_client_token_list', options_list=['--add-client-tokens'], nargs='*', required=False,
427                   help='Client tokens to be added. Use the format "--add-client-tokens [TOKEN_NAME1 TOKEN_NAME2 ...]" per token id.')
428        c.argument('remove_client_token_list', options_list=['--remove-client-tokens'], nargs='*', required=False,
429                   help='Client tokens to be removed. Use the format "--remove-client-tokens [TOKEN_NAME1 TOKEN_NAME2 ...]" per token id.')
430        c.argument('sync_window', options_list=['--sync-window', '-w'], help='Used to determine the schedule duration. Uses ISO 8601 duration format.', required=False)
431        c.argument('sync_schedule', options_list=['--sync-schedule', '-s'], help='Optional parameter to define the sync schedule. Uses cron expression to determine the schedule. If not specified, the instance is considered always online and attempts to sync every minute.', required=False)
432        c.argument('sync_message_ttl', help='Determines how long the sync messages will be kept in the cloud. Uses ISO 8601 duration format.', required=False)
433
434    with self.argument_context('acr connected-registry repo') as c:
435        c.argument('add_repos', options_list=['--add'], nargs='*', required=False,
436                   help='repository permissions to be added to the targeted connected registry and it\'s ancestors sync scope maps. Use the format "--add [REPO1 REPO2 ...]" per flag. ' + repo_valid_actions)
437        c.argument('remove_repos', options_list=['--remove'], nargs='*', required=False,
438                   help='respsitory permissions to be removed from the targeted connected registry and it\'s succesors sync scope maps. Use the format "--remove [REPO1 REPO2 ...]" per flag. ' + repo_valid_actions)
439
440    with self.argument_context('acr connected-registry install') as c:
441        c.argument('parent_protocol', arg_type=get_enum_type(['http', 'https']), options_list=['--parent-protocol'], help='Required parameter to specify the parent protocol.', required=True)
442
443
444def _get_helm_default_install_location():
445    exe_name = 'helm'
446    system = platform.system()
447    if system == 'Windows':
448        home_dir = os.environ.get('USERPROFILE')
449        if not home_dir:
450            return None
451        install_location = os.path.join(home_dir, r'.azure-{0}\{0}.exe'.format(exe_name))
452    elif system in ('Linux', 'Darwin'):
453        install_location = '/usr/local/bin/{}'.format(exe_name)
454    else:
455        install_location = None
456    return install_location
457