underpost 3.2.9 → 3.2.11
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/npmpkg.ci.yml +1 -0
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -0
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +195 -1
- package/CLI-HELP.md +92 -23
- package/README.md +38 -9
- package/bin/build.js +27 -7
- package/bin/build.template.js +187 -0
- package/bin/deploy.js +12 -2
- package/bin/index.js +2 -1
- package/bump.config.js +26 -0
- package/conf.js +20 -7
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +4 -2
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +27 -12
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +5 -5
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +5 -5
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +9 -7
- package/src/api/test/test.router.js +17 -12
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +5 -4
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +100 -35
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +700 -232
- package/src/cli/db.js +59 -60
- package/src/cli/deploy.js +216 -137
- package/src/cli/fs.js +13 -3
- package/src/cli/index.js +80 -15
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +9 -3
- package/src/cli/release.js +334 -140
- package/src/cli/repository.js +68 -23
- package/src/cli/run.js +191 -47
- package/src/cli/secrets.js +11 -2
- package/src/cli/test.js +9 -3
- package/src/client/Default.index.js +9 -3
- package/src/client/components/core/Auth.js +5 -0
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/client/components/core/PanelForm.js +56 -52
- package/src/client/components/core/Worker.js +162 -363
- package/src/client/sw/core.sw.js +174 -112
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +129 -21
- package/src/index.js +1 -1
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +81 -79
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +16 -4
- package/src/server/valkey.js +2 -0
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- /package/src/client/ssr/{offline → views}/Maintenance.js +0 -0
- /package/src/client/ssr/{offline → views}/NoNetworkConnection.js +0 -0
- /package/src/client/ssr/{pages → views}/Test.js +0 -0
package/src/cli/repository.js
CHANGED
|
@@ -924,8 +924,6 @@ class UnderpostRepository {
|
|
|
924
924
|
shellExec(`cd ${privateRepoPath} && underpost pull . ${process.env.GITHUB_USERNAME}/${privateRepoName}`, {
|
|
925
925
|
silent: true,
|
|
926
926
|
});
|
|
927
|
-
shellExec(`underpost run secret`);
|
|
928
|
-
shellExec(`underpost run underpost-config`);
|
|
929
927
|
const packageJsonDeploy = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
|
|
930
928
|
const packageJsonEngine = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
|
|
931
929
|
if (packageJsonDeploy.version !== packageJsonEngine.version) {
|
|
@@ -1008,11 +1006,14 @@ Prevent build private config repo.`,
|
|
|
1008
1006
|
const host = 'default.net';
|
|
1009
1007
|
const path = '/';
|
|
1010
1008
|
DefaultConf.server[host][path].valkey = {
|
|
1011
|
-
port: 6379,
|
|
1012
|
-
host: '
|
|
1009
|
+
port: 'env:VALKEY_PORT:int:6379',
|
|
1010
|
+
host: 'env:VALKEY_HOST:127.0.0.1',
|
|
1013
1011
|
};
|
|
1014
|
-
|
|
1015
|
-
DefaultConf.server[host][path].db.
|
|
1012
|
+
DefaultConf.server[host][path].db.host = 'env:DB_HOST:mongodb://127.0.0.1:27017';
|
|
1013
|
+
DefaultConf.server[host][path].db.replicaSet = 'env:DB_REPLICA_SET:rs0';
|
|
1014
|
+
DefaultConf.server[host][path].db.authSource = 'env:DB_AUTH_SOURCE:admin';
|
|
1015
|
+
DefaultConf.server[host][path].db.user = 'env:DB_USER:';
|
|
1016
|
+
DefaultConf.server[host][path].db.password = 'env:DB_PASSWORD:';
|
|
1016
1017
|
defaultConf = true;
|
|
1017
1018
|
break;
|
|
1018
1019
|
}
|
|
@@ -1048,9 +1049,9 @@ Prevent build private config repo.`,
|
|
|
1048
1049
|
*/
|
|
1049
1050
|
clean(options = { paths: [''] }) {
|
|
1050
1051
|
for (const path of options.paths) {
|
|
1051
|
-
shellExec(`cd ${path} && git reset`, { silent: true });
|
|
1052
|
-
shellExec(`cd ${path} && git checkout .`, { silent: true });
|
|
1053
|
-
shellExec(`cd ${path} && git clean -f -d`, { silent: true });
|
|
1052
|
+
shellExec(`cd ${path} && git reset`, { silentOnError: true, silent: true, disableLog: true });
|
|
1053
|
+
shellExec(`cd ${path} && git checkout .`, { silentOnError: true, silent: true, disableLog: true });
|
|
1054
|
+
shellExec(`cd ${path} && git clean -f -d`, { silentOnError: true, silent: true, disableLog: true });
|
|
1054
1055
|
}
|
|
1055
1056
|
},
|
|
1056
1057
|
|
|
@@ -1104,7 +1105,7 @@ Prevent build private config repo.`,
|
|
|
1104
1105
|
|
|
1105
1106
|
try {
|
|
1106
1107
|
// Fetch directory contents recursively
|
|
1107
|
-
const copiedFiles = await this.
|
|
1108
|
+
const copiedFiles = await this.fetchAndCopyGitHubDirectory({
|
|
1108
1109
|
apiUrl,
|
|
1109
1110
|
targetPath,
|
|
1110
1111
|
basePath: directoryPath,
|
|
@@ -1140,7 +1141,7 @@ Prevent build private config repo.`,
|
|
|
1140
1141
|
* @returns {Promise<array>} Array of copied file paths.
|
|
1141
1142
|
* @memberof UnderpostRepository
|
|
1142
1143
|
*/
|
|
1143
|
-
async
|
|
1144
|
+
async fetchAndCopyGitHubDirectory(options) {
|
|
1144
1145
|
const { apiUrl, targetPath, basePath, branch } = options;
|
|
1145
1146
|
const copiedFiles = [];
|
|
1146
1147
|
|
|
@@ -1175,14 +1176,12 @@ Prevent build private config repo.`,
|
|
|
1175
1176
|
|
|
1176
1177
|
logger.info(`Found ${contents.length} items in directory: ${basePath}`);
|
|
1177
1178
|
|
|
1178
|
-
// Process each item in the directory
|
|
1179
1179
|
for (const item of contents) {
|
|
1180
1180
|
const itemTargetPath = `${targetPath}/${item.name}`;
|
|
1181
1181
|
|
|
1182
1182
|
if (item.type === 'file') {
|
|
1183
1183
|
logger.info(`Downloading file: ${item.path}`);
|
|
1184
1184
|
|
|
1185
|
-
// Download file content
|
|
1186
1185
|
const fileResponse = await fetch(item.download_url);
|
|
1187
1186
|
if (!fileResponse.ok) {
|
|
1188
1187
|
logger.error(`Failed to download: ${item.download_url}`);
|
|
@@ -1192,16 +1191,14 @@ Prevent build private config repo.`,
|
|
|
1192
1191
|
const fileContent = await fileResponse.text();
|
|
1193
1192
|
fs.writeFileSync(itemTargetPath, fileContent);
|
|
1194
1193
|
|
|
1195
|
-
logger.info(
|
|
1194
|
+
logger.info(`Saved: ${itemTargetPath}`);
|
|
1196
1195
|
copiedFiles.push(itemTargetPath);
|
|
1197
1196
|
} else if (item.type === 'dir') {
|
|
1198
|
-
logger.info(
|
|
1197
|
+
logger.info(`Processing directory: ${item.path}`);
|
|
1199
1198
|
|
|
1200
|
-
// Create subdirectory
|
|
1201
1199
|
fs.mkdirSync(itemTargetPath, { recursive: true });
|
|
1202
1200
|
|
|
1203
|
-
|
|
1204
|
-
const subFiles = await this._fetchAndCopyGitHubDirectory({
|
|
1201
|
+
const subFiles = await this.fetchAndCopyGitHubDirectory({
|
|
1205
1202
|
apiUrl: item.url,
|
|
1206
1203
|
targetPath: itemTargetPath,
|
|
1207
1204
|
basePath: item.path,
|
|
@@ -1209,7 +1206,7 @@ Prevent build private config repo.`,
|
|
|
1209
1206
|
});
|
|
1210
1207
|
|
|
1211
1208
|
copiedFiles.push(...subFiles);
|
|
1212
|
-
logger.info(
|
|
1209
|
+
logger.info(`Completed directory: ${item.path} (${subFiles.length} files)`);
|
|
1213
1210
|
} else {
|
|
1214
1211
|
logger.warn(`Skipping unknown item type '${item.type}': ${item.path}`);
|
|
1215
1212
|
}
|
|
@@ -1295,7 +1292,7 @@ Prevent build private config repo.`,
|
|
|
1295
1292
|
},
|
|
1296
1293
|
/**
|
|
1297
1294
|
* Checks whether a remote Git repository URL is reachable.
|
|
1298
|
-
* Uses `
|
|
1295
|
+
* Uses `silentOnError` so a non-reachable remote returns false instead of throwing.
|
|
1299
1296
|
* Injects `GITHUB_TOKEN` into GitHub HTTPS URLs when available.
|
|
1300
1297
|
* @param {string} url - Full HTTPS clone URL to test (e.g. "https://github.com/org/repo.git").
|
|
1301
1298
|
* @returns {boolean} `true` when the remote responded with at least one ref hash.
|
|
@@ -1305,10 +1302,11 @@ Prevent build private config repo.`,
|
|
|
1305
1302
|
if (!url) return false;
|
|
1306
1303
|
const authUrl = Underpost.repo.resolveAuthUrl(url);
|
|
1307
1304
|
// GIT_TERMINAL_PROMPT=0 prevents git from hanging on credential prompts inside containers.
|
|
1308
|
-
const raw = shellExec(`GIT_TERMINAL_PROMPT=0 git ls-remote "${authUrl}" HEAD 2>&1
|
|
1305
|
+
const raw = shellExec(`GIT_TERMINAL_PROMPT=0 git ls-remote "${authUrl}" HEAD 2>&1`, {
|
|
1309
1306
|
stdout: true,
|
|
1310
1307
|
silent: true,
|
|
1311
1308
|
disableLog: true,
|
|
1309
|
+
silentOnError: true,
|
|
1312
1310
|
});
|
|
1313
1311
|
logger.info('isRemoteRepo', { url, raw: (raw || '').slice(0, 120) });
|
|
1314
1312
|
return typeof raw === 'string' && /^[0-9a-f]{40}\t/m.test(raw);
|
|
@@ -1380,11 +1378,12 @@ Prevent build private config repo.`,
|
|
|
1380
1378
|
}
|
|
1381
1379
|
shellExec(`cd "${repoPath}" && git config user.name '${gitUsername}'`);
|
|
1382
1380
|
shellExec(`cd "${repoPath}" && git config user.email '${gitEmail}'`);
|
|
1383
|
-
|
|
1381
|
+
shellExec(`cd "${repoPath}" && git config core.filemode false`);
|
|
1384
1382
|
if (origin) {
|
|
1385
|
-
const currentRemote = shellExec(`cd "${repoPath}" && git remote get-url origin
|
|
1383
|
+
const currentRemote = shellExec(`cd "${repoPath}" && git remote get-url origin`, {
|
|
1386
1384
|
stdout: true,
|
|
1387
1385
|
silent: true,
|
|
1386
|
+
silentOnError: true,
|
|
1388
1387
|
}).trim();
|
|
1389
1388
|
if (!currentRemote) {
|
|
1390
1389
|
shellExec(`cd "${repoPath}" && git remote add origin "${origin}"`);
|
|
@@ -1608,6 +1607,52 @@ Prevent build private config repo.`,
|
|
|
1608
1607
|
logger.info('engine-private in /home/dd removed');
|
|
1609
1608
|
}
|
|
1610
1609
|
},
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* Resolves the GitHub repository for a given instance runtime by scanning
|
|
1613
|
+
* every `conf.instances.json` listed in `./engine-private/deploy/dd.router`.
|
|
1614
|
+
*
|
|
1615
|
+
* Resolution order:
|
|
1616
|
+
* 1. If `runtime` is falsy, returns `${GITHUB_USERNAME}/engine`.
|
|
1617
|
+
* 2. Iterates each deploy ID found in `dd.router` and looks for an instance
|
|
1618
|
+
* whose `runtime` field matches the supplied value.
|
|
1619
|
+
* 3. When a match is found, returns `instance.metadata.repository`.
|
|
1620
|
+
* 4. Falls back to `${GITHUB_USERNAME}/engine` when no match is found.
|
|
1621
|
+
*
|
|
1622
|
+
* @param {string} [runtime=''] - The runtime identifier to look up (e.g. `'cyberia-server'`, `'cyberia-client'`).
|
|
1623
|
+
* @returns {string} The resolved `owner/repo` string.
|
|
1624
|
+
* @memberof UnderpostRepository
|
|
1625
|
+
*/
|
|
1626
|
+
resolveInstanceRepo(runtime = '') {
|
|
1627
|
+
const fallback = `${process.env.GITHUB_USERNAME}/engine`;
|
|
1628
|
+
if (!runtime) return fallback;
|
|
1629
|
+
const ddRouter = './engine-private/deploy/dd.router';
|
|
1630
|
+
const deployIds = fs.existsSync(ddRouter)
|
|
1631
|
+
? fs
|
|
1632
|
+
.readFileSync(ddRouter, 'utf8')
|
|
1633
|
+
.split(',')
|
|
1634
|
+
.map((s) => s.trim())
|
|
1635
|
+
.filter(Boolean)
|
|
1636
|
+
: [];
|
|
1637
|
+
for (const deployId of deployIds) {
|
|
1638
|
+
const confPath = `./engine-private/conf/${deployId}/conf.instances.json`;
|
|
1639
|
+
if (!fs.existsSync(confPath)) continue;
|
|
1640
|
+
try {
|
|
1641
|
+
const instances = JSON.parse(fs.readFileSync(confPath, 'utf8'));
|
|
1642
|
+
const match = instances.find((i) => i && i.runtime === runtime);
|
|
1643
|
+
if (match && match.metadata && match.metadata.repository) {
|
|
1644
|
+
logger.info(`[resolveInstanceRepo] resolved from ${confPath}`, {
|
|
1645
|
+
runtime,
|
|
1646
|
+
repo: match.metadata.repository,
|
|
1647
|
+
});
|
|
1648
|
+
return match.metadata.repository;
|
|
1649
|
+
}
|
|
1650
|
+
} catch (err) {
|
|
1651
|
+
logger.warn(`[resolveInstanceRepo] failed to parse ${confPath}: ${err.message}`);
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
return fallback;
|
|
1655
|
+
},
|
|
1611
1656
|
};
|
|
1612
1657
|
}
|
|
1613
1658
|
|
package/src/cli/run.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
awaitDeployMonitor,
|
|
11
11
|
buildKindPorts,
|
|
12
12
|
Config,
|
|
13
|
+
cronDeployIdResolve,
|
|
14
|
+
etcHostFactory,
|
|
13
15
|
getNpmRootPath,
|
|
14
16
|
isDeployRunnerContext,
|
|
15
17
|
loadConfServerJson,
|
|
@@ -24,6 +26,7 @@ import { range, setPad, timer } from '../client/components/core/CommonJs.js';
|
|
|
24
26
|
import os from 'os';
|
|
25
27
|
import Underpost from '../index.js';
|
|
26
28
|
import dotenv from 'dotenv';
|
|
29
|
+
import { MongoBootstrap } from '../db/mongo/MongoBootstrap.js';
|
|
27
30
|
|
|
28
31
|
const waitForPort = (port, host = '127.0.0.1', { maxAttempts = 30, interval = 2000 } = {}) =>
|
|
29
32
|
new Promise((resolve, reject) => {
|
|
@@ -97,6 +100,7 @@ const logger = loggerFactory(import.meta);
|
|
|
97
100
|
* @property {string} deployId - The deployment ID.
|
|
98
101
|
* @property {string} instanceId - The instance ID.
|
|
99
102
|
* @property {string} user - The user to run as.
|
|
103
|
+
* @property {string} group - The group to use.
|
|
100
104
|
* @property {string} pid - The process ID.
|
|
101
105
|
* @property {boolean} disablePrivateConfUpdate - Whether to disable private configuration updates.
|
|
102
106
|
* @property {string} monitorStatus - The monitor status option.
|
|
@@ -114,6 +118,7 @@ const logger = loggerFactory(import.meta);
|
|
|
114
118
|
* @property {boolean} copy - Whether to copy the command to the clipboard instead of executing it.
|
|
115
119
|
* @property {boolean} skipFullBuild - Whether to skip the full client bundle build during deployment (supported by: sync, template-deploy).
|
|
116
120
|
* @property {boolean} pullBundle - Whether to pull the bundle before running. Use together with --skip-full-build to skip the local build entirely (supported by: sync, template-deploy).
|
|
121
|
+
* @property {boolean} remove - Whether to remove/teardown resources instead of creating them (e.g. delete-expose for k3s proxy devices in dev-cluster).
|
|
117
122
|
* @memberof UnderpostRun
|
|
118
123
|
*/
|
|
119
124
|
const DEFAULT_OPTION = {
|
|
@@ -165,6 +170,7 @@ const DEFAULT_OPTION = {
|
|
|
165
170
|
deployId: '',
|
|
166
171
|
instanceId: '',
|
|
167
172
|
user: '',
|
|
173
|
+
group: '',
|
|
168
174
|
pid: '',
|
|
169
175
|
disablePrivateConfUpdate: false,
|
|
170
176
|
monitorStatus: '',
|
|
@@ -180,6 +186,7 @@ const DEFAULT_OPTION = {
|
|
|
180
186
|
copy: false,
|
|
181
187
|
skipFullBuild: false,
|
|
182
188
|
pullBundle: false,
|
|
189
|
+
remove: false,
|
|
183
190
|
};
|
|
184
191
|
|
|
185
192
|
/**
|
|
@@ -209,28 +216,39 @@ class UnderpostRun {
|
|
|
209
216
|
'dev-cluster': (path, options = DEFAULT_OPTION) => {
|
|
210
217
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
211
218
|
const mongoHosts = ['mongodb-0.mongodb-service'];
|
|
219
|
+
let primaryMongoHost = 'mongodb-0.mongodb-service';
|
|
212
220
|
if (!options.expose) {
|
|
213
221
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --reset`);
|
|
214
222
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''}`);
|
|
215
223
|
|
|
216
224
|
shellExec(
|
|
217
|
-
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --
|
|
225
|
+
`${baseCommand} cluster${options.dev ? ' --dev' : ''} --mongodb4 --service-host ${mongoHosts.join(
|
|
218
226
|
',',
|
|
219
227
|
)} --pull-image`,
|
|
220
228
|
);
|
|
221
229
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
222
230
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
231
|
+
if (options.k3s) {
|
|
232
|
+
if (options.remove) {
|
|
233
|
+
shellExec(`${baseCommand} lxd --delete-expose k3s-control:27017`);
|
|
234
|
+
shellExec(`${baseCommand} lxd --delete-expose k3s-control:6379`);
|
|
235
|
+
} else {
|
|
236
|
+
shellExec(`${baseCommand} lxd --expose k3s-control:27017 --node-port 32017`);
|
|
237
|
+
shellExec(`${baseCommand} lxd --expose k3s-control:6379 --node-port 32079`);
|
|
238
|
+
}
|
|
239
|
+
shellExec(`lxc config device show k3s-control`);
|
|
240
|
+
} else {
|
|
227
241
|
try {
|
|
228
|
-
const primaryPodName =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
242
|
+
const primaryPodName =
|
|
243
|
+
MongoBootstrap.getPrimaryPodName({
|
|
244
|
+
namespace: options.namespace,
|
|
245
|
+
podName: 'mongodb-0',
|
|
246
|
+
disableAuth: options.dev,
|
|
247
|
+
}) || 'mongodb-0';
|
|
248
|
+
shellExec(
|
|
249
|
+
`${baseCommand} deploy --expose --namespace ${options.namespace} --disable-update-underpost-config mongo`,
|
|
250
|
+
{ async: true },
|
|
251
|
+
);
|
|
234
252
|
shellExec(
|
|
235
253
|
`${baseCommand} deploy --expose --namespace ${options.namespace} --disable-update-underpost-config valkey`,
|
|
236
254
|
{ async: true },
|
|
@@ -241,10 +259,9 @@ class UnderpostRun {
|
|
|
241
259
|
default: primaryMongoHost,
|
|
242
260
|
});
|
|
243
261
|
}
|
|
244
|
-
|
|
245
|
-
const hostListenResult = Underpost.deploy.etcHostFactory([primaryMongoHost]);
|
|
246
|
-
logger.info(hostListenResult.renderHosts);
|
|
247
262
|
}
|
|
263
|
+
const hostListenResult = etcHostFactory([primaryMongoHost]);
|
|
264
|
+
logger.info(hostListenResult.renderHosts);
|
|
248
265
|
},
|
|
249
266
|
|
|
250
267
|
/**
|
|
@@ -505,14 +522,16 @@ class UnderpostRun {
|
|
|
505
522
|
},
|
|
506
523
|
/**
|
|
507
524
|
* @method docker-image
|
|
508
|
-
* @description Dispatches the Docker image CI workflow (`docker-image.ci.yml`)
|
|
509
|
-
*
|
|
525
|
+
* @description Dispatches the Docker image CI workflow (`docker-image[.<runtime>].ci.yml`) via `workflow_dispatch`.
|
|
526
|
+
* Repository resolution is delegated to `Underpost.repo.resolveInstanceRepo(path)`.
|
|
527
|
+
* @param {string} path - Optional runtime / workflow suffix (e.g. `cyberia-server`, `cyberia-client`).
|
|
510
528
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
511
529
|
* @memberof UnderpostRun
|
|
512
530
|
*/
|
|
513
531
|
'docker-image': (path, options = DEFAULT_OPTION) => {
|
|
532
|
+
const repo = Underpost.repo.resolveInstanceRepo(path);
|
|
514
533
|
Underpost.repo.dispatchWorkflow({
|
|
515
|
-
repo
|
|
534
|
+
repo,
|
|
516
535
|
workflowFile: `docker-image${path ? `.${path}` : ''}.ci.yml`,
|
|
517
536
|
ref: 'master',
|
|
518
537
|
inputs: {},
|
|
@@ -527,6 +546,7 @@ class UnderpostRun {
|
|
|
527
546
|
*/
|
|
528
547
|
clean: (path = '', options = DEFAULT_OPTION) => {
|
|
529
548
|
Underpost.repo.clean({ paths: path ? path.split(',') : ['/home/dd/engine', '/home/dd/engine/engine-private'] });
|
|
549
|
+
if (options.dev) shellExec(`node bin run shared-dir ${path ? path : '/home/dd/engine'}`);
|
|
530
550
|
},
|
|
531
551
|
/**
|
|
532
552
|
* @method pull
|
|
@@ -536,16 +556,14 @@ class UnderpostRun {
|
|
|
536
556
|
* @memberof UnderpostRun
|
|
537
557
|
*/
|
|
538
558
|
pull: (path, options = DEFAULT_OPTION) => {
|
|
559
|
+
// shellExec is fail-fast by default — any non-zero exit throws and
|
|
560
|
+
// propagates up to the workflow step. No per-call flag required.
|
|
539
561
|
if (!fs.existsSync(`/home/dd`) || !fs.existsSync(`/home/dd/engine`)) {
|
|
540
562
|
fs.mkdirSync(`/home/dd`, { recursive: true });
|
|
541
|
-
shellExec(`cd /home/dd && underpost clone ${process.env.GITHUB_USERNAME}/engine`, {
|
|
542
|
-
silent: true,
|
|
543
|
-
});
|
|
563
|
+
shellExec(`cd /home/dd && underpost clone ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
|
|
544
564
|
} else {
|
|
545
565
|
shellExec(`underpost run clean`);
|
|
546
|
-
shellExec(`cd /home/dd/engine && underpost pull . ${process.env.GITHUB_USERNAME}/engine`, {
|
|
547
|
-
silent: true,
|
|
548
|
-
});
|
|
566
|
+
shellExec(`cd /home/dd/engine && underpost pull . ${process.env.GITHUB_USERNAME}/engine`, { silent: true });
|
|
549
567
|
}
|
|
550
568
|
if (!fs.existsSync(`/home/dd/engine/engine-private`))
|
|
551
569
|
shellExec(`cd /home/dd/engine && underpost clone ${process.env.GITHUB_USERNAME}/engine-private`, {
|
|
@@ -554,9 +572,7 @@ class UnderpostRun {
|
|
|
554
572
|
else
|
|
555
573
|
shellExec(
|
|
556
574
|
`cd /home/dd/engine/engine-private && underpost pull . ${process.env.GITHUB_USERNAME}/engine-private`,
|
|
557
|
-
{
|
|
558
|
-
silent: true,
|
|
559
|
-
},
|
|
575
|
+
{ silent: true },
|
|
560
576
|
);
|
|
561
577
|
},
|
|
562
578
|
/**
|
|
@@ -643,6 +659,11 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
643
659
|
/**
|
|
644
660
|
* @method sync
|
|
645
661
|
* @description Cleans up, and then runs a deployment synchronization command (`underpost deploy --kubeadm --build-manifest --sync...`) using parameters parsed from `path` (deployId, replicas, versions, image, node).
|
|
662
|
+
*
|
|
663
|
+
* Forwards `--image-pull-policy <policy>` to the underlying `deploy --build-manifest` invocation when `options.imagePullPolicy` is set,
|
|
664
|
+
* which then plumbs through `buildManifest` and `deploymentYamlPartsFactory` to override the container `imagePullPolicy` in the generated
|
|
665
|
+
* `deployment.yaml`. Useful when you want to force `Always` so the kubelet re-pulls a mutable tag on every rollout. Example:
|
|
666
|
+
* `node bin run sync dd-core --kubeadm --image-pull-policy Always`
|
|
646
667
|
* @param {string} path - The input value, identifier, or path for the operation (used as a comma-separated string containing deploy parameters).
|
|
647
668
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
648
669
|
* @memberof UnderpostRun
|
|
@@ -700,13 +721,14 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
700
721
|
|
|
701
722
|
const skipFullBuildFlag = options.skipFullBuild ? ' --skip-full-build' : '';
|
|
702
723
|
const pullBundleFlag = options.pullBundle ? ' --pull-bundle' : '';
|
|
724
|
+
const imagePullPolicyFlag = options.imagePullPolicy ? ` --image-pull-policy ${options.imagePullPolicy}` : '';
|
|
703
725
|
|
|
704
726
|
shellExec(
|
|
705
727
|
`${baseCommand} deploy${clusterFlag} --build-manifest --sync --info-router --replicas ${replicas} --node ${node}${
|
|
706
728
|
image ? ` --image ${image}` : ''
|
|
707
729
|
}${versions ? ` --versions ${versions}` : ''}${
|
|
708
730
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
709
|
-
}${timeoutFlags}${cmdString}${gitCleanFlag}${skipFullBuildFlag}${pullBundleFlag} ${deployId} ${env}`,
|
|
731
|
+
}${timeoutFlags}${cmdString}${gitCleanFlag}${skipFullBuildFlag}${pullBundleFlag}${imagePullPolicyFlag} ${deployId} ${env}`,
|
|
710
732
|
);
|
|
711
733
|
|
|
712
734
|
if (isDeployRunnerContext(path, options)) {
|
|
@@ -717,7 +739,7 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
717
739
|
shellExec(
|
|
718
740
|
`${baseCommand} deploy${clusterFlag}${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
|
|
719
741
|
options.namespace ? ` --namespace ${options.namespace}` : ''
|
|
720
|
-
}${timeoutFlags}${gitCleanFlag}`,
|
|
742
|
+
}${timeoutFlags}${gitCleanFlag}${imagePullPolicyFlag}`,
|
|
721
743
|
);
|
|
722
744
|
if (!targetTraffic)
|
|
723
745
|
targetTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace });
|
|
@@ -1023,6 +1045,9 @@ EOF
|
|
|
1023
1045
|
cmd: _cmd,
|
|
1024
1046
|
volumes: _volumes,
|
|
1025
1047
|
metadata: _metadata,
|
|
1048
|
+
lifecycle: _lifecycle,
|
|
1049
|
+
readinessProbe: _readinessProbe,
|
|
1050
|
+
livenessProbe: _livenessProbe,
|
|
1026
1051
|
} = instance;
|
|
1027
1052
|
if (id !== _id) continue;
|
|
1028
1053
|
const _deployId = `${deployId}-${_id}`;
|
|
@@ -1087,6 +1112,20 @@ EOF
|
|
|
1087
1112
|
),
|
|
1088
1113
|
);
|
|
1089
1114
|
|
|
1115
|
+
// Resolve env-scoped lifecycle/probe blocks: each can be either
|
|
1116
|
+
// { ...envObj } // shared shape
|
|
1117
|
+
// { development: {...}, production: {...} } // env-specific
|
|
1118
|
+
const pickEnv = (v) => (v && (v.development || v.production) ? v[env] : v);
|
|
1119
|
+
|
|
1120
|
+
// Convention: an instance config may place `imagePullPolicy` inside
|
|
1121
|
+
// the env-scoped lifecycle block (alongside postStart/preStop).
|
|
1122
|
+
// Extract it onto the container spec (where K8S expects it) and
|
|
1123
|
+
// strip it from the lifecycle hash so the rendered YAML stays valid.
|
|
1124
|
+
// CLI override (`--image-pull-policy`) wins over the conf value.
|
|
1125
|
+
const { lifecycle: lifecycleForManifest, imagePullPolicy: lifecycleImagePullPolicy } =
|
|
1126
|
+
Underpost.deploy.extractInstanceImagePullPolicy(pickEnv(_lifecycle));
|
|
1127
|
+
const instanceImagePullPolicy = options.imagePullPolicy || lifecycleImagePullPolicy;
|
|
1128
|
+
|
|
1090
1129
|
let deploymentYaml = `---
|
|
1091
1130
|
${Underpost.deploy
|
|
1092
1131
|
.deploymentYamlPartsFactory({
|
|
@@ -1099,6 +1138,11 @@ ${Underpost.deploy
|
|
|
1099
1138
|
namespace: options.namespace,
|
|
1100
1139
|
volumes: _volumes,
|
|
1101
1140
|
cmd: resolvedCmd,
|
|
1141
|
+
lifecycle: lifecycleForManifest,
|
|
1142
|
+
readinessProbe: pickEnv(_readinessProbe),
|
|
1143
|
+
livenessProbe: pickEnv(_livenessProbe),
|
|
1144
|
+
containerPort: _toPort,
|
|
1145
|
+
imagePullPolicy: instanceImagePullPolicy,
|
|
1102
1146
|
})
|
|
1103
1147
|
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort))}
|
|
1104
1148
|
`;
|
|
@@ -1130,7 +1174,7 @@ EOF
|
|
|
1130
1174
|
);
|
|
1131
1175
|
}
|
|
1132
1176
|
if (options.etcHosts) {
|
|
1133
|
-
const hostListenResult =
|
|
1177
|
+
const hostListenResult = etcHostFactory(etcHosts);
|
|
1134
1178
|
logger.info(hostListenResult.renderHosts);
|
|
1135
1179
|
}
|
|
1136
1180
|
},
|
|
@@ -1187,14 +1231,34 @@ EOF
|
|
|
1187
1231
|
volumes: _volumes,
|
|
1188
1232
|
metadata: _metadata,
|
|
1189
1233
|
runtime: _runtime,
|
|
1234
|
+
lifecycle: _lifecycle,
|
|
1235
|
+
readinessProbe: _readinessProbe,
|
|
1236
|
+
livenessProbe: _livenessProbe,
|
|
1190
1237
|
} = instance;
|
|
1191
1238
|
|
|
1192
|
-
// Resolve Dockerfile source
|
|
1193
|
-
|
|
1194
|
-
|
|
1239
|
+
// Resolve Dockerfile source. Dev/prod variant rules:
|
|
1240
|
+
// - When the instance defines a `runtime`, look under
|
|
1241
|
+
// `src/runtime/<runtime>/`. In `--dev` mode prefer `Dockerfile.dev`
|
|
1242
|
+
// when it exists, falling back to `Dockerfile`.
|
|
1243
|
+
// - When `runtime` is not set, look in the project root with the
|
|
1244
|
+
// same `.dev` → no-suffix precedence.
|
|
1245
|
+
// Dockerfile.dev is a full Dockerfile (not an overlay) — each runtime
|
|
1246
|
+
// owns the contract between its dev image and its prod image (debug
|
|
1247
|
+
// build flags, extra tooling, default ports, etc.).
|
|
1248
|
+
const dockerfileBase = _runtime ? `src/runtime/${_runtime}` : rootPath;
|
|
1249
|
+
const dockerfileCandidates = options.dev
|
|
1250
|
+
? [`${dockerfileBase}/Dockerfile.dev`, `${dockerfileBase}/Dockerfile`]
|
|
1251
|
+
: [`${dockerfileBase}/Dockerfile`];
|
|
1252
|
+
const dockerfileSourcePath = dockerfileCandidates.find((p) => fs.existsSync(p));
|
|
1253
|
+
if (dockerfileSourcePath) {
|
|
1254
|
+
if (options.dev && !dockerfileSourcePath.endsWith('.dev')) {
|
|
1255
|
+
logger.warn(
|
|
1256
|
+
`[instance-build-manifest] --dev requested but no Dockerfile.dev present; falling back to ${dockerfileSourcePath}`,
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1195
1259
|
fs.copyFileSync(dockerfileSourcePath, dockerfileManifestPath);
|
|
1196
1260
|
} else {
|
|
1197
|
-
logger.warn(`[instance-build-manifest] Dockerfile not found
|
|
1261
|
+
logger.warn(`[instance-build-manifest] Dockerfile not found; tried: ${dockerfileCandidates.join(', ')}`);
|
|
1198
1262
|
}
|
|
1199
1263
|
|
|
1200
1264
|
const _deployId = `${deployId}-${_id}`;
|
|
@@ -1239,6 +1303,17 @@ EOF
|
|
|
1239
1303
|
),
|
|
1240
1304
|
);
|
|
1241
1305
|
|
|
1306
|
+
// Env-aware lifecycle / probe selection. Each block may either be
|
|
1307
|
+
// a single object (shared across envs) or `{ development, production }`.
|
|
1308
|
+
const pickEnv = (v) => (v && (v.development || v.production) ? v[env] : v);
|
|
1309
|
+
|
|
1310
|
+
// Convention: an instance config may place `imagePullPolicy` inside
|
|
1311
|
+
// the env-scoped lifecycle block (alongside postStart/preStop).
|
|
1312
|
+
// Extract it onto the container spec and strip it from the lifecycle hash.
|
|
1313
|
+
const { lifecycle: lifecycleForManifest, imagePullPolicy: lifecycleImagePullPolicy } =
|
|
1314
|
+
Underpost.deploy.extractInstanceImagePullPolicy(pickEnv(_lifecycle));
|
|
1315
|
+
const instanceImagePullPolicy = options.imagePullPolicy || lifecycleImagePullPolicy;
|
|
1316
|
+
|
|
1242
1317
|
const deploymentYaml =
|
|
1243
1318
|
`---\n` +
|
|
1244
1319
|
Underpost.deploy
|
|
@@ -1252,6 +1327,11 @@ EOF
|
|
|
1252
1327
|
namespace: options.namespace,
|
|
1253
1328
|
volumes: _volumes,
|
|
1254
1329
|
cmd: resolvedCmd,
|
|
1330
|
+
lifecycle: lifecycleForManifest,
|
|
1331
|
+
readinessProbe: pickEnv(_readinessProbe),
|
|
1332
|
+
livenessProbe: pickEnv(_livenessProbe),
|
|
1333
|
+
containerPort: _toPort,
|
|
1334
|
+
imagePullPolicy: instanceImagePullPolicy,
|
|
1255
1335
|
})
|
|
1256
1336
|
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort));
|
|
1257
1337
|
|
|
@@ -1330,9 +1410,9 @@ EOF`);
|
|
|
1330
1410
|
// crictl is in the kubernetes repo but excluded by default — install it explicitly
|
|
1331
1411
|
shellExec(`sudo yum install -y cri-tools --disableexcludes=kubernetes`);
|
|
1332
1412
|
// Ensure CRI-O uses systemd cgroup driver (matches kubelet default)
|
|
1333
|
-
shellExec(
|
|
1334
|
-
|
|
1335
|
-
);
|
|
1413
|
+
shellExec(`sudo sed -i 's/^#\?cgroup_manager =.*/cgroup_manager = "systemd"/' /etc/crio/crio.conf`, {
|
|
1414
|
+
silentOnError: true,
|
|
1415
|
+
});
|
|
1336
1416
|
shellExec(`sudo systemctl enable --now crio`);
|
|
1337
1417
|
logger.info('CRI-O installed and started.');
|
|
1338
1418
|
// Write crictl config so all crictl calls default to the CRI-O socket
|
|
@@ -1466,7 +1546,8 @@ EOF`);
|
|
|
1466
1546
|
`git config user.name '${username}' && ` +
|
|
1467
1547
|
`git config user.email '${email}' && ` +
|
|
1468
1548
|
`git config credential.interactive always &&` +
|
|
1469
|
-
`git config pull.rebase false
|
|
1549
|
+
`git config pull.rebase false && ` +
|
|
1550
|
+
`git config core.filemode false`,
|
|
1470
1551
|
{
|
|
1471
1552
|
disableLog: true,
|
|
1472
1553
|
silent: true,
|
|
@@ -1843,7 +1924,7 @@ EOF`);
|
|
|
1843
1924
|
);
|
|
1844
1925
|
} else logger.error(`Service pod ${podToMonitor} failed to start in time.`);
|
|
1845
1926
|
if (options.etcHosts === true) {
|
|
1846
|
-
const hostListenResult =
|
|
1927
|
+
const hostListenResult = etcHostFactory([host]);
|
|
1847
1928
|
logger.info(hostListenResult.renderHosts);
|
|
1848
1929
|
}
|
|
1849
1930
|
},
|
|
@@ -1861,7 +1942,7 @@ EOF`);
|
|
|
1861
1942
|
const confServer = loadConfServerJson(`./engine-private/conf/${options.deployId}/conf.server.json`);
|
|
1862
1943
|
hosts.push(...Object.keys(confServer));
|
|
1863
1944
|
}
|
|
1864
|
-
const hostListenResult =
|
|
1945
|
+
const hostListenResult = etcHostFactory(hosts);
|
|
1865
1946
|
logger.info(hostListenResult.renderHosts);
|
|
1866
1947
|
},
|
|
1867
1948
|
|
|
@@ -2180,15 +2261,26 @@ EOF`);
|
|
|
2180
2261
|
* @memberof UnderpostRun
|
|
2181
2262
|
*/
|
|
2182
2263
|
kill: (path = '', options = DEFAULT_OPTION) => {
|
|
2183
|
-
if (options.pid)
|
|
2264
|
+
if (options.pid)
|
|
2265
|
+
return shellExec(`sudo kill -9 ${options.pid}`, {
|
|
2266
|
+
silentOnError: true,
|
|
2267
|
+
});
|
|
2184
2268
|
for (const _path of path.split(',')) {
|
|
2185
2269
|
if (_path.split('+')[1]) {
|
|
2186
2270
|
let [port, sumPortOffSet] = _path.split('+');
|
|
2187
2271
|
port = parseInt(port);
|
|
2188
2272
|
sumPortOffSet = parseInt(sumPortOffSet);
|
|
2189
2273
|
for (const sumPort of range(0, sumPortOffSet))
|
|
2190
|
-
shellExec(
|
|
2191
|
-
|
|
2274
|
+
shellExec(
|
|
2275
|
+
`PIDS=$(lsof -t -i:${parseInt(port) + parseInt(sumPort)}); [ -n "$PIDS" ] && sudo kill -9 $PIDS || true`,
|
|
2276
|
+
{
|
|
2277
|
+
silentOnError: true,
|
|
2278
|
+
},
|
|
2279
|
+
);
|
|
2280
|
+
} else
|
|
2281
|
+
shellExec(`PIDS=$(lsof -t -i:${_path}); [ -n "$PIDS" ] && sudo kill -9 $PIDS || true`, {
|
|
2282
|
+
silentOnError: true,
|
|
2283
|
+
});
|
|
2192
2284
|
}
|
|
2193
2285
|
},
|
|
2194
2286
|
/**
|
|
@@ -2235,9 +2327,10 @@ EOF`);
|
|
|
2235
2327
|
* @memberof UnderpostRun
|
|
2236
2328
|
*/
|
|
2237
2329
|
secret: (path, options = DEFAULT_OPTION) => {
|
|
2238
|
-
const
|
|
2239
|
-
|
|
2240
|
-
|
|
2330
|
+
const cronDeployId = cronDeployIdResolve() || 'dd-cron';
|
|
2331
|
+
Underpost.secret.underpost.createFromEnvFile(
|
|
2332
|
+
`/home/dd/engine/engine-private/conf/${cronDeployId}/.env.${options.dev ? 'development' : 'production'}`,
|
|
2333
|
+
);
|
|
2241
2334
|
},
|
|
2242
2335
|
/**
|
|
2243
2336
|
* @method underpost-config
|
|
@@ -2545,6 +2638,57 @@ EOF`;
|
|
|
2545
2638
|
}
|
|
2546
2639
|
}
|
|
2547
2640
|
},
|
|
2641
|
+
|
|
2642
|
+
/**
|
|
2643
|
+
* @method monitor-ui
|
|
2644
|
+
* @description Installs and enables the Cockpit KVM Dashboard (cockpit, cockpit-machines, libvirt)
|
|
2645
|
+
* and opens the cockpit firewall service. With `--remove`, closes the firewall service instead.
|
|
2646
|
+
* @param {string} path - Unused.
|
|
2647
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2648
|
+
* `options.remove` — when true, removes the cockpit firewall rule instead of adding it.
|
|
2649
|
+
* @memberof UnderpostRun
|
|
2650
|
+
*/
|
|
2651
|
+
'monitor-ui': (path, options = DEFAULT_OPTION) => {
|
|
2652
|
+
if (options.remove) {
|
|
2653
|
+
shellExec(`sudo firewall-cmd --zone=public --remove-service=cockpit --permanent`);
|
|
2654
|
+
shellExec(`sudo firewall-cmd --reload`);
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
shellExec(`sudo dnf install -y cockpit cockpit-machines libvirt`);
|
|
2658
|
+
shellExec(`sudo systemctl enable --now cockpit.socket libvirtd`);
|
|
2659
|
+
shellExec(`sudo firewall-cmd --permanent --add-service=cockpit`);
|
|
2660
|
+
shellExec(`sudo firewall-cmd --reload`);
|
|
2661
|
+
},
|
|
2662
|
+
|
|
2663
|
+
/**
|
|
2664
|
+
* @method shared-dir
|
|
2665
|
+
* @description Run once for initial shared-directory setup. Creates the group, adds the user,
|
|
2666
|
+
* creates the directory, sets ownership, applies the SGID bit, and configures default ACLs so
|
|
2667
|
+
* all future files inside the directory automatically inherit group write permissions.
|
|
2668
|
+
* Use `reload-shared-dir` for subsequent permission repairs without recreating the group.
|
|
2669
|
+
* @param {string} path - Target directory to set up (defaults to `/home/dd/engine`).
|
|
2670
|
+
* Customise via the `path` argument or leave empty to use the default.
|
|
2671
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2672
|
+
* Key fields: `options.user` (default `'admin'`), `options.group` (default `'engine-dev'`).
|
|
2673
|
+
* @memberof UnderpostRun
|
|
2674
|
+
*/
|
|
2675
|
+
'shared-dir': (path = '/home/dd/engine', options = DEFAULT_OPTION) => {
|
|
2676
|
+
const dir = path || '/home/dd/engine';
|
|
2677
|
+
const user = options.user || 'admin';
|
|
2678
|
+
const group = options.group || 'engine-dev';
|
|
2679
|
+
|
|
2680
|
+
logger.info(`[setup-shared-dir] dir=${dir} user=${user} group=${group}`);
|
|
2681
|
+
|
|
2682
|
+
shellExec(`sudo groupadd ${group} 2>/dev/null || true`);
|
|
2683
|
+
shellExec(`sudo usermod -aG ${group} ${user}`);
|
|
2684
|
+
shellExec(`sudo mkdir -p ${dir}`);
|
|
2685
|
+
shellExec(`sudo chown -R ${user}:${group} ${dir}`);
|
|
2686
|
+
shellExec(`sudo chmod -R 2775 ${dir}`);
|
|
2687
|
+
shellExec(`sudo setfacl -d -m g:${group}:rwx ${dir}`);
|
|
2688
|
+
shellExec(`sudo setfacl -m g:${group}:rwx ${dir}`);
|
|
2689
|
+
|
|
2690
|
+
logger.info(`[setup-shared-dir] Shared directory setup complete: ${dir}`);
|
|
2691
|
+
},
|
|
2548
2692
|
};
|
|
2549
2693
|
|
|
2550
2694
|
static API = {
|
|
@@ -2601,14 +2745,14 @@ EOF`;
|
|
|
2601
2745
|
if (options.replicas === '' || options.replicas === null || options.replicas === undefined)
|
|
2602
2746
|
options.replicas = 1;
|
|
2603
2747
|
options.npmRoot = npmRoot;
|
|
2604
|
-
logger.info(
|
|
2748
|
+
logger.info(`Executing runner`, { runner, namespace: options.namespace });
|
|
2605
2749
|
if (!Underpost.run.RUNNERS.includes(runner)) throw new Error(`Runner not found: ${runner}`);
|
|
2606
2750
|
const result = await Underpost.run.CALL(runner, path, options);
|
|
2607
2751
|
return result;
|
|
2608
2752
|
} catch (error) {
|
|
2609
2753
|
console.log(error);
|
|
2610
2754
|
logger.error(error);
|
|
2611
|
-
|
|
2755
|
+
process.exit(1);
|
|
2612
2756
|
}
|
|
2613
2757
|
},
|
|
2614
2758
|
};
|