underpost 2.8.56 → 2.8.62
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/.vscode/settings.json +3 -0
- package/bin/index.js +14 -6
- package/bin/vs.js +1 -0
- package/docker-compose.yml +1 -1
- package/manifests/mongodb/kustomization.yaml +2 -2
- package/package.json +1 -1
- package/src/cli/cron.js +1 -1
- package/src/cli/db.js +101 -39
- package/src/cli/deploy.js +44 -7
- package/src/cli/env.js +9 -3
- package/src/cli/fs.js +27 -12
- package/src/cli/image.js +27 -15
- package/src/cli/repository.js +9 -1
- package/src/client/components/core/CalendarCore.js +12 -1
- package/src/client/components/core/CommonJs.js +52 -1
- package/src/client/components/core/CssCore.js +2 -4
- package/src/client/components/core/Docs.js +1 -2
- package/src/client/components/core/Input.js +4 -2
- package/src/client/components/core/LoadingAnimation.js +8 -1
- package/src/client/components/core/Modal.js +31 -7
- package/src/client/components/core/Panel.js +8 -6
- package/src/client/components/core/PanelForm.js +23 -7
- package/src/client/services/core/core.service.js +15 -10
- package/src/client/ssr/Render.js +4 -1
- package/src/client/ssr/body/CacheControl.js +2 -3
- package/src/client/sw/default.sw.js +3 -3
- package/src/index.js +1 -1
- package/src/server/backup.js +2 -2
- package/src/server/client-build.js +32 -23
- package/src/server/conf.js +1 -1
- package/src/server/runtime.js +16 -1
- package/manifests/valkey/underpost-engine-valkey-service.yaml +0 -17
- package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +0 -39
package/.vscode/settings.json
CHANGED
package/bin/index.js
CHANGED
|
@@ -6,9 +6,6 @@ import Underpost from '../src/index.js';
|
|
|
6
6
|
import { getUnderpostRootPath, loadConf } from '../src/server/conf.js';
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import { commitData } from '../src/client/components/core/CommonJs.js';
|
|
9
|
-
import UnderpostScript from '../src/cli/script.js';
|
|
10
|
-
import UnderpostDB from '../src/cli/db.js';
|
|
11
|
-
import UnderpostCron from '../src/cli/cron.js';
|
|
12
9
|
|
|
13
10
|
const underpostRootPath = getUnderpostRootPath();
|
|
14
11
|
fs.existsSync(`${underpostRootPath}/.env`)
|
|
@@ -106,7 +103,9 @@ program
|
|
|
106
103
|
.option('--info-router', 'Display router structure')
|
|
107
104
|
.option('--expose', 'Expose service match deploy-list')
|
|
108
105
|
.option('--info-util', 'Display kubectl util management commands')
|
|
106
|
+
.option('--cert', 'Reset tls/ssl certificate secrets')
|
|
109
107
|
.option('--build-manifest', 'Build kind yaml manifests: deployments, services, proxy and secrets')
|
|
108
|
+
.option('--version', 'Set custom version')
|
|
110
109
|
.description('Manage deployment, for default deploy development pods')
|
|
111
110
|
.action(Underpost.deploy.callback);
|
|
112
111
|
|
|
@@ -130,6 +129,7 @@ program
|
|
|
130
129
|
.argument('<deploy-id>', 'Deploy configuration id')
|
|
131
130
|
.argument('[env]', 'Optional environment, for default is development')
|
|
132
131
|
.option('--run', 'Run custom entry point script')
|
|
132
|
+
.option('--build', 'Build custom image container scripts')
|
|
133
133
|
.description('Dockerfile custom node build script')
|
|
134
134
|
.action(Underpost.image.dockerfile.script);
|
|
135
135
|
|
|
@@ -140,6 +140,8 @@ program
|
|
|
140
140
|
.argument('[path]', 'Absolute or relative directory, for default is current')
|
|
141
141
|
.option('--image-archive', 'Only load tar image from ./images')
|
|
142
142
|
.option('--podman-save', 'Save image from podman to ./images')
|
|
143
|
+
.option('--image-name <image-name>', 'Set custom image name')
|
|
144
|
+
.option('--image-version <image-version>', 'Set custom image version')
|
|
143
145
|
.description('Build image from Dockerfile')
|
|
144
146
|
.action(Underpost.image.dockerfile.build);
|
|
145
147
|
|
|
@@ -161,13 +163,18 @@ program
|
|
|
161
163
|
.option('--import', 'Import container backups from repositories')
|
|
162
164
|
.option('--export', 'Export container backups to repositories')
|
|
163
165
|
.option('--pod-name <pod-name>', 'Optional pod context')
|
|
166
|
+
.option('--collection <collection>', 'Collection')
|
|
167
|
+
.option('--out-path <out-path>', 'Custom out path backup')
|
|
168
|
+
.option('--drop', 'Drop databases')
|
|
169
|
+
.option('--preserveUUID', 'Preserve Ids')
|
|
170
|
+
.option('--git', 'Upload to github')
|
|
164
171
|
.option('--ns <ns-name>', 'Optional name space context')
|
|
165
172
|
.description('Manage databases')
|
|
166
|
-
.action(
|
|
173
|
+
.action(Underpost.db.callback);
|
|
167
174
|
|
|
168
175
|
program
|
|
169
176
|
.command('script')
|
|
170
|
-
.argument('operator', `Options: ${Object.keys(
|
|
177
|
+
.argument('operator', `Options: ${Object.keys(Underpost.script)}`)
|
|
171
178
|
.argument('<script-name>', 'Script name')
|
|
172
179
|
.argument('[script-value]', 'Literal command, or path')
|
|
173
180
|
.option('--itc', 'Inside container execution context')
|
|
@@ -182,9 +189,10 @@ program
|
|
|
182
189
|
program
|
|
183
190
|
.command('cron')
|
|
184
191
|
.argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
|
|
185
|
-
.argument('[job-list]', `Deploy id list, e.g. ${Object.keys(
|
|
192
|
+
.argument('[job-list]', `Deploy id list, e.g. ${Object.keys(Underpost.cron)}, for default all available jobs`)
|
|
186
193
|
.option('--itc', 'Inside container execution context')
|
|
187
194
|
.option('--init', 'Init cron jobs for cron job default deploy id')
|
|
195
|
+
.option('--git', 'Upload to github')
|
|
188
196
|
.description('Cron jobs management')
|
|
189
197
|
.action(Underpost.cron.callback);
|
|
190
198
|
|
package/bin/vs.js
CHANGED
|
@@ -20,6 +20,7 @@ switch (process.argv[2]) {
|
|
|
20
20
|
logger.info('Open new vs windows', 'Ctrl Shift N');
|
|
21
21
|
logger.info('Close current vs windows', 'Ctrl Shift W');
|
|
22
22
|
logger.info('Preview md', 'Ctrl shift V');
|
|
23
|
+
logger.info('Open git changes', 'Ctrl G + G');
|
|
23
24
|
logger.warn('Terminal shortcut configure with command pallette', 'Ctl shift T');
|
|
24
25
|
break;
|
|
25
26
|
}
|
package/docker-compose.yml
CHANGED
package/package.json
CHANGED
package/src/cli/cron.js
CHANGED
|
@@ -46,7 +46,7 @@ class UnderpostCron {
|
|
|
46
46
|
callback: async function (
|
|
47
47
|
deployList = 'default',
|
|
48
48
|
jobList = Object.keys(UnderpostCron.JOB),
|
|
49
|
-
options = { itc: false, init: false },
|
|
49
|
+
options = { itc: false, init: false, git: false },
|
|
50
50
|
) {
|
|
51
51
|
if (options.init === true) {
|
|
52
52
|
await Underpost.test.setUpInfo();
|
package/src/cli/db.js
CHANGED
|
@@ -2,12 +2,26 @@ import { mergeFile, splitFileFactory } from '../server/conf.js';
|
|
|
2
2
|
import { loggerFactory } from '../server/logger.js';
|
|
3
3
|
import { shellExec } from '../server/process.js';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
|
+
import UnderpostDeploy from './deploy.js';
|
|
5
6
|
|
|
6
7
|
const logger = loggerFactory(import.meta);
|
|
7
8
|
|
|
8
9
|
class UnderpostDB {
|
|
9
10
|
static API = {
|
|
10
|
-
async callback(
|
|
11
|
+
async callback(
|
|
12
|
+
deployList = 'default',
|
|
13
|
+
options = {
|
|
14
|
+
import: false,
|
|
15
|
+
export: false,
|
|
16
|
+
podName: false,
|
|
17
|
+
ns: false,
|
|
18
|
+
collection: '',
|
|
19
|
+
outPath: '',
|
|
20
|
+
drop: false,
|
|
21
|
+
preserveUUID: false,
|
|
22
|
+
git: false,
|
|
23
|
+
},
|
|
24
|
+
) {
|
|
11
25
|
const newBackupTimestamp = new Date().getTime();
|
|
12
26
|
const nameSpace = options.ns && typeof options.ns === 'string' ? options.ns : 'default';
|
|
13
27
|
for (const _deployId of deployList.split(',')) {
|
|
@@ -43,10 +57,12 @@ class UnderpostDB {
|
|
|
43
57
|
logger.info('', { hostFolder, provider, dbName });
|
|
44
58
|
|
|
45
59
|
const backUpPath = `../${repoName}/${hostFolder}`;
|
|
60
|
+
if (!fs.existsSync(backUpPath)) fs.mkdirSync(backUpPath, { recursive: true });
|
|
61
|
+
shellExec(`cd ${backUpPath} && find . -type d -empty -delete`); // delete empty folders
|
|
46
62
|
const times = await fs.readdir(backUpPath);
|
|
47
|
-
const currentBackupTimestamp = Math.max(...times.map((t) => parseInt(t)));
|
|
63
|
+
const currentBackupTimestamp = Math.max(...times.map((t) => parseInt(t)).filter((t) => !isNaN(t)));
|
|
48
64
|
dbs[provider][dbName].currentBackupTimestamp = currentBackupTimestamp;
|
|
49
|
-
const removeBackupTimestamp = Math.min(...times.map((t) => parseInt(t)));
|
|
65
|
+
const removeBackupTimestamp = Math.min(...times.map((t) => parseInt(t)).filter((t) => !isNaN(t)));
|
|
50
66
|
|
|
51
67
|
const sqlContainerPath = `/home/${dbName}.sql`;
|
|
52
68
|
const _fromPartsParts = `../${repoName}/${hostFolder}/${currentBackupTimestamp}/${dbName}-parths.json`;
|
|
@@ -68,59 +84,105 @@ class UnderpostDB {
|
|
|
68
84
|
}
|
|
69
85
|
|
|
70
86
|
if (options.export === true && times.length >= 5) {
|
|
87
|
+
logger.info('remove', `../${repoName}/${hostFolder}/${removeBackupTimestamp}`);
|
|
71
88
|
fs.removeSync(`../${repoName}/${hostFolder}/${removeBackupTimestamp}`);
|
|
89
|
+
logger.info('create', `../${repoName}/${hostFolder}/${newBackupTimestamp}`);
|
|
72
90
|
fs.mkdirSync(`../${repoName}/${hostFolder}/${newBackupTimestamp}`, { recursive: true });
|
|
73
91
|
}
|
|
74
92
|
|
|
75
93
|
switch (provider) {
|
|
76
94
|
case 'mariadb': {
|
|
77
|
-
const
|
|
78
|
-
options.podName && typeof options.podName === 'string'
|
|
95
|
+
const podNames =
|
|
96
|
+
options.podName && typeof options.podName === 'string'
|
|
97
|
+
? options.podName.split(',')
|
|
98
|
+
: UnderpostDeploy.API.get('mariadb'); // `mariadb-statefulset-0`;
|
|
79
99
|
const serviceName = 'mariadb';
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`kubectl
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
for (const podNameData of [podNames[0]]) {
|
|
101
|
+
const podName = podNameData.NAME;
|
|
102
|
+
if (options.import === true) {
|
|
103
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "rm -rf /${dbName}.sql"`);
|
|
104
|
+
shellExec(`sudo kubectl cp ${_toSqlPath} ${nameSpace}/${podName}:/${dbName}.sql`);
|
|
105
|
+
const cmd = `mariadb -u ${user} -p${password} ${dbName} < /${dbName}.sql`;
|
|
106
|
+
shellExec(
|
|
107
|
+
`kubectl exec -i ${podName} -- ${serviceName} -p${password} -e 'CREATE DATABASE ${dbName};'`,
|
|
108
|
+
);
|
|
109
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "${cmd}"`);
|
|
110
|
+
}
|
|
111
|
+
if (options.export === true) {
|
|
112
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "rm -rf ${sqlContainerPath}"`);
|
|
113
|
+
const cmd = `mariadb-dump --user=${user} --password=${password} --lock-tables ${dbName} > ${sqlContainerPath}`;
|
|
114
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "${cmd}"`);
|
|
115
|
+
shellExec(
|
|
116
|
+
`sudo kubectl cp ${nameSpace}/${podName}:${sqlContainerPath} ${
|
|
117
|
+
options.outPath ? options.outPath : _toNewSqlPath
|
|
118
|
+
}`,
|
|
119
|
+
);
|
|
120
|
+
await splitFileFactory(dbName, options.outPath ? options.outPath : _toNewSqlPath);
|
|
121
|
+
}
|
|
93
122
|
}
|
|
94
123
|
break;
|
|
95
124
|
}
|
|
96
125
|
|
|
97
126
|
case 'mongoose': {
|
|
98
127
|
if (options.import === true) {
|
|
99
|
-
const
|
|
100
|
-
options.podName && typeof options.podName === 'string'
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
const podNames =
|
|
129
|
+
options.podName && typeof options.podName === 'string'
|
|
130
|
+
? options.podName.split(',')
|
|
131
|
+
: UnderpostDeploy.API.get('mongo');
|
|
132
|
+
// `mongodb-0`;
|
|
133
|
+
for (const podNameData of [podNames[0]]) {
|
|
134
|
+
const podName = podNameData.NAME;
|
|
135
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "rm -rf /${dbName}"`);
|
|
136
|
+
shellExec(
|
|
137
|
+
`sudo kubectl cp ${
|
|
138
|
+
options.outPath ? options.outPath : _toBsonPath
|
|
139
|
+
} ${nameSpace}/${podName}:/${dbName}`,
|
|
140
|
+
);
|
|
141
|
+
const cmd = `mongorestore -d ${dbName} /${dbName}${options.drop ? ' --drop' : ''}${
|
|
142
|
+
options.preserveUUID ? ' --preserveUUID' : ''
|
|
143
|
+
}`;
|
|
144
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "${cmd}"`);
|
|
145
|
+
}
|
|
104
146
|
}
|
|
105
147
|
if (options.export === true) {
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
} else {
|
|
148
|
+
const podNames =
|
|
149
|
+
options.podName && typeof options.podName === 'string'
|
|
150
|
+
? options.podName.split(',')
|
|
151
|
+
: UnderpostDeploy.API.get('mongo'); // `backup-access`;
|
|
152
|
+
for (const podNameData of [podNames[0]]) {
|
|
153
|
+
const podName = podNameData.NAME;
|
|
154
|
+
shellExec(`sudo kubectl exec -i ${podName} -- sh -c "rm -rf /${dbName}"`);
|
|
155
|
+
if (options.collections)
|
|
156
|
+
for (const collection of options.collections)
|
|
157
|
+
shellExec(
|
|
158
|
+
`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} --collection ${collection} -o /"`,
|
|
159
|
+
);
|
|
160
|
+
else shellExec(`sudo kubectl exec -i ${podName} -- sh -c "mongodump -d ${dbName} -o /"`);
|
|
120
161
|
shellExec(
|
|
121
|
-
`sudo kubectl cp ${nameSpace}/${podName}
|
|
162
|
+
`sudo kubectl cp ${nameSpace}/${podName}:/${dbName} ${
|
|
163
|
+
options.outPath ? options.outPath : _toNewBsonPath
|
|
164
|
+
}`,
|
|
122
165
|
);
|
|
123
166
|
}
|
|
167
|
+
if (false) {
|
|
168
|
+
const containerBaseBackupPath = '/backup';
|
|
169
|
+
let timeFolder = shellExec(
|
|
170
|
+
`sudo kubectl exec -i ${podName} -- sh -c "cd ${containerBaseBackupPath} && ls -a"`,
|
|
171
|
+
{
|
|
172
|
+
stdout: true,
|
|
173
|
+
disableLog: false,
|
|
174
|
+
silent: true,
|
|
175
|
+
},
|
|
176
|
+
).split(`\n`);
|
|
177
|
+
timeFolder = timeFolder[timeFolder.length - 2];
|
|
178
|
+
if (timeFolder === '..') {
|
|
179
|
+
logger.warn(`Cannot backup available`, { timeFolder });
|
|
180
|
+
} else {
|
|
181
|
+
shellExec(
|
|
182
|
+
`sudo kubectl cp ${nameSpace}/${podName}:${containerBaseBackupPath}/${timeFolder}/${dbName} ${_toNewBsonPath}`,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
124
186
|
}
|
|
125
187
|
break;
|
|
126
188
|
}
|
|
@@ -131,7 +193,7 @@ class UnderpostDB {
|
|
|
131
193
|
}
|
|
132
194
|
}
|
|
133
195
|
}
|
|
134
|
-
if (options.export === true) {
|
|
196
|
+
if (options.export === true && options.git === true) {
|
|
135
197
|
shellExec(`cd ../${repoName} && git add .`);
|
|
136
198
|
shellExec(
|
|
137
199
|
`underpost cmt ../${repoName} backup '' '${new Date(newBackupTimestamp).toLocaleDateString()} ${new Date(
|
package/src/cli/deploy.js
CHANGED
|
@@ -32,7 +32,7 @@ class UnderpostDeploy {
|
|
|
32
32
|
await Config.build(undefined, 'proxy', deployList);
|
|
33
33
|
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
34
34
|
},
|
|
35
|
-
async buildManifest(deployList, env) {
|
|
35
|
+
async buildManifest(deployList, env, version) {
|
|
36
36
|
for (const _deployId of deployList.split(',')) {
|
|
37
37
|
const deployId = _deployId.trim();
|
|
38
38
|
if (!deployId) continue;
|
|
@@ -50,7 +50,7 @@ class UnderpostDeploy {
|
|
|
50
50
|
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
51
51
|
|
|
52
52
|
logger.info('port range', { deployId, fromPort, toPort });
|
|
53
|
-
|
|
53
|
+
// const customImg = `underpost-engine:${version && typeof version === 'string' ? version : Underpost.version}`;
|
|
54
54
|
const deploymentYamlParts = `apiVersion: apps/v1
|
|
55
55
|
kind: Deployment
|
|
56
56
|
metadata:
|
|
@@ -69,7 +69,30 @@ spec:
|
|
|
69
69
|
spec:
|
|
70
70
|
containers:
|
|
71
71
|
- name: ${deployId}-${env}
|
|
72
|
-
image: localhost
|
|
72
|
+
image: localhost/debian:underpost
|
|
73
|
+
command:
|
|
74
|
+
- /bin/sh
|
|
75
|
+
- -c
|
|
76
|
+
- >
|
|
77
|
+
underpost dockerfile-node-script --build --run ${deployId} ${env}
|
|
78
|
+
lifecycle:
|
|
79
|
+
postStart:
|
|
80
|
+
exec:
|
|
81
|
+
command:
|
|
82
|
+
- /bin/sh
|
|
83
|
+
- -c
|
|
84
|
+
- >
|
|
85
|
+
sleep 20 &&
|
|
86
|
+
npm install -g underpost
|
|
87
|
+
underpost secret underpost --create-from-file /etc/config/.env.${env}
|
|
88
|
+
volumeMounts:
|
|
89
|
+
- name: config-volume
|
|
90
|
+
mountPath: /etc/config
|
|
91
|
+
volumes:
|
|
92
|
+
- name: config-volume
|
|
93
|
+
configMap:
|
|
94
|
+
name: underpost-config
|
|
95
|
+
# image: localhost/${deployId}-${env}:${version && typeof version === 'string' ? version : Underpost.version}
|
|
73
96
|
---
|
|
74
97
|
apiVersion: v1
|
|
75
98
|
kind: Service
|
|
@@ -180,7 +203,16 @@ spec:
|
|
|
180
203
|
async callback(
|
|
181
204
|
deployList = 'default',
|
|
182
205
|
env = 'development',
|
|
183
|
-
options = {
|
|
206
|
+
options = {
|
|
207
|
+
remove: false,
|
|
208
|
+
infoRouter: false,
|
|
209
|
+
sync: false,
|
|
210
|
+
buildManifest: false,
|
|
211
|
+
infoUtil: false,
|
|
212
|
+
expose: false,
|
|
213
|
+
cert: false,
|
|
214
|
+
version: '',
|
|
215
|
+
},
|
|
184
216
|
) {
|
|
185
217
|
if (options.infoUtil === true)
|
|
186
218
|
return logger.info(`
|
|
@@ -191,9 +223,13 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
191
223
|
if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
192
224
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
193
225
|
if (options.sync) UnderpostDeploy.API.sync(deployList);
|
|
194
|
-
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env);
|
|
226
|
+
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options.version);
|
|
195
227
|
if (options.infoRouter === true)
|
|
196
228
|
return logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
229
|
+
shellExec(`kubectl delete configmap underpost-config`);
|
|
230
|
+
shellExec(
|
|
231
|
+
`kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
|
|
232
|
+
);
|
|
197
233
|
const etcHost = (
|
|
198
234
|
concat,
|
|
199
235
|
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
@@ -219,7 +255,7 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
219
255
|
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
220
256
|
for (const host of Object.keys(confServer)) {
|
|
221
257
|
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
222
|
-
if (env === 'production') shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
258
|
+
if (env === 'production' && options.cert === true) shellExec(`sudo kubectl delete Certificate ${host}`);
|
|
223
259
|
if (!options.remove === true && env === 'development') concatHots += ` ${host}`;
|
|
224
260
|
}
|
|
225
261
|
|
|
@@ -231,7 +267,8 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
|
|
|
231
267
|
if (!options.remove === true) {
|
|
232
268
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
|
|
233
269
|
shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
|
|
234
|
-
if (env === 'production'
|
|
270
|
+
if (env === 'production' && options.cert === true)
|
|
271
|
+
shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
|
|
235
272
|
}
|
|
236
273
|
}
|
|
237
274
|
let renderHosts;
|
package/src/cli/env.js
CHANGED
|
@@ -28,15 +28,21 @@ class UnderpostRootEnv {
|
|
|
28
28
|
get(key) {
|
|
29
29
|
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
30
30
|
const envPath = `${exeRootPath}/.env`;
|
|
31
|
-
if (!fs.existsSync(envPath))
|
|
31
|
+
if (!fs.existsSync(envPath)) {
|
|
32
|
+
logger.error(`Unable to find underpost root environment`);
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
32
35
|
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
33
|
-
logger.info(
|
|
36
|
+
logger.info(`${key}(${typeof env[key]})`, env[key]);
|
|
34
37
|
return env[key];
|
|
35
38
|
},
|
|
36
39
|
list() {
|
|
37
40
|
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
38
41
|
const envPath = `${exeRootPath}/.env`;
|
|
39
|
-
if (!fs.existsSync(envPath))
|
|
42
|
+
if (!fs.existsSync(envPath)) {
|
|
43
|
+
logger.error(`Unable to find underpost root environment`);
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
40
46
|
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
41
47
|
logger.info('underpost root', env);
|
|
42
48
|
return env;
|
package/src/cli/fs.js
CHANGED
|
@@ -38,23 +38,36 @@ class UnderpostFileStorage {
|
|
|
38
38
|
options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
|
|
39
39
|
) {
|
|
40
40
|
const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
|
|
41
|
+
const deleteFiles = UnderpostRepository.API.getDeleteFiles(path);
|
|
42
|
+
for (const relativePath of deleteFiles) {
|
|
43
|
+
const _path = path + '/' + relativePath;
|
|
44
|
+
if (_path in storage) {
|
|
45
|
+
await UnderpostFileStorage.API.delete(_path);
|
|
46
|
+
delete storage[_path];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
41
49
|
const files =
|
|
42
50
|
options.git === true
|
|
43
51
|
? UnderpostRepository.API.getChangedFiles(path)
|
|
44
52
|
: await fs.readdir(path, { recursive: true });
|
|
45
|
-
|
|
46
|
-
const _path
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
if (options.pull === true) {
|
|
54
|
+
for (const _path of Object.keys(storage)) {
|
|
55
|
+
if (!fs.existsSync(_path) || options.force === true) {
|
|
56
|
+
if (options.force === true && fs.existsSync(_path)) fs.removeSync(_path);
|
|
57
|
+
await UnderpostFileStorage.API.pull(_path, options);
|
|
58
|
+
} else logger.warn(`Pull path already exists`, _path);
|
|
59
|
+
}
|
|
60
|
+
} else
|
|
61
|
+
for (const relativePath of files) {
|
|
62
|
+
const _path = path + '/' + relativePath;
|
|
63
|
+
if (fs.statSync(_path).isDirectory()) {
|
|
64
|
+
if (options.pull === true && !fs.existsSync(_path)) fs.mkdirSync(_path, { recursive: true });
|
|
65
|
+
continue;
|
|
66
|
+
} else if (!(_path in storage) || options.force === true) {
|
|
67
|
+
await UnderpostFileStorage.API.upload(_path, options);
|
|
68
|
+
if (storage) storage[_path] = {};
|
|
69
|
+
} else logger.warn('File already exists', _path);
|
|
50
70
|
}
|
|
51
|
-
if (options.pull === true) {
|
|
52
|
-
await UnderpostFileStorage.API.pull(_path, options);
|
|
53
|
-
} else if (!(_path in storage) || options.force === true) {
|
|
54
|
-
await UnderpostFileStorage.API.upload(_path, options);
|
|
55
|
-
if (storage) storage[_path] = {};
|
|
56
|
-
} else logger.warn('File already exists', _path);
|
|
57
|
-
}
|
|
58
71
|
UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
|
|
59
72
|
if (options.git === true) {
|
|
60
73
|
shellExec(`cd ${path} && git add .`);
|
|
@@ -91,6 +104,8 @@ class UnderpostFileStorage {
|
|
|
91
104
|
},
|
|
92
105
|
async pull(path) {
|
|
93
106
|
UnderpostFileStorage.API.cloudinaryConfig();
|
|
107
|
+
const folder = dir.dirname(path);
|
|
108
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
94
109
|
const downloadResult = await cloudinary.utils.download_archive_url({
|
|
95
110
|
public_ids: [path],
|
|
96
111
|
resource_type: 'raw',
|
package/src/cli/image.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import Underpost from '../index.js';
|
|
3
|
-
import { shellExec } from '../server/process.js';
|
|
3
|
+
import { shellCd, shellExec } from '../server/process.js';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
5
|
import { getNpmRootPath } from '../server/conf.js';
|
|
6
6
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
7
|
+
import UnderpostRootEnv from './env.js';
|
|
8
|
+
import { loggerFactory } from '../server/logger.js';
|
|
7
9
|
|
|
8
10
|
dotenv.config();
|
|
9
11
|
|
|
12
|
+
const logger = loggerFactory(import.meta);
|
|
13
|
+
|
|
10
14
|
class UnderpostImage {
|
|
11
15
|
static API = {
|
|
12
16
|
dockerfile: {
|
|
@@ -17,9 +21,13 @@ class UnderpostImage {
|
|
|
17
21
|
deployId = 'default',
|
|
18
22
|
env = 'development',
|
|
19
23
|
path = '.',
|
|
20
|
-
options = { imageArchive: false, podmanSave: false },
|
|
24
|
+
options = { imageArchive: false, podmanSave: false, imageName: '', imageVersion: '' },
|
|
21
25
|
) {
|
|
22
|
-
const imgName = `${
|
|
26
|
+
const imgName = `${
|
|
27
|
+
options.imageName && typeof options.imageName === 'string' ? options.imageName : `${deployId}-${env}`
|
|
28
|
+
}:${
|
|
29
|
+
options.imageVersion && typeof options.imageVersion === 'string' ? options.imageVersion : Underpost.version
|
|
30
|
+
}`;
|
|
23
31
|
const podManImg = `localhost/${imgName}`;
|
|
24
32
|
const imagesStoragePath = `/images`;
|
|
25
33
|
if (!fs.existsSync(`${path}${imagesStoragePath}`))
|
|
@@ -38,25 +46,29 @@ class UnderpostImage {
|
|
|
38
46
|
}
|
|
39
47
|
// --rm --no-cache
|
|
40
48
|
if (options.imageArchive !== true) {
|
|
41
|
-
fs.copyFile(`${getNpmRootPath()}/underpost/.env`, `${path}/.env.underpost`);
|
|
42
49
|
shellExec(
|
|
43
50
|
`cd ${path}${secrets}&& sudo podman build -f ./Dockerfile -t ${imgName} --pull=never --cap-add=CAP_AUDIT_WRITE${secretDockerInput}`,
|
|
44
51
|
);
|
|
45
|
-
fs.removeSync(`${path}/.env.underpost`);
|
|
46
52
|
}
|
|
47
53
|
if (options.imageArchive !== true || options.podmanSave === true)
|
|
48
54
|
shellExec(`cd ${path} && podman save -o ${tarFile} ${podManImg}`);
|
|
49
55
|
shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
|
|
50
56
|
},
|
|
51
|
-
async script(deployId = 'default', env = 'development', options = { run: false }) {
|
|
57
|
+
async script(deployId = 'default', env = 'development', options = { run: false, build: false }) {
|
|
58
|
+
if (options.build === true) {
|
|
59
|
+
const buildBasePath = `/home/dd`;
|
|
60
|
+
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
61
|
+
shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
|
|
62
|
+
shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
|
|
63
|
+
shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
|
|
64
|
+
shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
|
|
65
|
+
shellCd(`${buildBasePath}/engine`);
|
|
66
|
+
shellExec(`underpost install`);
|
|
67
|
+
const itcScripts = fs.readdir('./engine-private/itc-scripts');
|
|
68
|
+
for (const itcScript of itcScripts)
|
|
69
|
+
if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
|
|
70
|
+
}
|
|
52
71
|
switch (deployId) {
|
|
53
|
-
case 'dd-lampp':
|
|
54
|
-
{
|
|
55
|
-
const lamppPublicPath = '/xampp/htdocs/online';
|
|
56
|
-
shellExec(`sudo mkdir -p ${lamppPublicPath}`);
|
|
57
|
-
}
|
|
58
|
-
break;
|
|
59
|
-
|
|
60
72
|
default:
|
|
61
73
|
{
|
|
62
74
|
{
|
|
@@ -97,7 +109,7 @@ class UnderpostImage {
|
|
|
97
109
|
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
98
110
|
for (const replica of replicas) {
|
|
99
111
|
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
100
|
-
shellExec(`npm ${runCmd}
|
|
112
|
+
shellExec(`npm ${runCmd} deploy deploy-id:${replica}`, { async: true });
|
|
101
113
|
fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
102
114
|
const monitor = async () => {
|
|
103
115
|
await timer(1000);
|
|
@@ -107,7 +119,7 @@ class UnderpostImage {
|
|
|
107
119
|
}
|
|
108
120
|
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
109
121
|
}
|
|
110
|
-
shellExec(`npm ${runCmd}
|
|
122
|
+
shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`);
|
|
111
123
|
}
|
|
112
124
|
},
|
|
113
125
|
},
|
package/src/cli/repository.js
CHANGED
|
@@ -99,17 +99,25 @@ class UnderpostRepository {
|
|
|
99
99
|
});
|
|
100
100
|
},
|
|
101
101
|
|
|
102
|
+
getDeleteFiles(path = '.') {
|
|
103
|
+
const commandUntrack = `cd ${path} && git ls-files --deleted`;
|
|
104
|
+
const diffUntrackOutput = shellExec(commandUntrack, { stdout: true, silent: true });
|
|
105
|
+
return diffUntrackOutput.toString().split('\n').filter(Boolean);
|
|
106
|
+
},
|
|
107
|
+
|
|
102
108
|
getChangedFiles(path = '.', extension = '', head = false) {
|
|
103
109
|
const extensionFilter = extension ? `-- '***.${extension}'` : '';
|
|
104
110
|
const command = `cd ${path} && git diff ${head ? 'HEAD^ HEAD ' : ''}--name-only ${extensionFilter}`;
|
|
105
111
|
const commandUntrack = `cd ${path} && git ls-files --others --exclude-standard`;
|
|
106
112
|
const diffOutput = shellExec(command, { stdout: true, silent: true });
|
|
107
113
|
const diffUntrackOutput = shellExec(commandUntrack, { stdout: true, silent: true });
|
|
114
|
+
const deleteFiles = UnderpostRepository.API.getDeleteFiles(path);
|
|
108
115
|
return diffOutput
|
|
109
116
|
.toString()
|
|
110
117
|
.split('\n')
|
|
111
118
|
.filter(Boolean)
|
|
112
|
-
.concat(diffUntrackOutput.toString().split('\n').filter(Boolean))
|
|
119
|
+
.concat(diffUntrackOutput.toString().split('\n').filter(Boolean))
|
|
120
|
+
.filter((f) => !deleteFiles.includes(f));
|
|
113
121
|
},
|
|
114
122
|
};
|
|
115
123
|
}
|
|
@@ -404,7 +404,15 @@ const CalendarCore = {
|
|
|
404
404
|
<div class="in" style="margin-bottom: 100px"></div>`;
|
|
405
405
|
};
|
|
406
406
|
|
|
407
|
+
let delayBlock = false;
|
|
407
408
|
this.Data[options.idModal].updatePanel = async () => {
|
|
409
|
+
if (delayBlock) return;
|
|
410
|
+
else {
|
|
411
|
+
delayBlock = true;
|
|
412
|
+
setTimeout(() => {
|
|
413
|
+
delayBlock = false;
|
|
414
|
+
}, 500);
|
|
415
|
+
}
|
|
408
416
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
409
417
|
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
410
418
|
if (s(`.main-body-calendar-${options.idModal}`)) {
|
|
@@ -426,7 +434,10 @@ const CalendarCore = {
|
|
|
426
434
|
},
|
|
427
435
|
});
|
|
428
436
|
|
|
429
|
-
if (options.route === 'home')
|
|
437
|
+
// if (options.route === 'home')
|
|
438
|
+
setTimeout(() => {
|
|
439
|
+
CalendarCore.Data[options.idModal].updatePanel();
|
|
440
|
+
});
|
|
430
441
|
|
|
431
442
|
return html`
|
|
432
443
|
<style>
|