postgresai 0.17.0-dev.2 → 0.17.0-rc.2
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 +1 -1
- package/dist/bin/postgres-ai.js +141 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -250,7 +250,7 @@ postgresai mon health [--wait <sec>] # Check monitoring services health
|
|
|
250
250
|
|
|
251
251
|
When `--instance-id <uuid>` (or `PGAI_INSTANCE_ID`) is set, `local-install` forwards the id to the platform, which **adopts** the already-provisioned monitoring instance instead of self-registering a duplicate under an auto-created `postgres-ai-monitoring` project. The CLI then persists the adopted instance's real project to `.pgwatch-config`, so checkup reports upload alongside the rest of that instance's health data. Adoption is awaited (with one automatic retry); if it fails, the CLI warns and reports fall back to the default project until you re-run `local-install`. Without the flag, the legacy self-registration path is byte-for-byte unchanged.
|
|
252
252
|
|
|
253
|
-
`local-install` writes `.env` in the monitoring directory. It preserves existing `REPLICATOR_PASSWORD` and `
|
|
253
|
+
`local-install` writes `.env` in the monitoring directory. It preserves existing `REPLICATOR_PASSWORD`, `VM_AUTH_*` and the VictoriaMetrics admin-endpoint keys (`VM_DELETE_AUTH_KEY`, `VM_SNAPSHOT_AUTH_KEY`, `VM_FORCE_MERGE_AUTH_KEY`, `VM_PPROF_AUTH_KEY`, added in 0.17) or generates new random ones when missing. The admin keys live on the `sink-prometheus` command line, so `mon update` and `mon update-config` also recreate that container to apply them; `mon restart` (`docker compose restart`) does not; `VM_AUTH_USERNAME` defaults to `vmauth` when absent. The replication password is used by the demo PostgreSQL standby replication user, and the VM auth credentials are required before Docker Compose can provision Grafana datasources. If you run `docker compose` directly or maintain `.env` yourself, set both VM auth values before upgrading. For rotation, run `VM_AUTH_PASSWORD="$(openssl rand -base64 18)" ./scripts/rotate-vm-auth.sh` from the monitoring directory so `.env`, `sink-prometheus`, and `grafana` update together.
|
|
254
254
|
|
|
255
255
|
#### Monitoring target databases (`mon targets` subgroup)
|
|
256
256
|
```bash
|
package/dist/bin/postgres-ai.js
CHANGED
|
@@ -13524,7 +13524,7 @@ var {
|
|
|
13524
13524
|
// package.json
|
|
13525
13525
|
var package_default = {
|
|
13526
13526
|
name: "postgresai",
|
|
13527
|
-
version: "0.17.0-
|
|
13527
|
+
version: "0.17.0-rc.2",
|
|
13528
13528
|
description: "postgres_ai CLI",
|
|
13529
13529
|
license: "Apache-2.0",
|
|
13530
13530
|
private: false,
|
|
@@ -16884,7 +16884,7 @@ var Result = import_lib.default.Result;
|
|
|
16884
16884
|
var TypeOverrides = import_lib.default.TypeOverrides;
|
|
16885
16885
|
var defaults = import_lib.default.defaults;
|
|
16886
16886
|
// package.json
|
|
16887
|
-
var version = "0.17.0-
|
|
16887
|
+
var version = "0.17.0-rc.2";
|
|
16888
16888
|
var package_default2 = {
|
|
16889
16889
|
name: "postgresai",
|
|
16890
16890
|
version,
|
|
@@ -38701,47 +38701,101 @@ function stripMatchingQuotes(value) {
|
|
|
38701
38701
|
}
|
|
38702
38702
|
return trimmed;
|
|
38703
38703
|
}
|
|
38704
|
+
var VM_ADMIN_AUTH_KEYS = [
|
|
38705
|
+
"VM_DELETE_AUTH_KEY",
|
|
38706
|
+
"VM_SNAPSHOT_AUTH_KEY",
|
|
38707
|
+
"VM_FORCE_MERGE_AUTH_KEY",
|
|
38708
|
+
"VM_PPROF_AUTH_KEY"
|
|
38709
|
+
];
|
|
38704
38710
|
var REQUIRED_ENV_KEYS = [
|
|
38705
38711
|
{ key: "REPLICATOR_PASSWORD", defaultValue: () => crypto2.randomBytes(32).toString("hex"), introducedIn: "0.13" },
|
|
38706
38712
|
{ key: "VM_AUTH_USERNAME", defaultValue: () => "vmauth", introducedIn: "0.15" },
|
|
38707
|
-
{ key: "VM_AUTH_PASSWORD", defaultValue: () => crypto2.randomBytes(18).toString("base64"), introducedIn: "0.15" }
|
|
38713
|
+
{ key: "VM_AUTH_PASSWORD", defaultValue: () => crypto2.randomBytes(18).toString("base64"), introducedIn: "0.15" },
|
|
38714
|
+
{ key: "VM_DELETE_AUTH_KEY", defaultValue: () => crypto2.randomBytes(32).toString("hex"), introducedIn: "0.17" },
|
|
38715
|
+
{ key: "VM_SNAPSHOT_AUTH_KEY", defaultValue: () => crypto2.randomBytes(32).toString("hex"), introducedIn: "0.17" },
|
|
38716
|
+
{ key: "VM_FORCE_MERGE_AUTH_KEY", defaultValue: () => crypto2.randomBytes(32).toString("hex"), introducedIn: "0.17" },
|
|
38717
|
+
{ key: "VM_PPROF_AUTH_KEY", defaultValue: () => crypto2.randomBytes(32).toString("hex"), introducedIn: "0.17" }
|
|
38708
38718
|
];
|
|
38709
38719
|
function ensureRequiredEnvVars(projectDir) {
|
|
38710
38720
|
const envFile = path7.resolve(projectDir, ".env");
|
|
38711
38721
|
const existing = fs9.existsSync(envFile) ? fs9.readFileSync(envFile, "utf8") : "";
|
|
38712
38722
|
const added = [];
|
|
38713
38723
|
const appendLines = [];
|
|
38724
|
+
let content = existing;
|
|
38714
38725
|
for (const spec of REQUIRED_ENV_KEYS) {
|
|
38715
|
-
const
|
|
38716
|
-
if (!
|
|
38726
|
+
const present = new RegExp(`^[ ]*(?:export[ ]+)?${spec.key}=`, "m");
|
|
38727
|
+
if (!present.test(content)) {
|
|
38717
38728
|
appendLines.push(`${spec.key}=${spec.defaultValue()}`);
|
|
38718
38729
|
added.push(spec.key);
|
|
38730
|
+
continue;
|
|
38731
|
+
}
|
|
38732
|
+
if (VM_ADMIN_AUTH_KEYS.includes(spec.key)) {
|
|
38733
|
+
const blank = new RegExp(`^([ ]*(?:export[ ]+)?${spec.key}=)[ ]*(?:""|'')?[ ]*\r?$`, "gm");
|
|
38734
|
+
if (blank.test(content)) {
|
|
38735
|
+
const value = spec.defaultValue();
|
|
38736
|
+
content = content.replace(blank, (_match, prefix) => `${prefix}${value}`);
|
|
38737
|
+
added.push(spec.key);
|
|
38738
|
+
}
|
|
38719
38739
|
}
|
|
38720
38740
|
}
|
|
38721
|
-
if (appendLines.length === 0) {
|
|
38741
|
+
if (appendLines.length === 0 && content === existing) {
|
|
38722
38742
|
return added;
|
|
38723
38743
|
}
|
|
38724
|
-
const needsTrailingNewline =
|
|
38744
|
+
const needsTrailingNewline = content.length > 0 && !content.endsWith(`
|
|
38725
38745
|
`);
|
|
38726
|
-
const newContent =
|
|
38727
|
-
` : "") + appendLines.join(`
|
|
38746
|
+
const newContent = content + (needsTrailingNewline ? `
|
|
38747
|
+
` : "") + (appendLines.length > 0 ? appendLines.join(`
|
|
38728
38748
|
`) + `
|
|
38729
|
-
|
|
38730
|
-
|
|
38749
|
+
` : "");
|
|
38750
|
+
writeEnvFile(envFile, newContent);
|
|
38731
38751
|
return added;
|
|
38732
38752
|
}
|
|
38753
|
+
function writeEnvFile(envFile, content) {
|
|
38754
|
+
let targetFile = envFile;
|
|
38755
|
+
try {
|
|
38756
|
+
if (fs9.existsSync(envFile))
|
|
38757
|
+
targetFile = fs9.realpathSync(envFile);
|
|
38758
|
+
} catch {}
|
|
38759
|
+
const tmpFile = `${targetFile}.tmp`;
|
|
38760
|
+
fs9.writeFileSync(tmpFile, content, { encoding: "utf8", mode: 384 });
|
|
38761
|
+
try {
|
|
38762
|
+
fs9.chmodSync(tmpFile, 384);
|
|
38763
|
+
if (fs9.existsSync(targetFile)) {
|
|
38764
|
+
const st = fs9.statSync(targetFile);
|
|
38765
|
+
fs9.chownSync(tmpFile, st.uid, st.gid);
|
|
38766
|
+
}
|
|
38767
|
+
} catch {}
|
|
38768
|
+
try {
|
|
38769
|
+
fs9.renameSync(tmpFile, targetFile);
|
|
38770
|
+
} catch (error) {
|
|
38771
|
+
try {
|
|
38772
|
+
fs9.unlinkSync(tmpFile);
|
|
38773
|
+
} catch {}
|
|
38774
|
+
throw error;
|
|
38775
|
+
}
|
|
38776
|
+
}
|
|
38733
38777
|
var LOCAL_INSTALL_MANAGED_ENV_KEYS = [
|
|
38734
38778
|
"PGAI_TAG",
|
|
38735
38779
|
"PGAI_REGISTRY",
|
|
38736
38780
|
"GF_SECURITY_ADMIN_PASSWORD",
|
|
38737
38781
|
"REPLICATOR_PASSWORD",
|
|
38738
38782
|
"VM_AUTH_USERNAME",
|
|
38739
|
-
"VM_AUTH_PASSWORD"
|
|
38783
|
+
"VM_AUTH_PASSWORD",
|
|
38784
|
+
"VM_DELETE_AUTH_KEY",
|
|
38785
|
+
"VM_SNAPSHOT_AUTH_KEY",
|
|
38786
|
+
"VM_FORCE_MERGE_AUTH_KEY",
|
|
38787
|
+
"VM_PPROF_AUTH_KEY"
|
|
38740
38788
|
];
|
|
38741
38789
|
function buildLocalInstallEnv(existingEnv, imageTag) {
|
|
38742
38790
|
const readRaw = (key) => {
|
|
38743
|
-
const
|
|
38744
|
-
|
|
38791
|
+
const re = new RegExp(`^[ ]*(?:export[ ]+)?${key}=(.*)$`, "gm");
|
|
38792
|
+
let value = null;
|
|
38793
|
+
for (const m of existingEnv.matchAll(re)) {
|
|
38794
|
+
value = m[1].trim();
|
|
38795
|
+
}
|
|
38796
|
+
if (value === null)
|
|
38797
|
+
return null;
|
|
38798
|
+
return stripMatchingQuotes(value) === "" ? null : value;
|
|
38745
38799
|
};
|
|
38746
38800
|
const envLines = [`PGAI_TAG=${imageTag}`];
|
|
38747
38801
|
const registry = readRaw("PGAI_REGISTRY");
|
|
@@ -38756,11 +38810,15 @@ function buildLocalInstallEnv(existingEnv, imageTag) {
|
|
|
38756
38810
|
envLines.push(`VM_AUTH_USERNAME=${vmAuthUsername ? stripMatchingQuotes(vmAuthUsername) : "vmauth"}`);
|
|
38757
38811
|
const vmAuthPassword = readRaw("VM_AUTH_PASSWORD");
|
|
38758
38812
|
envLines.push(`VM_AUTH_PASSWORD=${vmAuthPassword ? stripMatchingQuotes(vmAuthPassword) : crypto2.randomBytes(18).toString("base64")}`);
|
|
38813
|
+
for (const key of VM_ADMIN_AUTH_KEYS) {
|
|
38814
|
+
const existing = readRaw(key);
|
|
38815
|
+
envLines.push(`${key}=${existing ? stripMatchingQuotes(existing) : crypto2.randomBytes(32).toString("hex")}`);
|
|
38816
|
+
}
|
|
38759
38817
|
const preservedKeys = [];
|
|
38760
38818
|
for (const line of existingEnv.split(/\r?\n/)) {
|
|
38761
38819
|
if (!line.trim())
|
|
38762
38820
|
continue;
|
|
38763
|
-
const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)=/);
|
|
38821
|
+
const m = line.match(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=/);
|
|
38764
38822
|
if (m) {
|
|
38765
38823
|
if (LOCAL_INSTALL_MANAGED_ENV_KEYS.includes(m[1]))
|
|
38766
38824
|
continue;
|
|
@@ -38772,9 +38830,9 @@ function buildLocalInstallEnv(existingEnv, imageTag) {
|
|
|
38772
38830
|
`) + `
|
|
38773
38831
|
`, preservedKeys };
|
|
38774
38832
|
}
|
|
38775
|
-
async function execFilePromise(file, args) {
|
|
38833
|
+
async function execFilePromise(file, args, options = {}) {
|
|
38776
38834
|
return new Promise((resolve, reject) => {
|
|
38777
|
-
childProcess.execFile(file, args, (error, stdout, stderr) => {
|
|
38835
|
+
childProcess.execFile(file, args, options, (error, stdout, stderr) => {
|
|
38778
38836
|
if (error) {
|
|
38779
38837
|
const err = error;
|
|
38780
38838
|
err.code = typeof error.code === "number" ? error.code : 1;
|
|
@@ -40513,6 +40571,12 @@ function isDockerRunning() {
|
|
|
40513
40571
|
return false;
|
|
40514
40572
|
}
|
|
40515
40573
|
}
|
|
40574
|
+
function shouldScaleOutNodeExporter(args) {
|
|
40575
|
+
const upIndex = args.indexOf("up");
|
|
40576
|
+
if (upIndex === -1)
|
|
40577
|
+
return false;
|
|
40578
|
+
return !args.slice(upIndex + 1).some((a) => !a.startsWith("-"));
|
|
40579
|
+
}
|
|
40516
40580
|
function getComposeCmd() {
|
|
40517
40581
|
const tryCmd = (cmd, args) => spawnSync2(cmd, args, { stdio: "ignore", timeout: 5000 }).status === 0;
|
|
40518
40582
|
if (tryCmd("docker", ["compose", "version"]))
|
|
@@ -40725,7 +40789,7 @@ async function runCompose(args, grafanaPassword) {
|
|
|
40725
40789
|
}
|
|
40726
40790
|
}
|
|
40727
40791
|
const finalArgs = [...args];
|
|
40728
|
-
if (process.platform === "darwin" && args
|
|
40792
|
+
if (process.platform === "darwin" && shouldScaleOutNodeExporter(args)) {
|
|
40729
40793
|
finalArgs.push("--scale", "self-node-exporter=0");
|
|
40730
40794
|
}
|
|
40731
40795
|
return new Promise((resolve) => {
|
|
@@ -40737,6 +40801,51 @@ async function runCompose(args, grafanaPassword) {
|
|
|
40737
40801
|
child.on("close", (code) => resolve(code || 0));
|
|
40738
40802
|
});
|
|
40739
40803
|
}
|
|
40804
|
+
async function applySinkPrometheusConfig(projectDir) {
|
|
40805
|
+
const composeCmd = getComposeCmd();
|
|
40806
|
+
if (!composeCmd) {
|
|
40807
|
+
console.error(`
|
|
40808
|
+
\u2717 docker compose not found, so the sink-prometheus config was not applied.`);
|
|
40809
|
+
return false;
|
|
40810
|
+
}
|
|
40811
|
+
let running;
|
|
40812
|
+
try {
|
|
40813
|
+
const { stdout } = await execFilePromise(composeCmd[0], [
|
|
40814
|
+
...composeCmd.slice(1),
|
|
40815
|
+
"-f",
|
|
40816
|
+
path7.resolve(projectDir, "docker-compose.yml"),
|
|
40817
|
+
"ps",
|
|
40818
|
+
"-q",
|
|
40819
|
+
"sink-prometheus"
|
|
40820
|
+
], { cwd: projectDir });
|
|
40821
|
+
running = stdout.trim().length > 0;
|
|
40822
|
+
} catch (error) {
|
|
40823
|
+
console.error(`
|
|
40824
|
+
\u2717 Could not determine whether sink-prometheus is running.`);
|
|
40825
|
+
console.error(" The admin-endpoint keys may NOT be in effect. To apply them:");
|
|
40826
|
+
console.error(" docker compose up -d --no-deps sink-prometheus");
|
|
40827
|
+
if (process.env.DEBUG) {
|
|
40828
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
40829
|
+
}
|
|
40830
|
+
return false;
|
|
40831
|
+
}
|
|
40832
|
+
if (!running) {
|
|
40833
|
+
console.log(`
|
|
40834
|
+
(sink-prometheus is not running - the new config applies when you start the stack)`);
|
|
40835
|
+
return true;
|
|
40836
|
+
}
|
|
40837
|
+
console.log(`
|
|
40838
|
+
Applying sink-prometheus config (VictoriaMetrics admin keys, #359)...`);
|
|
40839
|
+
const code = await runCompose(["up", "-d", "--no-deps", "sink-prometheus"]);
|
|
40840
|
+
if (code !== 0) {
|
|
40841
|
+
console.error("\u2717 Could not apply the sink-prometheus config.");
|
|
40842
|
+
console.error(" The admin-endpoint keys are NOT in effect until you run:");
|
|
40843
|
+
console.error(" docker compose up -d --no-deps sink-prometheus");
|
|
40844
|
+
return false;
|
|
40845
|
+
}
|
|
40846
|
+
console.log("\u2713 sink-prometheus is running the current config");
|
|
40847
|
+
return true;
|
|
40848
|
+
}
|
|
40740
40849
|
program2.command("help").description("show help").action(() => {
|
|
40741
40850
|
program2.outputHelp();
|
|
40742
40851
|
});
|
|
@@ -40775,7 +40884,7 @@ mon.command("local-install").description("install local monitoring stack (genera
|
|
|
40775
40884
|
const previousTag = previousTagMatch ? previousTagMatch[1].trim() : null;
|
|
40776
40885
|
const imageTag = opts.tag || package_default.version;
|
|
40777
40886
|
const { content: envContent, preservedKeys } = buildLocalInstallEnv(existingEnv, imageTag);
|
|
40778
|
-
|
|
40887
|
+
writeEnvFile(envFile, envContent);
|
|
40779
40888
|
if (preservedKeys.length > 0) {
|
|
40780
40889
|
console.log(`Preserved existing .env settings: ${preservedKeys.join(", ")}
|
|
40781
40890
|
`);
|
|
@@ -41071,9 +41180,9 @@ Searched: ${demoCandidates.join(", ")}
|
|
|
41071
41180
|
const envLines = envContent.split(/\r?\n/).filter((l) => !/^VM_AUTH_USERNAME=/.test(l) && !/^VM_AUTH_PASSWORD=/.test(l)).filter((l, i, arr) => !(i === arr.length - 1 && l === ""));
|
|
41072
41181
|
envLines.push(`VM_AUTH_USERNAME=${vmAuthUsername}`);
|
|
41073
41182
|
envLines.push(`VM_AUTH_PASSWORD=${vmAuthPassword}`);
|
|
41074
|
-
|
|
41183
|
+
writeEnvFile(envFile, envLines.join(`
|
|
41075
41184
|
`) + `
|
|
41076
|
-
|
|
41185
|
+
`);
|
|
41077
41186
|
}
|
|
41078
41187
|
console.log(`\u2713 VictoriaMetrics auth configured
|
|
41079
41188
|
`);
|
|
@@ -41374,8 +41483,13 @@ mon.command("update-config").description("apply monitoring services configuratio
|
|
|
41374
41483
|
}
|
|
41375
41484
|
await refreshBundledComposeIfStale(projectDir);
|
|
41376
41485
|
const code = await runCompose(["run", "--rm", "sources-generator"]);
|
|
41377
|
-
if (code !== 0)
|
|
41486
|
+
if (code !== 0) {
|
|
41378
41487
|
process.exitCode = code;
|
|
41488
|
+
return;
|
|
41489
|
+
}
|
|
41490
|
+
if (!await applySinkPrometheusConfig(projectDir)) {
|
|
41491
|
+
process.exitCode = 1;
|
|
41492
|
+
}
|
|
41379
41493
|
});
|
|
41380
41494
|
mon.command("update").description("update monitoring stack (migrate .env, pull images)").action(async () => {
|
|
41381
41495
|
console.log(`Updating PostgresAI monitoring stack...
|
|
@@ -41417,6 +41531,10 @@ mon.command("update").description("update monitoring stack (migrate .env, pull i
|
|
|
41417
41531
|
Updating Docker images...`);
|
|
41418
41532
|
const code = await runCompose(["pull"]);
|
|
41419
41533
|
if (code === 0) {
|
|
41534
|
+
if (!await applySinkPrometheusConfig(projectDir)) {
|
|
41535
|
+
process.exitCode = 1;
|
|
41536
|
+
return;
|
|
41537
|
+
}
|
|
41420
41538
|
console.log(`
|
|
41421
41539
|
\u2713 Update completed successfully`);
|
|
41422
41540
|
console.log(`
|
|
@@ -43402,5 +43520,6 @@ export {
|
|
|
43402
43520
|
refreshBundledComposeIfStale,
|
|
43403
43521
|
registerMonitoringInstance,
|
|
43404
43522
|
resolveAdoptedProject,
|
|
43523
|
+
shouldScaleOutNodeExporter,
|
|
43405
43524
|
updatePgwatchConfig
|
|
43406
43525
|
};
|