@underpostnet/underpost 2.99.4 → 2.99.6
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/.env.development +0 -3
- package/.env.production +1 -3
- package/.env.test +0 -3
- package/README.md +3 -3
- package/baremetal/commission-workflows.json +93 -4
- package/bin/deploy.js +56 -45
- package/cli.md +45 -28
- package/examples/static-page/README.md +101 -357
- package/examples/static-page/ssr-components/CustomPage.js +1 -13
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +40 -0
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +40 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +3 -4
- package/scripts/disk-devices.sh +13 -0
- package/scripts/maas-setup.sh +13 -9
- package/scripts/rocky-kickstart.sh +294 -0
- package/src/cli/baremetal.js +657 -263
- package/src/cli/cloud-init.js +120 -120
- package/src/cli/env.js +4 -1
- package/src/cli/image.js +4 -37
- package/src/cli/index.js +56 -11
- package/src/cli/kickstart.js +149 -0
- package/src/cli/repository.js +3 -1
- package/src/cli/run.js +56 -10
- package/src/cli/secrets.js +0 -34
- package/src/cli/static.js +23 -23
- package/src/client/components/core/Docs.js +22 -3
- package/src/index.js +30 -5
- package/src/server/backup.js +11 -4
- package/src/server/client-build-docs.js +1 -1
- package/src/server/conf.js +0 -22
- package/src/server/cron.js +339 -130
- package/src/server/dns.js +10 -0
- package/src/server/logger.js +22 -27
- package/src/server/tls.js +14 -14
- package/examples/static-page/QUICK-REFERENCE.md +0 -481
- package/examples/static-page/STATIC-GENERATOR-GUIDE.md +0 -757
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kickstart configuration generator for Underpost Engine
|
|
3
|
+
* @module src/cli/kickstart.js
|
|
4
|
+
* @namespace UnderpostKickStart
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { loggerFactory } from '../server/logger.js';
|
|
11
|
+
|
|
12
|
+
const logger = loggerFactory(import.meta);
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
|
|
16
|
+
class UnderpostKickStart {
|
|
17
|
+
static API = {
|
|
18
|
+
/**
|
|
19
|
+
* @method kickstartHeader
|
|
20
|
+
* @description Generates the kickstart header section with template variables.
|
|
21
|
+
* @param {object} options
|
|
22
|
+
* @param {string} [options.lang='en_US.UTF-8']
|
|
23
|
+
* @param {string} [options.keyboard='us']
|
|
24
|
+
* @param {string} [options.timezone='America/New_York']
|
|
25
|
+
* @param {string} [options.rootPassword]
|
|
26
|
+
* @memberof UnderpostKickStart
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
kickstartHeader: ({ lang = 'en_US.UTF-8', keyboard = 'us', timezone = 'America/New_York', rootPassword = '' }) => {
|
|
30
|
+
return [
|
|
31
|
+
'# Rocky Linux 9 Kickstart - Ephemeral Anaconda Live Environment with SSHD',
|
|
32
|
+
'cmdline',
|
|
33
|
+
'eula --agreed',
|
|
34
|
+
`keyboard --vckeymap=${keyboard} --xlayouts='${keyboard}'`,
|
|
35
|
+
`lang ${lang}`,
|
|
36
|
+
'network --bootproto=dhcp --device=link --activate --onboot=yes',
|
|
37
|
+
`timezone ${timezone} --utc`,
|
|
38
|
+
rootPassword ? `rootpw --plaintext ${rootPassword}` : 'rootpw --lock',
|
|
39
|
+
'firstboot --disable',
|
|
40
|
+
'skipx',
|
|
41
|
+
].join('\n');
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @method kickstartPreVariables
|
|
46
|
+
* @description Generates the variable assignments block for the %pre script.
|
|
47
|
+
* @param {object} options
|
|
48
|
+
* @param {string} [options.rootPassword]
|
|
49
|
+
* @param {string} [options.authorizedKeys]
|
|
50
|
+
* @param {string} [options.adminUsername]
|
|
51
|
+
* @memberof UnderpostKickStart
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
kickstartPreVariables: ({ rootPassword = '', authorizedKeys = '', adminUsername = '' }) => {
|
|
55
|
+
const sanitizedKeys = (authorizedKeys || '').trim();
|
|
56
|
+
return [
|
|
57
|
+
`ROOT_PASS='${rootPassword || ''}'`,
|
|
58
|
+
`AUTHORIZED_KEYS='${sanitizedKeys}'`,
|
|
59
|
+
`ADMIN_USER='${adminUsername || process.env.MAAS_ADMIN_USERNAME || 'maas'}'`,
|
|
60
|
+
].join('\n');
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @method kickstartFactory
|
|
65
|
+
* @description Generates a complete kickstart configuration by combining the header,
|
|
66
|
+
* variable assignments, and the rocky-kickstart.sh script body.
|
|
67
|
+
* @param {object} options
|
|
68
|
+
* @param {string} [options.lang='en_US.UTF-8']
|
|
69
|
+
* @param {string} [options.keyboard='us']
|
|
70
|
+
* @param {string} [options.timezone='America/New_York']
|
|
71
|
+
* @param {string} [options.rootPassword]
|
|
72
|
+
* @param {string} [options.authorizedKeys]
|
|
73
|
+
* @memberof UnderpostKickStart
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
kickstartFactory: ({
|
|
77
|
+
lang = 'en_US.UTF-8',
|
|
78
|
+
keyboard = 'us',
|
|
79
|
+
timezone = 'America/New_York',
|
|
80
|
+
rootPassword = process.env.MAAS_ADMIN_PASS,
|
|
81
|
+
authorizedKeys = '',
|
|
82
|
+
}) => {
|
|
83
|
+
const adminUsername = process.env.MAAS_ADMIN_USERNAME || 'maas';
|
|
84
|
+
const header = UnderpostKickStart.API.kickstartHeader({ lang, keyboard, timezone, rootPassword });
|
|
85
|
+
const variables = UnderpostKickStart.API.kickstartPreVariables({ rootPassword, authorizedKeys, adminUsername });
|
|
86
|
+
|
|
87
|
+
const scriptPath = path.resolve(__dirname, '../../scripts/rocky-kickstart.sh');
|
|
88
|
+
const scriptBody = fs.readFileSync(scriptPath, 'utf8');
|
|
89
|
+
|
|
90
|
+
return [
|
|
91
|
+
header,
|
|
92
|
+
'',
|
|
93
|
+
'%pre --interpreter=/bin/bash --log=/tmp/ks-pre.log --erroronfail',
|
|
94
|
+
'#!/bin/bash',
|
|
95
|
+
variables,
|
|
96
|
+
'',
|
|
97
|
+
scriptBody,
|
|
98
|
+
'%end',
|
|
99
|
+
].join('\n');
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @method kernelParamsFactory
|
|
104
|
+
* @description Appends kickstart-specific kernel parameters (inst.ks, inst.repo, inst.text, inst.sshd).
|
|
105
|
+
* @param {string} macAddress - The MAC address of the target machine.
|
|
106
|
+
* @param {array} cmd - The existing array of kernel parameters.
|
|
107
|
+
* @param {object} options - Options for generating kernel parameters.
|
|
108
|
+
* @param {string} options.ipDhcpServer - The IP address of the DHCP server.
|
|
109
|
+
* @param {number} [options.bootstrapHttpServerPort=8888] - Port for the bootstrap HTTP server.
|
|
110
|
+
* @param {string} options.hostname - The hostname of the target machine.
|
|
111
|
+
* @param {string} [options.architecture='amd64'] - The target architecture.
|
|
112
|
+
* @memberof UnderpostKickStart
|
|
113
|
+
* @returns {array}
|
|
114
|
+
*/
|
|
115
|
+
kernelParamsFactory(
|
|
116
|
+
macAddress,
|
|
117
|
+
cmd = [],
|
|
118
|
+
options = { ipDhcpServer: '', bootstrapHttpServerPort: 8888, hostname: '', architecture: 'amd64' },
|
|
119
|
+
) {
|
|
120
|
+
const { ipDhcpServer, bootstrapHttpServerPort, hostname, architecture } = options;
|
|
121
|
+
const repoArch = architecture && architecture.match('arm64') ? 'aarch64' : 'x86_64';
|
|
122
|
+
return cmd.concat([
|
|
123
|
+
`inst.ks=http://${ipDhcpServer}:${bootstrapHttpServerPort}/${hostname}/ks.cfg`,
|
|
124
|
+
`inst.repo=http://dl.rockylinux.org/pub/rocky/9/BaseOS/${repoArch}/os/`,
|
|
125
|
+
`inst.text`,
|
|
126
|
+
`inst.sshd`,
|
|
127
|
+
]);
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @method httpServerStaticFactory
|
|
132
|
+
* @description Writes kickstart ks.cfg file to the bootstrap HTTP server path.
|
|
133
|
+
* @param {object} params
|
|
134
|
+
* @param {string} params.bootstrapHttpServerPath
|
|
135
|
+
* @param {string} params.hostname
|
|
136
|
+
* @param {string} params.kickstartSrc
|
|
137
|
+
* @memberof UnderpostKickStart
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*/
|
|
140
|
+
httpServerStaticFactory({ bootstrapHttpServerPath, hostname, kickstartSrc }) {
|
|
141
|
+
if (!kickstartSrc) return;
|
|
142
|
+
const dest = `${bootstrapHttpServerPath}/${hostname}/ks.cfg`;
|
|
143
|
+
fs.writeFileSync(dest, kickstartSrc, 'utf8');
|
|
144
|
+
logger.info(`Kickstart file written to ${dest}`);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export default UnderpostKickStart;
|
package/src/cli/repository.js
CHANGED
|
@@ -152,6 +152,7 @@ class UnderpostRepository {
|
|
|
152
152
|
.map((commitData, i) => `${i === 0 ? '' : ' && '}git ${diffCmd} ${commitData.hash}`)
|
|
153
153
|
.join('');
|
|
154
154
|
if (history[0]) {
|
|
155
|
+
let index = history.length;
|
|
155
156
|
for (const commit of history) {
|
|
156
157
|
console.log(
|
|
157
158
|
shellExec(`git show -s --format=%ci ${commit.hash}`, {
|
|
@@ -160,7 +161,8 @@ class UnderpostRepository {
|
|
|
160
161
|
disableLog: true,
|
|
161
162
|
}).trim().green,
|
|
162
163
|
);
|
|
163
|
-
console.log(commit.hash.yellow, commit.message);
|
|
164
|
+
console.log(`${index}`.magenta, commit.hash.yellow, commit.message);
|
|
165
|
+
index--;
|
|
164
166
|
console.log(
|
|
165
167
|
shellExec(`git show --name-status --pretty="" ${commit.hash}`, {
|
|
166
168
|
stdout: true,
|
package/src/cli/run.js
CHANGED
|
@@ -68,7 +68,8 @@ const logger = loggerFactory(import.meta);
|
|
|
68
68
|
* @property {boolean} etcHosts - Whether to modify /etc/hosts.
|
|
69
69
|
* @property {string} confServerPath - The configuration server path.
|
|
70
70
|
* @property {string} underpostRoot - The root path of the Underpost installation.
|
|
71
|
-
* @property {string}
|
|
71
|
+
* @property {string} cmdCronJobs - Pre-script commands to run before cron job execution.
|
|
72
|
+
* @property {string} deployIdCronJobs - The deployment ID for cron jobs.
|
|
72
73
|
* @property {string} timezone - The timezone to set.
|
|
73
74
|
* @property {boolean} kubeadm - Whether to run in kubeadm mode.
|
|
74
75
|
* @property {boolean} kind - Whether to run in kind mode.
|
|
@@ -84,6 +85,8 @@ const logger = loggerFactory(import.meta);
|
|
|
84
85
|
* @property {string} monitorStatusKindType - The monitor status kind type option.
|
|
85
86
|
* @property {string} monitorStatusDeltaMs - The monitor status delta in milliseconds.
|
|
86
87
|
* @property {string} monitorStatusMaxAttempts - The maximum number of attempts for monitor status.
|
|
88
|
+
* @property {boolean} dryRun - Whether to perform a dry run.
|
|
89
|
+
* @property {boolean} createJobNow - Whether to create the job immediately.
|
|
87
90
|
* @property {boolean} logs - Whether to enable logs.
|
|
88
91
|
* @memberof UnderpostRun
|
|
89
92
|
*/
|
|
@@ -127,7 +130,8 @@ const DEFAULT_OPTION = {
|
|
|
127
130
|
etcHosts: false,
|
|
128
131
|
confServerPath: '',
|
|
129
132
|
underpostRoot: '',
|
|
130
|
-
|
|
133
|
+
cmdCronJobs: '',
|
|
134
|
+
deployIdCronJobs: '',
|
|
131
135
|
timezone: '',
|
|
132
136
|
kubeadm: false,
|
|
133
137
|
kind: false,
|
|
@@ -144,6 +148,8 @@ const DEFAULT_OPTION = {
|
|
|
144
148
|
monitorStatusDeltaMs: '',
|
|
145
149
|
monitorStatusMaxAttempts: '',
|
|
146
150
|
logs: false,
|
|
151
|
+
dryRun: false,
|
|
152
|
+
createJobNow: false,
|
|
147
153
|
};
|
|
148
154
|
|
|
149
155
|
/**
|
|
@@ -502,7 +508,21 @@ class UnderpostRun {
|
|
|
502
508
|
if (!validVersion) throw new Error('Version mismatch');
|
|
503
509
|
}
|
|
504
510
|
if (options.timezone !== 'none') shellExec(`${baseCommand} run${baseClusterCommand} tz`);
|
|
505
|
-
if (options.
|
|
511
|
+
if (options.deployIdCronJobs !== 'none') {
|
|
512
|
+
const cronClusterFlag = options.k3s
|
|
513
|
+
? ' --k3s'
|
|
514
|
+
: options.kind
|
|
515
|
+
? ' --kind'
|
|
516
|
+
: options.kubeadm
|
|
517
|
+
? ' --kubeadm'
|
|
518
|
+
: '';
|
|
519
|
+
const cronCmdFlag = options.cmdCronJobs ? ` --cmd-cron-jobs "${options.cmdCronJobs}"` : '';
|
|
520
|
+
const cronCreateJobNowFlag = options.createJobNow ? ' --create-job-now' : '';
|
|
521
|
+
const cronDryRunFlag = options.dryRun ? ' --dry-run' : '';
|
|
522
|
+
shellExec(
|
|
523
|
+
`${baseCommand} run${baseClusterCommand} cron${cronClusterFlag}${cronCmdFlag}${cronCreateJobNowFlag}${cronDryRunFlag}${options.deployIdCronJobs ? ` ${options.deployIdCronJobs}` : ''}`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
506
526
|
}
|
|
507
527
|
|
|
508
528
|
const currentTraffic = isDeployRunnerContext(path, options)
|
|
@@ -710,16 +730,29 @@ class UnderpostRun {
|
|
|
710
730
|
|
|
711
731
|
/**
|
|
712
732
|
* @method cron
|
|
713
|
-
* @description Sets up
|
|
733
|
+
* @description Sets up cron jobs using `underpost cron --setup-start` command, which likely configures scheduled tasks for the application.
|
|
714
734
|
* @param {string} path - The input value, identifier, or path for the operation.
|
|
715
735
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
716
736
|
* @memberof UnderpostRun
|
|
717
737
|
*/
|
|
718
738
|
cron: (path, options = DEFAULT_OPTION) => {
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
739
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
740
|
+
const devFlag = options.dev ? ' --dev' : '';
|
|
741
|
+
const gitFlag = options.git ? ' --git' : '';
|
|
742
|
+
const namespaceFlag =
|
|
743
|
+
options.namespace && options.namespace !== 'default' ? ` --namespace ${options.namespace}` : '';
|
|
744
|
+
const imageFlag = options.image ? ` --image ${options.image}` : '';
|
|
745
|
+
const cmdFlag = options.cmdCronJobs ? ` --cmd "${options.cmdCronJobs}"` : '';
|
|
746
|
+
const ddCronPath = './engine-private/deploy/dd.cron';
|
|
747
|
+
const defaultDeployId = !path && fs.existsSync(ddCronPath) ? fs.readFileSync(ddCronPath, 'utf8').trim() : '';
|
|
748
|
+
const setupStartId = path || defaultDeployId;
|
|
749
|
+
const setupStart = setupStartId ? ` --setup-start ${setupStartId} --apply` : '';
|
|
750
|
+
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : options.kubeadm ? ' --kubeadm' : '';
|
|
751
|
+
const createJobNowFlag = options.createJobNow ? ' --create-job-now' : '';
|
|
752
|
+
const dryRunFlag = options.dryRun ? ' --dry-run' : '';
|
|
753
|
+
shellExec(
|
|
754
|
+
`${baseCommand} cron${devFlag}${gitFlag}${namespaceFlag}${imageFlag}${cmdFlag}${clusterFlag}${createJobNowFlag}${dryRunFlag}${setupStart}`,
|
|
755
|
+
);
|
|
723
756
|
},
|
|
724
757
|
|
|
725
758
|
/**
|
|
@@ -991,7 +1024,7 @@ EOF
|
|
|
991
1024
|
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
|
|
992
1025
|
};
|
|
993
1026
|
|
|
994
|
-
await Underpost.run.
|
|
1027
|
+
await Underpost.run.CALL('deploy-job', path, payload);
|
|
995
1028
|
},
|
|
996
1029
|
|
|
997
1030
|
/**
|
|
@@ -1234,6 +1267,19 @@ EOF
|
|
|
1234
1267
|
shellExec(`./scripts/disk-clean.sh`);
|
|
1235
1268
|
},
|
|
1236
1269
|
|
|
1270
|
+
/**
|
|
1271
|
+
* @method disk-devices
|
|
1272
|
+
* @description Executes the `disk-devices.sh` script to display information about disk devices.
|
|
1273
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
1274
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1275
|
+
* @memberof UnderpostRun
|
|
1276
|
+
*/
|
|
1277
|
+
'disk-devices': async (path = '/', options = DEFAULT_OPTION) => {
|
|
1278
|
+
const { underpostRoot } = options;
|
|
1279
|
+
shellExec(`chmod +x ${underpostRoot}/scripts/disk-devices.sh`);
|
|
1280
|
+
shellExec(`${underpostRoot}/scripts/disk-devices.sh`);
|
|
1281
|
+
},
|
|
1282
|
+
|
|
1237
1283
|
/**
|
|
1238
1284
|
* @method disk-usage
|
|
1239
1285
|
* @description Displays disk usage statistics using the `du` command, sorted by size.
|
|
@@ -1537,7 +1583,7 @@ EOF
|
|
|
1537
1583
|
`${baseCommand} secret underpost --create-from-file /etc/config/.env.${env}`,
|
|
1538
1584
|
`${baseCommand} start --build --run ${deployId} ${env} --underpost-quickly-install`,
|
|
1539
1585
|
];
|
|
1540
|
-
shellExec(`node bin run sync${baseClusterCommand} --cron-jobs none dd-test --cmd "${cmd}"`);
|
|
1586
|
+
shellExec(`node bin run sync${baseClusterCommand} --deploy-id-cron-jobs none dd-test --cmd "${cmd}"`);
|
|
1541
1587
|
},
|
|
1542
1588
|
|
|
1543
1589
|
/**
|
package/src/cli/secrets.js
CHANGED
|
@@ -18,40 +18,6 @@ dotenv.config();
|
|
|
18
18
|
*/
|
|
19
19
|
class UnderpostSecret {
|
|
20
20
|
static API = {
|
|
21
|
-
/**
|
|
22
|
-
* @method docker
|
|
23
|
-
* @description Manages the secrets of the application.
|
|
24
|
-
* @memberof UnderpostSecret
|
|
25
|
-
*/
|
|
26
|
-
docker: {
|
|
27
|
-
/**
|
|
28
|
-
* @method init
|
|
29
|
-
* @description Initializes the docker secrets.
|
|
30
|
-
* @memberof UnderpostSecret
|
|
31
|
-
*/
|
|
32
|
-
init() {
|
|
33
|
-
shellExec(`docker swarm init`);
|
|
34
|
-
},
|
|
35
|
-
/**
|
|
36
|
-
* @method createFromEnvFile
|
|
37
|
-
* @description Creates a secret from an env file.
|
|
38
|
-
* @param {string} envPath - The path to the env file.
|
|
39
|
-
* @memberof UnderpostSecret
|
|
40
|
-
*/
|
|
41
|
-
createFromEnvFile(envPath) {
|
|
42
|
-
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
43
|
-
for (const key of Object.keys(envObj)) {
|
|
44
|
-
Underpost.secret.docker.set(key, envObj[key]);
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
set(key, value) {
|
|
48
|
-
shellExec(`docker secret rm ${key}`);
|
|
49
|
-
shellExec(`echo "${value}" | docker secret create ${key} -`);
|
|
50
|
-
},
|
|
51
|
-
list() {
|
|
52
|
-
shellExec(`docker secret ls`);
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
21
|
/**
|
|
56
22
|
* @method underpost
|
|
57
23
|
* @description Manages the secrets of the application.
|
package/src/cli/static.js
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import path from 'path';
|
|
9
|
+
import express from 'express';
|
|
9
10
|
import { ssrFactory } from '../server/ssr.js';
|
|
10
11
|
import { shellExec } from '../server/process.js';
|
|
11
12
|
import Underpost from '../index.js';
|
|
12
13
|
import { JSONweb } from '../server/client-formatted.js';
|
|
13
|
-
import { loggerFactory } from '../server/logger.js';
|
|
14
|
+
import { loggerFactory, loggerMiddleware } from '../server/logger.js';
|
|
14
15
|
|
|
15
16
|
const logger = loggerFactory(import.meta);
|
|
16
17
|
|
|
@@ -68,11 +69,8 @@ const logger = loggerFactory(import.meta);
|
|
|
68
69
|
* @property {string} [page=''] - SSR component path to render
|
|
69
70
|
* @property {string} [title='Home'] - Page title (deprecated: use metadata.title)
|
|
70
71
|
* @property {string} [outputPath='.'] - Output file path
|
|
71
|
-
* @property {string} [deployId=''] - Deployment identifier
|
|
72
|
-
* @property {string} [buildHost=''] - Build host URL
|
|
73
72
|
* @property {string} [buildPath='/'] - Build path
|
|
74
73
|
* @property {string} [env='production'] - Environment (development/production)
|
|
75
|
-
* @property {boolean} [build=false] - Whether to trigger build
|
|
76
74
|
* @property {boolean} [dev=false] - Development mode flag
|
|
77
75
|
* @property {boolean} [minify=true] - Minify HTML output
|
|
78
76
|
* @property {MetadataOptions} [metadata={}] - Comprehensive metadata options
|
|
@@ -95,11 +93,8 @@ const DefaultStaticGenerationOptions = {
|
|
|
95
93
|
page: '',
|
|
96
94
|
title: '',
|
|
97
95
|
outputPath: '',
|
|
98
|
-
deployId: '',
|
|
99
|
-
buildHost: '',
|
|
100
96
|
buildPath: '/',
|
|
101
97
|
env: 'production',
|
|
102
|
-
build: false,
|
|
103
98
|
dev: false,
|
|
104
99
|
minify: true,
|
|
105
100
|
metadata: {},
|
|
@@ -385,11 +380,8 @@ class UnderpostStatic {
|
|
|
385
380
|
* @param {string} [options.page] - Path to the SSR component to render
|
|
386
381
|
* @param {string} [options.title] - Page title (deprecated: use metadata.title)
|
|
387
382
|
* @param {string} [options.outputPath] - Output file path
|
|
388
|
-
* @param {string} [options.deployId] - Deployment identifier
|
|
389
|
-
* @param {string} [options.buildHost] - Build host URL
|
|
390
383
|
* @param {string} [options.buildPath='/'] - Build path
|
|
391
384
|
* @param {string} [options.env='production'] - Environment (development/production)
|
|
392
|
-
* @param {boolean} [options.build=false] - Whether to trigger build
|
|
393
385
|
* @param {boolean} [options.minify=true] - Minify HTML output
|
|
394
386
|
* @param {MetadataOptions} [options.metadata={}] - Comprehensive metadata options
|
|
395
387
|
* @param {Object} [options.scripts={}] - Script injection options
|
|
@@ -602,21 +594,29 @@ class UnderpostStatic {
|
|
|
602
594
|
}
|
|
603
595
|
}
|
|
604
596
|
|
|
605
|
-
//
|
|
606
|
-
if (options.
|
|
607
|
-
|
|
608
|
-
|
|
597
|
+
// Start standalone static file server if --run-sv is specified
|
|
598
|
+
if (options.runSv !== undefined) {
|
|
599
|
+
const port = typeof options.runSv === 'string' ? parseInt(options.runSv, 10) : 5000;
|
|
600
|
+
const servePath =
|
|
601
|
+
options.outputPath && options.outputPath !== '.'
|
|
602
|
+
? path.dirname(path.resolve(options.outputPath))
|
|
603
|
+
: path.resolve('.');
|
|
604
|
+
|
|
605
|
+
if (!fs.existsSync(servePath)) {
|
|
606
|
+
logger.error(`Serve path does not exist: ${servePath}`);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
609
|
|
|
610
|
-
|
|
611
|
-
shellExec(
|
|
612
|
-
`npm run build ${options.deployId}${options.buildHost ? ` ${options.buildHost} ${options.buildPath}` : ``}`,
|
|
613
|
-
);
|
|
610
|
+
const app = express();
|
|
614
611
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
612
|
+
app.use(loggerMiddleware(import.meta, 'debug', () => false));
|
|
613
|
+
|
|
614
|
+
app.use('/', express.static(servePath));
|
|
615
|
+
|
|
616
|
+
app.listen(port, () => {
|
|
617
|
+
logger.info(`Static file server running at http://localhost:${port}`);
|
|
618
|
+
logger.info(`Serving files from: ${servePath}`);
|
|
619
|
+
});
|
|
620
620
|
}
|
|
621
621
|
},
|
|
622
622
|
|
|
@@ -22,8 +22,9 @@ const Docs = {
|
|
|
22
22
|
return html`
|
|
23
23
|
<iframe
|
|
24
24
|
class="in iframe-${ModalId}"
|
|
25
|
-
style="width: 100%; border: none; background: white"
|
|
25
|
+
style="width: 100%; border: none; background: white; display: block"
|
|
26
26
|
src="${docData.url()}"
|
|
27
|
+
sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-popups-to-escape-sandbox"
|
|
27
28
|
>
|
|
28
29
|
</iframe>
|
|
29
30
|
`;
|
|
@@ -37,9 +38,27 @@ const Docs = {
|
|
|
37
38
|
query: true,
|
|
38
39
|
RouterInstance: Modal.Data['modal-docs'].options.RouterInstance,
|
|
39
40
|
});
|
|
41
|
+
const iframeEl = s(`.iframe-${ModalId}`);
|
|
42
|
+
if (iframeEl) {
|
|
43
|
+
iframeEl.addEventListener('load', () => {
|
|
44
|
+
try {
|
|
45
|
+
const iframeWin = iframeEl.contentWindow;
|
|
46
|
+
if (iframeWin) {
|
|
47
|
+
Object.defineProperty(iframeWin, 'parent', { get: () => iframeWin, configurable: false });
|
|
48
|
+
Object.defineProperty(iframeWin, 'top', { get: () => iframeWin, configurable: false });
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
// cross-origin or security restriction — safe to ignore
|
|
52
|
+
}
|
|
53
|
+
window.scrollTo(0, 0);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
40
56
|
Modal.Data[ModalId].onObserverListener[ModalId] = () => {
|
|
41
|
-
if (s(`.iframe-${ModalId}`))
|
|
42
|
-
|
|
57
|
+
if (s(`.iframe-${ModalId}`)) {
|
|
58
|
+
const barEl = s(`.bar-default-modal-${ModalId}`);
|
|
59
|
+
const barHeight = barEl ? barEl.offsetHeight : Modal.headerTitleHeight;
|
|
60
|
+
s(`.iframe-${ModalId}`).style.height = `${s(`.${ModalId}`).offsetHeight - barHeight}px`;
|
|
61
|
+
}
|
|
43
62
|
|
|
44
63
|
if (type.match('coverage')) {
|
|
45
64
|
simpleIconsRender(`.doc-icon-coverage`);
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import UnderpostBaremetal from './cli/baremetal.js';
|
|
8
8
|
import UnderpostCloudInit from './cli/cloud-init.js';
|
|
9
|
+
import UnderpostKickStart from './cli/kickstart.js';
|
|
9
10
|
import UnderpostCluster from './cli/cluster.js';
|
|
10
11
|
import UnderpostDB from './cli/db.js';
|
|
11
12
|
import UnderpostDeploy from './cli/deploy.js';
|
|
@@ -25,7 +26,7 @@ import UnderpostDns from './server/dns.js';
|
|
|
25
26
|
import UnderpostBackup from './server/backup.js';
|
|
26
27
|
import UnderpostCron from './server/cron.js';
|
|
27
28
|
import UnderpostStartUp from './server/start.js';
|
|
28
|
-
import
|
|
29
|
+
import UnderpostTLS from './server/tls.js';
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Underpost main module methods
|
|
@@ -39,7 +40,16 @@ class Underpost {
|
|
|
39
40
|
* @type {String}
|
|
40
41
|
* @memberof Underpost
|
|
41
42
|
*/
|
|
42
|
-
static version = 'v2.99.
|
|
43
|
+
static version = 'v2.99.6';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Required Node.js major version
|
|
47
|
+
* @static
|
|
48
|
+
* @type {String}
|
|
49
|
+
* @memberof Underpost
|
|
50
|
+
*/
|
|
51
|
+
static majorNodejsVersion = 'v24';
|
|
52
|
+
|
|
43
53
|
/**
|
|
44
54
|
* Repository cli API
|
|
45
55
|
* @static
|
|
@@ -170,6 +180,16 @@ class Underpost {
|
|
|
170
180
|
return UnderpostCloudInit.API;
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
/**
|
|
184
|
+
* KickStart cli API
|
|
185
|
+
* @static
|
|
186
|
+
* @type {UnderpostKickStart.API}
|
|
187
|
+
* @memberof Underpost
|
|
188
|
+
*/
|
|
189
|
+
static get kickstart() {
|
|
190
|
+
return UnderpostKickStart.API;
|
|
191
|
+
}
|
|
192
|
+
|
|
173
193
|
/**
|
|
174
194
|
* Run cli API
|
|
175
195
|
* @static
|
|
@@ -233,14 +253,19 @@ class Underpost {
|
|
|
233
253
|
/**
|
|
234
254
|
* TLS/SSL server utilities API
|
|
235
255
|
* @static
|
|
236
|
-
* @type {
|
|
256
|
+
* @type {UnderpostTLS.API}
|
|
237
257
|
* @memberof Underpost
|
|
238
258
|
*/
|
|
239
259
|
static get tls() {
|
|
240
|
-
return
|
|
260
|
+
return UnderpostTLS.API;
|
|
241
261
|
}
|
|
242
262
|
}
|
|
243
263
|
|
|
264
|
+
if (!process.version || !process.version.startsWith(`${Underpost.majorNodejsVersion}.`))
|
|
265
|
+
console.warn(
|
|
266
|
+
`${`Underpost Warning: Required Node.js version is `.red}${`${Underpost.majorNodejsVersion}.x`.bgBlue.bold.white}${`, you are using `.red}${process.version.bgRed.bold.white}`,
|
|
267
|
+
);
|
|
268
|
+
|
|
244
269
|
const up = Underpost;
|
|
245
270
|
|
|
246
271
|
const underpost = Underpost;
|
|
@@ -269,7 +294,7 @@ export {
|
|
|
269
294
|
UnderpostBackup,
|
|
270
295
|
UnderpostCron,
|
|
271
296
|
UnderpostStartUp,
|
|
272
|
-
|
|
297
|
+
UnderpostTLS,
|
|
273
298
|
};
|
|
274
299
|
|
|
275
300
|
export default Underpost;
|
package/src/server/backup.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Manages backup operations for deployments.
|
|
3
3
|
* @module src/server/backup.js
|
|
4
|
-
* @namespace
|
|
4
|
+
* @namespace UnderpostBakcUp
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import fs from 'fs-extra';
|
|
@@ -16,7 +16,7 @@ const logger = loggerFactory(import.meta);
|
|
|
16
16
|
/**
|
|
17
17
|
* @class BackUp
|
|
18
18
|
* @description Manages backup operations for deployments.
|
|
19
|
-
* @memberof
|
|
19
|
+
* @memberof UnderpostBakcUp
|
|
20
20
|
*/
|
|
21
21
|
class BackUp {
|
|
22
22
|
/**
|
|
@@ -25,7 +25,10 @@ class BackUp {
|
|
|
25
25
|
* @param {string} deployList - The list of deployments to backup.
|
|
26
26
|
* @param {Object} options - The options for the backup operation.
|
|
27
27
|
* @param {boolean} options.git - Whether to backup data using Git.
|
|
28
|
-
* @
|
|
28
|
+
* @param {boolean} [options.k3s] - Use k3s cluster context.
|
|
29
|
+
* @param {boolean} [options.kind] - Use kind cluster context.
|
|
30
|
+
* @param {boolean} [options.kubeadm] - Use kubeadm cluster context.
|
|
31
|
+
* @memberof UnderpostBakcUp
|
|
29
32
|
*/
|
|
30
33
|
static callback = async function (deployList, options = { git: false }) {
|
|
31
34
|
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
@@ -34,12 +37,16 @@ class BackUp {
|
|
|
34
37
|
logger.info('init backups callback', deployList);
|
|
35
38
|
await logger.setUpInfo();
|
|
36
39
|
|
|
40
|
+
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : options.kubeadm ? ' --kubeadm' : '';
|
|
41
|
+
|
|
37
42
|
for (const _deployId of deployList.split(',')) {
|
|
38
43
|
const deployId = _deployId.trim();
|
|
39
44
|
if (!deployId) continue;
|
|
40
45
|
|
|
41
46
|
logger.info('Executing database export for', deployId);
|
|
42
|
-
shellExec(
|
|
47
|
+
shellExec(
|
|
48
|
+
`node bin db ${options.git ? '--git --force-clone ' : ''}--export --primary-pod${clusterFlag} ${deployId}`,
|
|
49
|
+
);
|
|
43
50
|
}
|
|
44
51
|
};
|
|
45
52
|
}
|
|
@@ -137,7 +137,7 @@ const buildJsDocs = async ({ host, path, metadata = {} }) => {
|
|
|
137
137
|
|
|
138
138
|
jsDocsConfig.opts.destination = `./public/${host}${path === '/' ? path : `${path}/`}docs/`;
|
|
139
139
|
jsDocsConfig.opts.theme_opts.title = metadata?.title ? metadata.title : undefined;
|
|
140
|
-
jsDocsConfig.opts.theme_opts.favicon = `./public/${host}${path === '/' ?
|
|
140
|
+
jsDocsConfig.opts.theme_opts.favicon = `./public/${host}${path === '/' ? '/' : `${path}/`}favicon.ico`;
|
|
141
141
|
|
|
142
142
|
fs.writeFileSync(`./jsdoc.json`, JSON.stringify(jsDocsConfig, null, 4), 'utf8');
|
|
143
143
|
logger.warn('build jsdoc view', jsDocsConfig.opts.destination);
|
package/src/server/conf.js
CHANGED
|
@@ -1172,14 +1172,6 @@ const getPathsSSR = (conf) => {
|
|
|
1172
1172
|
* @memberof ServerConfBuilder
|
|
1173
1173
|
*/
|
|
1174
1174
|
const Cmd = {
|
|
1175
|
-
/**
|
|
1176
|
-
* @method delete
|
|
1177
|
-
* @description Deletes the deploy.
|
|
1178
|
-
* @param {string} deployId - The deploy ID.
|
|
1179
|
-
* @returns {string} - The delete command.
|
|
1180
|
-
* @memberof Cmd
|
|
1181
|
-
*/
|
|
1182
|
-
delete: (deployId) => `pm2 delete ${deployId}`,
|
|
1183
1175
|
/**
|
|
1184
1176
|
* @method run
|
|
1185
1177
|
* @description Runs the deploy.
|
|
@@ -1221,20 +1213,6 @@ const Cmd = {
|
|
|
1221
1213
|
* @memberof Cmd
|
|
1222
1214
|
*/
|
|
1223
1215
|
syncPorts: () => `node bin/deploy sync-env-port`,
|
|
1224
|
-
/**
|
|
1225
|
-
* @method cron
|
|
1226
|
-
* @description Creates a cron job.
|
|
1227
|
-
* @param {string} deployList - The deploy list.
|
|
1228
|
-
* @param {string} jobList - The job list.
|
|
1229
|
-
* @param {string} name - The name.
|
|
1230
|
-
* @param {string} expression - The expression.
|
|
1231
|
-
* @param {object} options - The options.
|
|
1232
|
-
* @param {number} instances - The number of PM2 instances (default: 1).
|
|
1233
|
-
* @returns {string} - The cron command.
|
|
1234
|
-
* @memberof Cmd
|
|
1235
|
-
*/
|
|
1236
|
-
cron: (deployList, jobList, name, expression, options, instances = 1) =>
|
|
1237
|
-
`pm2 start ./bin/index.js --no-autorestart --instances ${instances} --cron "${expression}" --name ${name} -- cron ${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1238
1216
|
};
|
|
1239
1217
|
|
|
1240
1218
|
/**
|