Compare commits
2 Commits
78d5c272e9
...
2e6d6d748f
Author | SHA1 | Date |
---|---|---|
|
2e6d6d748f | |
|
443f0deb85 |
|
@ -14,39 +14,70 @@ targetNodes:
|
||||||
- llsmp
|
- llsmp
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
backup:
|
main:
|
||||||
fields:
|
fields:
|
||||||
- type: checkbox
|
- type: radio-fieldset
|
||||||
name: enableScheduledBackup
|
name: scheduleType
|
||||||
caption: Enable Scheduled Backup
|
hidden: false
|
||||||
default: false
|
default: '1'
|
||||||
- type: list
|
|
||||||
name: backupSchedule
|
|
||||||
caption: Backup Schedule
|
|
||||||
required: true
|
|
||||||
dependsOn: enableScheduledBackup:true
|
|
||||||
values:
|
values:
|
||||||
- value: daily
|
- value: 1
|
||||||
caption: Daily
|
caption: Pre-defined
|
||||||
- value: weekly
|
showIf:
|
||||||
caption: Weekly
|
1:
|
||||||
- value: monthly
|
- name: cronTime
|
||||||
caption: Monthly
|
caption: Backup schedule
|
||||||
- value: custom
|
type: list
|
||||||
caption: Custom
|
editable: false
|
||||||
showIf: enableScheduledBackup:true
|
values:
|
||||||
- type: string
|
- value: 0 * * * *
|
||||||
name: customCron
|
caption: "Hourly (at minute 0)"
|
||||||
caption: Custom Cron Schedule
|
- value: 0 0 * * *
|
||||||
dependsOn: backupSchedule:custom
|
caption: "Daily (at 00:00)"
|
||||||
showIf: backupSchedule:custom
|
- 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
|
- type: spinner
|
||||||
name: backupRetentionCount
|
name: backupCount
|
||||||
caption: Number of Backups to Retain
|
caption: Number of backups
|
||||||
default: 5
|
tooltip: "The number of newest backups to be kept during rotation."
|
||||||
min: 1
|
min: 1
|
||||||
max: 30
|
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:
|
onInstall:
|
||||||
- checkApplication
|
- checkApplication
|
||||||
|
@ -54,20 +85,51 @@ onInstall:
|
||||||
- installRestic
|
- installRestic
|
||||||
- setSchedule
|
- 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:
|
actions:
|
||||||
checkApplication:
|
checkApplication:
|
||||||
cmd[${nodes.cp.master.id}]: |-
|
- cmd[${nodes.cp.master.id}]: |-
|
||||||
#!/bin/bash
|
[ -f /root/check_app.sh ] && rm -f /root/check_app.sh;
|
||||||
if [ -e /var/www/webroot/ROOT/wp-config.php ]; then
|
wget -O /root/check_app.sh ${baseUrl}/scripts/check_app.sh;
|
||||||
echo "$(date) trying to install the backup add-on" >> /var/log/backup_addon.log
|
bash /root/check_app.sh;
|
||||||
if [ -e /home/jelastic/bin/wp ]; then
|
user: root
|
||||||
/home/jelastic/bin/wp --info >> /var/log/backup_addon.log
|
- if (response.out == "Non-supported"):
|
||||||
fi
|
- stopEvent:
|
||||||
else
|
type: warning
|
||||||
echo "$(date) The application deployed to WEBROOT cannot be backuped by Jelastic backup add-on" >> /var/log/backup_addon.log
|
message: Deployed application is not supported by Backup add-on.
|
||||||
echo "Non-supported"
|
|
||||||
fi
|
|
||||||
|
|
||||||
checkAddons:
|
checkAddons:
|
||||||
- script: |-
|
- script: |-
|
||||||
var onAfterReturn = { setGlobals: {} },
|
var onAfterReturn = { setGlobals: {} },
|
||||||
|
@ -80,7 +142,7 @@ actions:
|
||||||
if (resp.result != 0) return resp;
|
if (resp.result != 0) return resp;
|
||||||
glbs["alreadyInstalled"] = false;
|
glbs["alreadyInstalled"] = false;
|
||||||
for (let i = 0, n = resp.apps.length; i < n; i++) {
|
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') {
|
if (resp.apps[i].app_id == 'db-backup') {
|
||||||
glbs["alreadyInstalled"] = true;
|
glbs["alreadyInstalled"] = true;
|
||||||
break;
|
break;
|
||||||
|
@ -92,7 +154,7 @@ actions:
|
||||||
- stopEvent:
|
- stopEvent:
|
||||||
type: warning
|
type: warning
|
||||||
message: Database backup add-on is already installed on ${env.name}. Backup addon installation is not possible.
|
message: Database backup add-on is already installed on ${env.name}. Backup addon installation is not possible.
|
||||||
|
|
||||||
installRestic:
|
installRestic:
|
||||||
cmd [cp]: |-
|
cmd [cp]: |-
|
||||||
if which dnf; then
|
if which dnf; then
|
||||||
|
@ -107,18 +169,6 @@ actions:
|
||||||
fi
|
fi
|
||||||
user: root
|
user: root
|
||||||
|
|
||||||
setSchedule:
|
|
||||||
- setGlobals:
|
|
||||||
storageEnv: ${settings.storageName}
|
|
||||||
- if ("${settings.scheduleType}" == 2):
|
|
||||||
- convert
|
|
||||||
- else:
|
|
||||||
- setGlobals:
|
|
||||||
cron: ${settings.cronTime}
|
|
||||||
- installScript:
|
|
||||||
cronTime: ${globals.cron}
|
|
||||||
backupCount: ${settings.backupCount}
|
|
||||||
|
|
||||||
installScript:
|
installScript:
|
||||||
- removeScript
|
- removeScript
|
||||||
- getStorageCtid
|
- getStorageCtid
|
||||||
|
@ -133,30 +183,114 @@ actions:
|
||||||
backupExecNode: ${nodes.cp.master.id}
|
backupExecNode: ${nodes.cp.master.id}
|
||||||
storageEnv: ${response.storageEnvShortName}
|
storageEnv: ${response.storageEnvShortName}
|
||||||
|
|
||||||
globals:
|
callScript:
|
||||||
scriptSufix: mb-backup-manager
|
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:
|
backupAllNow:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/backupAll.sh
|
- script: ${baseUrl}/scripts/backupAllNow.js
|
||||||
backupDatabaseOnly:
|
backupDatabaseOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/backupDatabase.sh
|
- script: ${baseUrl}/scripts/backupDatabaseOnly.js
|
||||||
backupWordPressCoreFilesOnly:
|
backupWordPressCoreOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/backupWordPressCore.sh
|
- script: ${baseUrl}/scripts/backupWordPressCoreOnly.js
|
||||||
backupMediaFilesOnly:
|
backupMediaFilesOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/backupMediaFiles.sh
|
- script: ${baseUrl}/scripts/backupMediaFilesOnly.js
|
||||||
restoreAll:
|
restoreAllOnSpecific:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/restoreAll.sh
|
- script: ${baseUrl}/scripts/restoreAllOnSpecific.js
|
||||||
restoreDatabaseOnly:
|
restoreDatabaseOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/restoreDatabase.sh
|
- script: ${baseUrl}/scripts/restoreDatabaseOnly.js
|
||||||
restoreMediaFilesOnly:
|
restoreMediaFilesOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/restoreMediaFiles.sh
|
- script: ${baseUrl}/scripts/restoreMediaFilesOnly.js
|
||||||
restoreWordPressCoreFilesOnly:
|
restoreWordPressCoreOnly:
|
||||||
cmd[${nodes.cp.master.id}]: scripts/restoreWordPressCore.sh
|
- script: ${baseUrl}/scripts/restoreWordPressCoreOnly.js
|
||||||
configureBackupSchedule:
|
|
||||||
script: scripts/configureSchedule.js
|
|
||||||
manageBackupRetention:
|
|
||||||
script: scripts/manageRetention.js
|
|
||||||
|
|
||||||
onUninstall:
|
menu:
|
||||||
- cmd[${nodes.cp.master.id}]: scripts/uninstallRestic.sh
|
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
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue