@underpostnet/underpost 2.8.4 → 2.8.5
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/ghpkg.yml +13 -46
- package/.github/workflows/npmpkg.yml +67 -0
- package/.github/workflows/publish.yml +5 -5
- package/.github/workflows/pwa-microservices-template.page.yml +3 -2
- package/.github/workflows/pwa-microservices-template.test.yml +2 -2
- package/.vscode/settings.json +6 -1
- package/CHANGELOG.md +16 -0
- package/Dockerfile +6 -27
- package/bin/build.js +52 -169
- package/bin/deploy.js +6 -27
- package/bin/file.js +29 -15
- package/bin/index.js +158 -30
- package/bin/util.js +0 -8
- package/docker-compose.yml +1 -1
- package/manifests/mongodb/backup-access.yaml +16 -0
- package/manifests/mongodb/backup-cronjob.yaml +42 -0
- package/manifests/mongodb/backup-pv-pvc.yaml +22 -0
- package/manifests/mongodb/configmap.yaml +26 -0
- package/manifests/mongodb/headless-service.yaml +10 -0
- package/manifests/mongodb/kustomization.yaml +11 -0
- package/manifests/mongodb/pv-pvc.yaml +23 -0
- package/manifests/mongodb/statefulset.yaml +125 -0
- package/manifests/valkey/kustomization.yaml +2 -2
- package/manifests/valkey/service.yaml +17 -0
- package/manifests/valkey/statefulset.yaml +39 -0
- package/package.json +21 -5
- package/src/api/core/core.service.js +1 -1
- package/src/cli/cluster.js +154 -0
- package/src/cli/cron.js +90 -0
- package/src/cli/db.js +148 -0
- package/src/cli/deploy.js +277 -0
- package/src/cli/env.js +52 -0
- package/src/cli/image.js +125 -0
- package/src/cli/repository.js +104 -0
- package/src/cli/script.js +29 -0
- package/src/cli/secrets.js +37 -0
- package/src/cli/test.js +83 -0
- package/src/client/components/core/Auth.js +22 -4
- package/src/client/components/core/CommonJs.js +82 -1
- package/src/client/components/core/Css.js +1 -0
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Modal.js +0 -1
- package/src/client/components/core/Scroll.js +1 -0
- package/src/client/components/core/Translate.js +4 -0
- package/src/client/components/core/VanillaJs.js +0 -9
- package/src/client/components/core/Worker.js +34 -31
- package/src/client/ssr/body/CacheControl.js +2 -2
- package/src/index.js +77 -26
- package/src/server/backup.js +49 -93
- package/src/server/client-build.js +1 -10
- package/src/server/client-formatted.js +5 -3
- package/src/server/conf.js +68 -187
- package/src/server/dns.js +48 -65
- package/src/server/logger.js +7 -7
- package/src/server/network.js +17 -7
- package/src/server/runtime.js +8 -22
- package/src/dns.js +0 -22
- package/src/server/project.js +0 -39
- package/startup.cjs +0 -12
- /package/manifests/deployment/{mongo-express.yaml → mongo-express/deployment.yaml} +0 -0
- /package/manifests/deployment/{phpmyadmin.yaml → phpmyadmin/deployment.yaml} +0 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildKindPorts,
|
|
3
|
+
buildPortProxyRouter,
|
|
4
|
+
buildProxyRouter,
|
|
5
|
+
Config,
|
|
6
|
+
getDataDeploy,
|
|
7
|
+
loadReplicas,
|
|
8
|
+
} from '../server/conf.js';
|
|
9
|
+
import { loggerFactory } from '../server/logger.js';
|
|
10
|
+
import { shellExec } from '../server/process.js';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import dotenv from 'dotenv';
|
|
13
|
+
import Underpost from '../index.js';
|
|
14
|
+
|
|
15
|
+
const logger = loggerFactory(import.meta);
|
|
16
|
+
|
|
17
|
+
class UnderpostDeploy {
|
|
18
|
+
static API = {
|
|
19
|
+
sync(deployList) {
|
|
20
|
+
const deployGroupId = 'dd.tmp';
|
|
21
|
+
fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
|
|
22
|
+
return getDataDeploy({
|
|
23
|
+
buildSingleReplica: true,
|
|
24
|
+
deployGroupId,
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
async routerFactory(deployList, env) {
|
|
28
|
+
const initEnvPath = `./engine-private/conf/${deployList.split(',')[0]}/.env.${env}`;
|
|
29
|
+
const initEnvObj = dotenv.parse(fs.readFileSync(initEnvPath, 'utf8'));
|
|
30
|
+
process.env.PORT = initEnvObj.PORT;
|
|
31
|
+
process.env.NODE_ENV = env;
|
|
32
|
+
await Config.build(undefined, 'proxy', deployList);
|
|
33
|
+
return buildPortProxyRouter(env === 'development' ? 80 : 443, buildProxyRouter());
|
|
34
|
+
},
|
|
35
|
+
async buildManifest(deployList, env) {
|
|
36
|
+
for (const _deployId of deployList.split(',')) {
|
|
37
|
+
const deployId = _deployId.trim();
|
|
38
|
+
if (!deployId) continue;
|
|
39
|
+
|
|
40
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
41
|
+
const ports = Object.values(router).map((p) => parseInt(p.split(':')[2]));
|
|
42
|
+
const fromPort = Math.min(...ports);
|
|
43
|
+
const toPort = Math.max(...ports);
|
|
44
|
+
const confServer = loadReplicas(
|
|
45
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
46
|
+
'proxy',
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
50
|
+
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
51
|
+
|
|
52
|
+
logger.info('port range', { deployId, fromPort, toPort });
|
|
53
|
+
|
|
54
|
+
const deploymentYamlParts = `apiVersion: apps/v1
|
|
55
|
+
kind: Deployment
|
|
56
|
+
metadata:
|
|
57
|
+
name: ${deployId}-${env}
|
|
58
|
+
labels:
|
|
59
|
+
app: ${deployId}-${env}
|
|
60
|
+
spec:
|
|
61
|
+
replicas: 2
|
|
62
|
+
selector:
|
|
63
|
+
matchLabels:
|
|
64
|
+
app: ${deployId}-${env}
|
|
65
|
+
template:
|
|
66
|
+
metadata:
|
|
67
|
+
labels:
|
|
68
|
+
app: ${deployId}-${env}
|
|
69
|
+
spec:
|
|
70
|
+
containers:
|
|
71
|
+
- name: ${deployId}-${env}
|
|
72
|
+
image: localhost/${deployId}-${env}:${Underpost.version}
|
|
73
|
+
---
|
|
74
|
+
apiVersion: v1
|
|
75
|
+
kind: Service
|
|
76
|
+
metadata:
|
|
77
|
+
name: ${deployId}-${env}-service
|
|
78
|
+
spec:
|
|
79
|
+
selector:
|
|
80
|
+
app: ${deployId}-${env}
|
|
81
|
+
ports:
|
|
82
|
+
type: LoadBalancer`.split('ports:');
|
|
83
|
+
deploymentYamlParts[1] =
|
|
84
|
+
buildKindPorts(fromPort, toPort) +
|
|
85
|
+
` type: LoadBalancer
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
fs.writeFileSync(
|
|
89
|
+
`./engine-private/conf/${deployId}/build/${env}/deployment.yaml`,
|
|
90
|
+
deploymentYamlParts.join(`ports:
|
|
91
|
+
`),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
let proxyYaml = '';
|
|
95
|
+
let secretYaml = '';
|
|
96
|
+
|
|
97
|
+
for (const host of Object.keys(confServer)) {
|
|
98
|
+
if (env === 'production')
|
|
99
|
+
secretYaml += `
|
|
100
|
+
---
|
|
101
|
+
apiVersion: cert-manager.io/v1
|
|
102
|
+
kind: Certificate
|
|
103
|
+
metadata:
|
|
104
|
+
name: ${host}
|
|
105
|
+
spec:
|
|
106
|
+
commonName: ${host}
|
|
107
|
+
dnsNames:
|
|
108
|
+
- ${host}
|
|
109
|
+
issuerRef:
|
|
110
|
+
name: letsencrypt-prod
|
|
111
|
+
kind: ClusterIssuer
|
|
112
|
+
secretName: ${host}`;
|
|
113
|
+
|
|
114
|
+
const pathPortConditions = [];
|
|
115
|
+
for (const path of Object.keys(confServer[host])) {
|
|
116
|
+
const { peer } = confServer[host][path];
|
|
117
|
+
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
118
|
+
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
119
|
+
// logger.info('', { host, port, path });
|
|
120
|
+
pathPortConditions.push({
|
|
121
|
+
port,
|
|
122
|
+
path,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (peer) {
|
|
126
|
+
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
127
|
+
pathPortConditions.push({
|
|
128
|
+
port: port + 1,
|
|
129
|
+
path: '/peer',
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// logger.info('', { host, pathPortConditions });
|
|
135
|
+
proxyYaml += `
|
|
136
|
+
---
|
|
137
|
+
apiVersion: projectcontour.io/v1
|
|
138
|
+
kind: HTTPProxy
|
|
139
|
+
metadata:
|
|
140
|
+
name: ${host}
|
|
141
|
+
spec:
|
|
142
|
+
virtualhost:
|
|
143
|
+
fqdn: ${host}${
|
|
144
|
+
env === 'development'
|
|
145
|
+
? ''
|
|
146
|
+
: `
|
|
147
|
+
tls:
|
|
148
|
+
secretName: ${host}`
|
|
149
|
+
}
|
|
150
|
+
routes:`;
|
|
151
|
+
for (const conditionObj of pathPortConditions) {
|
|
152
|
+
const { path, port } = conditionObj;
|
|
153
|
+
proxyYaml += `
|
|
154
|
+
- conditions:
|
|
155
|
+
- prefix: ${path}
|
|
156
|
+
enableWebsockets: true
|
|
157
|
+
services:
|
|
158
|
+
- name: ${deployId}-${env}-service
|
|
159
|
+
port: ${port}`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/proxy.yaml`;
|
|
163
|
+
fs.writeFileSync(yamlPath, proxyYaml, 'utf8');
|
|
164
|
+
if (env === 'production') {
|
|
165
|
+
const yamlPath = `./engine-private/conf/${deployId}/build/${env}/secret.yaml`;
|
|
166
|
+
fs.writeFileSync(yamlPath, secretYaml, 'utf8');
|
|
167
|
+
} else {
|
|
168
|
+
const deploymentsFiles = ['Dockerfile', 'proxy.yaml', 'deployment.yaml'];
|
|
169
|
+
for (const file of deploymentsFiles) {
|
|
170
|
+
if (fs.existsSync(`./engine-private/conf/${deployId}/build/${env}/${file}`)) {
|
|
171
|
+
fs.copyFileSync(
|
|
172
|
+
`./engine-private/conf/${deployId}/build/${env}/${file}`,
|
|
173
|
+
`./manifests/deployment/${deployId}-${env}/${file}`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
async callback(
|
|
181
|
+
deployList = 'default',
|
|
182
|
+
env = 'development',
|
|
183
|
+
options = { remove: false, infoRouter: false, sync: false, buildManifest: false },
|
|
184
|
+
) {
|
|
185
|
+
if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
186
|
+
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
187
|
+
if (options.sync) UnderpostDeploy.API.sync(deployList);
|
|
188
|
+
if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env);
|
|
189
|
+
if (options.infoRouter === true)
|
|
190
|
+
return logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
|
|
191
|
+
|
|
192
|
+
for (const _deployId of deployList.split(',')) {
|
|
193
|
+
const deployId = _deployId.trim();
|
|
194
|
+
if (!deployId) continue;
|
|
195
|
+
|
|
196
|
+
shellExec(`sudo kubectl delete svc ${deployId}-${env}-service`);
|
|
197
|
+
shellExec(`sudo kubectl delete deployment ${deployId}-${env}`);
|
|
198
|
+
|
|
199
|
+
const etcHost = (
|
|
200
|
+
concat,
|
|
201
|
+
) => `127.0.0.1 ${concat} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
202
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
203
|
+
let concatHots = '';
|
|
204
|
+
|
|
205
|
+
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
206
|
+
for (const host of Object.keys(confServer)) {
|
|
207
|
+
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
208
|
+
if (!options.remove === true && env === 'development') concatHots += ` ${host}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!options.remove === true) {
|
|
212
|
+
shellExec(`sudo kubectl apply -f ./manifests/deployment/${deployId}-${env}/deployment.yaml`);
|
|
213
|
+
shellExec(`sudo kubectl apply -f ./manifests/deployment/${deployId}-${env}/proxy.yaml`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let renderHosts;
|
|
217
|
+
|
|
218
|
+
switch (process.platform) {
|
|
219
|
+
case 'linux':
|
|
220
|
+
{
|
|
221
|
+
switch (env) {
|
|
222
|
+
case 'development':
|
|
223
|
+
renderHosts = etcHost(concatHots);
|
|
224
|
+
fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
225
|
+
|
|
226
|
+
break;
|
|
227
|
+
|
|
228
|
+
default:
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
|
|
234
|
+
default:
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
logger.info(
|
|
238
|
+
`
|
|
239
|
+
` + renderHosts,
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
getPods(deployId) {
|
|
244
|
+
const raw = shellExec(`sudo kubectl get pods --all-namespaces -o wide`, {
|
|
245
|
+
stdout: true,
|
|
246
|
+
disableLog: false,
|
|
247
|
+
silent: true,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const heads = raw
|
|
251
|
+
.split(`\n`)[0]
|
|
252
|
+
.split(' ')
|
|
253
|
+
.filter((_r) => _r.trim());
|
|
254
|
+
|
|
255
|
+
const pods = raw
|
|
256
|
+
.split(`\n`)
|
|
257
|
+
.filter((r) => (deployId ? r.match(deployId) : r.trim() && !r.match('NAME')))
|
|
258
|
+
.map((r) => r.split(' ').filter((_r) => _r.trim()));
|
|
259
|
+
|
|
260
|
+
const result = [];
|
|
261
|
+
|
|
262
|
+
for (const row of pods) {
|
|
263
|
+
const pod = {};
|
|
264
|
+
let index = -1;
|
|
265
|
+
for (const head of heads) {
|
|
266
|
+
index++;
|
|
267
|
+
pod[head] = row[index];
|
|
268
|
+
}
|
|
269
|
+
result.push(pod);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return result;
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export default UnderpostDeploy;
|
package/src/cli/env.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getNpmRootPath, writeEnv } from '../server/conf.js';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import { loggerFactory } from '../server/logger.js';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
|
|
6
|
+
dotenv.config();
|
|
7
|
+
|
|
8
|
+
const logger = loggerFactory(import.meta);
|
|
9
|
+
|
|
10
|
+
class UnderpostRootEnv {
|
|
11
|
+
static API = {
|
|
12
|
+
set(key, value) {
|
|
13
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
14
|
+
const envPath = `${exeRootPath}/.env`;
|
|
15
|
+
let env = {};
|
|
16
|
+
if (fs.existsSync(envPath)) env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
17
|
+
env[key] = value;
|
|
18
|
+
writeEnv(envPath, env);
|
|
19
|
+
},
|
|
20
|
+
delete(key) {
|
|
21
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
22
|
+
const envPath = `${exeRootPath}/.env`;
|
|
23
|
+
let env = {};
|
|
24
|
+
if (fs.existsSync(envPath)) env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
25
|
+
delete env[key];
|
|
26
|
+
writeEnv(envPath, env);
|
|
27
|
+
},
|
|
28
|
+
get(key) {
|
|
29
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
30
|
+
const envPath = `${exeRootPath}/.env`;
|
|
31
|
+
if (!fs.existsSync(envPath)) return logger.error(`Unable to find underpost root environment`);
|
|
32
|
+
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
33
|
+
logger.info('underpost root', { [key]: env[key] });
|
|
34
|
+
return env[key];
|
|
35
|
+
},
|
|
36
|
+
list() {
|
|
37
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
38
|
+
const envPath = `${exeRootPath}/.env`;
|
|
39
|
+
if (!fs.existsSync(envPath)) return logger.error(`Unable to find underpost root environment`);
|
|
40
|
+
const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
41
|
+
logger.info('underpost root', env);
|
|
42
|
+
return env;
|
|
43
|
+
},
|
|
44
|
+
clean() {
|
|
45
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
46
|
+
const envPath = `${exeRootPath}/.env`;
|
|
47
|
+
fs.removeSync(envPath);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default UnderpostRootEnv;
|
package/src/cli/image.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import Underpost from '../index.js';
|
|
3
|
+
import { shellExec } from '../server/process.js';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
6
|
+
import { timer } from '../client/components/core/CommonJs.js';
|
|
7
|
+
|
|
8
|
+
dotenv.config();
|
|
9
|
+
|
|
10
|
+
class UnderpostImage {
|
|
11
|
+
static API = {
|
|
12
|
+
dockerfile: {
|
|
13
|
+
pullBaseImages() {
|
|
14
|
+
shellExec(`sudo podman pull docker.io/library/debian:buster`);
|
|
15
|
+
},
|
|
16
|
+
build(deployId = 'default', env = 'development', path = '.', options = { imageArchive: false }) {
|
|
17
|
+
const imgName = `${deployId}-${env}:${Underpost.version}`;
|
|
18
|
+
const podManImg = `localhost/${imgName}`;
|
|
19
|
+
const imagesStoragePath = `./images`;
|
|
20
|
+
const tarFile = `${imagesStoragePath}/${imgName.replace(':', '_')}.tar`;
|
|
21
|
+
|
|
22
|
+
let secrets = ' ';
|
|
23
|
+
let secretDockerInput = '';
|
|
24
|
+
|
|
25
|
+
const envObj = dotenv.parse(fs.readFileSync(`${getNpmRootPath()}/underpost/.env`, 'utf8'));
|
|
26
|
+
|
|
27
|
+
for (const key of Object.keys(envObj)) {
|
|
28
|
+
continue;
|
|
29
|
+
secrets += ` && export ${key}="${envObj[key]}" `; // $(cat gitlab-token.txt)
|
|
30
|
+
secretDockerInput += ` --secret id=${key},env=${key} \ `;
|
|
31
|
+
}
|
|
32
|
+
// --rm --no-cache
|
|
33
|
+
if (options.imageArchive !== true) {
|
|
34
|
+
fs.copyFile(`${getNpmRootPath()}/underpost/.env`, `${path}/.env.underpost`);
|
|
35
|
+
shellExec(
|
|
36
|
+
`cd ${path}${secrets}&& sudo podman build -f ./Dockerfile -t ${imgName} --pull=never --cap-add=CAP_AUDIT_WRITE${secretDockerInput}`,
|
|
37
|
+
);
|
|
38
|
+
fs.removeSync(`${path}/.env.underpost`);
|
|
39
|
+
shellExec(`cd ${path} && podman save -o ${tarFile} ${podManImg}`);
|
|
40
|
+
}
|
|
41
|
+
shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
|
|
42
|
+
},
|
|
43
|
+
async script(deployId = 'default', env = 'development', options = { run: false }) {
|
|
44
|
+
switch (deployId) {
|
|
45
|
+
case 'dd-lampp':
|
|
46
|
+
{
|
|
47
|
+
const lamppPublicPath = '/xampp/htdocs/online';
|
|
48
|
+
shellExec(`sudo mkdir -p ${lamppPublicPath}`);
|
|
49
|
+
|
|
50
|
+
{
|
|
51
|
+
shellExec(
|
|
52
|
+
`cd ${lamppPublicPath} && git clone https://${process.env.GITHUB_TOKEN}@github.com/${process.env.DD_LAMPP_REPO_0}`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
shellExec(`cd ${lamppPublicPath} && sudo ${process.env.DD_LAMPP_SCRIPT_0}`);
|
|
56
|
+
|
|
57
|
+
shellExec(
|
|
58
|
+
`sudo sed -i -e "s@define( 'DB_HOST', 'localhost' );@define( 'DB_HOST', '${process.env.MARIADB_HOST}' );@g" ${lamppPublicPath}/${process.env.DD_LAMPP_REPO_0_FOLDER}/wp-config.php`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
{
|
|
62
|
+
shellExec(
|
|
63
|
+
`cd ${lamppPublicPath} && git clone https://${process.env.GITHUB_TOKEN}@github.com/${process.env.DD_LAMPP_REPO_1}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
{
|
|
71
|
+
{
|
|
72
|
+
const originPath = `./src/db/mongo/MongooseDB.js`;
|
|
73
|
+
fs.writeFileSync(
|
|
74
|
+
originPath,
|
|
75
|
+
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
76
|
+
`connect: async (host, name) => {`,
|
|
77
|
+
`connect: async (host, name) => {
|
|
78
|
+
host = 'mongodb://mongodb-0.mongodb-service:27017';
|
|
79
|
+
`,
|
|
80
|
+
),
|
|
81
|
+
'utf8',
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
{
|
|
86
|
+
const originPath = `./src/server/valkey.js`;
|
|
87
|
+
fs.writeFileSync(
|
|
88
|
+
originPath,
|
|
89
|
+
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
90
|
+
` // port: 6379,
|
|
91
|
+
// host: 'service-valkey.default.svc.cluster.local',`,
|
|
92
|
+
` port: 6379,
|
|
93
|
+
host: 'service-valkey.default.svc.cluster.local',`,
|
|
94
|
+
),
|
|
95
|
+
'utf8',
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
102
|
+
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
103
|
+
if (options.run === true) {
|
|
104
|
+
const runCmd = env === 'production' ? 'prod-img' : 'dev-img';
|
|
105
|
+
if (fs.existsSync(`./engine-private/replica`)) {
|
|
106
|
+
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
107
|
+
for (const replica of replicas) {
|
|
108
|
+
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
109
|
+
shellExec(`npm run ${runCmd} ${replica} deploy`, { async: true });
|
|
110
|
+
fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
111
|
+
const monitor = async () => {
|
|
112
|
+
await timer(1000);
|
|
113
|
+
if (fs.existsSync(`./tmp/await-deploy`)) return await monitor();
|
|
114
|
+
};
|
|
115
|
+
await monitor();
|
|
116
|
+
}
|
|
117
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
118
|
+
}
|
|
119
|
+
shellExec(`npm run ${runCmd} ${deployId} deploy`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export default UnderpostImage;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { commitData } from '../client/components/core/CommonJs.js';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import { pbcopy, shellExec } from '../server/process.js';
|
|
4
|
+
import { actionInitLog, loggerFactory } from '../server/logger.js';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
7
|
+
import { listenPortController, listenServerFactory } from '../server/network.js';
|
|
8
|
+
|
|
9
|
+
dotenv.config();
|
|
10
|
+
|
|
11
|
+
const logger = loggerFactory(import.meta);
|
|
12
|
+
|
|
13
|
+
class UnderpostRepository {
|
|
14
|
+
static API = {
|
|
15
|
+
clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false }) {
|
|
16
|
+
const repoName = gitUri.split('/').pop();
|
|
17
|
+
if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
|
|
18
|
+
shellExec(
|
|
19
|
+
`git clone ${options?.bare === true ? ` --bare ` : ''}https://${
|
|
20
|
+
process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
|
|
21
|
+
}github.com/${gitUri}.git`,
|
|
22
|
+
{
|
|
23
|
+
disableLog: true,
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') {
|
|
28
|
+
shellExec(
|
|
29
|
+
`cd ${repoPath} && git pull https://${
|
|
30
|
+
process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
|
|
31
|
+
}github.com/${gitUri}.git`,
|
|
32
|
+
{
|
|
33
|
+
disableLog: true,
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
commit(
|
|
38
|
+
repoPath = './',
|
|
39
|
+
commitType = 'feat',
|
|
40
|
+
subModule = '',
|
|
41
|
+
message = '',
|
|
42
|
+
options = {
|
|
43
|
+
copy: false,
|
|
44
|
+
info: false,
|
|
45
|
+
empty: false,
|
|
46
|
+
},
|
|
47
|
+
) {
|
|
48
|
+
if (commitType === 'reset') {
|
|
49
|
+
shellExec(`cd ${repoPath} && git reset --soft HEAD~${isNaN(parseInt(subModule)) ? 1 : parseInt(subModule)}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (options.info) return logger.info('', commitData);
|
|
53
|
+
const _message = `${commitType}${subModule ? `(${subModule})` : ''}${process.argv.includes('!') ? '!' : ''}: ${
|
|
54
|
+
commitData[commitType].emoji
|
|
55
|
+
} ${message ? message : commitData[commitType].description}`;
|
|
56
|
+
if (options.copy) return pbcopy(_message);
|
|
57
|
+
shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false }) {
|
|
61
|
+
shellExec(
|
|
62
|
+
`cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git${
|
|
63
|
+
options?.f === true ? ' --force' : ''
|
|
64
|
+
}`,
|
|
65
|
+
{
|
|
66
|
+
disableLog: true,
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
logger.info(
|
|
70
|
+
'commit url',
|
|
71
|
+
`http://github.com/${gitUri}/commit/${shellExec(`cd ${repoPath} && git rev-parse --verify HEAD`, {
|
|
72
|
+
stdout: true,
|
|
73
|
+
}).trim()}`,
|
|
74
|
+
);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
new(repositoryName) {
|
|
78
|
+
return new Promise(async (resolve, reject) => {
|
|
79
|
+
try {
|
|
80
|
+
await logger.setUpInfo();
|
|
81
|
+
if (repositoryName === 'service') return resolve(await listenPortController(listenServerFactory(), ':'));
|
|
82
|
+
else actionInitLog();
|
|
83
|
+
const exeRootPath = `${getNpmRootPath()}/underpost`;
|
|
84
|
+
const destFolder = `./${repositoryName}`;
|
|
85
|
+
logger.info('Note: This process may take several minutes to complete');
|
|
86
|
+
logger.info('build app', { destFolder });
|
|
87
|
+
if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
|
|
88
|
+
fs.mkdirSync(destFolder, { recursive: true });
|
|
89
|
+
fs.copySync(exeRootPath, destFolder);
|
|
90
|
+
fs.writeFileSync(`${destFolder}/.gitignore`, fs.readFileSync(`${exeRootPath}/.dockerignore`, 'utf8'), 'utf8');
|
|
91
|
+
shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
|
|
92
|
+
shellExec(`cd ${destFolder} && npm run build`);
|
|
93
|
+
shellExec(`cd ${destFolder} && npm run dev`);
|
|
94
|
+
return resolve();
|
|
95
|
+
} catch (error) {
|
|
96
|
+
logger.error(error, error.stack);
|
|
97
|
+
return reject(error.message);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export default UnderpostRepository;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getNpmRootPath } from '../server/conf.js';
|
|
2
|
+
import { loggerFactory } from '../server/logger.js';
|
|
3
|
+
import { shellExec } from '../server/process.js';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
|
|
6
|
+
const logger = loggerFactory(import.meta);
|
|
7
|
+
|
|
8
|
+
class UnderpostScript {
|
|
9
|
+
static API = {
|
|
10
|
+
set(key, value) {
|
|
11
|
+
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
12
|
+
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
13
|
+
packageJson.scripts[key] = value;
|
|
14
|
+
fs.writeFileSync(`${npmRoot}/package.json`, JSON.stringify(packageJson, null, 4));
|
|
15
|
+
},
|
|
16
|
+
run(key) {
|
|
17
|
+
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
18
|
+
shellExec(`cd ${npmRoot} && npm run ${key}`);
|
|
19
|
+
},
|
|
20
|
+
get(key) {
|
|
21
|
+
const npmRoot = `${getNpmRootPath()}/underpost`;
|
|
22
|
+
const packageJson = JSON.parse(fs.readFileSync(`${npmRoot}/package.json`, 'utf8'));
|
|
23
|
+
logger.info('[get] ' + key, packageJson.scripts[key]);
|
|
24
|
+
return packageJson.scripts[key];
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default UnderpostScript;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import { shellExec } from '../server/process.js';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import UnderpostRootEnv from './env.js';
|
|
5
|
+
|
|
6
|
+
class UnderpostSecret {
|
|
7
|
+
static API = {
|
|
8
|
+
docker: {
|
|
9
|
+
init() {
|
|
10
|
+
shellExec(`docker swarm init`);
|
|
11
|
+
},
|
|
12
|
+
createFromEnvFile(envPath) {
|
|
13
|
+
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
14
|
+
for (const key of Object.keys(envObj)) {
|
|
15
|
+
UnderpostSecret.API.docker.set(key, envObj[key]);
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
set(key, value) {
|
|
19
|
+
shellExec(`docker secret rm ${key}`);
|
|
20
|
+
shellExec(`echo "${value}" | docker secret create ${key} -`);
|
|
21
|
+
},
|
|
22
|
+
list() {
|
|
23
|
+
shellExec(`docker secret ls`);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
underpost: {
|
|
27
|
+
createFromEnvFile(envPath) {
|
|
28
|
+
const envObj = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
|
|
29
|
+
for (const key of Object.keys(envObj)) {
|
|
30
|
+
UnderpostRootEnv.API.set(key, envObj[key]);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default UnderpostSecret;
|