Skip to content

Commit

Permalink
Custom Domains on Managed Environments (#152)
Browse files Browse the repository at this point in the history
* initial no dockerfile support for up

* bump version

* add to help text, history text

* Fill in Cormac's link for oryx runtimes (see here microsoft/Oryx#1502)

* pass target port to ACR task; add better error information

* bump version

* fix bug with containerapp create

* add test case

* bump version

* Updated to preview api version and reran all tests. (#147)

* Ran tests.

* Update src/containerapp/azext_containerapp/_clients.py

Co-authored-by: Silas Strawn <[email protected]>

Co-authored-by: Haroon Feisal <[email protected]>
Co-authored-by: Silas Strawn <[email protected]>

* resolve anthony's comments

* Revert "`az containerapp up`: Support No Dockerfile Scenario"

* Revert "Revert "`az containerapp up`: Support No Dockerfile Scenario""

* Added custom domain support to env create.

* Updated param help group text.

* Added test.

* Wrote env update, wrote test for env update with custom domains.

* Minor update.

* Added help to env update.

Co-authored-by: Silas Strawn <[email protected]>
Co-authored-by: Haroon Feisal <[email protected]>
  • Loading branch information
3 people authored Sep 15, 2022
1 parent 2e3db8a commit 3665e8b
Show file tree
Hide file tree
Showing 27 changed files with 532 additions and 371 deletions.
2 changes: 2 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Release History

0.3.12
++++++
* Add 'az containerapp env update' to update managed environment properties
* Add custom domains support to 'az containerapp env create' and 'az containerapp env update'

0.3.11
++++++
Expand Down
1 change: 1 addition & 0 deletions src/containerapp/azext_containerapp/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@
DEFAULT_PORT = 8080 # used for no dockerfile scenario; not the hello world image

HELLO_WORLD_IMAGE = "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest"

11 changes: 11 additions & 0 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,17 @@
--location eastus2
"""

helps['containerapp env update'] = """
type: command
short-summary: Update a Container Apps environment.
examples:
- name: Update an environment's custom domain configuration.
text: |
az containerapp env update -n MyContainerappEnvironment -g MyResourceGroup \\
--dns-suffix my-suffix.net --certificate-file MyFilePath \\
--certificate-password MyCertPass
"""


helps['containerapp env delete'] = """
type: command
Expand Down
9 changes: 8 additions & 1 deletion src/containerapp/azext_containerapp/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,17 @@
"daprAIInstrumentationKey": None,
"vnetConfiguration": None, # VnetConfiguration
"internalLoadBalancerEnabled": None,
"appLogsConfiguration": None
"appLogsConfiguration": None,
"customDomainConfiguration": None # CustomDomainConfiguration
}
}

CustomDomainConfiguration = {
"dnsSuffix": None,
"certificateValue": None,
"certificatePassword": None
}

AppLogsConfiguration = {
"destination": None,
"logAnalyticsConfiguration": None
Expand Down
6 changes: 6 additions & 0 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ def load_arguments(self, _):
c.argument('platform_reserved_cidr', options_list=['--platform-reserved-cidr'], help='IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other Subnet IP ranges')
c.argument('platform_reserved_dns_ip', options_list=['--platform-reserved-dns-ip'], help='An IP address from the IP range defined by Platform Reserved CIDR that will be reserved for the internal DNS server.')
c.argument('internal_only', arg_type=get_three_state_flag(), options_list=['--internal-only'], help='Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource, therefore must provide infrastructureSubnetResourceId if enabling this property')

with self.argument_context('containerapp env', arg_group='Custom Domain') as c:
c.argument('hostname', options_list=['--custom-domain-dns-suffix', '--dns-suffix'], help='The DNS suffix for the environment\'s custom domain.')
c.argument('certificate_file', options_list=['--custom-domain-certificate-file', '--certificate-file'], help='The filepath of the certificate file (.pfx or .pem) for the environment\'s custom domain. To manage certificates for container apps, use `az containerapp env certificate`.')
c.argument('certificate_password', options_list=['--custom-domain-certificate-password', '--certificate-password'], help='The certificate file password for the environment\'s custom domain.')

with self.argument_context('containerapp env create') as c:
c.argument('zone_redundant', options_list=["--zone-redundant", "-z"], help="Enable zone redundancy on the environment. Cannot be used without --infrastructure-subnet-resource-id. If used with --location, the subnet's location must match")

Expand Down
10 changes: 10 additions & 0 deletions src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,16 @@ def safe_get(model, *keys, default=None):
return model.get(keys[-1], default)


def safe_set(model, *keys, value):
penult = {}
for k in keys:
if k not in model:
model[k] = {}
penult = model
model = model[k]
penult[keys[-1]] = value


def is_platform_windows():
return platform.system() == "Windows"

Expand Down
1 change: 1 addition & 0 deletions src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def load_command_table(self, _):
g.custom_command('list', 'list_managed_environments')
g.custom_command('create', 'create_managed_environment', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_command('delete', 'delete_managed_environment', supports_no_wait=True, confirmation=True, exception_handler=ex_handler_factory())
g.custom_command('update', 'update_managed_environment', supports_no_wait=True, exception_handler=ex_handler_factory())

with self.command_group('containerapp env dapr-component') as g:
g.custom_command('list', 'list_dapr_components')
Expand Down
46 changes: 44 additions & 2 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@
ContainerAppCertificateEnvelope as ContainerAppCertificateEnvelopeModel,
ContainerAppCustomDomain as ContainerAppCustomDomainModel,
AzureFileProperties as AzureFilePropertiesModel,
CustomDomainConfiguration as CustomDomainConfigurationModel,
ScaleRule as ScaleRuleModel)

from ._utils import (_validate_subscription_registered, _get_location_from_resource_group, _ensure_location_allowed,
parse_secret_flags, store_as_secret_and_return_secret_ref, parse_env_var_flags,
_generate_log_analytics_if_not_provided, _get_existing_secrets, _convert_object_from_snake_to_camel_case,
Expand All @@ -66,7 +68,7 @@
generate_randomized_cert_name, _get_name, load_cert_file, check_cert_name_availability,
validate_hostname, patch_new_custom_domain, get_custom_domains, _validate_revision_name, set_managed_identity,
create_acrpull_role_assignment, is_registry_msi_system, clean_null_values, _populate_secret_values,
validate_environment_location, parse_metadata_flags, parse_auth_flags)
validate_environment_location, safe_set, parse_metadata_flags, parse_auth_flags)
from ._validators import validate_create
from ._ssh_utils import (SSH_DEFAULT_ENCODING, WebSocketConnection, read_ssh, get_stdin_writer, SSH_CTRL_C_MSG,
SSH_BACKUP_ENCODING)
Expand Down Expand Up @@ -1000,6 +1002,9 @@ def create_managed_environment(cmd,
tags=None,
disable_warnings=False,
zone_redundant=False,
hostname=None,
certificate_file=None,
certificate_password=None,
no_wait=False):
if zone_redundant:
if not infrastructure_subnet_resource_id:
Expand Down Expand Up @@ -1037,6 +1042,14 @@ def create_managed_environment(cmd,
managed_env_def["tags"] = tags
managed_env_def["properties"]["zoneRedundant"] = zone_redundant

if hostname:
customDomain = CustomDomainConfigurationModel
blob, _ = load_cert_file(certificate_file, certificate_password)
customDomain["dnsSuffix"] = hostname
customDomain["certificatePassword"] = certificate_password
customDomain["certificateValue"] = blob
managed_env_def["properties"]["customDomainConfiguration"] = customDomain

if instrumentation_key is not None:
managed_env_def["properties"]["daprAIInstrumentationKey"] = instrumentation_key

Expand Down Expand Up @@ -1080,9 +1093,38 @@ def create_managed_environment(cmd,
def update_managed_environment(cmd,
name,
resource_group_name,
hostname=None,
certificate_file=None,
certificate_password=None,
tags=None,
no_wait=False):
raise CLIInternalError('Containerapp env update is not yet supported.')
try:
r = ManagedEnvironmentClient.show(cmd=cmd, resource_group_name=resource_group_name, name=name)
except CLIError as e:
handle_raw_exception(e)

# General setup
env_def = {}
safe_set(env_def, "location", value=r["location"]) # required for API
safe_set(env_def, "tags", value=tags)

# Custom domains
safe_set(env_def, "properties", "customDomainConfiguration", value={})
cert_def = env_def["properties"]["customDomainConfiguration"]
if hostname:
blob, _ = load_cert_file(certificate_file, certificate_password)
safe_set(cert_def, "dnsSuffix", value=hostname)
safe_set(cert_def, "certificatePassword", value=certificate_password)
safe_set(cert_def, "certificateValue", value=blob)

# no PATCH api support atm, put works fine even with partial json
try:
r = ManagedEnvironmentClient.create(
cmd=cmd, resource_group_name=resource_group_name, name=name, managed_environment_envelope=env_def, no_wait=no_wait)

return r
except Exception as e:
handle_raw_exception(e)


def show_managed_environment(cmd, name, resource_group_name):
Expand Down
Loading

0 comments on commit 3665e8b

Please sign in to comment.