underpost 2.8.7 → 2.8.8

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 (47) hide show
  1. package/.vscode/extensions.json +34 -2
  2. package/README.md +7 -5
  3. package/bin/db.js +1 -0
  4. package/bin/deploy.js +259 -74
  5. package/cli.md +88 -9
  6. package/conf.js +4 -0
  7. package/docker-compose.yml +1 -1
  8. package/manifests/deployment/adminer/service.yaml +1 -1
  9. package/manifests/deployment/dd-template-development/deployment.yaml +167 -0
  10. package/manifests/deployment/dd-template-development/proxy.yaml +46 -0
  11. package/manifests/deployment/fastapi/initial_data.sh +56 -0
  12. package/manifests/deployment/spark/spark-pi-py.yaml +21 -0
  13. package/manifests/envoy-service-nodeport.yaml +23 -0
  14. package/manifests/kubelet-config.yaml +65 -0
  15. package/manifests/lxd/lxd-admin-profile.yaml +17 -0
  16. package/manifests/lxd/lxd-preseed.yaml +30 -0
  17. package/manifests/lxd/underpost-setup.sh +163 -0
  18. package/manifests/maas/lxd-preseed.yaml +32 -0
  19. package/manifests/maas/maas-setup.sh +82 -0
  20. package/manifests/mariadb/statefulset.yaml +2 -1
  21. package/manifests/mariadb/storage-class.yaml +10 -0
  22. package/manifests/mongodb/kustomization.yaml +1 -1
  23. package/manifests/mongodb/statefulset.yaml +12 -11
  24. package/manifests/mongodb/storage-class.yaml +9 -0
  25. package/manifests/mongodb-4.4/service-deployment.yaml +2 -2
  26. package/manifests/mysql/kustomization.yaml +7 -0
  27. package/manifests/mysql/pv-pvc.yaml +27 -0
  28. package/manifests/mysql/statefulset.yaml +55 -0
  29. package/manifests/postgresql/statefulset.yaml +1 -1
  30. package/manifests/valkey/service.yaml +3 -9
  31. package/manifests/valkey/statefulset.yaml +12 -15
  32. package/package.json +1 -1
  33. package/src/cli/baremetal.js +60 -0
  34. package/src/cli/cluster.js +506 -207
  35. package/src/cli/deploy.js +47 -14
  36. package/src/cli/env.js +2 -2
  37. package/src/cli/image.js +83 -9
  38. package/src/cli/index.js +68 -61
  39. package/src/cli/lxd.js +395 -0
  40. package/src/cli/repository.js +9 -6
  41. package/src/index.js +17 -1
  42. package/src/runtime/lampp/Dockerfile +1 -1
  43. package/src/server/conf.js +58 -0
  44. package/src/server/logger.js +3 -3
  45. package/src/server/runtime.js +1 -1
  46. package/src/server/valkey.js +3 -3
  47. package/manifests/calico-custom-resources.yaml +0 -25
package/src/cli/lxd.js ADDED
@@ -0,0 +1,395 @@
1
+ import { getNpmRootPath } from '../server/conf.js';
2
+ import { getLocalIPv4Address } from '../server/dns.js';
3
+ import { pbcopy, shellExec } from '../server/process.js';
4
+ import fs from 'fs-extra';
5
+
6
+ /**
7
+ * @class UnderpostLxd
8
+ * @description Provides a set of static methods to interact with LXD,
9
+ * encapsulating common LXD operations for VM management and network testing.
10
+ */
11
+ class UnderpostLxd {
12
+ static API = {
13
+ /**
14
+ * @method callback
15
+ * @description Main entry point for LXD operations based on provided options.
16
+ * @param {object} options - Configuration options for LXD operations.
17
+ * @param {boolean} [options.init=false] - Initialize LXD.
18
+ * @param {boolean} [options.reset=false] - Reset LXD installation.
19
+ * @param {boolean} [options.dev=false] - Run in development mode (adjusts paths).
20
+ * @param {boolean} [options.install=false] - Install LXD snap.
21
+ * @param {boolean} [options.createVirtualNetwork=false] - Create default LXD bridge network (lxdbr0).
22
+ * @param {boolean} [options.createAdminProfile=false] - Create admin-profile for VMs.
23
+ * @param {boolean} [options.control=false] - Flag for control plane VM initialization.
24
+ * @param {boolean} [options.worker=false] - Flag for worker node VM initialization.
25
+ * @param {boolean} [options.k3s=false] - Flag to indicate K3s cluster type for VM initialization.
26
+ * @param {string} [options.initVm=''] - Initialize a specific VM.
27
+ * @param {string} [options.createVm=''] - Create a new VM with the given name.
28
+ * @param {string} [options.infoVm=''] - Display information about a specific VM.
29
+ * @param {string} [options.rootSize=''] - Root disk size for new VMs (e.g., '32GiB').
30
+ * @param {string} [options.joinNode=''] - Join a worker node to a control plane (format: 'workerName,controlName').
31
+ * @param {string} [options.expose=''] - Expose ports from a VM to the host (format: 'vmName:port1,port2').
32
+ * @param {string} [options.deleteExpose=''] - Delete exposed ports from a VM (format: 'vmName:port1,port2').
33
+ * @param {string} [options.test=''] - Test health, status and network connectivity for a VM.
34
+ * @param {string} [options.autoExposeK8sPorts=''] - Automatically expose common Kubernetes ports for the VM.
35
+ */
36
+ async callback(
37
+ options = {
38
+ init: false,
39
+ reset: false,
40
+ dev: false,
41
+ install: false,
42
+ createVirtualNetwork: false,
43
+ createAdminProfile: false,
44
+ control: false,
45
+ worker: false,
46
+ k3s: false,
47
+ initVm: '',
48
+ createVm: '',
49
+ infoVm: '',
50
+ rootSize: '',
51
+ joinNode: '',
52
+ expose: '',
53
+ deleteExpose: '',
54
+ test: '',
55
+ autoExposeK8sPorts: '',
56
+ },
57
+ ) {
58
+ const npmRoot = getNpmRootPath();
59
+ const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
60
+ if (options.reset === true) {
61
+ shellExec(`sudo systemctl stop snap.lxd.daemon || true`);
62
+ shellExec(`sudo snap remove lxd --purge || true`);
63
+ }
64
+ if (options.install === true) shellExec(`sudo snap install lxd`);
65
+ if (options.init === true) {
66
+ shellExec(`sudo systemctl start snap.lxd.daemon`);
67
+ shellExec(`sudo systemctl status snap.lxd.daemon`);
68
+ const lxdPressedContent = fs
69
+ .readFileSync(`${underpostRoot}/manifests/lxd/lxd-preseed.yaml`, 'utf8')
70
+ .replaceAll(`127.0.0.1`, getLocalIPv4Address());
71
+ shellExec(`echo "${lxdPressedContent}" | lxd init --preseed`);
72
+ shellExec(`lxc cluster list`);
73
+ }
74
+ if (options.createVirtualNetwork === true) {
75
+ shellExec(`lxc network create lxdbr0 \
76
+ ipv4.address=10.250.250.1/24 \
77
+ ipv4.nat=true \
78
+ ipv4.dhcp=true \
79
+ ipv6.address=none`);
80
+ }
81
+ if (options.createAdminProfile === true) {
82
+ pbcopy(`lxc profile create admin-profile`);
83
+ shellExec(`cat ${underpostRoot}/manifests/lxd/lxd-admin-profile.yaml | lxc profile edit admin-profile`);
84
+ shellExec(`lxc profile show admin-profile`);
85
+ }
86
+ if (options.createVm && typeof options.createVm === 'string') {
87
+ pbcopy(
88
+ `lxc launch images:rockylinux/9 ${
89
+ options.createVm
90
+ } --vm --target lxd-node1 -c limits.cpu=2 -c limits.memory=4GB --profile admin-profile -d root,size=${
91
+ options.rootSize && typeof options.rootSize === 'string' ? options.rootSize + 'GiB' : '32GiB'
92
+ }`,
93
+ );
94
+ }
95
+ if (options.initVm && typeof options.initVm === 'string') {
96
+ let flag = '';
97
+ if (options.control === true) {
98
+ if (options.k3s === true) {
99
+ flag = ' -s -- --k3s';
100
+ } else {
101
+ // Default to kubeadm if not K3s
102
+ flag = ' -s -- --kubeadm';
103
+ }
104
+ shellExec(`lxc exec ${options.initVm} -- bash -c 'mkdir -p /home/dd/engine'`);
105
+ shellExec(`lxc file push /home/dd/engine/engine-private ${options.initVm}/home/dd/engine --recursive`);
106
+ shellExec(`lxc file push /home/dd/engine/manifests ${options.initVm}/home/dd/engine --recursive`);
107
+ } else if (options.worker == true) {
108
+ if (options.k3s === true) {
109
+ flag = ' -s -- --worker --k3s';
110
+ } else {
111
+ // Default to kubeadm worker
112
+ flag = ' -s -- --worker';
113
+ }
114
+ }
115
+ console.log(`Executing underpost-setup.sh on VM: ${options.initVm}`);
116
+ shellExec(`cat ${underpostRoot}/manifests/lxd/underpost-setup.sh | lxc exec ${options.initVm} -- bash${flag}`);
117
+ console.log(`underpost-setup.sh execution completed on VM: ${options.initVm}`);
118
+ }
119
+ // --- Automatic Kubernetes Port Exposure ---
120
+ if (options.autoExposeK8sPorts && typeof options.autoExposeK8sPorts === 'string') {
121
+ console.log(`Automatically exposing Kubernetes ports for VM: ${options.autoExposeK8sPorts}`);
122
+ const vmName = options.autoExposeK8sPorts;
123
+ const hostIp = getLocalIPv4Address();
124
+ let vmIp = '';
125
+ let retries = 0;
126
+ const maxRetries = 10;
127
+ const delayMs = 5000; // 5 seconds
128
+
129
+ // Wait for VM to get an IP address
130
+ while (!vmIp && retries < maxRetries) {
131
+ try {
132
+ console.log(`Attempting to get IPv4 address for ${vmName} (Attempt ${retries + 1}/${maxRetries})...`);
133
+ vmIp = shellExec(
134
+ `lxc list ${vmName} --format json | jq -r '.[0].state.network.enp5s0.addresses[] | select(.family=="inet") | .address'`,
135
+ { stdout: true },
136
+ ).trim();
137
+ if (vmIp) {
138
+ console.log(`IPv4 address found for ${vmName}: ${vmIp}`);
139
+ } else {
140
+ console.log(`IPv4 address not yet available for ${vmName}. Retrying in ${delayMs / 1000} seconds...`);
141
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
142
+ }
143
+ } catch (error) {
144
+ console.error(`Error getting IPv4 address for exposure: ${error.message}`);
145
+ console.log(`Retrying in ${delayMs / 1000} seconds...`);
146
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
147
+ }
148
+ retries++;
149
+ }
150
+
151
+ if (!vmIp) {
152
+ console.error(`Failed to get VM IP for ${vmName} after ${maxRetries} attempts. Cannot expose ports.`);
153
+ return;
154
+ }
155
+
156
+ let portsToExpose = [];
157
+ if (options.control === true) {
158
+ // Kubernetes API Server (Kubeadm and K3s both use 6443 by default)
159
+ portsToExpose.push('6443');
160
+ // Standard HTTP/HTTPS for Ingress if deployed
161
+ portsToExpose.push('80');
162
+ portsToExpose.push('443');
163
+ }
164
+ // Add common NodePorts if needed, or rely on explicit 'expose'
165
+ portsToExpose.push('30000'); // Example NodePort
166
+ portsToExpose.push('30001'); // Example NodePort
167
+ portsToExpose.push('30002'); // Example NodePort
168
+
169
+ const protocols = ['tcp']; // Most K8s services are TCP, UDP for some like DNS
170
+
171
+ for (const port of portsToExpose) {
172
+ for (const protocol of protocols) {
173
+ const deviceName = `${vmName}-${protocol}-port-${port}`;
174
+ try {
175
+ // Remove existing device first to avoid conflicts if re-running
176
+ shellExec(`lxc config device remove ${vmName} ${deviceName} || true`);
177
+ shellExec(
178
+ `lxc config device add ${vmName} ${deviceName} proxy listen=${protocol}:${hostIp}:${port} connect=${protocol}:${vmIp}:${port} nat=true`,
179
+ );
180
+ console.log(`Exposed ${protocol}:${hostIp}:${port} -> ${vmIp}:${port} for ${vmName}`);
181
+ } catch (error) {
182
+ console.error(`Failed to expose port ${port} for ${vmName}: ${error.message}`);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ if (options.joinNode && typeof options.joinNode === 'string') {
188
+ const [workerNode, controlNode] = options.joinNode.split(',');
189
+ // Determine if it's a Kubeadm or K3s join
190
+ const isK3sJoin = options.k3s === true;
191
+
192
+ if (isK3sJoin) {
193
+ console.log(`Attempting to join K3s worker node ${workerNode} to control plane ${controlNode}`);
194
+ // Get K3s token from control plane
195
+ const k3sToken = shellExec(
196
+ `lxc exec ${controlNode} -- bash -c 'sudo cat /var/lib/rancher/k3s/server/node-token'`,
197
+ { stdout: true },
198
+ ).trim();
199
+ // Get control plane IP
200
+ const controlPlaneIp = shellExec(
201
+ `lxc list ${controlNode} --format json | jq -r '.[0].state.network.enp5s0.addresses[] | select(.family=="inet") | .address'`,
202
+ { stdout: true },
203
+ ).trim();
204
+
205
+ if (!k3sToken || !controlPlaneIp) {
206
+ console.error(`Failed to get K3s token or control plane IP. Cannot join worker.`);
207
+ return;
208
+ }
209
+ const k3sJoinCommand = `K3S_URL=https://${controlPlaneIp}:6443 K3S_TOKEN=${k3sToken} curl -sfL https://get.k3s.io | sh -`;
210
+ shellExec(`lxc exec ${workerNode} -- bash -c '${k3sJoinCommand}'`);
211
+ console.log(`K3s worker node ${workerNode} join command executed.`);
212
+ } else {
213
+ // Kubeadm join
214
+ console.log(`Attempting to join Kubeadm worker node ${workerNode} to control plane ${controlNode}`);
215
+ const token = shellExec(
216
+ `echo "$(lxc exec ${controlNode} -- bash -c 'sudo kubeadm token create --print-join-command')"`,
217
+ { stdout: true },
218
+ );
219
+ shellExec(`lxc exec ${workerNode} -- bash -c '${token}'`);
220
+ console.log(`Kubeadm worker node ${workerNode} join command executed.`);
221
+ }
222
+ }
223
+ if (options.infoVm && typeof options.infoVm === 'string') {
224
+ shellExec(`lxc config show ${options.infoVm}`);
225
+ shellExec(`lxc info --show-log ${options.infoVm}`);
226
+ shellExec(`lxc info ${options.infoVm}`);
227
+ shellExec(`lxc list ${options.infoVm}`);
228
+ }
229
+ if (options.expose && typeof options.expose === 'string') {
230
+ const [vmName, ports] = options.expose.split(':');
231
+ console.log({ vmName, ports });
232
+ const protocols = ['tcp']; // udp
233
+ const hostIp = getLocalIPv4Address();
234
+ const vmIp = shellExec(
235
+ `lxc list ${vmName} --format json | jq -r '.[0].state.network.enp5s0.addresses[] | select(.family=="inet") | .address'`,
236
+ { stdout: true },
237
+ ).trim();
238
+ if (!vmIp) {
239
+ console.error(`Could not get VM IP for ${vmName}. Cannot expose ports.`);
240
+ return;
241
+ }
242
+ for (const port of ports.split(',')) {
243
+ for (const protocol of protocols) {
244
+ const deviceName = `${vmName}-${protocol}-port-${port}`;
245
+ shellExec(`lxc config device remove ${vmName} ${deviceName} || true`); // Use || true to prevent error if device doesn't exist
246
+ shellExec(
247
+ `lxc config device add ${vmName} ${deviceName} proxy listen=${protocol}:${hostIp}:${port} connect=${protocol}:${vmIp}:${port} nat=true`,
248
+ );
249
+ console.log(`Manually exposed ${protocol}:${hostIp}:${port} -> ${vmIp}:${port} for ${vmName}`);
250
+ }
251
+ }
252
+ }
253
+ if (options.deleteExpose && typeof options.deleteExpose === 'string') {
254
+ const [controlNode, ports] = options.deleteExpose.split(':');
255
+ console.log({ controlNode, ports });
256
+ const protocols = ['tcp']; // udp
257
+ for (const port of ports.split(',')) {
258
+ for (const protocol of protocols) {
259
+ shellExec(`lxc config device remove ${controlNode} ${controlNode}-${protocol}-port-${port}`);
260
+ }
261
+ }
262
+ }
263
+
264
+ if (options.test && typeof options.test === 'string') {
265
+ const vmName = options.test;
266
+ console.log(`Starting comprehensive test for VM: ${vmName}`);
267
+
268
+ // 1. Monitor for IPv4 address
269
+ let vmIp = '';
270
+ let retries = 0;
271
+ const maxRetries = 10;
272
+ const delayMs = 5000; // 5 seconds
273
+
274
+ while (!vmIp && retries < maxRetries) {
275
+ try {
276
+ console.log(`Attempting to get IPv4 address for ${vmName} (Attempt ${retries + 1}/${maxRetries})...`);
277
+ vmIp = shellExec(
278
+ `lxc list ${vmName} --format json | jq -r '.[0].state.network.enp5s0.addresses[] | select(.family=="inet") | .address'`,
279
+ { stdout: true },
280
+ ).trim();
281
+ if (vmIp) {
282
+ console.log(`IPv4 address found for ${vmName}: ${vmIp}`);
283
+ } else {
284
+ console.log(`IPv4 address not yet available for ${vmName}. Retrying in ${delayMs / 1000} seconds...`);
285
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
286
+ }
287
+ } catch (error) {
288
+ console.error(`Error getting IPv4 address: ${error.message}`);
289
+ console.log(`Retrying in ${delayMs / 1000} seconds...`);
290
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
291
+ }
292
+ retries++;
293
+ }
294
+
295
+ if (!vmIp) {
296
+ console.error(`Failed to get IPv4 address for ${vmName} after ${maxRetries} attempts. Aborting tests.`);
297
+ return;
298
+ }
299
+
300
+ // 2. Iteratively check connection to google.com
301
+ let connectedToGoogle = false;
302
+ retries = 0;
303
+ while (!connectedToGoogle && retries < maxRetries) {
304
+ try {
305
+ console.log(`Checking connectivity to google.com from ${vmName} (Attempt ${retries + 1}/${maxRetries})...`);
306
+ const curlOutput = shellExec(
307
+ `lxc exec ${vmName} -- bash -c 'curl -s -o /dev/null -w "%{http_code}" http://google.com'`,
308
+ { stdout: true },
309
+ );
310
+ if (curlOutput.startsWith('2') || curlOutput.startsWith('3')) {
311
+ console.log(`Successfully connected to google.com from ${vmName}.`);
312
+ connectedToGoogle = true;
313
+ } else {
314
+ console.log(`Connectivity to google.com not yet verified. Retrying in ${delayMs / 1000} seconds...`);
315
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
316
+ }
317
+ } catch (error) {
318
+ console.error(`Error checking connectivity to google.com: ${error.message}`);
319
+ console.log(`Retrying in ${delayMs / 1000} seconds...`);
320
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
321
+ }
322
+ retries++;
323
+ }
324
+
325
+ if (!connectedToGoogle) {
326
+ console.error(
327
+ `Failed to connect to google.com from ${vmName} after ${maxRetries} attempts. Aborting further tests.`,
328
+ );
329
+ return;
330
+ }
331
+
332
+ // 3. Check other connectivity, network, and VM health parameters
333
+ console.log(`\n--- Comprehensive Health Report for ${vmName} ---`);
334
+
335
+ // VM Status
336
+ console.log('\n--- VM Status ---');
337
+ try {
338
+ const vmStatus = shellExec(`lxc list ${vmName} --format json`, { stdout: true, silent: true });
339
+ console.log(JSON.stringify(JSON.parse(vmStatus), null, 2));
340
+ } catch (error) {
341
+ console.error(`Error getting VM status: ${error.message}`);
342
+ }
343
+
344
+ // CPU Usage
345
+ console.log('\n--- CPU Usage ---');
346
+ try {
347
+ const cpuUsage = shellExec(`lxc exec ${vmName} -- bash -c 'top -bn1 | grep "Cpu(s)"'`, { stdout: true });
348
+ console.log(cpuUsage.trim());
349
+ } catch (error) {
350
+ console.error(`Error getting CPU usage: ${error.message}`);
351
+ }
352
+
353
+ // Memory Usage
354
+ console.log('\n--- Memory Usage ---');
355
+ try {
356
+ const memoryUsage = shellExec(`lxc exec ${vmName} -- bash -c 'free -m'`, { stdout: true });
357
+ console.log(memoryUsage.trim());
358
+ } catch (error) {
359
+ console.error(`Error getting memory usage: ${error.message}`);
360
+ }
361
+
362
+ // Disk Usage
363
+ console.log('\n--- Disk Usage (Root Partition) ---');
364
+ try {
365
+ const diskUsage = shellExec(`lxc exec ${vmName} -- bash -c 'df -h /'`, { stdout: true });
366
+ console.log(diskUsage.trim());
367
+ } catch (error) {
368
+ console.error(`Error getting disk usage: ${error.message}`);
369
+ }
370
+
371
+ // Network Interface Status
372
+ console.log('\n--- Network Interface Status (ip a) ---');
373
+ try {
374
+ const ipA = shellExec(`lxc exec ${vmName} -- bash -c 'ip a'`, { stdout: true });
375
+ console.log(ipA.trim());
376
+ } catch (error) {
377
+ console.error(`Error getting network interface status: ${error.message}`);
378
+ }
379
+
380
+ // DNS Resolution (resolv.conf)
381
+ console.log('\n--- DNS Configuration (/etc/resolv.conf) ---');
382
+ try {
383
+ const resolvConf = shellExec(`lxc exec ${vmName} -- bash -c 'cat /etc/resolv.conf'`, { stdout: true });
384
+ console.log(resolvConf.trim());
385
+ } catch (error) {
386
+ console.error(`Error getting DNS configuration: ${error.message}`);
387
+ }
388
+
389
+ console.log(`\nComprehensive test for VM: ${vmName} completed.`);
390
+ }
391
+ },
392
+ };
393
+ }
394
+
395
+ export default UnderpostLxd;
@@ -12,23 +12,25 @@ const logger = loggerFactory(import.meta);
12
12
 
13
13
  class UnderpostRepository {
14
14
  static API = {
15
- clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false }) {
15
+ clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false, g8: false }) {
16
+ const gExtension = options.g8 === true ? '.g8' : '.git';
16
17
  const repoName = gitUri.split('/').pop();
17
18
  if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
18
19
  shellExec(
19
20
  `git clone ${options?.bare === true ? ` --bare ` : ''}https://${
20
21
  process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
21
- }github.com/${gitUri}.git`,
22
+ }github.com/${gitUri}${gExtension}`,
22
23
  {
23
24
  disableLog: true,
24
25
  },
25
26
  );
26
27
  },
27
- pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') {
28
+ pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { g8: false }) {
29
+ const gExtension = options.g8 === true ? '.g8' : '.git';
28
30
  shellExec(
29
31
  `cd ${repoPath} && git pull https://${
30
32
  process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
31
- }github.com/${gitUri}.git`,
33
+ }github.com/${gitUri}${gExtension}`,
32
34
  {
33
35
  disableLog: true,
34
36
  },
@@ -57,9 +59,10 @@ class UnderpostRepository {
57
59
  shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
58
60
  },
59
61
 
60
- push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false }) {
62
+ push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false, g8: false }) {
63
+ const gExtension = options.g8 === true ? '.g8' : '.git';
61
64
  shellExec(
62
- `cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git${
65
+ `cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}${gExtension}${
63
66
  options?.f === true ? ' --force' : ''
64
67
  }`,
65
68
  {
package/src/index.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * @namespace Underpost
5
5
  */
6
6
 
7
+ import UnderpostBaremetal from './cli/baremetal.js';
7
8
  import UnderpostCluster from './cli/cluster.js';
8
9
  import UnderpostCron from './cli/cron.js';
9
10
  import UnderpostDB from './cli/db.js';
@@ -11,6 +12,7 @@ import UnderpostDeploy from './cli/deploy.js';
11
12
  import UnderpostRootEnv from './cli/env.js';
12
13
  import UnderpostFileStorage from './cli/fs.js';
13
14
  import UnderpostImage from './cli/image.js';
15
+ import UnderpostLxd from './cli/lxd.js';
14
16
  import UnderpostMonitor from './cli/monitor.js';
15
17
  import UnderpostRepository from './cli/repository.js';
16
18
  import UnderpostScript from './cli/script.js';
@@ -30,7 +32,7 @@ class Underpost {
30
32
  * @type {String}
31
33
  * @memberof Underpost
32
34
  */
33
- static version = 'v2.8.7';
35
+ static version = 'v2.8.8';
34
36
  /**
35
37
  * Repository cli API
36
38
  * @static
@@ -122,6 +124,20 @@ class Underpost {
122
124
  * @memberof Underpost
123
125
  */
124
126
  static monitor = UnderpostMonitor.API;
127
+ /**
128
+ * LXD cli API
129
+ * @static
130
+ * @type {UnderpostLxd.API}
131
+ * @memberof Underpost
132
+ */
133
+ static lxd = UnderpostLxd.API;
134
+ /**
135
+ * Baremetal cli API
136
+ * @static
137
+ * @type {UnderpostBaremetal.API}
138
+ * @memberof Underpost
139
+ */
140
+ static baremetal = UnderpostBaremetal.API;
125
141
  }
126
142
 
127
143
  const up = Underpost;
@@ -1,6 +1,6 @@
1
1
  ARG BASE_DEBIAN=buster
2
2
 
3
- USER root
3
+ # USER root
4
4
 
5
5
  FROM debian:${BASE_DEBIAN}
6
6
 
@@ -1171,6 +1171,63 @@ const writeEnv = (envPath, envObj) =>
1171
1171
  'utf8',
1172
1172
  );
1173
1173
 
1174
+ const buildCliDoc = (program) => {
1175
+ let md = shellExec(`node bin help`, { silent: true, stdout: true }).split('Options:');
1176
+ const baseOptions =
1177
+ `## ${md[0].split(`\n`)[2]}
1178
+
1179
+ ### Usage: ` +
1180
+ '`' +
1181
+ md[0].split(`\n`)[0].split('Usage: ')[1] +
1182
+ '`' +
1183
+ `
1184
+ ` +
1185
+ '```\n Options:' +
1186
+ md[1] +
1187
+ ' \n```';
1188
+ md =
1189
+ baseOptions +
1190
+ `
1191
+
1192
+ ## Commands:
1193
+ `;
1194
+ program.commands.map((o) => {
1195
+ md +=
1196
+ `
1197
+
1198
+ ` +
1199
+ '### `' +
1200
+ o._name +
1201
+ '` :' +
1202
+ `
1203
+ ` +
1204
+ '```\n ' +
1205
+ shellExec(`node bin help ${o._name}`, { silent: true, stdout: true }) +
1206
+ ' \n```' +
1207
+ `
1208
+ `;
1209
+ });
1210
+ fs.writeFileSync(`./src/client/public/nexodev/docs/references/Command Line Interface.md`, md, 'utf8');
1211
+ fs.writeFileSync(`./cli.md`, md, 'utf8');
1212
+ const readmeSplit = `pwa-microservices-template</a>`;
1213
+ const readme = fs.readFileSync(`./README.md`, 'utf8').split(readmeSplit);
1214
+ fs.writeFileSync(
1215
+ './README.md',
1216
+ readme[0] +
1217
+ readmeSplit +
1218
+ `
1219
+
1220
+ ` +
1221
+ baseOptions +
1222
+ `
1223
+
1224
+ <a target="_top" href="https://github.com/underpostnet/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
1225
+
1226
+ `,
1227
+ 'utf8',
1228
+ );
1229
+ };
1230
+
1174
1231
  export {
1175
1232
  Cmd,
1176
1233
  Config,
@@ -1214,4 +1271,5 @@ export {
1214
1271
  deployRangePortFactory,
1215
1272
  awaitDeployMonitor,
1216
1273
  rebuildConfFactory,
1274
+ buildCliDoc,
1217
1275
  };
@@ -176,7 +176,7 @@ const loggerMiddleware = (meta = { url: '' }) => {
176
176
  );
177
177
  };
178
178
 
179
- const underpostASCI = () => `
179
+ const underpostASCII = () => `
180
180
 
181
181
  ██╗░░░██╗███╗░░██╗██████╗░███████╗██████╗░██████╗░░█████╗░░██████╗████████╗
182
182
  ██║░░░██║████╗░██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗██╔════╝╚══██╔══╝
@@ -188,10 +188,10 @@ const underpostASCI = () => `
188
188
 
189
189
  const actionInitLog = () =>
190
190
  console.log(
191
- underpostASCI() +
191
+ underpostASCII() +
192
192
  `
193
193
  https://www.nexodev.org/docs
194
194
  `,
195
195
  );
196
196
 
197
- export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCI, actionInitLog };
197
+ export { loggerFactory, loggerMiddleware, setUpInfo, underpostASCII, actionInitLog };
@@ -366,7 +366,7 @@ const buildRuntime = async () => {
366
366
  if (db && apis) await DataBaseProvider.load({ apis, host, path, db });
367
367
 
368
368
  // valkey server
369
- await createValkeyConnection({ host, path }, valkey);
369
+ if (valkey) await createValkeyConnection({ host, path }, valkey);
370
370
 
371
371
  if (mailer) {
372
372
  const mailerSsrConf = confSSR[getCapVariableName(client)];
@@ -34,14 +34,14 @@ const selectDtoFactory = (payload, select) => {
34
34
  const valkeyClientFactory = async (options) => {
35
35
  const valkey = new Valkey({
36
36
  // port: 6379,
37
- // host: 'service-valkey.default.svc.cluster.local',
37
+ // host: 'valkey-service.default.svc.cluster.local',
38
38
  port: options?.port ? options.port : undefined,
39
- host: options?.port ? options.host : undefined,
39
+ host: options?.host ? options.host : undefined,
40
40
  retryStrategy: (attempt) => {
41
41
  if (attempt === 1) {
42
42
  valkey.disconnect();
43
43
  valkeyEnabled = false;
44
- logger.warn('Valkey service not enabled', { valkeyEnabled });
44
+ logger.warn('Valkey service not enabled', { ...options, valkeyEnabled });
45
45
  return;
46
46
  }
47
47
  return 1000; // 1 second interval attempt
@@ -1,25 +0,0 @@
1
- # This section includes base Calico installation configuration.
2
- # For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.Installation
3
- apiVersion: operator.tigera.io/v1
4
- kind: Installation
5
- metadata:
6
- name: default
7
- spec:
8
- # Configures Calico networking.
9
- calicoNetwork:
10
- # Note: The ipPools section cannot be modified post-install.
11
- ipPools:
12
- - blockSize: 26
13
- cidr: 192.168.0.0/16
14
- encapsulation: VXLANCrossSubnet
15
- natOutgoing: Enabled
16
- nodeSelector: all()
17
-
18
- ---
19
- # This section configures the Calico API server.
20
- # For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.APIServer
21
- apiVersion: operator.tigera.io/v1
22
- kind: APIServer
23
- metadata:
24
- name: default
25
- spec: {}