@techwavedev/agi-agent-kit 1.1.7 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @techwavedev/agi-agent-kit might be problematic. Click here for more details.
- package/CHANGELOG.md +82 -1
- package/README.md +190 -12
- package/bin/init.js +30 -2
- package/package.json +6 -3
- package/templates/base/AGENTS.md +54 -23
- package/templates/base/README.md +325 -0
- package/templates/base/directives/memory_integration.md +95 -0
- package/templates/base/execution/memory_manager.py +309 -0
- package/templates/base/execution/session_boot.py +218 -0
- package/templates/base/execution/session_init.py +320 -0
- package/templates/base/skill-creator/SKILL_skillcreator.md +23 -36
- package/templates/base/skill-creator/scripts/init_skill.py +18 -135
- package/templates/skills/ec/README.md +31 -0
- package/templates/skills/ec/aws/SKILL.md +1020 -0
- package/templates/skills/ec/aws/defaults.yaml +13 -0
- package/templates/skills/ec/aws/references/common_patterns.md +80 -0
- package/templates/skills/ec/aws/references/mcp_servers.md +98 -0
- package/templates/skills/ec/aws-terraform/SKILL.md +349 -0
- package/templates/skills/ec/aws-terraform/references/best_practices.md +394 -0
- package/templates/skills/ec/aws-terraform/references/checkov_reference.md +337 -0
- package/templates/skills/ec/aws-terraform/scripts/configure_mcp.py +150 -0
- package/templates/skills/ec/confluent-kafka/SKILL.md +655 -0
- package/templates/skills/ec/confluent-kafka/references/ansible_playbooks.md +792 -0
- package/templates/skills/ec/confluent-kafka/references/ec_deployment.md +579 -0
- package/templates/skills/ec/confluent-kafka/references/kraft_migration.md +490 -0
- package/templates/skills/ec/confluent-kafka/references/troubleshooting.md +778 -0
- package/templates/skills/ec/confluent-kafka/references/upgrade_7x_to_8x.md +488 -0
- package/templates/skills/ec/confluent-kafka/scripts/kafka_health_check.py +435 -0
- package/templates/skills/ec/confluent-kafka/scripts/upgrade_preflight.py +568 -0
- package/templates/skills/ec/confluent-kafka/scripts/validate_config.py +455 -0
- package/templates/skills/ec/consul/SKILL.md +427 -0
- package/templates/skills/ec/consul/references/acl_setup.md +168 -0
- package/templates/skills/ec/consul/references/ha_config.md +196 -0
- package/templates/skills/ec/consul/references/troubleshooting.md +267 -0
- package/templates/skills/ec/consul/references/upgrades.md +213 -0
- package/templates/skills/ec/consul/scripts/consul_health_report.py +530 -0
- package/templates/skills/ec/consul/scripts/consul_status.py +264 -0
- package/templates/skills/ec/consul/scripts/generate_values.py +170 -0
- package/templates/skills/ec/documentation/SKILL.md +351 -0
- package/templates/skills/ec/documentation/references/best_practices.md +201 -0
- package/templates/skills/ec/documentation/scripts/analyze_code.py +307 -0
- package/templates/skills/ec/documentation/scripts/detect_changes.py +460 -0
- package/templates/skills/ec/documentation/scripts/generate_changelog.py +312 -0
- package/templates/skills/ec/documentation/scripts/sync_docs.py +272 -0
- package/templates/skills/ec/documentation/scripts/update_skill_docs.py +366 -0
- package/templates/skills/ec/gitlab/SKILL.md +529 -0
- package/templates/skills/ec/gitlab/references/agent_installation.md +416 -0
- package/templates/skills/ec/gitlab/references/api_reference.md +508 -0
- package/templates/skills/ec/gitlab/references/gitops_flux.md +465 -0
- package/templates/skills/ec/gitlab/references/troubleshooting.md +518 -0
- package/templates/skills/ec/gitlab/scripts/generate_agent_values.py +329 -0
- package/templates/skills/ec/gitlab/scripts/gitlab_agent_status.py +414 -0
- package/templates/skills/ec/jira/SKILL.md +484 -0
- package/templates/skills/ec/jira/references/jql_reference.md +148 -0
- package/templates/skills/ec/jira/scripts/add_comment.py +91 -0
- package/templates/skills/ec/jira/scripts/bulk_log_work.py +124 -0
- package/templates/skills/ec/jira/scripts/create_ticket.py +162 -0
- package/templates/skills/ec/jira/scripts/get_ticket.py +191 -0
- package/templates/skills/ec/jira/scripts/jira_client.py +383 -0
- package/templates/skills/ec/jira/scripts/log_work.py +154 -0
- package/templates/skills/ec/jira/scripts/search_tickets.py +104 -0
- package/templates/skills/ec/jira/scripts/update_comment.py +67 -0
- package/templates/skills/ec/jira/scripts/update_ticket.py +161 -0
- package/templates/skills/ec/karpenter/SKILL.md +301 -0
- package/templates/skills/ec/karpenter/references/ec2nodeclasses.md +421 -0
- package/templates/skills/ec/karpenter/references/migration.md +396 -0
- package/templates/skills/ec/karpenter/references/nodepools.md +400 -0
- package/templates/skills/ec/karpenter/references/troubleshooting.md +359 -0
- package/templates/skills/ec/karpenter/scripts/generate_ec2nodeclass.py +187 -0
- package/templates/skills/ec/karpenter/scripts/generate_nodepool.py +245 -0
- package/templates/skills/ec/karpenter/scripts/karpenter_status.py +359 -0
- package/templates/skills/ec/opensearch/SKILL.md +720 -0
- package/templates/skills/ec/opensearch/references/ml_neural_search.md +576 -0
- package/templates/skills/ec/opensearch/references/operator.md +532 -0
- package/templates/skills/ec/opensearch/references/query_dsl.md +532 -0
- package/templates/skills/ec/opensearch/scripts/configure_mcp.py +148 -0
- package/templates/skills/ec/victoriametrics/SKILL.md +598 -0
- package/templates/skills/ec/victoriametrics/references/kubernetes.md +531 -0
- package/templates/skills/ec/victoriametrics/references/prometheus_migration.md +333 -0
- package/templates/skills/ec/victoriametrics/references/troubleshooting.md +442 -0
- package/templates/skills/knowledge/SKILLS_CATALOG.md +274 -4
- package/templates/skills/knowledge/intelligent-routing/SKILL.md +237 -164
- package/templates/skills/knowledge/parallel-agents/SKILL.md +345 -73
- package/templates/skills/knowledge/plugin-discovery/SKILL.md +582 -0
- package/templates/skills/knowledge/plugin-discovery/scripts/platform_setup.py +1083 -0
- package/templates/skills/knowledge/design-md/README.md +0 -34
- package/templates/skills/knowledge/design-md/SKILL.md +0 -193
- package/templates/skills/knowledge/design-md/examples/DESIGN.md +0 -154
- package/templates/skills/knowledge/notebooklm-mcp/SKILL.md +0 -71
- package/templates/skills/knowledge/notebooklm-mcp/assets/example_asset.txt +0 -24
- package/templates/skills/knowledge/notebooklm-mcp/references/api_reference.md +0 -34
- package/templates/skills/knowledge/notebooklm-mcp/scripts/example.py +0 -19
- package/templates/skills/knowledge/react-components/README.md +0 -36
- package/templates/skills/knowledge/react-components/SKILL.md +0 -53
- package/templates/skills/knowledge/react-components/examples/gold-standard-card.tsx +0 -80
- package/templates/skills/knowledge/react-components/package-lock.json +0 -231
- package/templates/skills/knowledge/react-components/package.json +0 -16
- package/templates/skills/knowledge/react-components/resources/architecture-checklist.md +0 -15
- package/templates/skills/knowledge/react-components/resources/component-template.tsx +0 -37
- package/templates/skills/knowledge/react-components/resources/stitch-api-reference.md +0 -14
- package/templates/skills/knowledge/react-components/resources/style-guide.json +0 -27
- package/templates/skills/knowledge/react-components/scripts/fetch-stitch.sh +0 -30
- package/templates/skills/knowledge/react-components/scripts/validate.js +0 -68
- package/templates/skills/knowledge/self-update/SKILL.md +0 -60
- package/templates/skills/knowledge/self-update/scripts/update_kit.py +0 -103
- package/templates/skills/knowledge/stitch-loop/README.md +0 -54
- package/templates/skills/knowledge/stitch-loop/SKILL.md +0 -235
- package/templates/skills/knowledge/stitch-loop/examples/SITE.md +0 -73
- package/templates/skills/knowledge/stitch-loop/examples/next-prompt.md +0 -25
- package/templates/skills/knowledge/stitch-loop/resources/baton-schema.md +0 -61
- package/templates/skills/knowledge/stitch-loop/resources/site-template.md +0 -104
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Script: gitlab_agent_status.py
|
|
4
|
+
Purpose: Check GitLab agent health and generate status report
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python gitlab_agent_status.py --namespace gitlab-agent \
|
|
8
|
+
--gitlab-url https://gitlab.example.com \
|
|
9
|
+
--project-id 123 \
|
|
10
|
+
--output reports/gitlab/
|
|
11
|
+
|
|
12
|
+
Arguments:
|
|
13
|
+
--namespace, -n Kubernetes namespace (default: gitlab-agent)
|
|
14
|
+
--gitlab-url GitLab instance URL (or GITLAB_HOST env var)
|
|
15
|
+
--project-id GitLab project ID (or PROJECT_ID env var)
|
|
16
|
+
--agent-id Specific agent ID (optional, checks all if omitted)
|
|
17
|
+
--output, -o Output directory for reports (default: current)
|
|
18
|
+
--format, -f Output format: json, markdown, or both (default: both)
|
|
19
|
+
|
|
20
|
+
Exit Codes:
|
|
21
|
+
0 - Success, all agents healthy
|
|
22
|
+
1 - Invalid arguments
|
|
23
|
+
2 - Connection error
|
|
24
|
+
3 - Unhealthy agents detected
|
|
25
|
+
4 - Processing error
|
|
26
|
+
|
|
27
|
+
Environment Variables:
|
|
28
|
+
GITLAB_HOST - GitLab hostname
|
|
29
|
+
GITLAB_TOKEN - GitLab personal/project access token
|
|
30
|
+
PROJECT_ID - Default project ID
|
|
31
|
+
KUBECONFIG - Kubernetes config path
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
import argparse
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import subprocess
|
|
38
|
+
import sys
|
|
39
|
+
from datetime import datetime
|
|
40
|
+
from pathlib import Path
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def run_kubectl(args: list) -> tuple:
|
|
44
|
+
"""Run kubectl command and return (success, output)"""
|
|
45
|
+
try:
|
|
46
|
+
result = subprocess.run(
|
|
47
|
+
["kubectl"] + args,
|
|
48
|
+
capture_output=True,
|
|
49
|
+
text=True,
|
|
50
|
+
timeout=30
|
|
51
|
+
)
|
|
52
|
+
return result.returncode == 0, result.stdout.strip()
|
|
53
|
+
except subprocess.TimeoutExpired:
|
|
54
|
+
return False, "Command timed out"
|
|
55
|
+
except FileNotFoundError:
|
|
56
|
+
return False, "kubectl not found"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_agent_pods(namespace: str) -> dict:
|
|
60
|
+
"""Get agent pod status from Kubernetes"""
|
|
61
|
+
success, output = run_kubectl([
|
|
62
|
+
"get", "pods", "-n", namespace,
|
|
63
|
+
"-l", "app.kubernetes.io/name=gitlab-agent",
|
|
64
|
+
"-o", "json"
|
|
65
|
+
])
|
|
66
|
+
|
|
67
|
+
if not success:
|
|
68
|
+
return {"error": output, "pods": []}
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
data = json.loads(output)
|
|
72
|
+
pods = []
|
|
73
|
+
for item in data.get("items", []):
|
|
74
|
+
pod = {
|
|
75
|
+
"name": item["metadata"]["name"],
|
|
76
|
+
"status": item["status"]["phase"],
|
|
77
|
+
"ready": all(
|
|
78
|
+
c.get("ready", False)
|
|
79
|
+
for c in item["status"].get("containerStatuses", [])
|
|
80
|
+
),
|
|
81
|
+
"restarts": sum(
|
|
82
|
+
c.get("restartCount", 0)
|
|
83
|
+
for c in item["status"].get("containerStatuses", [])
|
|
84
|
+
),
|
|
85
|
+
"node": item["spec"].get("nodeName", "unknown"),
|
|
86
|
+
"image": item["spec"]["containers"][0]["image"] if item["spec"].get("containers") else "unknown"
|
|
87
|
+
}
|
|
88
|
+
pods.append(pod)
|
|
89
|
+
return {"error": None, "pods": pods}
|
|
90
|
+
except json.JSONDecodeError as e:
|
|
91
|
+
return {"error": f"JSON parse error: {e}", "pods": []}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_agent_logs(namespace: str, lines: int = 50) -> str:
|
|
95
|
+
"""Get recent agent logs"""
|
|
96
|
+
success, output = run_kubectl([
|
|
97
|
+
"logs", "-n", namespace,
|
|
98
|
+
"-l", "app.kubernetes.io/name=gitlab-agent",
|
|
99
|
+
"--tail", str(lines)
|
|
100
|
+
])
|
|
101
|
+
return output if success else f"Error getting logs: {output}"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_helm_status(namespace: str) -> dict:
|
|
105
|
+
"""Get Helm release status"""
|
|
106
|
+
try:
|
|
107
|
+
result = subprocess.run(
|
|
108
|
+
["helm", "list", "-n", namespace, "-o", "json"],
|
|
109
|
+
capture_output=True,
|
|
110
|
+
text=True,
|
|
111
|
+
timeout=30
|
|
112
|
+
)
|
|
113
|
+
if result.returncode != 0:
|
|
114
|
+
return {"error": result.stderr, "releases": []}
|
|
115
|
+
|
|
116
|
+
releases = json.loads(result.stdout)
|
|
117
|
+
return {"error": None, "releases": releases}
|
|
118
|
+
except Exception as e:
|
|
119
|
+
return {"error": str(e), "releases": []}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def get_gitlab_agents(gitlab_url: str, token: str, project_id: str) -> dict:
|
|
123
|
+
"""Get agents from GitLab API"""
|
|
124
|
+
import urllib.request
|
|
125
|
+
import ssl
|
|
126
|
+
|
|
127
|
+
url = f"{gitlab_url}/api/v4/projects/{project_id}/cluster_agents"
|
|
128
|
+
|
|
129
|
+
# Create request with token
|
|
130
|
+
req = urllib.request.Request(url)
|
|
131
|
+
req.add_header("PRIVATE-TOKEN", token)
|
|
132
|
+
|
|
133
|
+
# Allow self-signed certs (common in on-prem)
|
|
134
|
+
ctx = ssl.create_default_context()
|
|
135
|
+
ctx.check_hostname = False
|
|
136
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
with urllib.request.urlopen(req, context=ctx, timeout=30) as response:
|
|
140
|
+
data = json.loads(response.read().decode())
|
|
141
|
+
return {"error": None, "agents": data}
|
|
142
|
+
except urllib.error.HTTPError as e:
|
|
143
|
+
return {"error": f"HTTP {e.code}: {e.reason}", "agents": []}
|
|
144
|
+
except urllib.error.URLError as e:
|
|
145
|
+
return {"error": f"Connection error: {e.reason}", "agents": []}
|
|
146
|
+
except Exception as e:
|
|
147
|
+
return {"error": str(e), "agents": []}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_agent_tokens(gitlab_url: str, token: str, project_id: str, agent_id: int) -> dict:
|
|
151
|
+
"""Get tokens for an agent from GitLab API"""
|
|
152
|
+
import urllib.request
|
|
153
|
+
import ssl
|
|
154
|
+
|
|
155
|
+
url = f"{gitlab_url}/api/v4/projects/{project_id}/cluster_agents/{agent_id}/tokens"
|
|
156
|
+
|
|
157
|
+
req = urllib.request.Request(url)
|
|
158
|
+
req.add_header("PRIVATE-TOKEN", token)
|
|
159
|
+
|
|
160
|
+
ctx = ssl.create_default_context()
|
|
161
|
+
ctx.check_hostname = False
|
|
162
|
+
ctx.verify_mode = ssl.CERT_NONE
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
with urllib.request.urlopen(req, context=ctx, timeout=30) as response:
|
|
166
|
+
data = json.loads(response.read().decode())
|
|
167
|
+
return {"error": None, "tokens": data}
|
|
168
|
+
except Exception as e:
|
|
169
|
+
return {"error": str(e), "tokens": []}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def generate_report(data: dict, output_format: str, output_dir: str):
|
|
173
|
+
"""Generate status report in requested format(s)"""
|
|
174
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
175
|
+
output_path = Path(output_dir)
|
|
176
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
177
|
+
|
|
178
|
+
if output_format in ("json", "both"):
|
|
179
|
+
json_file = output_path / f"gitlab_agent_status_{timestamp}.json"
|
|
180
|
+
with open(json_file, "w") as f:
|
|
181
|
+
json.dump(data, f, indent=2, default=str)
|
|
182
|
+
print(f"JSON report: {json_file}")
|
|
183
|
+
|
|
184
|
+
if output_format in ("markdown", "both"):
|
|
185
|
+
md_file = output_path / f"gitlab_agent_status_{timestamp}.md"
|
|
186
|
+
md_content = generate_markdown(data)
|
|
187
|
+
with open(md_file, "w") as f:
|
|
188
|
+
f.write(md_content)
|
|
189
|
+
print(f"Markdown report: {md_file}")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def generate_markdown(data: dict) -> str:
|
|
193
|
+
"""Generate markdown report from data"""
|
|
194
|
+
lines = [
|
|
195
|
+
f"# GitLab Agent Status Report",
|
|
196
|
+
f"",
|
|
197
|
+
f"**Generated:** {data['timestamp']}",
|
|
198
|
+
f"**Environment:** {data['environment']}",
|
|
199
|
+
f"",
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
# Summary
|
|
203
|
+
healthy = data.get("healthy", False)
|
|
204
|
+
status_emoji = "✅" if healthy else "❌"
|
|
205
|
+
lines.append(f"## Summary: {status_emoji} {'Healthy' if healthy else 'Issues Detected'}")
|
|
206
|
+
lines.append("")
|
|
207
|
+
|
|
208
|
+
# Kubernetes Status
|
|
209
|
+
lines.append("## Kubernetes Status")
|
|
210
|
+
lines.append("")
|
|
211
|
+
k8s = data.get("kubernetes", {})
|
|
212
|
+
pods = k8s.get("pods", {}).get("pods", [])
|
|
213
|
+
|
|
214
|
+
if pods:
|
|
215
|
+
lines.append("| Pod | Status | Ready | Restarts | Node |")
|
|
216
|
+
lines.append("|-----|--------|-------|----------|------|")
|
|
217
|
+
for pod in pods:
|
|
218
|
+
ready = "✅" if pod["ready"] else "❌"
|
|
219
|
+
lines.append(f"| {pod['name']} | {pod['status']} | {ready} | {pod['restarts']} | {pod['node']} |")
|
|
220
|
+
else:
|
|
221
|
+
lines.append("No agent pods found.")
|
|
222
|
+
lines.append("")
|
|
223
|
+
|
|
224
|
+
# Helm Status
|
|
225
|
+
helm = k8s.get("helm", {}).get("releases", [])
|
|
226
|
+
if helm:
|
|
227
|
+
lines.append("### Helm Release")
|
|
228
|
+
lines.append("")
|
|
229
|
+
for release in helm:
|
|
230
|
+
lines.append(f"- **Name:** {release.get('name')}")
|
|
231
|
+
lines.append(f"- **Chart:** {release.get('chart')}")
|
|
232
|
+
lines.append(f"- **Status:** {release.get('status')}")
|
|
233
|
+
lines.append(f"- **Revision:** {release.get('revision')}")
|
|
234
|
+
lines.append("")
|
|
235
|
+
|
|
236
|
+
# GitLab API Status
|
|
237
|
+
lines.append("## GitLab API Status")
|
|
238
|
+
lines.append("")
|
|
239
|
+
gitlab = data.get("gitlab", {})
|
|
240
|
+
agents = gitlab.get("agents", {}).get("agents", [])
|
|
241
|
+
|
|
242
|
+
if agents:
|
|
243
|
+
lines.append("### Registered Agents")
|
|
244
|
+
lines.append("")
|
|
245
|
+
lines.append("| ID | Name | Created |")
|
|
246
|
+
lines.append("|----|------|---------|")
|
|
247
|
+
for agent in agents:
|
|
248
|
+
lines.append(f"| {agent['id']} | {agent['name']} | {agent.get('created_at', 'N/A')} |")
|
|
249
|
+
lines.append("")
|
|
250
|
+
|
|
251
|
+
# Tokens
|
|
252
|
+
tokens = gitlab.get("tokens", [])
|
|
253
|
+
if tokens:
|
|
254
|
+
lines.append("### Agent Tokens")
|
|
255
|
+
lines.append("")
|
|
256
|
+
lines.append("| Agent | Token ID | Name | Status | Created |")
|
|
257
|
+
lines.append("|-------|----------|------|--------|---------|")
|
|
258
|
+
for token_info in tokens:
|
|
259
|
+
for token in token_info.get("tokens", []):
|
|
260
|
+
lines.append(f"| {token_info['agent_id']} | {token['id']} | {token['name']} | {token['status']} | {token.get('created_at', 'N/A')} |")
|
|
261
|
+
else:
|
|
262
|
+
api_error = gitlab.get("agents", {}).get("error")
|
|
263
|
+
if api_error:
|
|
264
|
+
lines.append(f"**Error:** {api_error}")
|
|
265
|
+
else:
|
|
266
|
+
lines.append("No agents found.")
|
|
267
|
+
lines.append("")
|
|
268
|
+
|
|
269
|
+
# Issues
|
|
270
|
+
issues = data.get("issues", [])
|
|
271
|
+
if issues:
|
|
272
|
+
lines.append("## Issues Detected")
|
|
273
|
+
lines.append("")
|
|
274
|
+
for issue in issues:
|
|
275
|
+
lines.append(f"- ⚠️ {issue}")
|
|
276
|
+
lines.append("")
|
|
277
|
+
|
|
278
|
+
# Recent Logs
|
|
279
|
+
lines.append("## Recent Logs")
|
|
280
|
+
lines.append("")
|
|
281
|
+
lines.append("```")
|
|
282
|
+
logs = data.get("kubernetes", {}).get("logs", "No logs available")
|
|
283
|
+
lines.append(logs[-3000:] if len(logs) > 3000 else logs) # Limit log size
|
|
284
|
+
lines.append("```")
|
|
285
|
+
|
|
286
|
+
return "\n".join(lines)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def main():
|
|
290
|
+
parser = argparse.ArgumentParser(
|
|
291
|
+
description="Check GitLab agent health and generate status report",
|
|
292
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
293
|
+
epilog=__doc__
|
|
294
|
+
)
|
|
295
|
+
parser.add_argument(
|
|
296
|
+
"--namespace", "-n",
|
|
297
|
+
default="gitlab-agent",
|
|
298
|
+
help="Kubernetes namespace (default: gitlab-agent)"
|
|
299
|
+
)
|
|
300
|
+
parser.add_argument(
|
|
301
|
+
"--gitlab-url",
|
|
302
|
+
default=os.environ.get("GITLAB_HOST", ""),
|
|
303
|
+
help="GitLab instance URL"
|
|
304
|
+
)
|
|
305
|
+
parser.add_argument(
|
|
306
|
+
"--project-id",
|
|
307
|
+
default=os.environ.get("PROJECT_ID", ""),
|
|
308
|
+
help="GitLab project ID"
|
|
309
|
+
)
|
|
310
|
+
parser.add_argument(
|
|
311
|
+
"--agent-id",
|
|
312
|
+
help="Specific agent ID (optional)"
|
|
313
|
+
)
|
|
314
|
+
parser.add_argument(
|
|
315
|
+
"--output", "-o",
|
|
316
|
+
default=".",
|
|
317
|
+
help="Output directory (default: current)"
|
|
318
|
+
)
|
|
319
|
+
parser.add_argument(
|
|
320
|
+
"--format", "-f",
|
|
321
|
+
choices=["json", "markdown", "both"],
|
|
322
|
+
default="both",
|
|
323
|
+
help="Output format (default: both)"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
args = parser.parse_args()
|
|
327
|
+
|
|
328
|
+
# Get GitLab token from environment
|
|
329
|
+
gitlab_token = os.environ.get("GITLAB_TOKEN", "")
|
|
330
|
+
|
|
331
|
+
# Normalize GitLab URL
|
|
332
|
+
gitlab_url = args.gitlab_url
|
|
333
|
+
if gitlab_url and not gitlab_url.startswith("http"):
|
|
334
|
+
gitlab_url = f"https://{gitlab_url}"
|
|
335
|
+
|
|
336
|
+
# Collect data
|
|
337
|
+
data = {
|
|
338
|
+
"timestamp": datetime.now().isoformat(),
|
|
339
|
+
"environment": {
|
|
340
|
+
"namespace": args.namespace,
|
|
341
|
+
"gitlab_url": gitlab_url,
|
|
342
|
+
"project_id": args.project_id
|
|
343
|
+
},
|
|
344
|
+
"kubernetes": {},
|
|
345
|
+
"gitlab": {},
|
|
346
|
+
"issues": [],
|
|
347
|
+
"healthy": True
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
print(f"Checking GitLab agent status in namespace: {args.namespace}")
|
|
351
|
+
|
|
352
|
+
# Kubernetes checks
|
|
353
|
+
print(" - Checking pods...")
|
|
354
|
+
data["kubernetes"]["pods"] = get_agent_pods(args.namespace)
|
|
355
|
+
|
|
356
|
+
print(" - Checking Helm release...")
|
|
357
|
+
data["kubernetes"]["helm"] = get_helm_status(args.namespace)
|
|
358
|
+
|
|
359
|
+
print(" - Getting recent logs...")
|
|
360
|
+
data["kubernetes"]["logs"] = get_agent_logs(args.namespace)
|
|
361
|
+
|
|
362
|
+
# GitLab API checks (if configured)
|
|
363
|
+
if gitlab_url and gitlab_token and args.project_id:
|
|
364
|
+
print(f" - Checking GitLab API ({gitlab_url})...")
|
|
365
|
+
data["gitlab"]["agents"] = get_gitlab_agents(gitlab_url, gitlab_token, args.project_id)
|
|
366
|
+
|
|
367
|
+
# Get tokens for each agent
|
|
368
|
+
agents = data["gitlab"]["agents"].get("agents", [])
|
|
369
|
+
data["gitlab"]["tokens"] = []
|
|
370
|
+
for agent in agents:
|
|
371
|
+
token_data = get_agent_tokens(gitlab_url, gitlab_token, args.project_id, agent["id"])
|
|
372
|
+
token_data["agent_id"] = agent["id"]
|
|
373
|
+
data["gitlab"]["tokens"].append(token_data)
|
|
374
|
+
else:
|
|
375
|
+
print(" - Skipping GitLab API (missing URL, token, or project ID)")
|
|
376
|
+
|
|
377
|
+
# Analyze for issues
|
|
378
|
+
pods = data["kubernetes"]["pods"].get("pods", [])
|
|
379
|
+
if not pods:
|
|
380
|
+
data["issues"].append("No agent pods found in namespace")
|
|
381
|
+
data["healthy"] = False
|
|
382
|
+
else:
|
|
383
|
+
for pod in pods:
|
|
384
|
+
if pod["status"] != "Running":
|
|
385
|
+
data["issues"].append(f"Pod {pod['name']} is {pod['status']}")
|
|
386
|
+
data["healthy"] = False
|
|
387
|
+
if not pod["ready"]:
|
|
388
|
+
data["issues"].append(f"Pod {pod['name']} is not ready")
|
|
389
|
+
data["healthy"] = False
|
|
390
|
+
if pod["restarts"] > 5:
|
|
391
|
+
data["issues"].append(f"Pod {pod['name']} has {pod['restarts']} restarts")
|
|
392
|
+
|
|
393
|
+
# Check for errors in logs
|
|
394
|
+
logs = data["kubernetes"].get("logs", "")
|
|
395
|
+
if '"level":"error"' in logs or '"level":"warn"' in logs:
|
|
396
|
+
data["issues"].append("Errors or warnings found in agent logs")
|
|
397
|
+
|
|
398
|
+
# Generate report
|
|
399
|
+
generate_report(data, args.format, args.output)
|
|
400
|
+
|
|
401
|
+
# Print summary
|
|
402
|
+
print("")
|
|
403
|
+
if data["healthy"]:
|
|
404
|
+
print("✅ All agents healthy")
|
|
405
|
+
sys.exit(0)
|
|
406
|
+
else:
|
|
407
|
+
print("❌ Issues detected:")
|
|
408
|
+
for issue in data["issues"]:
|
|
409
|
+
print(f" - {issue}")
|
|
410
|
+
sys.exit(3)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
if __name__ == "__main__":
|
|
414
|
+
main()
|