@underpostnet/underpost 2.97.0 → 2.97.5
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/README.md +2 -2
- package/baremetal/commission-workflows.json +33 -3
- package/bin/deploy.js +1 -1
- package/cli.md +7 -2
- package/conf.js +3 -0
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -1
- package/packer/scripts/fuse-tar-root +3 -3
- package/scripts/disk-clean.sh +23 -23
- package/scripts/gpu-diag.sh +2 -2
- package/scripts/ip-info.sh +11 -11
- package/scripts/maas-upload-boot-resource.sh +1 -1
- package/scripts/nvim.sh +1 -1
- package/scripts/packer-setup.sh +13 -13
- package/scripts/rocky-setup.sh +2 -2
- package/scripts/rpmfusion-ffmpeg-setup.sh +4 -4
- package/scripts/ssl.sh +7 -7
- package/src/api/core/core.service.js +0 -5
- package/src/api/default/default.service.js +7 -5
- package/src/api/document/document.model.js +30 -1
- package/src/api/document/document.router.js +6 -0
- package/src/api/document/document.service.js +423 -51
- package/src/api/file/file.model.js +112 -4
- package/src/api/file/file.ref.json +42 -0
- package/src/api/file/file.service.js +380 -32
- package/src/api/user/user.model.js +38 -1
- package/src/api/user/user.router.js +96 -63
- package/src/api/user/user.service.js +81 -48
- package/src/cli/baremetal.js +689 -329
- package/src/cli/cluster.js +50 -52
- package/src/cli/db.js +424 -166
- package/src/cli/deploy.js +1 -1
- package/src/cli/index.js +12 -1
- package/src/cli/lxd.js +3 -3
- package/src/cli/repository.js +1 -1
- package/src/cli/run.js +2 -1
- package/src/cli/ssh.js +10 -10
- package/src/client/components/core/Account.js +327 -36
- package/src/client/components/core/AgGrid.js +3 -0
- package/src/client/components/core/Auth.js +9 -3
- package/src/client/components/core/Chat.js +2 -2
- package/src/client/components/core/Content.js +159 -78
- package/src/client/components/core/Css.js +16 -2
- package/src/client/components/core/CssCore.js +16 -12
- package/src/client/components/core/FileExplorer.js +115 -8
- package/src/client/components/core/Input.js +204 -11
- package/src/client/components/core/LogIn.js +42 -20
- package/src/client/components/core/Modal.js +257 -177
- package/src/client/components/core/Panel.js +324 -27
- package/src/client/components/core/PanelForm.js +280 -73
- package/src/client/components/core/PublicProfile.js +888 -0
- package/src/client/components/core/Router.js +117 -15
- package/src/client/components/core/SearchBox.js +1117 -0
- package/src/client/components/core/SignUp.js +26 -7
- package/src/client/components/core/SocketIo.js +6 -3
- package/src/client/components/core/Translate.js +98 -0
- package/src/client/components/core/Validator.js +15 -0
- package/src/client/components/core/windowGetDimensions.js +6 -6
- package/src/client/components/default/MenuDefault.js +59 -12
- package/src/client/components/default/RoutesDefault.js +1 -0
- package/src/client/services/core/core.service.js +163 -1
- package/src/client/services/default/default.management.js +451 -64
- package/src/client/services/default/default.service.js +13 -6
- package/src/client/services/document/document.service.js +23 -0
- package/src/client/services/file/file.service.js +43 -16
- package/src/client/services/user/user.service.js +13 -9
- package/src/db/DataBaseProvider.js +1 -1
- package/src/db/mongo/MongooseDB.js +1 -1
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +4 -4
- package/src/runtime/express/Express.js +2 -1
- package/src/runtime/lampp/Lampp.js +2 -2
- package/src/server/auth.js +3 -6
- package/src/server/data-query.js +449 -0
- package/src/server/dns.js +4 -4
- package/src/server/object-layer.js +0 -3
- package/src/ws/IoInterface.js +2 -2
package/src/cli/db.js
CHANGED
|
@@ -74,16 +74,27 @@ const MAX_BACKUP_RETENTION = 5;
|
|
|
74
74
|
* Provides comprehensive database management including import/export, multi-pod targeting,
|
|
75
75
|
* Git integration, and cluster metadata management.
|
|
76
76
|
*/
|
|
77
|
+
/**
|
|
78
|
+
* UnderpostDB class for managing database operations and backups.
|
|
79
|
+
* @class UnderpostDB
|
|
80
|
+
* @memberof UnderpostDB
|
|
81
|
+
*/
|
|
77
82
|
class UnderpostDB {
|
|
83
|
+
/**
|
|
84
|
+
* Static API object containing all database operation methods.
|
|
85
|
+
* @static
|
|
86
|
+
* @memberof UnderpostDB
|
|
87
|
+
*/
|
|
78
88
|
static API = {
|
|
79
89
|
/**
|
|
80
|
-
* Helper: Gets filtered pods based on criteria
|
|
81
|
-
* @
|
|
82
|
-
* @
|
|
83
|
-
* @param {
|
|
84
|
-
* @param {string} [criteria.
|
|
85
|
-
* @param {string} [criteria.
|
|
86
|
-
* @
|
|
90
|
+
* Helper: Gets filtered pods based on criteria.
|
|
91
|
+
* @method _getFilteredPods
|
|
92
|
+
* @memberof UnderpostDB
|
|
93
|
+
* @param {Object} criteria - Filter criteria.
|
|
94
|
+
* @param {string} [criteria.podNames] - Comma-separated pod name patterns.
|
|
95
|
+
* @param {string} [criteria.namespace='default'] - Kubernetes namespace.
|
|
96
|
+
* @param {string} [criteria.deployId] - Deployment ID pattern.
|
|
97
|
+
* @return {Array<PodInfo>} Filtered pod list.
|
|
87
98
|
*/
|
|
88
99
|
_getFilteredPods(criteria = {}) {
|
|
89
100
|
const { podNames, namespace = 'default', deployId } = criteria;
|
|
@@ -113,12 +124,13 @@ class UnderpostDB {
|
|
|
113
124
|
},
|
|
114
125
|
|
|
115
126
|
/**
|
|
116
|
-
* Helper: Executes kubectl command with error handling
|
|
117
|
-
* @
|
|
118
|
-
* @
|
|
119
|
-
* @param {
|
|
120
|
-
* @param {
|
|
121
|
-
* @
|
|
127
|
+
* Helper: Executes kubectl command with error handling.
|
|
128
|
+
* @method _executeKubectl
|
|
129
|
+
* @memberof UnderpostDB
|
|
130
|
+
* @param {string} command - kubectl command to execute.
|
|
131
|
+
* @param {Object} [options={}] - Execution options.
|
|
132
|
+
* @param {string} [options.context=''] - Command context for logging.
|
|
133
|
+
* @return {string|null} Command output or null on error.
|
|
122
134
|
*/
|
|
123
135
|
_executeKubectl(command, options = {}) {
|
|
124
136
|
const { context = '' } = options;
|
|
@@ -133,14 +145,15 @@ class UnderpostDB {
|
|
|
133
145
|
},
|
|
134
146
|
|
|
135
147
|
/**
|
|
136
|
-
* Helper: Copies file to pod
|
|
137
|
-
* @
|
|
138
|
-
* @
|
|
139
|
-
* @param {
|
|
140
|
-
* @param {string} params.
|
|
141
|
-
* @param {string} params.
|
|
142
|
-
* @param {string} params.
|
|
143
|
-
* @
|
|
148
|
+
* Helper: Copies file to pod.
|
|
149
|
+
* @method _copyToPod
|
|
150
|
+
* @memberof UnderpostDB
|
|
151
|
+
* @param {Object} params - Copy parameters.
|
|
152
|
+
* @param {string} params.sourcePath - Source file path.
|
|
153
|
+
* @param {string} params.podName - Target pod name.
|
|
154
|
+
* @param {string} params.namespace - Pod namespace.
|
|
155
|
+
* @param {string} params.destPath - Destination path in pod.
|
|
156
|
+
* @return {boolean} Success status.
|
|
144
157
|
*/
|
|
145
158
|
_copyToPod({ sourcePath, podName, namespace, destPath }) {
|
|
146
159
|
try {
|
|
@@ -154,14 +167,15 @@ class UnderpostDB {
|
|
|
154
167
|
},
|
|
155
168
|
|
|
156
169
|
/**
|
|
157
|
-
* Helper: Copies file from pod
|
|
158
|
-
* @
|
|
159
|
-
* @
|
|
160
|
-
* @param {
|
|
161
|
-
* @param {string} params.
|
|
162
|
-
* @param {string} params.
|
|
163
|
-
* @param {string} params.
|
|
164
|
-
* @
|
|
170
|
+
* Helper: Copies file from pod.
|
|
171
|
+
* @method _copyFromPod
|
|
172
|
+
* @memberof UnderpostDB
|
|
173
|
+
* @param {Object} params - Copy parameters.
|
|
174
|
+
* @param {string} params.podName - Source pod name.
|
|
175
|
+
* @param {string} params.namespace - Pod namespace.
|
|
176
|
+
* @param {string} params.sourcePath - Source path in pod.
|
|
177
|
+
* @param {string} params.destPath - Destination file path.
|
|
178
|
+
* @return {boolean} Success status.
|
|
165
179
|
*/
|
|
166
180
|
_copyFromPod({ podName, namespace, sourcePath, destPath }) {
|
|
167
181
|
try {
|
|
@@ -175,13 +189,14 @@ class UnderpostDB {
|
|
|
175
189
|
},
|
|
176
190
|
|
|
177
191
|
/**
|
|
178
|
-
* Helper: Executes command in pod
|
|
179
|
-
* @
|
|
180
|
-
* @
|
|
181
|
-
* @param {
|
|
182
|
-
* @param {string} params.
|
|
183
|
-
* @param {string} params.
|
|
184
|
-
* @
|
|
192
|
+
* Helper: Executes command in pod.
|
|
193
|
+
* @method _execInPod
|
|
194
|
+
* @memberof UnderpostDB
|
|
195
|
+
* @param {Object} params - Execution parameters.
|
|
196
|
+
* @param {string} params.podName - Pod name.
|
|
197
|
+
* @param {string} params.namespace - Pod namespace.
|
|
198
|
+
* @param {string} params.command - Command to execute.
|
|
199
|
+
* @return {string|null} Command output or null.
|
|
185
200
|
*/
|
|
186
201
|
_execInPod({ podName, namespace, command }) {
|
|
187
202
|
try {
|
|
@@ -194,14 +209,15 @@ class UnderpostDB {
|
|
|
194
209
|
},
|
|
195
210
|
|
|
196
211
|
/**
|
|
197
|
-
* Helper: Manages Git repository for backups
|
|
198
|
-
* @
|
|
199
|
-
* @
|
|
200
|
-
* @param {
|
|
201
|
-
* @param {string} params.
|
|
202
|
-
* @param {string}
|
|
203
|
-
* @param {
|
|
204
|
-
* @
|
|
212
|
+
* Helper: Manages Git repository for backups.
|
|
213
|
+
* @method _manageGitRepo
|
|
214
|
+
* @memberof UnderpostDB
|
|
215
|
+
* @param {Object} params - Git parameters.
|
|
216
|
+
* @param {string} params.repoName - Repository name.
|
|
217
|
+
* @param {string} params.operation - Operation (clone, pull, commit, push).
|
|
218
|
+
* @param {string} [params.message=''] - Commit message.
|
|
219
|
+
* @param {boolean} [params.forceClone=false] - Force remove and re-clone repository.
|
|
220
|
+
* @return {boolean} Success status.
|
|
205
221
|
*/
|
|
206
222
|
_manageGitRepo({ repoName, operation, message = '', forceClone = false }) {
|
|
207
223
|
try {
|
|
@@ -263,12 +279,13 @@ class UnderpostDB {
|
|
|
263
279
|
},
|
|
264
280
|
|
|
265
281
|
/**
|
|
266
|
-
* Helper: Manages backup timestamps and cleanup
|
|
267
|
-
* @
|
|
268
|
-
* @
|
|
269
|
-
* @param {
|
|
270
|
-
* @param {
|
|
271
|
-
* @
|
|
282
|
+
* Helper: Manages backup timestamps and cleanup.
|
|
283
|
+
* @method _manageBackupTimestamps
|
|
284
|
+
* @memberof UnderpostDB
|
|
285
|
+
* @param {string} backupPath - Backup directory path.
|
|
286
|
+
* @param {number} newTimestamp - New backup timestamp.
|
|
287
|
+
* @param {boolean} shouldCleanup - Whether to cleanup old backups.
|
|
288
|
+
* @return {Object} Backup info with current and removed timestamps.
|
|
272
289
|
*/
|
|
273
290
|
_manageBackupTimestamps(backupPath, newTimestamp, shouldCleanup) {
|
|
274
291
|
try {
|
|
@@ -311,16 +328,17 @@ class UnderpostDB {
|
|
|
311
328
|
},
|
|
312
329
|
|
|
313
330
|
/**
|
|
314
|
-
* Helper: Performs MariaDB import operation
|
|
315
|
-
* @
|
|
316
|
-
* @
|
|
317
|
-
* @param {
|
|
318
|
-
* @param {
|
|
319
|
-
* @param {string} params.
|
|
320
|
-
* @param {string} params.
|
|
321
|
-
* @param {string} params.
|
|
322
|
-
* @param {string} params.
|
|
323
|
-
* @
|
|
331
|
+
* Helper: Performs MariaDB import operation.
|
|
332
|
+
* @method _importMariaDB
|
|
333
|
+
* @memberof UnderpostDB
|
|
334
|
+
* @param {Object} params - Import parameters.
|
|
335
|
+
* @param {PodInfo} params.pod - Target pod.
|
|
336
|
+
* @param {string} params.namespace - Namespace.
|
|
337
|
+
* @param {string} params.dbName - Database name.
|
|
338
|
+
* @param {string} params.user - Database user.
|
|
339
|
+
* @param {string} params.password - Database password.
|
|
340
|
+
* @param {string} params.sqlPath - SQL file path.
|
|
341
|
+
* @return {boolean} Success status.
|
|
324
342
|
*/
|
|
325
343
|
_importMariaDB({ pod, namespace, dbName, user, password, sqlPath }) {
|
|
326
344
|
try {
|
|
@@ -367,16 +385,17 @@ class UnderpostDB {
|
|
|
367
385
|
},
|
|
368
386
|
|
|
369
387
|
/**
|
|
370
|
-
* Helper: Performs MariaDB export operation
|
|
371
|
-
* @
|
|
372
|
-
* @
|
|
373
|
-
* @param {
|
|
374
|
-
* @param {
|
|
375
|
-
* @param {string} params.
|
|
376
|
-
* @param {string} params.
|
|
377
|
-
* @param {string} params.
|
|
378
|
-
* @param {string} params.
|
|
379
|
-
* @
|
|
388
|
+
* Helper: Performs MariaDB export operation.
|
|
389
|
+
* @method _exportMariaDB
|
|
390
|
+
* @memberof UnderpostDB
|
|
391
|
+
* @param {Object} params - Export parameters.
|
|
392
|
+
* @param {PodInfo} params.pod - Source pod.
|
|
393
|
+
* @param {string} params.namespace - Namespace.
|
|
394
|
+
* @param {string} params.dbName - Database name.
|
|
395
|
+
* @param {string} params.user - Database user.
|
|
396
|
+
* @param {string} params.password - Database password.
|
|
397
|
+
* @param {string} params.outputPath - Output file path.
|
|
398
|
+
* @return {Promise<boolean>} A promise that resolves with success status.
|
|
380
399
|
*/
|
|
381
400
|
async _exportMariaDB({ pod, namespace, dbName, user, password, outputPath }) {
|
|
382
401
|
try {
|
|
@@ -422,16 +441,17 @@ class UnderpostDB {
|
|
|
422
441
|
},
|
|
423
442
|
|
|
424
443
|
/**
|
|
425
|
-
* Helper: Performs MongoDB import operation
|
|
426
|
-
* @
|
|
427
|
-
* @
|
|
428
|
-
* @param {
|
|
429
|
-
* @param {
|
|
430
|
-
* @param {string} params.
|
|
431
|
-
* @param {string} params.
|
|
432
|
-
* @param {
|
|
433
|
-
* @param {boolean} params.
|
|
434
|
-
* @
|
|
444
|
+
* Helper: Performs MongoDB import operation.
|
|
445
|
+
* @method _importMongoDB
|
|
446
|
+
* @memberof UnderpostDB
|
|
447
|
+
* @param {Object} params - Import parameters.
|
|
448
|
+
* @param {PodInfo} params.pod - Target pod.
|
|
449
|
+
* @param {string} params.namespace - Namespace.
|
|
450
|
+
* @param {string} params.dbName - Database name.
|
|
451
|
+
* @param {string} params.bsonPath - BSON directory path.
|
|
452
|
+
* @param {boolean} params.drop - Whether to drop existing database.
|
|
453
|
+
* @param {boolean} params.preserveUUID - Whether to preserve UUIDs.
|
|
454
|
+
* @return {boolean} Success status.
|
|
435
455
|
*/
|
|
436
456
|
_importMongoDB({ pod, namespace, dbName, bsonPath, drop, preserveUUID }) {
|
|
437
457
|
try {
|
|
@@ -474,15 +494,16 @@ class UnderpostDB {
|
|
|
474
494
|
},
|
|
475
495
|
|
|
476
496
|
/**
|
|
477
|
-
* Helper: Performs MongoDB export operation
|
|
478
|
-
* @
|
|
479
|
-
* @
|
|
480
|
-
* @param {
|
|
481
|
-
* @param {
|
|
482
|
-
* @param {string} params.
|
|
483
|
-
* @param {string} params.
|
|
484
|
-
* @param {string}
|
|
485
|
-
* @
|
|
497
|
+
* Helper: Performs MongoDB export operation.
|
|
498
|
+
* @method _exportMongoDB
|
|
499
|
+
* @memberof UnderpostDB
|
|
500
|
+
* @param {Object} params - Export parameters.
|
|
501
|
+
* @param {PodInfo} params.pod - Source pod.
|
|
502
|
+
* @param {string} params.namespace - Namespace.
|
|
503
|
+
* @param {string} params.dbName - Database name.
|
|
504
|
+
* @param {string} params.outputPath - Output directory path.
|
|
505
|
+
* @param {string} [params.collections=''] - Comma-separated collection list.
|
|
506
|
+
* @return {boolean} Success status.
|
|
486
507
|
*/
|
|
487
508
|
_exportMongoDB({ pod, namespace, dbName, outputPath, collections = '' }) {
|
|
488
509
|
try {
|
|
@@ -531,13 +552,14 @@ class UnderpostDB {
|
|
|
531
552
|
},
|
|
532
553
|
|
|
533
554
|
/**
|
|
534
|
-
* Helper: Gets MongoDB collection statistics
|
|
535
|
-
* @
|
|
536
|
-
* @
|
|
537
|
-
* @param {
|
|
538
|
-
* @param {string} params.
|
|
539
|
-
* @param {string} params.
|
|
540
|
-
* @
|
|
555
|
+
* Helper: Gets MongoDB collection statistics.
|
|
556
|
+
* @method _getMongoStats
|
|
557
|
+
* @memberof UnderpostDB
|
|
558
|
+
* @param {Object} params - Parameters.
|
|
559
|
+
* @param {string} params.podName - Pod name.
|
|
560
|
+
* @param {string} params.namespace - Namespace.
|
|
561
|
+
* @param {string} params.dbName - Database name.
|
|
562
|
+
* @return {Object|null} Collection statistics or null on error.
|
|
541
563
|
*/
|
|
542
564
|
_getMongoStats({ podName, namespace, dbName }) {
|
|
543
565
|
try {
|
|
@@ -589,15 +611,16 @@ class UnderpostDB {
|
|
|
589
611
|
},
|
|
590
612
|
|
|
591
613
|
/**
|
|
592
|
-
* Helper: Gets MariaDB table statistics
|
|
593
|
-
* @
|
|
594
|
-
* @
|
|
595
|
-
* @param {
|
|
596
|
-
* @param {string} params.
|
|
597
|
-
* @param {string} params.
|
|
598
|
-
* @param {string} params.
|
|
599
|
-
* @param {string} params.
|
|
600
|
-
* @
|
|
614
|
+
* Helper: Gets MariaDB table statistics.
|
|
615
|
+
* @method _getMariaDBStats
|
|
616
|
+
* @memberof UnderpostDB
|
|
617
|
+
* @param {Object} params - Parameters.
|
|
618
|
+
* @param {string} params.podName - Pod name.
|
|
619
|
+
* @param {string} params.namespace - Namespace.
|
|
620
|
+
* @param {string} params.dbName - Database name.
|
|
621
|
+
* @param {string} params.user - Database user.
|
|
622
|
+
* @param {string} params.password - Database password.
|
|
623
|
+
* @return {Object|null} Table statistics or null on error.
|
|
601
624
|
*/
|
|
602
625
|
_getMariaDBStats({ podName, namespace, dbName, user, password }) {
|
|
603
626
|
try {
|
|
@@ -627,12 +650,14 @@ class UnderpostDB {
|
|
|
627
650
|
},
|
|
628
651
|
|
|
629
652
|
/**
|
|
630
|
-
* Helper: Displays database statistics in table format
|
|
631
|
-
* @
|
|
632
|
-
* @
|
|
633
|
-
* @param {
|
|
634
|
-
* @param {string} params.
|
|
635
|
-
* @param {
|
|
653
|
+
* Helper: Displays database statistics in table format.
|
|
654
|
+
* @method _displayStats
|
|
655
|
+
* @memberof UnderpostDB
|
|
656
|
+
* @param {Object} params - Parameters.
|
|
657
|
+
* @param {string} params.provider - Database provider.
|
|
658
|
+
* @param {string} params.dbName - Database name.
|
|
659
|
+
* @param {Array<Object>} params.stats - Statistics array.
|
|
660
|
+
* @return {void}
|
|
636
661
|
*/
|
|
637
662
|
_displayStats({ provider, dbName, stats }) {
|
|
638
663
|
if (!stats || stats.length === 0) {
|
|
@@ -663,13 +688,13 @@ class UnderpostDB {
|
|
|
663
688
|
},
|
|
664
689
|
|
|
665
690
|
/**
|
|
666
|
-
*
|
|
667
|
-
* @
|
|
668
|
-
* @param {Object} options - Options for getting primary pod
|
|
669
|
-
* @param {string} [options.namespace='default'] - Kubernetes namespace
|
|
670
|
-
* @param {string} [options.podName='mongodb-0'] - Initial pod name to query replica set status
|
|
671
|
-
* @returns {string|null} Primary pod name or null if not found
|
|
691
|
+
* Gets MongoDB primary pod name from replica set status.
|
|
692
|
+
* @method getMongoPrimaryPodName
|
|
672
693
|
* @memberof UnderpostDB
|
|
694
|
+
* @param {Object} [options={}] - Options for getting primary pod.
|
|
695
|
+
* @param {string} [options.namespace='default'] - Kubernetes namespace.
|
|
696
|
+
* @param {string} [options.podName='mongodb-0'] - Initial pod name to query replica set status.
|
|
697
|
+
* @return {string|null} Primary pod name or null if not found.
|
|
673
698
|
*/
|
|
674
699
|
getMongoPrimaryPodName(options = { namespace: 'default', podName: 'mongodb-0' }) {
|
|
675
700
|
const { namespace = 'default', podName = 'mongodb-0' } = options;
|
|
@@ -705,36 +730,38 @@ class UnderpostDB {
|
|
|
705
730
|
},
|
|
706
731
|
|
|
707
732
|
/**
|
|
708
|
-
* Main callback: Initiates database backup workflow
|
|
709
|
-
*
|
|
710
|
-
* @description Orchestrates the backup process for multiple deployments, handling
|
|
733
|
+
* Main callback: Initiates database backup workflow.
|
|
734
|
+
* Orchestrates the backup process for multiple deployments, handling
|
|
711
735
|
* database connections, backup storage, and optional Git integration for version control.
|
|
712
736
|
* Supports targeting multiple specific pods, nodes, and namespaces with advanced filtering.
|
|
713
|
-
* @
|
|
714
|
-
* @param {Object} options - Backup options
|
|
715
|
-
* @param {boolean} [options.import=false] - Whether to perform import operation
|
|
716
|
-
* @param {boolean} [options.export=false] - Whether to perform export operation
|
|
717
|
-
* @param {string} [options.podName=''] - Comma-separated pod name patterns to target
|
|
718
|
-
* @param {string} [options.ns='default'] - Kubernetes namespace
|
|
719
|
-
* @param {string} [options.collections=''] - Comma-separated MongoDB collections for export
|
|
720
|
-
* @param {string} [options.outPath=''] - Output path for backups
|
|
721
|
-
* @param {boolean} [options.drop=false] - Whether to drop existing database on import
|
|
722
|
-
* @param {boolean} [options.preserveUUID=false] - Whether to preserve UUIDs on MongoDB import
|
|
723
|
-
* @param {boolean} [options.git=false] - Whether to use Git for backup versioning
|
|
724
|
-
* @param {string} [options.hosts=''] - Comma-separated list of hosts to filter databases
|
|
725
|
-
* @param {string} [options.paths=''] - Comma-separated list of paths to filter databases
|
|
726
|
-
* @param {boolean} [options.allPods=false] - Whether to target all pods in deployment
|
|
727
|
-
* @param {boolean} [options.primaryPod=false] - Whether to target MongoDB primary pod only
|
|
728
|
-
* @param {string} [options.primaryPodEnsure=''] - Pod name to ensure MongoDB primary pod is running
|
|
729
|
-
* @param {boolean} [options.stats=false] - Whether to display database statistics
|
|
730
|
-
* @param {number} [options.macroRollbackExport=1] - Number of commits to rollback in macro export
|
|
731
|
-
* @param {boolean} [options.forceClone=false] - Whether to force re-clone Git repository
|
|
732
|
-
* @param {boolean} [options.dev=false] - Development mode flag
|
|
733
|
-
* @param {boolean} [options.k3s=false] - k3s cluster flag
|
|
734
|
-
* @param {boolean} [options.kubeadm=false] - kubeadm cluster flag
|
|
735
|
-
* @param {boolean} [options.kind=false] - kind cluster flag
|
|
736
|
-
* @returns {Promise<void>} Resolves when operation is complete
|
|
737
|
+
* @method callback
|
|
737
738
|
* @memberof UnderpostDB
|
|
739
|
+
* @param {string} [deployList='default'] - Comma-separated list of deployment IDs.
|
|
740
|
+
* @param {Object} [options={}] - Backup options.
|
|
741
|
+
* @param {boolean} [options.import=false] - Whether to perform import operation.
|
|
742
|
+
* @param {boolean} [options.export=false] - Whether to perform export operation.
|
|
743
|
+
* @param {string} [options.podName=''] - Comma-separated pod name patterns to target.
|
|
744
|
+
* @param {string} [options.ns='default'] - Kubernetes namespace.
|
|
745
|
+
* @param {string} [options.collections=''] - Comma-separated MongoDB collections for export.
|
|
746
|
+
* @param {string} [options.outPath=''] - Output path for backups.
|
|
747
|
+
* @param {boolean} [options.drop=false] - Whether to drop existing database on import.
|
|
748
|
+
* @param {boolean} [options.preserveUUID=false] - Whether to preserve UUIDs on MongoDB import.
|
|
749
|
+
* @param {boolean} [options.git=false] - Whether to use Git for backup versioning.
|
|
750
|
+
* @param {string} [options.hosts=''] - Comma-separated list of hosts to filter databases.
|
|
751
|
+
* @param {string} [options.paths=''] - Comma-separated list of paths to filter databases.
|
|
752
|
+
* @param {boolean} [options.allPods=false] - Whether to target all pods in deployment.
|
|
753
|
+
* @param {boolean} [options.primaryPod=false] - Whether to target MongoDB primary pod only.
|
|
754
|
+
* @param {string} [options.primaryPodEnsure=''] - Pod name to ensure MongoDB primary pod is running.
|
|
755
|
+
* @param {boolean} [options.stats=false] - Whether to display database statistics.
|
|
756
|
+
* @param {number} [options.macroRollbackExport=1] - Number of commits to rollback in macro export.
|
|
757
|
+
* @param {boolean} [options.forceClone=false] - Whether to force re-clone Git repository.
|
|
758
|
+
* @param {boolean} [options.cleanFsCollection=false] - Clean orphaned File documents flag.
|
|
759
|
+
* @param {boolean} [options.cleanFsDryRun=false] - Dry run mode flag (use with cleanFsCollection).
|
|
760
|
+
* @param {boolean} [options.dev=false] - Development mode flag.
|
|
761
|
+
* @param {boolean} [options.k3s=false] - k3s cluster flag.
|
|
762
|
+
* @param {boolean} [options.kubeadm=false] - kubeadm cluster flag.
|
|
763
|
+
* @param {boolean} [options.kind=false] - kind cluster flag.
|
|
764
|
+
* @return {Promise<void>} Resolves when operation is complete.
|
|
738
765
|
*/
|
|
739
766
|
async callback(
|
|
740
767
|
deployList = 'default',
|
|
@@ -756,6 +783,8 @@ class UnderpostDB {
|
|
|
756
783
|
stats: false,
|
|
757
784
|
macroRollbackExport: 1,
|
|
758
785
|
forceClone: false,
|
|
786
|
+
cleanFsCollection: false,
|
|
787
|
+
cleanFsDryRun: false,
|
|
759
788
|
dev: false,
|
|
760
789
|
k3s: false,
|
|
761
790
|
kubeadm: false,
|
|
@@ -767,6 +796,17 @@ class UnderpostDB {
|
|
|
767
796
|
|
|
768
797
|
if (deployList === 'dd') deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
769
798
|
|
|
799
|
+
// Handle clean-fs-collection operation
|
|
800
|
+
if (options.cleanFsCollection || options.cleanFsDryRun) {
|
|
801
|
+
logger.info('Starting File collection cleanup operation', { deployList });
|
|
802
|
+
await UnderpostDB.API.cleanFsCollection(deployList, {
|
|
803
|
+
hosts: options.hosts,
|
|
804
|
+
paths: options.paths,
|
|
805
|
+
dryRun: options.cleanFsDryRun,
|
|
806
|
+
});
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
|
|
770
810
|
logger.info('Starting database operation', {
|
|
771
811
|
deployList,
|
|
772
812
|
namespace,
|
|
@@ -1100,16 +1140,16 @@ class UnderpostDB {
|
|
|
1100
1140
|
},
|
|
1101
1141
|
|
|
1102
1142
|
/**
|
|
1103
|
-
* Creates cluster metadata for the specified deployment
|
|
1104
|
-
*
|
|
1105
|
-
* @description Loads database configuration and initializes cluster metadata including
|
|
1143
|
+
* Creates cluster metadata for the specified deployment.
|
|
1144
|
+
* Loads database configuration and initializes cluster metadata including
|
|
1106
1145
|
* instances and cron jobs. This method populates the database with deployment information.
|
|
1107
|
-
* @
|
|
1108
|
-
* @param {string} [host=process.env.DEFAULT_DEPLOY_HOST] - The host identifier
|
|
1109
|
-
* @param {string} [path=process.env.DEFAULT_DEPLOY_PATH] - The path identifier
|
|
1110
|
-
* @returns {Promise<void>}
|
|
1146
|
+
* @method clusterMetadataFactory
|
|
1111
1147
|
* @memberof UnderpostDB
|
|
1112
|
-
* @
|
|
1148
|
+
* @param {string} [deployId=process.env.DEFAULT_DEPLOY_ID] - The deployment ID.
|
|
1149
|
+
* @param {string} [host=process.env.DEFAULT_DEPLOY_HOST] - The host identifier.
|
|
1150
|
+
* @param {string} [path=process.env.DEFAULT_DEPLOY_PATH] - The path identifier.
|
|
1151
|
+
* @return {Promise<void>} Resolves when metadata creation is complete.
|
|
1152
|
+
* @throws {Error} If database configuration is invalid or connection fails.
|
|
1113
1153
|
*/
|
|
1114
1154
|
async clusterMetadataFactory(
|
|
1115
1155
|
deployId = process.env.DEFAULT_DEPLOY_ID,
|
|
@@ -1272,22 +1312,240 @@ class UnderpostDB {
|
|
|
1272
1312
|
},
|
|
1273
1313
|
|
|
1274
1314
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1277
|
-
*
|
|
1315
|
+
* Cleans orphaned File references from database collections.
|
|
1316
|
+
* Iterates over all deploy-ids and checks if File documents are actually referenced
|
|
1317
|
+
* by other collections. Removes File documents that are not referenced anywhere.
|
|
1318
|
+
* @method cleanFsCollection
|
|
1319
|
+
* @memberof UnderpostDB
|
|
1320
|
+
* @param {string} [deployList='dd'] - Comma-separated list of deployment IDs.
|
|
1321
|
+
* @param {Object} [options={}] - Clean operation options.
|
|
1322
|
+
* @param {string} [options.hosts=''] - Comma-separated list of hosts to filter.
|
|
1323
|
+
* @param {string} [options.paths=''] - Comma-separated list of paths to filter.
|
|
1324
|
+
* @param {boolean} [options.dryRun=false] - If true, only reports what would be deleted.
|
|
1325
|
+
* @return {Promise<void>} Resolves when clean operation is complete.
|
|
1326
|
+
*/
|
|
1327
|
+
async cleanFsCollection(
|
|
1328
|
+
deployList = 'dd',
|
|
1329
|
+
options = {
|
|
1330
|
+
hosts: '',
|
|
1331
|
+
paths: '',
|
|
1332
|
+
dryRun: false,
|
|
1333
|
+
},
|
|
1334
|
+
) {
|
|
1335
|
+
if (deployList === 'dd') deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
1336
|
+
|
|
1337
|
+
logger.info('Starting File collection cleanup', { deployList, options });
|
|
1338
|
+
|
|
1339
|
+
// Load file.ref.json to know which models reference File
|
|
1340
|
+
const fileRefPath = './src/api/file/file.ref.json';
|
|
1341
|
+
if (!fs.existsSync(fileRefPath)) {
|
|
1342
|
+
logger.error('file.ref.json not found', { path: fileRefPath });
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
const fileRefData = JSON.parse(fs.readFileSync(fileRefPath, 'utf8'));
|
|
1347
|
+
logger.info('Loaded file reference configuration', { apis: fileRefData.length });
|
|
1348
|
+
|
|
1349
|
+
// Filter hosts and paths if specified
|
|
1350
|
+
const filterHosts = options.hosts ? options.hosts.split(',').map((h) => h.trim()) : [];
|
|
1351
|
+
const filterPaths = options.paths ? options.paths.split(',').map((p) => p.trim()) : [];
|
|
1352
|
+
|
|
1353
|
+
// Track all connections to close them at the end
|
|
1354
|
+
const connectionsToClose = [];
|
|
1355
|
+
|
|
1356
|
+
for (const _deployId of deployList.split(',')) {
|
|
1357
|
+
const deployId = _deployId.trim();
|
|
1358
|
+
if (!deployId) continue;
|
|
1359
|
+
|
|
1360
|
+
logger.info('Processing deployment for File cleanup', { deployId });
|
|
1361
|
+
|
|
1362
|
+
// Load server configuration
|
|
1363
|
+
const confServerPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
1364
|
+
if (!fs.existsSync(confServerPath)) {
|
|
1365
|
+
logger.error('Configuration file not found', { path: confServerPath });
|
|
1366
|
+
continue;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
const confServer = JSON.parse(fs.readFileSync(confServerPath, 'utf8'));
|
|
1370
|
+
|
|
1371
|
+
// Process each host+path combination
|
|
1372
|
+
for (const host of Object.keys(confServer)) {
|
|
1373
|
+
if (filterHosts.length > 0 && !filterHosts.includes(host)) continue;
|
|
1374
|
+
|
|
1375
|
+
for (const path of Object.keys(confServer[host])) {
|
|
1376
|
+
if (filterPaths.length > 0 && !filterPaths.includes(path)) continue;
|
|
1377
|
+
|
|
1378
|
+
const { db, apis } = confServer[host][path];
|
|
1379
|
+
if (!db || !apis) continue;
|
|
1380
|
+
|
|
1381
|
+
// Check if 'file' api is in the apis list
|
|
1382
|
+
if (!apis.includes('file')) {
|
|
1383
|
+
logger.info('Skipping - no file api in configuration', { host, path });
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// logger.info('Processing host+path with file api', { host, path, db: db.name });
|
|
1388
|
+
|
|
1389
|
+
try {
|
|
1390
|
+
// Connect to database
|
|
1391
|
+
const dbProvider = await DataBaseProvider.load({ apis, host, path, db });
|
|
1392
|
+
if (!dbProvider || !dbProvider.models) {
|
|
1393
|
+
logger.error('Failed to load database provider', { host, path });
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
const { models } = dbProvider;
|
|
1398
|
+
|
|
1399
|
+
// Track this connection for cleanup
|
|
1400
|
+
connectionsToClose.push({ host, path, dbProvider });
|
|
1401
|
+
|
|
1402
|
+
// Check if File model exists
|
|
1403
|
+
if (!models.File) {
|
|
1404
|
+
logger.warn('File model not loaded', { host, path });
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
// Get all File documents
|
|
1409
|
+
const allFiles = await models.File.find({}, '_id').lean();
|
|
1410
|
+
logger.info('Found File documents', { count: allFiles.length, host, path });
|
|
1411
|
+
|
|
1412
|
+
if (allFiles.length === 0) continue;
|
|
1413
|
+
|
|
1414
|
+
// Track which File IDs are referenced
|
|
1415
|
+
const referencedFileIds = new Set();
|
|
1416
|
+
|
|
1417
|
+
// Check each API from file.ref.json
|
|
1418
|
+
for (const refConfig of fileRefData) {
|
|
1419
|
+
const { api, model: modelFields } = refConfig;
|
|
1420
|
+
|
|
1421
|
+
// Check if this API is loaded in current context
|
|
1422
|
+
const modelName = api
|
|
1423
|
+
.split('-')
|
|
1424
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
1425
|
+
.join('');
|
|
1426
|
+
const Model = models[modelName];
|
|
1427
|
+
|
|
1428
|
+
if (!Model) {
|
|
1429
|
+
logger.debug('Model not loaded in current context', { api, modelName, host, path });
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
logger.info('Checking references in model', { api, modelName });
|
|
1434
|
+
|
|
1435
|
+
// Helper function to recursively check field references
|
|
1436
|
+
const checkFieldReferences = async (fieldPath, fieldConfig) => {
|
|
1437
|
+
for (const [fieldName, fieldValue] of Object.entries(fieldConfig)) {
|
|
1438
|
+
const currentPath = fieldPath ? `${fieldPath}.${fieldName}` : fieldName;
|
|
1439
|
+
|
|
1440
|
+
if (fieldValue === true) {
|
|
1441
|
+
// This is a File reference field
|
|
1442
|
+
const query = {};
|
|
1443
|
+
query[currentPath] = { $exists: true, $ne: null };
|
|
1444
|
+
|
|
1445
|
+
const docs = await Model.find(query, currentPath).lean();
|
|
1446
|
+
|
|
1447
|
+
for (const doc of docs) {
|
|
1448
|
+
// Navigate to the nested field
|
|
1449
|
+
const parts = currentPath.split('.');
|
|
1450
|
+
let value = doc;
|
|
1451
|
+
for (const part of parts) {
|
|
1452
|
+
value = value?.[part];
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (value) {
|
|
1456
|
+
if (Array.isArray(value)) {
|
|
1457
|
+
value.forEach((id) => id && referencedFileIds.add(id.toString()));
|
|
1458
|
+
} else {
|
|
1459
|
+
referencedFileIds.add(value.toString());
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
logger.info('Found references', {
|
|
1465
|
+
model: modelName,
|
|
1466
|
+
field: currentPath,
|
|
1467
|
+
count: docs.length,
|
|
1468
|
+
});
|
|
1469
|
+
} else if (typeof fieldValue === 'object') {
|
|
1470
|
+
// Nested object, recurse
|
|
1471
|
+
await checkFieldReferences(currentPath, fieldValue);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
|
|
1476
|
+
await checkFieldReferences('', modelFields);
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
logger.info('Total referenced File IDs', { count: referencedFileIds.size, host, path });
|
|
1480
|
+
|
|
1481
|
+
// Find orphaned files
|
|
1482
|
+
const orphanedFiles = allFiles.filter((file) => !referencedFileIds.has(file._id.toString()));
|
|
1483
|
+
|
|
1484
|
+
if (orphanedFiles.length === 0) {
|
|
1485
|
+
logger.info('No orphaned files found', { host, path });
|
|
1486
|
+
} else {
|
|
1487
|
+
logger.info('Found orphaned files', { count: orphanedFiles.length, host, path });
|
|
1488
|
+
|
|
1489
|
+
if (options.dryRun) {
|
|
1490
|
+
logger.info('Dry run - would delete files', {
|
|
1491
|
+
count: orphanedFiles.length,
|
|
1492
|
+
ids: orphanedFiles.map((f) => f._id.toString()),
|
|
1493
|
+
});
|
|
1494
|
+
} else {
|
|
1495
|
+
const orphanedIds = orphanedFiles.map((f) => f._id);
|
|
1496
|
+
const deleteResult = await models.File.deleteMany({ _id: { $in: orphanedIds } });
|
|
1497
|
+
logger.info('Deleted orphaned files', {
|
|
1498
|
+
deletedCount: deleteResult.deletedCount,
|
|
1499
|
+
host,
|
|
1500
|
+
path,
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
} catch (error) {
|
|
1505
|
+
logger.error('Error processing host+path', {
|
|
1506
|
+
host,
|
|
1507
|
+
path,
|
|
1508
|
+
error: error.message,
|
|
1509
|
+
stack: error.stack,
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// Close all connections
|
|
1517
|
+
logger.info('Closing all database connections', { count: connectionsToClose.length });
|
|
1518
|
+
for (const { host, path, dbProvider } of connectionsToClose) {
|
|
1519
|
+
try {
|
|
1520
|
+
if (dbProvider && dbProvider.close) {
|
|
1521
|
+
await dbProvider.close();
|
|
1522
|
+
logger.info('Connection closed', { host, path });
|
|
1523
|
+
}
|
|
1524
|
+
} catch (error) {
|
|
1525
|
+
logger.error('Error closing connection', { host, path, error: error.message });
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
logger.info('File collection cleanup completed');
|
|
1530
|
+
},
|
|
1531
|
+
|
|
1532
|
+
/**
|
|
1533
|
+
* Handles backup of cluster metadata.
|
|
1534
|
+
* Orchestrates backup and restore operations for cluster metadata including
|
|
1278
1535
|
* instances and cron jobs. Supports import/export and metadata generation.
|
|
1279
|
-
* @
|
|
1280
|
-
* @param {string} [host=process.env.DEFAULT_DEPLOY_HOST] - The host identifier
|
|
1281
|
-
* @param {string} [path=process.env.DEFAULT_DEPLOY_PATH] - The path identifier
|
|
1282
|
-
* @param {Object} [options] - Backup operation options
|
|
1283
|
-
* @param {boolean} [options.generate=false] - Generate cluster metadata
|
|
1284
|
-
* @param {boolean} [options.itc=false] - Execute in container context
|
|
1285
|
-
* @param {boolean} [options.import=false] - Import metadata from backup
|
|
1286
|
-
* @param {boolean} [options.export=false] - Export metadata to backup
|
|
1287
|
-
* @param {boolean} [options.instances=false] - Process instances collection
|
|
1288
|
-
* @param {boolean} [options.crons=false] - Process crons collection
|
|
1289
|
-
* @returns {void}
|
|
1536
|
+
* @method clusterMetadataBackupCallback
|
|
1290
1537
|
* @memberof UnderpostDB
|
|
1538
|
+
* @param {string} [deployId=process.env.DEFAULT_DEPLOY_ID] - The deployment ID.
|
|
1539
|
+
* @param {string} [host=process.env.DEFAULT_DEPLOY_HOST] - The host identifier.
|
|
1540
|
+
* @param {string} [path=process.env.DEFAULT_DEPLOY_PATH] - The path identifier.
|
|
1541
|
+
* @param {Object} [options={}] - Backup operation options.
|
|
1542
|
+
* @param {boolean} [options.generate=false] - Generate cluster metadata.
|
|
1543
|
+
* @param {boolean} [options.itc=false] - Execute in container context.
|
|
1544
|
+
* @param {boolean} [options.import=false] - Import metadata from backup.
|
|
1545
|
+
* @param {boolean} [options.export=false] - Export metadata to backup.
|
|
1546
|
+
* @param {boolean} [options.instances=false] - Process instances collection.
|
|
1547
|
+
* @param {boolean} [options.crons=false] - Process crons collection.
|
|
1548
|
+
* @return {Promise<void>} Resolves when backup operation is complete.
|
|
1291
1549
|
*/
|
|
1292
1550
|
async clusterMetadataBackupCallback(
|
|
1293
1551
|
deployId = process.env.DEFAULT_DEPLOY_ID,
|