Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Containerapp] 'az containerapp env create': Support --mi-system-assigned and --mi-user-assigned, support 'az containerapp env identity assign/remove/show' #7226

Merged
merged 5 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Greedygre marked this conversation as resolved.
Show resolved Hide resolved

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'] = """
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
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')
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
c.argument('user_assigned', options_list=['--mi-user-assigned'], nargs='+', help='Space-separated user identities to be assigned.')
njuCZ marked this conversation as resolved.
Show resolved Hide resolved

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:
njuCZ marked this conversation as resolved.
Show resolved Hide resolved
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
Loading