underpost 3.2.2 → 3.2.4
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/.github/workflows/publish.ci.yml +21 -8
- package/CHANGELOG.md +20 -0
- package/CLI-HELP.md +5 -2
- package/README.md +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -3
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -3
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -2
- package/src/cli/db.js +8 -26
- package/src/cli/env.js +10 -0
- package/src/cli/index.js +3 -0
- package/src/cli/repository.js +20 -16
- package/src/cli/run.js +4 -0
- package/src/index.js +1 -1
- package/src/server/backup.js +40 -45
- package/src/server/cron.js +2 -3
- package/src/server/start.js +1 -2
|
@@ -3,17 +3,27 @@ on:
|
|
|
3
3
|
push:
|
|
4
4
|
tags:
|
|
5
5
|
- 'v*'
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write
|
|
8
|
+
packages: write
|
|
9
|
+
id-token: write
|
|
6
10
|
jobs:
|
|
7
11
|
build-and-publish:
|
|
8
12
|
# prevents this action from running on forks
|
|
9
13
|
if: github.repository == 'underpostnet/pwa-microservices-template'
|
|
10
14
|
runs-on: ubuntu-latest
|
|
11
15
|
permissions:
|
|
12
|
-
contents:
|
|
16
|
+
contents: write
|
|
17
|
+
packages: write
|
|
13
18
|
id-token: write
|
|
14
19
|
steps:
|
|
15
20
|
- uses: actions/checkout@v6
|
|
16
21
|
|
|
22
|
+
- name: Install required packages
|
|
23
|
+
run: |
|
|
24
|
+
sudo apt-get update -y
|
|
25
|
+
sudo apt-get install -y sudo tar gzip bzip2 git curl
|
|
26
|
+
|
|
17
27
|
- uses: actions/setup-node@v6
|
|
18
28
|
with:
|
|
19
29
|
node-version: '24.x'
|
|
@@ -27,12 +37,21 @@ jobs:
|
|
|
27
37
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
28
38
|
run: npm publish --provenance --access public
|
|
29
39
|
|
|
40
|
+
- name: Dispatch release CD
|
|
41
|
+
run: |
|
|
42
|
+
curl -s -f -X POST \
|
|
43
|
+
-H "Accept: application/vnd.github.v3+json" \
|
|
44
|
+
-H "Authorization: token ${{ secrets.GIT_AUTH_TOKEN }}" \
|
|
45
|
+
"https://api.github.com/repos/underpostnet/pwa-microservices-template/actions/workflows/release.cd.yml/dispatches" \
|
|
46
|
+
-d '{"ref":"master"}'
|
|
47
|
+
|
|
30
48
|
build-and-publish-ghpkg:
|
|
31
49
|
# prevents this action from running on forks
|
|
32
50
|
if: github.repository == 'underpostnet/pwa-microservices-template-ghpkg'
|
|
33
51
|
runs-on: ubuntu-latest
|
|
34
52
|
permissions:
|
|
35
|
-
contents:
|
|
53
|
+
contents: write
|
|
54
|
+
packages: write
|
|
36
55
|
id-token: write
|
|
37
56
|
steps:
|
|
38
57
|
- uses: actions/checkout@v6
|
|
@@ -66,9 +85,3 @@ jobs:
|
|
|
66
85
|
npm publish
|
|
67
86
|
env:
|
|
68
87
|
NODE_AUTH_TOKEN: ${{ secrets.GIT_AUTH_TOKEN }}
|
|
69
|
-
|
|
70
|
-
# Release deploy — triggers release.cd.yml after Docker build succeeds
|
|
71
|
-
deploy-release:
|
|
72
|
-
needs: build-and-publish
|
|
73
|
-
uses: ./.github/workflows/release.cd.yml
|
|
74
|
-
secrets: inherit
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## 2026-04-15
|
|
4
4
|
|
|
5
|
+
### cli-cron
|
|
6
|
+
|
|
7
|
+
- Update underpost container environment path for volume mount ([8fdfb5416](https://github.com/underpostnet/engine/commit/8fdfb54165f4ef7379fccbeb20e5c476320bc1f6))
|
|
8
|
+
|
|
9
|
+
### github-actions
|
|
10
|
+
|
|
11
|
+
- Add dispatch step for release CD in publish workflow ([8dc0e3ccd](https://github.com/underpostnet/engine/commit/8dc0e3ccd1a578f776edf215428d08640b44c3d1))
|
|
12
|
+
|
|
13
|
+
## New release v:3.2.3 (2026-04-15)
|
|
14
|
+
|
|
15
|
+
### cli-cron
|
|
16
|
+
|
|
17
|
+
- Remove is-inside-container dependency and implement isInsideContainer method in env module ([79d39ece0](https://github.com/underpostnet/engine/commit/79d39ece0db1f3acb65af22e3bc7f7c6a66487a9))
|
|
18
|
+
|
|
19
|
+
### github-actions
|
|
20
|
+
|
|
21
|
+
- Ensure deploy-release job runs only on successful build-and-publish ([08ba04632](https://github.com/underpostnet/engine/commit/08ba0463263f6cb2b6c14a6bd56e547c152a0a3a))
|
|
22
|
+
|
|
23
|
+
## New release v:3.2.2 (2026-04-15)
|
|
24
|
+
|
|
5
25
|
### docker-image
|
|
6
26
|
|
|
7
27
|
- Remove unnecessary directory creation and volume declaration for working directory in Dockerfile ([84f7f8950](https://github.com/underpostnet/engine/commit/84f7f8950d45512b6177c7523e4d278f2db25ef4))
|
package/CLI-HELP.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
## underpost ci/cd cli v3.2.
|
|
1
|
+
## underpost ci/cd cli v3.2.4
|
|
2
2
|
|
|
3
3
|
### Usage: `underpost [options] [command]`
|
|
4
4
|
```
|
|
@@ -321,7 +321,7 @@ Manages Underpost configurations using various operators.
|
|
|
321
321
|
|
|
322
322
|
Arguments:
|
|
323
323
|
operator The configuration operation to perform. Options: set,
|
|
324
|
-
delete, get, list, clean.
|
|
324
|
+
delete, get, list, clean, isInsideContainer.
|
|
325
325
|
key Optional: The specific configuration key to manage.
|
|
326
326
|
value Optional: The value to set for the configuration key.
|
|
327
327
|
|
|
@@ -562,6 +562,8 @@ Options:
|
|
|
562
562
|
environment file.
|
|
563
563
|
--create-from-env Creates secrets from container environment
|
|
564
564
|
variables (envFrom: secretRef).
|
|
565
|
+
--global-clean Removes all filesystem traces of secrets
|
|
566
|
+
(engine-private, .env, conf cache).
|
|
565
567
|
--list Lists all available secrets for the
|
|
566
568
|
platform.
|
|
567
569
|
-h, --help display help for command
|
|
@@ -685,6 +687,7 @@ Options:
|
|
|
685
687
|
--instances Apply to instance data collection
|
|
686
688
|
--generate Generate cluster metadata
|
|
687
689
|
--itc Apply under container execution context
|
|
690
|
+
--dev Sets the development cli context
|
|
688
691
|
-h, --help display help for command
|
|
689
692
|
|
|
690
693
|
```
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
<div align="center">
|
|
18
18
|
|
|
19
|
-
[](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml) [](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [](https://www.npmjs.com/package/underpost) [](https://socket.dev/npm/package/underpost/overview/3.2.4) [](https://coveralls.io/github/underpostnet/engine?branch=master) [](https://www.npmjs.org/package/underpost) [](https://www.npmjs.com/package/underpost)
|
|
20
20
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
@@ -61,7 +61,7 @@ npm run dev
|
|
|
61
61
|
<a target="_top" href="https://www.nexodev.org/docs?cid=src">See Docs here.</a>
|
|
62
62
|
|
|
63
63
|
<!-- cli-index-start -->
|
|
64
|
-
## underpost ci/cd cli v3.2.
|
|
64
|
+
## underpost ci/cd cli v3.2.4
|
|
65
65
|
|
|
66
66
|
### Usage: `underpost [options] [command]`
|
|
67
67
|
```
|
|
@@ -23,7 +23,7 @@ spec:
|
|
|
23
23
|
spec:
|
|
24
24
|
containers:
|
|
25
25
|
- name: dd-cron-backup
|
|
26
|
-
image: underpost/underpost-engine:v3.2.
|
|
26
|
+
image: underpost/underpost-engine:v3.2.4
|
|
27
27
|
command:
|
|
28
28
|
- /bin/sh
|
|
29
29
|
- -c
|
|
@@ -35,9 +35,8 @@ spec:
|
|
|
35
35
|
volumeMounts:
|
|
36
36
|
- mountPath: /home/dd/engine
|
|
37
37
|
name: underpost-cron-container-volume
|
|
38
|
-
- mountPath: /usr/lib/node_modules/underpost
|
|
38
|
+
- mountPath: /usr/lib/node_modules/underpost
|
|
39
39
|
name: underpost-share-env
|
|
40
|
-
subPath: .env
|
|
41
40
|
volumes:
|
|
42
41
|
- hostPath:
|
|
43
42
|
path: /home/dd/engine
|
|
@@ -23,7 +23,7 @@ spec:
|
|
|
23
23
|
spec:
|
|
24
24
|
containers:
|
|
25
25
|
- name: dd-cron-dns
|
|
26
|
-
image: underpost/underpost-engine:v3.2.
|
|
26
|
+
image: underpost/underpost-engine:v3.2.4
|
|
27
27
|
command:
|
|
28
28
|
- /bin/sh
|
|
29
29
|
- -c
|
|
@@ -35,9 +35,8 @@ spec:
|
|
|
35
35
|
volumeMounts:
|
|
36
36
|
- mountPath: /home/dd/engine
|
|
37
37
|
name: underpost-cron-container-volume
|
|
38
|
-
- mountPath: /usr/lib/node_modules/underpost
|
|
38
|
+
- mountPath: /usr/lib/node_modules/underpost
|
|
39
39
|
name: underpost-share-env
|
|
40
|
-
subPath: .env
|
|
41
40
|
volumes:
|
|
42
41
|
- hostPath:
|
|
43
42
|
path: /home/dd/engine
|
|
@@ -17,7 +17,7 @@ spec:
|
|
|
17
17
|
spec:
|
|
18
18
|
containers:
|
|
19
19
|
- name: dd-default-development-blue
|
|
20
|
-
image: localhost/rockylinux9-underpost:v3.2.
|
|
20
|
+
image: localhost/rockylinux9-underpost:v3.2.4
|
|
21
21
|
# resources:
|
|
22
22
|
# requests:
|
|
23
23
|
# memory: "124Ki"
|
|
@@ -100,7 +100,7 @@ spec:
|
|
|
100
100
|
spec:
|
|
101
101
|
containers:
|
|
102
102
|
- name: dd-default-development-green
|
|
103
|
-
image: localhost/rockylinux9-underpost:v3.2.
|
|
103
|
+
image: localhost/rockylinux9-underpost:v3.2.4
|
|
104
104
|
# resources:
|
|
105
105
|
# requests:
|
|
106
106
|
# memory: "124Ki"
|
|
@@ -20,7 +20,7 @@ spec:
|
|
|
20
20
|
spec:
|
|
21
21
|
containers:
|
|
22
22
|
- name: dd-test-development-blue
|
|
23
|
-
image: localhost/rockylinux9-underpost:v3.2.
|
|
23
|
+
image: localhost/rockylinux9-underpost:v3.2.4
|
|
24
24
|
envFrom:
|
|
25
25
|
- secretRef:
|
|
26
26
|
name: underpost-config
|
|
@@ -112,7 +112,7 @@ spec:
|
|
|
112
112
|
spec:
|
|
113
113
|
containers:
|
|
114
114
|
- name: dd-test-development-green
|
|
115
|
-
image: localhost/rockylinux9-underpost:v3.2.
|
|
115
|
+
image: localhost/rockylinux9-underpost:v3.2.4
|
|
116
116
|
envFrom:
|
|
117
117
|
- secretRef:
|
|
118
118
|
name: underpost-config
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"main": "src/index.js",
|
|
4
4
|
"name": "underpost",
|
|
5
|
-
"version": "3.2.
|
|
5
|
+
"version": "3.2.4",
|
|
6
6
|
"description": "pwa api rest template",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"start": "node --max-old-space-size=8192 src/server",
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"http-proxy-middleware": "^3.0.5",
|
|
87
87
|
"ignore-walk": "^8.0.0",
|
|
88
88
|
"iovalkey": "^0.3.3",
|
|
89
|
-
"is-inside-container": "^1.0.0",
|
|
90
89
|
"json-colorizer": "^3.0.1",
|
|
91
90
|
"jsonwebtoken": "^9.0.3",
|
|
92
91
|
"mariadb": "^3.2.2",
|
package/src/cli/db.js
CHANGED
|
@@ -14,7 +14,6 @@ import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
|
14
14
|
import { loadReplicas, pathPortAssignmentFactory, loadCronDeployEnv } from '../server/conf.js';
|
|
15
15
|
import Underpost from '../index.js';
|
|
16
16
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
17
|
-
import isInsideContainer from 'is-inside-container';
|
|
18
17
|
const logger = loggerFactory(import.meta);
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -582,10 +581,9 @@ class UnderpostDB {
|
|
|
582
581
|
repoBackup: false,
|
|
583
582
|
},
|
|
584
583
|
) {
|
|
585
|
-
// Ensure engine-private is available (clone
|
|
584
|
+
// Ensure engine-private is available (clone if inside a deployment
|
|
586
585
|
// container where globalSecretClean has already removed it).
|
|
587
586
|
const firstDeployId = deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
|
|
588
|
-
const { ephemeral } = Underpost.repo.privateEngineRepoFactory(firstDeployId || undefined);
|
|
589
587
|
try {
|
|
590
588
|
loadCronDeployEnv();
|
|
591
589
|
const newBackupTimestamp = new Date().getTime();
|
|
@@ -948,11 +946,6 @@ class UnderpostDB {
|
|
|
948
946
|
} catch (error) {
|
|
949
947
|
logger.error('Database operation failed', { error: error.message });
|
|
950
948
|
throw error;
|
|
951
|
-
} finally {
|
|
952
|
-
if (ephemeral && isInsideContainer()) {
|
|
953
|
-
Underpost.repo.cleanupPrivateEngineRepo();
|
|
954
|
-
Underpost.env.clean();
|
|
955
|
-
}
|
|
956
949
|
}
|
|
957
950
|
},
|
|
958
951
|
|
|
@@ -965,6 +958,8 @@ class UnderpostDB {
|
|
|
965
958
|
* @param {string} [deployId=process.env.DEFAULT_DEPLOY_ID] - The deployment ID.
|
|
966
959
|
* @param {string} [host=process.env.DEFAULT_DEPLOY_HOST] - The host identifier.
|
|
967
960
|
* @param {string} [path=process.env.DEFAULT_DEPLOY_PATH] - The path identifier.
|
|
961
|
+
* @param {object} [options] - Options.
|
|
962
|
+
* @param {boolean} [options.dev=false] - Development mode flag.
|
|
968
963
|
* @return {Promise<void>} Resolves when metadata creation is complete.
|
|
969
964
|
* @throws {Error} If database configuration is invalid or connection fails.
|
|
970
965
|
*/
|
|
@@ -972,8 +967,8 @@ class UnderpostDB {
|
|
|
972
967
|
deployId = process.env.DEFAULT_DEPLOY_ID,
|
|
973
968
|
host = process.env.DEFAULT_DEPLOY_HOST,
|
|
974
969
|
path = process.env.DEFAULT_DEPLOY_PATH,
|
|
970
|
+
options = { dev: false },
|
|
975
971
|
) {
|
|
976
|
-
const { ephemeral } = Underpost.repo.privateEngineRepoFactory(deployId || undefined);
|
|
977
972
|
try {
|
|
978
973
|
loadCronDeployEnv();
|
|
979
974
|
deployId = deployId ? deployId : process.env.DEFAULT_DEPLOY_ID;
|
|
@@ -1146,11 +1141,6 @@ class UnderpostDB {
|
|
|
1146
1141
|
} catch (error) {
|
|
1147
1142
|
logger.error('Cluster metadata creation failed', { error: error.message });
|
|
1148
1143
|
throw error;
|
|
1149
|
-
} finally {
|
|
1150
|
-
if (ephemeral && isInsideContainer()) {
|
|
1151
|
-
Underpost.repo.cleanupPrivateEngineRepo();
|
|
1152
|
-
Underpost.env.clean();
|
|
1153
|
-
}
|
|
1154
1144
|
}
|
|
1155
1145
|
},
|
|
1156
1146
|
|
|
@@ -1165,6 +1155,7 @@ class UnderpostDB {
|
|
|
1165
1155
|
* @param {string} [options.hosts=''] - Comma-separated list of hosts to filter.
|
|
1166
1156
|
* @param {string} [options.paths=''] - Comma-separated list of paths to filter.
|
|
1167
1157
|
* @param {boolean} [options.dryRun=false] - If true, only reports what would be deleted.
|
|
1158
|
+
* @param {boolean} [options.dev=false] - Development mode flag.
|
|
1168
1159
|
* @return {Promise<void>} Resolves when clean operation is complete.
|
|
1169
1160
|
*/
|
|
1170
1161
|
async cleanFsCollection(
|
|
@@ -1173,10 +1164,10 @@ class UnderpostDB {
|
|
|
1173
1164
|
hosts: '',
|
|
1174
1165
|
paths: '',
|
|
1175
1166
|
dryRun: false,
|
|
1167
|
+
dev: false,
|
|
1176
1168
|
},
|
|
1177
1169
|
) {
|
|
1178
1170
|
const firstDeployId = deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
|
|
1179
|
-
const { ephemeral } = Underpost.repo.privateEngineRepoFactory(firstDeployId || undefined);
|
|
1180
1171
|
try {
|
|
1181
1172
|
loadCronDeployEnv();
|
|
1182
1173
|
if (deployList === 'dd') deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
@@ -1386,11 +1377,6 @@ class UnderpostDB {
|
|
|
1386
1377
|
} catch (error) {
|
|
1387
1378
|
logger.error('File collection cleanup failed', { error: error.message });
|
|
1388
1379
|
throw error;
|
|
1389
|
-
} finally {
|
|
1390
|
-
if (ephemeral && isInsideContainer()) {
|
|
1391
|
-
Underpost.repo.cleanupPrivateEngineRepo();
|
|
1392
|
-
Underpost.env.clean();
|
|
1393
|
-
}
|
|
1394
1380
|
}
|
|
1395
1381
|
},
|
|
1396
1382
|
|
|
@@ -1410,6 +1396,7 @@ class UnderpostDB {
|
|
|
1410
1396
|
* @param {boolean} [options.export=false] - Export metadata to backup.
|
|
1411
1397
|
* @param {boolean} [options.instances=false] - Process instances collection.
|
|
1412
1398
|
* @param {boolean} [options.crons=false] - Process crons collection.
|
|
1399
|
+
* @param {boolean} [options.dev=false] - Development mode flag.
|
|
1413
1400
|
* @return {Promise<void>} Resolves when backup operation is complete.
|
|
1414
1401
|
*/
|
|
1415
1402
|
async clusterMetadataBackupCallback(
|
|
@@ -1423,9 +1410,9 @@ class UnderpostDB {
|
|
|
1423
1410
|
export: false,
|
|
1424
1411
|
instances: false,
|
|
1425
1412
|
crons: false,
|
|
1413
|
+
dev: false,
|
|
1426
1414
|
},
|
|
1427
1415
|
) {
|
|
1428
|
-
const { ephemeral } = Underpost.repo.privateEngineRepoFactory(deployId || undefined);
|
|
1429
1416
|
try {
|
|
1430
1417
|
loadCronDeployEnv();
|
|
1431
1418
|
deployId = deployId ? deployId : process.env.DEFAULT_DEPLOY_ID;
|
|
@@ -1492,11 +1479,6 @@ class UnderpostDB {
|
|
|
1492
1479
|
} catch (error) {
|
|
1493
1480
|
logger.error('Cluster metadata backup operation failed', { error: error.message });
|
|
1494
1481
|
throw error;
|
|
1495
|
-
} finally {
|
|
1496
|
-
if (ephemeral && isInsideContainer()) {
|
|
1497
|
-
Underpost.repo.cleanupPrivateEngineRepo();
|
|
1498
|
-
Underpost.env.clean();
|
|
1499
|
-
}
|
|
1500
1482
|
}
|
|
1501
1483
|
},
|
|
1502
1484
|
};
|
package/src/cli/env.js
CHANGED
|
@@ -153,6 +153,16 @@ class UnderpostRootEnv {
|
|
|
153
153
|
const envPath = `${exeRootPath}/.env`;
|
|
154
154
|
fs.removeSync(envPath);
|
|
155
155
|
},
|
|
156
|
+
/**
|
|
157
|
+
* @method isInsideContainer
|
|
158
|
+
* @description Detects whether the current process is running inside a container.
|
|
159
|
+
* Checks for Kubernetes service injection or Docker's .dockerenv marker.
|
|
160
|
+
* @returns {boolean} True if running inside a container.
|
|
161
|
+
* @memberof UnderpostEnv
|
|
162
|
+
*/
|
|
163
|
+
isInsideContainer() {
|
|
164
|
+
return !!process.env.KUBERNETES_SERVICE_HOST || fs.existsSync('/.dockerenv');
|
|
165
|
+
},
|
|
156
166
|
};
|
|
157
167
|
}
|
|
158
168
|
|
package/src/cli/index.js
CHANGED
|
@@ -338,9 +338,11 @@ program
|
|
|
338
338
|
.option('--init', 'Initializes the secrets platform environment.')
|
|
339
339
|
.option('--create-from-file <path-env-file>', 'Creates secrets from a specified environment file.')
|
|
340
340
|
.option('--create-from-env', 'Creates secrets from container environment variables (envFrom: secretRef).')
|
|
341
|
+
.option('--global-clean', 'Removes all filesystem traces of secrets (engine-private, .env, conf cache).')
|
|
341
342
|
.option('--list', 'Lists all available secrets for the platform.')
|
|
342
343
|
.description(`Manages secrets for various platforms.`)
|
|
343
344
|
.action((...args) => {
|
|
345
|
+
if (args[1].globalClean) return Underpost.secret.globalSecretClean();
|
|
344
346
|
if (args[1].createFromFile) return Underpost.secret[args[0]].createFromEnvFile(args[1].createFromFile);
|
|
345
347
|
if (args[1].createFromEnv) return Underpost.secret[args[0]].createFromContainerEnv();
|
|
346
348
|
if (args[1].list) return Underpost.secret[args[0]].list();
|
|
@@ -442,6 +444,7 @@ program
|
|
|
442
444
|
.option('--instances', 'Apply to instance data collection')
|
|
443
445
|
.option('--generate', 'Generate cluster metadata')
|
|
444
446
|
.option('--itc', 'Apply under container execution context')
|
|
447
|
+
.option('--dev', 'Sets the development cli context')
|
|
445
448
|
.description('Manages cluster metadata operations, including import and export.')
|
|
446
449
|
.action(Underpost.db.clusterMetadataBackupCallback);
|
|
447
450
|
|
package/src/cli/repository.js
CHANGED
|
@@ -1501,6 +1501,7 @@ Prevent build private config repo.`,
|
|
|
1501
1501
|
`git config --global --add safe.directory '${siteRoot}' 2>/dev/null || true`,
|
|
1502
1502
|
`cd '${siteRoot}' && git add -A && git commit -m 'backup $(date -u +%Y-%m-%dT%H:%M:%SZ)' || true`,
|
|
1503
1503
|
`cd '${siteRoot}' && underpost push . ${githubUsername}/${repoName}`,
|
|
1504
|
+
`cd /home/dd/engine && node bin secret underpost --global-clean`,
|
|
1504
1505
|
].join(' && ');
|
|
1505
1506
|
|
|
1506
1507
|
try {
|
|
@@ -1517,38 +1518,41 @@ Prevent build private config repo.`,
|
|
|
1517
1518
|
/**
|
|
1518
1519
|
* Clones the deploy-specific private repository into `./engine-private`
|
|
1519
1520
|
* when it does not already exist on disk. Returns `{ ephemeral: true }`
|
|
1520
|
-
*
|
|
1521
|
-
*
|
|
1522
|
-
*
|
|
1521
|
+
* If `./engine-private` already exists, the call is a no-op unless
|
|
1522
|
+
* `options.force` is `true`, in which case the directory is removed and
|
|
1523
|
+
* re-cloned.
|
|
1523
1524
|
*
|
|
1524
1525
|
* @param {string} [deployId] - Deploy ID (e.g. `dd-core`) used to derive
|
|
1525
1526
|
* the repo name `engine-{component}-private`. Falls back to
|
|
1526
|
-
* `process.env.DEFAULT_DEPLOY_ID`.
|
|
1527
|
-
*
|
|
1527
|
+
* `process.env.DEFAULT_DEPLOY_ID`. When neither is available the
|
|
1528
|
+
* default repo name `engine-private` is used.
|
|
1529
|
+
* @param {object} [options]
|
|
1530
|
+
* @param {boolean} [options.force=false] - Remove existing `engine-private`
|
|
1531
|
+
* and re-clone.
|
|
1528
1532
|
* @memberof UnderpostRepository
|
|
1529
1533
|
*/
|
|
1530
|
-
privateEngineRepoFactory(deployId) {
|
|
1531
|
-
if (fs.existsSync('./engine-private')) return
|
|
1534
|
+
privateEngineRepoFactory(deployId, options = { force: false }) {
|
|
1535
|
+
if (fs.existsSync('./engine-private') && !options.force) return;
|
|
1532
1536
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1537
|
+
if (options.force && fs.existsSync('./engine-private')) {
|
|
1538
|
+
fs.removeSync('./engine-private');
|
|
1539
|
+
logger.info('engine-private removed (force re-clone)');
|
|
1536
1540
|
}
|
|
1541
|
+
|
|
1542
|
+
const effectiveDeployId = deployId || process.env.DEFAULT_DEPLOY_ID;
|
|
1543
|
+
|
|
1537
1544
|
const username = process.env.GITHUB_USERNAME;
|
|
1538
1545
|
if (!username) {
|
|
1539
1546
|
throw new Error('privateEngineRepoFactory: GITHUB_USERNAME not set');
|
|
1540
1547
|
}
|
|
1541
1548
|
|
|
1542
|
-
const
|
|
1543
|
-
|
|
1544
|
-
logger.info(`engine-private missing — cloning ${username}/${repoName} (ephemeral)`);
|
|
1549
|
+
const repoName = effectiveDeployId ? `engine-${effectiveDeployId.split('-')[1]}-private` : 'engine-private';
|
|
1550
|
+
logger.info(`engine-private missing — cloning ${username}/${repoName}`);
|
|
1545
1551
|
shellExec(`underpost clone ${username}/${repoName}`);
|
|
1546
1552
|
if (!fs.existsSync(`./${repoName}`)) {
|
|
1547
1553
|
throw new Error(`privateEngineRepoFactory: clone failed for ${username}/${repoName}`);
|
|
1548
1554
|
}
|
|
1549
|
-
shellExec(`mv ./${repoName} ./engine-private`);
|
|
1550
|
-
|
|
1551
|
-
return { ephemeral: true };
|
|
1555
|
+
if (repoName !== 'engine-private') shellExec(`mv ./${repoName} ./engine-private`);
|
|
1552
1556
|
},
|
|
1553
1557
|
|
|
1554
1558
|
/**
|
package/src/cli/run.js
CHANGED
|
@@ -699,6 +699,10 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
699
699
|
);
|
|
700
700
|
|
|
701
701
|
if (isDeployRunnerContext(path, options)) {
|
|
702
|
+
// Backup app/services repositories with repo-backup configured
|
|
703
|
+
shellExec(
|
|
704
|
+
`${baseCommand} db ${deployId} ${clusterFlag} --repo-backup --dev --primary-pod --git --force-clone --preserveUUID ${options.namespace ? ` --ns ${options.namespace}` : ''}`,
|
|
705
|
+
);
|
|
702
706
|
shellExec(
|
|
703
707
|
`${baseCommand} deploy${clusterFlag}${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
|
|
704
708
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
package/src/index.js
CHANGED
package/src/server/backup.js
CHANGED
|
@@ -38,59 +38,54 @@ class BackUp {
|
|
|
38
38
|
*/
|
|
39
39
|
static callback = async function (deployList, options = { git: false }) {
|
|
40
40
|
const firstDeployId = deployList && deployList !== 'dd' ? deployList.split(',')[0].trim() : '';
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
45
|
-
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim();
|
|
41
|
+
loadCronDeployEnv();
|
|
42
|
+
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
43
|
+
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim();
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
logger.info('init backups callback', deployList);
|
|
46
|
+
await logger.setUpInfo();
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : options.kubeadm ? ' --kubeadm' : '';
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
for (const _deployId of deployList.split(',')) {
|
|
51
|
+
const deployId = _deployId.trim();
|
|
52
|
+
if (!deployId) continue;
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
const dbCommand = `node bin db ${options.git ? '--git --force-clone ' : ''}--export --primary-pod${clusterFlag} ${deployId}`;
|
|
55
|
+
const repoCommand = `node bin db --repo-backup${clusterFlag} ${deployId}`;
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
// Pass GITHUB_TOKEN and GITHUB_USERNAME ephemerally through the SSH command
|
|
58
|
+
// so git operations can push backups without relying on host env files.
|
|
59
|
+
const envPrefix = [
|
|
60
|
+
process.env.GITHUB_TOKEN ? `GITHUB_TOKEN=${process.env.GITHUB_TOKEN}` : '',
|
|
61
|
+
process.env.GITHUB_USERNAME ? `GITHUB_USERNAME=${process.env.GITHUB_USERNAME}` : '',
|
|
62
|
+
]
|
|
63
|
+
.filter(Boolean)
|
|
64
|
+
.join(' ');
|
|
65
|
+
const prefixCmd = (cmd) => (envPrefix ? `${envPrefix} ${cmd}` : cmd);
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
try {
|
|
68
|
+
logger.info('Executing database export via SSH for', deployId);
|
|
69
|
+
await Underpost.ssh.sshRemoteRunner(prefixCmd(dbCommand), {
|
|
70
|
+
remote: true,
|
|
71
|
+
useSudo: true,
|
|
72
|
+
cd: '/home/dd/engine',
|
|
73
|
+
});
|
|
74
|
+
} catch (err) {
|
|
75
|
+
logger.error(`Error during database export for ${deployId}:`, err);
|
|
76
|
+
}
|
|
79
77
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
78
|
+
// Repository backup: Cron container → SSH to host → host finds pod → kubectl exec git backup
|
|
79
|
+
try {
|
|
80
|
+
logger.info('Executing repository backup via SSH for', deployId);
|
|
81
|
+
await Underpost.ssh.sshRemoteRunner(prefixCmd(repoCommand), {
|
|
82
|
+
remote: true,
|
|
83
|
+
useSudo: true,
|
|
84
|
+
cd: '/home/dd/engine',
|
|
85
|
+
});
|
|
86
|
+
} catch (err) {
|
|
87
|
+
logger.error(`Error during repository backup for ${deployId}:`, err);
|
|
91
88
|
}
|
|
92
|
-
} finally {
|
|
93
|
-
if (ephemeral) Underpost.repo.cleanupPrivateEngineRepo();
|
|
94
89
|
}
|
|
95
90
|
};
|
|
96
91
|
}
|
package/src/server/cron.js
CHANGED
|
@@ -16,7 +16,7 @@ const volumeHostPath = '/home/dd';
|
|
|
16
16
|
const enginePath = '/home/dd/engine';
|
|
17
17
|
const cronVolumeName = 'underpost-cron-container-volume';
|
|
18
18
|
const shareEnvVolumeName = 'underpost-share-env';
|
|
19
|
-
const
|
|
19
|
+
const underpostContainerEnvDir = '/usr/lib/node_modules/underpost';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Generates a Kubernetes CronJob YAML manifest string.
|
|
@@ -105,9 +105,8 @@ spec:
|
|
|
105
105
|
volumeMounts:
|
|
106
106
|
- mountPath: ${enginePath}
|
|
107
107
|
name: ${cronVolumeName}
|
|
108
|
-
- mountPath: ${
|
|
108
|
+
- mountPath: ${underpostContainerEnvDir}
|
|
109
109
|
name: ${shareEnvVolumeName}
|
|
110
|
-
subPath: .env
|
|
111
110
|
volumes:
|
|
112
111
|
- hostPath:
|
|
113
112
|
path: ${enginePath}
|
package/src/server/start.js
CHANGED
|
@@ -9,7 +9,6 @@ import { awaitDeployMonitor } from './conf.js';
|
|
|
9
9
|
import { actionInitLog, loggerFactory } from './logger.js';
|
|
10
10
|
import { shellCd, shellExec } from './process.js';
|
|
11
11
|
import Underpost from '../index.js';
|
|
12
|
-
import isInsideContainer from 'is-inside-container';
|
|
13
12
|
const logger = loggerFactory(import.meta);
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -197,7 +196,7 @@ class UnderpostStartUp {
|
|
|
197
196
|
shellExec(`node bin env ${deployId} ${env}`);
|
|
198
197
|
shellExec(`npm ${runCmd} ${deployId}`, { async: true });
|
|
199
198
|
await awaitDeployMonitor(true);
|
|
200
|
-
if (env === 'production' && isInsideContainer()) Underpost.secret.globalSecretClean();
|
|
199
|
+
if (env === 'production' && Underpost.env.isInsideContainer()) Underpost.secret.globalSecretClean();
|
|
201
200
|
Underpost.env.set('container-status', `${deployId}-${env}-running-deployment`);
|
|
202
201
|
},
|
|
203
202
|
};
|