Skip to content
Merged
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
8 changes: 8 additions & 0 deletions src/appnet-preview/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.. :changelog:

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

1.0.0b1
++++++
* Initial release.
54 changes: 54 additions & 0 deletions src/appnet-preview/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Azure CLI AppnetPreview Extension #
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README title uses AppnetPreview (camel-cased) while the extension name is appnet-preview. Consider aligning the README heading with the published extension name to reduce confusion (e.g., “Azure CLI appnet-preview Extension”).

Suggested change
# Azure CLI AppnetPreview Extension #
# Azure CLI appnet-preview Extension #

Copilot uses AI. Check for mistakes.
This is an extension to Azure CLI to manage Application Network resources.

## How to use ##

### Install the extension
```bash
az extension add --name appnet-preview
```

### List available Application Network versions
```bash
az appnet list-versions --location <location>
```

### Create an Application Network
```bash
az appnet create --resource-group <resource-group> --appnet-name <name> --location <location>
```

### Join an AKS cluster to an Application Network

**Prerequisites:** You must have an existing AKS cluster before running `az appnet member join`.

```bash
# Create an AKS cluster first (if you don't have one)
az aks create --resource-group <resource-group> --name <aks-name> --location <location>

# Get the AKS cluster resource ID
AKS_ID=$(az aks show --resource-group <resource-group> --name <aks-name> --query id -o tsv)

# Join the AKS cluster to the Application Network
az appnet member join --resource-group <resource-group> --appnet-name <appnet-name> \
--member-name <member-name> --cluster-type AKS --member-resource-id $AKS_ID \
--upgrade-mode FullyManaged --release-channel Stable
```

### Other commands
```bash
# List Application Networks
az appnet list --resource-group <resource-group>

# Show an Application Network
az appnet show --resource-group <resource-group> --name <appnet-name>

# List members in an Application Network
az appnet member list --resource-group <resource-group> --appnet-name <appnet-name>

# Remove a member from an Application Network
az appnet member remove --resource-group <resource-group> --appnet-name <appnet-name> --member-name <member-name>

# Delete an Application Network
az appnet delete --resource-group <resource-group> --name <appnet-name>
```
66 changes: 66 additions & 0 deletions src/appnet-preview/azext_appnet_preview/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

from azure.cli.core import AzCommandsLoader
from azext_appnet_preview._help import helps # pylint: disable=unused-import


class AppnetPreviewCommandsLoader(AzCommandsLoader):

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType
custom_command_type = CliCommandType(
operations_tmpl='azext_appnet_preview.custom#{}')
super().__init__(cli_ctx=cli_ctx,
custom_command_type=custom_command_type)

def load_command_table(self, args):
from azext_appnet_preview.commands import load_command_table
from azure.cli.core.aaz import load_aaz_command_table
try:
from . import aaz
except ImportError:
aaz = None
if aaz:
load_aaz_command_table(
loader=self,
aaz_pkg_name=aaz.__name__,
args=args
)
load_command_table(self, args)

# Add table transformers to AAZ commands
self._add_table_transformers()

return self.command_table

def _add_table_transformers(self):
"""Add table transformers to AAZ-generated commands."""
from azext_appnet_preview._format import (
appnet_list_versions_table_format,
appnet_member_list_table_format,
appnet_member_upgrade_history_table_format
)

# Map command names to their table transformers
table_transformers = {
'appnet list-versions': appnet_list_versions_table_format,
'appnet member list': appnet_member_list_table_format,
'appnet member upgrade-history list': appnet_member_upgrade_history_table_format,
}

# Apply table transformers to commands
for command_name, transformer in table_transformers.items():
if command_name in self.command_table:
self.command_table[command_name].table_transformer = transformer

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


COMMAND_LOADER_CLS = AppnetPreviewCommandsLoader
96 changes: 96 additions & 0 deletions src/appnet-preview/azext_appnet_preview/_format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from collections import OrderedDict
from jmespath import compile as compile_jmes, Options


def appnet_list_versions_table_format(results):
"""Format appnet list-versions results for display with "-o table"."""
formatted_results = []
for result in results:
# Extract the main info
base_info = {
'kubernetesVersion': result.get('properties', {}).get('kubernetesVersion', 'N/A'),
}

# Get fully managed versions
fully_managed = result.get('properties', {}).get('fullyManagedVersions', {})
if fully_managed and fully_managed.get('releaseChannels'):
for channel in fully_managed['releaseChannels']:
formatted_results.append({
'kubernetesVersion': base_info['kubernetesVersion'],
'mode': 'FullyManaged',
'releaseChannel': channel.get('releaseChannel', 'N/A'),
'version': channel.get('version', 'N/A'),
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appnet_list_versions_table_format produces rows with different keys depending on mode (self-managed rows include availableUpgrades, fully-managed rows don’t). This can lead to inconsistent table columns/blank fields. Consider adding availableUpgrades (e.g., 'N/A') to the fully-managed rows so the output schema is consistent.

Suggested change
'version': channel.get('version', 'N/A'),
'version': channel.get('version', 'N/A'),
'availableUpgrades': 'N/A',

Copilot uses AI. Check for mistakes.
})

# Get self managed versions
self_managed = result.get('properties', {}).get('selfManagedVersions', {})
if self_managed and self_managed.get('versions'):
for version_info in self_managed['versions']:
upgrades_str = ', '.join(version_info.get('upgrades', []))
formatted_results.append({
'kubernetesVersion': base_info['kubernetesVersion'],
'mode': 'SelfManaged',
'releaseChannel': 'N/A',
'version': version_info.get('version', 'N/A'),
'availableUpgrades': upgrades_str if upgrades_str else 'None',
})

return formatted_results


def appnet_member_list_table_format(results):
"""Format appnet member list results for display with "-o table"."""
return [_appnet_member_show_table_format(r) for r in results]


def _appnet_member_show_table_format(result):
"""Format a single appnet member as summary results for display with "-o table"."""
# Extract resource group from ID
resource_id = result.get('id', '')
resource_group = 'N/A'
if resource_id:
parts = resource_id.split('/resourceGroups/')
if len(parts) > 1:
resource_group = parts[1].split('/')[0]

parsed = compile_jmes("""{
name: name,
location: location,
clusterType: properties.clusterType,
mode: properties.mode,
provisioningState: properties.provisioningState,
clusterResourceId: properties.metadata.resourceId
}""")

result_dict = parsed.search(result, Options(dict_cls=OrderedDict))
result_dict['resourceGroup'] = resource_group

# Shorten cluster resource ID for readability
if result_dict.get('clusterResourceId'):
result_dict['clusterName'] = result_dict['clusterResourceId'].split('/')[-1]
del result_dict['clusterResourceId']

return result_dict


def appnet_member_upgrade_history_table_format(results):
"""Format appnet member upgrade history results for display with "-o table"."""
formatted_results = []
for result in results:
parsed = compile_jmes("""{
name: name,
upgradeState: properties.upgradeState,
fromVersion: properties.fromVersion,
toVersion: properties.toVersion,
startTime: properties.startTime,
endTime: properties.endTime,
upgradeType: properties.upgradeType
}""")
formatted_results.append(parsed.search(result, Options(dict_cls=OrderedDict)))

return formatted_results
11 changes: 11 additions & 0 deletions src/appnet-preview/azext_appnet_preview/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long
# pylint: disable=too-many-lines

from knack.help_files import helps # pylint: disable=unused-import
13 changes: 13 additions & 0 deletions src/appnet-preview/azext_appnet_preview/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: disable=too-many-lines
# pylint: disable=too-many-statements


def load_arguments(self, _): # pylint: disable=unused-argument
pass
6 changes: 6 additions & 0 deletions src/appnet-preview/azext_appnet_preview/aaz/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------
10 changes: 10 additions & 0 deletions src/appnet-preview/azext_appnet_preview/aaz/latest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: skip-file
# flake8: noqa

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: skip-file
# flake8: noqa

from azure.cli.core.aaz import *


@register_command_group(
"appnet",
is_preview=True,
)
class __CMDGroup(AAZCommandGroup):
"""Azure Kubernetes Application Network
"""
pass


__all__ = ["__CMDGroup"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: skip-file
# flake8: noqa

from .__cmd_group import *
from ._create import *
from ._delete import *
from ._list import *
from ._list_versions import *
from ._show import *
from ._update import *
from ._wait import *
Loading
Loading