diff --git a/deploy/docker/fs/opt/appsmith/utils/bin/backup.js b/deploy/docker/fs/opt/appsmith/utils/bin/backup.js index a2ef2b85578f..6268a5aa276c 100644 --- a/deploy/docker/fs/opt/appsmith/utils/bin/backup.js +++ b/deploy/docker/fs/opt/appsmith/utils/bin/backup.js @@ -1,7 +1,6 @@ const fsPromises = require('fs/promises'); const path = require('path'); const os = require('os'); -const shell = require('shelljs'); const utils = require('./utils'); const Constants = require('./constants'); const logger = require('./logger'); @@ -16,17 +15,18 @@ async function run() { let errorCode = 0; let backupRootPath, archivePath, encryptionPassword; let encryptArchive = false; + try { - const check_supervisord_status_cmd = '/usr/bin/supervisorctl >/dev/null 2>&1'; - shell.exec(check_supervisord_status_cmd, function (code) { - if (code > 0) { - shell.echo('application is not running, starting supervisord'); - shell.exec('/usr/bin/supervisord'); - } - }); + await utils.execCommandSilent(["/usr/bin/supervisorctl"]); + } catch (e) { + console.error('Supervisor is not running, exiting.'); + process.exitCode = 1; + return; + } + try { console.log('Available free space at /appsmith-stacks'); - const availSpaceInBytes = getAvailableBackupSpaceInBytes(); + const availSpaceInBytes = getAvailableBackupSpaceInBytes("/appsmith-stacks"); console.log('\n'); checkAvailableBackupSpace(availSpaceInBytes); @@ -232,13 +232,14 @@ function getTimeStampInISO() { return new Date().toISOString().replace(/:/g, '-') } -function getAvailableBackupSpaceInBytes() { - return parseInt(shell.exec('df --output=avail -B 1 /appsmith-stacks | tail -n 1'), 10) +async function getAvailableBackupSpaceInBytes(path) { + const stat = await fsPromises.statfs(path); + return stat.bsize * stat.bfree; } function checkAvailableBackupSpace(availSpaceInBytes) { if (availSpaceInBytes < Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES) { - throw new Error('Not enough space avaliable at /appsmith-stacks. Please ensure availability of atleast 2GB to backup successfully.'); + throw new Error("Not enough space available at /appsmith-stacks. Please ensure availability of at least 2GB to backup successfully."); } } @@ -259,4 +260,4 @@ module.exports = { removeOldBackups, getEncryptionPasswordFromUser, encryptBackupArchive, -}; \ No newline at end of file +}; diff --git a/deploy/docker/fs/opt/appsmith/utils/bin/backup.test.js b/deploy/docker/fs/opt/appsmith/utils/bin/backup.test.js index 335dfd71a427..ddf46775e431 100644 --- a/deploy/docker/fs/opt/appsmith/utils/bin/backup.test.js +++ b/deploy/docker/fs/opt/appsmith/utils/bin/backup.test.js @@ -3,7 +3,6 @@ const Constants = require('./constants'); const os = require('os'); const fsPromises = require('fs/promises'); const utils = require('./utils'); -const shell = require('shelljs'); const readlineSync = require('readline-sync'); describe('Backup Tests', () => { @@ -13,19 +12,19 @@ test('Timestamp string in ISO format', () => { expect(backup.getTimeStampInISO()).toMatch(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\-(\d{2})\-(\d{2})\.(\d{3})Z/) }); -test('Available Space in /appsmith-stacks volume in Bytes', () => { - shell.exec = jest.fn((format) => '20'); - const res = expect(backup.getAvailableBackupSpaceInBytes()) - res.toBe(20) - +test('Available Space in /appsmith-stacks volume in Bytes', async () => { + const res = expect(await backup.getAvailableBackupSpaceInBytes("/")) + res.toBeGreaterThan(1024 * 1024) }); + it('Checkx the constant is 2 GB', () => { let size = 2 * 1024 * 1024 * 1024 expect(Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES).toBe(size) }); + it('Should throw Error when the available size is below MIN_REQUIRED_DISK_SPACE_IN_BYTES', () => { let size = Constants.MIN_REQUIRED_DISK_SPACE_IN_BYTES - 1; - expect(() => {backup.checkAvailableBackupSpace(size)}).toThrow('Not enough space avaliable at /appsmith-stacks. Please ensure availability of atleast 2GB to backup successfully.'); + expect(() => backup.checkAvailableBackupSpace(size)).toThrow(); }); it('Should not hould throw Error when the available size is >= MIN_REQUIRED_DISK_SPACE_IN_BYTES', () => { diff --git a/deploy/docker/fs/opt/appsmith/utils/bin/constants.js b/deploy/docker/fs/opt/appsmith/utils/bin/constants.js index 369fd5042e45..ae44158c82e2 100644 --- a/deploy/docker/fs/opt/appsmith/utils/bin/constants.js +++ b/deploy/docker/fs/opt/appsmith/utils/bin/constants.js @@ -11,9 +11,9 @@ const LAST_ERROR_MAIL_TS = "/appsmith-stacks/data/backup/last-error-mail-ts" const ENV_PATH = "/appsmith-stacks/configuration/docker.env" -const MIN_REQUIRED_DISK_SPACE_IN_BYTES = 2147483648 // 2GB +const MIN_REQUIRED_DISK_SPACE_IN_BYTES = 2_147_483_648 // 2GB -const DURATION_BETWEEN_BACKUP_ERROR_MAILS_IN_MILLI_SEC = 21600000 // 6 hrs +const DURATION_BETWEEN_BACKUP_ERROR_MAILS_IN_MILLI_SEC = 21_600_000 // 6 hrs const APPSMITH_DEFAULT_BACKUP_ARCHIVE_LIMIT = 4 // 4 backup archives @@ -27,4 +27,4 @@ module.exports = { DURATION_BETWEEN_BACKUP_ERROR_MAILS_IN_MILLI_SEC, APPSMITH_DEFAULT_BACKUP_ARCHIVE_LIMIT, ENV_PATH -} \ No newline at end of file +} diff --git a/deploy/docker/fs/opt/appsmith/utils/bin/utils.js b/deploy/docker/fs/opt/appsmith/utils/bin/utils.js index 8b70980adc0c..f64dfd9f451e 100644 --- a/deploy/docker/fs/opt/appsmith/utils/bin/utils.js +++ b/deploy/docker/fs/opt/appsmith/utils/bin/utils.js @@ -154,9 +154,10 @@ function execCommandSilent(cmd, options) { const p = childProcess.spawn(cmd[0], cmd.slice(1), { ...options, + stdio: "ignore", }); - p.on("exit", (code) => { + p.on("close", (code) => { if (isPromiseDone) { return; } @@ -173,8 +174,7 @@ function execCommandSilent(cmd, options) { return; } isPromiseDone = true; - console.error("Error running command", err); - reject(); + reject(err); }); }); } diff --git a/deploy/docker/fs/opt/appsmith/utils/bin/utils.test.js b/deploy/docker/fs/opt/appsmith/utils/bin/utils.test.js new file mode 100644 index 000000000000..f707f2778c5b --- /dev/null +++ b/deploy/docker/fs/opt/appsmith/utils/bin/utils.test.js @@ -0,0 +1,22 @@ +const { describe, test, expect } = require("@jest/globals"); +const utils = require("./utils"); + +describe("execCommandSilent", () => { + + test("Runs a command", async () => { + await utils.execCommandSilent(["echo"]); + }); + + test("silences stdout and stderr", async () => { + const consoleSpy = jest.spyOn(console, "log"); + await utils.execCommandSilent(["node", "--eval", "console.log('test')"]); + expect(consoleSpy).not.toHaveBeenCalled(); + consoleSpy.mockRestore(); + }); + + test("handles errors silently", async () => { + await expect(utils.execCommandSilent(["nonexistentcommand"])) + .rejects.toThrow(); + }); + +});