Skip to content

Commit cfedf74

Browse files
committed
Merge branch 'docs/add-upgrade-instructions' into 'main'
docs: add upgrade instructions to README with tests See merge request postgres-ai/postgresai!170
2 parents b37ad5d + 2569742 commit cfedf74

File tree

3 files changed

+677
-29
lines changed

3 files changed

+677
-29
lines changed

README.md

Lines changed: 256 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,261 @@ npx postgresai checkup --json postgresql://... | claude -p "find issues and sugg
225225

226226
**[PostgresAI](https://postgres.ai)** — Self-Driving Postgres
227227

228-
Apache 2.0 · [Contributing](CONTRIBUTING.md)
228+
## 🎯 Use cases
229+
230+
**For developers:**
231+
```bash
232+
postgresai mon local-install --demo
233+
```
234+
Get a complete monitoring setup with demo data in under 2 minutes.
235+
236+
**For production:**
237+
```bash
238+
postgresai mon local-install --api-key=your_key
239+
# Then add your databases
240+
postgresai mon targets add "postgresql://user:pass@host:port/DB"
241+
```
242+
243+
## 🔧 Management commands
244+
245+
```bash
246+
# Instance management
247+
postgresai mon targets add "postgresql://user:pass@host:port/DB"
248+
postgresai mon targets list
249+
postgresai mon targets test my-DB
250+
251+
# Service management
252+
postgresai mon status
253+
postgresai mon logs
254+
postgresai mon restart
255+
256+
# Health check
257+
postgresai mon health
258+
```
259+
260+
## 🔄 Upgrading
261+
262+
To upgrade postgres_ai monitoring to a newer version:
263+
264+
### Step 1: Update the CLI
265+
266+
```bash
267+
npm install -g postgresai@latest
268+
```
269+
270+
Or if you're using npx:
271+
```bash
272+
npx postgresai@latest --version # verify the new version
273+
```
274+
275+
### Step 2: Stop running services
276+
277+
```bash
278+
postgresai mon stop
279+
```
280+
281+
### Step 3: Pull new Docker images and restart
282+
283+
The simplest approach is to re-run local-install, which updates the image tag and pulls new images:
284+
285+
```bash
286+
postgresai mon local-install -y
287+
```
288+
289+
This will:
290+
- Update the `PGAI_TAG` in `.env` (located in your monitoring directory, typically `~/.postgres_ai/` or your current working directory) to match the new CLI version
291+
- Pull the latest Docker images
292+
- Start the services with the new images
293+
294+
> **Note:** The `.env` file contains configuration for the monitoring stack, including `PGAI_TAG` (the Docker image version tag) and optionally `GF_SECURITY_ADMIN_PASSWORD` (Grafana admin password) and `PGAI_REGISTRY` (custom Docker registry).
295+
296+
**Alternative: Manual upgrade**
297+
298+
If you prefer more control:
299+
300+
```bash
301+
# Update the PGAI_TAG in .env to match your CLI version
302+
postgresai --version # check your CLI version
303+
# Edit .env and set PGAI_TAG to the version number
304+
305+
# Pull new images
306+
docker compose pull
307+
308+
# Start services
309+
postgresai mon start
310+
```
311+
312+
### Verify the upgrade
313+
314+
After upgrading, verify services are running correctly:
315+
316+
```bash
317+
postgresai mon status
318+
postgresai mon health
319+
```
320+
321+
Check Grafana dashboards at http://localhost:3000 to confirm metrics are being collected.
322+
323+
## 📋 Checkup reports
324+
325+
postgres_ai monitoring generates automated health check reports based on [postgres-checkup](https://gitlab.com/postgres-ai/postgres-checkup). Each report has a unique check ID and title:
326+
327+
### A. General / Infrastructural
328+
| Check ID | Title |
329+
|----------|-------|
330+
| A001 | System information |
331+
| A002 | Version information |
332+
| A003 | Postgres settings |
333+
| A004 | Cluster information |
334+
| A005 | Extensions |
335+
| A006 | Postgres setting deviations |
336+
| A007 | Altered settings |
337+
| A008 | Disk usage and file system type |
338+
339+
### D. Monitoring / Troubleshooting
340+
| Check ID | Title |
341+
|----------|-------|
342+
| D004 | pg_stat_statements and pg_stat_kcache settings |
343+
344+
### F. Autovacuum, Bloat
345+
| Check ID | Title |
346+
|----------|-------|
347+
| F001 | Autovacuum: current settings |
348+
| F004 | Autovacuum: heap bloat (estimated) |
349+
| F005 | Autovacuum: index bloat (estimated) |
350+
351+
### G. Performance / Connections / Memory-related settings
352+
| Check ID | Title |
353+
|----------|-------|
354+
| G001 | Memory-related settings |
355+
356+
### H. Index analysis
357+
| Check ID | Title |
358+
|----------|-------|
359+
| H001 | Invalid indexes |
360+
| H002 | Unused indexes |
361+
| H004 | Redundant indexes |
362+
363+
### K. SQL query analysis
364+
| Check ID | Title |
365+
|----------|-------|
366+
| K001 | Globally aggregated query metrics |
367+
| K003 | Top queries by total time (total_exec_time + total_plan_time) |
368+
| K004 | Top queries by temp bytes written |
369+
| K005 | Top queries by WAL generation |
370+
| K006 | Top queries by shared blocks read |
371+
| K007 | Top queries by shared blocks hit |
372+
373+
### M. SQL query analysis (top queries)
374+
| Check ID | Title |
375+
|----------|-------|
376+
| M001 | Top queries by mean execution time |
377+
| M002 | Top queries by rows (I/O intensity) |
378+
| M003 | Top queries by I/O time |
379+
380+
### N. Wait events analysis
381+
| Check ID | Title |
382+
|----------|-------|
383+
| N001 | Wait events grouped by type and query |
384+
385+
## 🌐 Access points
386+
387+
After running local-install:
388+
389+
- **🚀 MAIN: Grafana Dashboard**: http://localhost:3000 (login: `monitoring`; password is shown at the end of local-install)
390+
391+
Technical URLs (for advanced users):
392+
- **Demo DB**: postgresql://postgres:postgres@localhost:55432/target_database
393+
- **Monitoring**: http://localhost:58080 (PGWatch)
394+
- **Metrics**: http://localhost:59090 (Victoria Metrics)
395+
396+
## 📖 Help
397+
398+
```bash
399+
postgresai --help
400+
postgresai mon --help
401+
```
402+
403+
## 🔑 PostgresAI access token
404+
Get your access token at [PostgresAI](https://postgres.ai) for automated report uploads and advanced analysis.
405+
406+
## 🛣️ Roadmap
407+
408+
- Host stats for on-premise and managed Postgres setups
409+
- `pg_wait_sampling` and `pg_stat_kcache` extension support
410+
- Additional expert dashboards: autovacuum, checkpointer, lock analysis
411+
- Query plan analysis and automated recommendations
412+
- Enhanced AI integration capabilities
413+
414+
## 🧪 Testing
415+
416+
Python-based report generation lives under `reporter/` and now ships with a pytest suite.
417+
418+
### Installation
419+
420+
Install dev dependencies (includes `pytest`, `pytest-postgresql`, `psycopg`, etc.):
421+
```bash
422+
python3 -m pip install -r reporter/requirements-dev.txt
423+
```
424+
425+
### Running Tests
426+
427+
#### Unit Tests Only (Fast, No External Services Required)
428+
429+
Run only unit tests with mocked Prometheus interactions:
430+
```bash
431+
pytest tests/reporter
432+
```
433+
434+
This automatically skips integration tests. Or run specific test files:
435+
```bash
436+
pytest tests/reporter/test_generators_unit.py -v
437+
pytest tests/reporter/test_formatters.py -v
438+
```
439+
440+
#### All Tests: Unit + Integration (Requires PostgreSQL)
441+
442+
Run the complete test suite (both unit and integration tests):
443+
```bash
444+
pytest tests/reporter --run-integration
445+
```
446+
447+
Integration tests create a temporary PostgreSQL instance automatically and require PostgreSQL binaries (`initdb`, `postgres`) on your PATH. No manual database setup or environment variables are required - the tests create and destroy their own temporary PostgreSQL instances.
448+
449+
**Summary:**
450+
- `pytest tests/reporter`**Unit tests only** (integration tests skipped)
451+
- `pytest tests/reporter --run-integration`**Both unit and integration tests**
452+
453+
### Test Coverage
454+
455+
Generate coverage report:
456+
```bash
457+
pytest tests/reporter -m unit --cov=reporter --cov-report=html
458+
```
459+
460+
View the coverage report by opening `htmlcov/index.html` in your browser.
461+
462+
## 🤝 Contributing
463+
464+
We welcome contributions from Postgres experts! Please check our [GitLab repository](https://gitlab.com/postgres-ai/postgres_ai) for:
465+
- Code standards and review process
466+
- Dashboard design principles
467+
- Testing requirements for monitoring components
468+
469+
## 📄 License
470+
471+
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
472+
473+
## 🏢 About PostgresAI
474+
475+
postgres_ai monitoring is developed by [PostgresAI](https://postgres.ai), bringing years of Postgres expertise into automated monitoring and analysis tools. We provide enterprise consulting and advanced Postgres solutions for fast-growing companies.
476+
477+
## 📞 Support & community
478+
479+
- 💬 [Get support](https://postgres.ai/contact)
480+
- 📺 [Postgres.TV (YouTube)](https://postgres.tv)
481+
- 🎙️ [Postgres FM Podcast](https://postgres.fm)
482+
- 🐛 [Report issues](https://gitlab.com/postgres-ai/postgres_ai/-/issues)
483+
- 📧 [Enterprise support](https://postgres.ai/consulting)
229484

230485
</div>

cli/test/init.integration.test.ts

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import * as path from "path";
1010
import * as net from "net";
1111
import { Client } from "pg";
1212

13+
const TEST_TIMEOUT = 30000; // 30 seconds
14+
1315
function sqlLiteral(value: string): string {
1416
return `'${String(value).replace(/'/g, "''")}'`;
1517
}
@@ -215,7 +217,7 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
215217
} finally {
216218
await pg.cleanup();
217219
}
218-
}, { timeout: 15000 });
220+
}, { timeout: TEST_TIMEOUT });
219221

220222
test("requires explicit monitoring password in non-interactive mode", async () => {
221223
pg = await createTempPostgres();
@@ -239,7 +241,7 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
239241
} finally {
240242
await pg.cleanup();
241243
}
242-
}, { timeout: 15000 });
244+
}, { timeout: TEST_TIMEOUT });
243245

244246
test(
245247
"fixes slightly-off permissions idempotently",
@@ -296,21 +298,19 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
296298
await pg.cleanup();
297299
}
298300
},
299-
{ timeout: 15000 }
301+
{ timeout: TEST_TIMEOUT }
300302
);
301303

302-
test(
303-
"reports nicely when lacking permissions",
304-
async () => {
305-
pg = await createTempPostgres();
304+
test("reports nicely when lacking permissions", async () => {
305+
pg = await createTempPostgres();
306306

307-
try {
308-
// Create limited user that can connect but cannot create roles / grant.
309-
const limitedPw = "limitedpw";
310-
{
311-
const c = new Client({ connectionString: pg.adminUri });
312-
await c.connect();
313-
await c.query(`do $$ begin
307+
try {
308+
// Create limited user that can connect but cannot create roles / grant.
309+
const limitedPw = "limitedpw";
310+
{
311+
const c = new Client({ connectionString: pg.adminUri });
312+
await c.connect();
313+
await c.query(`do $$ begin
314314
if not exists (select 1 from pg_roles where rolname='limited') then
315315
begin
316316
create role limited login password ${sqlLiteral(limitedPw)};
@@ -323,18 +323,16 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
323323
await c.end();
324324
}
325325

326-
const limitedUri = `postgresql://limited:${limitedPw}@127.0.0.1:${pg.port}/testdb`;
327-
const r = runCliInit([limitedUri, "--password", "monpw", "--skip-optional-permissions"]);
328-
expect(r.status).not.toBe(0);
329-
expect(r.stderr).toMatch(/Error: prepare-db:/);
330-
expect(r.stderr).toMatch(/Failed at step "/);
331-
expect(r.stderr).toMatch(/Fix: connect as a superuser/i);
332-
} finally {
333-
await pg.cleanup();
334-
}
335-
},
336-
{ timeout: 15000 }
337-
);
326+
const limitedUri = `postgresql://limited:${limitedPw}@127.0.0.1:${pg.port}/testdb`;
327+
const r = runCliInit([limitedUri, "--password", "monpw", "--skip-optional-permissions"]);
328+
expect(r.status).not.toBe(0);
329+
expect(r.stderr).toMatch(/Error: prepare-db:/);
330+
expect(r.stderr).toMatch(/Failed at step "/);
331+
expect(r.stderr).toMatch(/Fix: connect as a superuser/i);
332+
} finally {
333+
await pg.cleanup();
334+
}
335+
}, { timeout: TEST_TIMEOUT });
338336

339337
test(
340338
"--verify returns 0 when ok and non-zero when missing",
@@ -372,7 +370,8 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
372370
} finally {
373371
await pg.cleanup();
374372
}
375-
}
373+
},
374+
{ timeout: TEST_TIMEOUT }
376375
);
377376

378377
// 15s timeout for PostgreSQL startup + two CLI init commands in slow CI
@@ -406,7 +405,7 @@ describe.skipIf(skipTests)("integration: prepare-db", () => {
406405
} finally {
407406
await pg.cleanup();
408407
}
409-
}, { timeout: 15000 });
408+
}, { timeout: TEST_TIMEOUT });
410409

411410
// 60s timeout for PostgreSQL startup + multiple SQL queries in slow CI
412411
test("explain_generic validates input and prevents SQL injection", async () => {

0 commit comments

Comments
 (0)