@@ -2,12 +2,26 @@ import { mergeFile, splitFileFactory } from '../server/conf.js';
2
2
import { loggerFactory } from '../server/logger.js' ;
3
3
import { shellExec } from '../server/process.js' ;
4
4
import fs from 'fs-extra' ;
5
+ import UnderpostDeploy from './deploy.js' ;
5
6
6
7
const logger = loggerFactory ( import . meta) ;
7
8
8
9
class UnderpostDB {
9
10
static API = {
10
- async callback ( deployList = 'default' , options = { import : false , export : false , podName : false , ns : false } ) {
11
+ async callback (
12
+ deployList = 'default' ,
13
+ options = {
14
+ import : false ,
15
+ export : false ,
16
+ podName : false ,
17
+ ns : false ,
18
+ collection : '' ,
19
+ outPath : '' ,
20
+ drop : false ,
21
+ preserveUUID : false ,
22
+ git : false ,
23
+ } ,
24
+ ) {
11
25
const newBackupTimestamp = new Date ( ) . getTime ( ) ;
12
26
const nameSpace = options . ns && typeof options . ns === 'string' ? options . ns : 'default' ;
13
27
for ( const _deployId of deployList . split ( ',' ) ) {
@@ -43,10 +57,12 @@ class UnderpostDB {
43
57
logger . info ( '' , { hostFolder, provider, dbName } ) ;
44
58
45
59
const backUpPath = `../${ repoName } /${ hostFolder } ` ;
60
+ if ( ! fs . existsSync ( backUpPath ) ) fs . mkdirSync ( backUpPath , { recursive : true } ) ;
61
+ shellExec ( `cd ${ backUpPath } && find . -type d -empty -delete` ) ; // delete empty folders
46
62
const times = await fs . readdir ( backUpPath ) ;
47
- const currentBackupTimestamp = Math . max ( ...times . map ( ( t ) => parseInt ( t ) ) ) ;
63
+ const currentBackupTimestamp = Math . max ( ...times . map ( ( t ) => parseInt ( t ) ) . filter ( ( t ) => ! isNaN ( t ) ) ) ;
48
64
dbs [ provider ] [ dbName ] . currentBackupTimestamp = currentBackupTimestamp ;
49
- const removeBackupTimestamp = Math . min ( ...times . map ( ( t ) => parseInt ( t ) ) ) ;
65
+ const removeBackupTimestamp = Math . min ( ...times . map ( ( t ) => parseInt ( t ) ) . filter ( ( t ) => ! isNaN ( t ) ) ) ;
50
66
51
67
const sqlContainerPath = `/home/${ dbName } .sql` ;
52
68
const _fromPartsParts = `../${ repoName } /${ hostFolder } /${ currentBackupTimestamp } /${ dbName } -parths.json` ;
@@ -68,59 +84,105 @@ class UnderpostDB {
68
84
}
69
85
70
86
if ( options . export === true && times . length >= 5 ) {
87
+ logger . info ( 'remove' , `../${ repoName } /${ hostFolder } /${ removeBackupTimestamp } ` ) ;
71
88
fs . removeSync ( `../${ repoName } /${ hostFolder } /${ removeBackupTimestamp } ` ) ;
89
+ logger . info ( 'create' , `../${ repoName } /${ hostFolder } /${ newBackupTimestamp } ` ) ;
72
90
fs . mkdirSync ( `../${ repoName } /${ hostFolder } /${ newBackupTimestamp } ` , { recursive : true } ) ;
73
91
}
74
92
75
93
switch ( provider ) {
76
94
case 'mariadb' : {
77
- const podName =
78
- options . podName && typeof options . podName === 'string' ? options . podName : `mariadb-statefulset-0` ;
95
+ const podNames =
96
+ options . podName && typeof options . podName === 'string'
97
+ ? options . podName . split ( ',' )
98
+ : UnderpostDeploy . API . get ( 'mariadb' ) ; // `mariadb-statefulset-0`;
79
99
const serviceName = 'mariadb' ;
80
- if ( options . import === true ) {
81
- shellExec ( `sudo kubectl cp ${ _toSqlPath } ${ nameSpace } /${ podName } :/${ dbName } .sql` ) ;
82
- const cmd = `mariadb -u ${ user } -p${ password } ${ dbName } < /${ dbName } .sql` ;
83
- shellExec (
84
- `kubectl exec -i ${ podName } -- ${ serviceName } -p${ password } -e 'CREATE DATABASE ${ dbName } ;'` ,
85
- ) ;
86
- shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
87
- }
88
- if ( options . export === true ) {
89
- const cmd = `mariadb-dump --user=${ user } --password=${ password } --lock-tables ${ dbName } > ${ sqlContainerPath } ` ;
90
- shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
91
- shellExec ( `sudo kubectl cp ${ nameSpace } /${ podName } :${ sqlContainerPath } ${ _toNewSqlPath } ` ) ;
92
- await splitFileFactory ( dbName , _toNewSqlPath ) ;
100
+ for ( const podNameData of [ podNames [ 0 ] ] ) {
101
+ const podName = podNameData . NAME ;
102
+ if ( options . import === true ) {
103
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "rm -rf /${ dbName } .sql"` ) ;
104
+ shellExec ( `sudo kubectl cp ${ _toSqlPath } ${ nameSpace } /${ podName } :/${ dbName } .sql` ) ;
105
+ const cmd = `mariadb -u ${ user } -p${ password } ${ dbName } < /${ dbName } .sql` ;
106
+ shellExec (
107
+ `kubectl exec -i ${ podName } -- ${ serviceName } -p${ password } -e 'CREATE DATABASE ${ dbName } ;'` ,
108
+ ) ;
109
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
110
+ }
111
+ if ( options . export === true ) {
112
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "rm -rf ${ sqlContainerPath } "` ) ;
113
+ const cmd = `mariadb-dump --user=${ user } --password=${ password } --lock-tables ${ dbName } > ${ sqlContainerPath } ` ;
114
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
115
+ shellExec (
116
+ `sudo kubectl cp ${ nameSpace } /${ podName } :${ sqlContainerPath } ${
117
+ options . outPath ? options . outPath : _toNewSqlPath
118
+ } `,
119
+ ) ;
120
+ await splitFileFactory ( dbName , options . outPath ? options . outPath : _toNewSqlPath ) ;
121
+ }
93
122
}
94
123
break ;
95
124
}
96
125
97
126
case 'mongoose' : {
98
127
if ( options . import === true ) {
99
- const podName =
100
- options . podName && typeof options . podName === 'string' ? options . podName : `mongodb-0` ;
101
- shellExec ( `sudo kubectl cp ${ _toBsonPath } ${ nameSpace } /${ podName } :/${ dbName } ` ) ;
102
- const cmd = `mongorestore -d ${ dbName } /${ dbName } ` ;
103
- shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
128
+ const podNames =
129
+ options . podName && typeof options . podName === 'string'
130
+ ? options . podName . split ( ',' )
131
+ : UnderpostDeploy . API . get ( 'mongo' ) ;
132
+ // `mongodb-0`;
133
+ for ( const podNameData of [ podNames [ 0 ] ] ) {
134
+ const podName = podNameData . NAME ;
135
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "rm -rf /${ dbName } "` ) ;
136
+ shellExec (
137
+ `sudo kubectl cp ${
138
+ options . outPath ? options . outPath : _toBsonPath
139
+ } ${ nameSpace } /${ podName } :/${ dbName } `,
140
+ ) ;
141
+ const cmd = `mongorestore -d ${ dbName } /${ dbName } ${ options . drop ? ' --drop' : '' } ${
142
+ options . preserveUUID ? ' --preserveUUID' : ''
143
+ } `;
144
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "${ cmd } "` ) ;
145
+ }
104
146
}
105
147
if ( options . export === true ) {
106
- const podName = `backup-access` ;
107
- const containerBaseBackupPath = '/backup' ;
108
- let timeFolder = shellExec (
109
- `sudo kubectl exec -i ${ podName } -- sh -c "cd ${ containerBaseBackupPath } && ls -a"` ,
110
- {
111
- stdout : true ,
112
- disableLog : false ,
113
- silent : true ,
114
- } ,
115
- ) . split ( `\n` ) ;
116
- timeFolder = timeFolder [ timeFolder . length - 2 ] ;
117
- if ( timeFolder === '..' ) {
118
- logger . warn ( `Cannot backup available` , { timeFolder } ) ;
119
- } else {
148
+ const podNames =
149
+ options . podName && typeof options . podName === 'string'
150
+ ? options . podName . split ( ',' )
151
+ : UnderpostDeploy . API . get ( 'mongo' ) ; // `backup-access`;
152
+ for ( const podNameData of [ podNames [ 0 ] ] ) {
153
+ const podName = podNameData . NAME ;
154
+ shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "rm -rf /${ dbName } "` ) ;
155
+ if ( options . collections )
156
+ for ( const collection of options . collections )
157
+ shellExec (
158
+ `sudo kubectl exec -i ${ podName } -- sh -c "mongodump -d ${ dbName } --collection ${ collection } -o /${ dbName } "` ,
159
+ ) ;
160
+ else shellExec ( `sudo kubectl exec -i ${ podName } -- sh -c "mongodump -d ${ dbName } -o /${ dbName } "` ) ;
120
161
shellExec (
121
- `sudo kubectl cp ${ nameSpace } /${ podName } :${ containerBaseBackupPath } /${ timeFolder } /${ dbName } ${ _toNewBsonPath } ` ,
162
+ `sudo kubectl cp ${ nameSpace } /${ podName } :/${ dbName } ${
163
+ options . outPath ? options . outPath : _toNewBsonPath
164
+ } `,
122
165
) ;
123
166
}
167
+ if ( false ) {
168
+ const containerBaseBackupPath = '/backup' ;
169
+ let timeFolder = shellExec (
170
+ `sudo kubectl exec -i ${ podName } -- sh -c "cd ${ containerBaseBackupPath } && ls -a"` ,
171
+ {
172
+ stdout : true ,
173
+ disableLog : false ,
174
+ silent : true ,
175
+ } ,
176
+ ) . split ( `\n` ) ;
177
+ timeFolder = timeFolder [ timeFolder . length - 2 ] ;
178
+ if ( timeFolder === '..' ) {
179
+ logger . warn ( `Cannot backup available` , { timeFolder } ) ;
180
+ } else {
181
+ shellExec (
182
+ `sudo kubectl cp ${ nameSpace } /${ podName } :${ containerBaseBackupPath } /${ timeFolder } /${ dbName } ${ _toNewBsonPath } ` ,
183
+ ) ;
184
+ }
185
+ }
124
186
}
125
187
break ;
126
188
}
@@ -131,7 +193,7 @@ class UnderpostDB {
131
193
}
132
194
}
133
195
}
134
- if ( options . export === true ) {
196
+ if ( options . export === true && options . git === true ) {
135
197
shellExec ( `cd ../${ repoName } && git add .` ) ;
136
198
shellExec (
137
199
`underpost cmt ../${ repoName } backup '' '${ new Date ( newBackupTimestamp ) . toLocaleDateString ( ) } ${ new Date (
0 commit comments