Skip to content

Commit

Permalink
[Containerapp] 'az containerapp env create': Support --mi-system-assi…
Browse files Browse the repository at this point in the history
…gned and --mi-user-assigned, support 'az containerapp env identity assign/remove/show' (#7226)
  • Loading branch information
njuCZ authored Feb 2, 2024
1 parent 4189bd7 commit f0715eb
Show file tree
Hide file tree
Showing 11 changed files with 15,438 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ upcoming
* Upgrade api-version to 2023-11-02-preview
* 'az containerapp create/update/up': support --build-env-vars to set environment variables for build
* 'az containerapp create/update': support --max-inactive-revisions
* 'az containerapp env create': support --mi-system-assigned and --mi-user-assigned for environment create commands
* 'az containerapp env identity': support for container app environment assign/remove/show commands

0.3.46
++++++
Expand Down
59 changes: 59 additions & 0 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,61 @@
--dapr-component-name MyDaprComponentName --environment MyEnvironment
"""

# Identity Commands
helps['containerapp env identity'] = """
type: group
short-summary: Commands to manage environment managed identities.
"""

helps['containerapp env identity assign'] = """
type: command
short-summary: Assign managed identity to a managed environment.
long-summary: Managed identities can be user-assigned or system-assigned.
examples:
- name: Assign system identity.
text: |
az containerapp env identity assign -n my-env -g MyResourceGroup --system-assigned
- name: Assign user identity.
text: |
az containerapp env identity assign -n my-env -g MyResourceGroup --user-assigned myUserIdentityName
- name: Assign user identity (from a different resource group than the managed environment).
text: |
az containerapp env identity assign -n my-env -g MyResourceGroup --user-assigned myUserIdentityResourceId
- name: Assign system and user identity.
text: |
az containerapp env identity assign -n my-env -g MyResourceGroup --system-assigned --user-assigned myUserIdentityResourceId
"""

helps['containerapp env identity remove'] = """
type: command
short-summary: Remove a managed identity from a managed environment.
examples:
- name: Remove system identity.
text: |
az containerapp env identity remove -n my-env -g MyResourceGroup --system-assigned
- name: Remove user identity.
text: |
az containerapp env identity remove -n my-env -g MyResourceGroup --user-assigned myUserIdentityName
- name: Remove system and user identity (from a different resource group than the containerapp).
text: |
az containerapp env identity remove -n my-env -g MyResourceGroup --system-assigned --user-assigned myUserIdentityResourceId
- name: Remove all user identities.
text: |
az containerapp env identity remove -n my-env -g MyResourceGroup --user-assigned
- name: Remove system identity and all user identities.
text: |
az containerapp env identity remove -n my-env -g MyResourceGroup --system-assigned --user-assigned
"""

helps['containerapp env identity show'] = """
type: command
short-summary: Show managed identities of a managed environment.
examples:
- name: Show managed identities.
text: |
az containerapp env identity show -n my-env -g MyResourceGroup
"""

helps['containerapp up'] = """
type: command
short-summary: Create or update a container app as well as any associated resources (ACR, resource group, container apps environment, GitHub Actions, etc.)
Expand Down Expand Up @@ -178,6 +233,10 @@
text: |
az containerapp env create -n MyContainerappEnvironment -g MyResourceGroup \\
--location eastus2 --enable-workload-profiles false
- name: Create an environment with system assigned and user assigned identity.
text: |
az containerapp env create -n MyContainerappEnvironment -g MyResourceGroup \\
--location eastus2 --mi-system-assigned --mi-user-assigned MyUserIdentityResourceId
"""

helps['containerapp service'] = """
Expand Down
5 changes: 5 additions & 0 deletions src/containerapp/azext_containerapp/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,3 +525,8 @@
"name": None,
"type": None
}

ManagedServiceIdentity = {
"type": None, # 'None', 'SystemAssigned', 'UserAssigned', 'SystemAssigned,UserAssigned'
"userAssignedIdentities": None # {string: UserAssignedIdentity}
}
11 changes: 11 additions & 0 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ def load_arguments(self, _):
c.argument('enable_dedicated_gpu', arg_type=get_three_state_flag(), options_list=["--enable-dedicated-gpu"],
help="Boolean indicating if the environment is enabled to have dedicated gpu", is_preview=True)

with self.argument_context('containerapp env create', arg_group='Identity', is_preview=True) as c:
c.argument('system_assigned', options_list=['--mi-system-assigned'], help='Boolean indicating whether to assign system-assigned identity.', action='store_true')
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 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.')
Expand Down Expand Up @@ -148,6 +152,13 @@ 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')

with self.argument_context('containerapp env identity remove', is_preview=True) as c:
c.argument('user_assigned', nargs='*', help="Space-separated user identities. If no user identities are specified, all user identities will be removed.")

with self.argument_context('containerapp up') as c:
c.argument('environment', validator=validate_env_name_or_id_for_up, options_list=['--environment'], help="Name or resource ID of the container app's managed environment or connected environment.")
Expand Down
5 changes: 5 additions & 0 deletions src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ def load_command_table(self, _):
with self.command_group('containerapp env dapr-component') as g:
g.custom_command('init', 'init_dapr_components', is_preview=True)

with self.command_group('containerapp env identity',is_preview=True) as g:
g.custom_command('assign', 'assign_env_managed_identity', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_command('remove', 'remove_env_managed_identity', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_show_command('show', 'show_env_managed_identity')

with self.command_group('containerapp service', deprecate_info=self.deprecate(redirect='containerapp add-on', expiration='2.59.0', hide=True), is_preview=True) as g:
g.custom_command('list', 'list_all_services')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from azure.cli.command_modules.containerapp._utils import get_default_workload_profiles, safe_set
from azure.cli.command_modules.containerapp._utils import get_default_workload_profiles, safe_set, _ensure_identity_resource_id
from knack.log import get_logger

from azure.cli.command_modules.containerapp.containerapp_env_decorator import ContainerAppEnvCreateDecorator, \
ContainerAppEnvUpdateDecorator
from azure.cli.core.azclierror import RequiredArgumentMissingError, ValidationError
from azure.cli.core.commands.client_factory import get_subscription_id
from ._models import ManagedServiceIdentity
from ._utils import safe_get
from ._client_factory import handle_non_404_status_code_exception

Expand All @@ -23,6 +25,7 @@ def construct_payload(self):

self.set_up_infrastructure_resource_group()
self.set_up_dynamic_json_columns()
self.set_up_managed_identity()

def validate_arguments(self):
super().validate_arguments()
Expand All @@ -43,6 +46,32 @@ def set_up_dynamic_json_columns(self):
def set_up_infrastructure_resource_group(self):
if self.get_argument_enable_workload_profiles() and self.get_argument_infrastructure_subnet_resource_id() is not None:
self.managed_env_def["properties"]["InfrastructureResourceGroup"] = self.get_argument_infrastructure_resource_group()

def set_up_managed_identity(self):
identity_def = ManagedServiceIdentity
identity_def["type"] = "None"

assign_system_identity = self.get_argument_system_assigned()
if self.get_argument_user_assigned():
assign_user_identities = [x.lower() for x in self.get_argument_user_assigned()]
else:
assign_user_identities = []

if assign_system_identity and assign_user_identities:
identity_def["type"] = "SystemAssigned, UserAssigned"
elif assign_system_identity:
identity_def["type"] = "SystemAssigned"
elif assign_user_identities:
identity_def["type"] = "UserAssigned"

if assign_user_identities:
identity_def["userAssignedIdentities"] = {}
subscription_id = get_subscription_id(self.cmd.cli_ctx)

for r in assign_user_identities:
r = _ensure_identity_resource_id(subscription_id, self.get_argument_resource_group_name(), r)
identity_def["userAssignedIdentities"][r] = {} # pylint: disable=unsupported-assignment-operation
self.managed_env_def["identity"] = identity_def

def set_up_workload_profiles(self):
if self.get_argument_enable_workload_profiles():
Expand Down Expand Up @@ -79,6 +108,12 @@ def get_argument_enable_dedicated_gpu(self):
def get_argument_logs_dynamic_json_columns(self):
return self.get_param("logs_dynamic_json_columns")

def get_argument_system_assigned(self):
return self.get_param("system_assigned")

def get_argument_user_assigned(self):
return self.get_param("user_assigned")


class ContainerappEnvPreviewUpdateDecorator(ContainerAppEnvUpdateDecorator):
def set_up_app_log_configuration(self):
Expand Down
Loading

0 comments on commit f0715eb

Please sign in to comment.