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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **The three upstream lines at their decoupled releases: kagent `1.0.0`, Substrate `1.0.0`, agentgateway `2.0.0` under its nested names** (giantswarm/agent-platform#608; epic giantswarm/giantswarm#37705). The lines release stable semver of their own, decoupled from the upstream versions their `FORK.md`s record, and publish nothing more under the former `vX.Y.Z-gs.N` scheme. `components.kagent*.versionRange` and `components.substrate*.versionRange` are `>=1.0.0 <1.1.0`; both charts name the agentgateway line's `2.0.0` in full — `agentgateway.controller.image` `giantswarm/agentgateway-upstream/controller:2.0.0`, `agentgateway.proxy.image` `giantswarm/agentgateway-upstream/agentgateway:2.0.0`, `substrate.images.agentgateway` the same data plane for Substrate's egress gateway — so the packaging chart's defaults cannot move the images (a value wins over a chart default, and a default that moved alone to the nested names rendered a tag that existed only there); `components.agentgateway.versionRange` is `>=2.2.2 <3.0.0`, the packaging release that renders a bare tag as written. The range shape follows the scheme — a patch of a line never changes a runtime contract, a re-pin onto another upstream release is at least a minor — so `agent-platform.substrate.validateRange` admits an exact version or `>=X.Y.Z <X.(Y+1).0` and refuses a `-0` bound (Flux's Masterminds semver skips prereleases while no bound of a range carries one and evaluates them all once one does, so `<1.1.0-0` would have put every installation on the line's newest dev build) and the former `>=X.Y.Z-gs.N <X.Y.(Z+1)-0`, `agent-platform.substrate.workerPoolSpreadFloor` is `1.0.0`, `examples/customer-bom.yaml` pins `1.0.0` and `2.2.2`, and the verify scripts' fixtures move to the stable shapes. UPGRADE.md names the operator's part.\n\n- **The kagent line's and the Substrate line's charts come from gsoci; the lines move to `v0.11.0-gs.22` and `v0.0.30-gs.5`** (giantswarm/agent-platform#580; epic giantswarm/giantswarm#37853). The two lines publish natively to the org's registry from CircleCI — the multi-arch images and the charts, signed with the Giant Swarm identity, releases and dev builds alike — so `components.kagent.repository` and `components.kagent-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/kagent/helm`, `components.substrate.repository` and `components.substrate-crds.repository` are `oci://gsoci.azurecr.io/giantswarm/substrate/helm`. The Substrate floor moves to `0.0.30-gs.5` — the line's first release published there, the patches of gs.4 — in `components.substrate*.versionRange` (`>=0.0.30-gs.5 <0.0.31-0`), the BOM pin and, derived from it, the kagent WorkerPool's worker image, so the atelet and the worker are one native, signed release and nothing of the line depends on a copy. The kagent floor moves to `0.11.0-gs.22` the same way (`components.kagent*.versionRange` `>=0.11.0-gs.22 <0.11.1-0`, the BOM pin): the chart paths on gsoci begin with each line's first native release — the older releases exist there as retagger's image copies only, no charts — and the kagent chart's stamped digests of its Go ADK and Claude harness images resolve on gsoci from that release on. With the charts the last ghcr.io reference of the two lines goes: a default installation pulls everything of kagent and Substrate from gsoci, and the dev channel (a `components.<name>.semverFilter` on the lines' `-dev.giantswarm.` builds) needs no registry override any more — `kagent.registry` and `substrate.image.registry` stay on their defaults (README "Dev channel"). `make verify-images` tolerates the two lines by name no longer; the upstream CloudNativePG chart is the one pending entry left, behind a Giant Swarm wrapper release on the same operator line. `verify-components` and `verify-kagent-wiring` assert the new sources; `verify-target` holds them on both sides of the golden comparison until `origin/main` carries them. UPGRADE.md.
Expand All @@ -16,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- **The mcp-kubernetes chart's own ServiceMonitor and its three Grafana boards are on** (giantswarm/giantswarm#36711). The chart ships a ServiceMonitor over the dedicated metrics port and the boards `administrator`, `security` and `cluster-operator`, and this chart turned none of them on, so an installation that runs the Kubernetes MCP server collected nothing from it. `mcp-kubernetes.mcpKubernetes.instrumentation.serviceMonitor.enabled` and `mcp-kubernetes.grafanaDashboards.enabled` follow the resolved `global.observability.metrics.serviceMonitor.enabled` (`auto | true | false`), the monitor carries `observability.giantswarm.io/tenant`, and the boards land in `Shared Org / Agent Platform` beside the platform's own. The chart's `prometheusRules` stay off: its three alerts link to runbook pages that do not exist yet. The floor `1.1.1` already carries every key, so no range moves.
- **Every agent platform dashboard lands in one folder customers can reach: `Shared Org / Agent Platform`** (giantswarm/giantswarm#36711). The muster board (`Muster / MCP Gateway`) was loaded into the staff-only `Giant Swarm` organization, in a folder named after the component, so the people who run agents on the platform could not see it: `muster.observability.grafanaDashboard.folder` is `Agent Platform` and `.giantswarm.organization` is `Shared Org`. `Shared Org` is the organization every logged-in customer reaches as a Viewer and it carries the observability data of Giant Swarm managed components, which is where these boards belong; the `Giant Swarm` organization is staff-only. The boards that follow — the agentgateway gateway board, the platform's own overview — land in the same folder.
- **The agentgateway packaging chart's own monitors and dashboard are on: `agentgateway.monitoring.enabled`** (giantswarm/giantswarm#36711, giantswarm/agentgateway#60). It follows the resolved `global.observability.metrics.serviceMonitor.enabled` like every other monitor of this chart (`auto | true | false`), at the fleet's 60s interval and with the `observability.giantswarm.io/tenant` label on both monitors. It turns on three objects the platform did not have: the **controller** ServiceMonitor, which nothing scraped, and with it the only view of the control plane that serves the data planes their config; upstream's proxy PodMonitor; and upstream's own Grafana board — Overview, Requests, LLM, **MCP tool calls**, Latency, **XDS**, **Runtime** — vendored in the packaging chart since 2.0.0 and never rendered. The MCP and runtime series it reads were already collected and had no consumer. The board is upstream's to maintain, so a version bump carries its fixes; the boards the platform writes itself (LLM cost per agent and per person) stay in `giantswarm/dashboards`.

Expand Down
6 changes: 6 additions & 0 deletions helm/agent-platform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1257,11 +1257,17 @@ The map is merged into each component's own `nodeSelector` (`muster.nodeSelector
| backstage.backstage.extraVolumeMounts[0].mountPath | string | `"/etc/agent-platform/idp-ca"` | |
| backstage.backstage.extraVolumeMounts[0].readOnly | bool | `true` | |
| mcp-kubernetes.fullnameOverride | string | `"mcp-kubernetes"` | |
| mcp-kubernetes.mcpKubernetes.instrumentation.serviceMonitor.enabled | string | `"auto"` | |
| mcp-kubernetes.mcpKubernetes.instrumentation.serviceMonitor.labels."observability.giantswarm.io/tenant" | string | `"giantswarm"` | |
| mcp-kubernetes.mcpKubernetes.oauth.enabled | bool | `true` | |
| mcp-kubernetes.mcpKubernetes.oauth.provider | string | `"dex"` | |
| mcp-kubernetes.mcpKubernetes.oauth.allowPrivateURLs | bool | `true` | |
| mcp-kubernetes.mcpKubernetes.oauth.sso.allowPrivateIPs | bool | `true` | |
| mcp-kubernetes.mcpKubernetes.oauth.enableDownstreamOAuth | bool | `true` | |
| mcp-kubernetes.grafanaDashboards.enabled | string | `"auto"` | |
| mcp-kubernetes.grafanaDashboards.folder | string | `"Agent Platform"` | |
| mcp-kubernetes.grafanaDashboards.giantswarm.enabled | bool | `true` | |
| mcp-kubernetes.grafanaDashboards.giantswarm.organization | string | `"Shared Org"` | |
| mcp-kubernetes.kubernetesAudience | string | `"dex-k8s-authenticator"` | |
| cloudnative-pg | object | `{}` | |
| kagent-crds.kmcp.enabled | bool | `false` | |
Expand Down
8 changes: 7 additions & 1 deletion helm/agent-platform/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -1317,7 +1317,11 @@ answers, but only where the leaf is left at `auto`:
OTLP gateway they export to is part of that platform),
agentgateway.monitoring.enabled (the packaging
chart's own gate over its controller ServiceMonitor,
proxy PodMonitor and dashboard ConfigMap)
proxy PodMonitor and dashboard ConfigMap),
mcp-kubernetes.mcpKubernetes.instrumentation
.serviceMonitor.enabled and
mcp-kubernetes.grafanaDashboards.enabled (its
monitor and the three boards it ships)
Two leaves have no `auto` form and are derived directly, off only:
valkey.valkey.metrics.podMonitor.enabled — the valkey chart's own default is
on; written false when monitors are off, left absent otherwise so the
Expand Down Expand Up @@ -1376,6 +1380,8 @@ connectivity release both read the resolved value. */ -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "muster" "muster" "observability" "grafanaDashboard" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "kagent" "oauth2-proxy" "metrics" "serviceMonitor" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "agentgateway" "monitoring" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "mcp-kubernetes" "mcpKubernetes" "instrumentation" "serviceMonitor" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "mcp-kubernetes" "grafanaDashboards" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "kagent" "otel" "tracing" "enabled") "value" $monitors) -}}
{{- include "agent-platform.shape.derive" (dict "values" $v "path" (list "kagent" "otel" "logging" "enabled") "value" $monitors) -}}
{{- /* valkey PodMonitor: the chart's own default is on, so only "off" is written. */ -}}
Expand Down
22 changes: 22 additions & 0 deletions helm/agent-platform/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4385,13 +4385,35 @@ backstage: # @schema skipProperties: true; additionalProperties: true
mcp-kubernetes: # @schema skipProperties: true; additionalProperties: true
fullnameOverride: mcp-kubernetes
mcpKubernetes:
instrumentation:
# The chart serves /metrics on its own port whatever this holds
# (mcpKubernetes.metrics, on by default); this renders the monitor that
# collects it. `auto` follows the resolved
# global.observability.metrics.serviceMonitor.enabled.
serviceMonitor:
enabled: auto # @schema type: [boolean, string]; enum: [auto, true, false]
labels:
# Mimir routes a scrape by this label; a monitor without it writes to
# no tenant of the GS observability platform.
observability.giantswarm.io/tenant: giantswarm
oauth:
enabled: true
provider: dex
allowPrivateURLs: true
sso:
allowPrivateIPs: true
enableDownstreamOAuth: true
# The three boards the chart ships (administrator, security, cluster
# operator), into the platform's own folder. `auto` follows the resolved
# global.observability.metrics.serviceMonitor.enabled: the operator that picks
# a board up is part of the platform the monitor writes to. Both annotation
# values carry a space, so neither can be a label.
grafanaDashboards:
enabled: auto # @schema type: [boolean, string]; enum: [auto, true, false]
folder: "Agent Platform"
giantswarm:
enabled: true
organization: "Shared Org"
# --- Wiring (read by the connectivity chart, not passed to the mcp-kubernetes chart) ---
# Audience the forwarded IdP id_token must carry on top of the platform
# client's so the kube-apiserver accepts it: muster requests this
Expand Down
17 changes: 15 additions & 2 deletions tests/verify-target.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@
"--set", "agentgateway.monitoring.grafanaDashboard.annotations.observability\\.giantswarm\\.io/organization=Shared Org",
"--set", "agentgateway.monitoring.grafanaDashboard.annotations.observability\\.giantswarm\\.io/folder=Agent Platform",
]
# giantswarm/giantswarm#36711: this tree turns the mcp-kubernetes chart's own
# ServiceMonitor and its three Grafana boards on, which GOLDEN_REF's defaults
# leave off and whose keys it does not carry at all. The whole block is written
# on BOTH sides so the forwarded values compare equal; dropped once GOLDEN_REF
# carries it.
MCP_KUBERNETES_MONITORING_HOLD = [
"--set", "mcp-kubernetes.mcpKubernetes.instrumentation.serviceMonitor.enabled=false",
"--set", "mcp-kubernetes.mcpKubernetes.instrumentation.serviceMonitor.labels.observability\\.giantswarm\\.io/tenant=giantswarm",
"--set", "mcp-kubernetes.grafanaDashboards.enabled=false",
"--set", "mcp-kubernetes.grafanaDashboards.folder=Agent Platform",
"--set", "mcp-kubernetes.grafanaDashboards.giantswarm.enabled=true",
"--set", "mcp-kubernetes.grafanaDashboards.giantswarm.organization=Shared Org",
]
AGENTGATEWAY_IMAGES_HOLD = [
"--set", "agentgateway.controller.image.repository=giantswarm/agentgateway-upstream/controller",
"--set", "agentgateway.controller.image.tag=2.0.0",
Expand Down Expand Up @@ -382,8 +395,8 @@ def check_golden(meta: str, connectivity: str) -> None:
# carries the switch.
hold_iv = ["--set", "modelServing.imageVerification.enabled=false"]
shapes = [
("meta default", meta, [*hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD, *AGENTGATEWAY_MONITORING_HOLD]),
("meta ci + engine off", meta, ["-f", f"{meta}/ci/ci-values.yaml", *ENGINE_OFF, *hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD, *AGENTGATEWAY_MONITORING_HOLD]),
("meta default", meta, [*hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD, *AGENTGATEWAY_MONITORING_HOLD, *MCP_KUBERNETES_MONITORING_HOLD]),
("meta ci + engine off", meta, ["-f", f"{meta}/ci/ci-values.yaml", *ENGINE_OFF, *hold_608, *METRIC_LABELS_HOLD, *hold_iv, *MUSTER_DASHBOARD_HOLD, *AGENTGATEWAY_MONITORING_HOLD, *MCP_KUBERNETES_MONITORING_HOLD]),
("connectivity default", connectivity, [*VM, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
("connectivity full", connectivity, [*CONN_FULL, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
("connectivity backstage", connectivity, [*CONN_BACKSTAGE, *METRIC_LABELS_HOLD, *hold_iv, *AGENTGATEWAY_IMAGES_HOLD]),
Expand Down
Loading