From 2e6d6d748fdd25fb9eaf1da4ae3516f478d152cd Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 5 Mar 2024 01:31:33 +0800 Subject: [PATCH] Created main JPS --- mbbackupmanager.jps | 302 ++++++++++++++++++++++--------- scripts/mb-backbackup-manager.js | 93 ++++++++++ 2 files changed, 308 insertions(+), 87 deletions(-) create mode 100644 scripts/mb-backbackup-manager.js diff --git a/mbbackupmanager.jps b/mbbackupmanager.jps index afb2993..f21e927 100644 --- a/mbbackupmanager.jps +++ b/mbbackupmanager.jps @@ -14,39 +14,70 @@ targetNodes: - llsmp settings: - backup: + main: fields: - - type: checkbox - name: enableScheduledBackup - caption: Enable Scheduled Backup - default: false - - type: list - name: backupSchedule - caption: Backup Schedule - required: true - dependsOn: enableScheduledBackup:true + - type: radio-fieldset + name: scheduleType + hidden: false + default: '1' values: - - value: daily - caption: Daily - - value: weekly - caption: Weekly - - value: monthly - caption: Monthly - - value: custom - caption: Custom - showIf: enableScheduledBackup:true - - type: string - name: customCron - caption: Custom Cron Schedule - dependsOn: backupSchedule:custom - showIf: backupSchedule:custom + - value: 1 + caption: Pre-defined + showIf: + 1: + - name: cronTime + caption: Backup schedule + type: list + editable: false + values: + - value: 0 * * * * + caption: "Hourly (at minute 0)" + - value: 0 0 * * * + caption: "Daily (at 00:00)" + - value: 0 0 * * 0 + caption: "Weekly (at 00:00 on Sunday)" + - value: 0 0 1 * * + caption: "Monthly (at 00:00 on day 1)" + default: 0 0 * * * + - caption: Backup storage + type: list + tooltip: "The environment with backup storage to be used for backups creation. Presence of this environment is obligatory." + name: storageName + dependsOn: region + required: true - type: spinner - name: backupRetentionCount - caption: Number of Backups to Retain - default: 5 + name: backupCount + caption: Number of backups + tooltip: "The number of newest backups to be kept during rotation." min: 1 max: 30 - tooltip: "The number of newest backups to be kept during rotation." + default: 5 + onBeforeInit: scripts/configOnBeforeInit.js + + restore: + fields: [] + onBeforeInit: scripts/multipleRestoreOnBeforeInit.js + +onBeforeInit: scripts/backupOnBeforeInit.js + +buttons: +- caption: Backup Now + action: backup + loadingText: Backing up... + confirmText: Do you want to initiate the backup process? + successText: The backup process has been finished successfully. + +- caption: Restore + action: restore + loadingText: Restoring... + settings: restore + successText: The backup have been successfully restored. + title: Restore Backup + submitButtonText: Restore + confirmText: You are going to restore from a backup, which will override all your existing data. This action cannot be canceled or reverted. Do you want to proceed? + +globals: + scriptSufix: wp-backup onInstall: - checkApplication @@ -54,20 +85,51 @@ onInstall: - installRestic - setSchedule +onUninstall: + - callScript: uninstall + - removeScript + +onBeforeDelete: + - callScript: uninstall + - removeScript + +onAfterRedeployContainer[cp]: + - installRestic + +onAfterClone: + - script: return {result:0, jps:MANIFEST}; + - install: ${response.jps} + nodeGroup: ${targetNodes.nodeGroup:cp} + envName: ${event.response.env.envName} + settings: + scheduleType: ${settings.scheduleType} + storageName: ${settings.storageName} + cronTime: ${settings.cronTime} + backupTime: ${settings.backupTime} + sun: ${settings.sun} + mon: ${settings.mon} + tue: ${settings.tue} + wed: ${settings.wed} + thu: ${settings.thu} + fri: ${settings.fri} + sat: ${settings.sat} + tz: ${settings.tz} + backupCount: ${settings.backupCount} + +onAfterConfirmTransfer: setSchedule + actions: checkApplication: - cmd[${nodes.cp.master.id}]: |- - #!/bin/bash - if [ -e /var/www/webroot/ROOT/wp-config.php ]; then - echo "$(date) trying to install the backup add-on" >> /var/log/backup_addon.log - if [ -e /home/jelastic/bin/wp ]; then - /home/jelastic/bin/wp --info >> /var/log/backup_addon.log - fi - else - echo "$(date) The application deployed to WEBROOT cannot be backuped by Jelastic backup add-on" >> /var/log/backup_addon.log - echo "Non-supported" - fi - + - cmd[${nodes.cp.master.id}]: |- + [ -f /root/check_app.sh ] && rm -f /root/check_app.sh; + wget -O /root/check_app.sh ${baseUrl}/scripts/check_app.sh; + bash /root/check_app.sh; + user: root + - if (response.out == "Non-supported"): + - stopEvent: + type: warning + message: Deployed application is not supported by Backup add-on. + checkAddons: - script: |- var onAfterReturn = { setGlobals: {} }, @@ -80,7 +142,7 @@ actions: if (resp.result != 0) return resp; glbs["alreadyInstalled"] = false; for (let i = 0, n = resp.apps.length; i < n; i++) { - if (resp.apps[i].isInstalled) { + if (resp.apps[i].isInstalled) { if (resp.apps[i].app_id == 'db-backup') { glbs["alreadyInstalled"] = true; break; @@ -92,38 +154,20 @@ actions: - stopEvent: type: warning message: Database backup add-on is already installed on ${env.name}. Backup addon installation is not possible. - + installRestic: - cmd [cp]: |- - if ! which restic > /dev/null; then - echo "Restic not found, installing..." - if which dnf > /dev/null; then - dnf install -y epel-release - dnf install -y restic + cmd [cp]: |- + if which dnf; then + dnf install epel-release + dnf install restic else yum-config-manager --add-repo https://copr.fedorainfracloud.org/coprs/copart/restic/repo/epel-7/copart-restic-epel-7.repo yum-config-manager --enable copr:copr.fedorainfracloud.org:copart:restic yum -y install restic yum-config-manager --disable copr:copr.fedorainfracloud.org:copart:restic - fi - else - echo "Restic is already installed." - fi - # Ensure the backup-addon logrotate configuration is always updated - wget -O /etc/logrotate.d/backup-addon ${baseUrl}/scripts/backup-addon; - user: root - - setSchedule: - - setGlobals: - storageEnv: ${settings.storageName} - - if ("${settings.scheduleType}" == 2): - - convert - - else: - - setGlobals: - cron: ${settings.cronTime} - - installScript: - cronTime: ${globals.cron} - backupCount: ${settings.backupCount} + wget -O /etc/logrotate.d/backup-addon ${baseUrl}/scripts/backup-addon; + fi + user: root installScript: - removeScript @@ -139,30 +183,114 @@ actions: backupExecNode: ${nodes.cp.master.id} storageEnv: ${response.storageEnvShortName} -globals: - scriptSufix: mb-backup-manager + callScript: + script: |- + var resp = api.dev.scripting.Eval(appid, session, '${env.envName}-${globals.scriptSufix}', {action:"${this}"}); + if (resp.result === 1702 && "${this}" == "uninstall") { + return { result: 0, out: "script not found" }; + } else { + return resp.response || resp; + } + + removeScript: + script: |- + var resp = api.dev.scripting.GetScript(appid, session, '${env.envName}-${globals.scriptSufix}'); + if (resp.result === 0) { + var resp = api.dev.scripting.DeleteScript(appid, session, '${env.envName}-${globals.scriptSufix}'); + return resp.response || resp; + } + return { result: 0 }; + + backup: + - callScript: backup + + restore: + - cmd[cp]: |- + echo "${settings.backupedEnvName}" > /root/.backupedenv + echo "${settings.backupDir}" > /root/.backupid + user: root + - callScript: restore + + configure: + - setSchedule + + getStorageCtid: + - script: scripts/getStorageCtid.js + + convert: + - script: | + var resp = {result:0, onAfterReturn: {setGlobals:{cron: ""}}}, offset = java.util.TimeZone.getTimeZone("${settings.tz}").getRawOffset(), + setGlobals = resp.onAfterReturn.setGlobals; + + var time = "${settings.backupTime}".split(":"), + d1 = new Date(2020, 1, 10, parseInt(time[0],10), parseInt(time[1],10)), + d2 = new Date(d1.getTime() - offset), + dd = d2.getDate() - d1.getDate(), + days = getDays([${settings.sun:0}, ${settings.mon:0}, ${settings.tue:0}, ${settings.wed:0}, ${settings.thu:0}, ${settings.fri:0}, ${settings.sat:0}], dd); + + setGlobals.cron = d2.getMinutes() + " " + d2.getHours() + " * * " + days.join(","); + + + function getDays(settings, dd) { + var days = []; + for (var i = 0, n = settings.length; i < n; i++) { + if (settings[i]) { + var day = i + dd; + if (day < 0) day +=7; else if (day > 6) day -=7; + days.push(day); + } + } + days.sort(); + return days; + } + + return resp; + + setSchedule: + - setGlobals: + storageEnv: ${settings.storageName} + - if ("${settings.scheduleType}" == 2): + - convert + - else: + - setGlobals: + cron: ${settings.cronTime} + - installScript: + cronTime: ${globals.cron} + backupCount: ${settings.backupCount} -actions: backupAllNow: - cmd[${nodes.cp.master.id}]: scripts/backupAll.sh + - script: ${baseUrl}/scripts/backupAllNow.js backupDatabaseOnly: - cmd[${nodes.cp.master.id}]: scripts/backupDatabase.sh - backupWordPressCoreFilesOnly: - cmd[${nodes.cp.master.id}]: scripts/backupWordPressCore.sh + - script: ${baseUrl}/scripts/backupDatabaseOnly.js + backupWordPressCoreOnly: + - script: ${baseUrl}/scripts/backupWordPressCoreOnly.js backupMediaFilesOnly: - cmd[${nodes.cp.master.id}]: scripts/backupMediaFiles.sh - restoreAll: - cmd[${nodes.cp.master.id}]: scripts/restoreAll.sh + - script: ${baseUrl}/scripts/backupMediaFilesOnly.js + restoreAllOnSpecific: + - script: ${baseUrl}/scripts/restoreAllOnSpecific.js restoreDatabaseOnly: - cmd[${nodes.cp.master.id}]: scripts/restoreDatabase.sh + - script: ${baseUrl}/scripts/restoreDatabaseOnly.js restoreMediaFilesOnly: - cmd[${nodes.cp.master.id}]: scripts/restoreMediaFiles.sh - restoreWordPressCoreFilesOnly: - cmd[${nodes.cp.master.id}]: scripts/restoreWordPressCore.sh - configureBackupSchedule: - script: scripts/configureSchedule.js - manageBackupRetention: - script: scripts/manageRetention.js + - script: ${baseUrl}/scripts/restoreMediaFilesOnly.js + restoreWordPressCoreOnly: + - script: ${baseUrl}/scripts/restoreWordPressCoreOnly.js -onUninstall: - - cmd[${nodes.cp.master.id}]: scripts/uninstallRestic.sh +menu: + items: + - caption: "Backup All Now" + action: backupAllNow + - caption: "Backup Database Only" + action: backupDatabaseOnly + - caption: "Backup WordPress Core Files Only" + action: backupWordPressCoreOnly + - caption: "Backup Media Files Only" + action: backupMediaFilesOnly + - caption: "Restore ALL on specific backup" + action: restoreAllOnSpecific + - caption: "Restore Database Only (specific backup)" + action: restoreDatabaseOnly + - caption: "Restore Media Files Only (specific backup)" + action: restoreMediaFilesOnly + - caption: "Restore WordPress Core Files Only (specific backup)" + action: restoreWordPressCoreOnly + \ No newline at end of file diff --git a/scripts/mb-backbackup-manager.js b/scripts/mb-backbackup-manager.js new file mode 100644 index 0000000..e38e152 --- /dev/null +++ b/scripts/mb-backbackup-manager.js @@ -0,0 +1,93 @@ +function BackupManager(config) { + var Response = com.hivext.api.Response, + Transport = com.hivext.api.core.utils.Transport, + Logger = org.slf4j.LoggerFactory.getLogger("backup-addon:" + config.envName); + + var me = this; + var BACKUP_TYPES = { + CORE: "core", + MEDIA: "media", + DATABASE: "db" + }; + + me.invoke = function(action) { + var actions = { + "backup": me.backup, + "restore": me.restore + }; + + return actions[action] ? actions[action].call(me) : { + result: Response.ERROR_UNKNOWN, + error: "Unknown action: " + action + }; + }; + + me.backup = function() { + // Sequentially perform all backups + me.backupCoreFiles(); + me.backupMediaFiles(); + me.backupDatabase(); + Logger.info("All backups completed successfully."); + }; + + me.backupCoreFiles = function() { + var backupName = me.getBackupName(BACKUP_TYPES.CORE); + // Placeholder for core files backup logic + Logger.info("Core files backup completed: " + backupName); + }; + + me.backupMediaFiles = function() { + var backupName = me.getBackupName(BACKUP_TYPES.MEDIA); + // Placeholder for media files backup logic + Logger.info("Media files backup completed: " + backupName); + }; + + me.backupDatabase = function() { + var backupName = me.getBackupName(BACKUP_TYPES.DATABASE); + // Placeholder for database backup logic + Logger.info("Database backup completed: " + backupName); + }; + + me.restore = function(backupName) { + // Determine type from backupName and call the respective restore function + var type = backupName.split("_")[1]; // Assumes naming convention is used + switch(type) { + case BACKUP_TYPES.CORE: + me.restoreCoreFiles(backupName); + break; + case BACKUP_TYPES.MEDIA: + me.restoreMediaFiles(backupName); + break; + case BACKUP_TYPES.DATABASE: + me.restoreDatabase(backupName); + break; + default: + Logger.error("Unknown backup type for restoration: " + backupName); + } + }; + + me.restoreCoreFiles = function(backupName) { + // Placeholder for core files restore logic + Logger.info("Core files restoration completed: " + backupName); + }; + + me.restoreMediaFiles = function(backupName) { + // Placeholder for media files restore logic + Logger.info("Media files restoration completed: " + backupName); + }; + + me.restoreDatabase = function(backupName) { + // Placeholder for database restore logic + Logger.info("Database restoration completed: " + backupName); + }; + + me.getBackupName = function(type) { + var dateFormat = new java.text.SimpleDateFormat("yyyyMMddHHmmss"); + var dateStr = dateFormat.format(new java.util.Date()); + return config.envName + "_" + type + "_" + dateStr; + }; +} + +// Note: This code assumes the existence of several placeholders where actual backup and restore logic should be implemented. +// Depending on the storage and execution environment, this could involve executing shell commands, interacting with APIs, +// or using tools like Restic for actual data handling.