querysub 0.716.0 → 0.718.0

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.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("typenode");
4
+ require("../src/deployManager/serviceConfigsPullMain");
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+
3
+ require("typenode");
4
+ require("../src/deployManager/serviceConfigsPushMain");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "querysub",
3
- "version": "0.716.0",
3
+ "version": "0.718.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
@@ -56,6 +56,8 @@
56
56
  "audit-imports": "./bin/audit-imports.js",
57
57
  "audit-disk-values": "./bin/audit-disk-values.js",
58
58
  "emergency-update": "./bin/emergency-update.js",
59
+ "service-configs-pull": "./bin/service-configs-pull.js",
60
+ "service-configs-push": "./bin/service-configs-push.js",
59
61
  "mcp-indexed-logs": "./bin/mcp-indexed-logs.js",
60
62
  "autofix": "./bin/autofix.js",
61
63
  "storageserve": "./bin/storageserve.js"
@@ -8,6 +8,10 @@ import { FindConfig } from "sliftutils/storage/IArchives";
8
8
 
9
9
  export const STORAGE_ACCOUNT = "root";
10
10
 
11
+ const STORE_NAME_HOSTNAMES: { [hostname: string]: string | undefined } = {
12
+ "99-255-70-23.querysubtest.com": "99-250-124-91.querysubtest.com",
13
+ };
14
+
11
15
 
12
16
  function createSourceWindows(
13
17
  overrides: Partial<RemoteConfigBase>,
@@ -60,7 +64,7 @@ function archiveBuilder(bucket: string, overrides: Partial<RemoteConfigBase>) {
60
64
  url: currentUrls[i],
61
65
  route: [routeStart, routeEnd],
62
66
  // IMPORTANT! name decides where our files are stored. We can't have two things writing to the same folder at the same time. But it also means if we reuse the name, then it has to be the same data.
63
- name: url.hostname.replaceAll(/[^a-z0-9-]/g, "_") + "_v" + config.routeVersion + "_" + routeStart + "_" + routeEnd,
67
+ name: (STORE_NAME_HOSTNAMES[url.hostname] || url.hostname).replaceAll(/[^a-z0-9-]/g, "_") + "_v" + config.routeVersion + "_" + routeStart + "_" + routeEnd,
64
68
  });
65
69
  }
66
70
  }
@@ -91,7 +95,7 @@ function archiveBuilder(bucket: string, overrides: Partial<RemoteConfigBase>) {
91
95
  ]);
92
96
 
93
97
  return createArchives({
94
- version: 30,
98
+ version: 31,
95
99
  sources,
96
100
  });
97
101
  }
@@ -0,0 +1,17 @@
1
+ import { STORAGE_DIR } from "../misc/appPaths";
2
+ import { ServiceConfig } from "./machineSchema";
3
+
4
+ export const SERVICE_CONFIGS_DIR = STORAGE_DIR + "service-configs/";
5
+
6
+ export function getServiceConfigFilePath(config: ServiceConfig): string {
7
+ let safeKey = config.parameters.key.replaceAll(/[^a-zA-Z0-9_-]/g, "_");
8
+ return `${SERVICE_CONFIGS_DIR}${safeKey}-${config.serviceId}.json`;
9
+ }
10
+
11
+ export function getDeployComparisonKey(config: ServiceConfig): string {
12
+ return JSON.stringify({
13
+ parameters: { ...config.parameters, releaseTime: undefined, overlapTime: undefined },
14
+ title: config.info.title,
15
+ notes: config.info.notes,
16
+ });
17
+ }
@@ -0,0 +1,40 @@
1
+ import "../inject";
2
+
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { pathToFileURL } from "url";
6
+ import { logErrors } from "../errors";
7
+ import { disablePathAuditer } from "../diagnostics/pathAuditerCallback";
8
+ import { green } from "socket-function/src/formatting/logColors";
9
+ import { MachineServiceControllerBase } from "./machineSchema";
10
+ import { SERVICE_CONFIGS_DIR, getServiceConfigFilePath } from "./serviceConfigsDisk";
11
+
12
+ async function main() {
13
+ disablePathAuditer();
14
+
15
+ let controller = new MachineServiceControllerBase();
16
+ let serviceIds = await controller.getServiceList();
17
+ await fs.promises.mkdir(SERVICE_CONFIGS_DIR, { recursive: true });
18
+
19
+ let existingFiles = new Set((await fs.promises.readdir(SERVICE_CONFIGS_DIR)).map(file => path.resolve(SERVICE_CONFIGS_DIR, file)));
20
+ let written = 0;
21
+ for (let serviceId of serviceIds) {
22
+ let config = await controller.getServiceConfig(serviceId);
23
+ if (!config) {
24
+ console.warn(`Service ${serviceId} is listed, but has no config, skipping it`);
25
+ continue;
26
+ }
27
+ let filePath = getServiceConfigFilePath(config);
28
+ existingFiles.delete(path.resolve(filePath));
29
+ await fs.promises.writeFile(filePath, JSON.stringify(config, undefined, 4));
30
+ console.log(`Wrote ${config.parameters.key} (${serviceId}) to ${pathToFileURL(filePath).href}`);
31
+ written++;
32
+ }
33
+ for (let staleFile of existingFiles) {
34
+ await fs.promises.unlink(staleFile);
35
+ console.log(`Removed ${pathToFileURL(staleFile).href}, as its service no longer exists`);
36
+ }
37
+ console.log(green(`Pulled ${written} service configs into ${pathToFileURL(path.resolve(SERVICE_CONFIGS_DIR)).href}. Edit them, then run service-configs-push.`));
38
+ }
39
+
40
+ main().catch(logErrors).finally(() => process.exit());
@@ -0,0 +1,63 @@
1
+ import "../inject";
2
+
3
+ import fs from "fs";
4
+ import yargs from "yargs";
5
+ import { pathToFileURL } from "url";
6
+ import { logErrors } from "../errors";
7
+ import { disablePathAuditer } from "../diagnostics/pathAuditerCallback";
8
+ import { delay } from "socket-function/src/batching";
9
+ import { formatDateTime, formatTime } from "socket-function/src/formatting/format";
10
+ import { green, magenta } from "socket-function/src/formatting/logColors";
11
+ import { DEFAULT_OVERLAP_TIME, MachineServiceControllerBase, ServiceConfig } from "./machineSchema";
12
+ import { SERVICE_CONFIGS_DIR, getDeployComparisonKey } from "./serviceConfigsDisk";
13
+
14
+ const NOTIFY_GRACE_PERIOD = 10 * 1000;
15
+
16
+ let args = yargs(process.argv)
17
+ .option("immediate", { type: "boolean", default: false, desc: "Deploy with no overlap, so the old instances are killed right away instead of running out the default overlap" })
18
+ .argv as { immediate: boolean };
19
+
20
+ async function main() {
21
+ disablePathAuditer();
22
+
23
+ let controller = new MachineServiceControllerBase();
24
+ let files = (await fs.promises.readdir(SERVICE_CONFIGS_DIR)).filter(file => file.endsWith(".json"));
25
+ let now = Date.now();
26
+ let overlapTime = args.immediate ? 0 : DEFAULT_OVERLAP_TIME;
27
+
28
+ let changed: ServiceConfig[] = [];
29
+ for (let file of files) {
30
+ let filePath = SERVICE_CONFIGS_DIR + file;
31
+ let contents = await fs.promises.readFile(filePath, "utf8");
32
+ let config = JSON.parse(contents) as ServiceConfig;
33
+ if (!config.serviceId) {
34
+ throw new Error(`Expected a serviceId in ${pathToFileURL(filePath).href}, was ${JSON.stringify(config.serviceId)}. Contents: ${contents.slice(0, 500)}`);
35
+ }
36
+ let current = await controller.getServiceConfig(config.serviceId);
37
+ if (!current) {
38
+ throw new Error(`Expected service ${config.serviceId} (from ${pathToFileURL(filePath).href}) to exist, it does not. Run service-configs-pull to resync the folder.`);
39
+ }
40
+ let before = getDeployComparisonKey(current);
41
+ let after = getDeployComparisonKey(config);
42
+ if (before === after) continue;
43
+ console.log(magenta(`${config.parameters.key} (${config.serviceId}) changed`));
44
+ console.log(` before: ${before}`);
45
+ console.log(` after: ${after}`);
46
+ config.parameters.releaseTime = now;
47
+ config.parameters.overlapTime = overlapTime;
48
+ changed.push(config);
49
+ }
50
+
51
+ if (changed.length === 0) {
52
+ console.log(green(`None of the ${files.length} service configs in ${pathToFileURL(SERVICE_CONFIGS_DIR).href} differ from what is deployed, nothing to push`));
53
+ return;
54
+ }
55
+
56
+ console.log(`Deploying ${changed.length} of ${files.length} service configs, releasing at ${formatDateTime(now)} with ${overlapTime ? `an overlap of ${formatTime(overlapTime)}` : "no overlap"}`);
57
+ await controller.setServiceConfigs(changed);
58
+ console.log(`Wrote ${changed.length} service configs, waiting for machine notifications to go out`);
59
+ await delay(NOTIFY_GRACE_PERIOD);
60
+ console.log(green(`Pushed ${changed.map(config => config.parameters.key).join(", ")}`));
61
+ }
62
+
63
+ main().catch(logErrors).finally(() => process.exit());