underpost 2.89.1 → 2.89.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.development +2 -0
- package/.env.production +2 -0
- package/.env.test +2 -0
- package/.github/workflows/release.cd.yml +2 -0
- package/README.md +2 -3
- package/cli.md +123 -94
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +10 -2
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -0
- package/manifests/grafana/deployment.yaml +7 -0
- package/manifests/grafana/kustomization.yaml +1 -1
- package/manifests/grafana/pvc.yaml +1 -1
- package/manifests/grafana/storage-class.yaml +9 -0
- package/manifests/pv-pvc-dd.yaml +34 -0
- package/package.json +1 -1
- package/src/cli/cluster.js +40 -18
- package/src/cli/deploy.js +193 -77
- package/src/cli/index.js +20 -1
- package/src/cli/repository.js +12 -0
- package/src/cli/run.js +185 -68
- package/src/client/components/core/ObjectLayerEngineModal.js +4 -3
- package/src/client/components/core/ObjectLayerEngineViewer.js +83 -31
- package/src/index.js +1 -1
- package/src/server/start.js +2 -1
package/src/cli/run.js
CHANGED
|
@@ -42,6 +42,9 @@ class UnderpostRun {
|
|
|
42
42
|
* @type {Object}
|
|
43
43
|
* @property {boolean} dev - Whether to run in development mode.
|
|
44
44
|
* @property {string} podName - The name of the pod to run.
|
|
45
|
+
* @property {string} nodeName - The name of the node to run.
|
|
46
|
+
* @property {number} port - Custom port to use.
|
|
47
|
+
* @property {boolean} etcHosts - Whether to modify /etc/hosts.
|
|
45
48
|
* @property {string} volumeHostPath - The host path for the volume.
|
|
46
49
|
* @property {string} volumeMountPath - The mount path for the volume.
|
|
47
50
|
* @property {string} imageName - The name of the image to run.
|
|
@@ -57,14 +60,22 @@ class UnderpostRun {
|
|
|
57
60
|
* @property {string} tty - The TTY option for the container.
|
|
58
61
|
* @property {string} stdin - The stdin option for the container.
|
|
59
62
|
* @property {string} restartPolicy - The restart policy for the container.
|
|
63
|
+
* @property {string} runtimeClassName - The runtime class name for the container.
|
|
64
|
+
* @property {string} imagePullPolicy - The image pull policy for the container.
|
|
65
|
+
* @property {string} apiVersion - The API version for the container.
|
|
66
|
+
* @property {string} claimName - The claim name for the volume.
|
|
67
|
+
* @property {string} kind - The kind of resource to create.
|
|
60
68
|
* @property {boolean} terminal - Whether to open a terminal.
|
|
61
69
|
* @property {number} devProxyPortOffset - The port offset for the development proxy.
|
|
62
70
|
* @property {string} confServerPath - The configuration server path.
|
|
71
|
+
* @property {string} underpostRoot - The root path of the Underpost installation.
|
|
63
72
|
* @memberof UnderpostRun
|
|
64
73
|
*/
|
|
65
74
|
static DEFAULT_OPTION = {
|
|
66
75
|
dev: false,
|
|
67
76
|
podName: '',
|
|
77
|
+
nodeName: '',
|
|
78
|
+
port: 0,
|
|
68
79
|
volumeHostPath: '',
|
|
69
80
|
volumeMountPath: '',
|
|
70
81
|
imageName: '',
|
|
@@ -80,9 +91,15 @@ class UnderpostRun {
|
|
|
80
91
|
tty: '',
|
|
81
92
|
stdin: '',
|
|
82
93
|
restartPolicy: '',
|
|
94
|
+
runtimeClassName: '',
|
|
95
|
+
imagePullPolicy: '',
|
|
96
|
+
apiVersion: '',
|
|
97
|
+
claimName: '',
|
|
98
|
+
kind: '',
|
|
83
99
|
terminal: false,
|
|
84
100
|
devProxyPortOffset: 0,
|
|
85
101
|
confServerPath: '',
|
|
102
|
+
underpostRoot: '',
|
|
86
103
|
};
|
|
87
104
|
/**
|
|
88
105
|
* @static
|
|
@@ -216,13 +233,66 @@ class UnderpostRun {
|
|
|
216
233
|
);
|
|
217
234
|
shellExec(`${baseCommand} cluster${options.dev ? ' --dev' : ''} --valkey --pull-image`);
|
|
218
235
|
}
|
|
219
|
-
shellExec(`${baseCommand} deploy --expose mongo`, { async: true });
|
|
220
|
-
shellExec(`${baseCommand} deploy --expose valkey`, { async: true });
|
|
236
|
+
shellExec(`${baseCommand} deploy --expose --disable-update-underpost-config mongo`, { async: true });
|
|
237
|
+
shellExec(`${baseCommand} deploy --expose --disable-update-underpost-config valkey`, { async: true });
|
|
221
238
|
{
|
|
222
239
|
const hostListenResult = UnderpostDeploy.API.etcHostFactory(mongoHosts);
|
|
223
240
|
logger.info(hostListenResult.renderHosts);
|
|
224
241
|
}
|
|
225
242
|
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @method metadata
|
|
246
|
+
* @description Generates metadata for the specified path after exposing the development cluster.
|
|
247
|
+
* @param {string} path - The input value, identifier, or path for the operation.
|
|
248
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
249
|
+
* @memberof UnderpostRun
|
|
250
|
+
*/
|
|
251
|
+
metadata: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
252
|
+
const ports = '6379,27017';
|
|
253
|
+
shellExec(`node bin run kill '${ports}'`);
|
|
254
|
+
shellExec(`node bin run dev-cluster --dev expose`, { async: true });
|
|
255
|
+
console.log('Loading fordward services...');
|
|
256
|
+
await timer(5000);
|
|
257
|
+
shellExec(`node bin metadata --generate ${path}`);
|
|
258
|
+
shellExec(`node bin run kill '${ports}'`);
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @method svc-ls
|
|
263
|
+
* @description Lists systemd services and installed packages, optionally filtering by the provided path.
|
|
264
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the optional filter for services and packages).
|
|
265
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
266
|
+
* @memberof UnderpostRun
|
|
267
|
+
*/
|
|
268
|
+
'svc-ls': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
269
|
+
const log = shellExec(`systemctl list-units --type=service${path ? ` | grep ${path}` : ''}`, {
|
|
270
|
+
silent: true,
|
|
271
|
+
stdout: true,
|
|
272
|
+
});
|
|
273
|
+
console.log(path ? log.replaceAll(path, path.red) : log);
|
|
274
|
+
const log0 = shellExec(`sudo dnf list installed${path ? ` | grep ${path}` : ''}`, {
|
|
275
|
+
silent: true,
|
|
276
|
+
stdout: true,
|
|
277
|
+
});
|
|
278
|
+
console.log(path ? log0.replaceAll(path, path.red) : log0);
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @method svc-rm
|
|
283
|
+
* @description Removes a systemd service by stopping it, disabling it, uninstalling the package, and deleting related files.
|
|
284
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the service name).
|
|
285
|
+
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
286
|
+
* @memberof UnderpostRun
|
|
287
|
+
*/
|
|
288
|
+
'svc-rm': (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
289
|
+
shellExec(`sudo systemctl stop ${path}`);
|
|
290
|
+
shellExec(`sudo systemctl disable --now ${path}`);
|
|
291
|
+
shellExec(`sudo dnf remove -y ${path}*`);
|
|
292
|
+
shellExec(`sudo rm -f /usr/lib/systemd/system/${path}.service`);
|
|
293
|
+
shellExec(`sudo rm -f /etc/yum.repos.d/${path}*.repo`);
|
|
294
|
+
},
|
|
295
|
+
|
|
226
296
|
/**
|
|
227
297
|
* @method ssh-cluster-info
|
|
228
298
|
* @description Executes the `ssh-cluster-info.sh` script to display cluster connection information.
|
|
@@ -498,7 +568,12 @@ class UnderpostRun {
|
|
|
498
568
|
* @memberof UnderpostRun
|
|
499
569
|
*/
|
|
500
570
|
'ls-images': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
501
|
-
console.table(
|
|
571
|
+
console.table(
|
|
572
|
+
UnderpostDeploy.API.getCurrentLoadedImages(
|
|
573
|
+
options.nodeName ? options.nodeName : 'kind-worker',
|
|
574
|
+
path === 'spec' ? true : false,
|
|
575
|
+
),
|
|
576
|
+
);
|
|
502
577
|
},
|
|
503
578
|
|
|
504
579
|
/**
|
|
@@ -515,39 +590,51 @@ class UnderpostRun {
|
|
|
515
590
|
},
|
|
516
591
|
|
|
517
592
|
/**
|
|
518
|
-
* @method
|
|
519
|
-
* @description
|
|
520
|
-
* @param {string} path - The input value, identifier, or path for the operation (used as
|
|
593
|
+
* @method dd-container
|
|
594
|
+
* @description Deploys a development or debug container tasks jobs, setting up necessary volumes and images, and running specified commands within the container.
|
|
595
|
+
* @param {string} path - The input value, identifier, or path for the operation (used as the command to run inside the container).
|
|
521
596
|
* @param {Object} options - The default underpost runner options for customizing workflow
|
|
522
597
|
* @memberof UnderpostRun
|
|
523
598
|
*/
|
|
524
|
-
'
|
|
525
|
-
options.dev = true;
|
|
599
|
+
'dd-container': async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
526
600
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
527
601
|
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
528
|
-
const currentImage = UnderpostDeploy.API.getCurrentLoadedImages(
|
|
529
|
-
|
|
530
|
-
|
|
602
|
+
const currentImage = UnderpostDeploy.API.getCurrentLoadedImages(
|
|
603
|
+
options.nodeName ? options.nodeName : 'kind-worker',
|
|
604
|
+
false,
|
|
605
|
+
).find((o) => o.IMAGE.match('underpost'));
|
|
531
606
|
const podName = `underpost-dev-container`;
|
|
532
|
-
if (!
|
|
607
|
+
if (!options.nodeName) {
|
|
608
|
+
shellExec(`docker exec -i kind-worker bash -c "rm -rf /home/dd"`);
|
|
533
609
|
shellExec(`docker exec -i kind-worker bash -c "mkdir -p /home/dd"`);
|
|
534
610
|
shellExec(`docker cp /home/dd/engine kind-worker:/home/dd/engine`);
|
|
535
611
|
shellExec(`docker exec -i kind-worker bash -c "chown -R 1000:1000 /home/dd || true; chmod -R 755 /home/dd"`);
|
|
612
|
+
} else {
|
|
613
|
+
shellExec(`kubectl apply -f ${options.underpostRoot}/manifests/pv-pvc-dd.yaml`);
|
|
536
614
|
}
|
|
537
|
-
if (!currentImage)
|
|
615
|
+
if (!currentImage)
|
|
616
|
+
shellExec(
|
|
617
|
+
`${baseCommand} dockerfile-pull-base-images${baseClusterCommand} ${options.dev ? '--kind-load' : '--kubeadm-load'}`,
|
|
618
|
+
);
|
|
538
619
|
// shellExec(`kubectl delete pod ${podName} --ignore-not-found`);
|
|
539
620
|
await UnderpostRun.RUNNERS['deploy-job']('', {
|
|
540
|
-
dev:
|
|
621
|
+
dev: options.dev,
|
|
541
622
|
podName,
|
|
542
|
-
imageName: currentImage
|
|
543
|
-
|
|
623
|
+
imageName: currentImage
|
|
624
|
+
? currentImage.image
|
|
625
|
+
? currentImage.image
|
|
626
|
+
: currentImage.IMAGE
|
|
627
|
+
? `${currentImage.IMAGE}:${currentImage.TAG}`
|
|
628
|
+
: `localhost/rockylinux9-underpost:${Underpost.version}`
|
|
629
|
+
: `localhost/rockylinux9-underpost:${Underpost.version}`,
|
|
544
630
|
volumeMountPath: '/home/dd',
|
|
631
|
+
...(options.dev ? { volumeHostPath: '/home/dd' } : { claimName: 'pvc-dd' }),
|
|
545
632
|
on: {
|
|
546
633
|
init: async () => {
|
|
547
634
|
// openTerminal(`kubectl logs -f ${podName}`);
|
|
548
635
|
},
|
|
549
636
|
},
|
|
550
|
-
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm run test`)],
|
|
637
|
+
args: [daemonProcess(path ? path : `cd /home/dd/engine && npm install && npm run test`)],
|
|
551
638
|
});
|
|
552
639
|
},
|
|
553
640
|
|
|
@@ -883,52 +970,84 @@ class UnderpostRun {
|
|
|
883
970
|
service: async (path = '', options = UnderpostRun.DEFAULT_OPTION) => {
|
|
884
971
|
const env = options.dev ? 'development' : 'production';
|
|
885
972
|
const baseCommand = options.dev ? 'node bin' : 'underpost';
|
|
886
|
-
|
|
973
|
+
const baseClusterCommand = options.dev ? ' --dev' : '';
|
|
887
974
|
shellCd(`/home/dd/engine`);
|
|
888
975
|
let [deployId, serviceId, host, _path, replicas, image, node] = path.split(',');
|
|
976
|
+
// const confClient = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.client.json`, 'utf8'));
|
|
977
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
978
|
+
// const confSSR = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.ssr.json`, 'utf8'));
|
|
979
|
+
// const packageData = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/package.json`, 'utf8'));
|
|
889
980
|
const services = fs.existsSync(`./engine-private/deploy/${deployId}/conf.services.json`)
|
|
890
981
|
? JSON.parse(fs.readFileSync(`./engine-private/deploy/${deployId}/conf.services.json`, 'utf8'))
|
|
891
982
|
: [];
|
|
983
|
+
let serviceData = services.findIndex((s) => s.serviceId === serviceId);
|
|
984
|
+
const payload = {
|
|
985
|
+
serviceId,
|
|
986
|
+
path: _path,
|
|
987
|
+
port: options.port,
|
|
988
|
+
host,
|
|
989
|
+
};
|
|
990
|
+
let podToMonitor;
|
|
991
|
+
if (!payload.port)
|
|
992
|
+
switch (serviceId) {
|
|
993
|
+
case 'mongo-express-service': {
|
|
994
|
+
payload.port = 8081;
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
case 'grafana': {
|
|
998
|
+
payload.port = 3000;
|
|
999
|
+
// payload.pathRewritePolicy = [
|
|
1000
|
+
// {
|
|
1001
|
+
// prefix: '/grafana',
|
|
1002
|
+
// replacement: '/',
|
|
1003
|
+
// },
|
|
1004
|
+
// ];
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
if (serviceData == -1) {
|
|
1009
|
+
services.push(payload);
|
|
1010
|
+
} else {
|
|
1011
|
+
services[serviceData] = payload;
|
|
1012
|
+
}
|
|
1013
|
+
fs.writeFileSync(
|
|
1014
|
+
`./engine-private/conf/${deployId}/conf.services.json`,
|
|
1015
|
+
JSON.stringify(services, null, 4),
|
|
1016
|
+
'utf8',
|
|
1017
|
+
);
|
|
892
1018
|
switch (serviceId) {
|
|
893
1019
|
case 'mongo-express-service': {
|
|
894
|
-
let serviceData = services.findIndex((s) => s.serviceId === serviceId);
|
|
895
|
-
const payload = {
|
|
896
|
-
serviceId,
|
|
897
|
-
path: _path,
|
|
898
|
-
port: 8081,
|
|
899
|
-
host,
|
|
900
|
-
};
|
|
901
|
-
if (serviceData == -1) {
|
|
902
|
-
services.push(payload);
|
|
903
|
-
} else {
|
|
904
|
-
services[serviceData] = payload;
|
|
905
|
-
}
|
|
906
|
-
fs.writeFileSync(
|
|
907
|
-
`./engine-private/conf/${deployId}/conf.services.json`,
|
|
908
|
-
JSON.stringify(services, null, 4),
|
|
909
|
-
'utf8',
|
|
910
|
-
);
|
|
911
1020
|
shellExec(`kubectl delete svc mongo-express-service --ignore-not-found`);
|
|
912
1021
|
shellExec(`kubectl delete deployment mongo-express --ignore-not-found`);
|
|
913
1022
|
shellExec(`kubectl apply -f manifests/deployment/mongo-express/deployment.yaml`);
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
replicas ? replicas : 1
|
|
923
|
-
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
924
|
-
);
|
|
925
|
-
shellExec(
|
|
926
|
-
`${baseCommand} deploy --kubeadm --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
|
|
927
|
-
);
|
|
928
|
-
} else logger.error('Mongo Express deployment failed');
|
|
1023
|
+
podToMonitor = 'mongo-express';
|
|
1024
|
+
break;
|
|
1025
|
+
}
|
|
1026
|
+
case 'grafana': {
|
|
1027
|
+
shellExec(
|
|
1028
|
+
`node bin cluster${baseClusterCommand} --grafana --hosts '${host}' --prom '${Object.keys(confServer)}'`,
|
|
1029
|
+
);
|
|
1030
|
+
podToMonitor = 'grafana';
|
|
929
1031
|
break;
|
|
930
1032
|
}
|
|
931
1033
|
}
|
|
1034
|
+
const success = await UnderpostTest.API.statusMonitor(podToMonitor);
|
|
1035
|
+
if (success) {
|
|
1036
|
+
const versions = UnderpostDeploy.API.getCurrentTraffic(deployId) || 'blue';
|
|
1037
|
+
if (!node) node = os.hostname();
|
|
1038
|
+
shellExec(
|
|
1039
|
+
`${baseCommand} deploy${options.dev ? '' : ' --kubeadm'}${options.devProxyPortOffset ? ' --disable-deployment-proxy' : ''} --build-manifest --sync --info-router --replicas ${
|
|
1040
|
+
replicas ? replicas : 1
|
|
1041
|
+
} --node ${node}${image ? ` --image ${image}` : ''}${versions ? ` --versions ${versions}` : ''} dd ${env}`,
|
|
1042
|
+
);
|
|
1043
|
+
shellExec(
|
|
1044
|
+
`${baseCommand} deploy${options.dev ? '' : ' --kubeadm'}${options.devProxyPortOffset ? ' --disable-deployment-proxy' : ''} --disable-update-deployment ${deployId} ${env} --versions ${versions}`,
|
|
1045
|
+
);
|
|
1046
|
+
} else logger.error('Mongo Express deployment failed');
|
|
1047
|
+
if (options.etcHosts === true) {
|
|
1048
|
+
const hostListenResult = UnderpostDeploy.API.etcHostFactory([host]);
|
|
1049
|
+
logger.info(hostListenResult.renderHosts);
|
|
1050
|
+
}
|
|
932
1051
|
},
|
|
933
1052
|
|
|
934
1053
|
/**
|
|
@@ -1058,28 +1177,34 @@ class UnderpostRun {
|
|
|
1058
1177
|
'deploy-job': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
|
|
1059
1178
|
const podName = options.podName || 'deploy-job';
|
|
1060
1179
|
const volumeName = `${podName}-volume`;
|
|
1061
|
-
|
|
1180
|
+
if (typeof options.args === 'string') options.args = options.args.split(',');
|
|
1181
|
+
const args = (options.args ? options.args : path ? [path] : [`python ${path}`]).filter((c) => c.trim());
|
|
1062
1182
|
const imageName = options.imageName || 'nvcr.io/nvidia/tensorflow:24.04-tf2-py3';
|
|
1063
1183
|
const containerName = options.containerName || `${podName}-container`;
|
|
1064
1184
|
const gpuEnable = imageName.match('nvidia');
|
|
1065
|
-
const runtimeClassName = gpuEnable ? 'nvidia' : '';
|
|
1185
|
+
const runtimeClassName = options.runtimeClassName ? options.runtimeClassName : gpuEnable ? 'nvidia' : '';
|
|
1066
1186
|
const namespace = options.namespace || 'default';
|
|
1067
1187
|
const volumeMountPath = options.volumeMountPath || path;
|
|
1068
1188
|
const volumeHostPath = options.volumeHostPath || path;
|
|
1069
|
-
const
|
|
1189
|
+
const claimName = options.claimName || '';
|
|
1190
|
+
const enableVolumeMount = volumeMountPath && (volumeHostPath || claimName);
|
|
1070
1191
|
const tty = options.tty ? 'true' : 'false';
|
|
1071
1192
|
const stdin = options.stdin ? 'true' : 'false';
|
|
1072
1193
|
const restartPolicy = options.restartPolicy || 'Never';
|
|
1073
|
-
|
|
1194
|
+
const kind = options.kind || 'Pod';
|
|
1195
|
+
const imagePullPolicy = options.imagePullPolicy || 'IfNotPresent';
|
|
1196
|
+
const apiVersion = options.apiVersion || 'v1';
|
|
1074
1197
|
if (options.volumeType === 'dev') options.volumeType = 'FileOrCreate';
|
|
1075
1198
|
const volumeType =
|
|
1076
|
-
options.volumeType || (enableVolumeMount && fs.statSync(volumeHostPath).isDirectory())
|
|
1199
|
+
options.volumeType || (enableVolumeMount && volumeHostPath && fs.statSync(volumeHostPath).isDirectory())
|
|
1200
|
+
? 'Directory'
|
|
1201
|
+
: 'File';
|
|
1077
1202
|
|
|
1078
1203
|
const envs = UnderpostRootEnv.API.list();
|
|
1079
1204
|
|
|
1080
1205
|
const cmd = `kubectl apply -f - <<EOF
|
|
1081
|
-
apiVersion:
|
|
1082
|
-
kind:
|
|
1206
|
+
apiVersion: ${apiVersion}
|
|
1207
|
+
kind: ${kind}
|
|
1083
1208
|
metadata:
|
|
1084
1209
|
name: ${podName}
|
|
1085
1210
|
namespace: ${namespace}
|
|
@@ -1091,7 +1216,7 @@ ${runtimeClassName ? ` runtimeClassName: ${runtimeClassName}` : ''}
|
|
|
1091
1216
|
containers:
|
|
1092
1217
|
- name: ${containerName}
|
|
1093
1218
|
image: ${imageName}
|
|
1094
|
-
imagePullPolicy:
|
|
1219
|
+
imagePullPolicy: ${imagePullPolicy}
|
|
1095
1220
|
tty: ${tty}
|
|
1096
1221
|
stdin: ${stdin}
|
|
1097
1222
|
command: ${JSON.stringify(options.command ? options.command : ['/bin/bash', '-c'])}
|
|
@@ -1117,15 +1242,7 @@ ${Object.keys(envs)
|
|
|
1117
1242
|
.join('\n')}`}
|
|
1118
1243
|
${
|
|
1119
1244
|
enableVolumeMount
|
|
1120
|
-
?
|
|
1121
|
-
volumeMounts:
|
|
1122
|
-
- name: ${volumeName}
|
|
1123
|
-
mountPath: ${volumeMountPath}
|
|
1124
|
-
volumes:
|
|
1125
|
-
- name: ${volumeName}
|
|
1126
|
-
hostPath:
|
|
1127
|
-
path: ${volumeHostPath}
|
|
1128
|
-
type: ${volumeType}`
|
|
1245
|
+
? UnderpostDeploy.API.volumeFactory([{ volumeMountPath, volumeName, volumeHostPath, volumeType, claimName }]).render
|
|
1129
1246
|
: ''
|
|
1130
1247
|
}
|
|
1131
1248
|
EOF`;
|
|
@@ -1156,7 +1273,7 @@ EOF`;
|
|
|
1156
1273
|
const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
|
|
1157
1274
|
if (options.command) options.command = options.command.split(',');
|
|
1158
1275
|
if (options.args) options.args = options.args.split(',');
|
|
1159
|
-
options.underpostRoot = underpostRoot;
|
|
1276
|
+
if (!options.underpostRoot) options.underpostRoot = underpostRoot;
|
|
1160
1277
|
options.npmRoot = npmRoot;
|
|
1161
1278
|
logger.info('callback', { path, options });
|
|
1162
1279
|
if (!(runner in UnderpostRun.RUNNERS)) throw new Error(`Runner not found: ${runner}`);
|
|
@@ -940,12 +940,13 @@ const ObjectLayerEngineModal = {
|
|
|
940
940
|
const queryParams = getQueryParams();
|
|
941
941
|
queryParams.page = 1;
|
|
942
942
|
setQueryParams(queryParams);
|
|
943
|
-
const
|
|
943
|
+
const modalId = 'modal-object-layer-engine-management';
|
|
944
|
+
const managerComponent = DefaultManagement.Tokens[modalId];
|
|
944
945
|
if (managerComponent) {
|
|
945
946
|
managerComponent.page = 1;
|
|
946
947
|
if (!managerComponent.readyRowDataEvent) managerComponent.readyRowDataEvent = {};
|
|
947
948
|
let readyLoad = false;
|
|
948
|
-
const gridId =
|
|
949
|
+
const gridId = `object-layer-engine-management-grid-${modalId}`;
|
|
949
950
|
managerComponent.readyRowDataEvent['object-layer-engine-management'] = async () => {
|
|
950
951
|
if (readyLoad) {
|
|
951
952
|
AgGrid.grids[gridId].setGridOption('getRowClass', null);
|
|
@@ -961,7 +962,7 @@ const ObjectLayerEngineModal = {
|
|
|
961
962
|
};
|
|
962
963
|
}
|
|
963
964
|
|
|
964
|
-
const _s = s(`.management-table-btn-reload
|
|
965
|
+
const _s = s(`.management-table-btn-reload-${modalId}`);
|
|
965
966
|
if (_s) _s.click();
|
|
966
967
|
|
|
967
968
|
s(`.main-btn-object-layer-engine-management`).click();
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { loggerFactory } from './Logger.js';
|
|
2
|
-
import { getProxyPath, listenQueryPathInstance } from './Router.js';
|
|
2
|
+
import { getProxyPath, listenQueryPathInstance, setPath, setQueryParams } from './Router.js';
|
|
3
3
|
import { ObjectLayerService } from '../../services/object-layer/object-layer.service.js';
|
|
4
4
|
import { NotificationManager } from './NotificationManager.js';
|
|
5
5
|
import { htmls, s } from './VanillaJs.js';
|
|
6
6
|
import { BtnIcon } from './BtnIcon.js';
|
|
7
7
|
import { darkTheme, ThemeEvents } from './Css.js';
|
|
8
|
-
import {
|
|
8
|
+
import { ObjectLayerManagement } from '../../services/object-layer/object-layer.management.js';
|
|
9
|
+
import { ObjectLayerEngineModal } from './ObjectLayerEngineModal.js';
|
|
9
10
|
|
|
10
11
|
const logger = loggerFactory(import.meta);
|
|
11
12
|
|
|
@@ -66,7 +67,7 @@ const ObjectLayerEngineViewer = {
|
|
|
66
67
|
if (cid) {
|
|
67
68
|
await this.loadObjectLayer(cid);
|
|
68
69
|
} else {
|
|
69
|
-
this.renderEmpty();
|
|
70
|
+
this.renderEmpty({ Elements });
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
73
|
},
|
|
@@ -103,9 +104,15 @@ const ObjectLayerEngineViewer = {
|
|
|
103
104
|
`;
|
|
104
105
|
},
|
|
105
106
|
|
|
106
|
-
renderEmpty: async function () {
|
|
107
|
+
renderEmpty: async function ({ Elements }) {
|
|
107
108
|
const id = 'object-layer-engine-viewer';
|
|
108
|
-
htmls(
|
|
109
|
+
htmls(
|
|
110
|
+
`#${id}`,
|
|
111
|
+
await ObjectLayerManagement.RenderTable({
|
|
112
|
+
Elements,
|
|
113
|
+
idModal: 'modal-object-layer-engine-viewer',
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
109
116
|
},
|
|
110
117
|
|
|
111
118
|
loadObjectLayer: async function (objectLayerId) {
|
|
@@ -398,6 +405,14 @@ const ObjectLayerEngineViewer = {
|
|
|
398
405
|
transform: none;
|
|
399
406
|
}
|
|
400
407
|
|
|
408
|
+
.edit-btn {
|
|
409
|
+
background: ${darkTheme ? '#4a9eff' : '#2196F3'};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.edit-btn:hover {
|
|
413
|
+
background: ${darkTheme ? '#3a8eff' : '#1186f2'};
|
|
414
|
+
}
|
|
415
|
+
|
|
401
416
|
@media (max-width: 768px) {
|
|
402
417
|
.gif-display-area {
|
|
403
418
|
max-height: 500px;
|
|
@@ -440,7 +455,8 @@ const ObjectLayerEngineViewer = {
|
|
|
440
455
|
.item-data-value-label {
|
|
441
456
|
font-size: 20px;
|
|
442
457
|
font-weight: 700;
|
|
443
|
-
color: ${darkTheme ? '#
|
|
458
|
+
color: ${darkTheme ? '#aaa' : '#666'};
|
|
459
|
+
text-align: center;
|
|
444
460
|
}
|
|
445
461
|
.item-stat-entry {
|
|
446
462
|
display: flex;
|
|
@@ -493,6 +509,32 @@ const ObjectLayerEngineViewer = {
|
|
|
493
509
|
</div>
|
|
494
510
|
</div>
|
|
495
511
|
|
|
512
|
+
<!-- Stats Data Section -->
|
|
513
|
+
<div class="control-group" style="margin-bottom: 20px;">
|
|
514
|
+
<h4><i class="fa-solid fa-chart-bar"></i> Stats Data</h4>
|
|
515
|
+
<div
|
|
516
|
+
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; padding: 10px 0;"
|
|
517
|
+
>
|
|
518
|
+
${Object.keys(stats).length > 0
|
|
519
|
+
? Object.entries(stats)
|
|
520
|
+
.map(([statKey, statValue]) => {
|
|
521
|
+
const statInfo = ObjectLayerEngineModal.statDescriptions[statKey];
|
|
522
|
+
if (!statInfo) return '';
|
|
523
|
+
return html`
|
|
524
|
+
<div class="item-stat-entry">
|
|
525
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
526
|
+
<i class="${statInfo.icon}" id="stat-icon-${statKey}-${id}"></i>
|
|
527
|
+
<span class="item-data-key-label">${statInfo.title}</span>
|
|
528
|
+
</div>
|
|
529
|
+
<span class="item-data-value-label">${statValue}</span>
|
|
530
|
+
</div>
|
|
531
|
+
`;
|
|
532
|
+
})
|
|
533
|
+
.join('')
|
|
534
|
+
: html`<div class="no-data-container">No stats data available</div>`}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
|
|
496
538
|
<div class="gif-display-area">
|
|
497
539
|
<div class="gif-canvas-container" id="gif-canvas-container">
|
|
498
540
|
<div style="text-align: center; color: ${darkTheme ? '#aaa' : '#666'};">
|
|
@@ -587,30 +629,17 @@ const ObjectLayerEngineViewer = {
|
|
|
587
629
|
</div>
|
|
588
630
|
</div>
|
|
589
631
|
</div>
|
|
590
|
-
|
|
591
|
-
<div
|
|
592
|
-
<
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
>
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
<div class="item-stat-entry">
|
|
601
|
-
<span class="item-data-key-label"> ${statKey} </span>
|
|
602
|
-
<span style="item-data-value-label"> ${statValue} </span>
|
|
603
|
-
</div>
|
|
604
|
-
`,
|
|
605
|
-
)
|
|
606
|
-
.join('')
|
|
607
|
-
: html`<div class="no-data-container">No stats data available</div>`}
|
|
608
|
-
</div>
|
|
632
|
+
|
|
633
|
+
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
|
634
|
+
<button class="download-btn" id="download-gif-btn" style="width: 100%;">
|
|
635
|
+
<i class="fa-solid fa-download"></i>
|
|
636
|
+
<span>Download GIF</span>
|
|
637
|
+
</button>
|
|
638
|
+
<button class="download-btn edit-btn" id="edit-object-layer-btn" style="width: 100%;">
|
|
639
|
+
<i class="fa-solid fa-edit"></i>
|
|
640
|
+
<span>Edit</span>
|
|
641
|
+
</button>
|
|
609
642
|
</div>
|
|
610
|
-
<button class="download-btn" id="download-gif-btn">
|
|
611
|
-
<i class="fa-solid fa-download"></i>
|
|
612
|
-
<span>Download GIF</span>
|
|
613
|
-
</button>
|
|
614
643
|
</div>
|
|
615
644
|
`,
|
|
616
645
|
);
|
|
@@ -658,6 +687,13 @@ const ObjectLayerEngineViewer = {
|
|
|
658
687
|
});
|
|
659
688
|
}
|
|
660
689
|
|
|
690
|
+
const editBtn = s('#edit-object-layer-btn');
|
|
691
|
+
if (editBtn) {
|
|
692
|
+
editBtn.addEventListener('click', () => {
|
|
693
|
+
this.toEngine();
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
|
|
661
697
|
// Back button
|
|
662
698
|
setTimeout(() => {
|
|
663
699
|
const backBtn = s('[data-id="btn-back"]');
|
|
@@ -1046,14 +1082,30 @@ const ObjectLayerEngineViewer = {
|
|
|
1046
1082
|
});
|
|
1047
1083
|
},
|
|
1048
1084
|
|
|
1049
|
-
|
|
1085
|
+
toEngine: function () {
|
|
1086
|
+
const { objectLayer } = this.Data;
|
|
1087
|
+
if (!objectLayer || !objectLayer._id) return;
|
|
1088
|
+
|
|
1089
|
+
// Navigate to editor route first
|
|
1090
|
+
setPath(`${getProxyPath()}object-layer-engine`);
|
|
1091
|
+
// Then add query param without replacing history
|
|
1092
|
+
setQueryParams({ cid: objectLayer._id }, { replace: true });
|
|
1093
|
+
|
|
1094
|
+
if (s(`.modal-object-layer-engine`)) {
|
|
1095
|
+
ObjectLayerEngineModal.Reload();
|
|
1096
|
+
} else {
|
|
1097
|
+
s(`.main-btn-object-layer-engine`)?.click();
|
|
1098
|
+
}
|
|
1099
|
+
},
|
|
1100
|
+
|
|
1101
|
+
Reload: async function ({ Elements }) {
|
|
1050
1102
|
const queryParams = new URLSearchParams(window.location.search);
|
|
1051
1103
|
const cid = queryParams.get('cid');
|
|
1052
1104
|
|
|
1053
1105
|
if (cid) {
|
|
1054
1106
|
await this.loadObjectLayer(cid);
|
|
1055
1107
|
} else {
|
|
1056
|
-
this.renderEmpty();
|
|
1108
|
+
this.renderEmpty({ Elements });
|
|
1057
1109
|
}
|
|
1058
1110
|
},
|
|
1059
1111
|
};
|
package/src/index.js
CHANGED
package/src/server/start.js
CHANGED
|
@@ -132,7 +132,8 @@ class UnderpostStartUp {
|
|
|
132
132
|
const buildBasePath = `/home/dd`;
|
|
133
133
|
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
134
134
|
shellExec(`cd ${buildBasePath} && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}`);
|
|
135
|
-
shellExec(`cd ${buildBasePath} && sudo
|
|
135
|
+
shellExec(`cd ${buildBasePath} && sudo cp -a ./${repoName}/* ./engine`);
|
|
136
|
+
shellExec(`cd ${buildBasePath} && sudo rm -rf ./${repoName}`);
|
|
136
137
|
shellExec(`cd ${buildBasePath}/engine && underpost clone ${process.env.GITHUB_USERNAME}/${repoName}-private`);
|
|
137
138
|
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
138
139
|
shellCd(`${buildBasePath}/engine`);
|