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.
Files changed (23) hide show
  1. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/PKG-INFO +1 -2
  2. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/PKG-INFO +1 -2
  3. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/requires.txt +0 -1
  4. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/__init__.py +1 -1
  5. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/init.py +2 -10
  6. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/monitor.py +85 -81
  7. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/pyproject.toml +1 -2
  8. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/README.md +0 -0
  9. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/SOURCES.txt +0 -0
  10. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/dependency_links.txt +0 -0
  11. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/entry_points.txt +0 -0
  12. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdk_cli.egg-info/top_level.txt +0 -0
  13. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/client.py +0 -0
  14. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/__init__.py +0 -0
  15. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/auth.py +0 -0
  16. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/chaos.py +0 -0
  17. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/docker.py +0 -0
  18. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/kubectl.py +0 -0
  19. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/playground.py +0 -0
  20. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/commands/predict.py +0 -0
  21. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/display.py +0 -0
  22. {checkdk_cli-0.2.6 → checkdk_cli-0.2.8}/checkdkcli/main.py +0 -0
  23. {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.6
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.6
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"
@@ -3,7 +3,6 @@ rich>=13.0.0
3
3
  requests>=2.31.0
4
4
  pyyaml>=6.0
5
5
  python-dotenv>=1.0.0
6
- websocket-client>=1.6.0
7
6
 
8
7
  [dev]
9
8
  pytest>=7.4.0
@@ -1,3 +1,3 @@
1
1
  """checkDK CLI package."""
2
2
 
3
- __version__ = "0.2.6"
3
+ __version__ = "0.2.8"
@@ -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
- f" [dim]CHECKDK_WS_URL={ws_url}[/]\n\n"
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 over WebSocket."""
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 get_ws_url
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 {col}"),
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
- def monitor_docker(container: str, duration: int, interval: int) -> None:
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
- try:
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]{ws_url}[/]")
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
- payload = {
141
- "cpu_usage": stats["cpu"], "memory_usage": stats["memory"],
142
- "disk_usage": 50.0, "network_latency": 0.0,
143
- "restart_count": 0, "probe_failures": 0,
144
- "cpu_pressure": 0, "memory_pressure": 0,
145
- "pod_age_minutes": 60,
146
- }
147
- sock.send(json.dumps(payload))
148
- raw = sock.recv()
149
- resp = json.loads(raw)
150
- history.append({
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
- def monitor_k8s(pod: str, namespace: str, duration: int, interval: int) -> None:
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
- try:
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]{ws_url}[/]")
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
- payload = {
210
- "cpu_usage": stats["cpu"], "memory_usage": stats["memory"],
211
- "disk_usage": 50.0, "network_latency": 0.0,
212
- "restart_count": 0, "probe_failures": 0,
213
- "cpu_pressure": 0, "memory_pressure": 0,
214
- "pod_age_minutes": 60,
215
- }
216
- sock.send(json.dumps(payload))
217
- raw = sock.recv()
218
- resp = json.loads(raw)
219
- history.append({
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.6"
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