checkdk-cli 0.2.5__tar.gz → 0.2.6__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.5 → checkdk_cli-0.2.6}/PKG-INFO +21 -45
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/README.md +20 -44
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/PKG-INFO +21 -45
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/__init__.py +1 -1
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/client.py +24 -2
- checkdk_cli-0.2.6/checkdkcli/commands/auth.py +181 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/init.py +12 -3
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/monitor.py +6 -7
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/pyproject.toml +1 -1
- checkdk_cli-0.2.5/checkdkcli/commands/auth.py +0 -110
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/SOURCES.txt +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/dependency_links.txt +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/entry_points.txt +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/requires.txt +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdk_cli.egg-info/top_level.txt +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/__init__.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/chaos.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/docker.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/kubectl.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/playground.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/commands/predict.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/display.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/checkdkcli/main.py +0 -0
- {checkdk_cli-0.2.5 → checkdk_cli-0.2.6}/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.6
|
|
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
|
|
@@ -50,29 +50,6 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
|
|
|
50
50
|
|
|
51
51
|
## Install
|
|
52
52
|
|
|
53
|
-
### npm (no Python required)
|
|
54
|
-
|
|
55
|
-
The easiest way to install for JavaScript / Node.js users.
|
|
56
|
-
Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
npm install -g @checkdk/cli
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Supported platforms:
|
|
63
|
-
|
|
64
|
-
| Platform | Package |
|
|
65
|
-
| --------------------------- | --------------------------- |
|
|
66
|
-
| Linux x64 | `@checkdk/cli-linux-x64` |
|
|
67
|
-
| Linux arm64 | `@checkdk/cli-linux-arm64` |
|
|
68
|
-
| macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
|
|
69
|
-
| macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
|
|
70
|
-
| Windows x64 | `@checkdk/cli-win32-x64` |
|
|
71
|
-
|
|
72
|
-
After install, `checkdk` is available on your PATH immediately.
|
|
73
|
-
|
|
74
|
-
### pip / pipx (Python required)
|
|
75
|
-
|
|
76
53
|
```bash
|
|
77
54
|
# Recommended — isolated install, checkdk on PATH globally
|
|
78
55
|
pipx install checkdk-cli
|
|
@@ -81,8 +58,6 @@ pipx install checkdk-cli
|
|
|
81
58
|
pip install checkdk-cli
|
|
82
59
|
```
|
|
83
60
|
|
|
84
|
-
Requires Python 3.10 or later.
|
|
85
|
-
|
|
86
61
|
The `checkdk` command is available immediately after install.
|
|
87
62
|
No configuration required — the CLI talks to `https://checkdk.app/api` by default.
|
|
88
63
|
|
|
@@ -132,21 +107,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
|
|
|
132
107
|
checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
|
|
133
108
|
```
|
|
134
109
|
|
|
135
|
-
| Option
|
|
136
|
-
|
|
137
|
-
| `--cpu`
|
|
138
|
-
| `--memory`
|
|
139
|
-
| `--disk`
|
|
140
|
-
| `--latency`
|
|
141
|
-
| `--restarts`
|
|
142
|
-
| `--probe-failures` | 0
|
|
143
|
-
| `--cpu-pressure`
|
|
144
|
-
| `--mem-pressure`
|
|
145
|
-
| `--age`
|
|
146
|
-
| `--service`
|
|
147
|
-
| `--platform`
|
|
148
|
-
| `--no-ai`
|
|
149
|
-
| `--json`
|
|
110
|
+
| Option | Default | Description |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `--cpu` | required | CPU usage % |
|
|
113
|
+
| `--memory` | required | Memory usage % |
|
|
114
|
+
| `--disk` | 50 | Disk usage % |
|
|
115
|
+
| `--latency` | 10 | Network latency ms |
|
|
116
|
+
| `--restarts` | 0 | Container restart count |
|
|
117
|
+
| `--probe-failures` | 0 | Liveness/readiness probe failures |
|
|
118
|
+
| `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
|
|
119
|
+
| `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
|
|
120
|
+
| `--age` | 60 | Pod age in minutes |
|
|
121
|
+
| `--service` | — | Service/pod name (label only) |
|
|
122
|
+
| `--platform` | docker | `docker` or `kubernetes` |
|
|
123
|
+
| `--no-ai` | — | Skip LLM, return ML result only |
|
|
124
|
+
| `--json` | — | Raw JSON output for scripting |
|
|
150
125
|
|
|
151
126
|
### Monitor (real-time)
|
|
152
127
|
|
|
@@ -177,10 +152,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
|
|
|
177
152
|
|
|
178
153
|
## Environment variables
|
|
179
154
|
|
|
180
|
-
| Variable
|
|
181
|
-
|
|
182
|
-
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL
|
|
183
|
-
| `CHECKDK_TOKEN`
|
|
155
|
+
| Variable | Default | Description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
|
|
158
|
+
| `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
|
|
184
159
|
|
|
185
160
|
The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
|
|
186
161
|
|
|
@@ -208,3 +183,4 @@ pytest
|
|
|
208
183
|
# Lint
|
|
209
184
|
ruff check .
|
|
210
185
|
```
|
|
186
|
+
|
|
@@ -12,29 +12,6 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
|
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
15
|
-
### npm (no Python required)
|
|
16
|
-
|
|
17
|
-
The easiest way to install for JavaScript / Node.js users.
|
|
18
|
-
Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install -g @checkdk/cli
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Supported platforms:
|
|
25
|
-
|
|
26
|
-
| Platform | Package |
|
|
27
|
-
| --------------------------- | --------------------------- |
|
|
28
|
-
| Linux x64 | `@checkdk/cli-linux-x64` |
|
|
29
|
-
| Linux arm64 | `@checkdk/cli-linux-arm64` |
|
|
30
|
-
| macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
|
|
31
|
-
| macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
|
|
32
|
-
| Windows x64 | `@checkdk/cli-win32-x64` |
|
|
33
|
-
|
|
34
|
-
After install, `checkdk` is available on your PATH immediately.
|
|
35
|
-
|
|
36
|
-
### pip / pipx (Python required)
|
|
37
|
-
|
|
38
15
|
```bash
|
|
39
16
|
# Recommended — isolated install, checkdk on PATH globally
|
|
40
17
|
pipx install checkdk-cli
|
|
@@ -43,8 +20,6 @@ pipx install checkdk-cli
|
|
|
43
20
|
pip install checkdk-cli
|
|
44
21
|
```
|
|
45
22
|
|
|
46
|
-
Requires Python 3.10 or later.
|
|
47
|
-
|
|
48
23
|
The `checkdk` command is available immediately after install.
|
|
49
24
|
No configuration required — the CLI talks to `https://checkdk.app/api` by default.
|
|
50
25
|
|
|
@@ -94,21 +69,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
|
|
|
94
69
|
checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
|
|
95
70
|
```
|
|
96
71
|
|
|
97
|
-
| Option
|
|
98
|
-
|
|
99
|
-
| `--cpu`
|
|
100
|
-
| `--memory`
|
|
101
|
-
| `--disk`
|
|
102
|
-
| `--latency`
|
|
103
|
-
| `--restarts`
|
|
104
|
-
| `--probe-failures` | 0
|
|
105
|
-
| `--cpu-pressure`
|
|
106
|
-
| `--mem-pressure`
|
|
107
|
-
| `--age`
|
|
108
|
-
| `--service`
|
|
109
|
-
| `--platform`
|
|
110
|
-
| `--no-ai`
|
|
111
|
-
| `--json`
|
|
72
|
+
| Option | Default | Description |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `--cpu` | required | CPU usage % |
|
|
75
|
+
| `--memory` | required | Memory usage % |
|
|
76
|
+
| `--disk` | 50 | Disk usage % |
|
|
77
|
+
| `--latency` | 10 | Network latency ms |
|
|
78
|
+
| `--restarts` | 0 | Container restart count |
|
|
79
|
+
| `--probe-failures` | 0 | Liveness/readiness probe failures |
|
|
80
|
+
| `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
|
|
81
|
+
| `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
|
|
82
|
+
| `--age` | 60 | Pod age in minutes |
|
|
83
|
+
| `--service` | — | Service/pod name (label only) |
|
|
84
|
+
| `--platform` | docker | `docker` or `kubernetes` |
|
|
85
|
+
| `--no-ai` | — | Skip LLM, return ML result only |
|
|
86
|
+
| `--json` | — | Raw JSON output for scripting |
|
|
112
87
|
|
|
113
88
|
### Monitor (real-time)
|
|
114
89
|
|
|
@@ -139,10 +114,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
|
|
|
139
114
|
|
|
140
115
|
## Environment variables
|
|
141
116
|
|
|
142
|
-
| Variable
|
|
143
|
-
|
|
144
|
-
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL
|
|
145
|
-
| `CHECKDK_TOKEN`
|
|
117
|
+
| Variable | Default | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
|
|
120
|
+
| `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
|
|
146
121
|
|
|
147
122
|
The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
|
|
148
123
|
|
|
@@ -170,3 +145,4 @@ pytest
|
|
|
170
145
|
# Lint
|
|
171
146
|
ruff check .
|
|
172
147
|
```
|
|
148
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: checkdk-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
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
|
|
@@ -50,29 +50,6 @@ dependencies — it is a thin HTTP/WebSocket client with a rich terminal UI.
|
|
|
50
50
|
|
|
51
51
|
## Install
|
|
52
52
|
|
|
53
|
-
### npm (no Python required)
|
|
54
|
-
|
|
55
|
-
The easiest way to install for JavaScript / Node.js users.
|
|
56
|
-
Pre-compiled standalone binaries are distributed per-platform — nothing else needs to be installed.
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
npm install -g @checkdk/cli
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Supported platforms:
|
|
63
|
-
|
|
64
|
-
| Platform | Package |
|
|
65
|
-
| --------------------------- | --------------------------- |
|
|
66
|
-
| Linux x64 | `@checkdk/cli-linux-x64` |
|
|
67
|
-
| Linux arm64 | `@checkdk/cli-linux-arm64` |
|
|
68
|
-
| macOS x64 (Intel) | `@checkdk/cli-darwin-x64` |
|
|
69
|
-
| macOS arm64 (Apple Silicon) | `@checkdk/cli-darwin-arm64` |
|
|
70
|
-
| Windows x64 | `@checkdk/cli-win32-x64` |
|
|
71
|
-
|
|
72
|
-
After install, `checkdk` is available on your PATH immediately.
|
|
73
|
-
|
|
74
|
-
### pip / pipx (Python required)
|
|
75
|
-
|
|
76
53
|
```bash
|
|
77
54
|
# Recommended — isolated install, checkdk on PATH globally
|
|
78
55
|
pipx install checkdk-cli
|
|
@@ -81,8 +58,6 @@ pipx install checkdk-cli
|
|
|
81
58
|
pip install checkdk-cli
|
|
82
59
|
```
|
|
83
60
|
|
|
84
|
-
Requires Python 3.10 or later.
|
|
85
|
-
|
|
86
61
|
The `checkdk` command is available immediately after install.
|
|
87
62
|
No configuration required — the CLI talks to `https://checkdk.app/api` by default.
|
|
88
63
|
|
|
@@ -132,21 +107,21 @@ checkdk predict --cpu 93 --memory 91 --restarts 3 \
|
|
|
132
107
|
checkdk predict --cpu 85 --memory 70 --json # CI/scripting output
|
|
133
108
|
```
|
|
134
109
|
|
|
135
|
-
| Option
|
|
136
|
-
|
|
137
|
-
| `--cpu`
|
|
138
|
-
| `--memory`
|
|
139
|
-
| `--disk`
|
|
140
|
-
| `--latency`
|
|
141
|
-
| `--restarts`
|
|
142
|
-
| `--probe-failures` | 0
|
|
143
|
-
| `--cpu-pressure`
|
|
144
|
-
| `--mem-pressure`
|
|
145
|
-
| `--age`
|
|
146
|
-
| `--service`
|
|
147
|
-
| `--platform`
|
|
148
|
-
| `--no-ai`
|
|
149
|
-
| `--json`
|
|
110
|
+
| Option | Default | Description |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `--cpu` | required | CPU usage % |
|
|
113
|
+
| `--memory` | required | Memory usage % |
|
|
114
|
+
| `--disk` | 50 | Disk usage % |
|
|
115
|
+
| `--latency` | 10 | Network latency ms |
|
|
116
|
+
| `--restarts` | 0 | Container restart count |
|
|
117
|
+
| `--probe-failures` | 0 | Liveness/readiness probe failures |
|
|
118
|
+
| `--cpu-pressure` | 0 | Node CPU pressure (0 or 1) |
|
|
119
|
+
| `--mem-pressure` | 0 | Node memory pressure (0 or 1) |
|
|
120
|
+
| `--age` | 60 | Pod age in minutes |
|
|
121
|
+
| `--service` | — | Service/pod name (label only) |
|
|
122
|
+
| `--platform` | docker | `docker` or `kubernetes` |
|
|
123
|
+
| `--no-ai` | — | Skip LLM, return ML result only |
|
|
124
|
+
| `--json` | — | Raw JSON output for scripting |
|
|
150
125
|
|
|
151
126
|
### Monitor (real-time)
|
|
152
127
|
|
|
@@ -177,10 +152,10 @@ Experiments: `cpu`, `memory`, `disk`, `network`, `pod-kill` (k8s only).
|
|
|
177
152
|
|
|
178
153
|
## Environment variables
|
|
179
154
|
|
|
180
|
-
| Variable
|
|
181
|
-
|
|
182
|
-
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL
|
|
183
|
-
| `CHECKDK_TOKEN`
|
|
155
|
+
| Variable | Default | Description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `CHECKDK_API_URL` | `https://checkdk.app/api` | Backend API base URL |
|
|
158
|
+
| `CHECKDK_TOKEN` | — | JWT auth token (set by `checkdk auth login`) |
|
|
184
159
|
|
|
185
160
|
The CLI auto-loads `~/.checkdk/.env` and `./.env` on startup.
|
|
186
161
|
|
|
@@ -208,3 +183,4 @@ pytest
|
|
|
208
183
|
# Lint
|
|
209
184
|
ruff check .
|
|
210
185
|
```
|
|
186
|
+
|
|
@@ -21,13 +21,35 @@ def get_api_url() -> str:
|
|
|
21
21
|
Priority:
|
|
22
22
|
1. $CHECKDK_API_URL environment variable
|
|
23
23
|
2. ~/.checkdk/.env (loaded by python-dotenv at startup)
|
|
24
|
-
3. Fallback to https://checkdk.app/api (production)
|
|
25
|
-
CHECKDK_API_URL=http://localhost:8000 for local dev
|
|
24
|
+
3. Fallback to https://checkdk.app/api (production)
|
|
26
25
|
"""
|
|
27
26
|
url = os.getenv("CHECKDK_API_URL", "https://checkdk.app/api").strip().rstrip("/")
|
|
28
27
|
return url
|
|
29
28
|
|
|
30
29
|
|
|
30
|
+
def get_ws_url() -> str:
|
|
31
|
+
"""Return the WebSocket base URL for real-time monitoring.
|
|
32
|
+
|
|
33
|
+
CloudFront does not support WebSocket upgrades on the free plan, so the
|
|
34
|
+
WebSocket connection goes directly to App Runner instead of via checkdk.app.
|
|
35
|
+
|
|
36
|
+
Priority:
|
|
37
|
+
1. $CHECKDK_WS_URL environment variable
|
|
38
|
+
2. ~/.checkdk/.env (CHECKDK_WS_URL=...)
|
|
39
|
+
3. Fallback to the App Runner service URL (wss://)
|
|
40
|
+
"""
|
|
41
|
+
stored = os.getenv("CHECKDK_WS_URL")
|
|
42
|
+
if stored:
|
|
43
|
+
return stored.strip().rstrip("/")
|
|
44
|
+
env_file = Path.home() / ".checkdk" / ".env"
|
|
45
|
+
if env_file.exists():
|
|
46
|
+
for line in env_file.read_text().splitlines():
|
|
47
|
+
if line.startswith("CHECKDK_WS_URL="):
|
|
48
|
+
return line.split("=", 1)[1].strip().strip('"').strip("'")
|
|
49
|
+
# Direct App Runner URL — bypasses CloudFront which blocks WebSocket
|
|
50
|
+
return "wss://m7fijvmhiq.us-east-1.awsapprunner.com"
|
|
51
|
+
|
|
52
|
+
|
|
31
53
|
def get_stored_token() -> Optional[str]:
|
|
32
54
|
"""Read a stored JWT from ~/.checkdk/.env, if present."""
|
|
33
55
|
token = os.getenv("CHECKDK_TOKEN")
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""checkdk auth commands - login, logout, whoami."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import socket
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
import time
|
|
10
|
+
import urllib.parse
|
|
11
|
+
import webbrowser
|
|
12
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import click
|
|
16
|
+
from rich.console import Console
|
|
17
|
+
from rich.panel import Panel
|
|
18
|
+
from rich.table import Table
|
|
19
|
+
|
|
20
|
+
from ..client import get_api_url, get_current_user, validate_token
|
|
21
|
+
|
|
22
|
+
_console = Console()
|
|
23
|
+
_ENV_FILE = Path.home() / ".checkdk" / ".env"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _save_token(token: str) -> None:
|
|
27
|
+
_ENV_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
lines = _ENV_FILE.read_text().splitlines() if _ENV_FILE.exists() else []
|
|
29
|
+
lines = [l for l in lines if not l.startswith("CHECKDK_TOKEN=")]
|
|
30
|
+
lines.append(f"CHECKDK_TOKEN={token}")
|
|
31
|
+
_ENV_FILE.write_text("\n".join(lines) + "\n")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _remove_token() -> None:
|
|
35
|
+
if not _ENV_FILE.exists():
|
|
36
|
+
return
|
|
37
|
+
lines = [l for l in _ENV_FILE.read_text().splitlines()
|
|
38
|
+
if not l.startswith("CHECKDK_TOKEN=")]
|
|
39
|
+
_ENV_FILE.write_text("\n".join(lines) + "\n")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _find_free_port() -> int:
|
|
43
|
+
"""Return an available localhost port."""
|
|
44
|
+
with socket.socket() as s:
|
|
45
|
+
s.bind(("127.0.0.1", 0))
|
|
46
|
+
return s.getsockname()[1]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _wait_for_token(port: int, timeout: int = 120) -> "str | None":
|
|
50
|
+
"""Start a temporary HTTP server on localhost and wait for the OAuth callback."""
|
|
51
|
+
received: dict = {"token": None}
|
|
52
|
+
server_ready = threading.Event()
|
|
53
|
+
|
|
54
|
+
class _Handler(BaseHTTPRequestHandler):
|
|
55
|
+
def do_GET(self) -> None:
|
|
56
|
+
parsed = urllib.parse.urlparse(self.path)
|
|
57
|
+
params = urllib.parse.parse_qs(parsed.query)
|
|
58
|
+
token = (params.get("token") or [None])[0]
|
|
59
|
+
received["token"] = token
|
|
60
|
+
|
|
61
|
+
if token:
|
|
62
|
+
body = (
|
|
63
|
+
b"<html><body style=\"font-family:sans-serif;text-align:center;"
|
|
64
|
+
b"margin-top:10vh;background:#0f172a;color:#e2e8f0\">"
|
|
65
|
+
b"<h2 style=\"color:#818cf8\">checkDK CLI</h2>"
|
|
66
|
+
b"<p style=\"font-size:1.2rem\">You\'re logged in!"
|
|
67
|
+
b" You can close this tab.</p></body></html>"
|
|
68
|
+
)
|
|
69
|
+
else:
|
|
70
|
+
body = b"<html><body>Authentication failed. Please try again.</body></html>"
|
|
71
|
+
|
|
72
|
+
self.send_response(200)
|
|
73
|
+
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
74
|
+
self.send_header("Content-Length", str(len(body)))
|
|
75
|
+
self.end_headers()
|
|
76
|
+
self.wfile.write(body)
|
|
77
|
+
|
|
78
|
+
def log_message(self, *_) -> None:
|
|
79
|
+
pass # silence access logs
|
|
80
|
+
|
|
81
|
+
httpd = HTTPServer(("127.0.0.1", port), _Handler)
|
|
82
|
+
httpd.timeout = 1 # poll interval
|
|
83
|
+
|
|
84
|
+
def _serve() -> None:
|
|
85
|
+
server_ready.set()
|
|
86
|
+
deadline = time.time() + timeout
|
|
87
|
+
while received["token"] is None and time.time() < deadline:
|
|
88
|
+
httpd.handle_request()
|
|
89
|
+
httpd.server_close()
|
|
90
|
+
|
|
91
|
+
t = threading.Thread(target=_serve, daemon=True)
|
|
92
|
+
t.start()
|
|
93
|
+
server_ready.wait()
|
|
94
|
+
t.join(timeout + 2)
|
|
95
|
+
return received["token"]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@click.group("auth")
|
|
99
|
+
def auth_cmd() -> None:
|
|
100
|
+
"""Authentication - log in, log out, or check who you are."""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@auth_cmd.command("login")
|
|
104
|
+
def login_cmd() -> None:
|
|
105
|
+
"""Log in to checkDK via GitHub or Google OAuth.
|
|
106
|
+
|
|
107
|
+
Starts a local callback server, opens the sign-in page in your browser,
|
|
108
|
+
and receives the token automatically - no copy-pasting required.
|
|
109
|
+
"""
|
|
110
|
+
port = _find_free_port()
|
|
111
|
+
callback_url = f"http://127.0.0.1:{port}/callback"
|
|
112
|
+
|
|
113
|
+
api = get_api_url()
|
|
114
|
+
base = api[: api.rindex("/api")] if "/api" in api else "https://checkdk.app"
|
|
115
|
+
encoded_cb = urllib.parse.quote(callback_url, safe="")
|
|
116
|
+
login_url = f"{base}/login?cli_callback={encoded_cb}"
|
|
117
|
+
|
|
118
|
+
_console.print("\n[bold]Opening browser for sign-in...[/]")
|
|
119
|
+
_console.print(
|
|
120
|
+
" [dim]If the browser did not open, visit:[/]\n"
|
|
121
|
+
f" [cyan]{login_url}[/]\n"
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
webbrowser.open(login_url)
|
|
126
|
+
except Exception:
|
|
127
|
+
_console.print(f"[yellow]Open this URL in your browser:[/] [cyan]{login_url}[/]\n")
|
|
128
|
+
|
|
129
|
+
with _console.status("[bold cyan]Waiting for authentication (2-min timeout)...[/]"):
|
|
130
|
+
token = _wait_for_token(port, timeout=120)
|
|
131
|
+
|
|
132
|
+
if not token:
|
|
133
|
+
_console.print("[bold red]Login timed out or was cancelled.[/]")
|
|
134
|
+
sys.exit(1)
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
user = validate_token(token)
|
|
138
|
+
except Exception as exc:
|
|
139
|
+
_console.print(f"[bold red]Token validation failed:[/] {exc}")
|
|
140
|
+
sys.exit(1)
|
|
141
|
+
|
|
142
|
+
_save_token(token)
|
|
143
|
+
os.environ["CHECKDK_TOKEN"] = token
|
|
144
|
+
|
|
145
|
+
_console.print(Panel(
|
|
146
|
+
f"[bold green]Logged in successfully![/]\n\n"
|
|
147
|
+
f" Name: {user.get('name', '?')}\n"
|
|
148
|
+
f" Email: {user.get('email', '?')}\n"
|
|
149
|
+
f" Provider: {user.get('provider', '?')}\n\n"
|
|
150
|
+
f"[dim]Token saved to {_ENV_FILE}[/]",
|
|
151
|
+
border_style="green",
|
|
152
|
+
))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@auth_cmd.command("logout")
|
|
156
|
+
def logout_cmd() -> None:
|
|
157
|
+
"""Remove the stored JWT token."""
|
|
158
|
+
_remove_token()
|
|
159
|
+
if "CHECKDK_TOKEN" in os.environ:
|
|
160
|
+
del os.environ["CHECKDK_TOKEN"]
|
|
161
|
+
_console.print("[bold green]Logged out.[/] Token removed from local config.")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@auth_cmd.command("whoami")
|
|
165
|
+
def whoami_cmd() -> None:
|
|
166
|
+
"""Show the currently logged-in user."""
|
|
167
|
+
try:
|
|
168
|
+
user = get_current_user()
|
|
169
|
+
except Exception as exc:
|
|
170
|
+
_console.print(f"[bold red]Not logged in or API unreachable:[/] {exc}")
|
|
171
|
+
_console.print("[dim]Run [bold]checkdk auth login[/] first.[/]")
|
|
172
|
+
sys.exit(1)
|
|
173
|
+
|
|
174
|
+
t = Table.grid(padding=(0, 2))
|
|
175
|
+
t.add_column(style="bold cyan")
|
|
176
|
+
t.add_column()
|
|
177
|
+
t.add_row("Name:", user.get("name", "?"))
|
|
178
|
+
t.add_row("Email:", user.get("email", "?"))
|
|
179
|
+
t.add_row("Provider:", user.get("provider", "?"))
|
|
180
|
+
t.add_row("User ID:", user.get("userId", "?"))
|
|
181
|
+
_console.print(Panel(t, title="Current User", border_style="cyan"))
|
|
@@ -16,7 +16,7 @@ def init_cmd() -> None:
|
|
|
16
16
|
"""Configure checkDK CLI (set API URL, API keys, etc.)."""
|
|
17
17
|
console.print("[bold]checkDK CLI configuration[/]\n")
|
|
18
18
|
|
|
19
|
-
default_url = os.getenv("CHECKDK_API_URL", "
|
|
19
|
+
default_url = os.getenv("CHECKDK_API_URL", "https://checkdk.app/api")
|
|
20
20
|
api_url = console.input(
|
|
21
21
|
f" Backend API URL [[dim]{default_url}[/]]: "
|
|
22
22
|
).strip() or default_url
|
|
@@ -33,10 +33,19 @@ def init_cmd() -> None:
|
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
existing.append(f"CHECKDK_API_URL={api_url}")
|
|
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
|
+
|
|
36
44
|
env_path.write_text("\n".join(existing) + "\n")
|
|
37
45
|
|
|
38
46
|
console.print(
|
|
39
47
|
f"\n[bold green]✓ Saved to:[/] {env_path}\n"
|
|
40
|
-
f" [dim]CHECKDK_API_URL={api_url}[/]\n
|
|
41
|
-
"
|
|
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."
|
|
42
51
|
)
|
|
@@ -14,6 +14,8 @@ from rich.live import Live
|
|
|
14
14
|
from rich.table import Table
|
|
15
15
|
from rich.text import Text
|
|
16
16
|
|
|
17
|
+
from ..client import get_ws_url
|
|
18
|
+
|
|
17
19
|
_console = Console()
|
|
18
20
|
|
|
19
21
|
|
|
@@ -95,9 +97,7 @@ def monitor_cmd() -> None:
|
|
|
95
97
|
help="Stop after N seconds (0 = run until Ctrl-C)")
|
|
96
98
|
@click.option("--interval", default=5, show_default=True, type=int,
|
|
97
99
|
help="Polling interval in seconds")
|
|
98
|
-
|
|
99
|
-
help="Backend base URL")
|
|
100
|
-
def monitor_docker(container: str, duration: int, interval: int, api_url: str) -> None:
|
|
100
|
+
def monitor_docker(container: str, duration: int, interval: int) -> None:
|
|
101
101
|
"""Stream live Docker container metrics and predict failure risk.
|
|
102
102
|
|
|
103
103
|
\b
|
|
@@ -114,7 +114,7 @@ def monitor_docker(container: str, duration: int, interval: int, api_url: str) -
|
|
|
114
114
|
|
|
115
115
|
import websocket as ws_lib
|
|
116
116
|
|
|
117
|
-
ws_url =
|
|
117
|
+
ws_url = get_ws_url() + "/ws/monitor"
|
|
118
118
|
history: list[dict] = []
|
|
119
119
|
start = time.time()
|
|
120
120
|
|
|
@@ -168,8 +168,7 @@ def monitor_docker(container: str, duration: int, interval: int, api_url: str) -
|
|
|
168
168
|
@click.option("--namespace", "-n", default="default", show_default=True)
|
|
169
169
|
@click.option("--duration", default=0, type=int, help="Stop after N seconds (0 = Ctrl-C)")
|
|
170
170
|
@click.option("--interval", default=5, show_default=True, type=int)
|
|
171
|
-
|
|
172
|
-
def monitor_k8s(pod: str, namespace: str, duration: int, interval: int, api_url: str) -> None:
|
|
171
|
+
def monitor_k8s(pod: str, namespace: str, duration: int, interval: int) -> None:
|
|
173
172
|
"""Stream live Kubernetes pod metrics and predict failure risk.
|
|
174
173
|
|
|
175
174
|
\b
|
|
@@ -185,7 +184,7 @@ def monitor_k8s(pod: str, namespace: str, duration: int, interval: int, api_url:
|
|
|
185
184
|
|
|
186
185
|
import websocket as ws_lib
|
|
187
186
|
|
|
188
|
-
ws_url =
|
|
187
|
+
ws_url = get_ws_url() + "/ws/monitor"
|
|
189
188
|
history: list[dict] = []
|
|
190
189
|
start = time.time()
|
|
191
190
|
|
|
@@ -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.6"
|
|
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"
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"""checkdk auth commands - login, logout, whoami."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
|
-
import webbrowser
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
|
|
10
|
-
import click
|
|
11
|
-
from rich.console import Console
|
|
12
|
-
from rich.panel import Panel
|
|
13
|
-
from rich.table import Table
|
|
14
|
-
|
|
15
|
-
from ..client import get_api_url, get_current_user, validate_token
|
|
16
|
-
|
|
17
|
-
_console = Console()
|
|
18
|
-
_ENV_FILE = Path.home() / ".checkdk" / ".env"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _save_token(token: str) -> None:
|
|
22
|
-
_ENV_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
23
|
-
lines = _ENV_FILE.read_text().splitlines() if _ENV_FILE.exists() else []
|
|
24
|
-
lines = [l for l in lines if not l.startswith("CHECKDK_TOKEN=")]
|
|
25
|
-
lines.append(f"CHECKDK_TOKEN={token}")
|
|
26
|
-
_ENV_FILE.write_text("\n".join(lines) + "\n")
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def _remove_token() -> None:
|
|
30
|
-
if not _ENV_FILE.exists():
|
|
31
|
-
return
|
|
32
|
-
lines = [l for l in _ENV_FILE.read_text().splitlines()
|
|
33
|
-
if not l.startswith("CHECKDK_TOKEN=")]
|
|
34
|
-
_ENV_FILE.write_text("\n".join(lines) + "\n")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@click.group("auth")
|
|
38
|
-
def auth_cmd() -> None:
|
|
39
|
-
"""Authentication - log in, log out, or check who you are."""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@auth_cmd.command("login")
|
|
43
|
-
def login_cmd() -> None:
|
|
44
|
-
"""Log in to checkDK via GitHub or Google OAuth.
|
|
45
|
-
|
|
46
|
-
Opens the sign-in page in your browser, then prompts you to paste
|
|
47
|
-
the JWT token shown after a successful login.
|
|
48
|
-
"""
|
|
49
|
-
login_url = f"{get_api_url().replace('/api', '')}/login" if "/api" in get_api_url() else "https://checkdk.app/login"
|
|
50
|
-
_console.print(f"\n[bold]Opening sign-in page:[/] [cyan]{login_url}[/]")
|
|
51
|
-
_console.print("[dim]Sign in with GitHub or Google, then copy the token from the page.[/]\n")
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
webbrowser.open(login_url)
|
|
55
|
-
except Exception:
|
|
56
|
-
_console.print("[yellow]Could not open browser automatically.[/]")
|
|
57
|
-
_console.print(f"Please visit: [cyan]{login_url}[/]\n")
|
|
58
|
-
|
|
59
|
-
token = _console.input("[bold]Paste your JWT token here:[/] ").strip()
|
|
60
|
-
if not token:
|
|
61
|
-
_console.print("[red]No token provided. Login cancelled.[/]")
|
|
62
|
-
sys.exit(1)
|
|
63
|
-
|
|
64
|
-
try:
|
|
65
|
-
user = validate_token(token)
|
|
66
|
-
except Exception as exc:
|
|
67
|
-
_console.print(f"[bold red]Token validation failed:[/] {exc}")
|
|
68
|
-
_console.print("[yellow]Make sure CHECKDK_API_URL points to a running backend.[/]")
|
|
69
|
-
sys.exit(1)
|
|
70
|
-
|
|
71
|
-
_save_token(token)
|
|
72
|
-
os.environ["CHECKDK_TOKEN"] = token
|
|
73
|
-
|
|
74
|
-
_console.print(Panel(
|
|
75
|
-
f"[bold green]Logged in successfully![/]\n\n"
|
|
76
|
-
f" Name: {user.get('name', '?')}\n"
|
|
77
|
-
f" Email: {user.get('email', '?')}\n"
|
|
78
|
-
f" Provider: {user.get('provider', '?')}\n\n"
|
|
79
|
-
f"[dim]Token saved to {_ENV_FILE}[/]",
|
|
80
|
-
border_style="green",
|
|
81
|
-
))
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@auth_cmd.command("logout")
|
|
85
|
-
def logout_cmd() -> None:
|
|
86
|
-
"""Remove the stored JWT token."""
|
|
87
|
-
_remove_token()
|
|
88
|
-
if "CHECKDK_TOKEN" in os.environ:
|
|
89
|
-
del os.environ["CHECKDK_TOKEN"]
|
|
90
|
-
_console.print("[bold green]Logged out.[/] Token removed from local config.")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@auth_cmd.command("whoami")
|
|
94
|
-
def whoami_cmd() -> None:
|
|
95
|
-
"""Show the currently logged-in user."""
|
|
96
|
-
try:
|
|
97
|
-
user = get_current_user()
|
|
98
|
-
except Exception as exc:
|
|
99
|
-
_console.print(f"[bold red]Not logged in or API unreachable:[/] {exc}")
|
|
100
|
-
_console.print("[dim]Run [bold]checkdk auth login[/] first.[/]")
|
|
101
|
-
sys.exit(1)
|
|
102
|
-
|
|
103
|
-
t = Table.grid(padding=(0, 2))
|
|
104
|
-
t.add_column(style="bold cyan")
|
|
105
|
-
t.add_column()
|
|
106
|
-
t.add_row("Name:", user.get("name", "?"))
|
|
107
|
-
t.add_row("Email:", user.get("email", "?"))
|
|
108
|
-
t.add_row("Provider:", user.get("provider", "?"))
|
|
109
|
-
t.add_row("User ID:", user.get("userId", "?"))
|
|
110
|
-
_console.print(Panel(t, title="Current User", border_style="cyan"))
|
|
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
|