Skip to content

Commit ea21f0f

Browse files
committed
helm and metrics script
Signed-off-by: Art Berger <art.berger@solo.io>
1 parent c950d4e commit ea21f0f

6 files changed

Lines changed: 186 additions & 33 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Generate Helm and metrics reference documentation for the agentgateway website.
4+
5+
Reads version config from .github/workflows/versions.json. Generates only
6+
agentgateway-relevant artifacts from a checked-out kgateway repo:
7+
- Helm: agentgateway and agentgateway-crds charts -> assets/agw-docs/pages/reference/helm/{version}/
8+
- Metrics: control plane metrics -> assets/agw-docs/snippets/{metricsSnippet} (metricsSnippet from versions.json, e.g. metrics-control-plane-22x.md)
9+
10+
API reference docs are generated by the workflow (reference-docs.yaml) and are not handled here.
11+
12+
Usage (from workflow):
13+
DOC_VERSION=2.2.x python3 .github/workflows/generate-ref-docs.py
14+
(run from website repo root; kgateway clone is at ./kgateway)
15+
"""
16+
17+
import json
18+
import os
19+
import platform
20+
import subprocess
21+
import sys
22+
23+
24+
# Agentgateway-only Helm charts: directory under install/helm : output filename
25+
HELM_CHARTS = [
26+
("agentgateway", "agentgateway"),
27+
("agentgateway-crds", "agentgateway-crds"),
28+
]
29+
30+
31+
def generate_helm_docs(version: str, website_dir: str, kgateway_dir: str) -> bool:
32+
"""Generate Helm chart reference docs for agentgateway and agentgateway-crds."""
33+
print(f" → Generating Helm docs for version {version}")
34+
35+
assets_path = os.path.join(website_dir, "assets", "agw-docs", "pages", "reference", "helm", version)
36+
os.makedirs(assets_path, exist_ok=True)
37+
generated_any = False
38+
39+
for dir_name, file_name in HELM_CHARTS:
40+
helm_path = os.path.join(kgateway_dir, "install", "helm", dir_name)
41+
if not os.path.exists(helm_path):
42+
print(f" Warning: {helm_path} does not exist, skipping {file_name}")
43+
continue
44+
45+
result = subprocess.run(
46+
[
47+
"go", "run", "github.com/norwoodj/helm-docs/cmd/helm-docs@v1.14.2",
48+
f"--chart-search-root={helm_path}",
49+
"--dry-run",
50+
],
51+
capture_output=True,
52+
text=True,
53+
check=True,
54+
)
55+
56+
helm_file = os.path.join(assets_path, f"{file_name}.md")
57+
with open(helm_file, "w") as f:
58+
f.write(result.stdout)
59+
60+
# Remove version badge and first 3 lines (title, blank, description)
61+
if platform.system() == "Darwin":
62+
subprocess.run(["sed", "-i", "", r"/!\[Version:/,/^$/d", helm_file], check=True)
63+
subprocess.run(["sed", "-i", "", "1,3d", helm_file], check=True)
64+
else:
65+
subprocess.run(["sed", "-i", r"/!\[Version:/,/^$/d", helm_file], check=True)
66+
subprocess.run(["sed", "-i", "1,3d", helm_file], check=True)
67+
68+
with open(helm_file, "r", encoding="utf-8") as f:
69+
content = f.read()
70+
71+
content = content.replace('{{< callout type=info >}}', '{{< callout type="info" >}}')
72+
if "## Values" not in content or ("## Values" in content and "|-----|" not in content):
73+
note = '\n\n{{< callout type="info" >}}\nNo configurable values are currently available for this chart.\n{{< /callout >}}\n'
74+
if "{{< callout" not in content:
75+
content = content.rstrip() + note
76+
77+
# Swap Default and Description columns
78+
swapped_lines = []
79+
in_table = False
80+
for line in content.splitlines():
81+
stripped = line.strip()
82+
if stripped.startswith("| Key ") and "Default" in line and "Description" in line:
83+
in_table = True
84+
swapped_lines.append("| Key | Type | Description | Default |")
85+
continue
86+
if in_table and stripped.startswith("|-----"):
87+
swapped_lines.append("|-----|------|-------------|---------|")
88+
continue
89+
if in_table and stripped.startswith("|"):
90+
parts = [p.strip() for p in line.split("|")]
91+
if len(parts) >= 6:
92+
key, typ, default, desc = parts[1], parts[2], parts[3], parts[4]
93+
swapped_lines.append(f"| {key} | {typ} | {desc} | {default} |")
94+
else:
95+
swapped_lines.append(line)
96+
else:
97+
if in_table and not stripped.startswith("|"):
98+
in_table = False
99+
swapped_lines.append(line)
100+
content = "\n".join(swapped_lines)
101+
102+
with open(helm_file, "w", encoding="utf-8") as f:
103+
f.write(content)
104+
105+
print(f" ✓ Generated {helm_file}")
106+
generated_any = True
107+
108+
return generated_any
109+
110+
111+
def generate_metrics_docs(version: str, website_dir: str, kgateway_dir: str, metrics_snippet: str) -> bool:
112+
"""Generate control plane metrics into a versioned snippet (e.g. metrics-control-plane-22x.md)."""
113+
print(f" → Generating metrics docs for version {version}")
114+
115+
snippets_dir = os.path.join(website_dir, "assets", "agw-docs", "snippets")
116+
os.makedirs(snippets_dir, exist_ok=True)
117+
out_file = os.path.join(snippets_dir, metrics_snippet)
118+
119+
try:
120+
result = subprocess.run(
121+
["go", "run", "./pkg/metrics/cmd/findmetrics", "--markdown", "."],
122+
capture_output=True,
123+
text=True,
124+
check=True,
125+
cwd=kgateway_dir,
126+
)
127+
md_content = result.stdout
128+
except subprocess.CalledProcessError as e:
129+
print(f" Warning: findmetrics failed: {e.stderr or e}")
130+
return False
131+
132+
with open(out_file, "w") as f:
133+
f.write(md_content)
134+
print(f" ✓ Generated {out_file}")
135+
return True
136+
137+
138+
def main() -> None:
139+
doc_version = os.environ.get("DOC_VERSION", "").strip()
140+
if not doc_version:
141+
print("Error: DOC_VERSION must be set (e.g. 2.2.x, 2.3.x)")
142+
sys.exit(1)
143+
144+
website_dir = os.environ.get("WEBSITE_DIR", ".")
145+
kgateway_dir = os.environ.get("KGATEWAY_DIR", "kgateway")
146+
147+
versions_file = os.path.join(website_dir, ".github", "workflows", "versions.json")
148+
if not os.path.exists(versions_file):
149+
print(f"Error: {versions_file} not found")
150+
sys.exit(1)
151+
152+
with open(versions_file) as f:
153+
versions = json.load(f)
154+
entry = next((v for v in versions if v.get("version") == doc_version), None)
155+
if not entry:
156+
print(f"Error: version {doc_version} not in versions.json")
157+
sys.exit(1)
158+
159+
# Snippet filename for metrics (e.g. metrics-control-plane-22x.md); fallback: derive from version
160+
metrics_snippet = entry.get("metricsSnippet") or f"metrics-control-plane-{doc_version.replace('.', '')}.md"
161+
162+
if not os.path.isdir(kgateway_dir):
163+
print(f"Error: kgateway directory not found at {kgateway_dir}")
164+
sys.exit(1)
165+
166+
print(f"Generating Helm + metrics for version {doc_version} (kgateway at {kgateway_dir})")
167+
success = 0
168+
if generate_helm_docs(doc_version, website_dir, kgateway_dir):
169+
success += 1
170+
if generate_metrics_docs(doc_version, website_dir, kgateway_dir, metrics_snippet):
171+
success += 1
172+
print(f"Done: generated {success}/2 doc types")
173+
174+
175+
if __name__ == "__main__":
176+
main()

.github/workflows/versions.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
"linkVersion": "main",
55
"url": "main",
66
"apiFile": "api-23x.md",
7-
"kgatewayRef": "main"
7+
"kgatewayRef": "main",
8+
"metricsSnippet": "metrics-control-plane-23x.md"
89
},
910
{
1011
"version": "2.2.x",
1112
"linkVersion": "latest",
1213
"url": "latest",
1314
"apiFile": "api-22x.md",
14-
"kgatewayRef": "v2.2.x"
15+
"kgatewayRef": "v2.2.x",
16+
"metricsSnippet": "metrics-control-plane-22x.md"
1517
}
1618
]

assets/agw-docs/pages/observability/control-plane-metrics.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,9 @@ Helpful terms:
4141

4242
* Transform: The process of the control plane converting high-level resources or intermediate representations (IR) into lower-level representations into the structure that the XDS API expects for a snapshot.
4343

44-
{{< reuse "agw-docs/snippets/latest/metrics-control-plane.md" >}}
44+
{{< version include-if="2.2.x" >}}
45+
{{< reuse "agw-docs/snippets/metrics-control-plane-22x.md" >}}
46+
{{< /version >}}
47+
{{< version include-if="2.3.x" >}}
48+
{{< reuse "agw-docs/snippets/metrics-control-plane-23x.md" >}}
49+
{{< /version >}}

assets/agw-docs/snippets/main/metrics-control-plane.md

Lines changed: 0 additions & 27 deletions
This file was deleted.
File renamed without changes.

assets/agw-docs/snippets/latest/metrics-control-plane.md renamed to assets/agw-docs/snippets/metrics-control-plane-23x.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ kgateway_status_syncer_status_syncs_total|counter|name, namespace, syncer, resul
1414
kgateway_translator_translation_duration_seconds|histogram|name, namespace, translator|Translation duration
1515
kgateway_translator_translations_running|gauge|name, namespace, translator|Current number of translations running
1616
kgateway_translator_translations_total|counter|name, namespace, translator, result|Total number of translations
17-
kgateway_xds_auth_rq_failure_total|counter||Total number of failed xDS auth requests
18-
kgateway_xds_auth_rq_success_total|counter||Total number of successful xDS auth requests
19-
kgateway_xds_auth_rq_total|counter||Total number of xDS auth requests
2017
kgateway_xds_snapshot_resources|gauge|gateway, namespace, resource|Current number of resources in XDS snapshot
2118
kgateway_xds_snapshot_sync_duration_seconds|histogram|gateway, namespace|Duration of time for a gateway resource update to be synced in an XDS snapshot
2219
kgateway_xds_snapshot_syncs_total|counter|gateway, namespace|Total number of XDS snapshot syncs

0 commit comments

Comments
 (0)