underpost 2.8.65 → 2.8.67

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/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.65",
5
+ "version": "2.8.67",
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",
@@ -11,6 +11,7 @@
11
11
  "dev": "env-cmd -f .env.development node src/client.dev default",
12
12
  "dev-img": "env-cmd -f .env.development node src/server",
13
13
  "prod-img": "env-cmd -f .env.production node src/server",
14
+ "monitor": "pm2 start bin/deploy.js --name monitor -- monitor",
14
15
  "dev-api": "env-cmd -f .env.development nodemon --watch src --ignore src/client src/api",
15
16
  "dev-client": "env-cmd -f .env.development node src/client.dev",
16
17
  "proxy": "node src/proxy proxy",
@@ -14,6 +14,7 @@ class UnderpostCluster {
14
14
  mongodb: false,
15
15
  mongodb4: false,
16
16
  mariadb: false,
17
+ postgresql: false,
17
18
  valkey: false,
18
19
  full: false,
19
20
  info: false,
@@ -24,8 +25,15 @@ class UnderpostCluster {
24
25
  nsUse: '',
25
26
  infoCapacity: false,
26
27
  infoCapacityPod: false,
28
+ istio: false,
29
+ pullImage: false,
27
30
  },
28
31
  ) {
32
+ // 1) Install kind, kubeadm, docker, podman
33
+ // 2) Check kubectl, kubelet, containerd.io
34
+ // 3) Install Nvidia drivers from Rocky Linux docs
35
+ // 4) Install LXD with MAAS from Rocky Linux docs
36
+ // 5) Install MAAS src from snap
29
37
  const npmRoot = getNpmRootPath();
30
38
  const underpostRoot = options?.dev === true ? '.' : `${npmRoot}/underpost`;
31
39
  if (options.infoCapacityPod === true) return logger.info('', UnderpostDeploy.API.resourcesFactory());
@@ -66,26 +74,62 @@ class UnderpostCluster {
66
74
  shellExec(`kubectl get secrets --all-namespaces -o wide`);
67
75
  shellExec(`docker secret ls`);
68
76
  shellExec(`kubectl get crd --all-namespaces -o wide`);
77
+ shellExec(`sudo kubectl api-resources`);
69
78
  return;
70
79
  }
71
80
 
72
- if (!UnderpostDeploy.API.get('kube-apiserver-kind-control-plane')[0]) {
81
+ if (
82
+ (!options.istio && !UnderpostDeploy.API.get('kube-apiserver-kind-control-plane')[0]) ||
83
+ (options.istio === true && !UnderpostDeploy.API.get('calico-kube-controllers')[0])
84
+ ) {
85
+ shellExec(`sudo setenforce 0`);
86
+ shellExec(`sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config`);
87
+ // sudo systemctl disable kubelet
88
+ // shellExec(`sudo systemctl enable --now kubelet`);
73
89
  shellExec(`containerd config default > /etc/containerd/config.toml`);
74
90
  shellExec(`sed -i -e "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml`);
75
91
  // shellExec(`cp /etc/kubernetes/admin.conf ~/.kube/config`);
76
- shellExec(`sudo systemctl restart kubelet`);
92
+ // shellExec(`sudo systemctl restart kubelet`);
77
93
  shellExec(`sudo service docker restart`);
78
94
  shellExec(`sudo systemctl enable --now containerd.service`);
79
- shellExec(`sudo systemctl restart containerd`);
80
- shellExec(
81
- `cd ${underpostRoot}/manifests && kind create cluster --config kind-config${
82
- options?.dev === true ? '-dev' : ''
83
- }.yaml`,
84
- );
85
- shellExec(`sudo chown $(id -u):$(id -g) $HOME/.kube/config**`);
95
+ shellExec(`sudo swapoff -a; sudo sed -i '/swap/d' /etc/fstab`);
96
+ if (options.istio === true) {
97
+ shellExec(`sysctl net.bridge.bridge-nf-call-iptables=1`);
98
+ shellExec(`sudo kubeadm init --pod-network-cidr=192.168.0.0/16`);
99
+ shellExec(`sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config`);
100
+ shellExec(`sudo chown $(id -u):$(id -g) $HOME/.kube/config**`);
101
+ // https://docs.tigera.io/calico/latest/getting-started/kubernetes/quickstart
102
+ shellExec(
103
+ `sudo kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.3/manifests/tigera-operator.yaml`,
104
+ );
105
+ // shellExec(
106
+ // `wget https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/custom-resources.yaml`,
107
+ // );
108
+ shellExec(`sudo kubectl apply -f ./manifests/calico-custom-resources.yaml`);
109
+ shellExec(`sudo systemctl restart containerd`);
110
+ } else {
111
+ shellExec(`sudo systemctl restart containerd`);
112
+ shellExec(
113
+ `cd ${underpostRoot}/manifests && kind create cluster --config kind-config${
114
+ options?.dev === true ? '-dev' : ''
115
+ }.yaml`,
116
+ );
117
+ shellExec(`sudo chown $(id -u):$(id -g) $HOME/.kube/config**`);
118
+ }
86
119
  } else logger.warn('Cluster already initialized');
87
120
 
88
121
  if (options.full === true || options.valkey === true) {
122
+ if (options.pullImage === true) {
123
+ // kubectl patch statefulset service-valkey --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
124
+ // kubectl patch statefulset service-valkey -p '{"spec":{"template":{"spec":{"containers":[{"name":"service-valkey","imagePullPolicy":"Never"}]}}}}'
125
+ shellExec(`docker pull valkey/valkey`);
126
+ // shellExec(`sudo kind load docker-image valkey/valkey`);
127
+ // shellExec(`sudo podman pull docker.io/valkey/valkey:latest`);
128
+ // shellExec(`podman save -o valkey.tar valkey/valkey`);
129
+ // shellExec(`sudo kind load image-archive valkey.tar`);
130
+ // shellExec(`sudo rm -rf ./valkey.tar`);
131
+ shellExec(`sudo kind load docker-image valkey/valkey:latest`);
132
+ }
89
133
  shellExec(`kubectl delete statefulset service-valkey`);
90
134
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey`);
91
135
  }
@@ -99,7 +143,17 @@ class UnderpostCluster {
99
143
  shellExec(`kubectl delete statefulset mariadb-statefulset`);
100
144
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb`);
101
145
  }
146
+ if (options.full === true || options.postgresql === true) {
147
+ shellExec(
148
+ `sudo kubectl create secret generic postgres-secret --from-file=password=/home/dd/engine/engine-private/postgresql-password`,
149
+ );
150
+ shellExec(`kubectl apply -k ./manifests/postgresql`);
151
+ }
102
152
  if (options.mongodb4 === true) {
153
+ if (options.pullImage === true) {
154
+ shellExec(`docker pull mongo:4.4`);
155
+ shellExec(`sudo kind load docker-image mongo:4.4`);
156
+ }
103
157
  shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb-4.4`);
104
158
 
105
159
  const deploymentName = 'mongodb-deployment';
@@ -199,10 +253,15 @@ class UnderpostCluster {
199
253
  `sudo sed -i -e "s@/var/lib/containers/storage@/home/containers/storage@g" /etc/containers/storage.conf`,
200
254
  );
201
255
  shellExec(`sudo podman system reset -f`);
256
+ // https://github.com/kubernetes-sigs/kind/issues/2886
257
+ shellExec(`sysctl net.bridge.bridge-nf-call-iptables=0`);
258
+ shellExec(`sysctl net.bridge.bridge-nf-call-arptables=0`);
259
+ shellExec(`sysctl net.bridge.bridge-nf-call-ip6tables=0`);
260
+ shellExec(`docker network rm kind`);
202
261
  },
203
262
  getResourcesCapacity() {
204
263
  const resources = {};
205
- const info = false
264
+ const info = true
206
265
  ? `Capacity:
207
266
  cpu: 8
208
267
  ephemeral-storage: 153131976Ki
package/src/cli/deploy.js CHANGED
@@ -22,11 +22,11 @@ class UnderpostDeploy {
22
22
  static NETWORK = {};
23
23
  static API = {
24
24
  sync(deployList, { versions, replicas }) {
25
- const deployGroupId = 'dd.tmp';
25
+ const deployGroupId = 'dd.router';
26
26
  fs.writeFileSync(`./engine-private/deploy/${deployGroupId}`, deployList, 'utf8');
27
27
  const totalPods = deployList.split(',').length * versions.split(',').length * parseInt(replicas);
28
- const limitFactor = 0.95;
29
- const reserveFactor = 0.35;
28
+ const limitFactor = 0.8;
29
+ const reserveFactor = 0.05;
30
30
  const resources = UnderpostCluster.API.getResourcesCapacity();
31
31
  const memory = parseInt(resources.memory.value / totalPods);
32
32
  const cpu = parseInt(resources.cpu.value / totalPods);
@@ -220,6 +220,14 @@ spec:
220
220
  }
221
221
  }
222
222
  },
223
+ getCurrentTraffic(deployId) {
224
+ // kubectl get deploy,sts,svc,configmap,secret -n default -o yaml --export > default.yaml
225
+ const hostTest = Object.keys(
226
+ JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
227
+ )[0];
228
+ const info = shellExec(`sudo kubectl get HTTPProxy/${hostTest} -o yaml`, { silent: true, stdout: true });
229
+ return info.match('blue') ? 'blue' : info.match('green') ? 'green' : null;
230
+ },
223
231
  async callback(
224
232
  deployList = 'default',
225
233
  env = 'development',
@@ -235,6 +243,9 @@ spec:
235
243
  traffic: '',
236
244
  dashboardUpdate: false,
237
245
  replicas: '',
246
+ disableUpdateDeployment: false,
247
+ infoTraffic: false,
248
+ rebuildClientsBundle: false,
238
249
  },
239
250
  ) {
240
251
  if (options.infoUtil === true)
@@ -242,11 +253,26 @@ spec:
242
253
  kubectl rollout restart deployment/deployment-name
243
254
  kubectl rollout undo deployment/deployment-name
244
255
  kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
245
- `);
256
+ kubectl get pods -w
257
+ kubectl patch statefulset service-valkey --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"valkey/valkey:latest"}]'
258
+ kubectl patch statefulset service-valkey -p '{"spec":{"template":{"spec":{"containers":[{"name":"service-valkey","imagePullPolicy":"Never"}]}}}}'
259
+ `);
246
260
  if (deployList === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`))
247
261
  deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
262
+ if (options.infoTraffic === true) {
263
+ for (const _deployId of deployList.split(',')) {
264
+ const deployId = _deployId.trim();
265
+ logger.info('', {
266
+ deployId,
267
+ env,
268
+ traffic: UnderpostDeploy.API.getCurrentTraffic(deployId),
269
+ });
270
+ }
271
+ return;
272
+ }
273
+ if (options.rebuildClientsBundle === true) await UnderpostDeploy.API.rebuildClientsBundle(deployList);
248
274
  if (!(options.versions && typeof options.versions === 'string')) options.versions = 'blue,green';
249
- if (!options.replicas) options.replicas = 2;
275
+ if (!options.replicas) options.replicas = 1;
250
276
  if (options.sync) UnderpostDeploy.API.sync(deployList, options);
251
277
  if (options.buildManifest === true) await UnderpostDeploy.API.buildManifest(deployList, env, options);
252
278
  if (options.infoRouter === true) logger.info('router', await UnderpostDeploy.API.routerFactory(deployList, env));
@@ -275,8 +301,12 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
275
301
  shellExec(`sudo kubectl port-forward -n default svc/${svc.NAME} ${port}:${port}`, { async: true });
276
302
  continue;
277
303
  }
278
- shellExec(`sudo kubectl delete svc ${deployId}-${env}-service`);
279
- shellExec(`sudo kubectl delete deployment ${deployId}-${env}`);
304
+
305
+ if (!options.disableUpdateDeployment)
306
+ for (const version of options.versions.split(',')) {
307
+ shellExec(`sudo kubectl delete svc ${deployId}-${env}-${version}-service`);
308
+ shellExec(`sudo kubectl delete deployment ${deployId}-${env}-${version}`);
309
+ }
280
310
 
281
311
  const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
282
312
  for (const host of Object.keys(confServer)) {
@@ -291,7 +321,7 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
291
321
  : `manifests/deployment/${deployId}-${env}`;
292
322
 
293
323
  if (!options.remove === true) {
294
- shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
324
+ if (!options.disableUpdateDeployment) shellExec(`sudo kubectl apply -f ./${manifestsPath}/deployment.yaml`);
295
325
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/proxy.yaml`);
296
326
  if (env === 'production' && options.cert === true)
297
327
  shellExec(`sudo kubectl apply -f ./${manifestsPath}/secret.yaml`);
@@ -354,6 +384,23 @@ kubectl scale statefulsets <stateful-set-name> --replicas=<new-replicas>
354
384
 
355
385
  return result;
356
386
  },
387
+ rebuildClientsBundle(deployList) {
388
+ for (const _deployId of deployList.split(',')) {
389
+ const deployId = _deployId.trim();
390
+ const repoName = `engine-${deployId.split('-')[1]}`;
391
+
392
+ shellExec(`underpost script set ${deployId}-client-build '
393
+ cd /home/dd/engine &&
394
+ git checkout . &&
395
+ underpost pull . underpostnet/${repoName} &&
396
+ underpost pull ./engine-private underpostnet/${repoName}-private &&
397
+ underpost env ${deployId} production &&
398
+ node bin/deploy build-full-client ${deployId}
399
+ '`);
400
+
401
+ shellExec(`node bin script run ${deployId}-client-build --itc --pod-name ${deployId}`);
402
+ }
403
+ },
357
404
  resourcesFactory() {
358
405
  return {
359
406
  requests: {
package/src/cli/fs.js CHANGED
@@ -24,7 +24,7 @@ class UnderpostFileStorage {
24
24
  getStorageConf(options) {
25
25
  let storage, storageConf;
26
26
  if (options.deployId && typeof options.deployId === 'string') {
27
- storageConf = `./engine-private/conf/${options.deployId}/storage.json`;
27
+ storageConf = options.storageFilePath ?? `./engine-private/conf/${options.deployId}/storage.json`;
28
28
  if (!fs.existsSync(storageConf)) fs.writeFileSync(storageConf, JSON.stringify({}), 'utf8');
29
29
  storage = JSON.parse(fs.readFileSync(storageConf, 'utf8'));
30
30
  }
@@ -35,7 +35,15 @@ class UnderpostFileStorage {
35
35
  },
36
36
  async recursiveCallback(
37
37
  path,
38
- options = { rm: false, recursive: false, deployId: '', force: false, pull: false, git: false },
38
+ options = {
39
+ rm: false,
40
+ recursive: false,
41
+ deployId: '',
42
+ force: false,
43
+ pull: false,
44
+ git: false,
45
+ storageFilePath: '',
46
+ },
39
47
  ) {
40
48
  const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
41
49
  const deleteFiles = options.pull === true ? [] : UnderpostRepository.API.getDeleteFiles(path);
@@ -85,7 +93,10 @@ class UnderpostFileStorage {
85
93
  if (options.rm === true) return await UnderpostFileStorage.API.delete(path, options);
86
94
  return await UnderpostFileStorage.API.upload(path, options);
87
95
  },
88
- async upload(path, options = { rm: false, recursive: false, deployId: '', force: false, pull: false }) {
96
+ async upload(
97
+ path,
98
+ options = { rm: false, recursive: false, deployId: '', force: false, pull: false, storageFilePath: '' },
99
+ ) {
89
100
  UnderpostFileStorage.API.cloudinaryConfig();
90
101
  const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
91
102
  // path = UnderpostFileStorage.API.file2Zip(path);
@@ -0,0 +1,312 @@
1
+ import dotenv from 'dotenv';
2
+ import { Command } from 'commander';
3
+ import Underpost from '../index.js';
4
+ import { getUnderpostRootPath, loadConf } from '../server/conf.js';
5
+ import fs from 'fs-extra';
6
+ import { commitData } from '../client/components/core/CommonJs.js';
7
+ import { shellExec } from '../server/process.js';
8
+
9
+ const underpostRootPath = getUnderpostRootPath();
10
+ fs.existsSync(`${underpostRootPath}/.env`)
11
+ ? dotenv.config({ path: `${underpostRootPath}/.env`, override: true })
12
+ : dotenv.config();
13
+
14
+ const program = new Command();
15
+
16
+ program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`).version(Underpost.version);
17
+
18
+ program
19
+ .command('new')
20
+ .argument('<app-name>', 'Application name')
21
+ .description('Create a new project')
22
+ .action(Underpost.repo.new);
23
+
24
+ program
25
+ .command('start')
26
+ .argument('<deploy-id>', 'Deploy configuration id')
27
+ .argument('[env]', 'Optional environment, for default is development')
28
+ .option('--run', 'Run app servers and monitor health server')
29
+ .option('--build', 'Build app client')
30
+ .action(Underpost.start.callback)
31
+ .description('Start up server, build pipelines, or services');
32
+
33
+ program
34
+ .command('clone')
35
+ .argument(`<uri>`, 'e.g. username/repository')
36
+ .option('--bare', 'Clone only .git files')
37
+ .description('Clone github repository')
38
+ .action(Underpost.repo.clone);
39
+
40
+ program
41
+ .command('pull')
42
+ .argument('<path>', 'Absolute or relative directory')
43
+ .argument(`<uri>`, 'e.g. username/repository')
44
+ .description('Pull github repository')
45
+ .action(Underpost.repo.pull);
46
+
47
+ program
48
+ .command('cmt')
49
+ .argument('<path>', 'Absolute or relative directory')
50
+ .argument(`<commit-type>`, `Options: ${Object.keys(commitData)}`)
51
+ .argument(`[module-tag]`, 'Optional set module tag')
52
+ .argument(`[message]`, 'Optional set additional message')
53
+ .option('--empty', 'Allow empty files')
54
+ .option('--copy', 'Copy to clipboard message')
55
+ .option('--info', 'Info commit types')
56
+ .description('Commit github repository')
57
+ .action(Underpost.repo.commit);
58
+
59
+ program
60
+ .command('push')
61
+ .argument('<path>', 'Absolute or relative directory')
62
+ .argument(`<uri>`, 'e.g. username/repository')
63
+ .option('-f', 'Force push overwriting repository')
64
+ .description('Push github repository')
65
+ .action(Underpost.repo.push);
66
+
67
+ program
68
+ .command('env')
69
+ .argument('<deploy-id>', `deploy configuration id, if 'clean' restore default`)
70
+ .argument('[env]', 'Optional environment, for default is production')
71
+ .description('Set environment variables files and conf related to <deploy-id>')
72
+ .action(loadConf);
73
+
74
+ program
75
+ .command('config')
76
+ .argument('operator', `Options: ${Object.keys(Underpost.env)}`)
77
+ .argument('[key]', 'Config key')
78
+ .argument('[value]', 'Config value')
79
+ .description(`Manage configuration, operators`)
80
+ .action((...args) => Underpost.env[args[0]](args[1], args[2]));
81
+
82
+ program
83
+ .command('root')
84
+ .description('Get npm root path')
85
+ .action(() => console.log(getNpmRootPath()));
86
+
87
+ program
88
+ .command('cluster')
89
+ .argument('[pod-name]', 'Optional pod name filter')
90
+ .option('--reset', `Delete all clusters and prune all data and caches`)
91
+ .option('--mariadb', 'Init with mariadb statefulset')
92
+ .option('--mongodb', 'Init with mongodb statefulset')
93
+ .option('--postgresql', 'Init with postgresql statefulset')
94
+ .option('--mongodb4', 'Init with mongodb 4.4 service')
95
+ .option('--istio', 'Init base istio cluster')
96
+ .option('--valkey', 'Init with valkey service')
97
+ .option('--contour', 'Init with project contour base HTTPProxy and envoy')
98
+ .option('--cert-manager', 'Init with letsencrypt-prod ClusterIssuer')
99
+ .option('--info', 'Get all kinds objects deployed')
100
+ .option('--full', 'Init with all statefulsets and services available')
101
+ .option('--ns-use <ns-name>', 'Switches current context to namespace')
102
+ .option('--dev', 'init with dev cluster')
103
+ .option('--list-pods', 'Display list pods information')
104
+ .option('--info-capacity', 'display current total machine capacity info')
105
+ .option('--info-capacity-pod', 'display current machine capacity pod info')
106
+ .option('--pull-image', 'Set optional pull associated image')
107
+ .action(Underpost.cluster.init)
108
+ .description('Manage cluster, for default initialization base kind cluster');
109
+
110
+ program
111
+ .command('deploy')
112
+ .argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
113
+ .argument('[env]', 'Optional environment, for default is development')
114
+ .option('--remove', 'Delete deployments and services')
115
+ .option('--sync', 'Sync deployments env, ports, and replicas')
116
+ .option('--info-router', 'Display router structure')
117
+ .option('--expose', 'Expose service match deploy-list')
118
+ .option('--info-util', 'Display kubectl util management commands')
119
+ .option('--cert', 'Reset tls/ssl certificate secrets')
120
+ .option('--build-manifest', 'Build kind yaml manifests: deployments, services, proxy and secrets')
121
+ .option('--dashboard-update', 'Update dashboard instance data with current router config')
122
+ .option('--replicas <replicas>', 'Set custom number of replicas')
123
+ .option('--versions <deployment-versions>', 'Comma separated custom deployment versions')
124
+ .option('--traffic <traffic-versions>', 'Comma separated custom deployment traffic')
125
+ .option('--disable-update-deployment', 'Disable update deployments')
126
+ .option('--info-traffic', 'get traffic conf form current resources deployments')
127
+ .option(
128
+ '--rebuild-clients-bundle',
129
+ 'Inside container, rebuild clients bundle, only static public or storage client files',
130
+ )
131
+ .description('Manage deployment, for default deploy development pods')
132
+ .action(Underpost.deploy.callback);
133
+
134
+ program
135
+ .command('secret')
136
+ .argument('<platform>', `Options: ${Object.keys(Underpost.secret)}`)
137
+ .option('--init', 'Init secrets platform environment')
138
+ .option('--create-from-file <path-env-file>', 'Create secret from env file')
139
+ .option('--list', 'Lists secrets')
140
+ // .option('--delete [secret-key]', 'Delete key secret, if not set, are default delete all')
141
+ // .option('--create [secret-key] [secret-value]', 'Create secret key, with secret value')
142
+ .description(`Manage secrets`)
143
+ .action((...args) => {
144
+ if (args[1].createFromFile) return Underpost.secret[args[0]].createFromEnvFile(args[1].createFromFile);
145
+ if (args[1].list) return Underpost.secret[args[0]].list();
146
+ if (args[1].init) return Underpost.secret[args[0]].init();
147
+ });
148
+
149
+ program
150
+ .command('dockerfile-image-build')
151
+ .option('--path [path]', 'Dockerfile path')
152
+ .option('--image-name [image-name]', 'Set image name')
153
+ .option('--image-path [image-path]', 'Set tar image path')
154
+ .option('--dockerfile-name [dockerfile-name]', 'set Dockerfile name')
155
+ .option('--podman-save', 'Export tar file from podman')
156
+ .option('--kind-load', 'Import tar image to Kind cluster')
157
+ .option('--secrets', 'Dockerfile env secrets')
158
+ .option('--secrets-path [secrets-path]', 'Dockerfile custom path env secrets')
159
+ .option('--no-cache', 'Build without using cache')
160
+ .description('Build image from Dockerfile')
161
+ .action(Underpost.image.dockerfile.build);
162
+
163
+ program
164
+ .command('dockerfile-pull-base-images')
165
+ .description('Pull underpost dockerfile images requirements')
166
+ .action(Underpost.image.dockerfile.pullBaseImages);
167
+
168
+ program
169
+ .command('install')
170
+ .description('Fast import underpost npm dependencies')
171
+ .action(() => {
172
+ fs.copySync(`${underpostRootPath}/node_modules`, './node_modules');
173
+ });
174
+
175
+ program
176
+ .command('db')
177
+ .argument('<deploy-list>', 'Deploy id list, e.g. default-a,default-b')
178
+ .option('--import', 'Import container backups from repositories')
179
+ .option('--export', 'Export container backups to repositories')
180
+ .option('--pod-name <pod-name>', 'Optional pod context')
181
+ .option('--collections <collections>', 'Comma separated collections')
182
+ .option('--out-path <out-path>', 'Custom out path backup')
183
+ .option('--drop', 'Drop databases')
184
+ .option('--preserveUUID', 'Preserve Ids')
185
+ .option('--git', 'Upload to github')
186
+ .option('--hosts <hosts>', 'Comma separated hosts')
187
+ .option('--paths <paths>', 'Comma separated paths')
188
+ .option('--ns <ns-name>', 'Optional name space context')
189
+ .description('Manage databases')
190
+ .action(Underpost.db.callback);
191
+
192
+ program
193
+ .command('script')
194
+ .argument('operator', `Options: ${Object.keys(Underpost.script)}`)
195
+ .argument('<script-name>', 'Script name')
196
+ .argument('[script-value]', 'Literal command, or path')
197
+ .option('--itc', 'Inside container execution context')
198
+ .option('--itc-path', 'Inside container path options')
199
+ .option('--ns <ns-name>', 'Options name space context')
200
+ .option('--pod-name <pod-name>')
201
+ .description(
202
+ 'Supports a number of built-in underpost global scripts and their preset life cycle events as well as arbitrary scripts',
203
+ )
204
+ .action((...args) => Underpost.script[args[0]](args[1], args[2], args[3]));
205
+
206
+ program
207
+ .command('cron')
208
+ .argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
209
+ .argument('[job-list]', `Deploy id list, e.g. ${Object.keys(Underpost.cron)}, for default all available jobs`)
210
+ .option('--itc', 'Inside container execution context')
211
+ .option('--init', 'Init cron jobs for cron job default deploy id')
212
+ .option('--git', 'Upload to github')
213
+ .option('--dashboard-update', 'Update dashboard cron data with current jobs config')
214
+ .description('Cron jobs management')
215
+ .action(Underpost.cron.callback);
216
+
217
+ program
218
+ .command('fs')
219
+ .argument('[path]', 'Absolute or relative directory')
220
+ .option('--rm', 'Remove file')
221
+ .option('--git', 'Current git changes')
222
+ .option('--recursive', 'Upload files recursively')
223
+ .option('--deploy-id <deploy-id>', 'Deploy configuration id')
224
+ .option('--pull', 'Download file')
225
+ .option('--force', 'Force action')
226
+ .option('--storage-file-path <storage-file-path>', 'custom file storage path')
227
+ .description('File storage management, for default upload file')
228
+ .action(Underpost.fs.callback);
229
+
230
+ program
231
+ .command('test')
232
+ .argument('[deploy-list]', 'Deploy id list, e.g. default-a,default-b')
233
+ .description('Manage Test, for default run current underpost default test')
234
+ .option('--itc', 'Inside container execution context')
235
+ .option('--sh', 'Copy to clipboard, container entrypoint shell command')
236
+ .option('--logs', 'Display container logs')
237
+ .option('--pod-name <pod-name>')
238
+ .option('--pod-status <pod-status>')
239
+ .option('--kind-type <kind-type>')
240
+ .action(Underpost.test.callback);
241
+
242
+ program
243
+ .command('monitor')
244
+ .argument('<deploy-id>', 'Deploy configuration id')
245
+ .argument('[env]', 'Optional environment, for default is development')
246
+ .option('--ms-interval <ms-interval>', 'Custom ms interval delta time')
247
+ .option('--now', 'Exec immediately monitor script')
248
+ .option('--single', 'Disable recurrence')
249
+ .option('--replicas <replicas>', 'Set custom number of replicas')
250
+ .option('--type <type>', 'Set custom monitor type')
251
+ .option('--sync', 'Sync with current proxy deployments proxy traffic')
252
+ .description('Monitor health server management')
253
+ .action(Underpost.monitor.callback);
254
+
255
+ const buildCliDoc = () => {
256
+ let md = shellExec(`node bin help`, { silent: true, stdout: true }).split('Options:');
257
+ const baseOptions =
258
+ `## ${md[0].split(`\n`)[2]}
259
+
260
+ ### Usage: ` +
261
+ '`' +
262
+ md[0].split(`\n`)[0].split('Usage: ')[1] +
263
+ '`' +
264
+ `
265
+ ` +
266
+ '```\n Options:' +
267
+ md[1] +
268
+ ' \n```';
269
+ md =
270
+ baseOptions +
271
+ `
272
+
273
+ ## Commands:
274
+ `;
275
+ program.commands.map((o) => {
276
+ md +=
277
+ `
278
+
279
+ ` +
280
+ '### `' +
281
+ o._name +
282
+ '` :' +
283
+ `
284
+ ` +
285
+ '```\n ' +
286
+ shellExec(`node bin help ${o._name}`, { silent: true, stdout: true }) +
287
+ ' \n```' +
288
+ `
289
+ `;
290
+ });
291
+ fs.writeFileSync(`./src/client/public/nexodev/docs/references/Command Line Interface.md`, md, 'utf8');
292
+ fs.writeFileSync(`./cli.md`, md, 'utf8');
293
+ const readmeSplit = `pwa-microservices-template</a>`;
294
+ const readme = fs.readFileSync(`./README.md`, 'utf8').split(readmeSplit);
295
+ fs.writeFileSync(
296
+ './README.md',
297
+ readme[0] +
298
+ readmeSplit +
299
+ `
300
+
301
+ ` +
302
+ baseOptions +
303
+ `
304
+
305
+ <a target="_top" href="https://github.com/underpostnet/pwa-microservices-template/blob/master/cli.md">See complete CLI Docs here.</a>
306
+
307
+ `,
308
+ 'utf8',
309
+ );
310
+ };
311
+
312
+ export { program, buildCliDoc };