checkdk-cli 0.2.6__tar.gz → 0.2.8__tar.gz
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.
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/PKG-INFO +1 -2
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/PKG-INFO +1 -2
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/requires.txt +0 -1
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/__init__.py +1 -1
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/init.py +2 -10
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/monitor.py +85 -81
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/pyproject.toml +1 -2
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/README.md +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/SOURCES.txt +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/dependency_links.txt +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/entry_points.txt +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/top_level.txt +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/client.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/__init__.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/auth.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/chaos.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/docker.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/kubectl.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/playground.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/predict.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/display.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/main.py +0 -0
- {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: checkdk-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
|
|
5
5
|
Author-email: checkDK Team <team@checkdk.app>
|
|
6
6
|
License: MIT
|
|
@@ -30,7 +30,6 @@ Requires-Dist: rich>=13.0.0
|
|
|
30
30
|
Requires-Dist: requests>=2.31.0
|
|
31
31
|
Requires-Dist: pyyaml>=6.0
|
|
32
32
|
Requires-Dist: python-dotenv>=1.0.0
|
|
33
|
-
Requires-Dist: websocket-client>=1.6.0
|
|
34
33
|
Provides-Extra: dev
|
|
35
34
|
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
36
35
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: checkdk-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor
|
|
5
5
|
Author-email: checkDK Team <team@checkdk.app>
|
|
6
6
|
License: MIT
|
|
@@ -30,7 +30,6 @@ Requires-Dist: rich>=13.0.0
|
|
|
30
30
|
Requires-Dist: requests>=2.31.0
|
|
31
31
|
Requires-Dist: pyyaml>=6.0
|
|
32
32
|
Requires-Dist: python-dotenv>=1.0.0
|
|
33
|
-
Requires-Dist: websocket-client>=1.6.0
|
|
34
33
|
Provides-Extra: dev
|
|
35
34
|
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
36
35
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
@@ -34,18 +34,10 @@ def init_cmd() -> None:
|
|
|
34
34
|
|
|
35
35
|
existing.append(f"CHECKDK_API_URL={api_url}")
|
|
36
36
|
|
|
37
|
-
default_ws = os.getenv("CHECKDK_WS_URL", "wss://m7fijvmhiq.us-east-1.awsapprunner.com")
|
|
38
|
-
ws_url = console.input(
|
|
39
|
-
f" WebSocket URL (for monitor) [[dim]{default_ws}[/]]: "
|
|
40
|
-
).strip() or default_ws
|
|
41
|
-
existing = [l for l in existing if not l.startswith("CHECKDK_WS_URL=")]
|
|
42
|
-
existing.append(f"CHECKDK_WS_URL={ws_url}")
|
|
43
|
-
|
|
44
37
|
env_path.write_text("\n".join(existing) + "\n")
|
|
45
38
|
|
|
46
39
|
console.print(
|
|
47
40
|
f"\n[bold green]✓ Saved to:[/] {env_path}\n"
|
|
48
|
-
f" [dim]CHECKDK_API_URL={api_url}[/]\n"
|
|
49
|
-
|
|
50
|
-
"Tip: You can also set these as shell environment variables."
|
|
41
|
+
f" [dim]CHECKDK_API_URL={api_url}[/]\n\n"
|
|
42
|
+
"Tip: You can also set this as a shell environment variable."
|
|
51
43
|
)
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
"""checkdk monitor - real-time container/pod health monitoring
|
|
1
|
+
"""checkdk monitor - real-time container/pod health monitoring via REST polling.
|
|
2
|
+
|
|
3
|
+
Polls the /predict endpoint on each interval instead of using a WebSocket
|
|
4
|
+
connection, which is blocked by the App Runner infrastructure layer.
|
|
5
|
+
"""
|
|
2
6
|
|
|
3
7
|
from __future__ import annotations
|
|
4
8
|
|
|
5
|
-
import json
|
|
6
9
|
import subprocess
|
|
7
10
|
import sys
|
|
8
11
|
import time
|
|
9
12
|
from typing import Optional
|
|
10
13
|
|
|
11
14
|
import click
|
|
15
|
+
import requests
|
|
12
16
|
from rich.console import Console
|
|
13
17
|
from rich.live import Live
|
|
14
18
|
from rich.table import Table
|
|
15
19
|
from rich.text import Text
|
|
16
20
|
|
|
17
|
-
from ..client import
|
|
21
|
+
from ..client import get_api_url
|
|
18
22
|
|
|
19
23
|
_console = Console()
|
|
20
24
|
|
|
@@ -25,6 +29,12 @@ def _risk_color(label: str) -> str:
|
|
|
25
29
|
)
|
|
26
30
|
|
|
27
31
|
|
|
32
|
+
def _level_color(level: str) -> str:
|
|
33
|
+
return {"low": "green", "medium": "yellow", "high": "red", "critical": "bold red"}.get(
|
|
34
|
+
level.lower(), "white"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
28
38
|
def _docker_stats(container: str) -> Optional[dict]:
|
|
29
39
|
"""Return one snapshot from docker stats --no-stream."""
|
|
30
40
|
try:
|
|
@@ -63,23 +73,59 @@ def _k8s_stats(pod: str, namespace: str) -> Optional[dict]:
|
|
|
63
73
|
return {"cpu": _pct(parts[1]), "memory": _pct(parts[2])}
|
|
64
74
|
|
|
65
75
|
|
|
76
|
+
def _predict(api_url: str, stats: dict, platform: str, service: str, no_ai: bool) -> Optional[dict]:
|
|
77
|
+
"""POST to /predict and return the prediction dict, or None on error."""
|
|
78
|
+
try:
|
|
79
|
+
resp = requests.post(
|
|
80
|
+
f"{api_url}/predict",
|
|
81
|
+
json={
|
|
82
|
+
"cpu": stats["cpu"],
|
|
83
|
+
"memory": stats["memory"],
|
|
84
|
+
"disk": 50.0,
|
|
85
|
+
"latency": 10.0,
|
|
86
|
+
"restarts": 0,
|
|
87
|
+
"probe_failures": 0,
|
|
88
|
+
"cpu_pressure": 0,
|
|
89
|
+
"mem_pressure": 0,
|
|
90
|
+
"age": 60,
|
|
91
|
+
"service": service,
|
|
92
|
+
"platform": platform,
|
|
93
|
+
"no_ai": no_ai,
|
|
94
|
+
},
|
|
95
|
+
timeout=15,
|
|
96
|
+
)
|
|
97
|
+
resp.raise_for_status()
|
|
98
|
+
data = resp.json()
|
|
99
|
+
pred = data.get("prediction", {})
|
|
100
|
+
return {
|
|
101
|
+
"label": pred.get("label", "unknown"),
|
|
102
|
+
"confidence": pred.get("confidence", 0.0),
|
|
103
|
+
"risk_level": pred.get("risk_level", "unknown"),
|
|
104
|
+
}
|
|
105
|
+
except Exception as exc:
|
|
106
|
+
_console.log(f"[dim red]Predict error: {exc}[/]")
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
66
110
|
def _build_table(history: list[dict]) -> Table:
|
|
67
111
|
t = Table(title="checkDK Real-Time Monitor", expand=True)
|
|
68
112
|
t.add_column("#", style="dim", width=4)
|
|
69
113
|
t.add_column("CPU %", style="cyan", width=8)
|
|
70
114
|
t.add_column("MEM %", style="cyan", width=8)
|
|
71
115
|
t.add_column("Risk Label", width=12)
|
|
116
|
+
t.add_column("Risk Level", width=12)
|
|
72
117
|
t.add_column("Confidence", width=12)
|
|
73
118
|
t.add_column("Time", style="dim")
|
|
74
119
|
for i, row in enumerate(history[-20:], 1):
|
|
75
120
|
label = row.get("label", "unknown")
|
|
121
|
+
level = row.get("risk_level", "unknown")
|
|
76
122
|
conf = row.get("confidence", 0.0)
|
|
77
|
-
col = _risk_color(label)
|
|
78
123
|
t.add_row(
|
|
79
124
|
str(i),
|
|
80
125
|
f"{row.get('cpu', 0):.1f}",
|
|
81
126
|
f"{row.get('mem', 0):.1f}",
|
|
82
|
-
Text(label, style=f"bold {
|
|
127
|
+
Text(label, style=f"bold {_risk_color(label)}"),
|
|
128
|
+
Text(level, style=_level_color(level)),
|
|
83
129
|
f"{conf:.2f}",
|
|
84
130
|
row.get("ts", ""),
|
|
85
131
|
)
|
|
@@ -97,37 +143,24 @@ def monitor_cmd() -> None:
|
|
|
97
143
|
help="Stop after N seconds (0 = run until Ctrl-C)")
|
|
98
144
|
@click.option("--interval", default=5, show_default=True, type=int,
|
|
99
145
|
help="Polling interval in seconds")
|
|
100
|
-
|
|
146
|
+
@click.option("--no-ai", is_flag=True, default=False,
|
|
147
|
+
help="Skip LLM analysis (faster, ML prediction only)")
|
|
148
|
+
def monitor_docker(container: str, duration: int, interval: int, no_ai: bool) -> None:
|
|
101
149
|
"""Stream live Docker container metrics and predict failure risk.
|
|
102
150
|
|
|
103
151
|
\b
|
|
104
152
|
Example:
|
|
105
153
|
checkdk monitor docker my-container
|
|
106
154
|
checkdk monitor docker api --duration 120 --interval 3
|
|
155
|
+
checkdk monitor docker api --no-ai
|
|
107
156
|
"""
|
|
108
|
-
|
|
109
|
-
import websocket # noqa: F401
|
|
110
|
-
except ImportError:
|
|
111
|
-
_console.print("[bold red]Missing dependency:[/] install websocket-client")
|
|
112
|
-
_console.print(" pip install websocket-client")
|
|
113
|
-
sys.exit(1)
|
|
114
|
-
|
|
115
|
-
import websocket as ws_lib
|
|
116
|
-
|
|
117
|
-
ws_url = get_ws_url() + "/ws/monitor"
|
|
157
|
+
api_url = get_api_url()
|
|
118
158
|
history: list[dict] = []
|
|
119
159
|
start = time.time()
|
|
120
160
|
|
|
121
|
-
_console.print(f"[bold]Monitoring container:[/] [cyan]{container}[/] [dim]{
|
|
161
|
+
_console.print(f"[bold]Monitoring container:[/] [cyan]{container}[/] [dim]{api_url}/predict[/]")
|
|
122
162
|
_console.print("[dim]Press Ctrl-C to stop.[/]\n")
|
|
123
163
|
|
|
124
|
-
try:
|
|
125
|
-
sock = ws_lib.create_connection(ws_url, timeout=10)
|
|
126
|
-
except Exception as exc:
|
|
127
|
-
_console.print(f"[bold red]Cannot connect to WebSocket:[/] {exc}")
|
|
128
|
-
_console.print("[yellow]Is the backend running with WebSocket support?[/]")
|
|
129
|
-
sys.exit(1)
|
|
130
|
-
|
|
131
164
|
try:
|
|
132
165
|
with Live(_build_table(history), refresh_per_second=1) as live:
|
|
133
166
|
while True:
|
|
@@ -137,29 +170,20 @@ def monitor_docker(container: str, duration: int, interval: int) -> None:
|
|
|
137
170
|
if stats is None:
|
|
138
171
|
time.sleep(interval)
|
|
139
172
|
continue
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
"cpu": stats["cpu"], "mem": stats["memory"],
|
|
152
|
-
"label": resp.get("label", "?"),
|
|
153
|
-
"confidence": resp.get("confidence", 0.0),
|
|
154
|
-
"ts": time.strftime("%H:%M:%S"),
|
|
155
|
-
})
|
|
156
|
-
live.update(_build_table(history))
|
|
173
|
+
pred = _predict(api_url, stats, platform="docker", service=container, no_ai=no_ai)
|
|
174
|
+
if pred:
|
|
175
|
+
history.append({
|
|
176
|
+
"cpu": stats["cpu"],
|
|
177
|
+
"mem": stats["memory"],
|
|
178
|
+
"label": pred["label"],
|
|
179
|
+
"risk_level": pred["risk_level"],
|
|
180
|
+
"confidence": pred["confidence"],
|
|
181
|
+
"ts": time.strftime("%H:%M:%S"),
|
|
182
|
+
})
|
|
183
|
+
live.update(_build_table(history))
|
|
157
184
|
time.sleep(interval)
|
|
158
185
|
except KeyboardInterrupt:
|
|
159
186
|
pass
|
|
160
|
-
finally:
|
|
161
|
-
try: sock.close()
|
|
162
|
-
except: pass
|
|
163
187
|
_console.print("\n[bold green]Monitor stopped.[/]")
|
|
164
188
|
|
|
165
189
|
|
|
@@ -168,35 +192,24 @@ def monitor_docker(container: str, duration: int, interval: int) -> None:
|
|
|
168
192
|
@click.option("--namespace", "-n", default="default", show_default=True)
|
|
169
193
|
@click.option("--duration", default=0, type=int, help="Stop after N seconds (0 = Ctrl-C)")
|
|
170
194
|
@click.option("--interval", default=5, show_default=True, type=int)
|
|
171
|
-
|
|
195
|
+
@click.option("--no-ai", is_flag=True, default=False,
|
|
196
|
+
help="Skip LLM analysis (faster, ML prediction only)")
|
|
197
|
+
def monitor_k8s(pod: str, namespace: str, duration: int, interval: int, no_ai: bool) -> None:
|
|
172
198
|
"""Stream live Kubernetes pod metrics and predict failure risk.
|
|
173
199
|
|
|
174
200
|
\b
|
|
175
201
|
Example:
|
|
176
202
|
checkdk monitor k8s my-pod -n production
|
|
177
203
|
checkdk monitor k8s api-pod --duration 120
|
|
204
|
+
checkdk monitor k8s api-pod --no-ai
|
|
178
205
|
"""
|
|
179
|
-
|
|
180
|
-
import websocket # noqa: F401
|
|
181
|
-
except ImportError:
|
|
182
|
-
_console.print("[bold red]Missing dependency:[/] install websocket-client")
|
|
183
|
-
sys.exit(1)
|
|
184
|
-
|
|
185
|
-
import websocket as ws_lib
|
|
186
|
-
|
|
187
|
-
ws_url = get_ws_url() + "/ws/monitor"
|
|
206
|
+
api_url = get_api_url()
|
|
188
207
|
history: list[dict] = []
|
|
189
208
|
start = time.time()
|
|
190
209
|
|
|
191
|
-
_console.print(f"[bold]Monitoring pod:[/] [cyan]{pod}[/] (ns: {namespace}) [dim]{
|
|
210
|
+
_console.print(f"[bold]Monitoring pod:[/] [cyan]{pod}[/] (ns: {namespace}) [dim]{api_url}/predict[/]")
|
|
192
211
|
_console.print("[dim]Press Ctrl-C to stop.[/]\n")
|
|
193
212
|
|
|
194
|
-
try:
|
|
195
|
-
sock = ws_lib.create_connection(ws_url, timeout=10)
|
|
196
|
-
except Exception as exc:
|
|
197
|
-
_console.print(f"[bold red]Cannot connect to WebSocket:[/] {exc}")
|
|
198
|
-
sys.exit(1)
|
|
199
|
-
|
|
200
213
|
try:
|
|
201
214
|
with Live(_build_table(history), refresh_per_second=1) as live:
|
|
202
215
|
while True:
|
|
@@ -206,27 +219,18 @@ def monitor_k8s(pod: str, namespace: str, duration: int, interval: int) -> None:
|
|
|
206
219
|
if stats is None:
|
|
207
220
|
time.sleep(interval)
|
|
208
221
|
continue
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"cpu": stats["cpu"], "mem": stats["memory"],
|
|
221
|
-
"label": resp.get("label", "?"),
|
|
222
|
-
"confidence": resp.get("confidence", 0.0),
|
|
223
|
-
"ts": time.strftime("%H:%M:%S"),
|
|
224
|
-
})
|
|
225
|
-
live.update(_build_table(history))
|
|
222
|
+
pred = _predict(api_url, stats, platform="kubernetes", service=pod, no_ai=no_ai)
|
|
223
|
+
if pred:
|
|
224
|
+
history.append({
|
|
225
|
+
"cpu": stats["cpu"],
|
|
226
|
+
"mem": stats["memory"],
|
|
227
|
+
"label": pred["label"],
|
|
228
|
+
"risk_level": pred["risk_level"],
|
|
229
|
+
"confidence": pred["confidence"],
|
|
230
|
+
"ts": time.strftime("%H:%M:%S"),
|
|
231
|
+
})
|
|
232
|
+
live.update(_build_table(history))
|
|
226
233
|
time.sleep(interval)
|
|
227
234
|
except KeyboardInterrupt:
|
|
228
235
|
pass
|
|
229
|
-
finally:
|
|
230
|
-
try: sock.close()
|
|
231
|
-
except: pass
|
|
232
236
|
_console.print("\n[bold green]Monitor stopped.[/]")
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "checkdk-cli"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "checkDK CLI – AI-powered Docker/Kubernetes issue detector and pod failure predictor"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -34,7 +34,6 @@ dependencies = [
|
|
|
34
34
|
"requests>=2.31.0",
|
|
35
35
|
"pyyaml>=6.0",
|
|
36
36
|
"python-dotenv>=1.0.0",
|
|
37
|
-
"websocket-client>=1.6.0",
|
|
38
37
|
]
|
|
39
38
|
|
|
40
39
|
[project.urls]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|