@wpmoo/toolkit 0.9.9 → 0.9.11
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.
- package/README.md +8 -2
- package/dist/daily-actions.js +21 -0
- package/dist/doctor.js +86 -10
- package/dist/external-templates.js +2 -0
- package/dist/help.js +10 -1
- package/dist/templates.js +24 -0
- package/docs/generated-environment-verification.md +15 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,10 @@ Every cockpit action maps to a direct command, so the same workflow can be used
|
|
|
144
144
|
./moo restore-snapshot --dry-run before-update devel
|
|
145
145
|
```
|
|
146
146
|
|
|
147
|
+
In `WPMOO_ENV=prod`, `install`, `update`, and `test` require `WPMOO_ALLOW_PROD_LIFECYCLE=1`.
|
|
148
|
+
`resetdb` and real `restore-snapshot` require `WPMOO_ALLOW_DESTRUCTIVE=1` in `stage` and `prod`.
|
|
149
|
+
`restore-snapshot --dry-run` remains allowed for preview.
|
|
150
|
+
|
|
147
151
|
Module source actions also have direct commands. Default is `private`; pass `--source-type oca` or `--source-type external` for non-private source repositories:
|
|
148
152
|
|
|
149
153
|
```bash
|
|
@@ -166,9 +170,11 @@ npx @wpmoo/toolkit doctor --json --postgres
|
|
|
166
170
|
|
|
167
171
|
JSON output is optional; human-readable output remains the default.
|
|
168
172
|
`doctor --postgres` adds read-only PostgreSQL health and performance diagnostics
|
|
169
|
-
such as database size,
|
|
170
|
-
|
|
173
|
+
such as database size, sessions currently running queries with
|
|
174
|
+
`pg_stat_activity.state = 'active'`, connection utilization against
|
|
175
|
+
`max_connections`, slow-query readiness, extension visibility, and settings.
|
|
171
176
|
`doctor --json --postgres` includes a structured `postgres` object for automation.
|
|
177
|
+
Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
|
|
172
178
|
|
|
173
179
|
## Documentation
|
|
174
180
|
|
package/dist/daily-actions.js
CHANGED
|
@@ -155,9 +155,15 @@ function isDestructiveCommand(command, args) {
|
|
|
155
155
|
return true;
|
|
156
156
|
return command === 'restore-snapshot' && args[0] !== '--dry-run';
|
|
157
157
|
}
|
|
158
|
+
function isProductionLifecycleCommand(command) {
|
|
159
|
+
return command === 'install' || command === 'update' || command === 'test';
|
|
160
|
+
}
|
|
158
161
|
function destructiveCommandError(command, envName) {
|
|
159
162
|
return `Refusing destructive command '${command}' in WPMOO_ENV=${envName}. Set WPMOO_ALLOW_DESTRUCTIVE=1 to run it intentionally.`;
|
|
160
163
|
}
|
|
164
|
+
function productionLifecycleCommandError(command) {
|
|
165
|
+
return `Refusing production lifecycle command '${command}' in WPMOO_ENV=prod. Set WPMOO_ALLOW_PROD_LIFECYCLE=1 to run it intentionally.`;
|
|
166
|
+
}
|
|
161
167
|
async function assertDestructiveCommandAllowed(command, args, cwd) {
|
|
162
168
|
if (!isDestructiveCommand(command, args)) {
|
|
163
169
|
return;
|
|
@@ -172,6 +178,20 @@ async function assertDestructiveCommandAllowed(command, args, cwd) {
|
|
|
172
178
|
throw new Error(destructiveCommandError(command, envName));
|
|
173
179
|
}
|
|
174
180
|
}
|
|
181
|
+
async function assertProductionLifecycleCommandAllowed(command, cwd) {
|
|
182
|
+
if (!isProductionLifecycleCommand(command)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const env = await readEnvFile(cwd);
|
|
186
|
+
const envName = process.env.WPMOO_ENV?.trim() || selectedComposeEnvironment(env);
|
|
187
|
+
if (envName !== 'prod') {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const allowProdLifecycle = process.env.WPMOO_ALLOW_PROD_LIFECYCLE?.trim() || env?.get('WPMOO_ALLOW_PROD_LIFECYCLE')?.trim();
|
|
191
|
+
if (allowProdLifecycle !== '1') {
|
|
192
|
+
throw new Error(productionLifecycleCommandError(command));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
175
195
|
async function assertEnvironmentRoot(cwd) {
|
|
176
196
|
try {
|
|
177
197
|
await access(join(cwd, markerPath));
|
|
@@ -194,6 +214,7 @@ export async function dailyActionPlan(command, argv, cwd = process.cwd()) {
|
|
|
194
214
|
await assertEnvironmentRoot(cwd);
|
|
195
215
|
const scriptPath = await assertScriptExists(cwd, dailyActionScripts[command]);
|
|
196
216
|
const args = scriptArgs(command, argv);
|
|
217
|
+
await assertProductionLifecycleCommandAllowed(command, cwd);
|
|
197
218
|
await assertDestructiveCommandAllowed(command, args, cwd);
|
|
198
219
|
return {
|
|
199
220
|
cwd,
|
package/dist/doctor.js
CHANGED
|
@@ -55,6 +55,16 @@ WITH metrics(metric, value) AS (
|
|
|
55
55
|
SELECT 'active_connections', count(*)::text
|
|
56
56
|
FROM pg_stat_activity
|
|
57
57
|
WHERE datname IS NOT NULL
|
|
58
|
+
AND state = 'active'
|
|
59
|
+
UNION ALL
|
|
60
|
+
SELECT 'connection_count', count(*)::text
|
|
61
|
+
FROM pg_stat_activity
|
|
62
|
+
WHERE datname IS NOT NULL
|
|
63
|
+
UNION ALL
|
|
64
|
+
SELECT 'max_connections', COALESCE(
|
|
65
|
+
(SELECT setting FROM pg_settings WHERE name = 'max_connections'),
|
|
66
|
+
'unavailable'
|
|
67
|
+
)
|
|
58
68
|
UNION ALL
|
|
59
69
|
SELECT 'total_database_size_bytes', COALESCE(sum(pg_database_size(datname)), 0)::text
|
|
60
70
|
FROM pg_database
|
|
@@ -82,16 +92,20 @@ FROM metrics
|
|
|
82
92
|
ORDER BY CASE metric
|
|
83
93
|
WHEN 'database_count' THEN 1
|
|
84
94
|
WHEN 'active_connections' THEN 2
|
|
85
|
-
WHEN '
|
|
86
|
-
WHEN '
|
|
87
|
-
WHEN '
|
|
88
|
-
WHEN '
|
|
95
|
+
WHEN 'connection_count' THEN 3
|
|
96
|
+
WHEN 'max_connections' THEN 4
|
|
97
|
+
WHEN 'total_database_size_bytes' THEN 5
|
|
98
|
+
WHEN 'slow_query_logging' THEN 6
|
|
99
|
+
WHEN 'pg_stat_statements' THEN 7
|
|
100
|
+
WHEN 'shared_buffers' THEN 8
|
|
89
101
|
ELSE 99
|
|
90
102
|
END;
|
|
91
103
|
`.trim();
|
|
92
104
|
const postgresDiagnosticKeys = [
|
|
93
105
|
'database_count',
|
|
94
106
|
'active_connections',
|
|
107
|
+
'connection_count',
|
|
108
|
+
'max_connections',
|
|
95
109
|
'total_database_size_bytes',
|
|
96
110
|
'slow_query_logging',
|
|
97
111
|
'pg_stat_statements',
|
|
@@ -126,27 +140,79 @@ function parsePostgresDiagnostics(output) {
|
|
|
126
140
|
return diagnostics;
|
|
127
141
|
}
|
|
128
142
|
function renderPostgresDiagnostics(diagnostics) {
|
|
143
|
+
const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
129
144
|
const parts = postgresDiagnosticKeys.flatMap((key) => {
|
|
130
145
|
const value = diagnostics[key];
|
|
131
|
-
|
|
146
|
+
const rendered = value ? [`${key}=${value}`] : [];
|
|
147
|
+
if (key === 'max_connections' && connectionUtilizationPct !== undefined) {
|
|
148
|
+
rendered.push(`connection_utilization_pct=${connectionUtilizationPct}`);
|
|
149
|
+
}
|
|
150
|
+
return rendered;
|
|
132
151
|
});
|
|
133
152
|
return parts.length > 0 ? `OK PostgreSQL diagnostics ${parts.join(' ')}` : undefined;
|
|
134
153
|
}
|
|
154
|
+
function missingPostgresDiagnosticKeys(diagnostics) {
|
|
155
|
+
return postgresDiagnosticKeys.filter((key) => !diagnostics[key]);
|
|
156
|
+
}
|
|
157
|
+
function unavailablePostgresDiagnosticsWarning(diagnostics, missingKeys) {
|
|
158
|
+
return Object.keys(diagnostics).length === 0
|
|
159
|
+
? 'no diagnostic rows returned'
|
|
160
|
+
: `incomplete diagnostic rows: missing ${missingKeys.join(', ')}`;
|
|
161
|
+
}
|
|
135
162
|
function integerDiagnostic(value) {
|
|
136
163
|
if (!value || !/^\d+$/u.test(value)) {
|
|
137
164
|
return undefined;
|
|
138
165
|
}
|
|
139
166
|
return Number.parseInt(value, 10);
|
|
140
167
|
}
|
|
168
|
+
function malformedPostgresDiagnosticKeys(diagnostics) {
|
|
169
|
+
const numericKeys = [
|
|
170
|
+
'database_count',
|
|
171
|
+
'active_connections',
|
|
172
|
+
'connection_count',
|
|
173
|
+
'max_connections',
|
|
174
|
+
'total_database_size_bytes',
|
|
175
|
+
];
|
|
176
|
+
return numericKeys.filter((key) => diagnostics[key] !== undefined && integerDiagnostic(diagnostics[key]) === undefined);
|
|
177
|
+
}
|
|
178
|
+
function postgresConnectionUtilizationPct(diagnostics) {
|
|
179
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
180
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
181
|
+
if (connectionCount === undefined || maxConnections === undefined || maxConnections <= 0) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
return Math.round((connectionCount / maxConnections) * 100);
|
|
185
|
+
}
|
|
186
|
+
function postgresConnectionUtilizationWarning(diagnostics) {
|
|
187
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
188
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
189
|
+
const utilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
190
|
+
if (connectionCount === undefined ||
|
|
191
|
+
maxConnections === undefined ||
|
|
192
|
+
utilizationPct === undefined ||
|
|
193
|
+
utilizationPct < 80) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return `PostgreSQL connection utilization is high: ${utilizationPct}% of max_connections used (${connectionCount}/${maxConnections}).`;
|
|
197
|
+
}
|
|
141
198
|
function structuredPostgresDiagnostics(diagnostics) {
|
|
142
199
|
const structured = {};
|
|
143
200
|
const databaseCount = integerDiagnostic(diagnostics.database_count);
|
|
144
201
|
const activeConnections = integerDiagnostic(diagnostics.active_connections);
|
|
202
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
203
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
204
|
+
const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
145
205
|
const totalDatabaseSizeBytes = integerDiagnostic(diagnostics.total_database_size_bytes);
|
|
146
206
|
if (databaseCount !== undefined)
|
|
147
207
|
structured.databaseCount = databaseCount;
|
|
148
208
|
if (activeConnections !== undefined)
|
|
149
209
|
structured.activeConnections = activeConnections;
|
|
210
|
+
if (connectionCount !== undefined)
|
|
211
|
+
structured.connectionCount = connectionCount;
|
|
212
|
+
if (maxConnections !== undefined)
|
|
213
|
+
structured.maxConnections = maxConnections;
|
|
214
|
+
if (connectionUtilizationPct !== undefined)
|
|
215
|
+
structured.connectionUtilizationPct = connectionUtilizationPct;
|
|
150
216
|
if (totalDatabaseSizeBytes !== undefined)
|
|
151
217
|
structured.totalDatabaseSizeBytes = totalDatabaseSizeBytes;
|
|
152
218
|
if (diagnostics.slow_query_logging)
|
|
@@ -555,22 +621,32 @@ export async function getDoctorReport(target = process.cwd(), runnerOrOptions =
|
|
|
555
621
|
if (actualOptions.postgres) {
|
|
556
622
|
try {
|
|
557
623
|
const postgresDiagnostics = await readPostgresDiagnostics(target, actualRunner);
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
624
|
+
const missingKeys = missingPostgresDiagnosticKeys(postgresDiagnostics);
|
|
625
|
+
const malformedKeys = malformedPostgresDiagnosticKeys(postgresDiagnostics);
|
|
626
|
+
if (missingKeys.length === 0 && malformedKeys.length === 0) {
|
|
627
|
+
const renderedPostgresDiagnostics = renderPostgresDiagnostics(postgresDiagnostics);
|
|
628
|
+
if (renderedPostgresDiagnostics) {
|
|
629
|
+
checks.push(renderedPostgresDiagnostics);
|
|
630
|
+
}
|
|
561
631
|
report.postgres = {
|
|
562
632
|
requested: true,
|
|
563
633
|
available: true,
|
|
564
634
|
diagnostics: structuredPostgresDiagnostics(postgresDiagnostics),
|
|
565
635
|
};
|
|
636
|
+
const connectionUtilizationWarning = postgresConnectionUtilizationWarning(postgresDiagnostics);
|
|
637
|
+
if (connectionUtilizationWarning) {
|
|
638
|
+
warnings.push(connectionUtilizationWarning);
|
|
639
|
+
}
|
|
566
640
|
}
|
|
567
641
|
else {
|
|
568
|
-
const warning =
|
|
642
|
+
const warning = malformedKeys.length > 0
|
|
643
|
+
? `malformed diagnostic values: ${malformedKeys.join(', ')}`
|
|
644
|
+
: unavailablePostgresDiagnosticsWarning(postgresDiagnostics, missingKeys);
|
|
569
645
|
warnings.push(`PostgreSQL diagnostics unavailable: ${warning}`);
|
|
570
646
|
report.postgres = {
|
|
571
647
|
requested: true,
|
|
572
648
|
available: false,
|
|
573
|
-
diagnostics:
|
|
649
|
+
diagnostics: structuredPostgresDiagnostics(postgresDiagnostics),
|
|
574
650
|
warning,
|
|
575
651
|
};
|
|
576
652
|
}
|
|
@@ -43,6 +43,8 @@ export function renderComposeEnvExample(options) {
|
|
|
43
43
|
'# Required only when intentionally running destructive database actions',
|
|
44
44
|
'# such as resetdb or restore-snapshot with WPMOO_ENV=stage or WPMOO_ENV=prod.',
|
|
45
45
|
'# WPMOO_ALLOW_DESTRUCTIVE=1',
|
|
46
|
+
'# Required only when intentionally running install/update/test in WPMOO_ENV=prod.',
|
|
47
|
+
'# WPMOO_ALLOW_PROD_LIFECYCLE=1',
|
|
46
48
|
'',
|
|
47
49
|
].join('\n');
|
|
48
50
|
}
|
package/dist/help.js
CHANGED
|
@@ -85,6 +85,11 @@ Daily actions:
|
|
|
85
85
|
Generated environments also include ./moo for local compose commands such as ./moo start.
|
|
86
86
|
Use ./moo or npx @wpmoo/toolkit with the same daily action arguments.
|
|
87
87
|
|
|
88
|
+
Production command guards:
|
|
89
|
+
In WPMOO_ENV=prod, install/update/test require WPMOO_ALLOW_PROD_LIFECYCLE=1.
|
|
90
|
+
resetdb and real restore-snapshot require WPMOO_ALLOW_DESTRUCTIVE=1 in stage/prod.
|
|
91
|
+
restore-snapshot --dry-run remains allowed for preview.
|
|
92
|
+
|
|
88
93
|
Cockpit:
|
|
89
94
|
Run npx @wpmoo/toolkit inside a generated environment to open the cockpit.
|
|
90
95
|
Use Command palette / to search slash commands across services, modules, database,
|
|
@@ -104,7 +109,10 @@ Status and doctor:
|
|
|
104
109
|
doctor: deeper health check. May check Docker CLI access and GitHub workflows.
|
|
105
110
|
doctor --fix: applies safe file-level repairs. Runs doctor again after fixes.
|
|
106
111
|
doctor --postgres: adds read-only PostgreSQL diagnostics such as database size,
|
|
107
|
-
|
|
112
|
+
sessions currently running queries with pg_stat_activity.state = 'active',
|
|
113
|
+
connection utilization against max_connections, slow-query readiness,
|
|
114
|
+
extension visibility, and settings.
|
|
115
|
+
Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
|
|
108
116
|
|
|
109
117
|
Task recipes:
|
|
110
118
|
Create environment:
|
|
@@ -148,6 +156,7 @@ Machine-readable JSON output:
|
|
|
148
156
|
npx @wpmoo/toolkit source sync --json
|
|
149
157
|
npx @wpmoo/toolkit doctor --json
|
|
150
158
|
doctor --json --postgres includes a structured postgres object for automation.
|
|
159
|
+
Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
|
|
151
160
|
|
|
152
161
|
Example:
|
|
153
162
|
npx @wpmoo/toolkit create \\
|
package/dist/templates.js
CHANGED
|
@@ -208,6 +208,10 @@ resources/odoo/entrypoint.sh
|
|
|
208
208
|
|
|
209
209
|
Development uses compose.yaml plus compose/dev.yaml by default.
|
|
210
210
|
Set WPMOO_ENV=stage or WPMOO_ENV=prod only after providing production-grade secrets and volumes.
|
|
211
|
+
In WPMOO_ENV=prod, module lifecycle commands such as install, update, and test
|
|
212
|
+
require WPMOO_ALLOW_PROD_LIFECYCLE=1. Destructive database commands such as
|
|
213
|
+
resetdb and real restore-snapshot require WPMOO_ALLOW_DESTRUCTIVE=1 in stage
|
|
214
|
+
and prod. restore-snapshot --dry-run remains available for preview.
|
|
211
215
|
|
|
212
216
|
If copied from the standalone resource, additional compose notes are in
|
|
213
217
|
\`docs/compose.md\`.
|
|
@@ -568,6 +572,23 @@ require_destructive_allowed() {
|
|
|
568
572
|
fi
|
|
569
573
|
}
|
|
570
574
|
|
|
575
|
+
allow_prod_lifecycle() {
|
|
576
|
+
local value="\${WPMOO_ALLOW_PROD_LIFECYCLE:-$(env_file_value WPMOO_ALLOW_PROD_LIFECYCLE)}"
|
|
577
|
+
[[ "$value" == "1" ]]
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
require_prod_lifecycle_allowed() {
|
|
581
|
+
local command="$1"
|
|
582
|
+
local env_name
|
|
583
|
+
env_name="$(selected_env)"
|
|
584
|
+
if [[ "$env_name" == "prod" ]]; then
|
|
585
|
+
if ! allow_prod_lifecycle; then
|
|
586
|
+
echo "Refusing production lifecycle command '$command' in WPMOO_ENV=prod. Set WPMOO_ALLOW_PROD_LIFECYCLE=1 to run it intentionally." >&2
|
|
587
|
+
exit 1
|
|
588
|
+
fi
|
|
589
|
+
fi
|
|
590
|
+
}
|
|
591
|
+
|
|
571
592
|
run_script() {
|
|
572
593
|
local script="$1"
|
|
573
594
|
shift
|
|
@@ -613,16 +634,19 @@ case "$command" in
|
|
|
613
634
|
"install")
|
|
614
635
|
shift
|
|
615
636
|
require_module_args "$command" "$@"
|
|
637
|
+
require_prod_lifecycle_allowed "$command"
|
|
616
638
|
run_script ./scripts/install.sh "$@"
|
|
617
639
|
;;
|
|
618
640
|
"update")
|
|
619
641
|
shift
|
|
620
642
|
require_module_args "$command" "$@"
|
|
643
|
+
require_prod_lifecycle_allowed "$command"
|
|
621
644
|
run_script ./scripts/update.sh "$@"
|
|
622
645
|
;;
|
|
623
646
|
"test")
|
|
624
647
|
shift
|
|
625
648
|
validate_test_args "$@"
|
|
649
|
+
require_prod_lifecycle_allowed "$command"
|
|
626
650
|
run_script ./scripts/test.sh "$@"
|
|
627
651
|
;;
|
|
628
652
|
"resetdb")
|
|
@@ -23,7 +23,7 @@ not validate staging or production deployments.
|
|
|
23
23
|
| Doctor checks | Metadata, compose files, scripts, source repo paths, and local tooling checks behave as expected. | `npx @wpmoo/toolkit doctor` or `./moo doctor` |
|
|
24
24
|
| Doctor safe fixes | Safe file-level fixes are applied only with `--fix`, then doctor runs again and reports any remaining manual issues. | `npx @wpmoo/toolkit doctor --fix` |
|
|
25
25
|
| Generated Postgres checks | For PostgreSQL 18 environments, doctor validates db mount targets avoid old PG image-specific paths and can normalize safe targets with `--fix`. | `npx @wpmoo/toolkit doctor`, `npx @wpmoo/toolkit doctor --fix` |
|
|
26
|
-
| PostgreSQL diagnostics | Optional read-only database health/performance diagnostics report database count, active
|
|
26
|
+
| PostgreSQL diagnostics | Optional read-only database health/performance diagnostics report database count, sessions currently running queries with `pg_stat_activity.state = 'active'`, total database size, slow-query readiness, extension visibility, and selected settings without failing doctor when the database is unavailable. | `npx @wpmoo/toolkit doctor --postgres`, `npx @wpmoo/toolkit doctor --json --postgres` |
|
|
27
27
|
| Source repo add/remove | Source repository registration and submodule lifecycle behave correctly. | `npx @wpmoo/toolkit add-repo ...`, `npx @wpmoo/toolkit remove-repo ...` |
|
|
28
28
|
| Source manifest sync | Source repo metadata, `.gitmodules`, and `odoo/custom/manifests/sources.yaml` stay aligned. | `npx @wpmoo/toolkit source list`, `npx @wpmoo/toolkit source sync` |
|
|
29
29
|
| Module add/remove | Module skeleton files include manifest, model, access CSV, explicit view XML, action/menu XML, post-install test scaffold, and selected source repo registration. Existing scaffold files are not overwritten. | `npx @wpmoo/toolkit add-module ...`, `npx @wpmoo/toolkit remove-module ...` |
|
|
@@ -53,6 +53,12 @@ scripts unless `.env` or the process environment explicitly sets
|
|
|
53
53
|
`WPMOO_ALLOW_DESTRUCTIVE=1`. `restore-snapshot --dry-run` remains allowed for
|
|
54
54
|
safe preview.
|
|
55
55
|
|
|
56
|
+
When `WPMOO_ENV=prod`, WPMoo also refuses module lifecycle commands that mutate
|
|
57
|
+
or exercise the Odoo database (`install`, `update`, and `test`) unless `.env` or
|
|
58
|
+
the process environment explicitly sets `WPMOO_ALLOW_PROD_LIFECYCLE=1`.
|
|
59
|
+
Staging keeps these commands available for release rehearsal while still
|
|
60
|
+
enforcing the destructive database guard above.
|
|
61
|
+
|
|
56
62
|
For PostgreSQL 18 environments (including `POSTGRES_IMAGE=postgres:18`), ensure db
|
|
57
63
|
volume and tmpfs mount targets use `/var/lib/postgresql` directly:
|
|
58
64
|
|
|
@@ -70,12 +76,16 @@ is involved, use PostgreSQL upgrade tooling first.
|
|
|
70
76
|
|
|
71
77
|
Use `doctor --postgres` when the database container is running and you want
|
|
72
78
|
read-only PostgreSQL diagnostics. The check uses fixed diagnostic queries for
|
|
73
|
-
database count,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
database count, sessions currently running queries where
|
|
80
|
+
`pg_stat_activity.state` is `active`, aggregate database size, slow-query
|
|
81
|
+
logging readiness,
|
|
82
|
+
`pg_stat_statements` availability, and `shared_buffers`. If the database is
|
|
83
|
+
unavailable, doctor reports a warning instead of failing the whole environment
|
|
84
|
+
check.
|
|
77
85
|
JSON output preserves `checks` and `warnings` while adding a structured
|
|
78
86
|
`postgres` object when `--postgres` is requested.
|
|
87
|
+
Incomplete or malformed PostgreSQL metric rows are reported as unavailable
|
|
88
|
+
diagnostics.
|
|
79
89
|
|
|
80
90
|
## Safe reset policy
|
|
81
91
|
|