underpost 3.2.4 → 3.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.cd.yml +1 -2
- package/CHANGELOG.md +268 -1
- package/CLI-HELP.md +26 -13
- package/Dockerfile +0 -4
- package/README.md +3 -3
- package/bin/build.js +13 -3
- package/bin/deploy.js +570 -1
- package/bin/file.js +5 -0
- package/conf.js +11 -2
- package/jsconfig.json +1 -1
- 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 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
- package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
- package/package.json +20 -11
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.service.js +10 -10
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.service.js +10 -10
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.service.js +36 -36
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.service.js +8 -8
- package/src/api/user/guest.service.js +99 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.service.js +3 -20
- package/src/cli/deploy.js +33 -30
- package/src/cli/fs.js +62 -5
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +5 -1
- package/src/cli/release.js +58 -2
- package/src/cli/repository.js +35 -3
- package/src/cli/run.js +304 -38
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/client/Default.index.js +21 -33
- package/src/client/components/core/404.js +4 -4
- package/src/client/components/core/500.js +4 -4
- package/src/client/components/core/Account.js +73 -60
- package/src/client/components/core/AgGrid.js +23 -33
- package/src/client/components/core/Alert.js +12 -13
- package/src/client/components/core/AppStore.js +1 -1
- package/src/client/components/core/Auth.js +20 -32
- package/src/client/components/core/Badge.js +7 -13
- package/src/client/components/core/BtnIcon.js +15 -17
- package/src/client/components/core/CalendarCore.js +42 -63
- package/src/client/components/core/Chat.js +13 -15
- package/src/client/components/core/ClientEvents.js +87 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/Content.js +17 -14
- package/src/client/components/core/Css.js +15 -71
- package/src/client/components/core/CssCore.js +12 -16
- package/src/client/components/core/D3Chart.js +4 -4
- package/src/client/components/core/Docs.js +60 -59
- package/src/client/components/core/DropDown.js +69 -91
- package/src/client/components/core/EventBus.js +92 -0
- package/src/client/components/core/EventsUI.js +14 -17
- package/src/client/components/core/FileExplorer.js +102 -234
- package/src/client/components/core/FullScreen.js +47 -75
- package/src/client/components/core/Input.js +24 -69
- package/src/client/components/core/Keyboard.js +25 -18
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +25 -31
- package/src/client/components/core/LogIn.js +41 -41
- package/src/client/components/core/LogOut.js +23 -14
- package/src/client/components/core/Modal.js +397 -176
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -50
- package/src/client/components/core/PanelForm.js +25 -125
- package/src/client/components/core/Polyhedron.js +110 -214
- package/src/client/components/core/PublicProfile.js +39 -32
- package/src/client/components/core/Recover.js +52 -48
- package/src/client/components/core/Responsive.js +88 -32
- package/src/client/components/core/RichText.js +9 -18
- package/src/client/components/core/Router.js +24 -3
- package/src/client/components/core/SearchBox.js +37 -37
- package/src/client/components/core/SignUp.js +39 -30
- package/src/client/components/core/SocketIo.js +31 -2
- package/src/client/components/core/SocketIoHandler.js +6 -6
- package/src/client/components/core/ToggleSwitch.js +8 -20
- package/src/client/components/core/ToolTip.js +5 -17
- package/src/client/components/core/Translate.js +56 -59
- package/src/client/components/core/Validator.js +26 -16
- package/src/client/components/core/Wallet.js +15 -26
- package/src/client/components/core/Worker.js +140 -25
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +6 -4
- package/src/client/components/default/LogOutDefault.js +6 -4
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +4 -4
- package/src/client/components/default/SignUpDefault.js +6 -4
- package/src/client/components/default/TranslateDefault.js +3 -3
- package/src/client/services/core/core.service.js +17 -49
- package/src/client/services/default/default.management.js +139 -242
- package/src/client/services/default/default.service.js +10 -16
- package/src/client/services/document/document.service.js +14 -19
- package/src/client/services/file/file.service.js +8 -13
- package/src/client/services/test/test.service.js +8 -13
- package/src/client/services/user/guest.service.js +79 -0
- package/src/client/services/user/user.management.js +5 -5
- package/src/client/services/user/user.service.js +14 -20
- package/src/client/ssr/body/404.js +3 -3
- package/src/client/ssr/body/500.js +3 -3
- package/src/client/ssr/body/CacheControl.js +5 -2
- package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
- package/src/client/ssr/offline/Maintenance.js +12 -11
- package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
- package/src/client/ssr/pages/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/index.js +1 -1
- package/src/runtime/express/Dockerfile +4 -4
- package/src/runtime/lampp/Dockerfile +8 -7
- package/src/runtime/wp/Dockerfile +11 -17
- package/src/server/backup.js +1 -2
- package/src/server/client-build-docs.js +45 -46
- package/src/server/client-build.js +334 -60
- package/src/server/client-formatted.js +47 -16
- package/src/server/conf.js +29 -13
- package/src/server/cron.js +6 -8
- package/src/server/dns.js +2 -1
- package/src/server/ipfs-client.js +232 -91
- package/src/server/process.js +13 -27
- package/src/server/start.js +6 -3
- package/src/server/valkey.js +134 -235
- package/tsconfig.docs.json +15 -0
- package/typedoc.json +20 -0
- package/jsdoc.json +0 -52
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/sw/default.sw.js +0 -127
- package/src/client/sw/template.sw.js +0 -84
package/src/cli/run.js
CHANGED
|
@@ -93,7 +93,6 @@ const logger = loggerFactory(import.meta);
|
|
|
93
93
|
* @property {boolean} kubeadm - Whether to run in kubeadm mode.
|
|
94
94
|
* @property {boolean} kind - Whether to run in kind mode.
|
|
95
95
|
* @property {boolean} k3s - Whether to run in k3s mode.
|
|
96
|
-
* @property {string} logType - The type of log to generate.
|
|
97
96
|
* @property {string} hosts - The hosts to use.
|
|
98
97
|
* @property {string} deployId - The deployment ID.
|
|
99
98
|
* @property {string} instanceId - The instance ID.
|
|
@@ -158,7 +157,6 @@ const DEFAULT_OPTION = {
|
|
|
158
157
|
kubeadm: false,
|
|
159
158
|
kind: false,
|
|
160
159
|
k3s: false,
|
|
161
|
-
logType: '',
|
|
162
160
|
hosts: '',
|
|
163
161
|
deployId: '',
|
|
164
162
|
instanceId: '',
|
|
@@ -490,21 +488,6 @@ class UnderpostRun {
|
|
|
490
488
|
: await Underpost.release.pwa(sanitizedMessage, options);
|
|
491
489
|
pbcopy(triggerCmd + ' && cd /home/dd/engine');
|
|
492
490
|
},
|
|
493
|
-
/**
|
|
494
|
-
* @method template-deploy-image
|
|
495
|
-
* @description Dispatches the Docker image CI workflow for the `engine` repository.
|
|
496
|
-
* @param {string} path - The input value, identifier, or path for the operation.
|
|
497
|
-
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
498
|
-
* @memberof UnderpostRun
|
|
499
|
-
*/
|
|
500
|
-
'template-deploy-image': (path, options = DEFAULT_OPTION) => {
|
|
501
|
-
Underpost.repo.dispatchWorkflow({
|
|
502
|
-
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
503
|
-
workflowFile: 'docker-image.ci.yml',
|
|
504
|
-
ref: 'master',
|
|
505
|
-
inputs: {},
|
|
506
|
-
});
|
|
507
|
-
},
|
|
508
491
|
/**
|
|
509
492
|
* @method docker-image
|
|
510
493
|
* @description Dispatches the Docker image CI workflow (`docker-image.ci.yml`) for the `engine` repository via `workflow_dispatch`.
|
|
@@ -515,7 +498,7 @@ class UnderpostRun {
|
|
|
515
498
|
'docker-image': (path, options = DEFAULT_OPTION) => {
|
|
516
499
|
Underpost.repo.dispatchWorkflow({
|
|
517
500
|
repo: `${process.env.GITHUB_USERNAME}/engine`,
|
|
518
|
-
workflowFile:
|
|
501
|
+
workflowFile: `docker-image${path ? `.${path}` : ''}.ci.yml`,
|
|
519
502
|
ref: 'master',
|
|
520
503
|
inputs: {},
|
|
521
504
|
});
|
|
@@ -652,8 +635,9 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
652
635
|
sync: async (path, options = DEFAULT_OPTION) => {
|
|
653
636
|
// Dev usage: node bin run --dev --build sync dd-default
|
|
654
637
|
const env = options.dev ? 'development' : 'production';
|
|
655
|
-
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
638
|
+
const baseCommand = 'node bin'; // options.dev ? 'node bin' : 'underpost';
|
|
656
639
|
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
640
|
+
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : ' --kubeadm';
|
|
657
641
|
const defaultPath = [
|
|
658
642
|
'dd-default',
|
|
659
643
|
options.replicas,
|
|
@@ -668,13 +652,23 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
668
652
|
image = image ? image : defaultPath[3];
|
|
669
653
|
node = node ? node : defaultPath[4];
|
|
670
654
|
shellExec(`${baseCommand} cluster --ns-use ${options.namespace}`);
|
|
655
|
+
|
|
656
|
+
if (image && !image.startsWith('localhost'))
|
|
657
|
+
Underpost.image.pullDockerHubImage({
|
|
658
|
+
dockerhubImage: image,
|
|
659
|
+
kind: options.kind || (!options.nodeName && !options.kubeadm && !options.k3s),
|
|
660
|
+
kubeadm: options.nodeName || options.kubeadm,
|
|
661
|
+
k3s: options.k3s,
|
|
662
|
+
});
|
|
663
|
+
|
|
671
664
|
if (isDeployRunnerContext(path, options)) {
|
|
672
665
|
if (!options.disablePrivateConfUpdate) {
|
|
673
666
|
const { validVersion } = Underpost.repo.privateConfUpdate(deployId);
|
|
674
667
|
if (!validVersion) throw new Error('Version mismatch');
|
|
675
668
|
}
|
|
676
669
|
if (options.timezone !== 'none') shellExec(`${baseCommand} run${baseClusterCommand} tz`);
|
|
677
|
-
if (options.deployIdCronJobs !== 'none')
|
|
670
|
+
if (options.deployIdCronJobs !== 'none')
|
|
671
|
+
shellExec(`node bin cron${baseClusterCommand}${clusterFlag} --setup-start --git --apply`);
|
|
678
672
|
}
|
|
679
673
|
|
|
680
674
|
const currentTraffic = isDeployRunnerContext(path, options)
|
|
@@ -687,7 +681,6 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
687
681
|
const cmdString = options.cmd
|
|
688
682
|
? ' --cmd ' + (options.cmd.find((c) => c.match('"')) ? '"' + options.cmd + '"' : "'" + options.cmd + "'")
|
|
689
683
|
: '';
|
|
690
|
-
const clusterFlag = options.k3s ? ' --k3s' : options.kind ? ' --kind' : ' --kubeadm';
|
|
691
684
|
const gitCleanFlag = options.gitClean ? ' --git-clean' : '';
|
|
692
685
|
|
|
693
686
|
shellExec(
|
|
@@ -701,7 +694,7 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
701
694
|
if (isDeployRunnerContext(path, options)) {
|
|
702
695
|
// Backup app/services repositories with repo-backup configured
|
|
703
696
|
shellExec(
|
|
704
|
-
`${baseCommand} db ${deployId} ${clusterFlag} --repo-backup --
|
|
697
|
+
`${baseCommand} db ${deployId} ${clusterFlag}${baseClusterCommand} --repo-backup --primary-pod --git --force-clone --preserveUUID ${options.namespace ? ` --ns ${options.namespace}` : ''}`,
|
|
705
698
|
);
|
|
706
699
|
shellExec(
|
|
707
700
|
`${baseCommand} deploy${clusterFlag}${cmdString} --replicas ${replicas} --disable-update-proxy ${deployId} ${env} --versions ${versions}${
|
|
@@ -927,12 +920,17 @@ echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com
|
|
|
927
920
|
image: _image,
|
|
928
921
|
fromPort: _fromPort,
|
|
929
922
|
toPort: _toPort,
|
|
923
|
+
fromDebugPort: _fromDebugPort,
|
|
924
|
+
toDebugPort: _toDebugPort,
|
|
930
925
|
cmd: _cmd,
|
|
931
926
|
volumes: _volumes,
|
|
932
927
|
metadata: _metadata,
|
|
933
928
|
} = instance;
|
|
934
929
|
if (id !== _id) continue;
|
|
935
930
|
const _deployId = `${deployId}-${_id}`;
|
|
931
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
932
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
933
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
936
934
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
937
935
|
hostTest: _host,
|
|
938
936
|
namespace: options.namespace,
|
|
@@ -1002,12 +1000,17 @@ EOF
|
|
|
1002
1000
|
image: _image,
|
|
1003
1001
|
fromPort: _fromPort,
|
|
1004
1002
|
toPort: _toPort,
|
|
1003
|
+
fromDebugPort: _fromDebugPort,
|
|
1004
|
+
toDebugPort: _toDebugPort,
|
|
1005
1005
|
cmd: _cmd,
|
|
1006
1006
|
volumes: _volumes,
|
|
1007
1007
|
metadata: _metadata,
|
|
1008
1008
|
} = instance;
|
|
1009
1009
|
if (id !== _id) continue;
|
|
1010
1010
|
const _deployId = `${deployId}-${_id}`;
|
|
1011
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
1012
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
1013
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
1011
1014
|
etcHosts.push(_host);
|
|
1012
1015
|
if (options.expose) continue;
|
|
1013
1016
|
// Examples images:
|
|
@@ -1015,12 +1018,13 @@ EOF
|
|
|
1015
1018
|
// `localhost/rockylinux9-underpost:${Underpost.version}`
|
|
1016
1019
|
if (!_image) _image = `underpost/underpost-engine:${Underpost.version}`;
|
|
1017
1020
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1021
|
+
if (_image && !_image.startsWith('localhost'))
|
|
1022
|
+
Underpost.image.pullDockerHubImage({
|
|
1023
|
+
dockerhubImage: _image,
|
|
1024
|
+
kind: options.kind || (!options.nodeName && !options.kubeadm && !options.k3s),
|
|
1025
|
+
kubeadm: options.nodeName || options.kubeadm,
|
|
1026
|
+
k3s: options.k3s,
|
|
1027
|
+
});
|
|
1024
1028
|
|
|
1025
1029
|
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
1026
1030
|
hostTest: _host,
|
|
@@ -1094,7 +1098,6 @@ EOF
|
|
|
1094
1098
|
targetTraffic,
|
|
1095
1099
|
ignorePods,
|
|
1096
1100
|
options.namespace,
|
|
1097
|
-
options.logType,
|
|
1098
1101
|
);
|
|
1099
1102
|
|
|
1100
1103
|
if (!ready) {
|
|
@@ -1114,6 +1117,153 @@ EOF
|
|
|
1114
1117
|
}
|
|
1115
1118
|
},
|
|
1116
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
* @method instance-build-manifest
|
|
1122
|
+
* @description Builds a Kubernetes Deployment + Service manifest for a specific instance entry
|
|
1123
|
+
* from `conf.instances.json` and writes it to a file.
|
|
1124
|
+
* Traffic colour is automatically chosen as the opposite of the current live colour (blue/green),
|
|
1125
|
+
* defaulting to `blue` when no deployment is running yet.
|
|
1126
|
+
*
|
|
1127
|
+
* If `--build` is supplied the image is built from the project Dockerfile and loaded into the
|
|
1128
|
+
* cluster before the manifest is written (kind by default; `--kubeadm` / `--k3s` override).
|
|
1129
|
+
*
|
|
1130
|
+
* @param {string} path - Comma-separated: `deployId,instanceId[,projectPath]`.
|
|
1131
|
+
* `projectPath` is the root directory that contains the `Dockerfile` (e.g. `./cyberia-client`).
|
|
1132
|
+
* Artifacts are written to `<projectPath>/manifests/<env>/Dockerfile` and
|
|
1133
|
+
* `<projectPath>/manifests/<env>/deployment.yaml`.
|
|
1134
|
+
* In production, files are also copied to `<projectPath>/Dockerfile` and
|
|
1135
|
+
* `<projectPath>/deployment.yaml`.
|
|
1136
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1137
|
+
* @memberof UnderpostRun
|
|
1138
|
+
*/
|
|
1139
|
+
'instance-build-manifest': (path, options = DEFAULT_OPTION) => {
|
|
1140
|
+
const env = options.dev ? 'development' : 'production';
|
|
1141
|
+
let [deployId, id, projectPath] = path.split(',');
|
|
1142
|
+
const rootPath = projectPath ? projectPath : '.';
|
|
1143
|
+
const envManifestPath = `${rootPath}/manifests/deployments/${id}-${env}`;
|
|
1144
|
+
const outputPath = `${envManifestPath}/deployment.yaml`;
|
|
1145
|
+
const dockerfileManifestPath = `${envManifestPath}/Dockerfile`;
|
|
1146
|
+
|
|
1147
|
+
fs.mkdirpSync(envManifestPath);
|
|
1148
|
+
|
|
1149
|
+
const confInstances = JSON.parse(
|
|
1150
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/conf.instances.json`, 'utf8'),
|
|
1151
|
+
);
|
|
1152
|
+
|
|
1153
|
+
const instance = confInstances.find((i) => i.id === id);
|
|
1154
|
+
if (!instance) {
|
|
1155
|
+
logger.error(`Instance with id '${id}' not found in conf.instances.json for deployId '${deployId}'`);
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
let {
|
|
1160
|
+
id: _id,
|
|
1161
|
+
host: _host,
|
|
1162
|
+
path: _path,
|
|
1163
|
+
image: _image,
|
|
1164
|
+
fromPort: _fromPort,
|
|
1165
|
+
toPort: _toPort,
|
|
1166
|
+
fromDebugPort: _fromDebugPort,
|
|
1167
|
+
toDebugPort: _toDebugPort,
|
|
1168
|
+
cmd: _cmd,
|
|
1169
|
+
volumes: _volumes,
|
|
1170
|
+
metadata: _metadata,
|
|
1171
|
+
runtime: _runtime,
|
|
1172
|
+
} = instance;
|
|
1173
|
+
|
|
1174
|
+
// Resolve Dockerfile source: use runtime-specific path when instance defines a runtime.
|
|
1175
|
+
const dockerfileSourcePath = _runtime ? `src/runtime/${_runtime}/Dockerfile` : `${rootPath}/Dockerfile`;
|
|
1176
|
+
if (fs.existsSync(dockerfileSourcePath)) {
|
|
1177
|
+
fs.copyFileSync(dockerfileSourcePath, dockerfileManifestPath);
|
|
1178
|
+
} else {
|
|
1179
|
+
logger.warn(`[instance-build-manifest] Dockerfile not found at ${dockerfileSourcePath}`);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
const _deployId = `${deployId}-${_id}`;
|
|
1183
|
+
if (!_image) _image = `underpost/underpost-engine:${Underpost.version}`;
|
|
1184
|
+
// Use debug ports in development when defined, fall back to production ports.
|
|
1185
|
+
if (env === 'development' && _fromDebugPort) _fromPort = _fromDebugPort;
|
|
1186
|
+
if (env === 'development' && _toDebugPort) _toPort = _toDebugPort;
|
|
1187
|
+
|
|
1188
|
+
// Build image from projectPath Dockerfile and load into cluster when --build is set.
|
|
1189
|
+
if (options.build && projectPath) {
|
|
1190
|
+
const isKind = !options.kubeadm && !options.k3s;
|
|
1191
|
+
Underpost.image.build({
|
|
1192
|
+
path: projectPath,
|
|
1193
|
+
imageName: _image,
|
|
1194
|
+
podmanSave: true,
|
|
1195
|
+
imagePath: projectPath,
|
|
1196
|
+
kind: isKind,
|
|
1197
|
+
kubeadm: !!options.kubeadm,
|
|
1198
|
+
k3s: !!options.k3s,
|
|
1199
|
+
reset: !!options.reset,
|
|
1200
|
+
dev: options.dev,
|
|
1201
|
+
});
|
|
1202
|
+
logger.info(`[instance-build-manifest] Image built and loaded`, {
|
|
1203
|
+
image: _image,
|
|
1204
|
+
cluster: isKind ? 'kind' : options.kubeadm ? 'kubeadm' : 'k3s',
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// Determine target traffic: opposite of current, or 'blue' if nothing is running yet.
|
|
1209
|
+
const currentTraffic = Underpost.deploy.getCurrentTraffic(_deployId, {
|
|
1210
|
+
hostTest: _host,
|
|
1211
|
+
namespace: options.namespace,
|
|
1212
|
+
});
|
|
1213
|
+
const targetTraffic = currentTraffic ? (currentTraffic === 'blue' ? 'green' : 'blue') : 'blue';
|
|
1214
|
+
|
|
1215
|
+
// Resolve {{grpc-service-dns}} using the parent deploy's current (or default) traffic.
|
|
1216
|
+
const parentTraffic = Underpost.deploy.getCurrentTraffic(deployId, { namespace: options.namespace }) || 'blue';
|
|
1217
|
+
const resolvedCmd = _cmd[env].map((c) =>
|
|
1218
|
+
c.replaceAll(
|
|
1219
|
+
'{{grpc-service-dns}}',
|
|
1220
|
+
`${deployId}-grpc-service-${env}-${parentTraffic}.${options.namespace || 'default'}.svc.cluster.local:50051`,
|
|
1221
|
+
),
|
|
1222
|
+
);
|
|
1223
|
+
|
|
1224
|
+
const deploymentYaml =
|
|
1225
|
+
`---\n` +
|
|
1226
|
+
Underpost.deploy
|
|
1227
|
+
.deploymentYamlPartsFactory({
|
|
1228
|
+
deployId: _deployId,
|
|
1229
|
+
env,
|
|
1230
|
+
suffix: targetTraffic,
|
|
1231
|
+
resources: Underpost.deploy.resourcesFactory(options),
|
|
1232
|
+
replicas: options.replicas,
|
|
1233
|
+
image: _image,
|
|
1234
|
+
namespace: options.namespace,
|
|
1235
|
+
volumes: _volumes,
|
|
1236
|
+
cmd: resolvedCmd,
|
|
1237
|
+
})
|
|
1238
|
+
.replace('{{ports}}', buildKindPorts(_fromPort, _toPort));
|
|
1239
|
+
|
|
1240
|
+
fs.writeFileSync(outputPath, deploymentYaml, 'utf8');
|
|
1241
|
+
logger.info(`[instance-build-manifest] Manifest written to ${outputPath}`, {
|
|
1242
|
+
deployId: _deployId,
|
|
1243
|
+
env,
|
|
1244
|
+
traffic: targetTraffic,
|
|
1245
|
+
image: _image,
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
if (env === 'production') {
|
|
1249
|
+
if (fs.existsSync(dockerfileManifestPath)) {
|
|
1250
|
+
fs.copyFileSync(dockerfileManifestPath, `${rootPath}/Dockerfile`);
|
|
1251
|
+
}
|
|
1252
|
+
fs.copyFileSync(outputPath, `${rootPath}/deployment.yaml`);
|
|
1253
|
+
logger.info('[instance-build-manifest] Production artifacts copied to project root', {
|
|
1254
|
+
rootPath,
|
|
1255
|
+
dockerfile: `${rootPath}/Dockerfile`,
|
|
1256
|
+
deployment: `${rootPath}/deployment.yaml`,
|
|
1257
|
+
});
|
|
1258
|
+
const ciSrc = `./.github/workflows/docker-image.${_runtime}.ci.yml`;
|
|
1259
|
+
if (fs.existsSync(ciSrc)) {
|
|
1260
|
+
if (!fs.existsSync(`${rootPath}/.github/workflows`)) fs.mkdirpSync(`${rootPath}/.github/workflows`);
|
|
1261
|
+
fs.copyFileSync(ciSrc, `${rootPath}/.github/workflows/docker-image.${_runtime}.ci.yml`);
|
|
1262
|
+
logger.info(`[instance-build-manifest] CI workflow copied`, { src: ciSrc });
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
|
|
1117
1267
|
/**
|
|
1118
1268
|
* @method ls-deployments
|
|
1119
1269
|
* @description Retrieves and logs a table of Kubernetes deployments using `Underpost.deploy.get`.
|
|
@@ -1919,6 +2069,16 @@ EOF
|
|
|
1919
2069
|
|
|
1920
2070
|
shellCd('/home/dd/engine');
|
|
1921
2071
|
},
|
|
2072
|
+
/**
|
|
2073
|
+
* @method pull-rocky-image
|
|
2074
|
+
* @description Pulls the base `rockylinux:9` image from Docker Hub via Podman.
|
|
2075
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
2076
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
2077
|
+
* @memberof UnderpostRun
|
|
2078
|
+
*/
|
|
2079
|
+
'pull-rocky-image': (path, options = DEFAULT_OPTION) => {
|
|
2080
|
+
shellExec(`sudo podman pull docker.io/library/rockylinux:9`);
|
|
2081
|
+
},
|
|
1922
2082
|
/**
|
|
1923
2083
|
* @method rmi
|
|
1924
2084
|
* @description Forces the removal of all local Podman images (`podman rmi $(podman images -qa) --force`).
|
|
@@ -1948,13 +2108,6 @@ EOF
|
|
|
1948
2108
|
} else shellExec(`sudo kill -9 $(lsof -t -i:${_path})`);
|
|
1949
2109
|
}
|
|
1950
2110
|
},
|
|
1951
|
-
/**
|
|
1952
|
-
* @method secret
|
|
1953
|
-
* @description Creates an Underpost secret named 'underpost' from a file, defaulting to `/home/dd/engine/engine-private/conf/dd-cron/.env.production` if no path is provided.
|
|
1954
|
-
* @param {string} path - The input value, identifier, or path for the operation (used as the optional path to the secret file).
|
|
1955
|
-
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
1956
|
-
* @memberof UnderpostRun
|
|
1957
|
-
*/
|
|
1958
2111
|
/**
|
|
1959
2112
|
* @method generate-pass
|
|
1960
2113
|
* @description Generates a cryptographically secure random password that satisfies all validatePassword
|
|
@@ -1991,10 +2144,16 @@ EOF
|
|
|
1991
2144
|
if (options.copy) pbcopy(password);
|
|
1992
2145
|
else console.log(password);
|
|
1993
2146
|
},
|
|
1994
|
-
|
|
2147
|
+
/**
|
|
2148
|
+
* @method secret
|
|
2149
|
+
* @description Creates an Underpost secret named 'underpost' from a file, defaulting to `/home/dd/engine/engine-private/conf/dd-cron/.env.production` if no path is provided.
|
|
2150
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional path to the secret file).
|
|
2151
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
2152
|
+
* @memberof UnderpostRun
|
|
2153
|
+
*/
|
|
1995
2154
|
secret: (path, options = DEFAULT_OPTION) => {
|
|
1996
2155
|
const secretPath = path ? path : `/home/dd/engine/engine-private/conf/dd-cron/.env.production`;
|
|
1997
|
-
const command =
|
|
2156
|
+
const command = `${options.dev ? 'node bin' : 'underpost'} secret underpost --create-from-file ${secretPath}`;
|
|
1998
2157
|
shellExec(command);
|
|
1999
2158
|
},
|
|
2000
2159
|
/**
|
|
@@ -2165,6 +2324,113 @@ EOF`;
|
|
|
2165
2324
|
if (options.logs) shellExec(`kubectl logs -f ${podName} -n ${namespace}`, { async: true });
|
|
2166
2325
|
}
|
|
2167
2326
|
},
|
|
2327
|
+
|
|
2328
|
+
/**
|
|
2329
|
+
* @method push-bundle
|
|
2330
|
+
* @description Builds the client zip for the specified deployment, splits it into parts, and uploads to file storage.
|
|
2331
|
+
* Steps: set env, build+split zip, switch to cron env, upload parts to storage.
|
|
2332
|
+
* @param {string} path - Optional `fsPath.splitOption` string.
|
|
2333
|
+
* Examples: `build` (default split 8), `build.16` (split 16 MB), `build.none-split` (no split flag).
|
|
2334
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2335
|
+
* @param {string} [options.deployId] - Override deploy ID.
|
|
2336
|
+
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
2337
|
+
* @memberof UnderpostRun
|
|
2338
|
+
*/
|
|
2339
|
+
'push-bundle': (path = '', options = DEFAULT_OPTION) => {
|
|
2340
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
2341
|
+
const env = options.dev ? 'development' : 'production';
|
|
2342
|
+
const deployId = options.deployId || 'dd-default';
|
|
2343
|
+
const pathParts = (path || '').split('.');
|
|
2344
|
+
const fsPath = (pathParts[0] || '').trim() || 'build';
|
|
2345
|
+
const splitOption = (pathParts[1] || '').trim();
|
|
2346
|
+
|
|
2347
|
+
let splitFlag = '--split 8';
|
|
2348
|
+
if (splitOption) {
|
|
2349
|
+
if (splitOption === 'none-split') {
|
|
2350
|
+
splitFlag = '';
|
|
2351
|
+
} else {
|
|
2352
|
+
const splitMb = Number(splitOption);
|
|
2353
|
+
if (Number.isFinite(splitMb) && splitMb > 0) {
|
|
2354
|
+
splitFlag = `--split ${splitMb}`;
|
|
2355
|
+
} else {
|
|
2356
|
+
logger.warn('push-bundle: invalid split option, using default split 8', {
|
|
2357
|
+
path,
|
|
2358
|
+
splitOption,
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
2365
|
+
shellExec(`${baseCommand} client ${deployId} --build-zip${splitFlag ? ` ${splitFlag}` : ''}`);
|
|
2366
|
+
shellExec(
|
|
2367
|
+
`${baseCommand} fs ${fsPath} --recursive --deploy-id ${deployId} --storage-file-path engine-private/conf/${deployId}/storage.bundle.json --force`,
|
|
2368
|
+
);
|
|
2369
|
+
},
|
|
2370
|
+
|
|
2371
|
+
/**
|
|
2372
|
+
* @method pull-bundle
|
|
2373
|
+
* @description Downloads split zip parts from file storage, merges and extracts them, and moves the result into the public directory.
|
|
2374
|
+
* Steps: set cron env, download parts (omit-unzip), merge zip, unzip, remove zip, move to public/<host>.
|
|
2375
|
+
* @param {string} path - Optional host name(s) used to locate zip(s) and as public destination(s) (e.g. 'underpost.net' or 'a.com,b.com').
|
|
2376
|
+
* If omitted, hosts are loaded from `engine-private/conf/<deployId>/conf.server.json`.
|
|
2377
|
+
* @param {Object} options - The default underpost runner options for customizing workflow.
|
|
2378
|
+
* @param {string} [options.deployId] - Deploy ID for storage lookup (defaults to 'dd-default').
|
|
2379
|
+
* @param {boolean} [options.dev] - Use development environment; defaults to production.
|
|
2380
|
+
* @memberof UnderpostRun
|
|
2381
|
+
*/
|
|
2382
|
+
'pull-bundle': (path = '', options = DEFAULT_OPTION) => {
|
|
2383
|
+
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
2384
|
+
const env = options.dev ? 'development' : 'production';
|
|
2385
|
+
const deployId = options.deployId || 'dd-default';
|
|
2386
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
2387
|
+
const hosts = path
|
|
2388
|
+
? path
|
|
2389
|
+
.split(',')
|
|
2390
|
+
.map((h) => h.trim())
|
|
2391
|
+
.filter(Boolean)
|
|
2392
|
+
: fs.existsSync(confServerPath)
|
|
2393
|
+
? Object.keys(loadConfServerJson(confServerPath))
|
|
2394
|
+
: [];
|
|
2395
|
+
|
|
2396
|
+
if (hosts.length === 0) {
|
|
2397
|
+
logger.error('pull-bundle: no hosts resolved', {
|
|
2398
|
+
deployId,
|
|
2399
|
+
path,
|
|
2400
|
+
confServerPath,
|
|
2401
|
+
});
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
shellExec(`${baseCommand} env ${deployId} ${env}`);
|
|
2406
|
+
if (!fs.existsSync('./build')) fs.mkdirSync('./build', { recursive: true });
|
|
2407
|
+
shellExec(
|
|
2408
|
+
`${baseCommand} fs build --recursive --deploy-id ${deployId} --storage-file-path engine-private/conf/${deployId}/storage.bundle.json --pull --omit-unzip`,
|
|
2409
|
+
);
|
|
2410
|
+
for (const host of hosts) {
|
|
2411
|
+
const zipPath = `build/${host}-.zip`;
|
|
2412
|
+
const hasZip = fs.existsSync(zipPath);
|
|
2413
|
+
const hasParts =
|
|
2414
|
+
fs.existsSync('./build') &&
|
|
2415
|
+
fs
|
|
2416
|
+
.readdirSync('./build')
|
|
2417
|
+
.some((name) => name.startsWith(`${host}-.zip.part`) || name.startsWith(`${host}-.zip-part`));
|
|
2418
|
+
|
|
2419
|
+
if (!hasZip && !hasParts) {
|
|
2420
|
+
logger.warn(`Bundle not found for host '${host}'. Skipping host.`, {
|
|
2421
|
+
zipPath,
|
|
2422
|
+
deployId,
|
|
2423
|
+
});
|
|
2424
|
+
continue;
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
if (hasParts) shellExec(`${baseCommand} client --merge-zip ${zipPath}`);
|
|
2428
|
+
shellExec(`${baseCommand} client --unzip ${zipPath}`);
|
|
2429
|
+
shellExec(`sudo rm -rf ${zipPath}`);
|
|
2430
|
+
if (fs.existsSync(`public/${host}`)) shellExec(`sudo rm -rf public/${host}`);
|
|
2431
|
+
shellExec(`sudo mv build/${host} public/${host}`);
|
|
2432
|
+
}
|
|
2433
|
+
},
|
|
2168
2434
|
};
|
|
2169
2435
|
|
|
2170
2436
|
static API = {
|
package/src/cli/ssh.js
CHANGED
|
@@ -315,7 +315,7 @@ EOF`);
|
|
|
315
315
|
console.log(`group_name : password_x : GID(Internal Group ID) : user_list`.blue);
|
|
316
316
|
console.log(filter ? groupsOut.replaceAll(filter, filter.red) : groupsOut);
|
|
317
317
|
console.log('Users'.bold.blue);
|
|
318
|
-
console.log(`
|
|
318
|
+
console.log(`user : x : UID : GID : GECOS : home_dir : shell`.blue);
|
|
319
319
|
console.log(filter ? usersOut.replaceAll(filter, filter.red) : usersOut);
|
|
320
320
|
}
|
|
321
321
|
|