From 7dfa7081fb83003f10ca0d2ddd42e35bbc44179c Mon Sep 17 00:00:00 2001 From: Robin Kluth Date: Wed, 29 Mar 2023 12:07:50 +0200 Subject: [PATCH] * Fixed default setting issue * Do not backup external volumes for now --- src/include/ABHelper.php | 96 ++++++++++++++++++++++++---------- src/include/ABSettings.php | 22 ++++++-- src/pages/content/settings.php | 17 ++++-- src/scripts/backup.php | 18 +++---- 4 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/include/ABHelper.php b/src/include/ABHelper.php index 4405f05..78db611 100644 --- a/src/include/ABHelper.php +++ b/src/include/ABHelper.php @@ -12,6 +12,7 @@ class ABHelper { const LOGLEVEL_ERR = 'error'; private static $skipStartContainers = []; + private static $dockerCfg = null; public static $targetLogLevel = ''; @@ -76,6 +77,13 @@ public static function backupLog(string $msg, string $level = self::LOGLEVEL_INF mkdir(ABSettings::$tempFolder); } + /** + * Do not log, if the script is not running + */ + if (!self::scriptRunning()) { + return; + } + if ($level != self::LOGLEVEL_DEBUG) { file_put_contents(ABSettings::$tempFolder . '/' . ABSettings::$logfile, ($skipDate ? '' : "[" . date("d.m.Y H:i:s") . "][$level]") . " $msg" . ($newLine ? "\n" : ''), FILE_APPEND); } @@ -227,33 +235,25 @@ public static function sortContainers($containers, $order, $reverse = false, $re public static function backupContainer($container, $destination) { global $abSettings, $dockerClient; - self::backupLog("Backup {$container['Name']} - Container Volumeinfo: " . print_r($container['Volumes'], true), self::LOGLEVEL_DEBUG); + $containerSettings = $abSettings->getContainerSpecificSettings($container['Name']); - $stripAppdataPath = ''; + self::backupLog("Backup {$container['Name']} - Container Volumeinfo: " . print_r($container['Volumes'], true), self::LOGLEVEL_DEBUG); - // Get default docker storage path - $dockerCfgFile = ABSettings::$dockerIniFile; - if (file_exists($dockerCfgFile)) { - self::backupLog("Parsing $dockerCfgFile", self::LOGLEVEL_DEBUG); - $dockerCfg = parse_ini_file($dockerCfgFile); - if ($dockerCfg) { - if (isset($dockerCfg['DOCKER_APP_CONFIG_PATH'])) { - $stripAppdataPath = $dockerCfg['DOCKER_APP_CONFIG_PATH']; - self::backupLog("Got default appdataPath: $stripAppdataPath", self::LOGLEVEL_DEBUG); - } - } else { - self::backupLog("Could not parse $dockerCfgFile", self::LOGLEVEL_DEBUG); - } + $volumes = self::examineContainerVolumes($container); + $dockerAppdataPath = self::getDockerAppdataPath(); + if (empty($dockerAppdataPath)) { + ABHelper::backupLog("Docker appdata path could not be examined!", self::LOGLEVEL_ERR); + return false; } - - $volumes = []; - foreach ($container['Volumes'] ?? [] as $volume) { - $hostPath = explode(":", $volume)[0]; - if (!empty($stripAppdataPath) && strpos($volume, $stripAppdataPath) === 0) { - $hostPath = ltrim(str_replace($stripAppdataPath, '', $hostPath), '/'); + if (true || $containerSettings['backupExtVolumes'] == 'no') { + self::backupLog("Should NOT backup ext volumes, sanitizing...", self::LOGLEVEL_DEBUG); + foreach ($volumes as $index => $volume) { + if (str_starts_with($volume, '/')) { + self::backupLog("Removing volume " . $volume . " because ext volumes should be skipped", self::LOGLEVEL_DEBUG); + unset($volumes[$index]); + } } - $volumes[] = $hostPath; } if (empty($volumes)) { @@ -265,14 +265,10 @@ public static function backupContainer($container, $destination) { $destination = $destination . "/" . $container['Name'] . '.tar'; - $containerSettings = $abSettings->getContainerSpecificSettings($container['Name']); - $tarVerifyOptions = ['--diff']; $tarOptions = ['-c']; - if (!empty($stripAppdataPath)) { - $tarOptions[] = $tarVerifyOptions[] = '-C ' . escapeshellarg($stripAppdataPath); - } + $tarOptions[] = $tarVerifyOptions[] = '-C ' . escapeshellarg($dockerAppdataPath); switch ($abSettings->compression) { case 'yes': @@ -337,6 +333,7 @@ public static function backupContainer($container, $destination) { /** * Special debug: The creation was ok but verification failed: Something is accessing docker files! List docker info for this container */ + $output = null; // Reset exec lines exec("ps aux | grep docker", $output); self::backupLog("ps aux docker:" . PHP_EOL . print_r($output, true), self::LOGLEVEL_DEBUG); $nowRunning = $dockerClient->getDockerContainers(); @@ -371,4 +368,49 @@ public static function scriptRunning($externalCmd = false) { public static function abortRequested() { return file_exists(ABSettings::$tempFolder . '/' . ABSettings::$stateFileAbort); } + + public static function getDockerAppdataPath() { + $dockerAppdataPath = ''; + + // Get default docker storage path + if (empty(self::$dockerCfg)) { + $dockerCfgFile = ABSettings::$dockerIniFile; + if (file_exists($dockerCfgFile)) { + self::backupLog("Parsing $dockerCfgFile", self::LOGLEVEL_DEBUG); + $dockerCfg = parse_ini_file($dockerCfgFile); + ABHelper::backupLog("dockerCfg: " . PHP_EOL . print_r($dockerCfg, true), self::LOGLEVEL_DEBUG); + if ($dockerCfg) { + self::$dockerCfg = $dockerCfg; + } else { + self::backupLog("Could not parse $dockerCfgFile", self::LOGLEVEL_ERR); + return false; + } + } + } else { + ABHelper::backupLog("Got dockerCfg from cache.", ABHelper::LOGLEVEL_DEBUG); + $dockerCfg = self::$dockerCfg; + } + + if (isset($dockerCfg['DOCKER_APP_CONFIG_PATH'])) { + $dockerAppdataPath = $dockerCfg['DOCKER_APP_CONFIG_PATH']; + } else { + self::backupLog("dockerCfg is there but no Appdata path iset set??", self::LOGLEVEL_ERR); + } + return $dockerAppdataPath; + } + + public static function examineContainerVolumes($container) { + + $dockerAppdataPath = self::getDockerAppdataPath(); + + $volumes = []; + foreach ($container['Volumes'] ?? [] as $volume) { + $hostPath = explode(":", $volume)[0]; + if (!empty($dockerAppdataPath) && str_starts_with($volume, $dockerAppdataPath)) { + $hostPath = ltrim(str_replace($dockerAppdataPath, '', $hostPath), '/'); + } + $volumes[] = rtrim($hostPath, '/'); + } + return $volumes; + } } diff --git a/src/include/ABSettings.php b/src/include/ABSettings.php index 205de1a..fb01ab8 100644 --- a/src/include/ABSettings.php +++ b/src/include/ABSettings.php @@ -36,7 +36,17 @@ class ABSettings { public string|int $keepMinBackups = '3'; public string $destination = ''; public string $compression = 'yes'; - public array $defaults = ['verifyBackup' => 'yes', 'ignoreBackupErrors' => 'no', 'updateContainer' => 'no']; + public array $defaults = [ + 'verifyBackup' => 'yes', + 'ignoreBackupErrorss' => 'no', + 'updateContainer' => 'no', + + // The following are hidden, container special default settings + 'skip' => 'no', + 'exclude' => '', + 'dontStop' => 'no', + 'backupExtVolumes' => 'no' + ]; public string $flashBackup = 'yes'; public string $notification = 'errors'; public string $backupFrequency = 'disabled'; @@ -61,7 +71,11 @@ public function __construct() { if ($config) { foreach ($config as $key => $value) { if (property_exists($this, $key)) { - $this->$key = $value; + if ($key == 'defaults') { + $this->$key = array_merge($this->defaults, $value); + } else { + $this->$key = $value; + } } } } @@ -103,10 +117,10 @@ public function getContainerSpecificSettings($name, $setEmptyToDefault = true) { foreach ($defaultSettings as $setting => $value) { $defaultSettings[$setting] = ''; } - return array_merge($defaultSettings, ['skip' => 'no', 'exclude' => '', 'dontStop' => 'no']); + return $defaultSettings; } - $settings = $this->containerSettings[$name]; + $settings = array_merge($this->defaults, $this->containerSettings[$name]); if ($setEmptyToDefault) { foreach ($settings as $setting => $value) { diff --git a/src/pages/content/settings.php b/src/pages/content/settings.php index 094fa74..38b065c 100644 --- a/src/pages/content/settings.php +++ b/src/pages/content/settings.php @@ -295,14 +295,15 @@ class="fa fa-clock-o title">Notifications, scheduling and retention foreach ($allContainers as $container) { $image = empty($container['Icon']) ? '/plugins/dynamix.docker.manager/images/question.png' : $container['Icon']; - $volumes = []; - foreach ($container['Volumes'] ?? [] as $volume) { - $volumes[] = explode(":", $volume)[0]; - } - $volumes = implode("
", $volumes); + $volumes = ABHelper::examineContainerVolumes($container); if (empty($volumes)) { $volumes = "No volumes - container will NOT being backed up!"; + } else { + foreach ($volumes as $index => $volume) { + $volumes[$index] = ' ' . $volume . ''; + } + $volumes = implode('
', $volumes); } $containerSetting = $abSettings->getContainerSpecificSettings($container['Name'], false); @@ -323,6 +324,12 @@ class="fa fa-clock-o title">Notifications, scheduling and retention
Configured volumes
$volumes
+ +
Verify Backup?