@calltelemetry/cli 0.6.11 → 0.6.13

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.
Files changed (103) hide show
  1. package/dist/commands/appliance.d.ts +3 -0
  2. package/dist/commands/appliance.d.ts.map +1 -0
  3. package/dist/commands/appliance.js +99 -0
  4. package/dist/commands/appliance.js.map +1 -0
  5. package/dist/commands/update.d.ts.map +1 -1
  6. package/dist/commands/update.js +19 -17
  7. package/dist/commands/update.js.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/bundle.d.ts.map +1 -1
  11. package/dist/lib/bundle.js +12 -1
  12. package/dist/lib/bundle.js.map +1 -1
  13. package/dist/lib/migration-001-cgnat.d.ts +2 -0
  14. package/dist/lib/migration-001-cgnat.d.ts.map +1 -0
  15. package/dist/lib/migration-001-cgnat.js +59 -0
  16. package/dist/lib/migration-001-cgnat.js.map +1 -0
  17. package/dist/lib/migration-002-swap.d.ts +12 -0
  18. package/dist/lib/migration-002-swap.d.ts.map +1 -0
  19. package/dist/lib/migration-002-swap.js +103 -0
  20. package/dist/lib/migration-002-swap.js.map +1 -0
  21. package/dist/lib/migration-003-nm-heal.d.ts +12 -0
  22. package/dist/lib/migration-003-nm-heal.d.ts.map +1 -0
  23. package/dist/lib/migration-003-nm-heal.js +75 -0
  24. package/dist/lib/migration-003-nm-heal.js.map +1 -0
  25. package/dist/lib/migration-004-systemd-docker.d.ts +13 -0
  26. package/dist/lib/migration-004-systemd-docker.d.ts.map +1 -0
  27. package/dist/lib/migration-004-systemd-docker.js +48 -0
  28. package/dist/lib/migration-004-systemd-docker.js.map +1 -0
  29. package/dist/lib/migration-005-ssh-keys.d.ts +13 -0
  30. package/dist/lib/migration-005-ssh-keys.d.ts.map +1 -0
  31. package/dist/lib/migration-005-ssh-keys.js +49 -0
  32. package/dist/lib/migration-005-ssh-keys.js.map +1 -0
  33. package/dist/lib/migration-006-console-loglevel.d.ts +10 -0
  34. package/dist/lib/migration-006-console-loglevel.d.ts.map +1 -0
  35. package/dist/lib/migration-006-console-loglevel.js +27 -0
  36. package/dist/lib/migration-006-console-loglevel.js.map +1 -0
  37. package/dist/lib/migration-007-nm-keyfile.d.ts +10 -0
  38. package/dist/lib/migration-007-nm-keyfile.d.ts.map +1 -0
  39. package/dist/lib/migration-007-nm-keyfile.js +30 -0
  40. package/dist/lib/migration-007-nm-keyfile.js.map +1 -0
  41. package/dist/lib/migration-008-systemd-restart.d.ts +13 -0
  42. package/dist/lib/migration-008-systemd-restart.d.ts.map +1 -0
  43. package/dist/lib/migration-008-systemd-restart.js +41 -0
  44. package/dist/lib/migration-008-systemd-restart.js.map +1 -0
  45. package/dist/lib/migration-009-bind-mount-files.d.ts +11 -0
  46. package/dist/lib/migration-009-bind-mount-files.d.ts.map +1 -0
  47. package/dist/lib/migration-009-bind-mount-files.js +86 -0
  48. package/dist/lib/migration-009-bind-mount-files.js.map +1 -0
  49. package/dist/lib/migration-010-jtapi-state.d.ts +11 -0
  50. package/dist/lib/migration-010-jtapi-state.d.ts.map +1 -0
  51. package/dist/lib/migration-010-jtapi-state.js +61 -0
  52. package/dist/lib/migration-010-jtapi-state.js.map +1 -0
  53. package/dist/lib/migration-011-docker-memory-limit.d.ts +13 -0
  54. package/dist/lib/migration-011-docker-memory-limit.d.ts.map +1 -0
  55. package/dist/lib/migration-011-docker-memory-limit.js +45 -0
  56. package/dist/lib/migration-011-docker-memory-limit.js.map +1 -0
  57. package/dist/lib/migration-012-db-pool-sizes.d.ts +12 -0
  58. package/dist/lib/migration-012-db-pool-sizes.d.ts.map +1 -0
  59. package/dist/lib/migration-012-db-pool-sizes.js +64 -0
  60. package/dist/lib/migration-012-db-pool-sizes.js.map +1 -0
  61. package/dist/lib/migrations.d.ts +34 -0
  62. package/dist/lib/migrations.d.ts.map +1 -0
  63. package/dist/lib/migrations.js +179 -0
  64. package/dist/lib/migrations.js.map +1 -0
  65. package/dist/lib/update-steps.d.ts.map +1 -1
  66. package/dist/lib/update-steps.js +12 -0
  67. package/dist/lib/update-steps.js.map +1 -1
  68. package/dist/lib/version.d.ts +1 -1
  69. package/dist/lib/version.js +1 -1
  70. package/dist/shell/commands/appliance-performance.d.ts +36 -0
  71. package/dist/shell/commands/appliance-performance.d.ts.map +1 -0
  72. package/dist/shell/commands/appliance-performance.js +221 -0
  73. package/dist/shell/commands/appliance-performance.js.map +1 -0
  74. package/dist/shell/commands/registry.d.ts.map +1 -1
  75. package/dist/shell/commands/registry.js +19 -0
  76. package/dist/shell/commands/registry.js.map +1 -1
  77. package/dist/shell/commands/users.d.ts.map +1 -1
  78. package/dist/shell/commands/users.js +42 -1
  79. package/dist/shell/commands/users.js.map +1 -1
  80. package/dist/shell/network-onboarding.d.ts +29 -7
  81. package/dist/shell/network-onboarding.d.ts.map +1 -1
  82. package/dist/shell/network-onboarding.js +332 -81
  83. package/dist/shell/network-onboarding.js.map +1 -1
  84. package/dist/ui/views/JtapiDisableView.d.ts +6 -0
  85. package/dist/ui/views/JtapiDisableView.d.ts.map +1 -0
  86. package/dist/ui/views/JtapiDisableView.js +52 -0
  87. package/dist/ui/views/JtapiDisableView.js.map +1 -0
  88. package/dist/ui/views/JtapiEnableView.d.ts +6 -0
  89. package/dist/ui/views/JtapiEnableView.d.ts.map +1 -0
  90. package/dist/ui/views/JtapiEnableView.js +40 -0
  91. package/dist/ui/views/JtapiEnableView.js.map +1 -0
  92. package/dist/ui/views/JtapiStatusView.d.ts +6 -0
  93. package/dist/ui/views/JtapiStatusView.d.ts.map +1 -0
  94. package/dist/ui/views/JtapiStatusView.js +11 -0
  95. package/dist/ui/views/JtapiStatusView.js.map +1 -0
  96. package/dist/ui/views/JtapiTroubleshootView.d.ts +6 -0
  97. package/dist/ui/views/JtapiTroubleshootView.d.ts.map +1 -0
  98. package/dist/ui/views/JtapiTroubleshootView.js +114 -0
  99. package/dist/ui/views/JtapiTroubleshootView.js.map +1 -0
  100. package/dist/ui/views/MainMenu.d.ts.map +1 -1
  101. package/dist/ui/views/MainMenu.js +11 -0
  102. package/dist/ui/views/MainMenu.js.map +1 -1
  103. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Migration 003: Fix NetworkManager connection profiles.
3
+ *
4
+ * OVA images sometimes ship with `permissions=user:root:;` or
5
+ * `autoconnect=false` in NM connection profiles, which prevents
6
+ * auto-connect on boot and breaks DNS resolution after reboot.
7
+ *
8
+ * Previously a self-healing check in cli.sh that ran on every invocation.
9
+ * Now a one-time migration.
10
+ */
11
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
12
+ import { spawnSync } from 'node:child_process';
13
+ import { join } from 'node:path';
14
+ const NM_CONNECTIONS_DIR = '/etc/NetworkManager/system-connections';
15
+ const NM_DOCKER_CONF = '/etc/NetworkManager/conf.d/docker-unmanaged.conf';
16
+ export async function migrateNmHeal() {
17
+ // Skip if NetworkManager isn't installed
18
+ try {
19
+ const which = spawnSync('which', ['nmcli'], { stdio: 'pipe' });
20
+ if (which.status !== 0)
21
+ return false;
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ let changed = false;
27
+ // Fix 1: Remove `permissions=user:root:;` and fix `autoconnect=false`
28
+ if (existsSync(NM_CONNECTIONS_DIR)) {
29
+ try {
30
+ const files = readdirSync(NM_CONNECTIONS_DIR).filter(f => f.endsWith('.nmconnection'));
31
+ for (const file of files) {
32
+ const path = join(NM_CONNECTIONS_DIR, file);
33
+ try {
34
+ const content = readFileSync(path, 'utf-8');
35
+ if (content.includes('permissions=user:root:;') || content.includes('autoconnect=false')) {
36
+ let patched = content
37
+ .replace(/permissions=user:root:;\n?/g, '')
38
+ .replace(/autoconnect=false/g, 'autoconnect=true');
39
+ // Write via sudo
40
+ const tmp = `/tmp/ct-nm-fix-${Date.now()}.nmconnection`;
41
+ require('node:fs').writeFileSync(tmp, patched);
42
+ spawnSync('sudo', ['cp', tmp, path], { stdio: 'pipe' });
43
+ spawnSync('sudo', ['chmod', '600', path], { stdio: 'pipe' });
44
+ try {
45
+ require('node:fs').unlinkSync(tmp);
46
+ }
47
+ catch { /* ignore */ }
48
+ changed = true;
49
+ }
50
+ }
51
+ catch { /* skip unreadable files */ }
52
+ }
53
+ }
54
+ catch { /* dir not readable */ }
55
+ }
56
+ // Fix 2: Add Docker bridge unmanaged-devices rule
57
+ if (!existsSync(NM_DOCKER_CONF)) {
58
+ const content = '[keyfile]\nunmanaged-devices=interface-name:docker*;interface-name:br-*;interface-name:veth*\n';
59
+ const tmp = `/tmp/ct-nm-docker-${Date.now()}.conf`;
60
+ require('node:fs').writeFileSync(tmp, content);
61
+ spawnSync('sudo', ['mkdir', '-p', '/etc/NetworkManager/conf.d'], { stdio: 'pipe' });
62
+ spawnSync('sudo', ['cp', tmp, NM_DOCKER_CONF], { stdio: 'pipe' });
63
+ try {
64
+ require('node:fs').unlinkSync(tmp);
65
+ }
66
+ catch { /* ignore */ }
67
+ changed = true;
68
+ }
69
+ // Reload NM if anything changed
70
+ if (changed) {
71
+ spawnSync('sudo', ['nmcli', 'connection', 'reload'], { stdio: 'pipe' });
72
+ }
73
+ return changed;
74
+ }
75
+ //# sourceMappingURL=migration-003-nm-heal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-003-nm-heal.js","sourceRoot":"","sources":["../../src/lib/migration-003-nm-heal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 004: Harden Docker systemd boot ordering.
3
+ *
4
+ * Ensures Docker starts AFTER firewalld is fully ready. Without this,
5
+ * Docker races firewalld at boot and gets ZONE_CONFLICT errors, which
6
+ * can cause container networking to fail until manual restart.
7
+ *
8
+ * Creates /etc/systemd/system/docker.service.d/override.conf with:
9
+ * After=network-online.target firewalld.service
10
+ * Wants=network-online.target
11
+ */
12
+ export declare function migrateSystemdDocker(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-004-systemd-docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-004-systemd-docker.d.ts","sourceRoot":"","sources":["../../src/lib/migration-004-systemd-docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CA4B7D"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Migration 004: Harden Docker systemd boot ordering.
3
+ *
4
+ * Ensures Docker starts AFTER firewalld is fully ready. Without this,
5
+ * Docker races firewalld at boot and gets ZONE_CONFLICT errors, which
6
+ * can cause container networking to fail until manual restart.
7
+ *
8
+ * Creates /etc/systemd/system/docker.service.d/override.conf with:
9
+ * After=network-online.target firewalld.service
10
+ * Wants=network-online.target
11
+ */
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const OVERRIDE_DIR = '/etc/systemd/system/docker.service.d';
15
+ const OVERRIDE_FILE = `${OVERRIDE_DIR}/override.conf`;
16
+ const EXPECTED_CONTENT = `[Unit]
17
+ After=network-online.target firewalld.service
18
+ Wants=network-online.target
19
+ `;
20
+ export async function migrateSystemdDocker() {
21
+ // Check if override already exists with correct content
22
+ if (existsSync(OVERRIDE_FILE)) {
23
+ try {
24
+ const current = readFileSync(OVERRIDE_FILE, 'utf-8');
25
+ if (current.includes('firewalld.service')) {
26
+ return false; // Already correct
27
+ }
28
+ }
29
+ catch { /* unreadable — recreate */ }
30
+ }
31
+ // Create override directory
32
+ spawnSync('sudo', ['mkdir', '-p', OVERRIDE_DIR], { stdio: 'pipe' });
33
+ // Write override file via sudo
34
+ const tmp = `/tmp/ct-systemd-override-${Date.now()}.conf`;
35
+ require('node:fs').writeFileSync(tmp, EXPECTED_CONTENT);
36
+ const cp = spawnSync('sudo', ['cp', tmp, OVERRIDE_FILE], { stdio: 'pipe' });
37
+ try {
38
+ require('node:fs').unlinkSync(tmp);
39
+ }
40
+ catch { /* ignore */ }
41
+ if (cp.status !== 0) {
42
+ throw new Error(`Failed to write ${OVERRIDE_FILE}`);
43
+ }
44
+ // Reload systemd
45
+ spawnSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe' });
46
+ return true;
47
+ }
48
+ //# sourceMappingURL=migration-004-systemd-docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-004-systemd-docker.js","sourceRoot":"","sources":["../../src/lib/migration-004-systemd-docker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAC5D,MAAM,aAAa,GAAG,GAAG,YAAY,gBAAgB,CAAC;AACtD,MAAM,gBAAgB,GAAG;;;CAGxB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,wDAAwD;IACxD,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACrD,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC,CAAC,kBAAkB;YAClC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,2BAA2B,CAAC,CAAC;IACzC,CAAC;IAED,4BAA4B;IAC5B,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEpE,+BAA+B;IAC/B,MAAM,GAAG,GAAG,4BAA4B,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;IAC1D,OAAO,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IACxD,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,mBAAmB,aAAa,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,iBAAiB;IACjB,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAErE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 005: Regenerate SSH host keys.
3
+ *
4
+ * OVA clones share the same SSH host keys from the template build,
5
+ * enabling MITM attacks between appliances. This migration regenerates
6
+ * unique host keys for each appliance.
7
+ *
8
+ * Only runs if the key fingerprint matches a known OVA template
9
+ * fingerprint, or if a sentinel file indicates keys haven't been
10
+ * regenerated since OVA deployment.
11
+ */
12
+ export declare function migrateSshKeys(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-005-ssh-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-005-ssh-keys.d.ts","sourceRoot":"","sources":["../../src/lib/migration-005-ssh-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAmCvD"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Migration 005: Regenerate SSH host keys.
3
+ *
4
+ * OVA clones share the same SSH host keys from the template build,
5
+ * enabling MITM attacks between appliances. This migration regenerates
6
+ * unique host keys for each appliance.
7
+ *
8
+ * Only runs if the key fingerprint matches a known OVA template
9
+ * fingerprint, or if a sentinel file indicates keys haven't been
10
+ * regenerated since OVA deployment.
11
+ */
12
+ import { existsSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const SSH_REGEN_SENTINEL = '/etc/ct-ssh-keys-regenerated';
15
+ export async function migrateSshKeys() {
16
+ // If sentinel exists, keys were already regenerated
17
+ if (existsSync(SSH_REGEN_SENTINEL)) {
18
+ return false;
19
+ }
20
+ // Check if SSH host keys exist at all
21
+ const hasKeys = existsSync('/etc/ssh/ssh_host_ed25519_key') ||
22
+ existsSync('/etc/ssh/ssh_host_rsa_key');
23
+ if (!hasKeys) {
24
+ // No keys at all — generate fresh ones
25
+ spawnSync('sudo', ['ssh-keygen', '-A'], { stdio: 'pipe' });
26
+ }
27
+ else {
28
+ // Keys exist but may be from OVA template — regenerate
29
+ // Remove old keys
30
+ spawnSync('sudo', ['bash', '-c', 'rm -f /etc/ssh/ssh_host_*_key*'], { stdio: 'pipe' });
31
+ // Generate new keys
32
+ const keygen = spawnSync('sudo', ['ssh-keygen', '-A'], { stdio: 'pipe' });
33
+ if (keygen.status !== 0) {
34
+ throw new Error('ssh-keygen -A failed');
35
+ }
36
+ }
37
+ // Write sentinel so this never runs again
38
+ const tmp = `/tmp/ct-ssh-sentinel-${Date.now()}`;
39
+ require('node:fs').writeFileSync(tmp, new Date().toISOString());
40
+ spawnSync('sudo', ['cp', tmp, SSH_REGEN_SENTINEL], { stdio: 'pipe' });
41
+ try {
42
+ require('node:fs').unlinkSync(tmp);
43
+ }
44
+ catch { /* ignore */ }
45
+ // Reload sshd to pick up new keys (don't restart — would kill current session)
46
+ spawnSync('sudo', ['systemctl', 'reload', 'sshd'], { stdio: 'pipe' });
47
+ return true;
48
+ }
49
+ //# sourceMappingURL=migration-005-ssh-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-005-ssh-keys.js","sourceRoot":"","sources":["../../src/lib/migration-005-ssh-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAY,MAAM,oBAAoB,CAAC;AAEzD,MAAM,kBAAkB,GAAG,8BAA8B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,oDAAoD;IACpD,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,MAAM,OAAO,GAAG,UAAU,CAAC,+BAA+B,CAAC;QAC3C,UAAU,CAAC,2BAA2B,CAAC,CAAC;IAExD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,uCAAuC;QACvC,SAAS,CAAC,MAAM,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,uDAAuD;QACvD,kBAAkB;QAClB,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,gCAAgC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEvF,oBAAoB;QACpB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,GAAG,GAAG,wBAAwB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACjD,OAAO,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAChE,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QAAC,OAAO,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAElE,+EAA+E;IAC/E,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEtE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Migration 006: Suppress noisy kernel console warnings.
3
+ *
4
+ * Docker/firewalld loads nft_compat and ip_set kernel modules which emit
5
+ * KERN_WARNING (level 4) messages to the console. These clutter the TTY
6
+ * and alarm users. The kernel cmdline loglevel=3 set during OVA build
7
+ * gets reset by systemd on boot; a sysctl.d drop-in persists it.
8
+ */
9
+ export declare function migrateConsoleLoglevel(): Promise<boolean>;
10
+ //# sourceMappingURL=migration-006-console-loglevel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-006-console-loglevel.d.ts","sourceRoot":"","sources":["../../src/lib/migration-006-console-loglevel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC,CAc/D"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Migration 006: Suppress noisy kernel console warnings.
3
+ *
4
+ * Docker/firewalld loads nft_compat and ip_set kernel modules which emit
5
+ * KERN_WARNING (level 4) messages to the console. These clutter the TTY
6
+ * and alarm users. The kernel cmdline loglevel=3 set during OVA build
7
+ * gets reset by systemd on boot; a sysctl.d drop-in persists it.
8
+ */
9
+ import { existsSync, writeFileSync, unlinkSync } from 'node:fs';
10
+ import { spawnSync } from 'node:child_process';
11
+ const SYSCTL_FILE = '/etc/sysctl.d/99-console-loglevel.conf';
12
+ export async function migrateConsoleLoglevel() {
13
+ if (existsSync(SYSCTL_FILE)) {
14
+ return false;
15
+ }
16
+ const content = 'kernel.printk = 3 4 1 3\n';
17
+ const tmp = `/tmp/ct-loglevel-${Date.now()}`;
18
+ writeFileSync(tmp, content);
19
+ spawnSync('sudo', ['cp', tmp, SYSCTL_FILE], { stdio: 'pipe' });
20
+ try {
21
+ unlinkSync(tmp);
22
+ }
23
+ catch { /* ignore */ }
24
+ spawnSync('sudo', ['sysctl', '-p', SYSCTL_FILE], { stdio: 'pipe' });
25
+ return true;
26
+ }
27
+ //# sourceMappingURL=migration-006-console-loglevel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-006-console-loglevel.js","sourceRoot":"","sources":["../../src/lib/migration-006-console-loglevel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,WAAW,GAAG,wCAAwC,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,2BAA2B,CAAC;IAC5C,MAAM,GAAG,GAAG,oBAAoB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC7C,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5B,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/D,IAAI,CAAC;QAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAE/C,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAEpE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Migration 007: Migrate legacy ifcfg network configs to NM keyfile format.
3
+ *
4
+ * RHEL 9 / AlmaLinux 9 deprecated the ifcfg backend for NetworkManager.
5
+ * Connections still using ifcfg-rh files emit deprecation warnings in logs
6
+ * and will stop working in future RHEL releases. `nmcli connection migrate`
7
+ * converts them to the native keyfile format in /etc/NetworkManager/system-connections/.
8
+ */
9
+ export declare function migrateNmKeyfile(): Promise<boolean>;
10
+ //# sourceMappingURL=migration-007-nm-keyfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-007-nm-keyfile.d.ts","sourceRoot":"","sources":["../../src/lib/migration-007-nm-keyfile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAuBzD"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Migration 007: Migrate legacy ifcfg network configs to NM keyfile format.
3
+ *
4
+ * RHEL 9 / AlmaLinux 9 deprecated the ifcfg backend for NetworkManager.
5
+ * Connections still using ifcfg-rh files emit deprecation warnings in logs
6
+ * and will stop working in future RHEL releases. `nmcli connection migrate`
7
+ * converts them to the native keyfile format in /etc/NetworkManager/system-connections/.
8
+ */
9
+ import { spawnSync } from 'node:child_process';
10
+ export async function migrateNmKeyfile() {
11
+ // Check if nmcli is available
12
+ const check = spawnSync('command', ['-v', 'nmcli'], { shell: true, stdio: 'pipe' });
13
+ if (check.status !== 0) {
14
+ return false;
15
+ }
16
+ // Count connections still using ifcfg backend
17
+ const list = spawnSync('nmcli', ['-t', '-f', 'FILENAME', 'connection', 'show'], { stdio: 'pipe' });
18
+ const output = list.stdout?.toString() ?? '';
19
+ const ifcfgCount = output.split('\n').filter((line) => line.includes('ifcfg')).length;
20
+ if (ifcfgCount === 0) {
21
+ return false;
22
+ }
23
+ // Migrate all ifcfg connections to keyfile format
24
+ const migrate = spawnSync('sudo', ['nmcli', 'connection', 'migrate'], { stdio: 'pipe' });
25
+ if (migrate.status !== 0) {
26
+ throw new Error(`nmcli connection migrate failed: ${migrate.stderr?.toString()}`);
27
+ }
28
+ return true;
29
+ }
30
+ //# sourceMappingURL=migration-007-nm-keyfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-007-nm-keyfile.js","sourceRoot":"","sources":["../../src/lib/migration-007-nm-keyfile.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,8BAA8B;IAC9B,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACpF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACnG,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtF,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kDAAkD;IAClD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 008: Add restart-on-failure policy to docker-compose-app.service.
3
+ *
4
+ * Without Restart=on-failure, a container crash or OOM kill leaves the
5
+ * appliance down until someone manually restarts. This migration adds:
6
+ * Restart=on-failure
7
+ * RestartSec=60
8
+ *
9
+ * Also ensures network-online.target dependency exists for boot on
10
+ * isolated LANs where DNS/DHCP may be slow.
11
+ */
12
+ export declare function migrateSystemdRestart(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-008-systemd-restart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-008-systemd-restart.d.ts","sourceRoot":"","sources":["../../src/lib/migration-008-systemd-restart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CA6B9D"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Migration 008: Add restart-on-failure policy to docker-compose-app.service.
3
+ *
4
+ * Without Restart=on-failure, a container crash or OOM kill leaves the
5
+ * appliance down until someone manually restarts. This migration adds:
6
+ * Restart=on-failure
7
+ * RestartSec=60
8
+ *
9
+ * Also ensures network-online.target dependency exists for boot on
10
+ * isolated LANs where DNS/DHCP may be slow.
11
+ */
12
+ import { existsSync, readFileSync } from 'node:fs';
13
+ import { spawnSync } from 'node:child_process';
14
+ const SERVICE_FILE = '/etc/systemd/system/docker-compose-app.service';
15
+ export async function migrateSystemdRestart() {
16
+ if (!existsSync(SERVICE_FILE)) {
17
+ return false;
18
+ }
19
+ const content = readFileSync(SERVICE_FILE, 'utf-8');
20
+ let changed = false;
21
+ // Add Restart=on-failure if missing
22
+ if (!content.includes('Restart=')) {
23
+ if (content.includes('TimeoutStartSec=')) {
24
+ spawnSync('sudo', ['sed', '-i', '/^TimeoutStartSec=/a Restart=on-failure\\nRestartSec=60', SERVICE_FILE], { stdio: 'pipe' });
25
+ }
26
+ else {
27
+ spawnSync('sudo', ['sed', '-i', '/^\\[Install\\]/i Restart=on-failure\\nRestartSec=60', SERVICE_FILE], { stdio: 'pipe' });
28
+ }
29
+ changed = true;
30
+ }
31
+ // Add network-online.target dependency if missing
32
+ if (!content.includes('network-online.target')) {
33
+ spawnSync('sudo', ['sed', '-i', '/^After=docker.service/a Wants=network-online.target\\nAfter=network-online.target', SERVICE_FILE], { stdio: 'pipe' });
34
+ changed = true;
35
+ }
36
+ if (changed) {
37
+ spawnSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe' });
38
+ }
39
+ return changed;
40
+ }
41
+ //# sourceMappingURL=migration-008-systemd-restart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-008-systemd-restart.js","sourceRoot":"","sources":["../../src/lib/migration-008-systemd-restart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,YAAY,GAAG,gDAAgD,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,oCAAoC;IACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACzC,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,yDAAyD,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/H,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,sDAAsD,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5H,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,kDAAkD;IAClD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QAC/C,SAAS,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,oFAAoF,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxJ,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Migration 009: Fix Docker bind-mount directory-vs-file confusion.
3
+ *
4
+ * Docker auto-creates missing bind-mount targets as DIRECTORIES.
5
+ * If alertmanager.yml or tempo.yaml were created as directories
6
+ * (from a `docker compose up` before the files existed), the services
7
+ * fail to start. This migration removes the bogus directories and
8
+ * creates the correct config files.
9
+ */
10
+ export declare function migrateBindMountFiles(): Promise<boolean>;
11
+ //# sourceMappingURL=migration-009-bind-mount-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-009-bind-mount-files.d.ts","sourceRoot":"","sources":["../../src/lib/migration-009-bind-mount-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkFH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAI9D"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Migration 009: Fix Docker bind-mount directory-vs-file confusion.
3
+ *
4
+ * Docker auto-creates missing bind-mount targets as DIRECTORIES.
5
+ * If alertmanager.yml or tempo.yaml were created as directories
6
+ * (from a `docker compose up` before the files existed), the services
7
+ * fail to start. This migration removes the bogus directories and
8
+ * creates the correct config files.
9
+ */
10
+ import { existsSync, statSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ const INSTALL_DIR = join(homedir(), '');
14
+ const ALERTMANAGER_DIR = join(INSTALL_DIR, 'alertmanager');
15
+ const ALERTMANAGER_FILE = join(ALERTMANAGER_DIR, 'alertmanager.yml');
16
+ const ALERTMANAGER_CONTENT = `global:
17
+ resolve_timeout: 5m
18
+ route:
19
+ receiver: 'default'
20
+ group_wait: 30s
21
+ group_interval: 5m
22
+ repeat_interval: 4h
23
+ receivers:
24
+ - name: 'default'
25
+ `;
26
+ const TEMPO_DIR = join(INSTALL_DIR, 'tempo');
27
+ const TEMPO_FILE = join(TEMPO_DIR, 'tempo.yaml');
28
+ const TEMPO_CONTENT = `server:
29
+ http_listen_port: 3200
30
+
31
+ distributor:
32
+ receivers:
33
+ otlp:
34
+ protocols:
35
+ grpc:
36
+ endpoint: 0.0.0.0:4317
37
+ http:
38
+ endpoint: 0.0.0.0:4318
39
+
40
+ ingester:
41
+ max_block_duration: 5m
42
+
43
+ compactor:
44
+ compaction:
45
+ block_retention: 72h # Keep traces for 3 days
46
+
47
+ storage:
48
+ trace:
49
+ backend: local
50
+ local:
51
+ path: /var/tempo/blocks
52
+ wal:
53
+ path: /var/tempo/wal
54
+
55
+ metrics_generator:
56
+ registry:
57
+ external_labels:
58
+ source: tempo
59
+ storage:
60
+ path: /var/tempo/generator/wal
61
+ remote_write:
62
+ - url: http://prometheus:9090/api/v1/write
63
+ send_exemplars: true
64
+ `;
65
+ function fixBindMount(dir, filePath, content) {
66
+ let changed = false;
67
+ // If the file path is a directory (Docker bind-mount bug), remove it
68
+ if (existsSync(filePath) && statSync(filePath).isDirectory()) {
69
+ rmSync(filePath, { recursive: true, force: true });
70
+ changed = true;
71
+ }
72
+ // Ensure parent directory exists
73
+ mkdirSync(dir, { recursive: true });
74
+ // Create the file if it doesn't exist
75
+ if (!existsSync(filePath)) {
76
+ writeFileSync(filePath, content);
77
+ changed = true;
78
+ }
79
+ return changed;
80
+ }
81
+ export async function migrateBindMountFiles() {
82
+ const a = fixBindMount(ALERTMANAGER_DIR, ALERTMANAGER_FILE, ALERTMANAGER_CONTENT);
83
+ const b = fixBindMount(TEMPO_DIR, TEMPO_FILE, TEMPO_CONTENT);
84
+ return a || b;
85
+ }
86
+ //# sourceMappingURL=migration-009-bind-mount-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-009-bind-mount-files.js","sourceRoot":"","sources":["../../src/lib/migration-009-bind-mount-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAExC,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAC3D,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;AACrE,MAAM,oBAAoB,GAAG;;;;;;;;;CAS5B,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AACjD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCrB,CAAC;AAEF,SAAS,YAAY,CAAC,GAAW,EAAE,QAAgB,EAAE,OAAe;IAClE,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,qEAAqE;IACrE,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC7D,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,iCAAiC;IACjC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpC,sCAAsC;IACtC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,CAAC,GAAG,YAAY,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;IAClF,MAAM,CAAC,GAAG,YAAY,CAAC,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;IAC7D,OAAO,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Migration 010: Migrate legacy .jtapi-enabled file to .env COMPOSE_PROFILES.
3
+ *
4
+ * Older appliances used a `.jtapi-enabled` sentinel file to track whether
5
+ * JTAPI was enabled. The compose stack now uses COMPOSE_PROFILES=jtapi
6
+ * in .env to conditionally include the jtapi-sidecar and ct-media services.
7
+ * This migration reads the old flag, sets the appropriate .env vars, and
8
+ * removes the sentinel file.
9
+ */
10
+ export declare function migrateJtapiState(): Promise<boolean>;
11
+ //# sourceMappingURL=migration-010-jtapi-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-010-jtapi-state.d.ts","sourceRoot":"","sources":["../../src/lib/migration-010-jtapi-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+BH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAsB1D"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Migration 010: Migrate legacy .jtapi-enabled file to .env COMPOSE_PROFILES.
3
+ *
4
+ * Older appliances used a `.jtapi-enabled` sentinel file to track whether
5
+ * JTAPI was enabled. The compose stack now uses COMPOSE_PROFILES=jtapi
6
+ * in .env to conditionally include the jtapi-sidecar and ct-media services.
7
+ * This migration reads the old flag, sets the appropriate .env vars, and
8
+ * removes the sentinel file.
9
+ */
10
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { homedir } from 'node:os';
13
+ const INSTALL_DIR = homedir();
14
+ const ENV_FILE = join(INSTALL_DIR, '.env');
15
+ const JTAPI_STATE_FILE = join(INSTALL_DIR, '.jtapi-enabled');
16
+ function envGet(key) {
17
+ if (!existsSync(ENV_FILE))
18
+ return '';
19
+ const content = readFileSync(ENV_FILE, 'utf-8');
20
+ const match = content.match(new RegExp(`^${key}=(.*)$`, 'm'));
21
+ return match?.[1] ?? '';
22
+ }
23
+ function envSet(key, value) {
24
+ if (!existsSync(ENV_FILE)) {
25
+ writeFileSync(ENV_FILE, `${key}=${value}\n`);
26
+ return;
27
+ }
28
+ const content = readFileSync(ENV_FILE, 'utf-8');
29
+ const regex = new RegExp(`^${key}=.*$`, 'm');
30
+ if (regex.test(content)) {
31
+ writeFileSync(ENV_FILE, content.replace(regex, `${key}=${value}`));
32
+ }
33
+ else {
34
+ writeFileSync(ENV_FILE, content.trimEnd() + `\n${key}=${value}\n`);
35
+ }
36
+ }
37
+ export async function migrateJtapiState() {
38
+ if (!existsSync(JTAPI_STATE_FILE)) {
39
+ return false;
40
+ }
41
+ // Add jtapi to COMPOSE_PROFILES if not already there
42
+ const profiles = envGet('COMPOSE_PROFILES');
43
+ if (!profiles.includes('jtapi')) {
44
+ envSet('COMPOSE_PROFILES', profiles ? `${profiles},jtapi` : 'jtapi');
45
+ }
46
+ // Set JTAPI env vars if not already present
47
+ if (!envGet('JTAPI_MODE'))
48
+ envSet('JTAPI_MODE', 'direct');
49
+ if (!envGet('JTAPI_SIDECAR_ENDPOINT'))
50
+ envSet('JTAPI_SIDECAR_ENDPOINT', 'jtapi-sidecar:50051');
51
+ if (!envGet('JTAPI_SIDECAR_URL'))
52
+ envSet('JTAPI_SIDECAR_URL', 'http://jtapi-sidecar:8080');
53
+ if (!envGet('S3_ENABLED'))
54
+ envSet('S3_ENABLED', 'true');
55
+ if (!envGet('CT_MEDIA_ENDPOINT'))
56
+ envSet('CT_MEDIA_ENDPOINT', 'ct-media:50053');
57
+ // Remove the legacy sentinel file
58
+ unlinkSync(JTAPI_STATE_FILE);
59
+ return true;
60
+ }
61
+ //# sourceMappingURL=migration-010-jtapi-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-010-jtapi-state.js","sourceRoot":"","sources":["../../src/lib/migration-010-jtapi-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,WAAW,GAAG,OAAO,EAAE,CAAC;AAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAC3C,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;AAE7D,SAAS,MAAM,CAAC,GAAW;IACzB,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9D,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,MAAM,CAAC,GAAW,EAAE,KAAa;IACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,aAAa,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACvE,CAAC;IAED,4CAA4C;IAC5C,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAAE,MAAM,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,MAAM,CAAC,wBAAwB,CAAC;QAAE,MAAM,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;IAC/F,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAAE,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,CAAC,CAAC;IAC3F,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC;QAAE,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;IAEhF,kCAAkC;IAClC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAE7B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Migration 011: Cap Docker daemon memory at 90% of system RAM.
3
+ *
4
+ * On a single-purpose Docker Compose appliance, containers can consume
5
+ * all available RAM, starving the OS (kernel, systemd, sshd, NM) and
6
+ * triggering the OOM killer. This migration creates a systemd drop-in
7
+ * that limits the Docker daemon + all containers to 90% of total RAM,
8
+ * guaranteeing 10% for the OS.
9
+ *
10
+ * Also updates existing 80% limit to 90% (previous default was too conservative).
11
+ */
12
+ export declare function migrateDockerMemoryLimit(): Promise<boolean>;
13
+ //# sourceMappingURL=migration-011-docker-memory-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-011-docker-memory-limit.d.ts","sourceRoot":"","sources":["../../src/lib/migration-011-docker-memory-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CA8BjE"}