underpost 2.8.652 → 2.8.781

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.
Files changed (51) hide show
  1. package/.vscode/extensions.json +37 -2
  2. package/.vscode/settings.json +2 -0
  3. package/CHANGELOG.md +24 -4
  4. package/README.md +5 -4
  5. package/bin/deploy.js +1455 -144
  6. package/cli.md +57 -14
  7. package/docker-compose.yml +1 -1
  8. package/manifests/deployment/adminer/deployment.yaml +32 -0
  9. package/manifests/deployment/adminer/kustomization.yaml +7 -0
  10. package/manifests/deployment/adminer/service.yaml +13 -0
  11. package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
  12. package/manifests/deployment/fastapi/backend-service.yml +19 -0
  13. package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
  14. package/manifests/deployment/fastapi/frontend-service.yml +15 -0
  15. package/manifests/deployment/fastapi/initial_data.sh +56 -0
  16. package/manifests/deployment/kafka/deployment.yaml +69 -0
  17. package/manifests/deployment/spark/spark-pi-py.yaml +21 -0
  18. package/manifests/envoy-service-nodeport.yaml +23 -0
  19. package/manifests/kubeadm-calico-config.yaml +119 -0
  20. package/manifests/kubelet-config.yaml +65 -0
  21. package/manifests/mongodb/kustomization.yaml +1 -1
  22. package/manifests/mongodb/statefulset.yaml +12 -11
  23. package/manifests/mongodb/storage-class.yaml +9 -0
  24. package/manifests/mongodb-4.4/service-deployment.yaml +1 -1
  25. package/manifests/mysql/kustomization.yaml +7 -0
  26. package/manifests/mysql/pv-pvc.yaml +27 -0
  27. package/manifests/mysql/statefulset.yaml +55 -0
  28. package/manifests/postgresql/configmap.yaml +9 -0
  29. package/manifests/postgresql/kustomization.yaml +10 -0
  30. package/manifests/postgresql/pv.yaml +15 -0
  31. package/manifests/postgresql/pvc.yaml +13 -0
  32. package/manifests/postgresql/service.yaml +10 -0
  33. package/manifests/postgresql/statefulset.yaml +37 -0
  34. package/manifests/valkey/statefulset.yaml +4 -3
  35. package/package.json +2 -1
  36. package/src/cli/cluster.js +281 -27
  37. package/src/cli/deploy.js +81 -15
  38. package/src/cli/fs.js +14 -3
  39. package/src/cli/image.js +34 -7
  40. package/src/cli/index.js +36 -1
  41. package/src/cli/lxd.js +19 -0
  42. package/src/cli/monitor.js +75 -30
  43. package/src/cli/repository.js +9 -6
  44. package/src/client/components/core/JoyStick.js +2 -2
  45. package/src/client/components/core/Modal.js +1 -0
  46. package/src/index.js +1 -1
  47. package/src/runtime/lampp/Dockerfile +1 -1
  48. package/src/server/conf.js +5 -1
  49. package/src/server/dns.js +47 -17
  50. package/src/server/runtime.js +2 -0
  51. package/src/server/start.js +0 -1
package/src/cli/image.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import fs from 'fs-extra';
2
- import { shellCd, shellExec } from '../server/process.js';
3
2
  import dotenv from 'dotenv';
4
- import { awaitDeployMonitor, getNpmRootPath } from '../server/conf.js';
5
3
  import { loggerFactory } from '../server/logger.js';
6
- import UnderpostMonitor from './monitor.js';
4
+ import Underpost from '../index.js';
5
+ import { getUnderpostRootPath } from '../server/conf.js';
6
+ import { shellExec } from '../server/process.js';
7
7
 
8
8
  dotenv.config();
9
9
 
@@ -12,8 +12,23 @@ const logger = loggerFactory(import.meta);
12
12
  class UnderpostImage {
13
13
  static API = {
14
14
  dockerfile: {
15
- pullBaseImages() {
15
+ pullBaseImages(
16
+ options = {
17
+ kindLoad: false,
18
+ kubeadmLoad: false,
19
+ path: false,
20
+ version: '',
21
+ },
22
+ ) {
16
23
  shellExec(`sudo podman pull docker.io/library/debian:buster`);
24
+ const IMAGE_NAME = `debian-underpost`;
25
+ const IMAGE_NAME_FULL = `${IMAGE_NAME}:${options.version ?? Underpost.version}`;
26
+ const LOAD_TYPE = options.kindLoad === true ? `--kin-load` : `--kubeadm-load`;
27
+ shellExec(
28
+ `underpost dockerfile-image-build --podman-save --no-cache --image-path=. --path ${
29
+ options.path ?? getUnderpostRootPath()
30
+ } --image-name=${IMAGE_NAME_FULL} ${LOAD_TYPE}`,
31
+ );
17
32
  },
18
33
  build(
19
34
  options = {
@@ -23,13 +38,24 @@ class UnderpostImage {
23
38
  dockerfileName: '',
24
39
  podmanSave: false,
25
40
  kindLoad: false,
41
+ kubeadmLoad: false,
26
42
  secrets: false,
27
43
  secretsPath: '',
28
44
  noCache: false,
29
45
  },
30
46
  ) {
31
- const { path, imageName, imagePath, dockerfileName, podmanSave, secrets, secretsPath, kindLoad, noCache } =
32
- options;
47
+ const {
48
+ path,
49
+ imageName,
50
+ imagePath,
51
+ dockerfileName,
52
+ podmanSave,
53
+ secrets,
54
+ secretsPath,
55
+ kindLoad,
56
+ noCache,
57
+ kubeadmLoad,
58
+ } = options;
33
59
  const podManImg = `localhost/${imageName}`;
34
60
  if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
35
61
  fs.mkdirSync(imagePath, { recursive: true });
@@ -54,11 +80,12 @@ class UnderpostImage {
54
80
  shellExec(
55
81
  `cd ${path}${secretsInput}&& sudo podman build -f ./${
56
82
  dockerfileName && typeof dockerfileName === 'string' ? dockerfileName : 'Dockerfile'
57
- } -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}${secretDockerInput}`,
83
+ } -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}${secretDockerInput} --network host`,
58
84
  );
59
85
 
60
86
  if (podmanSave === true) shellExec(`podman save -o ${tarFile} ${podManImg}`);
61
87
  if (kindLoad === true) shellExec(`sudo kind load image-archive ${tarFile}`);
88
+ if (kubeadmLoad === true) shellExec(`sudo ctr -n k8s.io images import ${tarFile}`);
62
89
  },
63
90
  },
64
91
  };
package/src/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import { getUnderpostRootPath, loadConf } from '../server/conf.js';
5
5
  import fs from 'fs-extra';
6
6
  import { commitData } from '../client/components/core/CommonJs.js';
7
7
  import { shellExec } from '../server/process.js';
8
+ import UnderpostLxd from './lxd.js';
8
9
 
9
10
  const underpostRootPath = getUnderpostRootPath();
10
11
  fs.existsSync(`${underpostRootPath}/.env`)
@@ -34,6 +35,7 @@ program
34
35
  .command('clone')
35
36
  .argument(`<uri>`, 'e.g. username/repository')
36
37
  .option('--bare', 'Clone only .git files')
38
+ .option('-g8', 'Use g8 repo extension')
37
39
  .description('Clone github repository')
38
40
  .action(Underpost.repo.clone);
39
41
 
@@ -42,6 +44,7 @@ program
42
44
  .argument('<path>', 'Absolute or relative directory')
43
45
  .argument(`<uri>`, 'e.g. username/repository')
44
46
  .description('Pull github repository')
47
+ .option('-g8', 'Use g8 repo extension')
45
48
  .action(Underpost.repo.pull);
46
49
 
47
50
  program
@@ -61,6 +64,7 @@ program
61
64
  .argument('<path>', 'Absolute or relative directory')
62
65
  .argument(`<uri>`, 'e.g. username/repository')
63
66
  .option('-f', 'Force push overwriting repository')
67
+ .option('-g8', 'Use g8 repo extension')
64
68
  .description('Push github repository')
65
69
  .action(Underpost.repo.push);
66
70
 
@@ -89,24 +93,31 @@ program
89
93
  .argument('[pod-name]', 'Optional pod name filter')
90
94
  .option('--reset', `Delete all clusters and prune all data and caches`)
91
95
  .option('--mariadb', 'Init with mariadb statefulset')
96
+ .option('--mysql', 'Init with mysql statefulset')
92
97
  .option('--mongodb', 'Init with mongodb statefulset')
98
+ .option('--postgresql', 'Init with postgresql statefulset')
93
99
  .option('--mongodb4', 'Init with mongodb 4.4 service')
100
+ .option('--istio', 'Init base istio cluster')
94
101
  .option('--valkey', 'Init with valkey service')
95
102
  .option('--contour', 'Init with project contour base HTTPProxy and envoy')
96
103
  .option('--cert-manager', 'Init with letsencrypt-prod ClusterIssuer')
104
+ .option('--dedicated-gpu', 'Init with dedicated gpu base resources env')
97
105
  .option('--info', 'Get all kinds objects deployed')
98
106
  .option('--full', 'Init with all statefulsets and services available')
99
107
  .option('--ns-use <ns-name>', 'Switches current context to namespace')
108
+ .option('--kubeadm', 'Init with kubeadm controlplane management')
100
109
  .option('--dev', 'init with dev cluster')
101
110
  .option('--list-pods', 'Display list pods information')
102
111
  .option('--info-capacity', 'display current total machine capacity info')
103
112
  .option('--info-capacity-pod', 'display current machine capacity pod info')
113
+ .option('--pull-image', 'Set optional pull associated image')
114
+ .option('--init-host', 'Install k8s node necessary cli env: kind, kubeadm, docker, podman, helm')
104
115
  .action(Underpost.cluster.init)
105
116
  .description('Manage cluster, for default initialization base kind cluster');
106
117
 
107
118
  program
108
119
  .command('deploy')
109
- .argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
120
+ .argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
110
121
  .argument('[env]', 'Optional environment, for default is development')
111
122
  .option('--remove', 'Delete deployments and services')
112
123
  .option('--sync', 'Sync deployments env, ports, and replicas')
@@ -119,6 +130,14 @@ program
119
130
  .option('--replicas <replicas>', 'Set custom number of replicas')
120
131
  .option('--versions <deployment-versions>', 'Comma separated custom deployment versions')
121
132
  .option('--traffic <traffic-versions>', 'Comma separated custom deployment traffic')
133
+ .option('--disable-update-deployment', 'Disable update deployments')
134
+ .option('--info-traffic', 'get traffic conf form current resources deployments')
135
+ .option('--kubeadm', 'Enable kubeadm context')
136
+ .option('--restore-hosts', 'Restore defautl etc hosts')
137
+ .option(
138
+ '--rebuild-clients-bundle',
139
+ 'Inside container, rebuild clients bundle, only static public or storage client files',
140
+ )
122
141
  .description('Manage deployment, for default deploy development pods')
123
142
  .action(Underpost.deploy.callback);
124
143
 
@@ -145,6 +164,7 @@ program
145
164
  .option('--dockerfile-name [dockerfile-name]', 'set Dockerfile name')
146
165
  .option('--podman-save', 'Export tar file from podman')
147
166
  .option('--kind-load', 'Import tar image to Kind cluster')
167
+ .option('--kubeadm-load', 'Import tar image to Kubeadm cluster')
148
168
  .option('--secrets', 'Dockerfile env secrets')
149
169
  .option('--secrets-path [secrets-path]', 'Dockerfile custom path env secrets')
150
170
  .option('--no-cache', 'Build without using cache')
@@ -153,6 +173,10 @@ program
153
173
 
154
174
  program
155
175
  .command('dockerfile-pull-base-images')
176
+ .option('--path [path]', 'Dockerfile path')
177
+ .option('--kind-load', 'Import tar image to Kind cluster')
178
+ .option('--kubeadm-load', 'Import tar image to Kubeadm cluster')
179
+ .option('--version', 'Set custom version')
156
180
  .description('Pull underpost dockerfile images requirements')
157
181
  .action(Underpost.image.dockerfile.pullBaseImages);
158
182
 
@@ -214,6 +238,7 @@ program
214
238
  .option('--deploy-id <deploy-id>', 'Deploy configuration id')
215
239
  .option('--pull', 'Download file')
216
240
  .option('--force', 'Force action')
241
+ .option('--storage-file-path <storage-file-path>', 'custom file storage path')
217
242
  .description('File storage management, for default upload file')
218
243
  .action(Underpost.fs.callback);
219
244
 
@@ -236,10 +261,20 @@ program
236
261
  .option('--ms-interval <ms-interval>', 'Custom ms interval delta time')
237
262
  .option('--now', 'Exec immediately monitor script')
238
263
  .option('--single', 'Disable recurrence')
264
+ .option('--replicas <replicas>', 'Set custom number of replicas')
239
265
  .option('--type <type>', 'Set custom monitor type')
266
+ .option('--sync', 'Sync with current proxy deployments proxy traffic')
240
267
  .description('Monitor health server management')
241
268
  .action(Underpost.monitor.callback);
242
269
 
270
+ program
271
+ .command('lxd')
272
+ .option('--init', 'Init lxd')
273
+ .option('--reset', 'Reset lxd on current machine')
274
+ .option('--install', 'Install lxd on current machine')
275
+ .description('Lxd management')
276
+ .action(UnderpostLxd.API.callback);
277
+
243
278
  const buildCliDoc = () => {
244
279
  let md = shellExec(`node bin help`, { silent: true, stdout: true }).split('Options:');
245
280
  const baseOptions =
package/src/cli/lxd.js ADDED
@@ -0,0 +1,19 @@
1
+ import { shellExec } from '../server/process.js';
2
+
3
+ class UnderpostLxd {
4
+ static API = {
5
+ async callback(options = { init: false, reset: false, install: false }) {
6
+ if (options.reset === true) {
7
+ shellExec(`sudo systemctl stop snap.lxd.daemon`);
8
+ shellExec(`sudo snap remove lxd --purge`);
9
+ }
10
+ if (options.install === true) shellExec(`sudo snap install lxd`);
11
+ if (options.init === true) {
12
+ shellExec(`sudo systemctl start snap.lxd.daemon`);
13
+ shellExec(`sudo systemctl status snap.lxd.daemon`);
14
+ }
15
+ },
16
+ };
17
+ }
18
+
19
+ export default UnderpostLxd;
@@ -5,6 +5,7 @@ import axios from 'axios';
5
5
  import UnderpostRootEnv from './env.js';
6
6
  import fs from 'fs-extra';
7
7
  import { shellExec } from '../server/process.js';
8
+ import { isInternetConnection } from '../server/dns.js';
8
9
 
9
10
  const logger = loggerFactory(import.meta);
10
11
 
@@ -13,7 +14,7 @@ class UnderpostMonitor {
13
14
  async callback(
14
15
  deployId,
15
16
  env = 'development',
16
- options = { now: false, single: false, msInterval: '', type: '' },
17
+ options = { now: false, single: false, msInterval: '', type: '', replicas: '', sync: false },
17
18
  commanderOptions,
18
19
  auxRouter,
19
20
  ) {
@@ -38,15 +39,43 @@ class UnderpostMonitor {
38
39
 
39
40
  const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
40
41
 
41
- logger.info(`${deployId} ${env}`, pathPortAssignmentData);
42
-
43
42
  let errorPayloads = [];
44
- let traffic = 'blue';
45
- const maxAttempts = Object.keys(pathPortAssignmentData)
46
- .map((host) => pathPortAssignmentData[host].length)
47
- .reduce((accumulator, value) => accumulator + value, 0);
43
+ if (options.sync === true) {
44
+ const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
45
+ if (currentTraffic) UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, currentTraffic);
46
+ }
47
+ let traffic = UnderpostRootEnv.API.get(`${deployId}-${env}-traffic`) ?? 'blue';
48
+ const maxAttempts = parseInt(
49
+ Object.keys(pathPortAssignmentData)
50
+ .map((host) => pathPortAssignmentData[host].length)
51
+ .reduce((accumulator, value) => accumulator + value, 0) * 2.5,
52
+ );
53
+
54
+ logger.info(`Init deploy monitor`, {
55
+ pathPortAssignmentData,
56
+ maxAttempts,
57
+ deployId,
58
+ env,
59
+ traffic,
60
+ });
61
+
62
+ const switchTraffic = () => {
63
+ if (traffic === 'blue') traffic = 'green';
64
+ else traffic = 'blue';
65
+ UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, traffic);
66
+ shellExec(
67
+ `node bin deploy --info-router --build-manifest --traffic ${traffic} --replicas ${
68
+ options.replicas ? options.replicas : 1
69
+ } ${deployId} ${env}`,
70
+ );
71
+ shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
72
+ };
48
73
 
49
74
  const monitor = async (reject) => {
75
+ if (UnderpostRootEnv.API.get(`monitor-init-callback-script`))
76
+ shellExec(UnderpostRootEnv.API.get(`monitor-init-callback-script`));
77
+ const currentTimestamp = new Date().getTime();
78
+ errorPayloads = errorPayloads.filter((e) => currentTimestamp - e.timestamp < 60 * 1000 * 5);
50
79
  logger.info(`[${deployId}-${env}] Check server health`);
51
80
  for (const host of Object.keys(pathPortAssignmentData)) {
52
81
  for (const instance of pathPortAssignmentData[host]) {
@@ -74,6 +103,7 @@ class UnderpostMonitor {
74
103
  status: error.status,
75
104
  code: error.code,
76
105
  errors: error.errors,
106
+ timestamp: new Date().getTime(),
77
107
  };
78
108
  if (errorPayload.status !== 404) {
79
109
  errorPayloads.push(errorPayload);
@@ -90,19 +120,17 @@ class UnderpostMonitor {
90
120
  fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
91
121
  );
92
122
 
123
+ shellExec(`kubectl delete configmap underpost-config`);
124
+ shellExec(
125
+ `kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
126
+ );
127
+
93
128
  for (const host of Object.keys(confServer)) {
94
129
  shellExec(`sudo kubectl delete HTTPProxy ${host}`);
95
130
  }
96
131
  shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic}`);
97
132
 
98
- if (traffic === 'blue') traffic = 'green';
99
- else traffic = 'blue';
100
-
101
- shellExec(
102
- `node bin deploy --info-router --build-manifest --traffic ${traffic} ${deployId} ${env}`,
103
- );
104
-
105
- shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
133
+ switchTraffic();
106
134
  }
107
135
 
108
136
  break;
@@ -116,7 +144,7 @@ class UnderpostMonitor {
116
144
  }
117
145
  errorPayloads = [];
118
146
  }
119
- logger.error('Error accumulator', errorPayloads.length);
147
+ logger.error(`Error accumulator ${deployId}-${env}-${traffic}`, errorPayloads.length);
120
148
  }
121
149
  });
122
150
  }
@@ -125,13 +153,19 @@ class UnderpostMonitor {
125
153
  if (options.now === true) await monitor();
126
154
  if (options.single === true) return;
127
155
  let optionsMsTimeout = parseInt(options.msInterval);
128
- if (isNaN(optionsMsTimeout)) optionsMsTimeout = 30000;
156
+ if (isNaN(optionsMsTimeout)) optionsMsTimeout = 60250; // 60.25 seconds
129
157
  let monitorTrafficName;
130
158
  let monitorPodName;
131
159
  const monitorCallBack = (resolve, reject) => {
132
160
  const envMsTimeout = UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-ms`);
133
161
  setTimeout(
134
162
  async () => {
163
+ const isOnline = await isInternetConnection();
164
+ if (!isOnline) {
165
+ logger.warn('No internet connection');
166
+ monitorCallBack(resolve, reject);
167
+ return;
168
+ }
135
169
  switch (options.type) {
136
170
  case 'blue-green':
137
171
  {
@@ -166,19 +200,30 @@ class UnderpostMonitor {
166
200
  default:
167
201
  break;
168
202
  }
169
- switch (UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-input`)) {
170
- case 'pause':
171
- monitorCallBack(resolve, reject);
172
- return;
173
- case 'restart':
174
- return reject();
175
- case 'stop':
176
- return resolve();
177
- default:
178
- await monitor(reject);
179
- monitorCallBack(resolve, reject);
180
- return;
181
- }
203
+ for (const monitorStatus of [
204
+ { key: `monitor-input`, value: UnderpostRootEnv.API.get(`monitor-input`) },
205
+ {
206
+ key: `${deployId}-${env}-monitor-input`,
207
+ value: UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-input`),
208
+ },
209
+ ])
210
+ switch (monitorStatus.value) {
211
+ case 'pause':
212
+ monitorCallBack(resolve, reject);
213
+ return;
214
+ case 'restart':
215
+ UnderpostRootEnv.API.delete(monitorStatus.key);
216
+ return reject();
217
+ case 'stop':
218
+ UnderpostRootEnv.API.delete(monitorStatus.key);
219
+ return resolve();
220
+ case 'blue-green-switch':
221
+ UnderpostRootEnv.API.delete(monitorStatus.key);
222
+ switchTraffic();
223
+ }
224
+ await monitor(reject);
225
+ monitorCallBack(resolve, reject);
226
+ return;
182
227
  },
183
228
  !isNaN(envMsTimeout) ? envMsTimeout : optionsMsTimeout,
184
229
  );
@@ -12,23 +12,25 @@ const logger = loggerFactory(import.meta);
12
12
 
13
13
  class UnderpostRepository {
14
14
  static API = {
15
- clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false }) {
15
+ clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false, g8: false }) {
16
+ const gExtension = options.g8 === true ? '.g8' : '.git';
16
17
  const repoName = gitUri.split('/').pop();
17
18
  if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
18
19
  shellExec(
19
20
  `git clone ${options?.bare === true ? ` --bare ` : ''}https://${
20
21
  process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
21
- }github.com/${gitUri}.git`,
22
+ }github.com/${gitUri}${gExtension}`,
22
23
  {
23
24
  disableLog: true,
24
25
  },
25
26
  );
26
27
  },
27
- pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') {
28
+ pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { g8: false }) {
29
+ const gExtension = options.g8 === true ? '.g8' : '.git';
28
30
  shellExec(
29
31
  `cd ${repoPath} && git pull https://${
30
32
  process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
31
- }github.com/${gitUri}.git`,
33
+ }github.com/${gitUri}${gExtension}`,
32
34
  {
33
35
  disableLog: true,
34
36
  },
@@ -57,9 +59,10 @@ class UnderpostRepository {
57
59
  shellExec(`cd ${repoPath} && git commit ${options?.empty ? `--allow-empty ` : ''}-m "${_message}"`);
58
60
  },
59
61
 
60
- push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false }) {
62
+ push(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template', options = { f: false, g8: false }) {
63
+ const gExtension = options.g8 === true ? '.g8' : '.git';
61
64
  shellExec(
62
- `cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}.git${
65
+ `cd ${repoPath} && git push https://${process.env.GITHUB_TOKEN}@github.com/${gitUri}${gExtension}${
63
66
  options?.f === true ? ' --force' : ''
64
67
  }`,
65
68
  {
@@ -19,8 +19,8 @@ const JoyStick = {
19
19
  /* border: 2px solid red; */
20
20
  left: 5px;
21
21
  bottom: 5px;
22
- height: 200px;
23
- width: 200px;
22
+ height: 175px;
23
+ width: 175px;
24
24
  z-index: 3;
25
25
  }
26
26
  .joy-img-background-${id} {
@@ -1629,6 +1629,7 @@ const Modal = {
1629
1629
  currentTopModalId: '',
1630
1630
  zIndexSync: function ({ idModal }) {
1631
1631
  setTimeout(() => {
1632
+ if (!this.Data[idModal]) return;
1632
1633
  const cleanTopModal = () => {
1633
1634
  Object.keys(this.Data).map((_idModal) => {
1634
1635
  if (this.Data[_idModal].options.zIndexSync && s(`.${_idModal}`)) s(`.${_idModal}`).style.zIndex = '3';
package/src/index.js CHANGED
@@ -30,7 +30,7 @@ class Underpost {
30
30
  * @type {String}
31
31
  * @memberof Underpost
32
32
  */
33
- static version = 'v2.8.652';
33
+ static version = 'v2.8.781';
34
34
  /**
35
35
  * Repository cli API
36
36
  * @static
@@ -1,6 +1,6 @@
1
1
  ARG BASE_DEBIAN=buster
2
2
 
3
- USER root
3
+ # USER root
4
4
 
5
5
  FROM debian:${BASE_DEBIAN}
6
6
 
@@ -927,7 +927,9 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
927
927
  const confServer = loadReplicas(
928
928
  JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
929
929
  );
930
+ const hosts = {};
930
931
  for (const host of Object.keys(confServer)) {
932
+ hosts[host] = {};
931
933
  for (const path of Object.keys(confServer[host])) {
932
934
  if (!confServer[host][path].db) continue;
933
935
  const { singleReplica, replicas, db } = confServer[host][path];
@@ -940,6 +942,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
940
942
  );
941
943
  for (const _host of Object.keys(confServerReplica)) {
942
944
  for (const _path of Object.keys(confServerReplica[_host])) {
945
+ hosts[host][_path] = { replica: { host, path } };
943
946
  confServerReplica[_host][_path].valkey = valkey;
944
947
  switch (provider) {
945
948
  case 'mongoose':
@@ -954,7 +957,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
954
957
  'utf8',
955
958
  );
956
959
  }
957
- }
960
+ } else hosts[host][path] = {};
958
961
  confServer[host][path].valkey = valkey;
959
962
  switch (provider) {
960
963
  case 'mongoose':
@@ -964,6 +967,7 @@ const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
964
967
  }
965
968
  }
966
969
  fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
970
+ return { hosts };
967
971
  };
968
972
 
969
973
  const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
package/src/server/dns.js CHANGED
@@ -5,6 +5,9 @@ import validator from 'validator';
5
5
  import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
6
6
  import { loggerFactory } from './logger.js';
7
7
  import UnderpostRootEnv from '../cli/env.js';
8
+ import dns from 'node:dns';
9
+ import os from 'node:os';
10
+ import { shellExec } from './process.js';
8
11
 
9
12
  dotenv.config();
10
13
 
@@ -18,35 +21,59 @@ const ip = {
18
21
  },
19
22
  };
20
23
 
24
+ const isInternetConnection = (domain = 'google.com') =>
25
+ new Promise((resolve) => dns.lookup(domain, {}, (err) => resolve(err ? false : true)));
26
+
27
+ // export INTERFACE=$(ip route | grep default | cut -d ' ' -f 5)
28
+ // export IP_ADDRESS=$(ip -4 addr show dev $INTERFACE | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
29
+ const getLocalIPv4Address = () =>
30
+ os.networkInterfaces()[
31
+ shellExec(`ip route | grep default | cut -d ' ' -f 5`, {
32
+ stdout: true,
33
+ silent: true,
34
+ disableLog: true,
35
+ }).trim()
36
+ ].find((i) => i.family === 'IPv4').address;
37
+
21
38
  class Dns {
22
39
  static callback = async function (deployList) {
23
40
  // Network topology configuration:
24
41
  // LAN -> [NAT-VPS](modem/router device) -> WAN
25
42
  // enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
26
- // disabled local red DHCP
43
+
44
+ // Enabling DHCP
45
+ // Navigate to Subnets > VLAN > Configure DHCP.
46
+ // Select the appropriate DHCP options (Managed or Relay).
47
+ // Save and apply changes.
48
+
27
49
  // verify inet ip proxy server address
28
50
  // DHCP (Dynamic Host Configuration Protocol) LAN reserver IP -> MAC ID
29
51
  // LAN server or device's local servers port -> 3000-3100 (2999-3101)
30
52
  // DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
31
53
  // Forward the router's TCP/UDP ports to the LAN device's IP address
32
- for (const _deployId of deployList.split(',')) {
33
- const deployId = _deployId.trim();
34
- const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
35
- const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
36
- const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
37
-
38
- let testIp;
39
-
40
- try {
41
- testIp = await ip.public.ipv4();
42
- } catch (error) {
43
- logger.error(error, { testIp, stack: error.stack });
44
- }
54
+ const isOnline = await isInternetConnection();
55
+
56
+ if (!isOnline) return;
45
57
 
46
- const currentIp = UnderpostRootEnv.API.get('ip');
58
+ let testIp;
47
59
 
48
- if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && currentIp !== testIp) {
49
- logger.info(`new ip`, testIp);
60
+ try {
61
+ testIp = await ip.public.ipv4();
62
+ } catch (error) {
63
+ logger.error(error, { testIp, stack: error.stack });
64
+ }
65
+
66
+ const currentIp = UnderpostRootEnv.API.get('ip');
67
+
68
+ if (validator.isIP(testIp) && currentIp !== testIp) {
69
+ logger.info(`new ip`, testIp);
70
+ UnderpostRootEnv.API.set('monitor-input', 'pause');
71
+
72
+ for (const _deployId of deployList.split(',')) {
73
+ const deployId = _deployId.trim();
74
+ const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
75
+ const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
76
+ const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
50
77
  for (const recordType of Object.keys(confCronData.records)) {
51
78
  switch (recordType) {
52
79
  case 'A':
@@ -68,6 +95,7 @@ class Dns {
68
95
  if (verifyIp === testIp) {
69
96
  logger.info('ip updated successfully', testIp);
70
97
  UnderpostRootEnv.API.set('ip', testIp);
98
+ UnderpostRootEnv.API.delete('monitor-input');
71
99
  } else logger.error('ip not updated', testIp);
72
100
  } catch (error) {
73
101
  logger.error(error, error.stack);
@@ -102,3 +130,5 @@ class Dns {
102
130
  }
103
131
 
104
132
  export default Dns;
133
+
134
+ export { Dns, ip, isInternetConnection, getLocalIPv4Address };
@@ -142,6 +142,8 @@ const buildRuntime = async () => {
142
142
  // if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
143
143
  // $_SERVER['HTTPS'] = 'on';
144
144
  // }
145
+ // For plugins:
146
+ // define( 'FS_METHOD', 'direct' );
145
147
 
146
148
  // ErrorDocument 404 /custom_404.html
147
149
  // ErrorDocument 500 /custom_50x.html
@@ -1,5 +1,4 @@
1
1
  import UnderpostDeploy from '../cli/deploy.js';
2
- import UnderpostMonitor from '../cli/monitor.js';
3
2
  import fs from 'fs-extra';
4
3
  import { awaitDeployMonitor } from './conf.js';
5
4
  import { actionInitLog, loggerFactory } from './logger.js';