Skip to content

Commit

Permalink
[ContainerApp] Add CLI for DotNet Components (Azure#7564)
Browse files Browse the repository at this point in the history
  • Loading branch information
snehapar9 authored and harryli0108 committed May 15, 2024
1 parent 5a4ea61 commit c39a237
Show file tree
Hide file tree
Showing 14 changed files with 17,688 additions and 191 deletions.
1 change: 1 addition & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ upcoming
* 'az containerapp env java-component eureka-server-for-spring': Support create/update/show/delete Spring Cloud Eureka; deprecation of 'az containerapp env java-component spring-cloud-eureka'
* 'az containerapp up': Fix InvalidResourceType error when cloud is not AzureCloud
* 'az containerapp create/update': Support enable or disable Java metrics with --runtime and --enable-java-metrics
* 'az containerapp env dotnet-component': Support create/show/list/delete for dotnet components
* 'az containerapp env create/update': Support peer-to-peer traffic encryption with --enable-peer-to-peer-encryption
* 'az containerapp update': Fix --scale-rule-tcp-concurrency for TCP scale rule
* 'az containerapp compose create': Fix an issue where the environment's location is not resolved from --location
Expand Down
115 changes: 115 additions & 0 deletions src/containerapp/azext_containerapp/_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -1130,3 +1130,118 @@ def list_by_subscription(cls, cmd, formatter=lambda x: x):

return sessionpools


class DotNetComponentPreviewClient():
api_version = PREVIEW_API_VERSION

@classmethod
def create(cls, cmd, resource_group_name, environment_name, name, dotnet_component_envelope, no_wait=False):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/dotNetComponents/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
environment_name,
name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "PUT", request_url, body=json.dumps(dotnet_component_envelope))

if no_wait:
return r.json()
elif r.status_code == 201:
operation_url = r.headers.get(HEADER_AZURE_ASYNC_OPERATION)
poll_status(cmd, operation_url)
r = send_raw_request(cmd.cli_ctx, "GET", request_url)

return r.json()

@classmethod
def update(cls, cmd, resource_group_name, environment_name, name, dotnet_component_envelope, no_wait=False):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/dotNetComponents/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
environment_name,
name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "PATCH", request_url, body=json.dumps(dotnet_component_envelope))

if no_wait:
return
elif r.status_code == 202:
operation_url = r.headers.get(HEADER_LOCATION)
response = poll_results(cmd, operation_url)
if response is None:
raise ResourceNotFoundError("Could not find the DotNet component")
else:
return response

return r.json()

@classmethod
def delete(cls, cmd, resource_group_name, environment_name, name, no_wait=False):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/dotNetComponents/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
environment_name,
name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "DELETE", request_url)

if no_wait:
return # API doesn't return JSON (it returns no content)
elif r.status_code in [200, 201, 202, 204]:
if r.status_code == 202:
operation_url = r.headers.get(HEADER_LOCATION)
poll_results(cmd, operation_url)

@classmethod
def show(cls, cmd, resource_group_name, environment_name, name):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/dotNetComponents/{}?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
environment_name,
name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)

return r.json()

@classmethod
def list(cls, cmd, resource_group_name, environment_name):
dotNet_component_list = []

management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/managedEnvironments/{}/dotNetComponents?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
environment_name,
cls.api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
r = r.json()

for component in r["value"]:
dotNet_component_list.append(component)

return dotNet_component_list
2 changes: 2 additions & 0 deletions src/containerapp/azext_containerapp/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
JAVA_COMPONENT_CONFIG = "SpringCloudConfig"
JAVA_COMPONENT_EUREKA = "SpringCloudEureka"

DOTNET_COMPONENT_RESOURCE_TYPE = "AspireDashboard"

RUNTIME_GENERIC = "generic"
RUNTIME_JAVA = "java"
SUPPORTED_RUNTIME_LIST = [RUNTIME_GENERIC, RUNTIME_JAVA]
46 changes: 46 additions & 0 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1684,3 +1684,49 @@
az containerapp sessionpool list -g MyResourceGroup
"""

# DotNet Components Commands
helps['containerapp env dotnet-component'] = """
type: group
short-summary: Commands to manage DotNet components within the environment.
"""

helps['containerapp env dotnet-component list'] = """
type: command
short-summary: Command to list DotNet components within the environment.
examples:
- name: List all DotNet components within an environment.
text: |
az containerapp env dotnet-component list -g MyResourceGroup --environment MyEnvironment
"""

helps['containerapp env dotnet-component create'] = """
type: command
short-summary: Command to create DotNet component to enable Aspire Dashboard. Supported DotNet component type is Aspire Dashboard.
examples:
- name: Create a DotNet component to enable Aspire Dashboard.
text: |
az containerapp env dotnet-component create -g MyResourceGroup \\
-n MyDotNetComponentName \\
--environment MyEnvironment \\
--type AspireDashboard
"""

helps['containerapp env dotnet-component delete'] = """
type: command
short-summary: Command to delete DotNet component to disable Aspire Dashboard.
examples:
- name: Delete DotNet component.
text: |
az containerapp env dotnet-component delete -g MyResourceGroup \\
-n MyDotNetComponentName \\
--environment MyEnvironment
"""

helps['containerapp env dotnet-component show'] = """
type: command
short-summary: Command to show DotNet component in environment.
examples:
- name: Show the details of an environment.
text: |
az containerapp env dotnet-component show -n MyDotNetComponentName --environment MyContainerappEnvironment -g MyResourceGroup
"""
6 changes: 6 additions & 0 deletions src/containerapp/azext_containerapp/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,9 @@
RuntimeJava = {
"enableMetrics": False
}

DotNetComponent = {
"properties": {
"componentType": "AspireDashboard"
}
}
18 changes: 12 additions & 6 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def load_arguments(self, _):
c.argument('logs_dynamic_json_columns', options_list=['--logs-dynamic-json-columns', '-j'], arg_type=get_three_state_flag(),
help='Boolean indicating whether to parse json string log into dynamic json columns. Only work for destination log-analytics.', is_preview=True)

# Telemetry
# Telemetry
with self.argument_context('containerapp env telemetry') as c:
c.argument('name', id_part=None)

Expand Down Expand Up @@ -114,7 +114,7 @@ def load_arguments(self, _):
help="Name of the share on the AzureFile or nfs AzureFile storage.")
c.argument('server', options_list=["--server", "-s"],
help="Server of the NfsAzureFile storage account.", is_preview=True)

# App Resiliency
with self.argument_context('containerapp resiliency') as c:
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)
Expand Down Expand Up @@ -164,7 +164,7 @@ def load_arguments(self, _):
help='Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity.', is_preview=True)
c.argument('certificate_key_vault_url', options_list=['--custom-domain-certificate-akv-url', '--certificate-akv-url'],
help='The URL pointing to the Azure Key Vault secret that holds the certificate.', is_preview=True)

with self.argument_context('containerapp env create') as c:
c.argument('enable_workload_profiles', arg_type=get_three_state_flag(), options_list=["--enable-workload-profiles", "-w"], help="Boolean indicating if the environment is enabled to have workload profiles")
c.argument('enable_dedicated_gpu', arg_type=get_three_state_flag(), options_list=["--enable-dedicated-gpu"],
Expand All @@ -175,9 +175,9 @@ def load_arguments(self, _):
c.argument('user_assigned', options_list=['--mi-user-assigned'], nargs='+', help='Space-separated user identities to be assigned.')

with self.argument_context('containerapp env certificate upload') as c:
c.argument('certificate_identity', options_list=['--certificate-identity', '--identity'],
c.argument('certificate_identity', options_list=['--certificate-identity', '--identity'],
help='Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity.', is_preview=True)
c.argument('certificate_key_vault_url', options_list=['--certificate-akv-url', '--akv-url'],
c.argument('certificate_key_vault_url', options_list=['--certificate-akv-url', '--akv-url'],
help='The URL pointing to the Azure Key Vault secret that holds the certificate.', is_preview=True)

with self.argument_context('containerapp env certificate create') as c:
Expand Down Expand Up @@ -225,7 +225,7 @@ def load_arguments(self, _):
with self.argument_context('containerapp env dapr-component init') as c:
c.argument('statestore', help="The state store component and dev service to create.")
c.argument('pubsub', help="The pubsub component and dev service to create.")

with self.argument_context('containerapp env identity', is_preview=True) as c:
c.argument('user_assigned', nargs='+', help="Space-separated user identities.")
c.argument('system_assigned', help="Boolean indicating whether to assign system-assigned identity.", action='store_true')
Expand Down Expand Up @@ -350,6 +350,12 @@ def load_arguments(self, _):
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)
c.argument('configuration', nargs="*", help="Java component configuration. Configuration must be in format \"<propertyName>=<value> <propertyName>=<value> ...\".")

with self.argument_context('containerapp env dotnet-component') as c:
c.argument('dotnet_component_name', options_list=['--name', '-n'], help="The DotNet component name.")
c.argument('environment_name', options_list=['--environment'], help="The environment name.")
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)
c.argument('dotnet_component_type', options_list=['--type'], arg_type=get_enum_type(['AspireDashboard']), help="The type of DotNet component.")

with self.argument_context('containerapp env', arg_group='Peer Traffic Configuration') as c:
c.argument('p2p_encryption_enabled', arg_type=get_three_state_flag(), options_list=['--enable-peer-to-peer-encryption'], is_preview=True, help='Boolean indicating whether the peer-to-peer traffic encryption is enabled for the environment.')

Expand Down
12 changes: 12 additions & 0 deletions src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ def load_command_table(self, args):
g.custom_show_command('show', 'show_eureka_server_for_spring')
g.custom_command('delete', 'delete_eureka_server_for_spring', confirmation=True, supports_no_wait=True)

with self.command_group('containerapp env dotnet-component', is_preview=True) as g:
g.custom_command('list', 'list_dotnet_components')
g.custom_show_command('show', 'show_dotnet_component')
g.custom_command('create', 'create_dotnet_component', supports_no_wait=True)
g.custom_command('delete', 'delete_dotnet_component', confirmation=True, supports_no_wait=True)

with self.command_group('containerapp env dotnet-component', is_preview=True) as g:
g.custom_command('list', 'list_dotnet_components')
g.custom_show_command('show', 'show_dotnet_component')
g.custom_command('create', 'create_dotnet_component', supports_no_wait=True)
g.custom_command('delete', 'delete_dotnet_component', confirmation=True, supports_no_wait=True)

with self.command_group('containerapp sessionpool', is_preview=True) as g:
g.custom_show_command('show', 'show_session_pool')
g.custom_show_command('list', 'list_session_pool')
Expand Down
Loading

0 comments on commit c39a237

Please sign in to comment.