Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gladys Plus should upload backups in several chunks #1519

Merged
merged 8 commits into from
May 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Display Gladys Plus backups in background jobs
  • Loading branch information
Pierre-Gilles committed May 9, 2022
commit 2a3cc1704d50cf307c6c4af85c563b8ed700f902
3 changes: 2 additions & 1 deletion front/src/config/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,8 @@
"jobTypes": {
"monthly-device-state-aggregate": "Monthly sensors aggregation",
"daily-device-state-aggregate": "Daily sensors aggregation",
"hourly-device-state-aggregate": "Hourly sensors aggregation"
"hourly-device-state-aggregate": "Hourly sensors aggregation",
"gladys-gateway-backup": "Gladys Plus backup"
},
"jobErrors": {
"purged-when-restarted": "Gladys Assistant restarted while this job was still running, so it was purged. It doesn't mean the job has failed, it's a normal behavior."
Expand Down
3 changes: 2 additions & 1 deletion front/src/config/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,8 @@
"jobTypes": {
"monthly-device-state-aggregate": "Aggrégation donnée capteur mensuelle",
"daily-device-state-aggregate": "Aggrégation donnée capteur journalière",
"hourly-device-state-aggregate": "Aggrégation donnée capteur horaire"
"hourly-device-state-aggregate": "Aggrégation donnée capteur horaire",
"gladys-gateway-backup": "Sauvegarde Gladys Plus"
},
"jobErrors": {
"purged-when-restarted": "Gladys Assistant a redémarré alors que cette tâche était en cours. Cela ne veut pas dire que cette tâche a échouée, c'est un comportement normal."
Expand Down
2 changes: 1 addition & 1 deletion server/api/controllers/gateway.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ module.exports = function GatewayController(gladys) {
* @apiGroup Gateway
*/
async function createBackup(req, res) {
gladys.event.emit(EVENTS.GATEWAY.CREATE_BACKUP, null);
gladys.event.emit(EVENTS.GATEWAY.CREATE_BACKUP);
res.json({
success: true,
});
Expand Down
16 changes: 15 additions & 1 deletion server/lib/gateway/gateway.backup.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ const UPLOAD_ONE_CHUNK_RETRY_OPTIONS = {

/**
* @description Create a backup and upload it to the Gateway
* @param {string} jobId - The job id.
* @returns {Promise} - Resolve when backup is finished.
* @example
* backup();
*/
async function backup() {
async function backup(jobId) {
const encryptKey = await this.variable.getValue('GLADYS_GATEWAY_BACKUP_KEY');
if (encryptKey === null) {
throw new NotFoundError('GLADYS_GATEWAY_BACKUP_KEY_NOT_FOUND');
Expand Down Expand Up @@ -60,17 +61,20 @@ async function backup() {
logger.info(`Gateway backup: Unlocking Database`);
});
}, SQLITE_BACKUP_RETRY_OPTIONS);
await this.job.updateProgress(jobId, 10);
const fileInfos = await fsPromise.stat(backupFilePath);
const fileSizeMB = Math.round(fileInfos.size / 1024 / 1024);
logger.info(`Gateway backup : Success! File size is ${fileSizeMB}mb.`);
// compress backup
logger.info(`Gateway backup: Gzipping backup`);
await exec(`gzip ${backupFilePath}`);
await this.job.updateProgress(jobId, 20);
// encrypt backup
logger.info(`Gateway backup: Encrypting backup`);
await exec(
`openssl enc -aes-256-cbc -pass pass:${encryptKey} -in ${compressedBackupFilePath} -out ${encryptedBackupFilePath}`,
);
await this.job.updateProgress(jobId, 30);
// Upload file to the Gladys Gateway
const encryptedFileInfos = await fsPromise.stat(encryptedBackupFilePath);
logger.info(
Expand All @@ -82,6 +86,9 @@ async function backup() {
file_size: encryptedFileInfos.size,
});
try {
let numberOfchunksUploaded = 0;
const totalOfChunksToUpload = initializeBackupResponse.parts.length;

const partsUploaded = await Promise.map(
initializeBackupResponse.parts,
async (part, index) => {
Expand All @@ -99,6 +106,12 @@ async function backup() {
systemInfos.gladys_version,
);

numberOfchunksUploaded += 1;

const percent = 30 + ((numberOfchunksUploaded * 100) / totalOfChunksToUpload) * 0.7;

await this.job.updateProgress(jobId, percent);

return {
PartNumber: part.part_number,
ETag: headers.etag.replace(/"/g, ''),
Expand All @@ -113,6 +126,7 @@ async function backup() {
parts: partsUploaded,
backup_id: initializeBackupResponse.backup_id,
});
await this.job.updateProgress(jobId, 100);
// done!
logger.info(`Gladys backup uploaded with success to Gladys Gateway.`);
} catch (e) {
Expand Down
7 changes: 5 additions & 2 deletions server/lib/gateway/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const GladysGatewayClient = require('@gladysassistant/gladys-gateway-js');
const WebCrypto = require('node-webcrypto-ossl');
const getConfig = require('../../utils/getConfig');
const logger = require('../../utils/logger');
const { EVENTS } = require('../../utils/constants');
const { EVENTS, JOB_TYPES } = require('../../utils/constants');
const { eventFunctionWrapper } = require('../../utils/functionsWrapper');

const serverUrl = getConfig().gladysGatewayServerUrl;
Expand All @@ -29,7 +29,7 @@ const { restoreBackupEvent } = require('./gateway.restoreBackupEvent');
const { saveUsersKeys } = require('./gateway.saveUsersKeys');
const { refreshUserKeys } = require('./gateway.refreshUserKeys');

const Gateway = function Gateway(variable, event, system, sequelize, config, user, stateManager, serviceManager) {
const Gateway = function Gateway(variable, event, system, sequelize, config, user, stateManager, serviceManager, job) {
this.variable = variable;
this.event = event;
this.system = system;
Expand All @@ -38,6 +38,7 @@ const Gateway = function Gateway(variable, event, system, sequelize, config, use
this.user = user;
this.stateManager = stateManager;
this.serviceManager = serviceManager;
this.job = job;
this.connected = false;
this.restoreInProgress = false;
this.usersKeys = [];
Expand All @@ -46,6 +47,8 @@ const Gateway = function Gateway(variable, event, system, sequelize, config, use
this.googleHomeForwardStateTimeout = 5 * 1000;
this.GladysGatewayClient = GladysGatewayClient;
this.gladysGatewayClient = new GladysGatewayClient({ cryptoLib, serverUrl, logger });
this.backup = this.job.wrapper(JOB_TYPES.GLADYS_GATEWAY_BACKUP, this.backup.bind(this));

this.event.on(EVENTS.GATEWAY.CREATE_BACKUP, eventFunctionWrapper(this.backup.bind(this)));
this.event.on(EVENTS.GATEWAY.CHECK_IF_BACKUP_NEEDED, eventFunctionWrapper(this.checkIfBackupNeeded.bind(this)));
this.event.on(EVENTS.GATEWAY.RESTORE_BACKUP, eventFunctionWrapper(this.restoreBackupEvent.bind(this)));
Expand Down
2 changes: 1 addition & 1 deletion server/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function Gladys(params = {}) {
const scene = new Scene(stateManager, event, device, message, variable, house, calendar, http);
const scheduler = new Scheduler(event);
const weather = new Weather(service, event, message, house);
const gateway = new Gateway(variable, event, system, db.sequelize, config, user, stateManager, service);
const gateway = new Gateway(variable, event, system, db.sequelize, config, user, stateManager, service, job);

const gladys = {
version: '0.1.0', // todo, read package.json
Expand Down
1 change: 1 addition & 0 deletions server/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ const JOB_TYPES = {
HOURLY_DEVICE_STATE_AGGREGATE: 'hourly-device-state-aggregate',
DAILY_DEVICE_STATE_AGGREGATE: 'daily-device-state-aggregate',
MONTHLY_DEVICE_STATE_AGGREGATE: 'monthly-device-state-aggregate',
GLADYS_GATEWAY_BACKUP: 'gladys-gateway-backup',
};

const JOB_STATUS = {
Expand Down