kctl-pg 0.7.2__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.
- kctl_pg-0.7.2/.gitignore +7 -0
- kctl_pg-0.7.2/PKG-INFO +18 -0
- kctl_pg-0.7.2/README.md +388 -0
- kctl_pg-0.7.2/e2e/.gitignore +3 -0
- kctl_pg-0.7.2/e2e/README.md +32 -0
- kctl_pg-0.7.2/e2e/fixtures/auth.ts +26 -0
- kctl_pg-0.7.2/e2e/package.json +15 -0
- kctl_pg-0.7.2/e2e/playwright.config.ts +15 -0
- kctl_pg-0.7.2/e2e/tests/smoke/connectivity.spec.ts +18 -0
- kctl_pg-0.7.2/pyproject.toml +46 -0
- kctl_pg-0.7.2/skills/postgres-admin/SKILL.md +402 -0
- kctl_pg-0.7.2/src/kctl_pg/__init__.py +3 -0
- kctl_pg-0.7.2/src/kctl_pg/__main__.py +5 -0
- kctl_pg-0.7.2/src/kctl_pg/cli.py +162 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/__init__.py +0 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/activity.py +176 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/automation.py +666 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/backup.py +177 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/config_cmd.py +545 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/dashboard.py +104 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/db.py +354 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/doctor_cmd.py +87 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/dr.py +821 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/extensions.py +126 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/health.py +91 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/indexes.py +578 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/lint.py +590 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/maintenance.py +379 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/performance.py +727 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/pg_config.py +235 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/pgbouncer.py +486 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/pipeline.py +601 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/query.py +60 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/replication.py +727 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/schemas.py +216 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/security.py +762 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/skill_cmd.py +76 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/stats.py +537 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/tables.py +996 -0
- kctl_pg-0.7.2/src/kctl_pg/commands/users.py +493 -0
- kctl_pg-0.7.2/src/kctl_pg/core/__init__.py +0 -0
- kctl_pg-0.7.2/src/kctl_pg/core/callbacks.py +58 -0
- kctl_pg-0.7.2/src/kctl_pg/core/client.py +152 -0
- kctl_pg-0.7.2/src/kctl_pg/core/config.py +165 -0
- kctl_pg-0.7.2/src/kctl_pg/core/exceptions.py +42 -0
- kctl_pg-0.7.2/src/kctl_pg/core/output.py +5 -0
- kctl_pg-0.7.2/tests/__init__.py +0 -0
- kctl_pg-0.7.2/tests/conftest.py +137 -0
- kctl_pg-0.7.2/tests/test_activity.py +309 -0
- kctl_pg-0.7.2/tests/test_automation.py +41 -0
- kctl_pg-0.7.2/tests/test_backup.py +258 -0
- kctl_pg-0.7.2/tests/test_dr.py +105 -0
- kctl_pg-0.7.2/tests/test_existing.py +265 -0
- kctl_pg-0.7.2/tests/test_lint.py +131 -0
- kctl_pg-0.7.2/tests/test_pipeline.py +218 -0
kctl_pg-0.7.2/.gitignore
ADDED
kctl_pg-0.7.2/PKG-INFO
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kctl-pg
|
|
3
|
+
Version: 0.7.2
|
|
4
|
+
Summary: Kodemeio PostgreSQL CLI — manage PostgreSQL servers via SSH tunnel
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: kctl-lib>=0.8.0
|
|
7
|
+
Requires-Dist: paramiko<4.0.0,>=3.4.0
|
|
8
|
+
Requires-Dist: psycopg[binary]>=3.2.0
|
|
9
|
+
Requires-Dist: pydantic>=2.10.0
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
11
|
+
Requires-Dist: rich>=13.9.0
|
|
12
|
+
Requires-Dist: sshtunnel>=0.4.0
|
|
13
|
+
Requires-Dist: typer>=0.15.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: mypy>=1.14.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.3.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff>=0.9.0; extra == 'dev'
|
|
18
|
+
Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
|
kctl_pg-0.7.2/README.md
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# kctl-pg
|
|
2
|
+
|
|
3
|
+
Kodemeio PostgreSQL CLI -- manage PostgreSQL servers via SSH tunnel.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv tool install ./packages/kctl-pg
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
To upgrade after code changes:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv tool install --force --reinstall ./packages/kctl-pg
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Configure a profile (interactive)
|
|
21
|
+
kctl-pg config init
|
|
22
|
+
|
|
23
|
+
# Verify connection
|
|
24
|
+
kctl-pg health
|
|
25
|
+
|
|
26
|
+
# Dashboard overview
|
|
27
|
+
kctl-pg dashboard
|
|
28
|
+
|
|
29
|
+
# List databases
|
|
30
|
+
kctl-pg db list
|
|
31
|
+
|
|
32
|
+
# List users
|
|
33
|
+
kctl-pg users list
|
|
34
|
+
|
|
35
|
+
# Check active connections
|
|
36
|
+
kctl-pg activity list
|
|
37
|
+
|
|
38
|
+
# Run a raw SQL query
|
|
39
|
+
kctl-pg query "SELECT version()"
|
|
40
|
+
|
|
41
|
+
# Dump a database backup
|
|
42
|
+
kctl-pg backup dump --database mydb
|
|
43
|
+
|
|
44
|
+
# Show slow queries
|
|
45
|
+
kctl-pg performance slow-queries
|
|
46
|
+
|
|
47
|
+
# Full health report
|
|
48
|
+
kctl-pg pipeline report
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Command Groups
|
|
52
|
+
|
|
53
|
+
| Group | Commands | Description |
|
|
54
|
+
|----------------|---------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------|
|
|
55
|
+
| `activity` | `list`, `kill`, `locks` | Active connections, long-running queries, lock waits |
|
|
56
|
+
| `automation` | `plan`, `alerts`, `report`, `baseline` | Automated maintenance planning and alert rules |
|
|
57
|
+
| `backup` | `dump`, `restore`, `list` | Database backup and restore via pg_dump / pg_restore |
|
|
58
|
+
| `config` | `init`, `add`, `use`, `show`, `validate`, `remove`, `set`, `profiles`, `current` | CLI configuration and profile management |
|
|
59
|
+
| `dashboard` | `dashboard` | Single-screen server overview (size, connections, health) |
|
|
60
|
+
| `db` | `list`, `create`, `drop`, `size`, `info`, `rename`, `copy`, `owner` | Database CRUD and metadata |
|
|
61
|
+
| `dr` | `verify-backup`, `test-failover`, `capacity-forecast`, `rpo-rto` | Disaster recovery checks, RPO/RTO status, capacity |
|
|
62
|
+
| `extensions` | `list`, `install`, `uninstall` | PostgreSQL extension management |
|
|
63
|
+
| `health` | `health` | Quick server health check (connections, replication, etc) |
|
|
64
|
+
| `indexes` | `list`, `bloat`, `duplicate`, `invalid`, `missing`, `create-concurrently`, `reindex-concurrently` | Index analysis, bloat detection, and safe concurrent ops |
|
|
65
|
+
| `lint` | `schema`, `indexes`, `permissions`, `all` | Static analysis for schema, index, and permission issues |
|
|
66
|
+
| `maintenance` | `vacuum`, `analyze`, `reindex`, `autovacuum`, `freeze`, `cluster`, `checkpoint`, `frozen-xid` | Table maintenance, vacuum, freeze, and statistics |
|
|
67
|
+
| `performance` | `overview`, `slow-queries`, `cache`, `settings`, `explain`, `temp-files`, `progress` | Query performance, cache hit ratios, and EXPLAIN plans |
|
|
68
|
+
| `pg-config` | `show`, `get`, `set`, `reset`, `reload`, `diff` | PostgreSQL server configuration (postgresql.conf) |
|
|
69
|
+
| `pgbouncer` | `status`, `pools`, `clients`, `servers`, `databases`, `stats`, `reload`, `pause`, `resume` | PgBouncer connection pooler management |
|
|
70
|
+
| `pipeline` | `gate`, `report` | CI/CD pipeline gates and full health reports |
|
|
71
|
+
| `query` | `query` | Execute raw SQL queries |
|
|
72
|
+
| `replication` | `status`, `lag`, `slots`, `create-slot`, `drop-slot`, `publications`, `subscriptions`, `promote`, `senders`, `receiver` | Streaming and logical replication management |
|
|
73
|
+
| `schemas` | `list`, `create`, `drop`, `size` | Schema management and sizing |
|
|
74
|
+
| `security` | `ssl`, `hba-rules`, `privileges`, `rls`, `rls-policies`, `superuser-audit`, `password-check` | SSL, pg_hba.conf, row-level security, and auditing |
|
|
75
|
+
| `stats` | `tables`, `indexes`, `bgwriter`, `replication`, `wal`, `io`, `database` | pg_stat_* statistics views |
|
|
76
|
+
| `tables` | `list`, `describe`, `size`, `partitions`, `constraints`, `triggers`, `dependencies`, `toast`, `sequences` | Table inspection, sizing, and metadata |
|
|
77
|
+
| `users` | `list`, `create`, `drop`, `password`, `get`, `grant`, `revoke`, `alter`, `grant-db`, `grant-schema`, `grant-table`, `default-privileges` | User and role management |
|
|
78
|
+
|
|
79
|
+
## SSH Tunnel Architecture
|
|
80
|
+
|
|
81
|
+
kctl-pg does **not** connect directly to PostgreSQL. All connections are established through an SSH tunnel to avoid exposing the PostgreSQL port on the network.
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
kctl-pg CLI
|
|
85
|
+
|
|
|
86
|
+
| SSH (port 22)
|
|
87
|
+
v
|
|
88
|
+
Remote Server (ssh_host)
|
|
89
|
+
|
|
|
90
|
+
| localhost tunnel -> 5432
|
|
91
|
+
v
|
|
92
|
+
PostgreSQL (host:port, internal network only)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The tunnel is opened automatically when any command needs a database connection and closed when the command completes. This is handled transparently by `PostgresClient` using `SSHTunnel` from `kctl-lib`.
|
|
96
|
+
|
|
97
|
+
For Dokploy-managed servers, the `host` in the config refers to the PostgreSQL host as seen **from the SSH server** (e.g. `10.0.0.2` for internal Hetzner network addresses), not from your local machine.
|
|
98
|
+
|
|
99
|
+
## Global Options
|
|
100
|
+
|
|
101
|
+
These options are available on every command:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
--json Output as JSON (machine-readable)
|
|
105
|
+
--quiet, -q Suppress informational messages
|
|
106
|
+
--profile, -p Use a named config profile
|
|
107
|
+
--host, -H PostgreSQL host override
|
|
108
|
+
--port PostgreSQL port override
|
|
109
|
+
--user, -U PostgreSQL user override
|
|
110
|
+
--password PostgreSQL password override
|
|
111
|
+
--version, -V Show version and exit
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Configuration
|
|
115
|
+
|
|
116
|
+
### Config File Format
|
|
117
|
+
|
|
118
|
+
kctl-pg shares the platform-wide config at `~/.config/kodemeio/config.yaml`. PostgreSQL settings are scoped under the `postgres` service key:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
default_profile: production
|
|
122
|
+
|
|
123
|
+
profiles:
|
|
124
|
+
production:
|
|
125
|
+
postgres:
|
|
126
|
+
host: 10.0.0.2 # Internal PG host (as seen from SSH server)
|
|
127
|
+
port: 5432
|
|
128
|
+
user: postgres
|
|
129
|
+
password: ${PG_PASSWORD} # Env var expansion supported
|
|
130
|
+
ssh_host: 49.13.14.79 # Public SSH host
|
|
131
|
+
ssh_port: 22
|
|
132
|
+
ssh_user: root
|
|
133
|
+
ssh_key: ~/.ssh/id_ed25519
|
|
134
|
+
databases:
|
|
135
|
+
- authentik
|
|
136
|
+
- odoo_production
|
|
137
|
+
staging:
|
|
138
|
+
postgres:
|
|
139
|
+
host: 10.0.0.3
|
|
140
|
+
port: 5432
|
|
141
|
+
user: postgres
|
|
142
|
+
password: ${PG_PASSWORD_STG}
|
|
143
|
+
ssh_host: staging.example.com
|
|
144
|
+
ssh_port: 22
|
|
145
|
+
ssh_user: root
|
|
146
|
+
ssh_key: ~/.ssh/id_ed25519
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Profile Management
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Interactive setup wizard
|
|
153
|
+
kctl-pg config init
|
|
154
|
+
|
|
155
|
+
# Add a named profile
|
|
156
|
+
kctl-pg config add production \
|
|
157
|
+
--host 10.0.0.2 \
|
|
158
|
+
--ssh-host 49.13.14.79 \
|
|
159
|
+
--user postgres
|
|
160
|
+
|
|
161
|
+
# Switch the default profile
|
|
162
|
+
kctl-pg config use production
|
|
163
|
+
|
|
164
|
+
# Show current profile config (secrets masked)
|
|
165
|
+
kctl-pg config show
|
|
166
|
+
|
|
167
|
+
# List all profiles
|
|
168
|
+
kctl-pg config profiles
|
|
169
|
+
|
|
170
|
+
# Validate current config
|
|
171
|
+
kctl-pg config validate
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Environment Variables
|
|
175
|
+
|
|
176
|
+
CLI flags take precedence over env vars, which take precedence over the config file.
|
|
177
|
+
|
|
178
|
+
| Variable | Description |
|
|
179
|
+
|---------------------|-----------------------------------------------|
|
|
180
|
+
| `KCTL_PG_HOST` | PostgreSQL host override |
|
|
181
|
+
| `KCTL_PG_PORT` | PostgreSQL port override |
|
|
182
|
+
| `KCTL_PG_USER` | PostgreSQL user override |
|
|
183
|
+
| `KCTL_PG_PASSWORD` | PostgreSQL password override |
|
|
184
|
+
| `KCTL_PG_SSH_HOST` | SSH host override |
|
|
185
|
+
| `KCTL_PG_PROFILE` | Active profile name override |
|
|
186
|
+
| `PGHOST` | Standard libpq host (lower priority) |
|
|
187
|
+
| `PGPORT` | Standard libpq port (lower priority) |
|
|
188
|
+
| `PGUSER` | Standard libpq user (lower priority) |
|
|
189
|
+
| `PGPASSWORD` | Standard libpq password (lower priority) |
|
|
190
|
+
|
|
191
|
+
### Connection Resolution Priority
|
|
192
|
+
|
|
193
|
+
1. CLI flags (`--host`, `--user`, `--password`, etc.)
|
|
194
|
+
2. `KCTL_PG_*` environment variables
|
|
195
|
+
3. Standard `PG*` environment variables (`PGHOST`, `PGUSER`, etc.)
|
|
196
|
+
4. Config file profile
|
|
197
|
+
|
|
198
|
+
## Common DBA Workflows
|
|
199
|
+
|
|
200
|
+
### Database Provisioning
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
# Create a role first
|
|
204
|
+
kctl-pg users create myuser --password secret --login
|
|
205
|
+
|
|
206
|
+
# Create a database with owner
|
|
207
|
+
kctl-pg db create mydb --owner myuser
|
|
208
|
+
|
|
209
|
+
# Grant full access on the database
|
|
210
|
+
kctl-pg users grant-db myuser mydb
|
|
211
|
+
|
|
212
|
+
# Grant usage on public schema
|
|
213
|
+
kctl-pg users grant-schema myuser public --database mydb
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Backup and Restore
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Dump a database
|
|
220
|
+
kctl-pg backup dump --database mydb --file mydb.dump
|
|
221
|
+
|
|
222
|
+
# List available backups
|
|
223
|
+
kctl-pg backup list
|
|
224
|
+
|
|
225
|
+
# Restore a backup
|
|
226
|
+
kctl-pg backup restore --file mydb.dump --database mydb_restore
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Performance Investigation
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Full performance overview
|
|
233
|
+
kctl-pg performance overview --database mydb
|
|
234
|
+
|
|
235
|
+
# Slow queries (top 20 by total time)
|
|
236
|
+
kctl-pg performance slow-queries --database mydb --limit 20
|
|
237
|
+
|
|
238
|
+
# Cache hit ratio
|
|
239
|
+
kctl-pg performance cache --database mydb
|
|
240
|
+
|
|
241
|
+
# EXPLAIN a query
|
|
242
|
+
kctl-pg performance explain "SELECT * FROM orders WHERE status = 'pending'" --database mydb
|
|
243
|
+
|
|
244
|
+
# Operations currently in progress
|
|
245
|
+
kctl-pg performance progress
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Index Maintenance
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Find bloated indexes
|
|
252
|
+
kctl-pg indexes bloat --database mydb
|
|
253
|
+
|
|
254
|
+
# Find duplicate indexes
|
|
255
|
+
kctl-pg indexes duplicate --database mydb
|
|
256
|
+
|
|
257
|
+
# Find invalid indexes (failed CONCURRENTLY build)
|
|
258
|
+
kctl-pg indexes invalid --database mydb
|
|
259
|
+
|
|
260
|
+
# Rebuild a specific index without locking writes
|
|
261
|
+
kctl-pg indexes reindex-concurrently --index my_index --database mydb
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Security Audit
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# Check SSL configuration
|
|
268
|
+
kctl-pg security ssl
|
|
269
|
+
|
|
270
|
+
# Review pg_hba.conf rules
|
|
271
|
+
kctl-pg security hba-rules
|
|
272
|
+
|
|
273
|
+
# Superuser audit
|
|
274
|
+
kctl-pg security superuser-audit
|
|
275
|
+
|
|
276
|
+
# Password hash methods in use
|
|
277
|
+
kctl-pg security password-check
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Replication Monitoring
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Replication status
|
|
284
|
+
kctl-pg replication status
|
|
285
|
+
|
|
286
|
+
# Replication lag per replica
|
|
287
|
+
kctl-pg replication lag
|
|
288
|
+
|
|
289
|
+
# List replication slots
|
|
290
|
+
kctl-pg replication slots
|
|
291
|
+
|
|
292
|
+
# WAL senders
|
|
293
|
+
kctl-pg replication senders
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### CI/CD Pipeline Integration
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# Gate: fail if replication lag > threshold, cache hit < 95%, connections > 80%
|
|
300
|
+
kctl-pg pipeline gate --database mydb
|
|
301
|
+
|
|
302
|
+
# Generate a full Markdown health report
|
|
303
|
+
kctl-pg pipeline report --database mydb --output report.md
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Server Configuration Tuning
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Show all non-default settings
|
|
310
|
+
kctl-pg pg-config show --changed-only
|
|
311
|
+
|
|
312
|
+
# Get a specific parameter
|
|
313
|
+
kctl-pg pg-config get shared_buffers
|
|
314
|
+
|
|
315
|
+
# Set a parameter (requires superuser)
|
|
316
|
+
kctl-pg pg-config set work_mem 64MB
|
|
317
|
+
|
|
318
|
+
# Reload config without restart
|
|
319
|
+
kctl-pg pg-config reload
|
|
320
|
+
|
|
321
|
+
# Diff current settings against defaults
|
|
322
|
+
kctl-pg pg-config diff
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Development
|
|
326
|
+
|
|
327
|
+
### Running Tests
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
cd packages/kctl-pg
|
|
331
|
+
uv run pytest tests/ -v
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Linting and Formatting
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
cd packages/kctl-pg
|
|
338
|
+
uv run ruff check src/
|
|
339
|
+
uv run ruff format src/
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Type Checking
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
cd packages/kctl-pg
|
|
346
|
+
uv run mypy src/kctl_pg/
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Project Structure
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
packages/kctl-pg/
|
|
353
|
+
src/kctl_pg/
|
|
354
|
+
cli.py Main Typer app + command group registration
|
|
355
|
+
__init__.py Version
|
|
356
|
+
core/
|
|
357
|
+
callbacks.py AppContext (subclasses AppContextBase from kctl-lib)
|
|
358
|
+
client.py PostgresClient (psycopg + SSHTunnel)
|
|
359
|
+
config.py Profile and connection resolution (SERVICE_KEY = "postgres")
|
|
360
|
+
exceptions.py KctlError subclasses
|
|
361
|
+
commands/
|
|
362
|
+
activity.py list, kill, locks
|
|
363
|
+
automation.py plan, alerts, report, baseline
|
|
364
|
+
backup.py dump, restore, list
|
|
365
|
+
config_cmd.py init, add, use, show, validate, remove, set, profiles, current
|
|
366
|
+
dashboard.py single-screen server overview
|
|
367
|
+
db.py list, create, drop, size, info, rename, copy, owner
|
|
368
|
+
dr.py verify-backup, test-failover, capacity-forecast, rpo-rto
|
|
369
|
+
extensions.py list, install, uninstall
|
|
370
|
+
health.py health
|
|
371
|
+
indexes.py list, bloat, duplicate, invalid, missing, create-concurrently, reindex-concurrently
|
|
372
|
+
lint.py schema, indexes, permissions, all
|
|
373
|
+
maintenance.py vacuum, analyze, reindex, autovacuum, freeze, cluster, checkpoint, frozen-xid
|
|
374
|
+
performance.py overview, slow-queries, cache, settings, explain, temp-files, progress
|
|
375
|
+
pg_config.py show, get, set, reset, reload, diff
|
|
376
|
+
pgbouncer.py status, pools, clients, servers, databases, stats, reload, pause, resume
|
|
377
|
+
pipeline.py gate, report
|
|
378
|
+
query.py raw SQL execution
|
|
379
|
+
replication.py status, lag, slots, create-slot, drop-slot, publications, subscriptions, promote, senders, receiver
|
|
380
|
+
schemas.py list, create, drop, size
|
|
381
|
+
security.py ssl, hba-rules, privileges, rls, rls-policies, superuser-audit, password-check
|
|
382
|
+
stats.py tables, indexes, bgwriter, replication, wal, io, database
|
|
383
|
+
tables.py list, describe, size, partitions, constraints, triggers, dependencies, toast, sequences
|
|
384
|
+
users.py list, create, drop, password, get, grant, revoke, alter, grant-db, grant-schema, grant-table, default-privileges
|
|
385
|
+
tests/ pytest test suite
|
|
386
|
+
pyproject.toml Package metadata and tool config
|
|
387
|
+
README.md This file
|
|
388
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# kctl-pg E2E Tests
|
|
2
|
+
|
|
3
|
+
Playwright-based E2E tests for kctl-pg verifying SSH connectivity and CLI health checks.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm run install-browsers
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Run
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Against staging PostgreSQL host via SSH
|
|
16
|
+
export PG_HOST=10.0.0.2
|
|
17
|
+
export PG_PASSWORD=<your-password>
|
|
18
|
+
export KCTL_PG_PROFILE=production
|
|
19
|
+
pnpm test
|
|
20
|
+
|
|
21
|
+
# Smoke tests only
|
|
22
|
+
pnpm test:smoke
|
|
23
|
+
|
|
24
|
+
# Visible browser
|
|
25
|
+
pnpm test:headed
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Env Vars
|
|
29
|
+
|
|
30
|
+
- `PG_HOST` — PostgreSQL host (SSH target)
|
|
31
|
+
- `PG_PASSWORD` — PostgreSQL password
|
|
32
|
+
- `KCTL_PG_PROFILE` — kctl-pg profile name to use (required for smoke tests)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { test as base } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export interface AuthFixtures {
|
|
4
|
+
pgHost: string;
|
|
5
|
+
pgPassword: string;
|
|
6
|
+
pgProfile: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const test = base.extend<AuthFixtures>({
|
|
10
|
+
pgHost: async ({}, use) => {
|
|
11
|
+
const host = process.env.PG_HOST;
|
|
12
|
+
if (!host) throw new Error("PG_HOST env var required");
|
|
13
|
+
await use(host);
|
|
14
|
+
},
|
|
15
|
+
pgPassword: async ({}, use) => {
|
|
16
|
+
const password = process.env.PG_PASSWORD;
|
|
17
|
+
if (!password) throw new Error("PG_PASSWORD env var required");
|
|
18
|
+
await use(password);
|
|
19
|
+
},
|
|
20
|
+
pgProfile: async ({}, use) => {
|
|
21
|
+
const profile = process.env.KCTL_PG_PROFILE || "default";
|
|
22
|
+
await use(profile);
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export { expect } from "@playwright/test";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kctl-pg-e2e",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "playwright test",
|
|
7
|
+
"test:smoke": "playwright test --project=smoke",
|
|
8
|
+
"test:headed": "playwright test --headed",
|
|
9
|
+
"install-browsers": "playwright install chromium"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@playwright/test": "^1.48.0",
|
|
13
|
+
"typescript": "^5.5.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
testDir: "./tests",
|
|
5
|
+
timeout: 60_000,
|
|
6
|
+
retries: 1,
|
|
7
|
+
reporter: "list",
|
|
8
|
+
use: {
|
|
9
|
+
baseURL: process.env.PG_HOST || "localhost",
|
|
10
|
+
},
|
|
11
|
+
projects: [
|
|
12
|
+
{ name: "smoke", testMatch: /smoke\/.*\.spec\.ts/ },
|
|
13
|
+
{ name: "scenarios", testMatch: /scenarios\/.*\.spec\.ts/ },
|
|
14
|
+
],
|
|
15
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { test, expect } from "@playwright/test";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
|
|
4
|
+
test.describe("kctl-pg CLI", () => {
|
|
5
|
+
test.skip(!process.env.KCTL_PG_PROFILE, "KCTL_PG_PROFILE not set");
|
|
6
|
+
|
|
7
|
+
test("health check succeeds", async () => {
|
|
8
|
+
const profile = process.env.KCTL_PG_PROFILE!;
|
|
9
|
+
const output = execFileSync(
|
|
10
|
+
"kctl-pg",
|
|
11
|
+
["--profile", profile, "health", "check"],
|
|
12
|
+
{
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
},
|
|
15
|
+
);
|
|
16
|
+
expect(output).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kctl-pg"
|
|
7
|
+
version = "0.7.2"
|
|
8
|
+
description = "Kodemeio PostgreSQL CLI — manage PostgreSQL servers via SSH tunnel"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"kctl-lib>=0.8.0",
|
|
12
|
+
"typer>=0.15.0",
|
|
13
|
+
"rich>=13.9.0",
|
|
14
|
+
"pydantic>=2.10.0",
|
|
15
|
+
"pyyaml>=6.0.2",
|
|
16
|
+
"psycopg[binary]>=3.2.0",
|
|
17
|
+
"sshtunnel>=0.4.0",
|
|
18
|
+
"paramiko>=3.4.0,<4.0.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
dev = [
|
|
23
|
+
"pytest>=8.3.0",
|
|
24
|
+
"ruff>=0.9.0",
|
|
25
|
+
"mypy>=1.14.0",
|
|
26
|
+
"types-PyYAML>=6.0.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
kctl-pg = "kctl_pg.cli:_run"
|
|
31
|
+
|
|
32
|
+
[tool.uv.sources]
|
|
33
|
+
kctl-lib = { workspace = true }
|
|
34
|
+
|
|
35
|
+
[project.entry-points."kctl_pg.plugins"]
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["src/kctl_pg"]
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
target-version = "py312"
|
|
42
|
+
line-length = 120
|
|
43
|
+
|
|
44
|
+
[tool.mypy]
|
|
45
|
+
python_version = "3.12"
|
|
46
|
+
strict = true
|