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
1 change: 1 addition & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ To release a new version, please select a new version number (usually plus 1 to
Pending
+++++++
* Add `--allowed-subjects-from-file` to `az aks identity-binding create` and add a new `az aks identity-binding update` command to manage the `allowedSubjects` list on identity bindings.
* Add `az aks alert-config` commands to manage AKS-managed alert configurations.

21.0.0b11
++++++++
Expand Down
4 changes: 4 additions & 0 deletions src/aks-preview/azext_aks_preview/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,7 @@ def cf_vm_skus(cli_ctx, *_):

def cf_prepared_image_specifications(cli_ctx, *_, subscription_id=None):
return get_container_service_pis_client(cli_ctx, subscription_id=subscription_id).prepared_image_specifications


def cf_alert_configurations(cli_ctx, *_):
return get_container_service_client(cli_ctx).alert_configurations
22 changes: 22 additions & 0 deletions src/aks-preview/azext_aks_preview/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,3 +612,25 @@ def _get(obj, attr):
('restrictions', restrictions_summary),
('capabilities', capabilities_summary),
])


def aks_alert_config_list_table_format(results):
"""Format a list of alert configurations as summary results for display with "-o table". """
return [_get_alert_config_table_row(result) for result in results]


def aks_alert_config_show_table_format(result):
"""Format an alert configuration as summary results for display with "-o table". """
return _get_alert_config_table_row(result)


def _get_alert_config_table_row(result):
"""Extract information from an alert configuration for table display."""
properties = result.get('properties') or {}
notification = properties.get('notification') or {}
return OrderedDict([
('name', result.get('name', '')),
('mode', properties.get('mode', '')),
('actionGroupId', notification.get('actionGroupId', '')),
('provisioningState', properties.get('provisioningState', '')),
])
120 changes: 120 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -4973,6 +4973,126 @@
text: az aks jwtauthenticator show -g MyResourceGroup --cluster-name MyCluster --name myjwt
"""

helps['aks alert-config'] = """
type: group
short-summary: Commands to manage AKS-managed alert configurations for a cluster.
long-summary: Alert configurations let AKS create and manage alerts for important cluster
events and conditions, delivering notifications through an Azure Monitor
action group.
"""

helps['aks alert-config add'] = """
type: command
short-summary: Add an alert configuration to a managed cluster.
parameters:
- name: --cluster-name
type: string
short-summary: Name of the managed cluster.
- name: --name -n
type: string
short-summary: Name of the alert configuration (must be unique within the cluster).
- name: --mode
type: string
short-summary: How AKS manages alerts for the cluster.
long-summary: Use Managed to have AKS create, update and delete the alerts and send
notifications to the configured action group. Use Disabled to turn
alerting off.
- name: --action-group-id
type: string
short-summary: Resource ID of the Azure Monitor action group to send notifications to.
long-summary: Optional. When omitted, the alert configuration is created without a
notification target and no notifications are delivered.
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: Add a managed alert configuration that notifies an action group
text: az aks alert-config add -g MyResourceGroup --cluster-name MyCluster -n myalerts --mode Managed --action-group-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Insights/actionGroups/myag
- name: Add an alert configuration with alerting disabled
text: az aks alert-config add -g MyResourceGroup --cluster-name MyCluster -n myalerts --mode Disabled
"""

helps['aks alert-config update'] = """
type: command
short-summary: Update an alert configuration in a managed cluster.
long-summary: Only the properties you specify are changed; the rest are preserved.
parameters:
- name: --cluster-name
type: string
short-summary: Name of the managed cluster.
- name: --name -n
type: string
short-summary: Name of the alert configuration to update.
- name: --mode
type: string
short-summary: How AKS manages alerts for the cluster.
- name: --action-group-id
type: string
short-summary: Resource ID of the Azure Monitor action group to send notifications to.
long-summary: Pass an empty string to remove the current notification target.
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: Turn off alerting without changing the notification target
text: az aks alert-config update -g MyResourceGroup --cluster-name MyCluster -n myalerts --mode Disabled
- name: Point an existing alert configuration at a different action group
text: az aks alert-config update -g MyResourceGroup --cluster-name MyCluster -n myalerts --action-group-id /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/MyResourceGroup/providers/Microsoft.Insights/actionGroups/otherag
- name: Clear the notification target
text: az aks alert-config update -g MyResourceGroup --cluster-name MyCluster -n myalerts --action-group-id ""
"""

helps['aks alert-config delete'] = """
type: command
short-summary: Delete an alert configuration from a managed cluster.
parameters:
- name: --cluster-name
type: string
short-summary: Name of the managed cluster.
- name: --name -n
type: string
short-summary: Name of the alert configuration to delete.
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: Delete an alert configuration
text: az aks alert-config delete -g MyResourceGroup --cluster-name MyCluster -n myalerts
"""

helps['aks alert-config list'] = """
type: command
short-summary: List the alert configurations of a managed cluster.
parameters:
- name: --cluster-name
type: string
short-summary: Name of the managed cluster.
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: List all alert configurations in a cluster
text: az aks alert-config list -g MyResourceGroup --cluster-name MyCluster
"""

helps['aks alert-config show'] = """
type: command
short-summary: Show the details of an alert configuration.
parameters:
- name: --cluster-name
type: string
short-summary: Name of the managed cluster.
- name: --name -n
type: string
short-summary: Name of the alert configuration to show.
- name: --aks-custom-headers
type: string
short-summary: Send custom headers. When specified, format should be Key1=Value1,Key2=Value2
examples:
- name: Show an alert configuration
text: az aks alert-config show -g MyResourceGroup --cluster-name MyCluster -n myalerts
"""

helps['aks prepared-image-specification'] = """
type: group
short-summary: Commands to manage prepared image specifications.
Expand Down
31 changes: 31 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from azext_aks_preview._validators import (
validate_nat_gateway_managed_outbound_ipv6_count,
validate_nat_gateway_v2_params,
validate_action_group_id,
)
from azext_aks_preview._client_factory import CUSTOM_MGMT_AKS_PREVIEW
from azext_aks_preview._completers import (
Expand Down Expand Up @@ -3688,6 +3689,36 @@ def load_arguments(self, _):
"'matchExpressions'. Maximum 100 entries.",
)

# AKS alert configuration commands
with self.argument_context("aks alert-config") as c:
c.argument("cluster_name", help="The cluster name.")
c.argument(
"aks_custom_headers",
help="Send custom headers. When specified, format should be Key1=Value1,Key2=Value2.",
)

for scope in ['aks alert-config add',
'aks alert-config update',
'aks alert-config delete',
'aks alert-config show']:
with self.argument_context(scope) as c:
c.argument('name', options_list=['--name', '-n'], required=True,
help='Name of the alert configuration.')

for scope in ['aks alert-config add',
'aks alert-config update']:
with self.argument_context(scope) as c:
c.argument('mode', arg_type=get_enum_type(['Disabled', 'Managed']),
help='How AKS manages alerts for the cluster.')
c.argument('action_group_id', options_list=['--action-group-id'],
validator=validate_action_group_id,
help='Resource ID of the Azure Monitor action group to send '
'notifications to. Pass an empty string to clear it.')

with self.argument_context('aks alert-config add') as c:
c.argument('mode', arg_type=get_enum_type(['Disabled', 'Managed']), required=True,
help='How AKS manages alerts for the cluster.')

# aks list-vm-skus command
with self.argument_context("aks list-vm-skus") as c:
c.argument(
Expand Down
23 changes: 23 additions & 0 deletions src/aks-preview/azext_aks_preview/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,3 +1270,26 @@ def validate_prepared_image_specification_id(namespace):
"--prepared-image-specification-id must be a resource ID of type "
"Microsoft.ContainerService/preparedImageSpecifications/versions."
)


def validate_action_group_id(namespace):
"""Validate that --action-group-id refers to a Microsoft.Insights/actionGroups resource.

An unset or empty value is allowed: the RP accepts an empty actionGroupId, and the CLI
always sends the key so the required-property contract is satisfied.
"""
action_group_id = getattr(namespace, "action_group_id", None)
if not action_group_id:
return
if not is_valid_resource_id(action_group_id):
raise InvalidArgumentValueError(
f"--action-group-id is not a valid Azure resource ID: {action_group_id}"
)
parsed = parse_resource_id(action_group_id)
provider_namespace = (parsed.get("namespace") or "").lower()
resource_type = (parsed.get("type") or "").lower()
if provider_namespace != "microsoft.insights" or resource_type != "actiongroups":
raise InvalidArgumentValueError(
"--action-group-id must reference a Microsoft.Insights/actionGroups resource, "
f"got: {action_group_id}"
)
106 changes: 106 additions & 0 deletions src/aks-preview/azext_aks_preview/alertconfiguration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# --------------------------------------------------------------------------------------------
# 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 (
RequiredArgumentMissingError,
ResourceNotFoundError,
)
from azure.cli.core.util import sdk_no_wait
from azure.core.exceptions import ResourceNotFoundError as SdkResourceNotFoundError

from azext_aks_preview.vendored_sdks.azure_mgmt_preview_aks.models import (
AlertConfiguration,
AlertConfigurationProperties,
AlertNotification,
)


def aks_alert_config_add_internal(cmd, client, raw_parameters, headers, no_wait): # pylint: disable=unused-argument
resource_group_name = raw_parameters.get("resource_group_name")
cluster_name = raw_parameters.get("cluster_name")
name = raw_parameters.get("name")
mode = raw_parameters.get("mode")
action_group_id = raw_parameters.get("action_group_id")

if not name:
raise RequiredArgumentMissingError(
"Please specify --name for the alert configuration."
)
if not mode:
raise RequiredArgumentMissingError(
"Please specify --mode for the alert configuration. "
"Allowed values are 'Managed' and 'Disabled'."
)

alert_config = AlertConfiguration(
properties=AlertConfigurationProperties(
mode=mode,
notification=AlertNotification(action_group_id=action_group_id or ""),
)
)

return sdk_no_wait(
no_wait,
client.begin_create_or_update,
resource_group_name,
cluster_name,
name,
alert_config,
headers=headers,
)


def aks_alert_config_update_internal(cmd, client, raw_parameters, headers, no_wait): # pylint: disable=unused-argument
resource_group_name = raw_parameters.get("resource_group_name")
cluster_name = raw_parameters.get("cluster_name")
name = raw_parameters.get("name")
mode = raw_parameters.get("mode")
action_group_id = raw_parameters.get("action_group_id")

if not name:
raise RequiredArgumentMissingError(
"Please specify --name for the alert configuration."
)
# An empty string is a meaningful value for --action-group-id (it clears the action
# group), so distinguish "not supplied" (None) from "supplied as empty".
if mode is None and action_group_id is None:
raise RequiredArgumentMissingError(
"Please specify at least one of --mode or --action-group-id to update."
)

try:
existing = client.get(resource_group_name, cluster_name, name, headers=headers)
except SdkResourceNotFoundError as ex:
raise ResourceNotFoundError(
f"Alert configuration '{name}' was not found in cluster '{cluster_name}'. "
"Use 'az aks alert-config add' to create it."
) from ex

existing_properties = getattr(existing, "properties", None)
existing_mode = getattr(existing_properties, "mode", None)
existing_notification = getattr(existing_properties, "notification", None)
existing_action_group_id = getattr(existing_notification, "action_group_id", None)

merged_mode = mode if mode is not None else existing_mode
merged_action_group_id = (
action_group_id if action_group_id is not None else existing_action_group_id
)

alert_config = AlertConfiguration(
properties=AlertConfigurationProperties(
mode=merged_mode,
notification=AlertNotification(action_group_id=merged_action_group_id or ""),
)
)

return sdk_no_wait(
no_wait,
client.begin_create_or_update,
resource_group_name,
cluster_name,
name,
alert_config,
headers=headers,
)
Loading
Loading