Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
11 changes: 11 additions & 0 deletions src/aimanager/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. :changelog:

Release History
===============

1.0.0
++++++
* Initial release.
* ``az aimanager``: Add ``create``, ``update``, ``list``, ``show``, ``delete`` and
``namespace add/update/list/show/delete`` commands for AI Manager, backed by the vendored
``azure-mgmt-containerserviceaimanager`` SDK.
5 changes: 5 additions & 0 deletions src/aimanager/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Microsoft Azure CLI 'aimanager' Extension
==========================================

This package is for the 'aimanager' extension.
i.e. 'az aimanager'
49 changes: 49 additions & 0 deletions src/aimanager/azext_aimanager/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# --------------------------------------------------------------------------------------------
# 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.core import AzCommandsLoader
from azure.cli.core.profiles import register_resource_type

# pylint: disable=unused-import
from azext_aimanager._help import helps
from azext_aimanager._client_factory import CUSTOM_MGMT_AIMANAGER


def register_aimanager_resource_type():
# The vendored azure-mgmt-containerserviceaimanager SDK is a single-api (typespec)
# package whose operation groups are instance attributes rather than client class
# properties, so an SDKProfile-based lookup cannot resolve them. It is therefore
# registered with api_version=None (no SDKProfile); the CustomResourceType import
# prefix points at the versioned package so cmd.get_models resolves models from
# `azext_aimanager.vendored_sdks.v2026_05_02_preview.models` directly.
register_resource_type(
"latest",
CUSTOM_MGMT_AIMANAGER,
None,
)


class AIManagerCommandsLoader(AzCommandsLoader):

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType
register_aimanager_resource_type()

aimanager_custom = CliCommandType(operations_tmpl='azext_aimanager.custom#{}')
super().__init__(cli_ctx=cli_ctx,
resource_type=CUSTOM_MGMT_AIMANAGER,
custom_command_type=aimanager_custom)

def load_command_table(self, args):
from azext_aimanager.commands import load_command_table
load_command_table(self, args)
return self.command_table

def load_arguments(self, command):
from azext_aimanager._params import load_arguments
load_arguments(self, command)


COMMAND_LOADER_CLS = AIManagerCommandsLoader
23 changes: 23 additions & 0 deletions src/aimanager/azext_aimanager/_client_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# --------------------------------------------------------------------------------------------
# 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.core.commands.client_factory import get_mgmt_service_client
from azure.cli.core.profiles import CustomResourceType

CUSTOM_MGMT_AIMANAGER = CustomResourceType(
'azext_aimanager.vendored_sdks.v2026_05_02_preview',
'ContainerServiceAIManagerMgmtClient')


def get_aimanager_client(cli_ctx, subscription_id=None):
return get_mgmt_service_client(cli_ctx, CUSTOM_MGMT_AIMANAGER, subscription_id=subscription_id)


def cf_ai_managers(cli_ctx, *_):
return get_aimanager_client(cli_ctx).ai_managers


def cf_ai_manager_namespaces(cli_ctx, *_):
return get_aimanager_client(cli_ctx).ai_manager_namespaces
116 changes: 116 additions & 0 deletions src/aimanager/azext_aimanager/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.help_files import helps # pylint: disable=unused-import


helps['aimanager'] = """
type: group
short-summary: Manage AI Manager resources for inference on AKS.
"""

helps['aimanager create'] = """
type: command
short-summary: Create an AI Manager resource.
examples:
- name: Create an AI Manager
text: az aimanager create --name my-ai-manager -g myrg -l eastus2
- name: Create an AI Manager with the Keep delete policy
text: az aimanager create --name my-ai-manager -g myrg -l eastus2 --delete-policy Keep
"""

helps['aimanager update'] = """
type: command
short-summary: Update an AI Manager resource.
examples:
- name: Update the tags of an AI Manager
text: az aimanager update --name my-ai-manager -g myrg --tags env=prod team=alpha
- name: Update the delete policy of an AI Manager
text: az aimanager update --name my-ai-manager -g myrg --delete-policy Keep
"""

helps['aimanager show'] = """
type: command
short-summary: Show the details of an AI Manager resource.
examples:
- name: Show an AI Manager
text: az aimanager show --name my-ai-manager -g myrg
"""

helps['aimanager delete'] = """
type: command
short-summary: Delete an AI Manager resource.
examples:
- name: Delete an AI Manager
text: az aimanager delete --name my-ai-manager -g myrg
"""

helps['aimanager list'] = """
type: command
short-summary: List AI Manager resources.
examples:
- name: List AI Managers in a resource group
text: az aimanager list -g myrg
- name: List all AI Managers in the subscription
text: az aimanager list
"""

helps['aimanager wait'] = """
type: command
short-summary: Wait for an AI Manager resource to reach a desired state.
"""

helps['aimanager namespace'] = """
type: group
short-summary: Manage namespaces within an AI Manager.
"""

helps['aimanager namespace add'] = """
type: command
short-summary: Add a namespace to an AI Manager.
examples:
- name: Add a namespace
text: az aimanager namespace add -m my-ai-manager -g myrg --name team-alpha
- name: Add a namespace with labels and annotations
text: az aimanager namespace add -m my-ai-manager -g myrg --name team-alpha --labels team=alpha --annotations owner=alice
"""

helps['aimanager namespace update'] = """
type: command
short-summary: Update a namespace within an AI Manager.
examples:
- name: Update the labels of a namespace
text: az aimanager namespace update -m my-ai-manager -g myrg --name team-alpha --labels team=beta
"""

helps['aimanager namespace show'] = """
type: command
short-summary: Show the details of a namespace within an AI Manager.
examples:
- name: Show a namespace
text: az aimanager namespace show -m my-ai-manager -g myrg --name team-alpha
"""

helps['aimanager namespace delete'] = """
type: command
short-summary: Delete a namespace within an AI Manager.
examples:
- name: Delete a namespace
text: az aimanager namespace delete -m my-ai-manager -g myrg --name team-alpha
"""

helps['aimanager namespace list'] = """
type: command
short-summary: List the namespaces within an AI Manager.
examples:
- name: List namespaces in an AI Manager
text: az aimanager namespace list -m my-ai-manager -g myrg
"""

helps['aimanager namespace wait'] = """
type: command
short-summary: Wait for an AI Manager namespace to reach a desired state.
"""
32 changes: 32 additions & 0 deletions src/aimanager/azext_aimanager/_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.util import CLIError


def parse_key_value_list(pairs):
"""Parse a list of ``key=value`` strings into a dictionary."""
result = {}
if pairs is None:
return result
for pair in pairs:
if "=" not in pair:
raise CLIError(f"Invalid format '{pair}'. Expected format key=value.")
key, value = pair.split("=", 1)
result[key.strip()] = value.strip()
return result


def get_aks_custom_headers(aks_custom_headers=None):
"""Parse a comma separated ``key=value`` string into a request headers dictionary."""
headers = {}
if aks_custom_headers is not None:
if aks_custom_headers != "":
for pair in aks_custom_headers.split(','):
parts = pair.split('=')
if len(parts) != 2:
raise CLIError('custom headers format is incorrect')
headers[parts[0]] = parts[1]
return headers
57 changes: 57 additions & 0 deletions src/aimanager/azext_aimanager/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long
from azure.cli.core.commands.parameters import (
tags_type,
get_location_type,
get_enum_type,
get_resource_name_completion_list,
)
from azext_aimanager.constants import DELETE_POLICIES
from azext_aimanager._validators import (
validate_ai_manager_name,
validate_namespace_name,
validate_labels,
validate_annotations,
)


def load_arguments(self, _):
with self.argument_context('aimanager') as c:
c.argument('ai_manager_name', options_list=['--name', '-n'],
validator=validate_ai_manager_name,
help='The name of the AI Manager resource.',
completer=get_resource_name_completion_list('Microsoft.ContainerService/aiManagers'))

for scope in ['aimanager create', 'aimanager update']:
with self.argument_context(scope) as c:
c.argument('tags', arg_type=tags_type, help='The tags to set to the AI Manager.')
c.argument('delete_policy', arg_type=get_enum_type(DELETE_POLICIES),
help='Delete options of the AI Manager. Defaults to Delete.')
c.argument('aks_custom_headers', options_list=['--aks-custom-headers'],
help='Comma-separated key=value pairs to specify custom headers.')

with self.argument_context('aimanager create') as c:
c.argument('location', arg_type=get_location_type(self.cli_ctx))

with self.argument_context('aimanager list') as c:
c.ignore('ai_manager_name')

with self.argument_context('aimanager namespace') as c:
c.argument('ai_manager_name', options_list=['--manager', '-m'],
validator=validate_ai_manager_name,
help='The name of the AI Manager resource.')
c.argument('namespace_name', options_list=['--name', '-n'],
validator=validate_namespace_name,
help='The name of the AI Manager namespace.')

for scope in ['aimanager namespace add', 'aimanager namespace update']:
with self.argument_context(scope) as c:
c.argument('labels', nargs='*', validator=validate_labels,
help='Space-separated labels (key=value) applied to the Kubernetes namespace.')
c.argument('annotations', nargs='*', validator=validate_annotations,
help='Space-separated annotations (key=value) applied to the Kubernetes namespace.')
c.argument('aks_custom_headers', options_list=['--aks-custom-headers'],
help='Comma-separated key=value pairs to specify custom headers.')
33 changes: 33 additions & 0 deletions src/aimanager/azext_aimanager/_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# --------------------------------------------------------------------------------------------
# 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.core.azclierror import InvalidArgumentValueError


def validate_ai_manager_name(namespace):
if namespace.ai_manager_name is not None and not namespace.ai_manager_name.strip():
raise InvalidArgumentValueError("AI Manager name must not be empty.")


def validate_namespace_name(namespace):
if getattr(namespace, "namespace_name", None) is not None and not namespace.namespace_name.strip():
raise InvalidArgumentValueError("--name/-n is not a valid namespace name.")


def _validate_key_value_pairs(values, option):
if not values:
return
for item in values:
if "=" not in item or not item.split("=", 1)[0].strip():
raise InvalidArgumentValueError(
f"{option} '{item}' is not in the expected key=value format.")


def validate_labels(namespace):
_validate_key_value_pairs(namespace.labels, "--labels")


def validate_annotations(namespace):
_validate_key_value_pairs(namespace.annotations, "--annotations")
5 changes: 5 additions & 0 deletions src/aimanager/azext_aimanager/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"azext.isPreview": true,
"azext.minCliCoreVersion": "2.61.0",
"version": "1.0.0"
}
44 changes: 44 additions & 0 deletions src/aimanager/azext_aimanager/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long
from azure.cli.core.commands import CliCommandType
from azext_aimanager._client_factory import (
cf_ai_managers,
cf_ai_manager_namespaces,
)


def load_command_table(self, _):

ai_managers_sdk = CliCommandType(
operations_tmpl="azext_aimanager.vendored_sdks.v2026_05_02_preview.operations._operations#AIManagersOperations.{}",
operation_group="ai_managers",
client_factory=cf_ai_managers
)

ai_manager_namespaces_sdk = CliCommandType(
operations_tmpl="azext_aimanager.vendored_sdks.v2026_05_02_preview.operations._operations#AIManagerNamespacesOperations.{}",
operation_group="ai_manager_namespaces",
client_factory=cf_ai_manager_namespaces
)

# aimanager command group
with self.command_group("aimanager", ai_managers_sdk, client_factory=cf_ai_managers) as g:
g.custom_command("create", "create_aimanager", supports_no_wait=True)
g.custom_command("update", "update_aimanager", supports_no_wait=True)
g.custom_show_command("show", "show_aimanager")
g.custom_command("list", "list_aimanager")
g.custom_command("delete", "delete_aimanager", supports_no_wait=True, confirmation=True)
g.wait_command("wait")

# aimanager namespace command group
with self.command_group("aimanager namespace", ai_manager_namespaces_sdk, client_factory=cf_ai_manager_namespaces) as g:
g.custom_command("add", "add_aimanager_namespace", supports_no_wait=True)
g.custom_command("update", "update_aimanager_namespace", supports_no_wait=True)
g.custom_show_command("show", "show_aimanager_namespace")
g.custom_command("list", "list_aimanager_namespace")
g.custom_command("delete", "delete_aimanager_namespace", supports_no_wait=True, confirmation=True)
g.wait_command("wait")
9 changes: 9 additions & 0 deletions src/aimanager/azext_aimanager/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# Delete policy values for an AI Manager resource.
DELETE_POLICY_KEEP = "Keep"
DELETE_POLICY_DELETE = "Delete"
DELETE_POLICIES = [DELETE_POLICY_KEEP, DELETE_POLICY_DELETE]
Loading
Loading