underpost 2.8.622 → 2.8.637
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/Dockerfile +9 -10
- package/bin/build.js +1 -1
- package/bin/index.js +19 -7
- package/docker-compose.yml +1 -1
- package/package.json +1 -1
- package/src/cli/deploy.js +8 -27
- package/src/cli/fs.js +7 -6
- package/src/cli/image.js +75 -69
- package/src/cli/monitor.js +92 -0
- package/src/client/components/core/Account.js +3 -3
- package/src/client/components/core/Blockchain.js +1 -1
- package/src/client/components/core/CalendarCore.js +4 -2
- package/src/client/components/core/CssCore.js +8 -2
- package/src/client/components/core/Docs.js +1 -1
- package/src/client/components/core/LoadingAnimation.js +1 -17
- package/src/client/components/core/LogIn.js +3 -3
- package/src/client/components/core/LogOut.js +1 -1
- package/src/client/components/core/Panel.js +5 -5
- package/src/client/components/core/PanelForm.js +3 -1
- package/src/client/components/core/Recover.js +3 -3
- package/src/client/components/core/SignUp.js +2 -2
- package/src/client/ssr/Render.js +2 -0
- package/src/index.js +9 -1
- package/src/runtime/lampp/Dockerfile +65 -0
- package/src/server/conf.js +45 -1
package/Dockerfile
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
ARG BASE_DEBIAN=buster
|
|
2
2
|
|
|
3
|
+
# USER root
|
|
4
|
+
|
|
3
5
|
FROM debian:${BASE_DEBIAN}
|
|
4
6
|
|
|
5
7
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
6
8
|
|
|
7
|
-
WORKDIR /home/dd
|
|
8
|
-
|
|
9
9
|
# Set root password to root, format is 'user:password'.
|
|
10
10
|
RUN echo 'root:root' | chpasswd
|
|
11
11
|
|
|
@@ -25,9 +25,6 @@ RUN mkdir -p /var/run/sshd
|
|
|
25
25
|
# Allow root login via password
|
|
26
26
|
RUN sed -ri 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
|
|
27
27
|
|
|
28
|
-
# copy supervisor config file to start openssh-server
|
|
29
|
-
COPY supervisord-openssh-server.conf /etc/supervisor/conf.d/supervisord-openssh-server.conf
|
|
30
|
-
|
|
31
28
|
# install open ssl git and others tools
|
|
32
29
|
RUN apt-get install -yq --no-install-recommends libssl-dev curl wget git gnupg
|
|
33
30
|
|
|
@@ -37,12 +34,14 @@ RUN apt-get install -y nodejs build-essential
|
|
|
37
34
|
RUN node --version
|
|
38
35
|
RUN npm --version
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
VOLUME [ "/home/dd/engine/logs" ]
|
|
37
|
+
WORKDIR /home/dd
|
|
43
38
|
|
|
44
39
|
EXPOSE 22
|
|
45
40
|
|
|
46
|
-
EXPOSE
|
|
41
|
+
EXPOSE 80
|
|
42
|
+
|
|
43
|
+
EXPOSE 443
|
|
44
|
+
|
|
45
|
+
EXPOSE 3000-3100
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
EXPOSE 4000-4100
|
package/bin/build.js
CHANGED
|
@@ -176,7 +176,7 @@ const { DefaultConf } = await import(`../conf.${confName}.js`);
|
|
|
176
176
|
if (!fs.existsSync(`${basePath}/images`)) fs.mkdirSync(`${basePath}/images`);
|
|
177
177
|
|
|
178
178
|
const env = process.argv.includes('development') ? 'development' : 'production';
|
|
179
|
-
const deploymentsFiles = ['
|
|
179
|
+
const deploymentsFiles = ['proxy.yaml', 'deployment.yaml', 'secret.yaml'];
|
|
180
180
|
// remove engine-private of .dockerignore for local testing
|
|
181
181
|
for (const file of deploymentsFiles) {
|
|
182
182
|
if (fs.existsSync(`./manifests/deployment/${confName}-${env}/${file}`)) {
|
package/bin/index.js
CHANGED
|
@@ -135,13 +135,15 @@ program
|
|
|
135
135
|
|
|
136
136
|
program
|
|
137
137
|
.command('dockerfile-image-build')
|
|
138
|
-
.
|
|
139
|
-
.
|
|
140
|
-
.
|
|
141
|
-
.option('--
|
|
142
|
-
.option('--podman-save', '
|
|
143
|
-
.option('--
|
|
144
|
-
.option('--
|
|
138
|
+
.option('--path [path]', 'Dockerfile path')
|
|
139
|
+
.option('--image-name [image-name]', 'Set image name')
|
|
140
|
+
.option('--image-path [image-path]', 'Set tar image path')
|
|
141
|
+
.option('--dockerfile-name [dockerfile-name]', 'set Dockerfile name')
|
|
142
|
+
.option('--podman-save', 'Export tar file from podman')
|
|
143
|
+
.option('--kind-load', 'Import tar image to Kind cluster')
|
|
144
|
+
.option('--secrets', 'Dockerfile env secrets')
|
|
145
|
+
.option('--secrets-path [secrets-path]', 'Dockerfile custom path env secrets')
|
|
146
|
+
.option('--no-cache', 'Build without using cache')
|
|
145
147
|
.description('Build image from Dockerfile')
|
|
146
148
|
.action(Underpost.image.dockerfile.build);
|
|
147
149
|
|
|
@@ -220,4 +222,14 @@ program
|
|
|
220
222
|
.option('--kind-type <kind-type>')
|
|
221
223
|
.action(Underpost.test.callback);
|
|
222
224
|
|
|
225
|
+
program
|
|
226
|
+
.command('monitor')
|
|
227
|
+
.argument('<deploy-id>', 'Deploy configuration id')
|
|
228
|
+
.argument('[env]', 'Optional environment, for default is development')
|
|
229
|
+
.option('--ms-interval <ms-interval>', 'Custom ms interval delta time')
|
|
230
|
+
.option('--now', 'Exec immediately monitor script')
|
|
231
|
+
.option('--single', 'Disable recurrence')
|
|
232
|
+
.description('Monitor health server management')
|
|
233
|
+
.action(Underpost.monitor.callback);
|
|
234
|
+
|
|
223
235
|
program.parse();
|
package/docker-compose.yml
CHANGED
package/package.json
CHANGED
package/src/cli/deploy.js
CHANGED
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
buildPortProxyRouter,
|
|
4
4
|
buildProxyRouter,
|
|
5
5
|
Config,
|
|
6
|
+
deployRangePortFactory,
|
|
6
7
|
getDataDeploy,
|
|
7
8
|
loadReplicas,
|
|
9
|
+
pathPortAssignmentFactory,
|
|
8
10
|
} from '../server/conf.js';
|
|
9
11
|
import { loggerFactory } from '../server/logger.js';
|
|
10
12
|
import { shellExec } from '../server/process.js';
|
|
@@ -36,15 +38,13 @@ class UnderpostDeploy {
|
|
|
36
38
|
for (const _deployId of deployList.split(',')) {
|
|
37
39
|
const deployId = _deployId.trim();
|
|
38
40
|
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
41
|
const confServer = loadReplicas(
|
|
45
42
|
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
46
43
|
'proxy',
|
|
47
44
|
);
|
|
45
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
46
|
+
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
47
|
+
const { fromPort, toPort } = deployRangePortFactory(router);
|
|
48
48
|
|
|
49
49
|
fs.mkdirSync(`./engine-private/conf/${deployId}/build/${env}`, { recursive: true });
|
|
50
50
|
if (env === 'development') fs.mkdirSync(`./manifests/deployment/${deployId}-${env}`, { recursive: true });
|
|
@@ -141,27 +141,8 @@ spec:
|
|
|
141
141
|
kind: ClusterIssuer
|
|
142
142
|
secretName: ${host}`;
|
|
143
143
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
const { peer } = confServer[host][path];
|
|
147
|
-
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
148
|
-
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
149
|
-
// logger.info('', { host, port, path });
|
|
150
|
-
pathPortConditions.push({
|
|
151
|
-
port,
|
|
152
|
-
path,
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
if (peer) {
|
|
156
|
-
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
157
|
-
pathPortConditions.push({
|
|
158
|
-
port: port + 1,
|
|
159
|
-
path: '/peer',
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// logger.info('', { host, pathPortConditions });
|
|
144
|
+
const pathPortAssignment = pathPortAssignmentData[host];
|
|
145
|
+
// logger.info('', { host, pathPortAssignment });
|
|
165
146
|
proxyYaml += `
|
|
166
147
|
---
|
|
167
148
|
apiVersion: projectcontour.io/v1
|
|
@@ -178,7 +159,7 @@ spec:
|
|
|
178
159
|
secretName: ${host}`
|
|
179
160
|
}
|
|
180
161
|
routes:`;
|
|
181
|
-
for (const conditionObj of
|
|
162
|
+
for (const conditionObj of pathPortAssignment) {
|
|
182
163
|
const { path, port } = conditionObj;
|
|
183
164
|
proxyYaml += `
|
|
184
165
|
- conditions:
|
package/src/cli/fs.js
CHANGED
|
@@ -38,7 +38,7 @@ 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);
|
|
41
|
+
const deleteFiles = options.pull === true ? [] : UnderpostRepository.API.getDeleteFiles(path);
|
|
42
42
|
for (const relativePath of deleteFiles) {
|
|
43
43
|
const _path = path + '/' + relativePath;
|
|
44
44
|
if (_path in storage) {
|
|
@@ -46,10 +46,6 @@ class UnderpostFileStorage {
|
|
|
46
46
|
delete storage[_path];
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
const files =
|
|
50
|
-
options.git === true
|
|
51
|
-
? UnderpostRepository.API.getChangedFiles(path)
|
|
52
|
-
: await fs.readdir(path, { recursive: true });
|
|
53
49
|
if (options.pull === true) {
|
|
54
50
|
for (const _path of Object.keys(storage)) {
|
|
55
51
|
if (!fs.existsSync(_path) || options.force === true) {
|
|
@@ -57,7 +53,11 @@ class UnderpostFileStorage {
|
|
|
57
53
|
await UnderpostFileStorage.API.pull(_path, options);
|
|
58
54
|
} else logger.warn(`Pull path already exists`, _path);
|
|
59
55
|
}
|
|
60
|
-
} else
|
|
56
|
+
} else {
|
|
57
|
+
const files =
|
|
58
|
+
options.git === true
|
|
59
|
+
? UnderpostRepository.API.getChangedFiles(path)
|
|
60
|
+
: await fs.readdir(path, { recursive: true });
|
|
61
61
|
for (const relativePath of files) {
|
|
62
62
|
const _path = path + '/' + relativePath;
|
|
63
63
|
if (fs.statSync(_path).isDirectory()) {
|
|
@@ -68,6 +68,7 @@ class UnderpostFileStorage {
|
|
|
68
68
|
if (storage) storage[_path] = {};
|
|
69
69
|
} else logger.warn('File already exists', _path);
|
|
70
70
|
}
|
|
71
|
+
}
|
|
71
72
|
UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
|
|
72
73
|
if (options.git === true) {
|
|
73
74
|
shellExec(`cd ${path} && git add .`);
|
package/src/cli/image.js
CHANGED
|
@@ -2,10 +2,10 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import Underpost from '../index.js';
|
|
3
3
|
import { shellCd, shellExec } from '../server/process.js';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
|
-
import { getNpmRootPath } from '../server/conf.js';
|
|
5
|
+
import { awaitDeployMonitor, getNpmRootPath } from '../server/conf.js';
|
|
6
6
|
import { timer } from '../client/components/core/CommonJs.js';
|
|
7
|
-
import UnderpostRootEnv from './env.js';
|
|
8
7
|
import { loggerFactory } from '../server/logger.js';
|
|
8
|
+
import UnderpostMonitor from './monitor.js';
|
|
9
9
|
|
|
10
10
|
dotenv.config();
|
|
11
11
|
|
|
@@ -18,41 +18,49 @@ class UnderpostImage {
|
|
|
18
18
|
shellExec(`sudo podman pull docker.io/library/debian:buster`);
|
|
19
19
|
},
|
|
20
20
|
build(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
options = {
|
|
22
|
+
path: '',
|
|
23
|
+
imageName: '',
|
|
24
|
+
imagePath: '',
|
|
25
|
+
dockerfileName: '',
|
|
26
|
+
podmanSave: false,
|
|
27
|
+
kindLoad: false,
|
|
28
|
+
secrets: false,
|
|
29
|
+
secretsPath: '',
|
|
30
|
+
noCache: false,
|
|
31
|
+
},
|
|
25
32
|
) {
|
|
26
|
-
const
|
|
27
|
-
options
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (!fs.existsSync(`${path}${imagesStoragePath}`))
|
|
34
|
-
fs.mkdirSync(`${path}${imagesStoragePath}`, { recursive: true });
|
|
35
|
-
const tarFile = `.${imagesStoragePath}/${imgName.replace(':', '_')}.tar`;
|
|
36
|
-
|
|
37
|
-
let secrets = ' ';
|
|
33
|
+
const { path, imageName, imagePath, dockerfileName, podmanSave, secrets, secretsPath, kindLoad, noCache } =
|
|
34
|
+
options;
|
|
35
|
+
const podManImg = `localhost/${imageName}`;
|
|
36
|
+
if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
|
|
37
|
+
fs.mkdirSync(imagePath, { recursive: true });
|
|
38
|
+
const tarFile = `${imagePath}/${imageName.replace(':', '_')}.tar`;
|
|
39
|
+
let secretsInput = ' ';
|
|
38
40
|
let secretDockerInput = '';
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
let cache = '';
|
|
42
|
+
if (secrets === true) {
|
|
43
|
+
const envObj = dotenv.parse(
|
|
44
|
+
fs.readFileSync(
|
|
45
|
+
secretsPath && typeof secretsPath === 'string' ? secretsPath : `${getNpmRootPath()}/underpost/.env`,
|
|
46
|
+
'utf8',
|
|
47
|
+
),
|
|
48
|
+
);
|
|
49
|
+
for (const key of Object.keys(envObj)) {
|
|
50
|
+
secretsInput += ` && export ${key}="${envObj[key]}" `; // $(cat gitlab-token.txt)
|
|
51
|
+
secretDockerInput += ` --secret id=${key},env=${key} \ `;
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
|
-
|
|
48
|
-
if (
|
|
54
|
+
if (noCache === true) cache += ' --rm --no-cache';
|
|
55
|
+
if (path && typeof path === 'string')
|
|
49
56
|
shellExec(
|
|
50
|
-
`cd ${path}${
|
|
57
|
+
`cd ${path}${secretsInput}&& sudo podman build -f ./${
|
|
58
|
+
dockerfileName && typeof dockerfileName === 'string' ? dockerfileName : 'Dockerfile'
|
|
59
|
+
} -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}${secretDockerInput}`,
|
|
51
60
|
);
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
|
|
61
|
+
|
|
62
|
+
if (podmanSave === true) shellExec(`podman save -o ${tarFile} ${podManImg}`);
|
|
63
|
+
if (kindLoad === true) shellExec(`sudo kind load image-archive ${tarFile}`);
|
|
56
64
|
},
|
|
57
65
|
async script(deployId = 'default', env = 'development', options = { run: false, build: false }) {
|
|
58
66
|
if (options.build === true) {
|
|
@@ -69,59 +77,57 @@ class UnderpostImage {
|
|
|
69
77
|
for (const itcScript of itcScripts)
|
|
70
78
|
if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
|
|
71
79
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
default:
|
|
75
|
-
{
|
|
80
|
+
switch (deployId) {
|
|
81
|
+
default:
|
|
76
82
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
{
|
|
84
|
+
const originPath = `./src/db/mongo/MongooseDB.js`;
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
originPath,
|
|
87
|
+
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
88
|
+
`connect: async (host, name) => {`,
|
|
89
|
+
`connect: async (host, name) => {
|
|
83
90
|
host = 'mongodb://mongodb-0.mongodb-service:27017';
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
`,
|
|
92
|
+
),
|
|
93
|
+
'utf8',
|
|
94
|
+
);
|
|
95
|
+
}
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
{
|
|
98
|
+
const originPath = `./src/server/valkey.js`;
|
|
99
|
+
fs.writeFileSync(
|
|
100
|
+
originPath,
|
|
101
|
+
fs.readFileSync(originPath, 'utf8').replaceAll(
|
|
102
|
+
` // port: 6379,
|
|
96
103
|
// host: 'service-valkey.default.svc.cluster.local',`,
|
|
97
|
-
|
|
104
|
+
` port: 6379,
|
|
98
105
|
host: 'service-valkey.default.svc.cluster.local',`,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
),
|
|
107
|
+
'utf8',
|
|
108
|
+
);
|
|
109
|
+
}
|
|
102
110
|
}
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
114
|
+
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
105
115
|
}
|
|
106
|
-
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
107
|
-
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
108
116
|
if (options.run === true) {
|
|
109
117
|
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
110
118
|
if (fs.existsSync(`./engine-private/replica`)) {
|
|
111
119
|
const replicas = await fs.readdir(`./engine-private/replica`);
|
|
112
120
|
for (const replica of replicas) {
|
|
121
|
+
if (!replica.match(deployId)) continue;
|
|
113
122
|
shellExec(`node bin/deploy conf ${replica} ${env}`);
|
|
114
123
|
shellExec(`npm ${runCmd} deploy deploy-id:${replica}`, { async: true });
|
|
115
|
-
|
|
116
|
-
const monitor = async () => {
|
|
117
|
-
await timer(1000);
|
|
118
|
-
if (fs.existsSync(`./tmp/await-deploy`)) return await monitor();
|
|
119
|
-
};
|
|
120
|
-
await monitor();
|
|
124
|
+
await awaitDeployMonitor(true);
|
|
121
125
|
}
|
|
122
|
-
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
123
126
|
}
|
|
124
|
-
shellExec(`
|
|
127
|
+
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
128
|
+
shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`, { async: true });
|
|
129
|
+
await awaitDeployMonitor(true);
|
|
130
|
+
await UnderpostMonitor.API.callback(deployId, env, { itc: true });
|
|
125
131
|
}
|
|
126
132
|
},
|
|
127
133
|
},
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { loadReplicas, pathPortAssignmentFactory } from '../server/conf.js';
|
|
2
|
+
import { loggerFactory } from '../server/logger.js';
|
|
3
|
+
import UnderpostDeploy from './deploy.js';
|
|
4
|
+
import axios from 'axios';
|
|
5
|
+
import UnderpostRootEnv from './env.js';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
|
|
8
|
+
const logger = loggerFactory(import.meta);
|
|
9
|
+
|
|
10
|
+
class UnderpostMonitor {
|
|
11
|
+
static API = {
|
|
12
|
+
async callback(deployId, env = 'development', options = { now: false, single: false, msInterval: '' }) {
|
|
13
|
+
const router = await UnderpostDeploy.API.routerFactory(deployId, env);
|
|
14
|
+
|
|
15
|
+
const confServer = loadReplicas(
|
|
16
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
17
|
+
'proxy',
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
21
|
+
|
|
22
|
+
logger.info('', pathPortAssignmentData);
|
|
23
|
+
|
|
24
|
+
const errorPayloads = [];
|
|
25
|
+
const maxAttempts = Object.keys(pathPortAssignmentData)
|
|
26
|
+
.map((host) => pathPortAssignmentData[host].length)
|
|
27
|
+
.reduce((accumulator, value) => accumulator + value, 0);
|
|
28
|
+
|
|
29
|
+
const monitor = async (reject) => {
|
|
30
|
+
logger.info('Check server health');
|
|
31
|
+
for (const host of Object.keys(pathPortAssignmentData)) {
|
|
32
|
+
for (const instance of pathPortAssignmentData[host]) {
|
|
33
|
+
const { port, path } = instance;
|
|
34
|
+
if (path.match('peer') || path.match('socket')) continue;
|
|
35
|
+
const urlTest = `http://localhost:${port}${path}`;
|
|
36
|
+
// logger.info('Test instance', urlTest);
|
|
37
|
+
await axios.get(urlTest, { timeout: 10000 }).catch((error) => {
|
|
38
|
+
// console.log(error);
|
|
39
|
+
const errorPayload = {
|
|
40
|
+
urlTest,
|
|
41
|
+
host,
|
|
42
|
+
port,
|
|
43
|
+
path,
|
|
44
|
+
name: error.name,
|
|
45
|
+
status: error.status,
|
|
46
|
+
code: error.code,
|
|
47
|
+
errors: error.errors,
|
|
48
|
+
};
|
|
49
|
+
if (errorPayload.status !== 404) {
|
|
50
|
+
errorPayloads.push(errorPayload);
|
|
51
|
+
if (errorPayloads.length >= maxAttempts) {
|
|
52
|
+
const message = JSON.stringify(errorPayloads, null, 4);
|
|
53
|
+
if (reject) reject(message);
|
|
54
|
+
else throw new Error(message);
|
|
55
|
+
}
|
|
56
|
+
logger.error('Error accumulator', errorPayloads.length);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (options.now === true) await monitor();
|
|
63
|
+
if (options.single === true) return;
|
|
64
|
+
let optionsMsTimeout = parseInt(options.msInterval);
|
|
65
|
+
if (isNaN(optionsMsTimeout)) optionsMsTimeout = 30000;
|
|
66
|
+
const monitorCallBack = (resolve, reject) => {
|
|
67
|
+
const envMsTimeout = UnderpostRootEnv.API.get('monitor-ms');
|
|
68
|
+
setTimeout(
|
|
69
|
+
async () => {
|
|
70
|
+
switch (UnderpostRootEnv.API.get('monitor-input')) {
|
|
71
|
+
case 'pause':
|
|
72
|
+
monitorCallBack(resolve, reject);
|
|
73
|
+
return;
|
|
74
|
+
case 'restart':
|
|
75
|
+
return reject();
|
|
76
|
+
case 'stop':
|
|
77
|
+
return resolve();
|
|
78
|
+
default:
|
|
79
|
+
await monitor(reject);
|
|
80
|
+
monitorCallBack(resolve, reject);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
!isNaN(envMsTimeout) ? envMsTimeout : optionsMsTimeout,
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
return await new Promise((...args) => monitorCallBack(...args));
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default UnderpostMonitor;
|
|
@@ -252,7 +252,7 @@ const Account = {
|
|
|
252
252
|
${options?.bottomRender ? await options.bottomRender() : ``}
|
|
253
253
|
<div class="in hide">
|
|
254
254
|
${await BtnIcon.Render({
|
|
255
|
-
class: 'section-mp form-button btn-account',
|
|
255
|
+
class: 'in section-mp form-button btn-account',
|
|
256
256
|
label: Translate.Render('update'),
|
|
257
257
|
type: 'submit',
|
|
258
258
|
})}
|
|
@@ -260,13 +260,13 @@ const Account = {
|
|
|
260
260
|
</form>
|
|
261
261
|
<div class="in">
|
|
262
262
|
${await BtnIcon.Render({
|
|
263
|
-
class: 'section-mp form-button btn-account-delete hide',
|
|
263
|
+
class: 'in section-mp form-button btn-account-delete hide',
|
|
264
264
|
label: html` ${Translate.Render(`delete-account`)}`,
|
|
265
265
|
type: 'button',
|
|
266
266
|
style: 'color: #5f5f5f',
|
|
267
267
|
})}
|
|
268
268
|
${await BtnIcon.Render({
|
|
269
|
-
class: 'section-mp form-button btn-account-delete-confirm',
|
|
269
|
+
class: 'in section-mp form-button btn-account-delete-confirm',
|
|
270
270
|
label: html` ${Translate.Render(`delete-account`)}`,
|
|
271
271
|
type: 'button',
|
|
272
272
|
style: 'color: #5f5f5f',
|
|
@@ -25,7 +25,7 @@ const BlockChainManagement = {
|
|
|
25
25
|
placeholder: true,
|
|
26
26
|
})}
|
|
27
27
|
${await BtnIcon.Render({
|
|
28
|
-
class: `section-mp btn-custom btn-upload-blockchain`,
|
|
28
|
+
class: `inl section-mp btn-custom btn-upload-blockchain`,
|
|
29
29
|
label: html`<i class="fas fa-plus"></i> ${Translate.Render(`create`)}`,
|
|
30
30
|
})}
|
|
31
31
|
</div>
|
|
@@ -409,9 +409,11 @@ const CalendarCore = {
|
|
|
409
409
|
if (delayBlock) return;
|
|
410
410
|
else {
|
|
411
411
|
delayBlock = true;
|
|
412
|
+
const _currentPath = `${location.pathname}${location.search}`;
|
|
412
413
|
setTimeout(() => {
|
|
413
414
|
delayBlock = false;
|
|
414
|
-
|
|
415
|
+
if (`${location.pathname}${location.search}` !== _currentPath) this.Data[options.idModal].updatePanel();
|
|
416
|
+
}, 1000);
|
|
415
417
|
}
|
|
416
418
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
417
419
|
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
@@ -521,7 +523,7 @@ const CalendarCore = {
|
|
|
521
523
|
<div class="in calendar-container hide">
|
|
522
524
|
<div class="stq modal calendar-buttons-container">
|
|
523
525
|
${await BtnIcon.Render({
|
|
524
|
-
class: `section-mp btn-custom close-calendar-container flr`,
|
|
526
|
+
class: `inl section-mp btn-custom close-calendar-container flr`,
|
|
525
527
|
label: html`<i class="fa-solid fa-xmark"></i> ${Translate.Render('close')}`,
|
|
526
528
|
type: 'button',
|
|
527
529
|
})}
|
|
@@ -396,7 +396,8 @@ const CssCoreDark = {
|
|
|
396
396
|
text-align: center;
|
|
397
397
|
background: #1a1a1a;
|
|
398
398
|
font-size: 17px;
|
|
399
|
-
height:
|
|
399
|
+
height: 30px;
|
|
400
|
+
padding: 5px 0px 5px 0px;
|
|
400
401
|
}
|
|
401
402
|
::placeholder {
|
|
402
403
|
color: #c6c4c4;
|
|
@@ -471,6 +472,7 @@ const CssCoreDark = {
|
|
|
471
472
|
width: 260px;
|
|
472
473
|
font-size: 20px;
|
|
473
474
|
padding: 10px;
|
|
475
|
+
min-height: 45px;
|
|
474
476
|
}
|
|
475
477
|
.toggle-form-container {
|
|
476
478
|
border: 2px solid #313131;
|
|
@@ -494,6 +496,7 @@ const CssCoreDark = {
|
|
|
494
496
|
font-size: 20px;
|
|
495
497
|
padding: 10px;
|
|
496
498
|
text-align: center;
|
|
499
|
+
min-height: 45px;
|
|
497
500
|
}
|
|
498
501
|
.drop-zone-file-explorer {
|
|
499
502
|
min-height: 300px;
|
|
@@ -700,7 +703,8 @@ const CssCoreLight = {
|
|
|
700
703
|
text-align: center;
|
|
701
704
|
background: #eaeaea;
|
|
702
705
|
font-size: 17px;
|
|
703
|
-
height:
|
|
706
|
+
height: 30px;
|
|
707
|
+
padding: 5px 0px 5px 0px;
|
|
704
708
|
}
|
|
705
709
|
::placeholder {
|
|
706
710
|
color: #333;
|
|
@@ -776,6 +780,7 @@ const CssCoreLight = {
|
|
|
776
780
|
width: 260px;
|
|
777
781
|
font-size: 20px;
|
|
778
782
|
padding: 10px;
|
|
783
|
+
min-height: 45px;
|
|
779
784
|
}
|
|
780
785
|
.toggle-form-container {
|
|
781
786
|
border-radius: 5px;
|
|
@@ -800,6 +805,7 @@ const CssCoreLight = {
|
|
|
800
805
|
font-size: 20px;
|
|
801
806
|
padding: 10px;
|
|
802
807
|
text-align: center;
|
|
808
|
+
min-height: 45px;
|
|
803
809
|
}
|
|
804
810
|
.input-container-width {
|
|
805
811
|
cursor: pointer;
|
|
@@ -79,7 +79,7 @@ const Docs = {
|
|
|
79
79
|
icon: html`<i class="fa-brands fa-osi"></i>`,
|
|
80
80
|
text: 'Source Docs',
|
|
81
81
|
url: function () {
|
|
82
|
-
return `${getProxyPath()}docs/engine/${window.renderPayload.version}`;
|
|
82
|
+
return `${getProxyPath()}docs/engine/${window.renderPayload.version.replace('v', '')}`;
|
|
83
83
|
},
|
|
84
84
|
},
|
|
85
85
|
{
|
|
@@ -75,28 +75,12 @@ const LoadingAnimation = {
|
|
|
75
75
|
const style = {
|
|
76
76
|
'text-align': 'center',
|
|
77
77
|
};
|
|
78
|
-
if (s(container).classList) {
|
|
79
|
-
const classes = Array.from(s(container).classList);
|
|
80
|
-
if (classes.find((e) => e.match('management-table-btn-mini'))) {
|
|
81
|
-
style.top = '-2px';
|
|
82
|
-
style.left = '-2px';
|
|
83
|
-
} else if (classes.find((e) => e.match('-btn-tool'))) {
|
|
84
|
-
style.top = '-26px';
|
|
85
|
-
style.left = '-10px';
|
|
86
|
-
} else if (classes.find((e) => e.match('main-btn-')) && !classes.find((e) => e.match('main-btn-square-menu'))) {
|
|
87
|
-
style.top = '-8px';
|
|
88
|
-
style.left = '-10px';
|
|
89
|
-
} else if (classes.find((e) => e.match('action-bar-box'))) {
|
|
90
|
-
style.top = '-30px';
|
|
91
|
-
style.left = '-12px';
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
78
|
|
|
95
79
|
append(
|
|
96
80
|
container,
|
|
97
81
|
html`
|
|
98
82
|
<div
|
|
99
|
-
class="
|
|
83
|
+
class="abs center ${id}"
|
|
100
84
|
style="${renderCssAttr({
|
|
101
85
|
style,
|
|
102
86
|
})}"
|
|
@@ -135,7 +135,7 @@ const LogIn = {
|
|
|
135
135
|
return html`
|
|
136
136
|
<div class="in">
|
|
137
137
|
${await BtnIcon.Render({
|
|
138
|
-
class: 'section-mp form-button btn-log-in-i-not-have-account',
|
|
138
|
+
class: 'in section-mp form-button btn-log-in-i-not-have-account',
|
|
139
139
|
label: html`<i class="fas fa-user-plus"></i> ${Translate.Render(`i-not-have-account`)}
|
|
140
140
|
<br />
|
|
141
141
|
${Translate.Render(`sign-up`)}`,
|
|
@@ -165,7 +165,7 @@ const LogIn = {
|
|
|
165
165
|
</div>
|
|
166
166
|
<div class="in">
|
|
167
167
|
${await BtnIcon.Render({
|
|
168
|
-
class: 'section-mp form-button btn-log-in-forgot-password',
|
|
168
|
+
class: 'in section-mp form-button btn-log-in-forgot-password',
|
|
169
169
|
label: html`<i class="fas fa-question-circle"></i> ${Translate.Render(`forgot-password`)}`,
|
|
170
170
|
type: 'button',
|
|
171
171
|
})}
|
|
@@ -181,7 +181,7 @@ const LogIn = {
|
|
|
181
181
|
|
|
182
182
|
<div class="in">
|
|
183
183
|
${await BtnIcon.Render({
|
|
184
|
-
class: 'section-mp form-button btn-log-in',
|
|
184
|
+
class: 'in section-mp form-button btn-log-in',
|
|
185
185
|
label: Translate.Render('log-in'),
|
|
186
186
|
type: 'submit',
|
|
187
187
|
})}
|
|
@@ -47,7 +47,7 @@ const LogOut = {
|
|
|
47
47
|
return html` <form class="in">
|
|
48
48
|
<div class="in">
|
|
49
49
|
${await BtnIcon.Render({
|
|
50
|
-
class: 'section-mp btn-custom btn-log-out',
|
|
50
|
+
class: 'inl section-mp btn-custom btn-log-out',
|
|
51
51
|
label: html`<i class="fa-solid fa-power-off"></i> ${Translate.Render('log-out')}`,
|
|
52
52
|
type: 'submit',
|
|
53
53
|
})}
|
|
@@ -246,7 +246,7 @@ const Panel = {
|
|
|
246
246
|
let render = '';
|
|
247
247
|
let renderForm = html` <div class="in modal stq" style="top: 0px; z-index: 1; padding-bottom: 5px">
|
|
248
248
|
${await BtnIcon.Render({
|
|
249
|
-
class: `section-mp btn-custom btn-${idPanel}-close`,
|
|
249
|
+
class: `inl section-mp btn-custom btn-${idPanel}-close`,
|
|
250
250
|
label: html`<i class="fa-solid fa-xmark"></i> ${Translate.Render('close')}`,
|
|
251
251
|
type: 'button',
|
|
252
252
|
})}
|
|
@@ -404,13 +404,13 @@ const Panel = {
|
|
|
404
404
|
}
|
|
405
405
|
let renderFormBtn = html`
|
|
406
406
|
${await BtnIcon.Render({
|
|
407
|
-
class: `section-mp btn-custom btn-${idPanel}-submit`,
|
|
407
|
+
class: `inl section-mp btn-custom btn-${idPanel}-submit`,
|
|
408
408
|
label: html`<span class="btn-${idPanel}-label-add"><i class="fas fa-plus"></i> ${Translate.Render('add')}</span
|
|
409
409
|
><span class="btn-${idPanel}-label-edit hide"><i class="fas fa-edit"></i> ${Translate.Render('edit')}</span>`,
|
|
410
410
|
type: 'submit',
|
|
411
411
|
})}
|
|
412
412
|
${await BtnIcon.Render({
|
|
413
|
-
class: `section-mp btn-custom btn-${idPanel}-clean`,
|
|
413
|
+
class: `inl section-mp btn-custom btn-${idPanel}-clean`,
|
|
414
414
|
label: html`<i class="fa-solid fa-broom"></i> ${Translate.Render('clear')}`,
|
|
415
415
|
type: 'button',
|
|
416
416
|
})}
|
|
@@ -546,7 +546,7 @@ const Panel = {
|
|
|
546
546
|
s(`.${btnSelector}`).onclick = () => dataBtn.onClick();
|
|
547
547
|
});
|
|
548
548
|
customButtonsRender += ` ${await BtnIcon.Render({
|
|
549
|
-
class: `section-mp btn-custom ${btnSelector}`,
|
|
549
|
+
class: `inl section-mp btn-custom ${btnSelector}`,
|
|
550
550
|
label: dataBtn.label,
|
|
551
551
|
type: 'button',
|
|
552
552
|
})}`;
|
|
@@ -656,7 +656,7 @@ const Panel = {
|
|
|
656
656
|
>
|
|
657
657
|
<div class="in ${idPanel}-form-header">
|
|
658
658
|
${await BtnIcon.Render({
|
|
659
|
-
class: `section-mp btn-custom btn-${idPanel}-add ${
|
|
659
|
+
class: `inl section-mp btn-custom btn-${idPanel}-add ${
|
|
660
660
|
options?.role?.add ? (!options.role.add() ? 'hide' : '') : ''
|
|
661
661
|
}`,
|
|
662
662
|
label: html`<i class="fas fa-plus"></i> ${Translate.Render('add')}`,
|
|
@@ -430,9 +430,11 @@ const PanelForm = {
|
|
|
430
430
|
if (delayBlock) return;
|
|
431
431
|
else {
|
|
432
432
|
delayBlock = true;
|
|
433
|
+
const _currentPath = `${location.pathname}${location.search}`;
|
|
433
434
|
setTimeout(() => {
|
|
434
435
|
delayBlock = false;
|
|
435
|
-
|
|
436
|
+
if (`${location.pathname}${location.search}` !== _currentPath) this.Data[idPanel].updatePanel();
|
|
437
|
+
}, 1000);
|
|
436
438
|
}
|
|
437
439
|
const cid = getQueryParams().cid ? getQueryParams().cid : '';
|
|
438
440
|
if (options.route === 'home') Modal.homeCid = newInstance(cid);
|
|
@@ -126,7 +126,7 @@ const Recover = {
|
|
|
126
126
|
});
|
|
127
127
|
return html`
|
|
128
128
|
${await BtnIcon.Render({
|
|
129
|
-
class: 'section-mp form-button btn-recover-log-in hide',
|
|
129
|
+
class: 'in section-mp form-button btn-recover-log-in hide',
|
|
130
130
|
label: Translate.Render('log-in'),
|
|
131
131
|
type: 'button',
|
|
132
132
|
})}
|
|
@@ -181,7 +181,7 @@ const Recover = {
|
|
|
181
181
|
${options?.bottomRender ? await options.bottomRender() : ``}
|
|
182
182
|
<div class="in recover-send-btn-container">
|
|
183
183
|
${await BtnIcon.Render({
|
|
184
|
-
class: 'section-mp form-button btn-recover',
|
|
184
|
+
class: 'in section-mp form-button btn-recover',
|
|
185
185
|
label: Translate.Render(mode === 'recover-verify-email' ? 'send-recover-verify-email' : 'change-password'),
|
|
186
186
|
type: 'button',
|
|
187
187
|
})}
|
|
@@ -191,7 +191,7 @@ const Recover = {
|
|
|
191
191
|
<i class="fa-solid fa-triangle-exclamation"></i> ${Translate.Render('15-min-valid-recover-email')}
|
|
192
192
|
</div>
|
|
193
193
|
${await BtnIcon.Render({
|
|
194
|
-
class: 'section-mp form-button btn-recover-resend',
|
|
194
|
+
class: 'in section-mp form-button btn-recover-resend',
|
|
195
195
|
label: html`${Translate.Render('resend')} ${Translate.Render('recover-verify-email')}`,
|
|
196
196
|
type: 'submit',
|
|
197
197
|
})}
|
|
@@ -63,7 +63,7 @@ const SignUp = {
|
|
|
63
63
|
});
|
|
64
64
|
return html`
|
|
65
65
|
${await BtnIcon.Render({
|
|
66
|
-
class: 'section-mp form-button btn-sign-up-i-have-account',
|
|
66
|
+
class: 'in section-mp form-button btn-sign-up-i-have-account',
|
|
67
67
|
label: html`<i class="fas fa-sign-in-alt"></i> ${Translate.Render('i-have-account')}<br />${Translate.Render(
|
|
68
68
|
'log-in',
|
|
69
69
|
)}`,
|
|
@@ -112,7 +112,7 @@ const SignUp = {
|
|
|
112
112
|
${options?.bottomRender ? await options.bottomRender() : ``}
|
|
113
113
|
<div class="in">
|
|
114
114
|
${await BtnIcon.Render({
|
|
115
|
-
class: 'section-mp form-button btn-sign-up',
|
|
115
|
+
class: 'in section-mp form-button btn-sign-up',
|
|
116
116
|
label: Translate.Render('sign-up'),
|
|
117
117
|
type: 'submit',
|
|
118
118
|
})}
|
package/src/client/ssr/Render.js
CHANGED
|
@@ -133,6 +133,8 @@ SrrComponent = ({ title, ssrPath, buildId, ssrHeadComponents, ssrBodyComponents,
|
|
|
133
133
|
border: none;
|
|
134
134
|
padding-block: 0;
|
|
135
135
|
padding-inline: 0;
|
|
136
|
+
height: 30px;
|
|
137
|
+
line-height: 30px;
|
|
136
138
|
}
|
|
137
139
|
input::file-selector-button {
|
|
138
140
|
outline: none !important;
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import UnderpostDeploy from './cli/deploy.js';
|
|
|
11
11
|
import UnderpostRootEnv from './cli/env.js';
|
|
12
12
|
import UnderpostFileStorage from './cli/fs.js';
|
|
13
13
|
import UnderpostImage from './cli/image.js';
|
|
14
|
+
import UnderpostMonitor from './cli/monitor.js';
|
|
14
15
|
import UnderpostRepository from './cli/repository.js';
|
|
15
16
|
import UnderpostScript from './cli/script.js';
|
|
16
17
|
import UnderpostSecret from './cli/secrets.js';
|
|
@@ -28,7 +29,7 @@ class Underpost {
|
|
|
28
29
|
* @type {String}
|
|
29
30
|
* @memberof Underpost
|
|
30
31
|
*/
|
|
31
|
-
static version = 'v2.8.
|
|
32
|
+
static version = 'v2.8.637';
|
|
32
33
|
/**
|
|
33
34
|
* Repository cli API
|
|
34
35
|
* @static
|
|
@@ -106,6 +107,13 @@ class Underpost {
|
|
|
106
107
|
* @memberof UnderpostFileStorage
|
|
107
108
|
*/
|
|
108
109
|
static fs = UnderpostFileStorage.API;
|
|
110
|
+
/**
|
|
111
|
+
* Monitor cli API
|
|
112
|
+
* @static
|
|
113
|
+
* @type {UnderpostMonitor.API}
|
|
114
|
+
* @memberof UnderpostMonitor
|
|
115
|
+
*/
|
|
116
|
+
static monitor = UnderpostMonitor.API;
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
const up = Underpost;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
ARG BASE_DEBIAN=buster
|
|
2
|
+
|
|
3
|
+
USER root
|
|
4
|
+
|
|
5
|
+
FROM debian:${BASE_DEBIAN}
|
|
6
|
+
|
|
7
|
+
ENV DEBIAN_FRONTEND=noninteractive
|
|
8
|
+
|
|
9
|
+
# Set root password to root, format is 'user:password'.
|
|
10
|
+
RUN echo 'root:root' | chpasswd
|
|
11
|
+
|
|
12
|
+
RUN apt-get update --fix-missing
|
|
13
|
+
RUN apt-get upgrade -y
|
|
14
|
+
# install sudo
|
|
15
|
+
RUN apt-get -y install sudo
|
|
16
|
+
# net-tools provides netstat commands
|
|
17
|
+
RUN apt-get -y install curl net-tools
|
|
18
|
+
RUN apt-get -yq install openssh-server supervisor
|
|
19
|
+
# Few handy utilities which are nice to have
|
|
20
|
+
RUN apt-get -y install nano vim less --no-install-recommends
|
|
21
|
+
RUN apt-get clean
|
|
22
|
+
|
|
23
|
+
# install ssh
|
|
24
|
+
RUN mkdir -p /var/run/sshd
|
|
25
|
+
# Allow root login via password
|
|
26
|
+
RUN sed -ri 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
|
|
27
|
+
|
|
28
|
+
# install open ssl git and others tools
|
|
29
|
+
RUN apt-get install -yq --no-install-recommends libssl-dev curl wget git gnupg
|
|
30
|
+
|
|
31
|
+
# install lampp
|
|
32
|
+
RUN curl -Lo xampp-linux-installer.run https://sourceforge.net/projects/xampp/files/XAMPP%20Linux/7.4.33/xampp-linux-x64-7.4.33-0-installer.run?from_af=true
|
|
33
|
+
RUN chmod +x xampp-linux-installer.run
|
|
34
|
+
RUN bash -c './xampp-linux-installer.run'
|
|
35
|
+
RUN ln -sf /opt/lampp/lampp /usr/bin/lampp
|
|
36
|
+
# Enable XAMPP web interface(remove security checks)
|
|
37
|
+
RUN sed -i.bak s'/Require local/Require all granted/g' /opt/lampp/etc/extra/httpd-xampp.conf
|
|
38
|
+
# Enable error display in php
|
|
39
|
+
RUN sed -i.bak s'/display_errors=Off/display_errors=On/g' /opt/lampp/etc/php.ini
|
|
40
|
+
# Enable includes of several configuration files
|
|
41
|
+
RUN mkdir /opt/lampp/apache2/conf.d
|
|
42
|
+
RUN echo "IncludeOptional /opt/lampp/apache2/conf.d/*.conf" >>/opt/lampp/etc/httpd.conf
|
|
43
|
+
# Create a /www folder and a symbolic link to it in /opt/lampp/htdocs. It'll be accessible via http://localhost:[port]/www/
|
|
44
|
+
# This is convenient because it doesn't interfere with xampp, phpmyadmin or other tools in /opt/lampp/htdocs
|
|
45
|
+
# /opt/lampp/etc/httpd.conf
|
|
46
|
+
RUN mkdir /www
|
|
47
|
+
RUN ln -s /www /opt/lampp/htdocs
|
|
48
|
+
|
|
49
|
+
# install nodejs https://github.com/nodesource/distributions/blob/master/README.md#deb
|
|
50
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_23.x | bash -
|
|
51
|
+
RUN apt-get install -y nodejs build-essential
|
|
52
|
+
RUN node --version
|
|
53
|
+
RUN npm --version
|
|
54
|
+
|
|
55
|
+
WORKDIR /home/dd
|
|
56
|
+
|
|
57
|
+
EXPOSE 22
|
|
58
|
+
|
|
59
|
+
EXPOSE 80
|
|
60
|
+
|
|
61
|
+
EXPOSE 443
|
|
62
|
+
|
|
63
|
+
EXPOSE 3000-3100
|
|
64
|
+
|
|
65
|
+
EXPOSE 4000-4100
|
package/src/server/conf.js
CHANGED
|
@@ -499,6 +499,40 @@ const buildProxyRouter = () => {
|
|
|
499
499
|
return proxyRouter;
|
|
500
500
|
};
|
|
501
501
|
|
|
502
|
+
const pathPortAssignmentFactory = (router, confServer) => {
|
|
503
|
+
const pathPortAssignmentData = {};
|
|
504
|
+
for (const host of Object.keys(confServer)) {
|
|
505
|
+
const pathPortAssignment = [];
|
|
506
|
+
for (const path of Object.keys(confServer[host])) {
|
|
507
|
+
const { peer } = confServer[host][path];
|
|
508
|
+
if (!router[`${host}${path === '/' ? '' : path}`]) continue;
|
|
509
|
+
const port = parseInt(router[`${host}${path === '/' ? '' : path}`].split(':')[2]);
|
|
510
|
+
// logger.info('', { host, port, path });
|
|
511
|
+
pathPortAssignment.push({
|
|
512
|
+
port,
|
|
513
|
+
path,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
if (peer) {
|
|
517
|
+
// logger.info('', { host, port: port + 1, path: '/peer' });
|
|
518
|
+
pathPortAssignment.push({
|
|
519
|
+
port: port + 1,
|
|
520
|
+
path: '/peer',
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
pathPortAssignmentData[host] = pathPortAssignment;
|
|
525
|
+
}
|
|
526
|
+
return pathPortAssignmentData;
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const deployRangePortFactory = (router) => {
|
|
530
|
+
const ports = Object.values(router).map((p) => parseInt(p.split(':')[2]));
|
|
531
|
+
const fromPort = Math.min(...ports);
|
|
532
|
+
const toPort = Math.max(...ports);
|
|
533
|
+
return { ports, fromPort, toPort };
|
|
534
|
+
};
|
|
535
|
+
|
|
502
536
|
const buildKindPorts = (from, to) =>
|
|
503
537
|
range(parseInt(from), parseInt(to))
|
|
504
538
|
.map(
|
|
@@ -729,7 +763,7 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
729
763
|
return true;
|
|
730
764
|
};
|
|
731
765
|
|
|
732
|
-
const deployTest = async (dataDeploy) => {
|
|
766
|
+
const deployTest = async (dataDeploy = [{ deployId: 'default' }]) => {
|
|
733
767
|
const failed = [];
|
|
734
768
|
for (const deploy of dataDeploy) {
|
|
735
769
|
const deployServerConfPath = fs.existsSync(`./engine-private/replica/${deploy.deployId}/conf.server.json`)
|
|
@@ -773,6 +807,12 @@ const deployTest = async (dataDeploy) => {
|
|
|
773
807
|
return { failed };
|
|
774
808
|
};
|
|
775
809
|
|
|
810
|
+
const awaitDeployMonitor = async (init = false, deltaMs = 1000) => {
|
|
811
|
+
if (init) fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
812
|
+
await timer(deltaMs);
|
|
813
|
+
if (fs.existsSync(`./tmp/await-deploy`)) return await awaitDeployMonitor();
|
|
814
|
+
};
|
|
815
|
+
|
|
776
816
|
const getDeployGroupId = () => {
|
|
777
817
|
const deployGroupIndexArg = process.argv.findIndex((a) => a.match(`deploy-group:`));
|
|
778
818
|
if (deployGroupIndexArg > -1) return process.argv[deployGroupIndexArg].split(':')[1].trim();
|
|
@@ -1122,4 +1162,8 @@ export {
|
|
|
1122
1162
|
getNpmRootPath,
|
|
1123
1163
|
getUnderpostRootPath,
|
|
1124
1164
|
writeEnv,
|
|
1165
|
+
deployTest,
|
|
1166
|
+
pathPortAssignmentFactory,
|
|
1167
|
+
deployRangePortFactory,
|
|
1168
|
+
awaitDeployMonitor,
|
|
1125
1169
|
};
|