underpost 2.8.6 → 2.8.8

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 (103) hide show
  1. package/.vscode/extensions.json +36 -3
  2. package/.vscode/settings.json +2 -0
  3. package/CHANGELOG.md +24 -4
  4. package/Dockerfile +9 -10
  5. package/README.md +41 -2
  6. package/bin/build.js +2 -2
  7. package/bin/db.js +1 -0
  8. package/bin/deploy.js +1521 -130
  9. package/bin/file.js +8 -0
  10. package/bin/index.js +1 -218
  11. package/cli.md +530 -0
  12. package/conf.js +4 -0
  13. package/docker-compose.yml +1 -1
  14. package/jsdoc.json +1 -1
  15. package/manifests/deployment/adminer/deployment.yaml +32 -0
  16. package/manifests/deployment/adminer/kustomization.yaml +7 -0
  17. package/manifests/deployment/adminer/service.yaml +13 -0
  18. package/manifests/deployment/dd-template-development/deployment.yaml +167 -0
  19. package/manifests/deployment/dd-template-development/proxy.yaml +46 -0
  20. package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
  21. package/manifests/deployment/fastapi/backend-service.yml +19 -0
  22. package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
  23. package/manifests/deployment/fastapi/frontend-service.yml +15 -0
  24. package/manifests/deployment/fastapi/initial_data.sh +56 -0
  25. package/manifests/deployment/kafka/deployment.yaml +69 -0
  26. package/manifests/deployment/spark/spark-pi-py.yaml +21 -0
  27. package/manifests/envoy-service-nodeport.yaml +23 -0
  28. package/manifests/kubeadm-calico-config.yaml +119 -0
  29. package/manifests/kubelet-config.yaml +65 -0
  30. package/manifests/lxd/lxd-admin-profile.yaml +17 -0
  31. package/manifests/lxd/lxd-preseed.yaml +30 -0
  32. package/manifests/lxd/underpost-setup.sh +163 -0
  33. package/manifests/maas/lxd-preseed.yaml +32 -0
  34. package/manifests/maas/maas-setup.sh +82 -0
  35. package/manifests/mariadb/statefulset.yaml +2 -1
  36. package/manifests/mariadb/storage-class.yaml +10 -0
  37. package/manifests/mongodb/kustomization.yaml +1 -1
  38. package/manifests/mongodb/statefulset.yaml +12 -11
  39. package/manifests/mongodb/storage-class.yaml +9 -0
  40. package/manifests/mongodb-4.4/service-deployment.yaml +3 -3
  41. package/manifests/mysql/kustomization.yaml +7 -0
  42. package/manifests/mysql/pv-pvc.yaml +27 -0
  43. package/manifests/mysql/statefulset.yaml +55 -0
  44. package/manifests/postgresql/configmap.yaml +9 -0
  45. package/manifests/postgresql/kustomization.yaml +10 -0
  46. package/manifests/postgresql/pv.yaml +15 -0
  47. package/manifests/postgresql/pvc.yaml +13 -0
  48. package/manifests/postgresql/service.yaml +10 -0
  49. package/manifests/postgresql/statefulset.yaml +37 -0
  50. package/manifests/valkey/service.yaml +3 -9
  51. package/manifests/valkey/statefulset.yaml +12 -13
  52. package/package.json +3 -9
  53. package/src/api/default/default.service.js +1 -1
  54. package/src/api/user/user.service.js +14 -11
  55. package/src/cli/baremetal.js +60 -0
  56. package/src/cli/cluster.js +551 -65
  57. package/src/cli/cron.js +39 -8
  58. package/src/cli/db.js +20 -10
  59. package/src/cli/deploy.js +288 -86
  60. package/src/cli/env.js +10 -4
  61. package/src/cli/fs.js +21 -9
  62. package/src/cli/image.js +116 -124
  63. package/src/cli/index.js +319 -0
  64. package/src/cli/lxd.js +395 -0
  65. package/src/cli/monitor.js +236 -0
  66. package/src/cli/repository.js +14 -8
  67. package/src/client/components/core/Account.js +28 -24
  68. package/src/client/components/core/Blockchain.js +1 -1
  69. package/src/client/components/core/CalendarCore.js +14 -84
  70. package/src/client/components/core/CommonJs.js +2 -1
  71. package/src/client/components/core/Css.js +0 -1
  72. package/src/client/components/core/CssCore.js +10 -2
  73. package/src/client/components/core/Docs.js +1 -1
  74. package/src/client/components/core/EventsUI.js +3 -3
  75. package/src/client/components/core/FileExplorer.js +86 -78
  76. package/src/client/components/core/JoyStick.js +2 -2
  77. package/src/client/components/core/LoadingAnimation.js +1 -17
  78. package/src/client/components/core/LogIn.js +3 -3
  79. package/src/client/components/core/LogOut.js +1 -1
  80. package/src/client/components/core/Modal.js +14 -8
  81. package/src/client/components/core/Panel.js +19 -61
  82. package/src/client/components/core/PanelForm.js +13 -22
  83. package/src/client/components/core/Recover.js +3 -3
  84. package/src/client/components/core/RichText.js +1 -11
  85. package/src/client/components/core/Router.js +3 -1
  86. package/src/client/components/core/SignUp.js +2 -2
  87. package/src/client/components/default/RoutesDefault.js +3 -2
  88. package/src/client/services/default/default.management.js +45 -38
  89. package/src/client/ssr/Render.js +2 -0
  90. package/src/index.js +34 -2
  91. package/src/mailer/MailerProvider.js +3 -0
  92. package/src/runtime/lampp/Dockerfile +65 -0
  93. package/src/server/client-build.js +13 -0
  94. package/src/server/conf.js +151 -1
  95. package/src/server/dns.js +56 -18
  96. package/src/server/json-schema.js +77 -0
  97. package/src/server/logger.js +3 -3
  98. package/src/server/network.js +7 -122
  99. package/src/server/peer.js +2 -2
  100. package/src/server/proxy.js +4 -4
  101. package/src/server/runtime.js +24 -11
  102. package/src/server/start.js +122 -0
  103. package/src/server/valkey.js +27 -13
package/src/cli/env.js CHANGED
@@ -25,18 +25,24 @@ class UnderpostRootEnv {
25
25
  delete env[key];
26
26
  writeEnv(envPath, env);
27
27
  },
28
- get(key) {
28
+ get(key, value, options = { plain: false }) {
29
29
  const exeRootPath = `${getNpmRootPath()}/underpost`;
30
30
  const envPath = `${exeRootPath}/.env`;
31
- if (!fs.existsSync(envPath)) return logger.error(`Unable to find underpost root environment`);
31
+ if (!fs.existsSync(envPath)) {
32
+ logger.error(`Unable to find underpost root environment`);
33
+ return undefined;
34
+ }
32
35
  const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
33
- logger.info('underpost root', { [key]: env[key] });
36
+ options?.plain === true ? console.log(env[key]) : logger.info(`${key}(${typeof env[key]})`, env[key]);
34
37
  return env[key];
35
38
  },
36
39
  list() {
37
40
  const exeRootPath = `${getNpmRootPath()}/underpost`;
38
41
  const envPath = `${exeRootPath}/.env`;
39
- if (!fs.existsSync(envPath)) return logger.error(`Unable to find underpost root environment`);
42
+ if (!fs.existsSync(envPath)) {
43
+ logger.error(`Unable to find underpost root environment`);
44
+ return {};
45
+ }
40
46
  const env = dotenv.parse(fs.readFileSync(envPath, 'utf8'));
41
47
  logger.info('underpost root', env);
42
48
  return env;
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,10 +35,18 @@ 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
- const deleteFiles = UnderpostRepository.API.getDeleteFiles(path);
49
+ const deleteFiles = options.pull === true ? [] : UnderpostRepository.API.getDeleteFiles(path);
42
50
  for (const relativePath of deleteFiles) {
43
51
  const _path = path + '/' + relativePath;
44
52
  if (_path in storage) {
@@ -46,10 +54,6 @@ class UnderpostFileStorage {
46
54
  delete storage[_path];
47
55
  }
48
56
  }
49
- const files =
50
- options.git === true
51
- ? UnderpostRepository.API.getChangedFiles(path)
52
- : await fs.readdir(path, { recursive: true });
53
57
  if (options.pull === true) {
54
58
  for (const _path of Object.keys(storage)) {
55
59
  if (!fs.existsSync(_path) || options.force === true) {
@@ -57,7 +61,11 @@ class UnderpostFileStorage {
57
61
  await UnderpostFileStorage.API.pull(_path, options);
58
62
  } else logger.warn(`Pull path already exists`, _path);
59
63
  }
60
- } else
64
+ } else {
65
+ const files =
66
+ options.git === true
67
+ ? UnderpostRepository.API.getChangedFiles(path)
68
+ : await fs.readdir(path, { recursive: true });
61
69
  for (const relativePath of files) {
62
70
  const _path = path + '/' + relativePath;
63
71
  if (fs.statSync(_path).isDirectory()) {
@@ -68,6 +76,7 @@ class UnderpostFileStorage {
68
76
  if (storage) storage[_path] = {};
69
77
  } else logger.warn('File already exists', _path);
70
78
  }
79
+ }
71
80
  UnderpostFileStorage.API.writeStorageConf(storage, storageConf);
72
81
  if (options.git === true) {
73
82
  shellExec(`cd ${path} && git add .`);
@@ -84,7 +93,10 @@ class UnderpostFileStorage {
84
93
  if (options.rm === true) return await UnderpostFileStorage.API.delete(path, options);
85
94
  return await UnderpostFileStorage.API.upload(path, options);
86
95
  },
87
- 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
+ ) {
88
100
  UnderpostFileStorage.API.cloudinaryConfig();
89
101
  const { storage, storageConf } = UnderpostFileStorage.API.getStorageConf(options);
90
102
  // path = UnderpostFileStorage.API.file2Zip(path);
package/src/cli/image.js CHANGED
@@ -1,145 +1,137 @@
1
1
  import fs from 'fs-extra';
2
- import Underpost from '../index.js';
3
- import { shellCd, shellExec } from '../server/process.js';
4
2
  import dotenv from 'dotenv';
5
- import { getNpmRootPath } from '../server/conf.js';
6
- import { timer } from '../client/components/core/CommonJs.js';
7
- import UnderpostRootEnv from './env.js';
3
+ import { loggerFactory } from '../server/logger.js';
4
+ import Underpost from '../index.js';
5
+ import { getUnderpostRootPath } from '../server/conf.js';
6
+ import { shellExec } from '../server/process.js';
8
7
 
9
8
  dotenv.config();
10
9
 
10
+ const logger = loggerFactory(import.meta);
11
+
11
12
  class UnderpostImage {
12
13
  static API = {
13
14
  dockerfile: {
14
- pullBaseImages() {
15
+ /**
16
+ * @method pullBaseImages
17
+ * @description Pulls base images and builds a 'debian-underpost' image,
18
+ * then loads it into the specified Kubernetes cluster type (Kind, Kubeadm, or K3s).
19
+ * @param {object} options - Options for pulling and loading images.
20
+ * @param {boolean} [options.kindLoad=false] - If true, load image into Kind cluster.
21
+ * @param {boolean} [options.kubeadmLoad=false] - If true, load image into Kubeadm cluster.
22
+ * @param {boolean} [options.k3sLoad=false] - If true, load image into K3s cluster.
23
+ * @param {string} [options.path=false] - Path to the Dockerfile context.
24
+ * @param {string} [options.version=''] - Version tag for the image.
25
+ */
26
+ pullBaseImages(
27
+ options = {
28
+ kindLoad: false,
29
+ kubeadmLoad: false,
30
+ k3sLoad: false,
31
+ path: false,
32
+ version: '',
33
+ },
34
+ ) {
15
35
  shellExec(`sudo podman pull docker.io/library/debian:buster`);
36
+ const IMAGE_NAME = `debian-underpost`;
37
+ const IMAGE_NAME_FULL = `${IMAGE_NAME}:${options.version ?? Underpost.version}`;
38
+ let LOAD_TYPE = '';
39
+ if (options.kindLoad === true) {
40
+ LOAD_TYPE = `--kind-load`;
41
+ } else if (options.kubeadmLoad === true) {
42
+ LOAD_TYPE = `--kubeadm-load`;
43
+ } else if (options.k3sLoad === true) {
44
+ // Handle K3s load type
45
+ LOAD_TYPE = `--k3s-load`;
46
+ }
47
+
48
+ shellExec(
49
+ `underpost dockerfile-image-build --podman-save --reset --image-path=. --path ${
50
+ options.path ?? getUnderpostRootPath()
51
+ } --image-name=${IMAGE_NAME_FULL} ${LOAD_TYPE}`,
52
+ );
16
53
  },
54
+ /**
55
+ * @method build
56
+ * @description Builds a Docker image using Podman, optionally saves it as a tar archive,
57
+ * and loads it into a specified Kubernetes cluster (Kind, Kubeadm, or K3s).
58
+ * @param {object} options - Options for building and loading images.
59
+ * @param {string} [options.path=''] - The path to the directory containing the Dockerfile.
60
+ * @param {string} [options.imageName=''] - The name and tag for the image (e.g., 'my-app:latest').
61
+ * @param {string} [options.imagePath=''] - Directory to save the image tar file.
62
+ * @param {string} [options.dockerfileName=''] - Name of the Dockerfile (defaults to 'Dockerfile').
63
+ * @param {boolean} [options.podmanSave=false] - If true, save the image as a tar archive using Podman.
64
+ * @param {boolean} [options.kindLoad=false] - If true, load the image archive into a Kind cluster.
65
+ * @param {boolean} [options.kubeadmLoad=false] - If true, load the image archive into a Kubeadm cluster (uses 'ctr').
66
+ * @param {boolean} [options.k3sLoad=false] - If true, load the image archive into a K3s cluster (uses 'k3s ctr').
67
+ * @param {boolean} [options.secrets=false] - If true, load secrets from the .env file for the build.
68
+ * @param {string} [options.secretsPath=''] - Custom path to the .env file for secrets.
69
+ * @param {boolean} [options.reset=false] - If true, perform a no-cache build.
70
+ */
17
71
  build(
18
- deployId = 'default',
19
- env = 'development',
20
- path = '.',
21
- options = { imageArchive: false, podmanSave: false, imageName: '', imageVersion: '' },
72
+ options = {
73
+ path: '',
74
+ imageName: '',
75
+ imagePath: '',
76
+ dockerfileName: '',
77
+ podmanSave: false,
78
+ kindLoad: false,
79
+ kubeadmLoad: false,
80
+ k3sLoad: false,
81
+ secrets: false,
82
+ secretsPath: '',
83
+ reset: false,
84
+ },
22
85
  ) {
23
- const imgName = `${
24
- options.imageName && typeof options.imageName === 'string' ? options.imageName : `${deployId}-${env}`
25
- }:${
26
- options.imageVersion && typeof options.imageVersions === 'string' ? options.imageVersion : Underpost.version
27
- }`;
28
- const podManImg = `localhost/${imgName}`;
29
- const imagesStoragePath = `/images`;
30
- if (!fs.existsSync(`${path}${imagesStoragePath}`))
31
- fs.mkdirSync(`${path}${imagesStoragePath}`, { recursive: true });
32
- const tarFile = `.${imagesStoragePath}/${imgName.replace(':', '_')}.tar`;
33
-
34
- let secrets = ' ';
86
+ const {
87
+ path,
88
+ imageName,
89
+ imagePath,
90
+ dockerfileName,
91
+ podmanSave,
92
+ secrets,
93
+ secretsPath,
94
+ kindLoad,
95
+ kubeadmLoad,
96
+ k3sLoad,
97
+ reset,
98
+ } = options;
99
+ const podManImg = `localhost/${imageName}`;
100
+ if (imagePath && typeof imagePath === 'string' && !fs.existsSync(imagePath))
101
+ fs.mkdirSync(imagePath, { recursive: true });
102
+ const tarFile = `${imagePath}/${imageName.replace(':', '_')}.tar`;
103
+ let secretsInput = ' ';
35
104
  let secretDockerInput = '';
36
-
37
- const envObj = dotenv.parse(fs.readFileSync(`${getNpmRootPath()}/underpost/.env`, 'utf8'));
38
-
39
- for (const key of Object.keys(envObj)) {
40
- continue;
41
- secrets += ` && export ${key}="${envObj[key]}" `; // $(cat gitlab-token.txt)
42
- secretDockerInput += ` --secret id=${key},env=${key} \ `;
43
- }
44
- // --rm --no-cache
45
- if (options.imageArchive !== true) {
46
- fs.copyFile(`${getNpmRootPath()}/underpost/.env`, `${path}/.env.underpost`);
47
- shellExec(
48
- `cd ${path}${secrets}&& sudo podman build -f ./Dockerfile -t ${imgName} --pull=never --cap-add=CAP_AUDIT_WRITE${secretDockerInput}`,
105
+ let cache = '';
106
+ if (secrets === true) {
107
+ const envObj = dotenv.parse(
108
+ fs.readFileSync(
109
+ secretsPath && typeof secretsPath === 'string' ? secretsPath : `${getNpmRootPath()}/underpost/.env`,
110
+ 'utf8',
111
+ ),
49
112
  );
50
- fs.removeSync(`${path}/.env.underpost`);
51
- }
52
- if (options.imageArchive !== true || options.podmanSave === true)
53
- shellExec(`cd ${path} && podman save -o ${tarFile} ${podManImg}`);
54
- shellExec(`cd ${path} && sudo kind load image-archive ${tarFile}`);
55
- },
56
- async script(deployId = 'default', env = 'development', options = { run: false, build: false }) {
57
- if (deployId === 'deploy') {
58
- const _deployId = UnderpostRootEnv.API.get('deploy-id');
59
- const _env = UnderpostRootEnv.API.get('deploy-env');
60
- const _path = UnderpostRootEnv.API.get('deploy-path');
61
- if (_deployId) {
62
- deployId = _deployId;
63
- if (_env) env = _env;
64
- if (_path) path = _path;
65
- } else {
66
- await timer(30 * 1000);
67
- return await UnderpostImage.API.script(deployId, env, path, options);
113
+ for (const key of Object.keys(envObj)) {
114
+ secretsInput += ` && export ${key}="${envObj[key]}" `; // Example: $(cat gitlab-token.txt)
115
+ secretDockerInput += ` --secret id=${key},env=${key} \ `;
68
116
  }
69
117
  }
70
- if (options.build === true) {
71
- const buildBasePath = `/home/dd`;
72
- const repoName = `engine-${deployId.split('-')[1]}`;
73
- fs.mkdirSync(buildBasePath, { recursive: true });
74
- shellExec(`cd ${buildBasePath} && underpost clone underpostnet/${repoName}`);
75
- shellExec(`cd ${buildBasePath} && sudo mv ./${repoName} ./engine`);
76
- shellExec(`cd ${buildBasePath}/engine && underpost clone underpostnet/${repoName}-private`);
77
- shellExec(`cd ${buildBasePath}/engine && sudo mv ./${repoName}-private ./engine-private`);
78
- shellCd(`${buildBasePath}/engine`);
79
- shellExec(`npm install`);
80
- const itcScripts = fs.readdir('./engine-private/itc-scripts');
81
- for (const itcScript of itcScripts)
82
- if (itcScript.match(deployId)) shellExec(`node ./engine-private/itc-scripts/${itcScript}`);
83
- }
84
- switch (deployId) {
85
- case 'dd-lampp':
86
- {
87
- const lamppPublicPath = '/xampp/htdocs/online';
88
- shellExec(`sudo mkdir -p ${lamppPublicPath}`);
89
- }
90
- break;
91
-
92
- default:
93
- {
94
- {
95
- const originPath = `./src/db/mongo/MongooseDB.js`;
96
- fs.writeFileSync(
97
- originPath,
98
- fs.readFileSync(originPath, 'utf8').replaceAll(
99
- `connect: async (host, name) => {`,
100
- `connect: async (host, name) => {
101
- host = 'mongodb://mongodb-0.mongodb-service:27017';
102
- `,
103
- ),
104
- 'utf8',
105
- );
106
- }
118
+ if (reset === true) cache += ' --rm --no-cache';
119
+ if (path && typeof path === 'string')
120
+ shellExec(
121
+ `cd ${path}${secretsInput}&& sudo podman build -f ./${
122
+ dockerfileName && typeof dockerfileName === 'string' ? dockerfileName : 'Dockerfile'
123
+ } -t ${imageName} --pull=never --cap-add=CAP_AUDIT_WRITE${cache}${secretDockerInput} --network host`,
124
+ );
107
125
 
108
- {
109
- const originPath = `./src/server/valkey.js`;
110
- fs.writeFileSync(
111
- originPath,
112
- fs.readFileSync(originPath, 'utf8').replaceAll(
113
- ` // port: 6379,
114
- // host: 'service-valkey.default.svc.cluster.local',`,
115
- ` port: 6379,
116
- host: 'service-valkey.default.svc.cluster.local',`,
117
- ),
118
- 'utf8',
119
- );
120
- }
121
- }
122
- break;
126
+ if (podmanSave === true) shellExec(`podman save -o ${tarFile} ${podManImg}`);
127
+ if (kindLoad === true) shellExec(`sudo kind load image-archive ${tarFile}`);
128
+ if (kubeadmLoad === true) {
129
+ // Use 'ctr' for Kubeadm
130
+ shellExec(`sudo ctr -n k8s.io images import ${tarFile}`);
123
131
  }
124
- shellExec(`node bin/deploy conf ${deployId} ${env}`);
125
- shellExec(`node bin/deploy build-full-client ${deployId}`);
126
- if (options.run === true) {
127
- const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
128
- if (fs.existsSync(`./engine-private/replica`)) {
129
- const replicas = await fs.readdir(`./engine-private/replica`);
130
- for (const replica of replicas) {
131
- shellExec(`node bin/deploy conf ${replica} ${env}`);
132
- shellExec(`npm ${runCmd} ${replica} deploy`, { async: true });
133
- fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
134
- const monitor = async () => {
135
- await timer(1000);
136
- if (fs.existsSync(`./tmp/await-deploy`)) return await monitor();
137
- };
138
- await monitor();
139
- }
140
- shellExec(`node bin/deploy conf ${deployId} ${env}`);
141
- }
142
- shellExec(`npm ${runCmd} ${deployId} deploy`);
132
+ if (k3sLoad === true) {
133
+ // Use 'k3s ctr' for K3s
134
+ shellExec(`sudo k3s ctr images import ${tarFile}`);
143
135
  }
144
136
  },
145
137
  },