""" Pydantic models for get_metric_metadata MCP tool input validation. Validates cluster context and optional metric/match/limit parameters for Prometheus metadata discovery. """ import re from typing import Optional from pydantic import BaseModel, Field, field_validator # Reuse the same max from list_metrics for consistency. MAX_METADATA_METRICS = 500 class MetricMetadataRequest(BaseModel): """ Input model for get_metric_metadata requests. Supports single-metric lookup (metric param) and bulk discovery with optional regex filtering (match param). """ cluster_id: str = Field( ..., description="Cluster identifier", ) env: str = Field( ..., description="Environment name used in biz_type resolution (e.g. prod, staging, dev)", ) deploy_type: str = Field( ..., description=( "Cluster deploy type used in biz_type resolution " "(dedicated, premium, resource_pool, starter, essential)" ), ) metric: Optional[str] = Field( default=None, description=( "Exact metric name for single-metric lookup " "(e.g. 'topsql_cpu_time_ms'). Mutually exclusive with match." ), ) match: Optional[str] = Field( default=None, description=( "Regex pattern to filter metric names in bulk mode " "(e.g. '^topsql_', 'http_requests_'). Applied client-side after fetching metadata." ), ) limit: Optional[int] = Field( default=None, ge=1, le=MAX_METADATA_METRICS, description=f"Maximum number of metrics to return (1–{MAX_METADATA_METRICS}). " "Defaults to server maximum if not specified.", ) @field_validator("metric") @classmethod def validate_metric_name(cls, v: Optional[str]) -> Optional[str]: if v is None or not v.strip(): return None return v.strip() @field_validator("match") @classmethod def validate_match_regex(cls, v: Optional[str]) -> Optional[str]: if v is None or not v.strip(): return None try: re.compile(v) except re.error as e: raise ValueError(f"Invalid search pattern. Error details: {e}") from e return v.strip() @field_validator("env", "deploy_type", mode="before") @classmethod def normalize_scope_text(cls, v: str) -> str: return v.strip().lower() @field_validator("cluster_id", mode="before") @classmethod def normalize_cluster_id(cls, v: object) -> str: if not isinstance(v, str): raise ValueError("cluster_id must be a string. Quote numeric IDs explicitly.") return str(v).strip()