backend-manager 2.5.13 → 2.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -72
- package/src/cli/cli.js +14 -4
- package/src/manager/functions/core/actions/api/admin/backup.js +81 -2
- package/src/manager/functions/core/cron/daily.js +1 -0
- package/src/manager/index.js +6 -3
- package/templates/{storage-lifecycle-config.json → storage-lifecycle-config-1-day.json} +0 -0
- package/templates/storage-lifecycle-config-30-days.json +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-manager",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.15",
|
|
4
4
|
"description": "Quick tools for developing Firebase functions",
|
|
5
5
|
"main": "src/manager/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -65,75 +65,5 @@
|
|
|
65
65
|
"bin/",
|
|
66
66
|
"src/",
|
|
67
67
|
"templates/"
|
|
68
|
-
],
|
|
69
|
-
"allDependencies": {
|
|
70
|
-
"@firebase/rules-unit-testing": "^2.0.4",
|
|
71
|
-
"@google-cloud/storage": "^5.20.5",
|
|
72
|
-
"@sendgrid/mail": "^7.7.0",
|
|
73
|
-
"@sentry/node": "^6.19.7",
|
|
74
|
-
"backend-assistant": "^0.0.74",
|
|
75
|
-
"busboy": "^1.6.0",
|
|
76
|
-
"chalk": "^4.1.2",
|
|
77
|
-
"cors": "^2.8.5",
|
|
78
|
-
"dotenv": "^16.0.2",
|
|
79
|
-
"firebase-admin": "^9.12.0",
|
|
80
|
-
"firebase-functions": "^3.24.0",
|
|
81
|
-
"fs-jetpack": "^4.3.1",
|
|
82
|
-
"hcaptcha": "^0.1.1",
|
|
83
|
-
"inquirer": "^8.2.4",
|
|
84
|
-
"json5": "^2.2.1",
|
|
85
|
-
"jwt-decode": "^3.1.2",
|
|
86
|
-
"lodash": "^4.17.21",
|
|
87
|
-
"lowdb": "^1.0.0",
|
|
88
|
-
"mailchimp-api-v3": "^1.15.0",
|
|
89
|
-
"moment": "^2.29.4",
|
|
90
|
-
"node-fetch": "^2.6.7",
|
|
91
|
-
"node-powertools": "^0.0.21",
|
|
92
|
-
"npm-api": "^1.0.1",
|
|
93
|
-
"paypal-server-api": "^0.0.8",
|
|
94
|
-
"pushid": "^1.0.0",
|
|
95
|
-
"semver": "^7.3.7",
|
|
96
|
-
"shortid": "^2.2.16",
|
|
97
|
-
"uid-generator": "^2.0.0",
|
|
98
|
-
"ultimate-jekyll-poster": "^0.0.15",
|
|
99
|
-
"universal-analytics": "^0.5.3",
|
|
100
|
-
"uuid": "^8.3.2",
|
|
101
|
-
"wonderful-fetch": "^0.0.14",
|
|
102
|
-
"yargs": "^17.5.1"
|
|
103
|
-
},
|
|
104
|
-
"allDependenciesKeys": [
|
|
105
|
-
"@firebase/rules-unit-testing",
|
|
106
|
-
"@google-cloud/storage",
|
|
107
|
-
"@sendgrid/mail",
|
|
108
|
-
"@sentry/node",
|
|
109
|
-
"backend-assistant",
|
|
110
|
-
"busboy",
|
|
111
|
-
"chalk",
|
|
112
|
-
"cors",
|
|
113
|
-
"dotenv",
|
|
114
|
-
"firebase-admin",
|
|
115
|
-
"firebase-functions",
|
|
116
|
-
"fs-jetpack",
|
|
117
|
-
"hcaptcha",
|
|
118
|
-
"inquirer",
|
|
119
|
-
"json5",
|
|
120
|
-
"jwt-decode",
|
|
121
|
-
"lodash",
|
|
122
|
-
"lowdb",
|
|
123
|
-
"mailchimp-api-v3",
|
|
124
|
-
"moment",
|
|
125
|
-
"node-fetch",
|
|
126
|
-
"node-powertools",
|
|
127
|
-
"npm-api",
|
|
128
|
-
"paypal-server-api",
|
|
129
|
-
"pushid",
|
|
130
|
-
"semver",
|
|
131
|
-
"shortid",
|
|
132
|
-
"uid-generator",
|
|
133
|
-
"ultimate-jekyll-poster",
|
|
134
|
-
"universal-analytics",
|
|
135
|
-
"uuid",
|
|
136
|
-
"wonderful-fetch",
|
|
137
|
-
"yargs"
|
|
138
68
|
]
|
|
139
|
-
}
|
|
69
|
+
}
|
package/src/cli/cli.js
CHANGED
|
@@ -1322,16 +1322,26 @@ async function cmd_iamImportExport(self) {
|
|
|
1322
1322
|
async function cmd_setStorageLifecycle(self) {
|
|
1323
1323
|
return new Promise(function(resolve, reject) {
|
|
1324
1324
|
const command = `gsutil lifecycle set {config} gs://{bucket}`
|
|
1325
|
-
.replace(/{config}/ig, path.resolve(`${__dirname}/../../templates/storage-lifecycle-config.json`))
|
|
1325
|
+
.replace(/{config}/ig, path.resolve(`${__dirname}/../../templates/storage-lifecycle-config-1-day.json`))
|
|
1326
1326
|
.replace(/{bucket}/ig, `us.artifacts.${self.projectName}.appspot.com`)
|
|
1327
|
+
const command2 = `gsutil lifecycle set {config} gs://{bucket}`
|
|
1328
|
+
.replace(/{config}/ig, path.resolve(`${__dirname}/../../templates/storage-lifecycle-config-30-days.json`))
|
|
1329
|
+
.replace(/{bucket}/ig, `bm-backup-firestore-${self.projectName}`)
|
|
1327
1330
|
|
|
1328
|
-
|
|
1331
|
+
exec(command, function (error, stdout, stderr) {
|
|
1329
1332
|
if (error) {
|
|
1330
1333
|
console.log(chalk.red(`Failed to run command`, error));
|
|
1331
1334
|
reject(error);
|
|
1332
1335
|
} else {
|
|
1333
|
-
|
|
1334
|
-
|
|
1336
|
+
exec(command2, function (error, stdout, stderr) {
|
|
1337
|
+
if (error) {
|
|
1338
|
+
console.log(chalk.red(`Failed to run command`, error));
|
|
1339
|
+
reject(error);
|
|
1340
|
+
} else {
|
|
1341
|
+
// console.log(chalk.green(`Added lifecycle`));
|
|
1342
|
+
resolve(stdout);
|
|
1343
|
+
}
|
|
1344
|
+
})
|
|
1335
1345
|
}
|
|
1336
1346
|
});
|
|
1337
1347
|
});
|
|
@@ -36,7 +36,7 @@ Module.prototype.main = function () {
|
|
|
36
36
|
const bucketAddress = `gs://${bucketName}`;
|
|
37
37
|
|
|
38
38
|
await self.createBucket(bucketName, resourceZone);
|
|
39
|
-
await self.deleteOldFiles(bucketName, resourceZone);
|
|
39
|
+
// await self.deleteOldFiles(bucketName, resourceZone);
|
|
40
40
|
|
|
41
41
|
client.exportDocuments({
|
|
42
42
|
name: databaseName,
|
|
@@ -127,7 +127,86 @@ Module.prototype.createBucket = function (bucketName, resourceZone) {
|
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
// https://github.com/zsolt-dev/auto-delete-gcp-storage-backups/blob/master/index.js
|
|
130
|
-
Module.prototype.
|
|
130
|
+
Module.prototype.__RETRY_deleteOldFiles = function (bucketName, resourceZone) {
|
|
131
|
+
const self = this;
|
|
132
|
+
const Manager = self.Manager;
|
|
133
|
+
const Api = self.Api;
|
|
134
|
+
const assistant = self.assistant;
|
|
135
|
+
const payload = self.payload;
|
|
136
|
+
|
|
137
|
+
return new Promise(async function(resolve, reject) {
|
|
138
|
+
const now = moment();
|
|
139
|
+
const deletionRegex = payload.data.payload.deletionRegex;
|
|
140
|
+
|
|
141
|
+
// Helpers
|
|
142
|
+
const getFileObjectWithMetaData = async (bucketName, fileName) => {
|
|
143
|
+
const [metaData] = await storage.bucket(bucketName).file(fileName).getMetadata();
|
|
144
|
+
return ({ fileName, created: metaData.timeCreated });
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const deleteFileFromBucket = async (bucketName, fileName) => {
|
|
148
|
+
assistant.log(`Deleting item: ${fileName}...`, );
|
|
149
|
+
return await storage.bucket(bucketName).file(fileName).delete();
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Main
|
|
153
|
+
// get the file names as an array
|
|
154
|
+
let [allFiles] = await storage.bucket(bucketName).getFiles();
|
|
155
|
+
let deletePromises = [];
|
|
156
|
+
let foldersToDelete = [];
|
|
157
|
+
allFiles = allFiles.map(file => file.name);
|
|
158
|
+
// console.log(`all files: ${allFiles.join(', ')}`);
|
|
159
|
+
|
|
160
|
+
allFiles.forEach((filePath, i) => {
|
|
161
|
+
const fileName = filePath.split('/')[0];
|
|
162
|
+
const date = moment(fileName.split('T')[0]);
|
|
163
|
+
const day = date.date();
|
|
164
|
+
const month = date.month();
|
|
165
|
+
const age = now.diff(date, 'days', false);
|
|
166
|
+
|
|
167
|
+
if (age >= 30) {
|
|
168
|
+
if (day === 1) { return }
|
|
169
|
+
deletePromises.push(deleteFileFromBucket(bucketName, backup.fileName))
|
|
170
|
+
assistant.log(`Preparing to delete ${filePath}: date=${date.format('MMM Do, YYYY')}, day=${day}, month=${month}, age=${age}`, );
|
|
171
|
+
// if (!foldersToDelete.includes(fileName)) {
|
|
172
|
+
// assistant.log(`Preparing to delete ${fileName}: date=${date.format('MMM Do, YYYY')}, day=${day}, month=${month}, age=${age}`, );
|
|
173
|
+
// foldersToDelete = foldersToDelete.concat(fileName);
|
|
174
|
+
// deletePromises.push(deleteFileFromBucket(bucketName, fileName))
|
|
175
|
+
// }
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
console.log('---deletePromises.length', deletePromises.length);
|
|
180
|
+
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
// transform to array of objects with creation timestamp { fileName: abc, created: xyz }
|
|
184
|
+
allFiles = allFiles.map(fileName => getFileObjectWithMetaData(bucketName, fileName));
|
|
185
|
+
allFiles = await Promise.all(allFiles);
|
|
186
|
+
|
|
187
|
+
allFiles.forEach((backup, i) => {
|
|
188
|
+
const date = moment(backup.created);
|
|
189
|
+
const day = date.date();
|
|
190
|
+
const month = date.month();
|
|
191
|
+
const age = now.diff(date, 'days', false);
|
|
192
|
+
|
|
193
|
+
assistant.log(`Sorting item ${i}: date=${date.format('MMM Do, YYYY')}, day=${day}, month=${month}, age=${age}`, );
|
|
194
|
+
|
|
195
|
+
if (age >= 31) {
|
|
196
|
+
if (day === 1) { return }
|
|
197
|
+
deletePromises.push(deleteFileFromBucket(bucketName, backup.fileName))
|
|
198
|
+
} else if ((deletionRegex && backup.fileName.match(deletionRegex))) {
|
|
199
|
+
deletePromises.push(deleteFileFromBucket(bucketName, backup.fileName))
|
|
200
|
+
}
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
await Promise.all(deletePromises);
|
|
204
|
+
|
|
205
|
+
return resolve();
|
|
206
|
+
});
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
Module.prototype.__deleteOldFiles = function (bucketName, resourceZone) {
|
|
131
210
|
const self = this;
|
|
132
211
|
const Manager = self.Manager;
|
|
133
212
|
const Api = self.Api;
|
|
@@ -24,6 +24,7 @@ Module.prototype.main = function() {
|
|
|
24
24
|
return new Promise(async function(resolve, reject) {
|
|
25
25
|
fetch(`${Manager.project.functionsUrl}/bm_api`, {
|
|
26
26
|
method: 'post',
|
|
27
|
+
response: 'json',
|
|
27
28
|
body: {
|
|
28
29
|
backendManagerKey: Manager.config.backend_manager.key,
|
|
29
30
|
command: 'admin:backup',
|
package/src/manager/index.js
CHANGED
|
@@ -48,6 +48,7 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
48
48
|
options.serviceAccountPath = typeof options.serviceAccountPath === 'undefined' ? 'service-account.json' : options.serviceAccountPath;
|
|
49
49
|
options.backendManagerConfigPath = typeof options.backendManagerConfigPath === 'undefined' ? 'backend-manager-config.json' : options.backendManagerConfigPath;
|
|
50
50
|
options.fetchStats = typeof options.fetchStats === 'undefined' ? true : options.fetchStats;
|
|
51
|
+
options.checkNodeVersion = typeof options.checkNodeVersion === 'undefined' ? true : options.checkNodeVersion;
|
|
51
52
|
options.uniqueAppName = options.uniqueAppName || undefined;
|
|
52
53
|
options.assistant = options.assistant || {};
|
|
53
54
|
// options.assistant.optionsLogString = options.assistant.optionsLogString || undefined;
|
|
@@ -75,7 +76,7 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
75
76
|
self.project.resourceZone = options.resourceZone;
|
|
76
77
|
self.project.serviceAccountPath = path.resolve(self.cwd, options.serviceAccountPath)
|
|
77
78
|
self.project.backendManagerConfigPath = path.resolve(self.cwd, options.backendManagerConfigPath)
|
|
78
|
-
|
|
79
|
+
|
|
79
80
|
self.package = resolveProjectPackage();
|
|
80
81
|
self.config = merge(
|
|
81
82
|
requireJSON5(self.project.backendManagerConfigPath),
|
|
@@ -117,7 +118,9 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
117
118
|
// Reject if package.json does not exist
|
|
118
119
|
if (semverUsing !== semverRequired) {
|
|
119
120
|
self.assistant.error(new Error(`Node.js version mismatch: using ${semverUsing} but asked for ${semverRequired}`), {environment: 'production'});
|
|
120
|
-
|
|
121
|
+
if (options.checkNodeVersion) {
|
|
122
|
+
return process.exit(1);
|
|
123
|
+
}
|
|
121
124
|
}
|
|
122
125
|
}
|
|
123
126
|
|
|
@@ -386,7 +389,7 @@ Manager.prototype.init = function (exporter, options) {
|
|
|
386
389
|
// Cron
|
|
387
390
|
exporter.bm_cronDaily =
|
|
388
391
|
self.libraries.functions
|
|
389
|
-
.runWith({ memory: '256MB', timeoutSeconds:
|
|
392
|
+
.runWith({ memory: '256MB', timeoutSeconds: 120 })
|
|
390
393
|
.pubsub.schedule('every 24 hours')
|
|
391
394
|
.onRun(async (context) => {
|
|
392
395
|
return self._process((new (require(`${core}/cron/daily.js`))()).init(self, { context: context, }))
|
|
File without changes
|