Skip to content

Commit edce5d0

Browse files
Merge branch 'Azure:main' into main
2 parents a60f6fc + fb7fc37 commit edce5d0

File tree

77 files changed

+36668
-15597
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+36668
-15597
lines changed

linter_exclusions.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ aks update:
198198
cluster_service_load_balancer_health_probe_mode:
199199
rule_exclusions:
200200
- option_length_too_long
201+
aks agent:
202+
parameters:
203+
prompt:
204+
rule_exclusions:
205+
- no_positional_parameters
201206
arcdata dc config init:
202207
parameters:
203208
path:

src/aks-preview/HISTORY.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
* Add framework for interactive AI-powered debugging tool.
1415

1516
18.0.0b26
1617
+++++++
17-
* Add `az aks identity-binding` command group for identity binding feataure.
18+
* Add `az aks identity-binding` command group for identity binding feature.
1819

1920
18.0.0b25
2021
+++++++

src/aks-preview/azext_aks_preview/_consts.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,3 +373,9 @@
373373
CONST_K8S_EXTENSION_NAME = "k8s-extension"
374374
CONST_K8S_EXTENSION_ACTION_MOD_NAME = "azext_k8s_extension.action"
375375
CONST_K8S_EXTENSION_FORMAT_MOD_NAME = "azext_k8s_extension._format"
376+
377+
# aks agent constants
378+
CONST_AGENT_CONFIG_PATH_DIR_ENV_KEY = "HOLMES_CONFIGPATH_DIR"
379+
CONST_AGENT_NAME = "AKS AGENT"
380+
CONST_AGENT_NAME_ENV_KEY = "AGENT_NAME"
381+
CONST_AGENT_CONFIG_FILE_NAME = "aksAgent.config"

src/aks-preview/azext_aks_preview/_help.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,3 +3943,101 @@
39433943
type: string
39443944
short-summary: Name of the identity binding to show.
39453945
"""
3946+
3947+
# pylint: disable=line-too-long
3948+
# helps[
3949+
# "aks agent"
3950+
# ] = """
3951+
# type: command
3952+
# short-summary: Run AI assistant to analyze and troubleshoot Kubernetes clusters.
3953+
# long-summary: |-
3954+
# This command allows you to ask questions about your Azure Kubernetes cluster and get answers using AI models.
3955+
# Environment variables must be set to use the AI model, please refer to https://docs.litellm.ai/docs/providers to learn more about supported AI providers and models and required environment variables.
3956+
# parameters:
3957+
# - name: --name -n
3958+
# type: string
3959+
# short-summary: Name of the managed cluster.
3960+
# - name: --resource-group -g
3961+
# type: string
3962+
# short-summary: Name of the resource group.
3963+
# - name: --model
3964+
# type: string
3965+
# short-summary: Model to use for the LLM.
3966+
# - name: --api-key
3967+
# type: string
3968+
# short-summary: API key to use for the LLM (if not given, uses environment variables AZURE_API_KEY, OPENAI_API_KEY).
3969+
# - name: --config-file
3970+
# type: string
3971+
# short-summary: Path to configuration file.
3972+
# - name: --max-steps
3973+
# type: int
3974+
# short-summary: Maximum number of steps the LLM can take to investigate the issue.
3975+
# - name: --no-interactive
3976+
# type: bool
3977+
# short-summary: Disable interactive mode. When set, the agent will not prompt for input and will run in batch mode.
3978+
# - name: --no-echo-request
3979+
# type: bool
3980+
# short-summary: Disable echoing back the question provided to AKS Agent in the output.
3981+
# - name: --show-tool-output
3982+
# type: bool
3983+
# short-summary: Show the output of each tool that was called during the analysis.
3984+
# - name: --refresh-toolsets
3985+
# type: bool
3986+
# short-summary: Refresh the toolsets status.
3987+
#
3988+
# examples:
3989+
# - name: Ask about pod issues in the cluster with Azure OpenAI
3990+
# text: |-
3991+
# export AZURE_API_BASE="https://my-azureopenai-service.openai.azure.com/"
3992+
# export AZURE_API_VERSION="2025-01-01-preview"
3993+
# export AZURE_API_KEY="sk-xxx"
3994+
# az aks agent "Why are my pods not starting?" --name MyManagedCluster --resource-group MyResourceGroup --model azure/my-gpt4.1-deployment
3995+
# - name: Ask about pod issues in the cluster with OpenAI
3996+
# text: |-
3997+
# export OPENAI_API_KEY="sk-xxx"
3998+
# az aks agent "Why are my pods not starting?" --name MyManagedCluster --resource-group MyResourceGroup --model gpt-4o
3999+
# text: az aks agent "Why are my pods not starting?"
4000+
# - name: Run in interactive mode without a question
4001+
# text: az aks agent "Check the pod status in my cluster" --name MyManagedCluster --resource-group MyResourceGroup --model azure/my-gpt4.1-deployment --api-key "sk-xxx"
4002+
# - name: Run in non-interactive batch mode
4003+
# text: az aks agent "Diagnose networking issues" --no-interactive --max-steps 15 --model azure/my-gpt4.1-deployment
4004+
# - name: Show detailed tool output during analysis
4005+
# text: az aks agent "Why is my service workload unavailable in namespace workload-ns?" --show-tool-output --model azure/my-gpt4.1-deployment
4006+
# - name: Use custom configuration file
4007+
# text: az aks agent "Check kubernetes pod resource usage" --config-file /path/to/custom.config --model azure/my-gpt4.1-deployment
4008+
# - name: Run agent with no echo of the original question
4009+
# text: az aks agent "What is the status of my cluster?" --no-echo-request --model azure/my-gpt4.1-deployment
4010+
# - name: Refresh toolsets to get the latest available tools
4011+
# text: az aks agent "What is the status of my cluster?" --refresh-toolsets --model azure/my-gpt4.1-deploymen
4012+
# - name: Run agent with config file
4013+
# text: |
4014+
# az aks agent "Check kubernetes pod resource usage" --config-file /path/to/custom.config
4015+
# Here is an example of config file:
4016+
# ```json
4017+
# model: "gpt-4o"
4018+
# api_key: "..."
4019+
# # define a list of mcp servers, mcp server can be defined
4020+
# mcp_servers:
4021+
# aks_mcp:
4022+
# description: "The AKS-MCP is a Model Context Protocol (MCP) server that enables AI assistants to interact with Azure Kubernetes Service (AKS) clusters"
4023+
# url: "http://localhost:8003/sse"
4024+
#
4025+
# # try adding your own tools or toggle the built-in toolsets here
4026+
# # e.g. query company-specific data, fetch logs from your existing observability tools, etc
4027+
# # To check how to add a customized toolset, please refer to https://docs.robusta.dev/master/configuration/holmesgpt/custom_toolsets.html#custom-toolsets
4028+
# # To find all built-in toolsets, please refer to https://docs.robusta.dev/master/configuration/holmesgpt/builtin_toolsets.html
4029+
# toolsets:
4030+
# # add a new json processor toolset
4031+
# json_processor:
4032+
# description: "A toolset for processing JSON data using jq"
4033+
# prerequisites:
4034+
# - command: "jq --version" # Ensure jq is installed
4035+
# tools:
4036+
# - name: "process_json"
4037+
# description: "A tool that uses jq to process JSON input"
4038+
# command: "echo '{{ json_input }}' | jq '.'" # Example jq command to format JSON
4039+
# # disable a built-in toolsets
4040+
# aks/core:
4041+
# enabled: false
4042+
# ```
4043+
# """

src/aks-preview/azext_aks_preview/_params.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
validate_nat_gateway_idle_timeout,
2424
validate_nat_gateway_managed_outbound_ip_count,
2525
)
26+
# from azure.cli.core.api import get_config_dir
2627
from azure.cli.core.commands.parameters import (
2728
edge_zone_type,
2829
file_type,
@@ -223,6 +224,7 @@
223224
validate_max_blocked_nodes,
224225
validate_resource_group_parameter,
225226
validate_location_resource_group_cluster_parameters,
227+
# validate_agent_config_file,
226228
)
227229
from azext_aks_preview.azurecontainerstorage._consts import (
228230
CONST_ACSTOR_ALL,
@@ -2775,6 +2777,71 @@ def load_arguments(self, _):
27752777
action="store_true",
27762778
)
27772779

2780+
# pylint: disable=line-too-long
2781+
# with self.argument_context("aks agent") as c:
2782+
# c.positional(
2783+
# "prompt",
2784+
# help="Ask any question and answer using available tools.",
2785+
# )
2786+
# c.argument(
2787+
# "resource_group_name",
2788+
# options_list=["--resource-group", "-g"],
2789+
# help="Name of resource group.",
2790+
# required=False,
2791+
# )
2792+
# c.argument(
2793+
# "name",
2794+
# options_list=["--name", "-n"],
2795+
# help="Name of the managed cluster.",
2796+
# required=False,
2797+
# )
2798+
# c.argument(
2799+
# "max_steps",
2800+
# type=int,
2801+
# default=10,
2802+
# required=False,
2803+
# help="Maximum number of steps the LLM can take to investigate the issue.",
2804+
# )
2805+
# c.argument(
2806+
# "config_file",
2807+
# default=os.path.join(get_config_dir(), "aksAgent.config"),
2808+
# validator=validate_agent_config_file,
2809+
# required=False,
2810+
# help="Path to the config file.",
2811+
# )
2812+
# c.argument(
2813+
# "model",
2814+
# help="The model to use for the LLM.",
2815+
# required=False,
2816+
# type=str,
2817+
# )
2818+
# c.argument(
2819+
# "api-key",
2820+
# help="API key to use for the LLM (if not given, uses environment variables AZURE_API_KEY, OPENAI_API_KEY)",
2821+
# required=False,
2822+
# type=str,
2823+
# )
2824+
# c.argument(
2825+
# "no_interactive",
2826+
# help="Disable interactive mode. When set, the agent will not prompt for input and will run in batch mode.",
2827+
# action="store_true",
2828+
# )
2829+
# c.argument(
2830+
# "no_echo_request",
2831+
# help="Disable echoing back the question provided to AKS Agent in the output.",
2832+
# action="store_true",
2833+
# )
2834+
# c.argument(
2835+
# "show_tool_output",
2836+
# help="Show the output of each tool that was called.",
2837+
# action="store_true",
2838+
# )
2839+
# c.argument(
2840+
# "refresh_toolsets",
2841+
# help="Refresh the toolsets status.",
2842+
# action="store_true",
2843+
# )
2844+
27782845

27792846
def _get_default_install_location(exe_name):
27802847
system = platform.system()

src/aks-preview/azext_aks_preview/_validators.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
import os
99
import os.path
1010
import re
11+
import yaml
1112
from ipaddress import ip_network
1213
from math import isclose, isnan
1314

1415
from azure.cli.core import keys
16+
from azure.cli.core.api import get_config_dir
1517
from azure.cli.core.azclierror import (
1618
ArgumentUsageError,
1719
InvalidArgumentValueError,
@@ -35,6 +37,7 @@
3537
CONST_NETWORK_POD_IP_ALLOCATION_MODE_STATIC_BLOCK,
3638
CONST_NODEPOOL_MODE_GATEWAY,
3739
CONST_AZURE_SERVICE_MESH_MAX_EGRESS_NAME_LENGTH,
40+
CONST_AGENT_CONFIG_FILE_NAME,
3841
)
3942
from azext_aks_preview._helpers import _fuzzy_match
4043
from knack.log import get_logger
@@ -977,3 +980,38 @@ def validate_location_resource_group_cluster_parameters(namespace):
977980
raise MutuallyExclusiveArgumentError(
978981
"Cannot specify --location and --resource-group and --cluster at the same time."
979982
)
983+
984+
985+
def _validate_param_yaml_file(yaml_path, param_name):
986+
if not yaml_path:
987+
return
988+
if not os.path.exists(yaml_path):
989+
raise InvalidArgumentValueError(
990+
f"--{param_name}={yaml_path}: file is not found."
991+
)
992+
if not os.access(yaml_path, os.R_OK):
993+
raise InvalidArgumentValueError(
994+
f"--{param_name}={yaml_path}: file is not readable."
995+
)
996+
try:
997+
with open(yaml_path, "r") as file:
998+
yaml.safe_load(file)
999+
except yaml.YAMLError as e:
1000+
raise InvalidArgumentValueError(
1001+
f"--{param_name}={yaml_path}: file is not a valid YAML file: {e}"
1002+
)
1003+
except Exception as e:
1004+
raise InvalidArgumentValueError(
1005+
f"--{param_name}={yaml_path}: An error occurred while reading the config file: {e}"
1006+
)
1007+
1008+
1009+
def validate_agent_config_file(namespace):
1010+
config_file = namespace.config_file
1011+
if not config_file:
1012+
return
1013+
default_config_path = os.path.join(get_config_dir(), CONST_AGENT_CONFIG_FILE_NAME)
1014+
if config_file == default_config_path and not os.path.exists(config_file):
1015+
return
1016+
1017+
_validate_param_yaml_file(config_file, "config-file")

src/aks-preview/azext_aks_preview/agent/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)