Skip to content

Commit

Permalink
Add backup folder to persistent volume for services (#267)
Browse files Browse the repository at this point in the history
Co-authored-by: Thomas Fink <[email protected]>
  • Loading branch information
ThomasAFink and ThomasAFink authored Apr 2, 2024
1 parent 107d2fb commit 77876b2
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 87 deletions.
2 changes: 1 addition & 1 deletion zmsapi/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@
\BO\Zmsdb\Source\Dldb::$importPath = \App::APP_PATH . \App::$data;

// load routing
\BO\Slim\Bootstrap::loadRouting(\App::APP_PATH . '/routing.php');
\BO\Slim\Bootstrap::loadRouting(\App::APP_PATH . '/routing.php');
3 changes: 1 addition & 2 deletions zmsapi/src/Zmsapi/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ class Application extends \BO\Slim\Application
*/
public static $data = '/data';


/**
* @var \DateTimeInterface $now time to use for today (testing)
*/
Expand All @@ -97,4 +96,4 @@ public static function getNow()
}
return new \DateTimeImmutable();
}
}
}
6 changes: 3 additions & 3 deletions zmsdb/bin/updateDldbData
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
require_once(__DIR__."/script_bootstrap.php");

if (!\BO\Zmsdb\Source\Dldb::$importPath) {
echo "MISSING dldb data directory. Does a config.php exists?\n";
exit(1);
echo "MISSING dldb \data directory. Does a config.php exists?\n";
}

if (isset($argv[1]) && $argv[1] == '--commit') {
$importer = new \BO\Zmsdb\Source\Dldb();
$importer->startImport(preg_grep('#--?v(erbose)?#', $argv));
Expand All @@ -16,4 +16,4 @@ if (isset($argv[1]) && $argv[1] == '--commit') {
. "\t!!!!!!!!!!!!!!!!!!!!!!!\n"
. "\t!! DATA LOSS WARNING !!\n"
. "\t!!!!!!!!!!!!!!!!!!!!!!!\n\n";
}
}
155 changes: 74 additions & 81 deletions zmsdldb/bin/dldbget
Original file line number Diff line number Diff line change
@@ -1,124 +1,117 @@
#!/usr/bin/env php
<?php
/**
* Download and validate json files
* Download and validate JSON files, and handle backups if changes are detected.
*/
$localInclude = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor';
$modulInclude = __DIR__ . str_repeat(DIRECTORY_SEPARATOR . '..', 3);
set_include_path(get_include_path() . PATH_SEPARATOR . $localInclude . PATH_SEPARATOR . $modulInclude);
require('autoload.php');
require 'vendor/autoload.php';

use Garden\Cli\Cli;
use \Httpful\Request;
use Httpful\Request;

$cli = new Cli();

$cli->description("Downloads json files from the official site and validates them and replaces the old files.")
$cli->description("Downloads JSON files from the official site, validates them, replaces the old files, and handles backups if changes are detected.")
->opt('output:o', 'Path to save files', true)
->opt('proxy:p', 'Proxy server like "proxy:3128"', false)
->opt('base:b', 'Base download url', false)
;
->opt('proxy:p', 'Proxy server like \"proxy:3128\"', false)
->opt('base:b', 'Base download url', true);
$args = $cli->parse($argv, true);

$destinationPath = realpath($args->getOpt('output'));
$destinationPath = $args->getOpt('output');
$backupPath = $destinationPath . '/backups';

if (!is_writeable($destinationPath) || !is_dir($destinationPath)) {
echo $cli->red("$destinationPath should be a writeable directory\n");
// Ensure the destination directory exists
if (!is_dir($destinationPath) && !mkdir($destinationPath, 0777, true) && !is_dir($destinationPath)) {
echo $cli->red("Failed to create the destination directory at $destinationPath\n");
exit(1);
}

$baseDomain = $args->getOpt("base");
$client = Request::init()
->withoutAutoParsing()
->followRedirects()
->timeout(30);
$proxy = $args->getOpt('proxy') ? $args->getOpt('proxy') : getenv('HTTP_PROXY');
$baseDomain = $args->getOpt('base');
$proxy = $args->getOpt('proxy') ?: getenv('HTTP_PROXY');
$client = Request::init()->withoutAutoParsing()->followRedirects()->timeout(30);

if ($proxy) {
$proxyconf = array();
preg_match('#^(?:(?P<user>[^:]+):(?P<pass>[^@]+)@)?(?P<host>[^:]+):?(?P<port>\d+)?$#', $proxy, $proxyconf);
$proxyconf = array_merge(array('host' => '','port' => '80','user' => false,'pass' => false), $proxyconf);
if ($proxyconf['user']) {
$client->useProxy(
$proxyconf['host'],
$proxyconf['port'],
CURLAUTH_BASIC,
$proxyconf['user'],
$proxyconf['pass']
);
} else {
$client->useProxy($proxyconf['host'], $proxyconf['port']);
}
$client->useProxy($proxy);
}

Request::ini($client);

$downloads = array(
array(
$downloads = [
[
'url' => '/export/standorte/json/',
'file' => 'locations_de.json',
),
array(
],
[
'url' => '/export/standorte/json/en/',
'file' => 'locations_en.json',
),
array(
],
[
'url' => '/export/dienstleistungen/json/',
'file' => 'services_de.json',
),
array(
],
[
'url' => '/export/dienstleistungen/json/en/',
'file' => 'services_en.json',
),
array(
],
[
'url' => '/export/themen/json/',
'file' => 'topic_de.json',
),
array(
],
[
'url' => '/export/behoerden/json/',
'file' => 'authority_de.json',
),
array(
],
[
'url' => '/export/settings/json/',
'file' => 'settings.json',
),
);
],
];

// Backup logic
$backupRequired = false;
foreach ($downloads as $download) {
$dest = $destinationPath . DIRECTORY_SEPARATOR . $download['file'];
$destFile = $destinationPath . '/' . $download['file'];
$request = Request::get($baseDomain . $download['url'])->send();

if (file_exists($dest)) {
$oldContentJson = file_get_contents($dest);
} else {
$oldContentJson = '{}';
if ($request->code !== 200 || (isset($request->body->error) && $request->body->error)) {
echo $cli->red("Failed to download or validate {$download['file']}\n");
continue;
}
$oldContent = json_decode($oldContentJson, true);
$oldContentJson = null;

$request = Request::get($baseDomain . $download['url']);

if (isset($oldContent['hash']) && !empty($oldContent['hash'])) {
$request->addHeader('If-None-Match', $oldContent['hash']);
$newContent = $request->raw_body;
if (file_exists($destFile) && md5_file($destFile) !== md5($newContent)) {
$backupRequired = true;
}
$oldContent = null;

$response = $request
//->followRedirects()
->send()
;

file_put_contents($destFile, $newContent);
}

if (304 == $response->code) {
continue;
// Perform backup if necessary
if ($backupRequired) {
$timestamp = date('Y-m-d');
$backupDir = $backupPath . '/' . $timestamp;

if (!mkdir($backupDir, 0777, true) && !is_dir($backupDir)) {
echo $cli->red("Failed to create backup directory at $backupDir\n");
exit(1);
}

// Copy updated files to backup
foreach (glob($destinationPath . '/*.json') as $file) {
if (strpos($file, '/backups/') === false && !copy($file, $backupDir . '/' . basename($file))) {
echo $cli->red("Failed to backup $file\n");
}
}
}

$json = $response->body;
$tmp = $destinationPath . DIRECTORY_SEPARATOR . 'tmp.' . $download['file'];
file_put_contents($tmp, $json);
$data = json_decode($json, true);
$json = null;
$response = null;
if (array_key_exists('error', $data) && $data['error'] === false) {
rename($tmp, $dest);
} else {
echo $cli->red($baseDomain . $download['url'] . " did not validate, see temp file $tmp \n");
exit(1);
// Logic to delete backups older than 7 days
$sevenDaysAgo = time() - (7 * 24 * 60 * 60);
foreach (glob($backupPath . '/*', GLOB_ONLYDIR) as $dir) {
if (filemtime($dir) < $sevenDaysAgo) {
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $item) {
$item->isDir() ? rmdir($item->getRealPath()) : unlink($item->getRealPath());
}
rmdir($dir);
echo "Deleted old backup: $dir\n";
}
$data = null;
}

echo "Downloads and backups (if necessary) completed.\n";

0 comments on commit 77876b2

Please sign in to comment.