From 08c7df0bf70077387b336d62be2b767e21c637dd Mon Sep 17 00:00:00 2001 From: linluliu Date: Tue, 7 Mar 2023 13:46:11 -0800 Subject: [PATCH 1/5] mark new commands and parameters as preview --- src/containerapp/HISTORY.rst | 11 +++++++++-- src/containerapp/azext_containerapp/_params.py | 2 +- src/containerapp/azext_containerapp/commands.py | 8 ++++---- .../tests/latest/test_containerapp_env_commands.py | 3 +-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/containerapp/HISTORY.rst b/src/containerapp/HISTORY.rst index 512d0078b20..c147919b4ce 100644 --- a/src/containerapp/HISTORY.rst +++ b/src/containerapp/HISTORY.rst @@ -2,8 +2,15 @@ Release History =============== -Upcoming -+++++++ +0.3.23 +++++++ +* BREAKING CHANGE: 'az containerapp env certificate list' returns [] if certificate not found, instead of raising an error. +* Added 'az containerapp env certificate create' to create managed certificate in a container app environment +* Added 'az containerapp hostname add' to add hostname to a container app without binding +* 'az containerapp env certificate delete': add support for managed certificate deletion +* 'az containerapp env certificate list': add optional parameters --managed-certificates-only and --private-key-certificates-only to list certificates by type +* 'az containerapp hostname bind': change --thumbprint to an optional parameter and add optional parameter --validation-method to support managed certificate bindings +* 'az containerapp ssl upload': log messages to indicate which step is in progress * Fix error when running `az containerapp up` on local source that doesn't contain a Dockerfile * Fix the 'TypeError: 'NoneType' object does not support item assignment' error obtained while running the CLI command 'az containerapp dapr enable' diff --git a/src/containerapp/azext_containerapp/_params.py b/src/containerapp/azext_containerapp/_params.py index 5018d62ca7a..1849cd59b62 100644 --- a/src/containerapp/azext_containerapp/_params.py +++ b/src/containerapp/azext_containerapp/_params.py @@ -374,7 +374,7 @@ def load_arguments(self, _): c.argument('thumbprint', options_list=['--thumbprint', '-t'], help='Thumbprint of the certificate.') c.argument('certificate', options_list=['--certificate', '-c'], help='Name or resource id of the certificate.') c.argument('environment', options_list=['--environment', '-e'], help='Name or resource id of the Container App environment.') - c.argument('validation_method', options_list=['--validation-method', '-v'], help='Validation method of custom domain ownership.') + c.argument('validation_method', options_list=['--validation-method', '-v'], help='Validation method of custom domain ownership.', is_preview=True) with self.argument_context('containerapp hostname add') as c: c.argument('hostname', help='The custom domain name.') diff --git a/src/containerapp/azext_containerapp/commands.py b/src/containerapp/azext_containerapp/commands.py index 2c494ab0585..7277394af65 100644 --- a/src/containerapp/azext_containerapp/commands.py +++ b/src/containerapp/azext_containerapp/commands.py @@ -77,10 +77,10 @@ def load_command_table(self, _): g.custom_command('remove', 'remove_dapr_component') with self.command_group('containerapp env certificate') as g: - g.custom_command('create', 'create_managed_certificate') - g.custom_command('list', 'list_certificates') + g.custom_command('create', 'create_managed_certificate', is_preview=True) + g.custom_command('list', 'list_certificates', is_preview=True) g.custom_command('upload', 'upload_certificate') - g.custom_command('delete', 'delete_certificate', confirmation=True, exception_handler=ex_handler_factory()) + g.custom_command('delete', 'delete_certificate', confirmation=True, exception_handler=ex_handler_factory(), is_preview=True) with self.command_group('containerapp env storage', is_preview=True) as g: g.custom_show_command('show', 'show_storage') @@ -180,7 +180,7 @@ def load_command_table(self, _): g.custom_command('upload', 'upload_ssl', exception_handler=ex_handler_factory()) with self.command_group('containerapp hostname') as g: - g.custom_command('add', 'add_hostname', exception_handler=ex_handler_factory()) + g.custom_command('add', 'add_hostname', exception_handler=ex_handler_factory(), is_preview=True) g.custom_command('bind', 'bind_hostname', exception_handler=ex_handler_factory()) g.custom_command('list', 'list_hostname') g.custom_command('delete', 'delete_hostname', confirmation=True, exception_handler=ex_handler_factory()) diff --git a/src/containerapp/azext_containerapp/tests/latest/test_containerapp_env_commands.py b/src/containerapp/azext_containerapp/tests/latest/test_containerapp_env_commands.py index ff668cab909..cf61db504f6 100644 --- a/src/containerapp/azext_containerapp/tests/latest/test_containerapp_env_commands.py +++ b/src/containerapp/azext_containerapp/tests/latest/test_containerapp_env_commands.py @@ -195,8 +195,7 @@ def test_containerapp_env_dapr_components(self, resource_group): @live_only() # encounters 'CannotOverwriteExistingCassetteException' only when run from recording (passes when run live) @ResourceGroupPreparer(location="northeurope") def test_containerapp_env_certificate_e2e(self, resource_group): - location = 'northcentralusstage' - self.cmd('configure --defaults location=northcentralusstage'.format(location)) + self.cmd('configure --defaults location={}'.format(TEST_LOCATION)) env_name = self.create_random_name(prefix='containerapp-e2e-env', length=24) logs_workspace_name = self.create_random_name(prefix='containerapp-env', length=24) From f90498aedb70c188a2167b35bde1f152d3289d32 Mon Sep 17 00:00:00 2001 From: linluliu Date: Tue, 7 Mar 2023 13:47:31 -0800 Subject: [PATCH 2/5] update setup.py --- src/containerapp/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containerapp/setup.py b/src/containerapp/setup.py index 4f07ae5a383..c00a5460b9d 100644 --- a/src/containerapp/setup.py +++ b/src/containerapp/setup.py @@ -17,7 +17,7 @@ # TODO: Confirm this is the right version number you want and it matches your # HISTORY.rst entry. -VERSION = '0.3.22' +VERSION = '0.3.23' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers From fc70b2cee3d94da07420164dc085b7fd60e86c6a Mon Sep 17 00:00:00 2001 From: linluliu Date: Tue, 7 Mar 2023 14:37:43 -0800 Subject: [PATCH 3/5] Update image tag used for 'no Dockerfile' containerapp up scenario --- src/containerapp/azext_containerapp/_constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containerapp/azext_containerapp/_constants.py b/src/containerapp/azext_containerapp/_constants.py index 3f74f9b07b6..ff5d354fe5f 100644 --- a/src/containerapp/azext_containerapp/_constants.py +++ b/src/containerapp/azext_containerapp/_constants.py @@ -40,7 +40,7 @@ ACR_TASK_TEMPLATE = """version: v1.1.0 steps: - - cmd: mcr.microsoft.com/oryx/cli:20220811.1 oryx dockerfile --bind-port {{target_port}} --output ./Dockerfile . + - cmd: mcr.microsoft.com/oryx/cli:debian-buster-20230222.1 oryx dockerfile --bind-port {{target_port}} --output ./Dockerfile . timeout: 28800 - build: -t $Registry/{{image_name}} -f Dockerfile . timeout: 28800 From f16cf6aa1ea23d1803da444c42cf5b3befe1dd50 Mon Sep 17 00:00:00 2001 From: linluliu Date: Fri, 10 Mar 2023 16:37:25 -0800 Subject: [PATCH 4/5] remove location parameter for env certificate create --- src/containerapp/azext_containerapp/_help.py | 2 +- src/containerapp/azext_containerapp/_params.py | 3 +-- src/containerapp/azext_containerapp/custom.py | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/containerapp/azext_containerapp/_help.py b/src/containerapp/azext_containerapp/_help.py index 9a2f8ac4c33..66f158471fd 100644 --- a/src/containerapp/azext_containerapp/_help.py +++ b/src/containerapp/azext_containerapp/_help.py @@ -905,7 +905,7 @@ examples: - name: Add hostname without binding. text: | - az containerapp hostname add -n MyContainerapp -g MyResourceGroup --hostname MyHostname --location MyLocation + az containerapp hostname add -n MyContainerapp -g MyResourceGroup --hostname MyHostname """ helps['containerapp hostname bind'] = """ diff --git a/src/containerapp/azext_containerapp/_params.py b/src/containerapp/azext_containerapp/_params.py index 1849cd59b62..2dcb2a86599 100644 --- a/src/containerapp/azext_containerapp/_params.py +++ b/src/containerapp/azext_containerapp/_params.py @@ -179,8 +179,7 @@ def load_arguments(self, _): with self.argument_context('containerapp env certificate create') as c: c.argument('hostname', options_list=['--hostname'], help='The custom domain name.') c.argument('certificate_name', options_list=['--certificate-name', '-c'], help='Name of the managed certificate which should be unique within the Container Apps environment.') - c.argument('location', get_location_type(self.cli_ctx), help='Location of the managed certificate which can be different from the location of the Container Apps environment.') - c.argument('validation_method', options_list=['--validation-method', '-v'], help='Validation method of custom domain ownership.') + c.argument('validation_method', options_list=['--validation-method', '-v'], help='Validation method of custom domain ownership. Supported methods are HTTP, CNAME and TXT.') with self.argument_context('containerapp env certificate upload') as c: c.argument('certificate_file', options_list=['--certificate-file', '-f'], help='The filepath of the .pfx or .pem file') diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index 60d5b79aa93..c4be599acb4 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -2737,7 +2737,7 @@ def containerapp_up_logic(cmd, resource_group_name, name, managed_env, image, en return create_containerapp(cmd=cmd, name=name, resource_group_name=resource_group_name, managed_env=managed_env, image=image, env_vars=env_vars, ingress=ingress, target_port=target_port, registry_server=registry_server, registry_user=registry_user, registry_pass=registry_pass) -def create_managed_certificate(cmd, name, resource_group_name, hostname, validation_method, certificate_name=None, location=None): +def create_managed_certificate(cmd, name, resource_group_name, hostname, validation_method, certificate_name=None): if certificate_name and not check_managed_cert_name_availability(cmd, resource_group_name, name, certificate_name): raise ValidationError(f"Certificate name '{certificate_name}' is not available.") cert_name = certificate_name @@ -2745,7 +2745,7 @@ def create_managed_certificate(cmd, name, resource_group_name, hostname, validat cert_name = generate_randomized_managed_cert_name(hostname, resource_group_name) if not check_managed_cert_name_availability(cmd, resource_group_name, name, certificate_name): cert_name = None - certificate_envelop = prepare_managed_certificate_envelop(cmd, name, resource_group_name, hostname, validation_method, location) + certificate_envelop = prepare_managed_certificate_envelop(cmd, name, resource_group_name, hostname, validation_method) try: r = ManagedEnvironmentClient.create_or_update_managed_certificate(cmd, resource_group_name, name, cert_name, certificate_envelop, True, validation_method == 'TXT') return r @@ -2976,7 +2976,7 @@ def bind_hostname(cmd, resource_group_name, name, hostname, thumbprint=None, cer while validation not in ["TXT", "CNAME", "HTTP"]: validation = prompt_str('\nPlease choose one of the following domain validation methods: TXT, CNAME, HTTP\nYour answer: ') - certificate_envelop = prepare_managed_certificate_envelop(cmd, env_name, resource_group_name, standardized_hostname, validation_method, location) + certificate_envelop = prepare_managed_certificate_envelop(cmd, env_name, resource_group_name, standardized_hostname, validation_method) try: managed_cert = ManagedEnvironmentClient.create_or_update_managed_certificate(cmd, resource_group_name, env_name, cert_name, certificate_envelop, False, validation_method == 'TXT') except Exception as e: From a7bbdd46fd7b330159122f79a7106230b032e631 Mon Sep 17 00:00:00 2001 From: linluliu Date: Fri, 10 Mar 2023 18:41:52 -0800 Subject: [PATCH 5/5] minor change --- src/containerapp/azext_containerapp/custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index c4be599acb4..66acd559ea2 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -2976,7 +2976,7 @@ def bind_hostname(cmd, resource_group_name, name, hostname, thumbprint=None, cer while validation not in ["TXT", "CNAME", "HTTP"]: validation = prompt_str('\nPlease choose one of the following domain validation methods: TXT, CNAME, HTTP\nYour answer: ') - certificate_envelop = prepare_managed_certificate_envelop(cmd, env_name, resource_group_name, standardized_hostname, validation_method) + certificate_envelop = prepare_managed_certificate_envelop(cmd, env_name, resource_group_name, standardized_hostname, validation_method, location) try: managed_cert = ManagedEnvironmentClient.create_or_update_managed_certificate(cmd, resource_group_name, env_name, cert_name, certificate_envelop, False, validation_method == 'TXT') except Exception as e: