underpost 2.8.857 → 2.8.861

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/src/cli/db.js CHANGED
@@ -4,6 +4,8 @@ import { shellExec } from '../server/process.js';
4
4
  import fs from 'fs-extra';
5
5
  import UnderpostDeploy from './deploy.js';
6
6
  import UnderpostCron from './cron.js';
7
+ import { DataBaseProvider } from '../db/DataBaseProvider.js';
8
+ import { loadReplicas, pathPortAssignmentFactory } from '../server/conf.js';
7
9
 
8
10
  const logger = loggerFactory(import.meta);
9
11
 
@@ -217,28 +219,29 @@ class UnderpostDB {
217
219
  }
218
220
  }
219
221
  },
220
- async updateDashboardData(
222
+ async clusterMetadataFactory(
221
223
  deployId = process.env.DEFAULT_DEPLOY_ID,
222
224
  host = process.env.DEFAULT_DEPLOY_HOST,
223
225
  path = process.env.DEFAULT_DEPLOY_PATH,
224
226
  ) {
225
- try {
226
- deployId = deployId ?? process.env.DEFAULT_DEPLOY_ID;
227
- host = host ?? process.env.DEFAULT_DEPLOY_HOST;
228
- path = path ?? process.env.DEFAULT_DEPLOY_PATH;
229
-
230
- const { db } = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'))[host][
231
- path
232
- ];
227
+ deployId = deployId ?? process.env.DEFAULT_DEPLOY_ID;
228
+ host = host ?? process.env.DEFAULT_DEPLOY_HOST;
229
+ path = path ?? process.env.DEFAULT_DEPLOY_PATH;
230
+ const env = 'production';
231
+ const deployList = fs.readFileSync('./engine-private/deploy/dd.router', 'utf8').split(',');
233
232
 
234
- await DataBaseProvider.load({ apis: ['instance'], host, path, db });
233
+ const { db } = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'))[host][
234
+ path
235
+ ];
236
+ try {
237
+ await DataBaseProvider.load({ apis: ['instance', 'cron'], host, path, db });
235
238
 
236
239
  /** @type {import('../api/instance/instance.model.js').InstanceModel} */
237
240
  const Instance = DataBaseProvider.instance[`${host}${path}`].mongoose.models.Instance;
238
241
 
239
242
  await Instance.deleteMany();
240
243
 
241
- for (const _deployId of deployList.split(',')) {
244
+ for (const _deployId of deployList) {
242
245
  const deployId = _deployId.trim();
243
246
  if (!deployId) continue;
244
247
  const confServer = loadReplicas(
@@ -252,34 +255,45 @@ class UnderpostDB {
252
255
  for (const { path, port } of pathPortAssignmentData[host]) {
253
256
  if (!confServer[host][path]) continue;
254
257
 
255
- const { client, runtime, apis } = confServer[host][path];
256
-
257
- const body = {
258
- deployId,
259
- host,
260
- path,
261
- port,
262
- client,
263
- runtime,
264
- apis,
265
- };
266
-
267
- logger.info('save', body);
258
+ const { client, runtime, apis, peer } = confServer[host][path];
259
+ {
260
+ const body = {
261
+ deployId,
262
+ host,
263
+ path,
264
+ port,
265
+ client,
266
+ runtime,
267
+ apis,
268
+ };
269
+
270
+ logger.info('Instance save', body);
271
+ await new Instance(body).save();
272
+ }
268
273
 
269
- await new Instance(body).save();
274
+ if (peer) {
275
+ const body = {
276
+ deployId,
277
+ host,
278
+ path: path === '/' ? '/peer' : `${path}/peer`,
279
+ port: port + 1,
280
+ runtime: 'nodejs',
281
+ };
282
+
283
+ logger.info('Instance save', body);
284
+ await new Instance(body).save();
285
+ }
270
286
  }
271
287
  }
272
288
  }
273
-
274
- await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
275
289
  } catch (error) {
276
290
  logger.error(error, error.stack);
277
291
  }
278
292
 
279
293
  try {
280
- const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
281
- const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
282
- const { db } = confServer[host][path];
294
+ const cronDeployId = fs.readFileSync('./engine-private/deploy/dd.cron', 'utf8').trim();
295
+ const confCronPath = `./engine-private/conf/${cronDeployId}/conf.cron.json`;
296
+ const confCron = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
283
297
 
284
298
  await DataBaseProvider.load({ apis: ['cron'], host, path, db });
285
299
 
@@ -288,21 +302,28 @@ class UnderpostDB {
288
302
 
289
303
  await Cron.deleteMany();
290
304
 
291
- for (const cronInstance of UnderpostCron.NETWORK) {
292
- logger.info('save', cronInstance);
293
- await new Cron(cronInstance).save();
305
+ for (const jobId of Object.keys(confCron.jobs)) {
306
+ const body = {
307
+ jobId,
308
+ deployId: UnderpostCron.API.getRelatedDeployId(jobId),
309
+ expression: confCron.jobs[jobId].expression,
310
+ enabled: confCron.jobs[jobId].enabled,
311
+ };
312
+ logger.info('Cron save', body);
313
+ await new Cron(body).save();
294
314
  }
295
-
296
- await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
297
315
  } catch (error) {
298
316
  logger.error(error, error.stack);
299
317
  }
318
+ await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
300
319
  },
301
320
  clusterMetadataBackupCallback(
302
321
  deployId = process.env.DEFAULT_DEPLOY_ID,
303
322
  host = process.env.DEFAULT_DEPLOY_HOST,
304
323
  path = process.env.DEFAULT_DEPLOY_PATH,
305
324
  options = {
325
+ generate: false,
326
+ itc: false,
306
327
  import: false,
307
328
  export: false,
308
329
  instances: false,
@@ -313,6 +334,10 @@ class UnderpostDB {
313
334
  host = host ?? process.env.DEFAULT_DEPLOY_HOST;
314
335
  path = path ?? process.env.DEFAULT_DEPLOY_PATH;
315
336
 
337
+ if (options.generate === true) {
338
+ UnderpostDB.API.clusterMetadataFactory(deployId, host, path);
339
+ }
340
+
316
341
  if (options.instances === true) {
317
342
  const outputPath = './engine-private/instances';
318
343
  if (fs.existsSync(outputPath)) fs.mkdirSync(outputPath, { recursive: true });
package/src/cli/deploy.js CHANGED
@@ -323,10 +323,7 @@ Password: <Your Key>
323
323
  logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
324
324
  return;
325
325
  }
326
- shellExec(`kubectl delete configmap underpost-config`);
327
- shellExec(
328
- `kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
329
- );
326
+ UnderpostDeploy.API.configMap(env);
330
327
  let renderHosts = '';
331
328
  let concatHots = '';
332
329
  const etcHost = (
@@ -477,6 +474,19 @@ Password: <Your Key>
477
474
  }
478
475
  return { ready: notReadyPods.length === 0, notReadyPods, readyPods };
479
476
  },
477
+ configMap(env) {
478
+ shellExec(`kubectl delete configmap underpost-config`);
479
+ shellExec(
480
+ `kubectl create configmap underpost-config --from-file=/home/dd/engine/engine-private/conf/dd-cron/.env.${env}`,
481
+ );
482
+ },
483
+ switchTraffic(deployId, env, targetTraffic, replicas = 1) {
484
+ UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
485
+ shellExec(
486
+ `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${replicas} ${deployId} ${env}`,
487
+ );
488
+ shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
489
+ },
480
490
  };
481
491
  }
482
492
 
package/src/cli/index.js CHANGED
@@ -23,6 +23,7 @@ program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`
23
23
  program
24
24
  .command('new')
25
25
  .argument('<app-name>', 'The name of the application to create.')
26
+ .option('--dev', 'Sets the development cli context')
26
27
  .description('Initializes a new Underpost project with a predefined structure.')
27
28
  .action(Underpost.repo.new);
28
29
 
@@ -249,6 +250,8 @@ program
249
250
  .option('--export', 'Exports to local storage.')
250
251
  .option('--crons', 'Apply to cron data collection')
251
252
  .option('--instances', 'Apply to instance data collection')
253
+ .option('--generate', 'Generate cluster metadata')
254
+ .option('--itc', 'Apply under container execution context')
252
255
  .description('Manages cluster metadata operations, including import and export.')
253
256
  .action(Underpost.db.clusterMetadataBackupCallback);
254
257
 
@@ -120,10 +120,7 @@ class UnderpostMonitor {
120
120
  fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
121
121
  );
122
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
- );
123
+ UnderpostDeploy.API.configMap(env);
127
124
 
128
125
  for (const host of Object.keys(confServer)) {
129
126
  shellExec(`sudo kubectl delete HTTPProxy ${host}`);
@@ -80,7 +80,7 @@ class UnderpostRepository {
80
80
  );
81
81
  },
82
82
 
83
- new(repositoryName) {
83
+ new(repositoryName, options = { dev: false }) {
84
84
  return new Promise(async (resolve, reject) => {
85
85
  try {
86
86
  await logger.setUpInfo();
@@ -89,15 +89,22 @@ class UnderpostRepository {
89
89
  await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':'),
90
90
  );
91
91
  else actionInitLog();
92
- const exeRootPath = `${getNpmRootPath()}/underpost`;
92
+ const npmRoot = getNpmRootPath();
93
+ const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
93
94
  const destFolder = `./${repositoryName}`;
94
95
  logger.info('Note: This process may take several minutes to complete');
95
96
  logger.info('build app', { destFolder });
96
97
  if (fs.existsSync(destFolder)) fs.removeSync(destFolder);
97
98
  fs.mkdirSync(destFolder, { recursive: true });
98
- fs.copySync(exeRootPath, destFolder);
99
- fs.writeFileSync(`${destFolder}/.gitignore`, fs.readFileSync(`${exeRootPath}/.dockerignore`, 'utf8'), 'utf8');
100
- shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
99
+ if (!options.dev) {
100
+ fs.copySync(underpostRoot, destFolder);
101
+ fs.writeFileSync(
102
+ `${destFolder}/.gitignore`,
103
+ fs.readFileSync(`${underpostRoot}/.dockerignore`, 'utf8'),
104
+ 'utf8',
105
+ );
106
+ shellExec(`cd ${destFolder} && git init && git add . && git commit -m "Base template implementation"`);
107
+ }
101
108
  shellExec(`cd ${destFolder} && npm run build`);
102
109
  shellExec(`cd ${destFolder} && npm run dev`);
103
110
  return resolve();
package/src/cli/run.js CHANGED
@@ -54,6 +54,9 @@ class UnderpostRun {
54
54
  }`,
55
55
  );
56
56
  },
57
+ 'underpost-config': (path, options = UnderpostRun.DEFAULT_OPTION) => {
58
+ UnderpostDeploy.API.configMap(path ?? 'production');
59
+ },
57
60
  'gpu-env': (path, options = UnderpostRun.DEFAULT_OPTION) => {
58
61
  shellExec(
59
62
  `node bin cluster --dev --reset && node bin cluster --dev --dedicated-gpu --kubeadm && kubectl get pods --all-namespaces -o wide -w`,
@@ -128,6 +131,16 @@ class UnderpostRun {
128
131
  const { underpostRoot } = options;
129
132
  shellExec(`node ${underpostRoot}/bin/vs ${path}`);
130
133
  },
134
+ 'dev-client': (_path, options = UnderpostRun.DEFAULT_OPTION) => {
135
+ let [deployId, hostpath, subConf, lite] = _path.split(',');
136
+ let [host, path] = hostpath.split('/');
137
+ if (!path) path = '/';
138
+ shellExec(`npm run dev-client ${deployId} ${host} ${path} ${subConf} static${lite === 'l' ? ' l' : ''}`);
139
+ },
140
+ 'dev-api': (path, options = UnderpostRun.DEFAULT_OPTION) => {
141
+ let [deployId, subConf] = path.split(',');
142
+ shellExec(`npm run dev-api ${deployId} ${subConf}`);
143
+ },
131
144
  monitor: (path, options = UnderpostRun.DEFAULT_OPTION) => {
132
145
  const pid = getTerminalPid();
133
146
  logger.info('monitor pid', pid);
@@ -205,6 +218,34 @@ class UnderpostRun {
205
218
  const { underpostRoot } = options;
206
219
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/deployment/adminer/.`);
207
220
  },
221
+ promote: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
222
+ let [inputDeployId, inputEnv, inputReplicas] = path.split(',');
223
+ if (!inputEnv) inputEnv = 'production';
224
+ if (!inputReplicas) inputReplicas = 1;
225
+ if (inputDeployId === 'dd') {
226
+ for (const deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',')) {
227
+ const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(deployId);
228
+ const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
229
+ UnderpostDeploy.API.switchTraffic(deployId, inputEnv, targetTraffic, inputReplicas);
230
+ }
231
+ } else {
232
+ const currentTraffic = UnderpostDeploy.API.getCurrentTraffic(inputDeployId);
233
+ const targetTraffic = currentTraffic === 'blue' ? 'green' : 'blue';
234
+ UnderpostDeploy.API.switchTraffic(inputDeployId, inputEnv, targetTraffic, inputReplicas);
235
+ }
236
+ },
237
+
238
+ metrics: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
239
+ const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
240
+ let hosts = [];
241
+ for (const deployId of deployList) {
242
+ const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
243
+ hosts = hosts.concat(Object.keys(confServer));
244
+ }
245
+ shellExec(`node bin cluster --prom ${hosts.join(',')}`);
246
+ shellExec(`node bin cluster --grafana`);
247
+ },
248
+
208
249
  cluster: async (path, options = UnderpostRun.DEFAULT_OPTION) => {
209
250
  const deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(',');
210
251
  const env = 'production';
@@ -255,14 +296,8 @@ class UnderpostRun {
255
296
 
256
297
  logger.info(`${iteratorTag} | Deployment ready. | Total delay number check iterations: ${checkStatusIteration}`);
257
298
 
258
- UnderpostRootEnv.API.set(`${deployId}-${env}-traffic`, targetTraffic);
299
+ UnderpostDeploy.API.switchTraffic(deployId, env, targetTraffic);
259
300
 
260
- shellExec(
261
- `node bin deploy --info-router --build-manifest --traffic ${targetTraffic} --replicas ${
262
- options.replicas ? options.replicas : 1
263
- } ${deployId} ${env}`,
264
- );
265
- shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
266
301
  shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${currentTraffic}`);
267
302
  },
268
303
  'tf-vae-test': async (path, options = UnderpostRun.DEFAULT_OPTION) => {
@@ -457,6 +457,19 @@ const getLang = () =>
457
457
  .slice(0, 2)
458
458
  .toLowerCase();
459
459
 
460
+ function hexToRgbA(hex) {
461
+ let c;
462
+ if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
463
+ c = hex.substring(1).split('');
464
+ if (c.length == 3) {
465
+ c = [c[0], c[0], c[1], c[1], c[2], c[2]];
466
+ }
467
+ c = '0x' + c.join('');
468
+ return [(c >> 16) & 255, (c >> 8) & 255, c & 255];
469
+ }
470
+ throw new Error('Invalid Hex');
471
+ }
472
+
460
473
  export {
461
474
  s,
462
475
  htmls,
@@ -486,4 +499,5 @@ export {
486
499
  isDevInstance,
487
500
  getDataFromInputFile,
488
501
  getLang,
502
+ hexToRgbA,
489
503
  };
package/src/index.js CHANGED
@@ -35,7 +35,7 @@ class Underpost {
35
35
  * @type {String}
36
36
  * @memberof Underpost
37
37
  */
38
- static version = 'v2.8.857';
38
+ static version = 'v2.8.861';
39
39
  /**
40
40
  * Repository cli API
41
41
  * @static
@@ -159,7 +159,7 @@ const buildCoverage = async ({ host, path }) => {
159
159
  shellExec(`npm test`);
160
160
  }
161
161
 
162
- const coverageBuildPath = `${jsDocsConfig.opts.destination}/coverage`;
162
+ const coverageBuildPath = `${jsDocsConfig.opts.destination}coverage`;
163
163
  fs.mkdirSync(coverageBuildPath, { recursive: true });
164
164
  fs.copySync(`./coverage`, coverageBuildPath);
165
165
 
@@ -59,7 +59,7 @@ const clientLiveBuild = async () => {
59
59
  const updates = JSON.parse(fs.readFileSync(`./tmp/client.build.json`, 'utf8'));
60
60
  const liveClientBuildPaths = [];
61
61
  for (let srcPath of updates) {
62
- srcPath = srcPath.replaceAll('/', `\\`); // linux case
62
+ srcPath = srcPath.replaceAll('/', `\\`);
63
63
 
64
64
  const srcBuildPath = `./src${srcPath.split('src')[1].replace(/\\/g, '/')}`;
65
65
  if (
@@ -535,7 +535,13 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
535
535
  );
536
536
  }
537
537
 
538
- if (!enableLiveRebuild && !process.argv.includes('l') && !process.argv.includes('deploy') && docsBuild) {
538
+ if (
539
+ fullBuildEnabled &&
540
+ !enableLiveRebuild &&
541
+ !process.argv.includes('l') &&
542
+ !process.argv.includes('deploy') &&
543
+ docsBuild
544
+ ) {
539
545
  await buildDocs({
540
546
  host,
541
547
  path,
@@ -7,7 +7,7 @@ const logger = loggerFactory(import.meta);
7
7
 
8
8
  const createClientDevServer = () => {
9
9
  // process.argv.slice(2).join(' ')
10
- shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')} l`);
10
+ shellExec(`env-cmd -f .env.development node bin/deploy build-full-client ${process.argv.slice(2).join(' ')}`);
11
11
  shellExec(
12
12
  `env-cmd -f .env.development node src/api ${process.argv[2]}${process.argv[5] ? ` ${process.argv[5]}` : ''}${
13
13
  process.argv.includes('static') ? ' static' : ''
@@ -35,10 +35,9 @@ const Config = {
35
35
  if (!deployContext) deployContext = process.argv[2];
36
36
  if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
37
37
  fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
38
- if (fs.existsSync(`./engine-private/conf/${deployContext}`))
39
- return loadConf(deployContext, process.env.NODE_ENV, subConf);
40
38
  if (fs.existsSync(`./engine-private/replica/${deployContext}`))
41
39
  return loadConf(deployContext, process.env.NODE_ENV, subConf);
40
+ else if (deployContext.startsWith('dd-')) return loadConf(deployContext, process.env.NODE_ENV, subConf);
42
41
 
43
42
  if (deployContext === 'deploy') return;
44
43
 
@@ -104,6 +103,7 @@ const loadConf = (deployId, envInput, subConf) => {
104
103
  shellExec(`git checkout ${path}/package-lock.json`);
105
104
  return;
106
105
  }
106
+ if (!deployId.startsWith('dd-')) deployId = 'dd-default';
107
107
  const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
108
108
  ? `./engine-private/replica/${deployId}`
109
109
  : `./engine-private/conf/${deployId}`;
@@ -79,11 +79,11 @@ class UnderpostStartUp {
79
79
  }
80
80
  }),
81
81
 
82
- async callback(deployId = 'default', env = 'development', options = { build: false, run: false }) {
82
+ async callback(deployId = 'dd-default', env = 'development', options = { build: false, run: false }) {
83
83
  if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
84
84
  if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
85
85
  },
86
- async build(deployId = 'default', env = 'development') {
86
+ async build(deployId = 'dd-default', env = 'development') {
87
87
  const buildBasePath = `/home/dd`;
88
88
  const repoName = `engine-${deployId.split('-')[1]}`;
89
89
  shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
@@ -100,7 +100,7 @@ class UnderpostStartUp {
100
100
  }
101
101
  shellExec(`node bin/deploy build-full-client ${deployId}`);
102
102
  },
103
- async run(deployId = 'default', env = 'development') {
103
+ async run(deployId = 'dd-default', env = 'development') {
104
104
  const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
105
105
  if (fs.existsSync(`./engine-private/replica`)) {
106
106
  const replicas = await fs.readdir(`./engine-private/replica`);