underpost 2.8.48 → 2.8.51

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/bin/build.js CHANGED
@@ -36,7 +36,7 @@ if (process.argv.includes('clean')) {
36
36
 
37
37
  if (process.argv.includes('conf')) {
38
38
  for (const _confName of (confName === 'dd'
39
- ? fs.readFileSync(`./engine-private/deploy/dd-router`, 'utf8')
39
+ ? fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8')
40
40
  : confName
41
41
  ).split(',')) {
42
42
  const _repoName = `engine-${_confName.split('dd-')[1]}`;
@@ -52,6 +52,12 @@ if (process.argv.includes('conf')) {
52
52
  fs.removeSync(toPath);
53
53
  fs.mkdirSync(toPath, { recursive: true });
54
54
  fs.copySync(`./engine-private/conf/${_confName}`, toPath);
55
+ if (fs.existsSync(`./engine-private/replica`)) {
56
+ const replicas = await fs.readdir(`./engine-private/replica`);
57
+ for (const replica of replicas)
58
+ if (replica.match(_confName))
59
+ fs.copySync(`./engine-private/replica/${replica}`, `../${privateRepoName}/replica/${replica}`);
60
+ }
55
61
  shellExec(
56
62
  `cd ../${privateRepoName}` +
57
63
  ` && git add .` +
package/bin/deploy.js CHANGED
@@ -141,28 +141,7 @@ try {
141
141
  loadConf(process.argv[3], process.argv[4]);
142
142
  break;
143
143
  }
144
- case 'run':
145
- {
146
- if (process.argv.includes('replicas')) {
147
- const deployGroupId = getDeployGroupId();
148
- const dataDeploy = getDataDeploy({
149
- deployId: process.argv[3],
150
- buildSingleReplica: true,
151
- deployGroupId,
152
- });
153
- if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
154
- await deployRun(dataDeploy);
155
- } else {
156
- loadConf(process.argv[3]);
157
- shellExec(`npm start ${process.argv.includes('maintenance') ? 'maintenance' : ''}`);
158
- }
159
- }
160
- break;
161
144
 
162
- case 'remove-await-deploy': {
163
- if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
164
- break;
165
- }
166
145
  case 'new-nodejs-app':
167
146
  {
168
147
  const deployId = process.argv[3];
@@ -229,6 +208,7 @@ try {
229
208
  break;
230
209
  case 'build-full-client':
231
210
  {
211
+ dotenv.config({ override: true });
232
212
  if (!process.argv[3]) process.argv[3] = 'default';
233
213
  const { deployId, folder } = loadConf(process.argv[3]);
234
214
 
@@ -254,7 +234,7 @@ try {
254
234
  serverConf[host][path].replicas.map((replica) => buildReplicaId({ deployId, replica })),
255
235
  );
256
236
 
257
- shellExec(Cmd.replica(deployId, host, path));
237
+ // shellExec(Cmd.replica(deployId, host, path));
258
238
  }
259
239
  }
260
240
  }
@@ -263,7 +243,7 @@ try {
263
243
  await buildClient();
264
244
 
265
245
  for (const replicaDeployId of deployIdSingleReplicas) {
266
- shellExec(Cmd.conf(replicaDeployId));
246
+ shellExec(Cmd.conf(replicaDeployId, process.env.NODE_ENV));
267
247
  shellExec(Cmd.build(replicaDeployId));
268
248
  }
269
249
  }
@@ -456,12 +436,13 @@ try {
456
436
  case 'run-macro':
457
437
  {
458
438
  if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
459
- const dataDeploy = getDataDeploy({ deployGroupId: process.argv[3], buildSingleReplica: true });
439
+ const dataDeploy = getDataDeploy({
440
+ deployGroupId: process.argv[3],
441
+ buildSingleReplica: true,
442
+ deployIdConcat: ['dd-proxy', 'dd-cron'],
443
+ });
460
444
  if (!process.argv[4]) await setUpProxyMaintenanceServer({ deployGroupId: process.argv[3] });
461
- await deployRun(
462
- process.argv[4] ? dataDeploy.filter((d) => d.deployId.match(process.argv[4])) : dataDeploy,
463
- true,
464
- );
445
+ await deployRun(process.argv[4] ? dataDeploy.filter((d) => d.deployId.match(process.argv[4])) : dataDeploy);
465
446
  }
466
447
  break;
467
448
 
package/bin/index.js CHANGED
@@ -8,8 +8,8 @@ import { getNpmRootPath, loadConf } from '../src/server/conf.js';
8
8
  import fs from 'fs-extra';
9
9
  import { commitData } from '../src/client/components/core/CommonJs.js';
10
10
  import UnderpostScript from '../src/cli/script.js';
11
- import { shellExec } from '../src/server/process.js';
12
11
  import UnderpostDB from '../src/cli/db.js';
12
+ import UnderpostCron from '../src/cli/cron.js';
13
13
 
14
14
  const npmRoot = getNpmRootPath();
15
15
  const underpostRoot = `${npmRoot}/underpost/.env`;
@@ -63,7 +63,7 @@ program
63
63
 
64
64
  program
65
65
  .command('env')
66
- .argument('<deploy-id>', 'deploy configuration id')
66
+ .argument('<deploy-id>', `deploy configuration id, if 'clean' restore default`)
67
67
  .argument('[env]', 'Optional environment, for default is production')
68
68
  .description('Set environment variables files and conf related to <deploy-id>')
69
69
  .action(loadConf);
@@ -99,7 +99,7 @@ program
99
99
 
100
100
  program
101
101
  .command('deploy')
102
- .argument('<deploy-list>', 'Deploy id list, e.g. default-a, default-b')
102
+ .argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
103
103
  .argument('[env]', 'Optional environment, for default is development')
104
104
  .option('--remove', 'Delete deployments and services')
105
105
  .option('--sync', 'Sync deployments env, ports, and replicas')
@@ -127,6 +127,7 @@ program
127
127
  .command('dockerfile-node-script')
128
128
  .argument('<deploy-id>', 'Deploy configuration id')
129
129
  .argument('[env]', 'Optional environment, for default is development')
130
+ .option('--run', 'Run custom entry point script')
130
131
  .description('Dockerfile custom node build script')
131
132
  .action(Underpost.image.dockerfile.script);
132
133
 
@@ -153,7 +154,7 @@ program
153
154
 
154
155
  program
155
156
  .command('db')
156
- .argument('<deploy-list>', 'Deploy id list, e.g. default-a, default-b')
157
+ .argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
157
158
  .option('--import', 'Import container backups from repositories')
158
159
  .option('--export', 'Export container backups to repositories')
159
160
  .description('Manage databases')
@@ -169,12 +170,22 @@ program
169
170
  )
170
171
  .action((...args) => Underpost.script[args[0]](args[1], args[2]));
171
172
 
173
+ program
174
+ .command('cron')
175
+ .argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
176
+ .argument('[job-list]', `Deploy id list, e.g. ${Object.keys(UnderpostCron.JOB)}, for default all available jobs`)
177
+ .option('--disable-kind-cluster', 'Disable kind cluster configuration')
178
+ .option('--init', 'Init cron jobs for cron job default deploy id')
179
+ .description('Cron jobs management')
180
+ .action(Underpost.cron.callback);
181
+
172
182
  program
173
183
  .command('test')
174
- .argument('[deploy-list]', 'Deploy id list, e.g. default-a, default-b')
184
+ .argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
175
185
  .description('Manage Test, for default run current underpost default test')
176
186
  .option('--inside-container', 'Inside container execution context')
177
187
  .option('--sh', 'Copy to clipboard, container entrypoint shell command')
188
+ .option('--logs', 'Display container logs')
178
189
  .action(Underpost.test.callback);
179
190
 
180
191
  program.parse();
package/bin/util.js CHANGED
@@ -112,14 +112,6 @@ try {
112
112
  fs.writeFileSync('b64-image', `data:image/jpg;base64,${fs.readFileSync(process.argv[3]).toString('base64')}`);
113
113
  break;
114
114
 
115
- case 'clean-env': {
116
- shellExec(`git checkout package.json`);
117
- shellExec(`git checkout .env.production`);
118
- shellExec(`git checkout .env.development`);
119
- shellExec(`git checkout .env.test`);
120
- shellExec(`git checkout jsdoc.json`);
121
- break;
122
- }
123
115
  case 'get-keys': {
124
116
  const sentence = fs.existsSync('./_')
125
117
  ? fs.readFileSync('./_', 'utf8')
@@ -58,7 +58,7 @@ services:
58
58
  cpus: '0.25'
59
59
  memory: 20M
60
60
  labels: # labels in Compose file instead of Dockerfile
61
- engine.version: '2.8.48'
61
+ engine.version: '2.8.51'
62
62
  networks:
63
63
  - load-balancer
64
64
 
@@ -16,25 +16,27 @@ spec:
16
16
  - -c
17
17
  - |
18
18
  # Perform backup
19
- mongodump -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --host=mongodb-service --port=27017 --out=/backup/$(date +\%Y-\%m-\%dT\%H-\%M-\%S)
19
+ mongodump --host=mongodb-service --port=27017 --out=/backup/$(date +\%Y-\%m-\%dT\%H-\%M-\%S)
20
20
  # Remove backups older than 7 days
21
21
  find /backup -type d -mtime +7 -exec rm -rf {} +
22
22
  volumeMounts:
23
23
  - name: backup-storage
24
24
  mountPath: /backup
25
- env:
26
- - name: MONGO_INITDB_ROOT_USERNAME
27
- valueFrom:
28
- secretKeyRef:
29
- name: mongodb-secret
30
- key: username
31
- - name: MONGO_INITDB_ROOT_PASSWORD
32
- valueFrom:
33
- secretKeyRef:
34
- name: mongodb-secret
35
- key: password
36
25
  restartPolicy: Never
37
26
  volumes:
38
27
  - name: backup-storage
39
28
  persistentVolumeClaim:
40
29
  claimName: backup-pvc
30
+ # mongodump -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --host=mongodb-service --port=27017 --out=/backup/$(date +\%Y-\%m-\%dT\%H-\%M-\%S)
31
+
32
+ # env:
33
+ # - name: MONGO_INITDB_ROOT_USERNAME
34
+ # valueFrom:
35
+ # secretKeyRef:
36
+ # name: mongodb-secret
37
+ # key: username
38
+ # - name: MONGO_INITDB_ROOT_PASSWORD
39
+ # valueFrom:
40
+ # secretKeyRef:
41
+ # name: mongodb-secret
42
+ # key: password
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "2.8.48",
5
+ "version": "2.8.51",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
@@ -9,7 +9,7 @@ const CoreService = {
9
9
  /** @type {import('./core.model.js').CoreModel} */
10
10
  const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
11
11
  if (req.path.startsWith('/sh')) {
12
- if (req.body.print) return shellExec(req.body.sh, { stdout: true });
12
+ if (req.body.stdout) return shellExec(req.body.sh, { stdout: true });
13
13
  shellExec(req.body.sh, { async: true });
14
14
  return 'Command "' + req.body.sh + '" running';
15
15
  }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * UnderpostCron CLI index module
3
+ * @module src/cli/cron.js
4
+ * @namespace UnderpostCron
5
+ */
6
+
7
+ import Underpost from '../index.js';
8
+ import BackUp from '../server/backup.js';
9
+ import { Cmd } from '../server/conf.js';
10
+ import Dns from '../server/dns.js';
11
+ import { netWorkCron, saveRuntimeCron } from '../server/network.js';
12
+ import { shellExec } from '../server/process.js';
13
+ import fs from 'fs-extra';
14
+
15
+ /**
16
+ * UnderpostCron main module methods
17
+ * @class
18
+ * @memberof UnderpostCron
19
+ */
20
+ class UnderpostCron {
21
+ static JOB = {
22
+ /**
23
+ * DNS cli API
24
+ * @static
25
+ * @type {Dns}
26
+ * @memberof UnderpostCron
27
+ */
28
+ dns: Dns,
29
+ /**
30
+ * BackUp cli API
31
+ * @static
32
+ * @type {BackUp}
33
+ * @memberof UnderpostCron
34
+ */
35
+ backup: BackUp,
36
+ };
37
+ static API = {
38
+ /**
39
+ * Run the cron jobs
40
+ * @static
41
+ * @param {String} deployList - Comma separated deploy ids
42
+ * @param {String} jobList - Comma separated job ids
43
+ * @return {void}
44
+ * @memberof UnderpostCron
45
+ */
46
+ callback: async function (
47
+ deployList = 'default',
48
+ jobList = Object.keys(UnderpostCron.JOB),
49
+ options = { disableKindCluster: false, init: false },
50
+ ) {
51
+ if (options.init === true) {
52
+ await Underpost.test.setUpInfo();
53
+ const jobDeployId = fs.readFileSync('./engine-private/deploy/dd.cron', 'utf8').trim();
54
+ deployList = fs.readFileSync('./engine-private/deploy/dd.router', 'utf8').trim();
55
+ const confCronConfig = JSON.parse(fs.readFileSync(`./engine-private/conf/${jobDeployId}/conf.cron.json`));
56
+ if (confCronConfig.jobs && Object.keys(confCronConfig.jobs).length > 0) {
57
+ for (const job of Object.keys(confCronConfig.jobs)) {
58
+ const name = `${jobDeployId}-${job}`;
59
+ let deployId;
60
+ shellExec(Cmd.delete(name));
61
+ switch (job) {
62
+ case 'dns':
63
+ deployId = jobDeployId;
64
+ break;
65
+
66
+ default:
67
+ deployId = deployList;
68
+ break;
69
+ }
70
+ shellExec(Cmd.cron(deployId, job, name, confCronConfig.jobs[job].expression, options));
71
+ netWorkCron.push({
72
+ deployId,
73
+ jobId: job,
74
+ expression: confCronConfig.jobs[job].expression,
75
+ });
76
+ }
77
+ }
78
+ await saveRuntimeCron();
79
+ if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
80
+ return;
81
+ }
82
+ for (const _jobId of jobList.split(',')) {
83
+ const jobId = _jobId.trim();
84
+ if (UnderpostCron.JOB[jobId]) await UnderpostCron.JOB[jobId].callback(deployList, options);
85
+ }
86
+ },
87
+ };
88
+ }
89
+
90
+ export default UnderpostCron;
package/src/cli/deploy.js CHANGED
@@ -17,8 +17,8 @@ const logger = loggerFactory(import.meta);
17
17
  class UnderpostDeploy {
18
18
  static API = {
19
19
  sync(deployList) {
20
- const deployGroupId = '_dd';
21
- fs.writeFileSync(`./engine-private/deploy/${deployGroupId}.json`, JSON.stringify(deployList.split(',')), 'utf8');
20
+ const deployGroupId = 'dd.tmp';
21
+ fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
22
22
  return getDataDeploy({
23
23
  buildSingleReplica: true,
24
24
  deployGroupId,
@@ -182,8 +182,8 @@ spec:
182
182
  env = 'development',
183
183
  options = { remove: false, infoRouter: false, sync: false, buildManifest: false },
184
184
  ) {
185
- if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd-router`))
186
- deployList = fs.readFileSync(`./engine-private/deploy/dd-router`, 'utf8');
185
+ if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
186
+ deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
187
187
  if (options.sync) UnderpostDeploy.API.sync(deployList);
188
188
  if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env);
189
189
  if (options.infoRouter === true)
package/src/cli/image.js CHANGED
@@ -3,6 +3,7 @@ import Underpost from '../index.js';
3
3
  import { shellExec } from '../server/process.js';
4
4
  import dotenv from 'dotenv';
5
5
  import { getNpmRootPath } from '../server/conf.js';
6
+ import { timer } from '../client/components/core/CommonJs.js';
6
7
 
7
8
  dotenv.config();
8
9
 
@@ -12,7 +13,7 @@ class UnderpostImage {
12
13
  pullBaseImages() {
13
14
  shellExec(`sudo podman pull docker.io/library/debian:buster`);
14
15
  },
15
- build(deployId = 'default', env = 'development', path = '.', imageArchive = false) {
16
+ build(deployId = 'default', env = 'development', path = '.', options = { imageArchive: false }) {
16
17
  const imgName = `${deployId}-${env}:${Underpost.version}`;
17
18
  const podManImg = `localhost/${imgName}`;
18
19
  const imagesStoragePath = `./images`;
@@ -29,7 +30,7 @@ class UnderpostImage {
29
30
  secretDockerInput += ` --secret id=${key},env=${key} \ `;
30
31
  }
31
32
  // --rm --no-cache
32
- if (imageArchive !== true) {
33
+ if (options.imageArchive !== true) {
33
34
  fs.copyFile(`${getNpmRootPath()}/underpost/.env`, `${path}/.env.underpost`);
34
35
  shellExec(
35
36
  `cd ${path}${secrets}&& sudo podman build -f ./Dockerfile -t ${imgName} --pull=never --cap-add=CAP_AUDIT_WRITE${secretDockerInput}`,
@@ -39,7 +40,7 @@ class UnderpostImage {
39
40
  }
40
41
  shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
41
42
  },
42
- async script(deployId = 'default', env = 'development') {
43
+ async script(deployId = 'default', env = 'development', options = { run: false }) {
43
44
  switch (deployId) {
44
45
  case 'dd-lampp':
45
46
  {
@@ -99,6 +100,24 @@ class UnderpostImage {
99
100
  }
100
101
  shellExec(`node bin/deploy conf ${deployId} ${env}`);
101
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
+ }
102
121
  },
103
122
  },
104
123
  };
@@ -15,7 +15,7 @@ class UnderpostRepository {
15
15
  clone(gitUri = 'underpostnet/pwa-microservices-template', options = { bare: false }) {
16
16
  const repoName = gitUri.split('/').pop();
17
17
  if (fs.existsSync(`./${repoName}`)) fs.removeSync(`./${repoName}`);
18
- return shellExec(
18
+ shellExec(
19
19
  `git clone ${options?.bare === true ? ` --bare ` : ''}https://${
20
20
  process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
21
21
  }github.com/${gitUri}.git`,
@@ -23,16 +23,6 @@ class UnderpostRepository {
23
23
  disableLog: true,
24
24
  },
25
25
  );
26
- if (process.env.GITHUB_TOKEN) {
27
- shellExec(
28
- `git clone https://${
29
- process.env.GITHUB_TOKEN ? `${process.env.GITHUB_TOKEN}@` : ''
30
- }github.com/${gitUri}-private.git`,
31
- );
32
- fs.moveSync(`./${repoName}-private`, `./${repoName}/engine-private`, {
33
- overwrite: true,
34
- });
35
- }
36
26
  },
37
27
  pull(repoPath = './', gitUri = 'underpostnet/pwa-microservices-template') {
38
28
  shellExec(
package/src/cli/test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MariaDB } from '../db/mariadb/MariaDB.js';
2
2
  import { getNpmRootPath } from '../server/conf.js';
3
- import { actionInitLog, loggerFactory } from '../server/logger.js';
3
+ import { actionInitLog, loggerFactory, setUpInfo } from '../server/logger.js';
4
4
  import { pbcopy, shellExec } from '../server/process.js';
5
5
  import UnderpostDeploy from './deploy.js';
6
6
 
@@ -28,10 +28,13 @@ class UnderpostTest {
28
28
  actionInitLog();
29
29
  shellExec(`cd ${getNpmRootPath()}/underpost && npm run test`);
30
30
  },
31
- async callback(deployList = '', options = { insideContainer: false, sh: false }) {
32
- if (options.sh === true) {
31
+ async callback(deployList = '', options = { insideContainer: false, sh: false, logs: false }) {
32
+ if (options.sh === true || options.logs === true) {
33
33
  const [pod] = UnderpostDeploy.API.getPods(deployList);
34
- if (pod) return pbcopy(`sudo kubectl exec -it ${pod.NAME} -- sh`);
34
+ if (pod) {
35
+ if (options.sh) return pbcopy(`sudo kubectl exec -it ${pod.NAME} -- sh`);
36
+ if (options.logs) return shellExec(`sudo kubectl logs -f ${pod.NAME}`);
37
+ }
35
38
  return logger.warn(`Couldn't find pods in deployment`, deployList);
36
39
  }
37
40
  if (deployList) {
@@ -761,6 +761,7 @@ const renderWave = ({ id }) => {
761
761
  const cssTokensEffect = {};
762
762
  const cssTokensContainer = {};
763
763
  const cssEffect = async (containerSelector, event) => {
764
+ return;
764
765
  // Array.from(event.target.classList)
765
766
  let offsetX, offsetY;
766
767
  if (Array.from(event.srcElement.classList).includes('ripple') && cssTokensContainer[containerSelector]) {
package/src/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import UnderpostCluster from './cli/cluster.js';
8
+ import UnderpostCron from './cli/cron.js';
8
9
  import UnderpostDB from './cli/db.js';
9
10
  import UnderpostDeploy from './cli/deploy.js';
10
11
  import UnderpostRootEnv from './cli/env.js';
@@ -26,7 +27,7 @@ class Underpost {
26
27
  * @type {String}
27
28
  * @memberof Underpost
28
29
  */
29
- static version = 'v2.8.48';
30
+ static version = 'v2.8.51';
30
31
  /**
31
32
  * Repository cli API
32
33
  * @static
@@ -90,6 +91,13 @@ class Underpost {
90
91
  * @memberof Underpost
91
92
  */
92
93
  static deploy = UnderpostDeploy.API;
94
+ /**
95
+ * Cron cli API
96
+ * @static
97
+ * @type {UnderpostCron.API}
98
+ * @memberof Underpost
99
+ */
100
+ static cron = UnderpostCron.API;
93
101
  }
94
102
 
95
103
  const up = Underpost;
@@ -1,120 +1,76 @@
1
1
  import fs from 'fs-extra';
2
2
  import { loggerFactory } from './logger.js';
3
- import { shellCd, shellExec } from './process.js';
4
- import { getCronBackUpFolder, getDataDeploy } from './conf.js';
3
+ import { shellExec } from './process.js';
4
+ import { getCronBackUpFolder } from './conf.js';
5
5
  import dotenv from 'dotenv';
6
6
 
7
7
  dotenv.config();
8
8
 
9
9
  const logger = loggerFactory(import.meta);
10
10
 
11
- const BackUpManagement = {
12
- repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_BACKUP_REPO}.git`,
13
- Init: async function ({ deployId }) {
14
- const Callback = async function () {
15
- const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
11
+ class BackUp {
12
+ static callback = async function (deployList, options = { disableKindCluster: false }) {
13
+ if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
14
+ deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
16
15
 
17
- const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
16
+ logger.info('init backups callback', deployList);
17
+ await logger.setUpInfo();
18
+ const currentDate = new Date().getTime();
19
+ const maxBackupRetention = 5;
18
20
 
19
- const { backups } = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
21
+ if (!fs.existsSync('./engine-private/cron-backups'))
22
+ fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
20
23
 
21
- if (!backups) return;
24
+ for (const _deployId of deployList.split(',')) {
25
+ const deployId = _deployId.trim();
26
+ if (!deployId) continue;
22
27
 
23
- logger.info('init backups callback');
24
- await logger.setUpInfo();
25
-
26
- const currentDate = new Date().getTime();
27
-
28
- if (!fs.existsSync('./engine-private/cron-backups'))
29
- fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
30
-
31
- for (const deployGroupData of backups) {
32
- const { deployGroupId } = deployGroupData;
33
- const dataDeploy = getDataDeploy({ deployGroupId });
34
-
35
- for (const deployObj of dataDeploy) {
36
- const { deployId, replicaHost } = deployObj;
37
-
38
- if (replicaHost) continue;
39
-
40
- const confServer = JSON.parse(
41
- fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
42
- ? fs.readFileSync(`./engine-private/replica/${deployId}/conf.server.json`, 'utf8')
43
- : fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
44
- );
45
-
46
- for (const host of Object.keys(confServer))
47
- for (const path of Object.keys(confServer[host])) {
48
- // retention policy
49
- let { db, backupFrequency, maxBackupRetention, singleReplica, wp, git, directory } =
50
- confServer[host][path];
51
-
52
- if (!db || singleReplica) continue;
53
-
54
- if (!backupFrequency) backupFrequency = 'daily';
55
- if (!maxBackupRetention) maxBackupRetention = 5;
56
-
57
- const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
58
- if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
59
- // .isDirectory()
60
- const files = await fs.readdir(backUpPath, { withFileTypes: true });
61
-
62
- const currentBackupsDirs = files
63
- .map((fileObj) => parseInt(fileObj.name))
64
- .sort((a, b) => a - b)
65
- .reverse();
28
+ if (options.disableKindCluster !== true) {
29
+ shellExec(`underpost db --export ${deployId}`);
30
+ continue;
31
+ }
66
32
 
67
- switch (backupFrequency) {
68
- case 'daily':
33
+ const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
69
34
 
70
- default:
71
- // if (currentBackupsDirs[0] && currentDate - currentBackupsDirs[0] < 1000 * 60 * 60 * 24) continue;
72
- break;
73
- }
35
+ for (const host of Object.keys(confServer))
36
+ for (const path of Object.keys(confServer[host])) {
37
+ // retention policy
38
+ const { db } = confServer[host][path];
39
+ if (!db) continue;
40
+ logger.info('Init backup', { host, path, db });
74
41
 
75
- for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
76
- const removePathRetention = `${backUpPath}/${retentionPath}`;
77
- logger.info('Remove backup folder', removePathRetention);
78
- fs.removeSync(removePathRetention);
79
- }
42
+ const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
43
+ if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
44
+ // .isDirectory()
45
+ const files = await fs.readdir(backUpPath, { withFileTypes: true });
80
46
 
81
- fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
47
+ const currentBackupsDirs = files
48
+ .map((fileObj) => parseInt(fileObj.name))
49
+ .sort((a, b) => a - b)
50
+ .reverse();
82
51
 
83
- shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
52
+ for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
53
+ const removePathRetention = `${backUpPath}/${retentionPath}`;
54
+ logger.info('Remove backup folder', removePathRetention);
55
+ fs.removeSync(removePathRetention);
56
+ }
84
57
 
85
- if (wp) {
86
- const repoUrl = `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${git
87
- .split('/')
88
- .pop()}.git`;
58
+ fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
89
59
 
90
- shellExec(
91
- `cd ${directory}` +
92
- ` && git pull ${repoUrl}` +
93
- ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
94
- ` && git push ${repoUrl}`,
95
- {
96
- disableLog: true,
97
- },
98
- );
99
- }
100
- }
60
+ shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
101
61
  }
102
- }
103
62
  shellExec(
104
63
  `cd ./engine-private/cron-backups` +
105
- ` && git pull ${BackUpManagement.repoUrl}` +
106
- ` && git add . && git commit -m "backup ${new Date().toLocaleDateString()}"` +
107
- ` && git push ${BackUpManagement.repoUrl}`,
64
+ ` && underpost pull . underpostnet/cron-backups` +
65
+ ` && git add .` +
66
+ ` && underpost cmt . backup cron-job '${new Date().toLocaleDateString()}'` +
67
+ ` && underpost push . underpostnet/cron-backups`,
108
68
  {
109
69
  disableLog: true,
110
70
  },
111
71
  );
112
- };
113
- await Callback();
114
- BackUpManagement.Callback = Callback;
115
- return Callback;
116
- },
117
- Callback: async function (params) {},
118
- };
72
+ }
73
+ };
74
+ }
119
75
 
120
- export { BackUpManagement };
76
+ export default BackUp;
@@ -98,6 +98,14 @@ const Config = {
98
98
  };
99
99
 
100
100
  const loadConf = (deployId, envInput, subConf) => {
101
+ if (deployId === 'clean') {
102
+ shellExec(`git checkout package.json`);
103
+ shellExec(`git checkout .env.production`);
104
+ shellExec(`git checkout .env.development`);
105
+ shellExec(`git checkout .env.test`);
106
+ shellExec(`git checkout jsdoc.json`);
107
+ return;
108
+ }
101
109
  const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
102
110
  ? `./engine-private/replica/${deployId}`
103
111
  : `./engine-private/conf/${deployId}`;
@@ -590,9 +598,25 @@ const cliSpinner = async (time = 5000, message0, message1, color, type = 'dots')
590
598
  const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
591
599
 
592
600
  const getDataDeploy = (
593
- options = { buildSingleReplica: false, deployGroupId: '', deployId: '', disableSyncEnvPort: false },
601
+ options = {
602
+ buildSingleReplica: false,
603
+ deployGroupId: '',
604
+ deployId: '',
605
+ disableSyncEnvPort: false,
606
+ deployIdConcat: [],
607
+ },
594
608
  ) => {
595
- let dataDeploy = JSON.parse(fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.json`, 'utf8'));
609
+ let dataDeploy =
610
+ options.deployGroupId === 'dd'
611
+ ? fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.router`, 'utf8')
612
+ : fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}`, 'utf8');
613
+
614
+ dataDeploy = dataDeploy
615
+ .split(',')
616
+ .map((deployId) => deployId.trim())
617
+ .filter((deployId) => deployId);
618
+
619
+ if (options.deployIdConcat) dataDeploy = dataDeploy.concat(options.deployIdConcat);
596
620
 
597
621
  if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
598
622
 
@@ -827,7 +851,7 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
827
851
  if (failed.length > 0) {
828
852
  for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
829
853
  if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
830
- if (process.argv.includes('manual')) await read({ prompt: 'Press enter to retry failed processes\n' });
854
+ await read({ prompt: 'Press enter to retry failed processes\n' });
831
855
  currentAttempt++;
832
856
  await deployRun(failed, currentAttempt);
833
857
  } else logger.info(`Deploy process successfully`);
@@ -973,15 +997,15 @@ const getPathsSSR = (conf) => {
973
997
 
974
998
  const Cmd = {
975
999
  delete: (deployId) => `pm2 delete ${deployId}`,
976
- run: (deployId) => `node bin/deploy run ${deployId}`,
1000
+ run: () => `npm start`,
977
1001
  build: (deployId) => `node bin/deploy build-full-client ${deployId}${process.argv.includes('l') ? ' l' : ''}`,
978
1002
  conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
979
1003
  replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
980
1004
  syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
981
- cron: (deployId, job, expression) => {
982
- shellExec(Cmd.delete(`${deployId}-${job}`));
983
- return `env-cmd -f .env.production pm2 start bin/cron.js --no-autorestart --instances 1 --cron "${expression}" --name ${deployId}-${job} -- ${job} ${deployId}`;
984
- },
1005
+ cron: (deployList, jobList, name, expression, options) =>
1006
+ `pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
1007
+ options?.disableKindCluster ? `--disable-kind-cluster ` : ''
1008
+ }${deployList} ${jobList}`,
985
1009
  };
986
1010
 
987
1011
  const fixDependencies = async () => {
@@ -1048,7 +1072,7 @@ const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
1048
1072
  shellExec(`node bin/deploy valkey-service`);
1049
1073
  const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
1050
1074
  shellExec(`node bin/deploy conf ${proxyDeployId} production`);
1051
- shellExec(`node bin/deploy run ${proxyDeployId} maintenance`);
1075
+ shellExec(`npm start ${proxyDeployId} maintenance`);
1052
1076
  };
1053
1077
 
1054
1078
  const getNpmRootPath = () =>
package/src/server/dns.js CHANGED
@@ -17,10 +17,8 @@ dotenv.config();
17
17
 
18
18
  const logger = loggerFactory(import.meta);
19
19
 
20
- const Dns = {
21
- repoUrl: `https://${process.env.GITHUB_TOKEN}@github.com/${process.env.GITHUB_USERNAME}/${process.env.GITHUB_DNS_REPO}.git`,
22
- callback: () => null,
23
- InitIpDaemon: async function ({ deployId }) {
20
+ class Dns {
21
+ static callback = async function (deployList) {
24
22
  // NAT-VPS modem/router device configuration:
25
23
  // LAN --> [NAT-VPS] --> WAN
26
24
  // enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
@@ -30,56 +28,55 @@ const Dns = {
30
28
  // LAN server or device's local servers port -> 3000-3100 (2999-3101)
31
29
  // DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
32
30
  // Forward the router's TCP/UDP ports to the LAN device's IP address
33
-
31
+ for (const _deployId of deployList.split(',')) {
32
+ const deployId = _deployId.trim();
34
33
  const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
35
-
36
34
  const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
37
- let confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
38
- if (confCronData.ipDaemon.disabled) return;
39
- Dns.ip = confCronData.ipDaemon.ip;
40
- logger.info(`Current ip`, Dns.ip);
41
- const callback = async () => {
42
- logger.info('init dns ip callback');
43
- await logger.setUpInfo();
44
- let testIp;
45
- try {
46
- testIp = await ip.public.ipv4();
47
- } catch (error) {
48
- logger.error(error, { testIp, stack: error.stack });
49
- }
50
- if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && Dns.ip !== testIp) {
51
- logger.info(`New ip`, testIp);
52
- for (const recordType of Object.keys(confCronData.records)) {
53
- switch (recordType) {
54
- case 'A':
55
- for (const dnsProvider of confCronData.records[recordType]) {
56
- if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
57
- await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
58
- }
59
- break;
35
+ const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
36
+
37
+ let testIp;
38
+
39
+ try {
40
+ testIp = await ip.public.ipv4();
41
+ } catch (error) {
42
+ logger.error(error, { testIp, stack: error.stack });
43
+ }
44
+ const ipFileName = `${deployId}.ip`;
45
+ const currentIp = fs.existsSync(`./engine-private/deploy/${ipFileName}`)
46
+ ? fs.readFileSync(`./engine-private/deploy/${ipFileName}`, 'utf8')
47
+ : undefined;
60
48
 
61
- default:
62
- break;
63
- }
49
+ if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && currentIp !== testIp) {
50
+ logger.info(`new ip`, testIp);
51
+ for (const recordType of Object.keys(confCronData.records)) {
52
+ switch (recordType) {
53
+ case 'A':
54
+ for (const dnsProvider of confCronData.records[recordType]) {
55
+ if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
56
+ await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
57
+ }
58
+ break;
59
+
60
+ default:
61
+ break;
64
62
  }
65
- try {
66
- const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
67
- const response = await axios.get(ipUrlTest);
68
- const verifyIp = response.request.socket.remoteAddress;
69
- logger.info(ipUrlTest + ' IP', verifyIp);
70
- if (verifyIp === testIp) {
71
- await this.saveIp(confCronPath, confCronData, testIp);
72
- } else logger.error('ip not updated');
73
- } catch (error) {
74
- logger.error(error), 'ip not updated';
63
+ }
64
+ try {
65
+ const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
66
+ const response = await axios.get(ipUrlTest);
67
+ const verifyIp = response.request.socket.remoteAddress;
68
+ logger.info(ipUrlTest + ' IP', verifyIp);
69
+ if (verifyIp === testIp) {
70
+ fs.writeFileSync(`./engine-private/deploy/${ipFileName}`, testIp, 'utf8');
71
+ } else logger.error('ip not updated');
72
+ } catch (error) {
73
+ logger.error(error), 'ip not updated';
75
74
  }
76
75
  }
77
- };
78
- await callback();
79
- this.callback = callback;
80
- return callback;
81
- },
82
- services: {
76
+ }
77
+ };
78
+
79
+ static services = {
83
80
  updateIp: {
84
81
  dondominio: (options) => {
85
82
  const { user, api_key, host, dns, ip } = options;
@@ -100,21 +97,7 @@ const Dns = {
100
97
  });
101
98
  },
102
99
  },
103
- },
104
- saveIp: async (confCronPath, confCronData, ip) => {
105
- Dns.ip = ip;
106
- confCronData.ipDaemon.ip = ip;
107
- fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
108
- shellExec(
109
- `cd ./engine-private` +
110
- ` && git pull ${Dns.repoUrl}` +
111
- ` && git add . && git commit -m "update ip ${new Date().toLocaleDateString()}"` +
112
- ` && git push ${Dns.repoUrl}`,
113
- {
114
- disableLog: true,
115
- },
116
- );
117
- },
118
- };
100
+ };
101
+ }
119
102
 
120
- export { Dns };
103
+ export default Dns;
package/src/dns.js DELETED
@@ -1,22 +0,0 @@
1
- 'use strict';
2
-
3
- // https://nodejs.org/api
4
- // https://expressjs.com/en/4x/api.html
5
-
6
- import dotenv from 'dotenv';
7
- import { loggerFactory } from './server/logger.js';
8
- import { Dns } from './server/dns.js';
9
- import { ProcessController } from './server/process.js';
10
- import { Config } from './server/conf.js';
11
-
12
- dotenv.config();
13
-
14
- await Config.build();
15
-
16
- const logger = loggerFactory(import.meta);
17
-
18
- await logger.setUpInfo();
19
-
20
- await Dns.InitIpDaemon();
21
-
22
- ProcessController.init(logger);