cyberia 2.99.8 → 3.0.2
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/.env.production +1 -0
- package/.github/workflows/engine-cyberia.cd.yml +1 -0
- package/.github/workflows/gitlab.ci.yml +20 -0
- package/.github/workflows/publish.ci.yml +18 -38
- package/.github/workflows/publish.cyberia.ci.yml +18 -38
- package/.vscode/extensions.json +8 -50
- package/.vscode/settings.json +0 -77
- package/CHANGELOG.md +171 -1
- package/{cli.md → CLI-HELP.md} +49 -44
- package/README.md +139 -0
- package/bin/build.js +7 -15
- package/bin/cyberia.js +385 -71
- package/bin/deploy.js +14 -151
- package/bin/file.js +13 -8
- package/bin/index.js +385 -71
- package/bin/zed.js +63 -2
- package/conf.js +32 -3
- package/deployment.yaml +2 -2
- package/jsdoc.json +1 -2
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/manifests/deployment/fastapi/initial_data.sh +4 -52
- package/manifests/ipfs/configmap.yaml +64 -0
- package/manifests/ipfs/headless-service.yaml +35 -0
- package/manifests/ipfs/kustomization.yaml +8 -0
- package/manifests/ipfs/statefulset.yaml +149 -0
- package/manifests/ipfs/storage-class.yaml +9 -0
- package/package.json +15 -11
- package/scripts/k3s-node-setup.sh +89 -0
- package/scripts/lxd-vm-setup.sh +23 -0
- package/scripts/rocky-setup.sh +1 -13
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +2 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +93 -2
- package/src/api/file/file.controller.js +3 -13
- package/src/api/file/file.ref.json +0 -21
- package/src/api/ipfs/ipfs.controller.js +104 -0
- package/src/api/ipfs/ipfs.model.js +71 -0
- package/src/api/ipfs/ipfs.router.js +31 -0
- package/src/api/ipfs/ipfs.service.js +193 -0
- package/src/api/object-layer/README.md +139 -0
- package/src/api/object-layer/object-layer.controller.js +3 -0
- package/src/api/object-layer/object-layer.model.js +15 -1
- package/src/api/object-layer/object-layer.router.js +6 -10
- package/src/api/object-layer/object-layer.service.js +311 -182
- package/src/api/user/user.router.js +0 -47
- package/src/cli/baremetal.js +7 -9
- package/src/cli/cluster.js +95 -152
- package/src/cli/deploy.js +8 -5
- package/src/cli/index.js +31 -31
- package/src/cli/ipfs.js +184 -0
- package/src/cli/lxd.js +192 -237
- package/src/cli/repository.js +4 -1
- package/src/cli/run.js +17 -2
- package/src/client/components/core/Docs.js +92 -6
- package/src/client/components/core/LoadingAnimation.js +2 -3
- package/src/client/components/core/Modal.js +1 -1
- package/src/client/components/core/VanillaJs.js +36 -25
- package/src/client/components/cyberia/ObjectLayerEngineModal.js +4 -5
- package/src/client/components/cyberia/ObjectLayerEngineViewer.js +280 -29
- package/src/client/services/ipfs/ipfs.service.js +144 -0
- package/src/client/services/object-layer/object-layer.management.js +161 -8
- package/src/client/services/user/user.management.js +0 -5
- package/src/client/services/user/user.service.js +1 -1
- package/src/index.js +12 -1
- package/src/runtime/express/Express.js +4 -3
- package/src/server/auth.js +18 -18
- package/src/server/client-build-docs.js +178 -41
- package/src/server/conf.js +1 -1
- package/src/server/ipfs-client.js +433 -0
- package/src/server/logger.js +22 -10
- package/src/server/object-layer.js +649 -18
- package/src/server/semantic-layer-generator.js +1083 -0
- package/src/server/shape-generator.js +952 -0
- package/test/shape-generator.test.js +457 -0
- package/.vscode/zed.keymap.json +0 -39
- package/.vscode/zed.settings.json +0 -20
- package/bin/ssl.js +0 -63
- package/manifests/lxd/underpost-setup.sh +0 -163
|
@@ -99,22 +99,6 @@ const UserRouter = (options) => {
|
|
|
99
99
|
#swagger.description = 'This endpoint get a JWT for authenticated user'
|
|
100
100
|
#swagger.path = '/user/auth'
|
|
101
101
|
#swagger.method = 'post'
|
|
102
|
-
#swagger.produces = ['application/json']
|
|
103
|
-
#swagger.consumes = ['application/json']
|
|
104
|
-
|
|
105
|
-
#swagger.requestBody = {
|
|
106
|
-
in: 'body',
|
|
107
|
-
description: 'User data',
|
|
108
|
-
required: true,
|
|
109
|
-
content: {
|
|
110
|
-
'application/json': {
|
|
111
|
-
schema: {
|
|
112
|
-
$ref: '#/components/schemas/userLogInRequest'
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
102
|
#swagger.responses[200] = {
|
|
119
103
|
description: 'User created successfully',
|
|
120
104
|
content: {
|
|
@@ -148,22 +132,6 @@ const UserRouter = (options) => {
|
|
|
148
132
|
#swagger.description = 'This endpoint will create a new user account'
|
|
149
133
|
#swagger.path = '/user'
|
|
150
134
|
#swagger.method = 'post'
|
|
151
|
-
#swagger.produces = ['application/json']
|
|
152
|
-
#swagger.consumes = ['application/json']
|
|
153
|
-
|
|
154
|
-
#swagger.requestBody = {
|
|
155
|
-
in: 'body',
|
|
156
|
-
description: 'User data',
|
|
157
|
-
required: true,
|
|
158
|
-
content: {
|
|
159
|
-
'application/json': {
|
|
160
|
-
schema: {
|
|
161
|
-
$ref: '#/components/schemas/userRequest'
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
135
|
#swagger.responses[200] = {
|
|
168
136
|
description: 'User created successfully',
|
|
169
137
|
content: {
|
|
@@ -274,8 +242,6 @@ const UserRouter = (options) => {
|
|
|
274
242
|
#swagger.description = 'This endpoint will update user data by ID'
|
|
275
243
|
#swagger.path = '/user/{id}'
|
|
276
244
|
#swagger.method = 'put'
|
|
277
|
-
#swagger.produces = ['application/json']
|
|
278
|
-
#swagger.consumes = ['application/json']
|
|
279
245
|
#swagger.security = [{
|
|
280
246
|
'bearerAuth': []
|
|
281
247
|
}]
|
|
@@ -287,19 +253,6 @@ const UserRouter = (options) => {
|
|
|
287
253
|
type: 'string'
|
|
288
254
|
}
|
|
289
255
|
|
|
290
|
-
#swagger.requestBody = {
|
|
291
|
-
in: 'body',
|
|
292
|
-
description: 'User data',
|
|
293
|
-
required: true,
|
|
294
|
-
content: {
|
|
295
|
-
'application/json': {
|
|
296
|
-
schema: {
|
|
297
|
-
$ref: '#/components/schemas/userRequest'
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
256
|
#swagger.responses[200] = {
|
|
304
257
|
description: 'User updated successfully',
|
|
305
258
|
content: {
|
package/src/cli/baremetal.js
CHANGED
|
@@ -534,9 +534,6 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
534
534
|
if (options.controlServerDbInstall === true) {
|
|
535
535
|
// Deploy the database provider and manage MAAS database.
|
|
536
536
|
shellExec(`node ${underpostRoot}/bin/deploy ${dbProviderId} install`);
|
|
537
|
-
shellExec(
|
|
538
|
-
`node ${underpostRoot}/bin/deploy pg-drop-db ${process.env.DB_PG_MAAS_NAME} ${process.env.DB_PG_MAAS_USER}`,
|
|
539
|
-
);
|
|
540
537
|
shellExec(`node ${underpostRoot}/bin/deploy maas-db`);
|
|
541
538
|
return;
|
|
542
539
|
}
|
|
@@ -1150,8 +1147,9 @@ rm -rf ${artifacts.join(' ')}`);
|
|
|
1150
1147
|
machine: machine ? machine.system_id : null,
|
|
1151
1148
|
});
|
|
1152
1149
|
|
|
1153
|
-
const { discovery, machine: discoveredMachine } =
|
|
1154
|
-
|
|
1150
|
+
const { discovery, machine: discoveredMachine } = await Underpost.baremetal.commissionMonitor(
|
|
1151
|
+
commissionMonitorPayload,
|
|
1152
|
+
);
|
|
1155
1153
|
if (discoveredMachine) machine = discoveredMachine;
|
|
1156
1154
|
}
|
|
1157
1155
|
},
|
|
@@ -2496,10 +2494,10 @@ fi
|
|
|
2496
2494
|
const discoverHostname = discovery.hostname
|
|
2497
2495
|
? discovery.hostname
|
|
2498
2496
|
: discovery.mac_organization
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2497
|
+
? discovery.mac_organization
|
|
2498
|
+
: discovery.domain
|
|
2499
|
+
? discovery.domain
|
|
2500
|
+
: `generic-host-${s4()}${s4()}`;
|
|
2503
2501
|
|
|
2504
2502
|
console.log(discoverHostname.bgBlue.bold.white);
|
|
2505
2503
|
console.log('ip target:'.green + ipAddress, 'ip discovered:'.green + discovery.ip);
|
package/src/cli/cluster.js
CHANGED
|
@@ -36,7 +36,7 @@ class UnderpostCluster {
|
|
|
36
36
|
* @param {boolean} [options.mysql=false] - Deploy MySQL.
|
|
37
37
|
* @param {boolean} [options.postgresql=false] - Deploy PostgreSQL.
|
|
38
38
|
* @param {boolean} [options.valkey=false] - Deploy Valkey.
|
|
39
|
-
* @param {boolean} [options.
|
|
39
|
+
* @param {boolean} [options.ipfs=false] - Deploy ipfs-cluster statefulset.
|
|
40
40
|
* @param {boolean} [options.info=false] - Display extensive Kubernetes cluster information.
|
|
41
41
|
* @param {boolean} [options.certManager=false] - Deploy Cert-Manager for certificate management.
|
|
42
42
|
* @param {boolean} [options.listPods=false] - List Kubernetes pods.
|
|
@@ -57,10 +57,10 @@ class UnderpostCluster {
|
|
|
57
57
|
* @param {string} [options.prom=''] - Initialize the cluster with a Prometheus Operator deployment and monitor scrap for specified hosts.
|
|
58
58
|
* @param {boolean} [options.uninstallHost=false] - Uninstall all host components.
|
|
59
59
|
* @param {boolean} [options.config=false] - Apply general host configuration (SELinux, containerd, sysctl, firewalld).
|
|
60
|
-
* @param {boolean} [options.worker=false] - Configure as a worker node (for Kubeadm or K3s join).
|
|
61
60
|
* @param {boolean} [options.chown=false] - Set up kubectl configuration for the current user.
|
|
62
61
|
* @param {boolean} [options.removeVolumeHostPaths=false] - Remove data from host paths used by Persistent Volumes.
|
|
63
62
|
* @param {string} [options.hosts] - Set custom hosts entries.
|
|
63
|
+
* @param {string} [options.replicas] - Set the number of replicas for certain deployments.
|
|
64
64
|
* @memberof UnderpostCluster
|
|
65
65
|
*/
|
|
66
66
|
async init(
|
|
@@ -73,7 +73,7 @@ class UnderpostCluster {
|
|
|
73
73
|
mysql: false,
|
|
74
74
|
postgresql: false,
|
|
75
75
|
valkey: false,
|
|
76
|
-
|
|
76
|
+
ipfs: false,
|
|
77
77
|
info: false,
|
|
78
78
|
certManager: false,
|
|
79
79
|
listPods: false,
|
|
@@ -94,32 +94,28 @@ class UnderpostCluster {
|
|
|
94
94
|
prom: '',
|
|
95
95
|
uninstallHost: false,
|
|
96
96
|
config: false,
|
|
97
|
-
worker: false,
|
|
98
97
|
chown: false,
|
|
99
98
|
removeVolumeHostPaths: false,
|
|
100
99
|
hosts: '',
|
|
100
|
+
replicas: '',
|
|
101
101
|
},
|
|
102
102
|
) {
|
|
103
|
-
|
|
104
|
-
if (options.initHost === true) return Underpost.cluster.initHost();
|
|
103
|
+
if (options.initHost) return Underpost.cluster.initHost();
|
|
105
104
|
|
|
106
|
-
|
|
107
|
-
if (options.uninstallHost === true) return Underpost.cluster.uninstallHost();
|
|
105
|
+
if (options.uninstallHost) return Underpost.cluster.uninstallHost();
|
|
108
106
|
|
|
109
|
-
|
|
110
|
-
if (options.config === true) return Underpost.cluster.config();
|
|
107
|
+
if (options.config) return Underpost.cluster.config();
|
|
111
108
|
|
|
112
|
-
|
|
113
|
-
if (options.chown === true) return Underpost.cluster.chown();
|
|
109
|
+
if (options.chown) return Underpost.cluster.chown();
|
|
114
110
|
|
|
115
111
|
const npmRoot = getNpmRootPath();
|
|
116
|
-
const underpostRoot = options
|
|
112
|
+
const underpostRoot = options.dev ? '.' : `${npmRoot}/underpost`;
|
|
117
113
|
|
|
118
|
-
if (options.listPods
|
|
114
|
+
if (options.listPods) return console.table(Underpost.deploy.get(podName ?? undefined));
|
|
119
115
|
// Set default namespace if not specified
|
|
120
116
|
if (!options.namespace) options.namespace = 'default';
|
|
121
117
|
|
|
122
|
-
if (options.nsUse
|
|
118
|
+
if (options.nsUse) {
|
|
123
119
|
// Verify if namespace exists, create if not
|
|
124
120
|
const namespaceExists = shellExec(`kubectl get namespace ${options.nsUse} --ignore-not-found -o name`, {
|
|
125
121
|
stdout: true,
|
|
@@ -140,11 +136,14 @@ class UnderpostCluster {
|
|
|
140
136
|
}
|
|
141
137
|
|
|
142
138
|
// Reset Kubernetes cluster components (Kind/Kubeadm/K3s) and container runtimes
|
|
143
|
-
if (options.reset
|
|
139
|
+
if (options.reset) {
|
|
140
|
+
const clusterType = options.k3s ? 'k3s' : options.kubeadm ? 'kubeadm' : 'kind';
|
|
144
141
|
return await Underpost.cluster.safeReset({
|
|
145
142
|
underpostRoot,
|
|
146
143
|
removeVolumeHostPaths: options.removeVolumeHostPaths,
|
|
144
|
+
clusterType,
|
|
147
145
|
});
|
|
146
|
+
}
|
|
148
147
|
|
|
149
148
|
// Check if a cluster (Kind, Kubeadm, or K3s) is already initialized
|
|
150
149
|
const alreadyKubeadmCluster = Underpost.deploy.get('calico-kube-controllers')[0];
|
|
@@ -153,67 +152,21 @@ class UnderpostCluster {
|
|
|
153
152
|
const alreadyK3sCluster = Underpost.deploy.get('svclb-traefik')[0];
|
|
154
153
|
|
|
155
154
|
// --- Kubeadm/Kind/K3s Cluster Initialization ---
|
|
156
|
-
|
|
157
|
-
// It prevents re-initialization if a cluster is already detected.
|
|
158
|
-
if (!options.worker && !alreadyKubeadmCluster && !alreadyKindCluster && !alreadyK3sCluster) {
|
|
155
|
+
if (!alreadyKubeadmCluster && !alreadyKindCluster && !alreadyK3sCluster) {
|
|
159
156
|
Underpost.cluster.config();
|
|
160
|
-
if (options.k3s
|
|
157
|
+
if (options.k3s) {
|
|
161
158
|
logger.info('Initializing K3s control plane...');
|
|
162
159
|
// Install K3s
|
|
163
|
-
|
|
160
|
+
logger.info('Installing K3s...');
|
|
164
161
|
shellExec(`curl -sfL https://get.k3s.io | sh -`);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
// Move k3s binary to /bin/k3s and make it executable
|
|
168
|
-
shellExec(`sudo mv /usr/local/bin/k3s /bin/k3s`);
|
|
169
|
-
shellExec(`sudo chmod +x /bin/k3s`);
|
|
170
|
-
console.log('K3s binary moved to /bin/k3s and made executable.');
|
|
162
|
+
logger.info('K3s installation completed.');
|
|
171
163
|
|
|
172
|
-
// Configure kubectl for the current user for K3s *before* checking readiness
|
|
173
|
-
// This ensures kubectl can find the K3s kubeconfig immediately after K3s installation.
|
|
174
164
|
Underpost.cluster.chown('k3s');
|
|
175
165
|
|
|
176
|
-
// Wait for K3s to be ready
|
|
177
166
|
logger.info('Waiting for K3s to be ready...');
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const delayMs = 5000; // 5 seconds
|
|
182
|
-
|
|
183
|
-
while (!k3sReady && retries < maxRetries) {
|
|
184
|
-
try {
|
|
185
|
-
// Explicitly use KUBECONFIG for kubectl commands to ensure it points to K3s config
|
|
186
|
-
const nodes = shellExec(`KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes -o json`, {
|
|
187
|
-
stdout: true,
|
|
188
|
-
silent: true,
|
|
189
|
-
});
|
|
190
|
-
const parsedNodes = JSON.parse(nodes);
|
|
191
|
-
if (
|
|
192
|
-
parsedNodes.items.some((node) =>
|
|
193
|
-
node.status.conditions.some((cond) => cond.type === 'Ready' && cond.status === 'True'),
|
|
194
|
-
)
|
|
195
|
-
) {
|
|
196
|
-
k3sReady = true;
|
|
197
|
-
logger.info('K3s cluster is ready.');
|
|
198
|
-
} else {
|
|
199
|
-
logger.info(`K3s not yet ready. Retrying in ${delayMs / 1000} seconds...`);
|
|
200
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
201
|
-
}
|
|
202
|
-
} catch (error) {
|
|
203
|
-
logger.info(`Error checking K3s status: ${error.message}. Retrying in ${delayMs / 1000} seconds...`);
|
|
204
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
205
|
-
}
|
|
206
|
-
retries++;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (!k3sReady) {
|
|
210
|
-
logger.error('K3s cluster did not become ready in time. Please check the K3s logs.');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// K3s includes local-path-provisioner by default, so no need to install explicitly.
|
|
215
|
-
logger.info('K3s comes with local-path-provisioner by default. Skipping explicit installation.');
|
|
216
|
-
} else if (options.kubeadm === true) {
|
|
167
|
+
shellExec(`sudo systemctl is-active --wait k3s || sudo systemctl wait --for=active k3s.service`);
|
|
168
|
+
logger.info('K3s service is active.');
|
|
169
|
+
} else if (options.kubeadm) {
|
|
217
170
|
logger.info('Initializing Kubeadm control plane...');
|
|
218
171
|
// Set default values if not provided
|
|
219
172
|
const podNetworkCidr = options.podNetworkCidr || '192.168.0.0/16';
|
|
@@ -249,32 +202,22 @@ class UnderpostCluster {
|
|
|
249
202
|
logger.info('Initializing Kind cluster...');
|
|
250
203
|
shellExec(
|
|
251
204
|
`cd ${underpostRoot}/manifests && kind create cluster --config kind-config${
|
|
252
|
-
options
|
|
205
|
+
options.dev ? '-dev' : ''
|
|
253
206
|
}.yaml`,
|
|
254
207
|
);
|
|
255
208
|
Underpost.cluster.chown('kind'); // Pass 'kind' to chown
|
|
256
209
|
}
|
|
257
|
-
} else if (options.worker === true) {
|
|
258
|
-
// Worker node specific configuration (kubeadm join command needs to be executed separately)
|
|
259
|
-
logger.info('Worker node configuration applied. Awaiting join command...');
|
|
260
|
-
// No direct cluster initialization here for workers. The `kubeadm join` or `k3s agent` command
|
|
261
|
-
// needs to be run on the worker after the control plane is up and a token is created.
|
|
262
|
-
// This part of the script is for general worker setup, not the join itself.
|
|
263
|
-
} else {
|
|
264
|
-
logger.warn('Cluster already initialized or worker flag not set for worker node.');
|
|
265
210
|
}
|
|
266
211
|
|
|
267
212
|
// --- Optional Component Deployments (Databases, Ingress, Cert-Manager) ---
|
|
268
213
|
// These deployments happen after the base cluster is up.
|
|
269
214
|
|
|
270
|
-
if (options.
|
|
215
|
+
if (options.dedicatedGpu) {
|
|
271
216
|
shellExec(`node ${underpostRoot}/bin/deploy nvidia-gpu-operator`);
|
|
272
|
-
shellExec(
|
|
273
|
-
`node ${underpostRoot}/bin/deploy kubeflow-spark-operator${options.kubeadm === true ? ' kubeadm' : ''}`,
|
|
274
|
-
);
|
|
217
|
+
shellExec(`node ${underpostRoot}/bin/deploy kubeflow-spark-operator${options.kubeadm ? ' kubeadm' : ''}`);
|
|
275
218
|
}
|
|
276
219
|
|
|
277
|
-
if (options.grafana
|
|
220
|
+
if (options.grafana) {
|
|
278
221
|
shellExec(`kubectl delete deployment grafana -n ${options.namespace} --ignore-not-found`);
|
|
279
222
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/grafana -n ${options.namespace}`);
|
|
280
223
|
const yaml = `${fs
|
|
@@ -287,7 +230,7 @@ EOF
|
|
|
287
230
|
`);
|
|
288
231
|
}
|
|
289
232
|
|
|
290
|
-
if (options.prom
|
|
233
|
+
if (options.prom) {
|
|
291
234
|
shellExec(`kubectl delete deployment prometheus --ignore-not-found`);
|
|
292
235
|
shellExec(`kubectl delete configmap prometheus-config --ignore-not-found`);
|
|
293
236
|
shellExec(`kubectl delete service prometheus --ignore-not-found`);
|
|
@@ -306,41 +249,26 @@ EOF
|
|
|
306
249
|
`);
|
|
307
250
|
}
|
|
308
251
|
|
|
309
|
-
if (options.
|
|
310
|
-
if (options.pullImage
|
|
311
|
-
// shellExec(`sudo podman pull valkey/valkey:latest`);
|
|
312
|
-
if (!options.kubeadm && !options.k3s) {
|
|
313
|
-
// Only load if not kubeadm/k3s (Kind needs it)
|
|
314
|
-
shellExec(`docker pull valkey/valkey:latest`);
|
|
315
|
-
shellExec(`sudo kind load docker-image valkey/valkey:latest`);
|
|
316
|
-
} else if (options.kubeadm || options.k3s)
|
|
317
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
318
|
-
shellExec(`sudo crictl pull valkey/valkey:latest`);
|
|
319
|
-
}
|
|
252
|
+
if (options.valkey) {
|
|
253
|
+
if (options.pullImage) Underpost.cluster.pullImage('valkey/valkey:latest', options);
|
|
320
254
|
shellExec(`kubectl delete statefulset valkey-service -n ${options.namespace} --ignore-not-found`);
|
|
321
255
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/valkey -n ${options.namespace}`);
|
|
322
256
|
await Underpost.test.statusMonitor('valkey-service', 'Running', 'pods', 1000, 60 * 10);
|
|
323
257
|
}
|
|
324
|
-
if (options.
|
|
258
|
+
if (options.ipfs) {
|
|
259
|
+
await Underpost.ipfs.deploy(options, underpostRoot);
|
|
260
|
+
}
|
|
261
|
+
if (options.mariadb) {
|
|
325
262
|
shellExec(
|
|
326
263
|
`sudo kubectl create secret generic mariadb-secret --from-file=username=/home/dd/engine/engine-private/mariadb-username --from-file=password=/home/dd/engine/engine-private/mariadb-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
327
264
|
);
|
|
328
265
|
shellExec(`kubectl delete statefulset mariadb-statefulset -n ${options.namespace} --ignore-not-found`);
|
|
329
266
|
|
|
330
|
-
if (options.pullImage
|
|
331
|
-
// shellExec(`sudo podman pull mariadb:latest`);
|
|
332
|
-
if (!options.kubeadm && !options.k3s) {
|
|
333
|
-
// Only load if not kubeadm/k3s (Kind needs it)
|
|
334
|
-
shellExec(`docker pull mariadb:latest`);
|
|
335
|
-
shellExec(`sudo kind load docker-image mariadb:latest`);
|
|
336
|
-
} else if (options.kubeadm || options.k3s)
|
|
337
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
338
|
-
shellExec(`sudo crictl pull mariadb:latest`);
|
|
339
|
-
}
|
|
267
|
+
if (options.pullImage) Underpost.cluster.pullImage('mariadb:latest', options);
|
|
340
268
|
shellExec(`kubectl apply -f ${underpostRoot}/manifests/mariadb/storage-class.yaml -n ${options.namespace}`);
|
|
341
269
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mariadb -n ${options.namespace}`);
|
|
342
270
|
}
|
|
343
|
-
if (options.
|
|
271
|
+
if (options.mysql) {
|
|
344
272
|
shellExec(
|
|
345
273
|
`sudo kubectl create secret generic mysql-secret --from-file=username=/home/dd/engine/engine-private/mysql-username --from-file=password=/home/dd/engine/engine-private/mysql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
346
274
|
);
|
|
@@ -349,31 +277,15 @@ EOF
|
|
|
349
277
|
shellExec(`sudo chown -R $(whoami):$(whoami) /mnt/data`);
|
|
350
278
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mysql -n ${options.namespace}`);
|
|
351
279
|
}
|
|
352
|
-
if (options.
|
|
353
|
-
if (options.pullImage
|
|
354
|
-
if (!options.kubeadm && !options.k3s) {
|
|
355
|
-
// Only load if not kubeadm/k3s (Kind needs it)
|
|
356
|
-
shellExec(`docker pull postgres:latest`);
|
|
357
|
-
shellExec(`sudo kind load docker-image postgres:latest`);
|
|
358
|
-
} else if (options.kubeadm || options.k3s)
|
|
359
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
360
|
-
shellExec(`sudo crictl pull postgres:latest`);
|
|
361
|
-
}
|
|
280
|
+
if (options.postgresql) {
|
|
281
|
+
if (options.pullImage) Underpost.cluster.pullImage('postgres:latest', options);
|
|
362
282
|
shellExec(
|
|
363
283
|
`sudo kubectl create secret generic postgres-secret --from-file=password=/home/dd/engine/engine-private/postgresql-password --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
364
284
|
);
|
|
365
285
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/postgresql -n ${options.namespace}`);
|
|
366
286
|
}
|
|
367
|
-
if (options.mongodb4
|
|
368
|
-
if (options.pullImage
|
|
369
|
-
if (!options.kubeadm && !options.k3s) {
|
|
370
|
-
// Only load if not kubeadm/k3s (Kind needs it)
|
|
371
|
-
shellExec(`docker pull mongo:4.4`);
|
|
372
|
-
shellExec(`sudo kind load docker-image mongo:4.4`);
|
|
373
|
-
} else if (options.kubeadm || options.k3s)
|
|
374
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
375
|
-
shellExec(`sudo crictl pull mongo:4.4`);
|
|
376
|
-
}
|
|
287
|
+
if (options.mongodb4) {
|
|
288
|
+
if (options.pullImage) Underpost.cluster.pullImage('mongo:4.4', options);
|
|
377
289
|
shellExec(`kubectl apply -k ${underpostRoot}/manifests/mongodb-4.4 -n ${options.namespace}`);
|
|
378
290
|
|
|
379
291
|
const deploymentName = 'mongodb-deployment';
|
|
@@ -394,16 +306,8 @@ EOF
|
|
|
394
306
|
--eval 'rs.initiate(${JSON.stringify(mongoConfig)})'`,
|
|
395
307
|
);
|
|
396
308
|
}
|
|
397
|
-
} else if (options.
|
|
398
|
-
if (options.pullImage
|
|
399
|
-
if (!options.kubeadm && !options.k3s) {
|
|
400
|
-
// Only load if not kubeadm/k3s (Kind needs it)
|
|
401
|
-
shellExec(`docker pull mongo:latest`);
|
|
402
|
-
shellExec(`sudo kind load docker-image mongo:latest`);
|
|
403
|
-
} else if (options.kubeadm || options.k3s)
|
|
404
|
-
// For kubeadm/k3s, ensure it's available for containerd
|
|
405
|
-
shellExec(`sudo crictl pull mongo:latest`);
|
|
406
|
-
}
|
|
309
|
+
} else if (options.mongodb) {
|
|
310
|
+
if (options.pullImage) Underpost.cluster.pullImage('mongo:latest', options);
|
|
407
311
|
shellExec(
|
|
408
312
|
`sudo kubectl create secret generic mongodb-keyfile --from-file=/home/dd/engine/engine-private/mongodb-keyfile --dry-run=client -o yaml | kubectl apply -f - -n ${options.namespace}`,
|
|
409
313
|
);
|
|
@@ -432,11 +336,11 @@ EOF
|
|
|
432
336
|
}
|
|
433
337
|
}
|
|
434
338
|
|
|
435
|
-
if (options.
|
|
339
|
+
if (options.contour) {
|
|
436
340
|
shellExec(
|
|
437
341
|
`kubectl apply -f https://cdn.jsdelivr.net/gh/projectcontour/contour@release-1.33/examples/render/contour.yaml`,
|
|
438
342
|
);
|
|
439
|
-
if (options.kubeadm
|
|
343
|
+
if (options.kubeadm) {
|
|
440
344
|
// Envoy service might need NodePort for kubeadm
|
|
441
345
|
shellExec(
|
|
442
346
|
`sudo kubectl apply -f ${underpostRoot}/manifests/envoy-service-nodeport.yaml -n ${options.namespace}`,
|
|
@@ -446,7 +350,7 @@ EOF
|
|
|
446
350
|
// so a specific NodePort service might not be needed or can be configured differently.
|
|
447
351
|
}
|
|
448
352
|
|
|
449
|
-
if (options.
|
|
353
|
+
if (options.certManager) {
|
|
450
354
|
if (!Underpost.deploy.get('cert-manager').find((p) => p.STATUS === 'Running')) {
|
|
451
355
|
shellExec(`helm repo add jetstack https://charts.jetstack.io --force-update`);
|
|
452
356
|
shellExec(
|
|
@@ -464,6 +368,32 @@ EOF
|
|
|
464
368
|
}
|
|
465
369
|
},
|
|
466
370
|
|
|
371
|
+
/**
|
|
372
|
+
* @method pullImage
|
|
373
|
+
* @description Pulls a container image using the appropriate runtime based on the cluster type.
|
|
374
|
+
* - For Kind clusters: pulls via Docker and loads the image into the Kind cluster.
|
|
375
|
+
* - For Kubeadm/K3s clusters: pulls via crictl (containerd).
|
|
376
|
+
* @param {string} image - The fully-qualified container image reference (e.g. 'mongo:latest').
|
|
377
|
+
* @param {object} options - The cluster options object from `init`.
|
|
378
|
+
* @param {boolean} [options.kubeadm=false] - Whether the cluster is Kubeadm-based.
|
|
379
|
+
* @param {boolean} [options.k3s=false] - Whether the cluster is K3s-based.
|
|
380
|
+
* @memberof UnderpostCluster
|
|
381
|
+
*/
|
|
382
|
+
pullImage(image, options = { kubeadm: false, k3s: false }) {
|
|
383
|
+
if (!options.kubeadm && !options.k3s) {
|
|
384
|
+
const tarPath = `/tmp/kind-image-${image.replace(/[\/:]/g, '-')}.tar`;
|
|
385
|
+
shellExec(`docker pull ${image}`);
|
|
386
|
+
shellExec(`docker save ${image} -o ${tarPath}`);
|
|
387
|
+
shellExec(
|
|
388
|
+
`for node in $(kind get nodes); do cat ${tarPath} | docker exec -i $node ctr --namespace=k8s.io images import -; done`,
|
|
389
|
+
);
|
|
390
|
+
shellExec(`rm -f ${tarPath}`);
|
|
391
|
+
} else if (options.kubeadm || options.k3s) {
|
|
392
|
+
// Kubeadm / K3s: use crictl to pull directly into containerd
|
|
393
|
+
shellExec(`sudo crictl pull ${image}`);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
|
|
467
397
|
/**
|
|
468
398
|
* @method config
|
|
469
399
|
* @description Configures host-level settings required for Kubernetes.
|
|
@@ -570,12 +500,15 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
570
500
|
* @description Performs a complete reset of the Kubernetes cluster and its container environments.
|
|
571
501
|
* This version focuses on correcting persistent permission errors (such as 'permission denied'
|
|
572
502
|
* in coredns) by restoring SELinux security contexts and safely cleaning up cluster artifacts.
|
|
503
|
+
* Only the uninstall/delete commands specific to the given clusterType are executed; all other
|
|
504
|
+
* cleanup steps (log truncation, filesystem, network) are always run as generic k8s resets.
|
|
573
505
|
* @param {object} [options] - Configuration options for the reset.
|
|
574
506
|
* @param {string} [options.underpostRoot] - The root path of the underpost project.
|
|
575
507
|
* @param {boolean} [options.removeVolumeHostPaths=false] - Whether to remove data from host paths used by Persistent Volumes.
|
|
508
|
+
* @param {string} [options.clusterType='kind'] - The type of cluster to reset: 'kind', 'kubeadm', or 'k3s'.
|
|
576
509
|
* @memberof UnderpostCluster
|
|
577
510
|
*/
|
|
578
|
-
async safeReset(options = { underpostRoot: '.', removeVolumeHostPaths: false }) {
|
|
511
|
+
async safeReset(options = { underpostRoot: '.', removeVolumeHostPaths: false, clusterType: 'kind' }) {
|
|
579
512
|
logger.info('Starting a safe and comprehensive reset of Kubernetes and container environments...');
|
|
580
513
|
|
|
581
514
|
try {
|
|
@@ -645,14 +578,22 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
645
578
|
// Safely unmount pod filesystems to avoid errors.
|
|
646
579
|
shellExec('sudo umount -f /var/lib/kubelet/pods/*/*');
|
|
647
580
|
|
|
648
|
-
// Phase 3: Execute official uninstallation commands
|
|
649
|
-
|
|
650
|
-
logger.info(
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
581
|
+
// Phase 3: Execute official uninstallation commands (type-specific)
|
|
582
|
+
const clusterType = options.clusterType || 'kind';
|
|
583
|
+
logger.info(
|
|
584
|
+
`Phase 3/7: Executing official reset/uninstallation commands for cluster type: '${clusterType}'...`,
|
|
585
|
+
);
|
|
586
|
+
if (clusterType === 'kubeadm') {
|
|
587
|
+
logger.info(' -> Executing kubeadm reset...');
|
|
588
|
+
shellExec('sudo kubeadm reset --force');
|
|
589
|
+
} else if (clusterType === 'k3s') {
|
|
590
|
+
logger.info(' -> Executing K3s uninstallation script if it exists...');
|
|
591
|
+
shellExec('sudo /usr/local/bin/k3s-uninstall.sh');
|
|
592
|
+
} else {
|
|
593
|
+
// Default: kind
|
|
594
|
+
logger.info(' -> Deleting Kind clusters...');
|
|
595
|
+
shellExec('kind get clusters | xargs -r -t -n1 kind delete cluster');
|
|
596
|
+
}
|
|
656
597
|
|
|
657
598
|
// Phase 4: File system cleanup
|
|
658
599
|
logger.info('Phase 4/7: Cleaning up remaining file system artifacts...');
|
|
@@ -672,9 +613,6 @@ net.ipv4.ip_forward = 1' | sudo tee ${iptableConfPath}`,
|
|
|
672
613
|
// Remove iptables rules and CNI network interfaces.
|
|
673
614
|
shellExec('sudo iptables -F');
|
|
674
615
|
shellExec('sudo iptables -t nat -F');
|
|
675
|
-
// Restore iptables rules
|
|
676
|
-
shellExec(`chmod +x ${options.underpostRoot}/scripts/nat-iptables.sh`);
|
|
677
|
-
shellExec(`${options.underpostRoot}/scripts/nat-iptables.sh`, { silent: true });
|
|
678
616
|
shellExec('sudo ip link del cni0');
|
|
679
617
|
shellExec('sudo ip link del flannel.1');
|
|
680
618
|
|
|
@@ -772,6 +710,11 @@ EOF`);
|
|
|
772
710
|
shellExec(`chmod +x /usr/local/bin/helm`);
|
|
773
711
|
shellExec(`sudo mv /usr/local/bin/helm /bin/helm`);
|
|
774
712
|
shellExec(`sudo rm -rf get_helm.sh`);
|
|
713
|
+
|
|
714
|
+
// Install snap
|
|
715
|
+
shellExec(`sudo yum install -y snapd`);
|
|
716
|
+
shellExec(`sudo systemctl enable --now snapd.socket`);
|
|
717
|
+
|
|
775
718
|
console.log('Host prerequisites installed successfully.');
|
|
776
719
|
},
|
|
777
720
|
|
package/src/cli/deploy.js
CHANGED
|
@@ -491,6 +491,7 @@ spec:
|
|
|
491
491
|
retryPerTryTimeout: '',
|
|
492
492
|
kindType: '',
|
|
493
493
|
port: 0,
|
|
494
|
+
exposePort: 0,
|
|
494
495
|
cmd: '',
|
|
495
496
|
},
|
|
496
497
|
) {
|
|
@@ -573,11 +574,13 @@ EOF`);
|
|
|
573
574
|
if (options.expose === true) {
|
|
574
575
|
const kindType = options.kindType ? options.kindType : 'svc';
|
|
575
576
|
const svc = Underpost.deploy.get(deployId, kindType)[0];
|
|
576
|
-
const port = options.
|
|
577
|
-
? options.
|
|
578
|
-
:
|
|
579
|
-
?
|
|
580
|
-
:
|
|
577
|
+
const port = options.exposePort
|
|
578
|
+
? parseInt(options.exposePort)
|
|
579
|
+
: options.port
|
|
580
|
+
? parseInt(options.port)
|
|
581
|
+
: kindType !== 'svc'
|
|
582
|
+
? 80
|
|
583
|
+
: parseInt(svc[`PORT(S)`].split('/TCP')[0]);
|
|
581
584
|
logger.info(deployId, {
|
|
582
585
|
svc,
|
|
583
586
|
port,
|