add backup settings and update cron fork

Signed-off-by: Maurice Preuß (envoyr) <envoyr@froxlor.org>
This commit is contained in:
Maurice Preuß (envoyr)
2023-06-06 17:30:12 +02:00
parent 2ec039372d
commit 94051dc9eb
10 changed files with 259 additions and 127 deletions

View File

@@ -52,7 +52,7 @@ final class MasterCron extends CliCommand
$this->setDescription('Regulary perform tasks created by froxlor');
$this->addArgument('job', InputArgument::IS_ARRAY, 'Job(s) to run');
$this->addOption('run-task', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Run a specific task [1 = re-generate configs, 4 = re-generate dns zones, 10 = re-set quotas, 99 = re-create cron.d-file]')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces re-generating of config-files (webserver, nameserver, etc.)')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Forces given job or, if none given, forces re-generating of config-files (webserver, nameserver, etc.)')
->addOption('debug', 'd', InputOption::VALUE_NONE, 'Output debug information about what is going on to STDOUT.')
->addOption('no-fork', 'N', InputOption::VALUE_NONE, 'Do not fork to background (traffic cron only).');
}
@@ -71,12 +71,13 @@ final class MasterCron extends CliCommand
// handle force option
if ($input->getOption('force')) {
// rebuild all config files
Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::REBUILD_DNS);
Cronjob::inserttask(TaskId::CREATE_QUOTA);
Cronjob::inserttask(TaskId::REBUILD_CRON);
array_push($jobs, 'tasks');
if (empty($jobs) || in_array('tasks', $jobs)) {
Cronjob::inserttask(TaskId::REBUILD_VHOST);
Cronjob::inserttask(TaskId::REBUILD_DNS);
Cronjob::inserttask(TaskId::CREATE_QUOTA);
Cronjob::inserttask(TaskId::REBUILD_CRON);
array_push($jobs, 'tasks');
}
define('CRON_IS_FORCED', 1);
}
// handle debug option
@@ -91,7 +92,7 @@ final class MasterCron extends CliCommand
if ($input->getOption('run-task')) {
$tasks_to_run = $input->getOption('run-task');
foreach ($tasks_to_run as $ttr) {
if (in_array($ttr, [1, 4, 10, 99])) {
if (in_array($ttr, [TaskId::REBUILD_VHOST, TaskId::REBUILD_DNS, TaskId::CREATE_QUOTA, TaskId::REBUILD_CRON])) {
Cronjob::inserttask($ttr);
array_push($jobs, 'tasks');
} else {

View File

@@ -0,0 +1,61 @@
<?php
/**
* This file is part of the Froxlor project.
* Copyright (c) 2010 the Froxlor Team (see authors).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can also view it online at
* https://files.froxlor.org/misc/COPYING.txt
*
* @copyright the authors
* @author Froxlor team <team@froxlor.org>
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
*/
namespace Froxlor\Cron\Backup;
use Froxlor\Cron\Forkable;
use Froxlor\Cron\FroxlorCron;
class BackupCron extends FroxlorCron
{
use Forkable;
public static function run()
{
$users = ['web1', 'web2', 'web3', 'web4', 'web5', 'web6', 'web7', 'web8', 'web9', 'web10'];
self::runFork([self::class, 'handle'], [
[
'user' => '1',
'data' => 'value1',
],
[
'user' => '2',
'data' => 'value2',
]
]);
}
private static function handle($user, $data)
{
echo "BackupCron: started - creating customer backup for user $user\n";
echo $data . "\n";
sleep(rand(1, 3));
echo "BackupCron: finished - creating customer backup for user $user\n";
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Froxlor\Cron;
use Froxlor\Database\Database;
use Froxlor\FroxlorLogger;
trait Forkable
{
public static function runFork($closure, array $attributes = [], int $concurrentChildren = 3)
{
$childrenPids = [];
// We only fork if pcntl_fork is available and nofork flag is not set
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
foreach ($attributes as $closureAttributes) {
// We close the database - connection before we fork, so we don't share resources with the child
Database::needRoot(false); // this forces the connection to be set to null
$pid = pcntl_fork();
if ($pid == -1) {
exit("Error forking...\n");
} else if ($pid == 0) {
// re-create db
Database::needRoot(false);
$closure(...$closureAttributes);
exit();
} else {
$childrenPids[] = $pid;
while(count($childrenPids) >= $concurrentChildren) {
foreach($childrenPids as $key => $pid) {
$res = pcntl_waitpid($pid, $status, WNOHANG);
// If the process has already exited
if($res == -1 || $res > 0)
unset($childrenPids[$key]);
}
sleep(1);
}
}
}
while(pcntl_waitpid(0, $status) != -1);
} else {
if (!defined('CRON_NOFORK_FLAG')) {
if (extension_loaded('pcntl')) {
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
} else {
$msg = "PHP compiled without pcntl.";
}
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking " . self::class . ", this may take a long time!");
}
foreach ($attributes as $closureAttributes) {
$closure(...$closureAttributes);
}
}
}
}

View File

@@ -25,59 +25,25 @@
namespace Froxlor\Cron\System;
use Exception;
use Froxlor\Cron\Forkable;
use Froxlor\Cron\FroxlorCron;
use Froxlor\Database\Database;
use Froxlor\FileDir;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
class BackupCron extends FroxlorCron
class ExportCron extends FroxlorCron
{
use Forkable;
public static function run()
{
// Check Backup-Lock
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
$BackupLock = FileDir::makeCorrectFile("/var/run/froxlor_cron_backup.lock");
if (file_exists($BackupLock) && is_numeric($BackupPid = file_get_contents($BackupLock))) {
if (function_exists('posix_kill')) {
$BackupPidStatus = @posix_kill($BackupPid, 0);
} else {
system("kill -CHLD " . $BackupPid . " 1> /dev/null 2> /dev/null", $BackupPidStatus);
$BackupPidStatus = !$BackupPidStatus;
}
if ($BackupPidStatus) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Backup run already in progress');
return 1;
}
}
// Create Backup Log and Fork
// We close the database - connection before we fork, so we don't share resources with the child
Database::needRoot(false); // this forces the connection to be set to null
$BackupPid = pcntl_fork();
// Parent
if ($BackupPid) {
file_put_contents($BackupLock, $BackupPid);
// unnecessary to recreate database connection here
return 0;
} elseif ($BackupPid == 0) {
// Child
posix_setsid();
// re-create db
Database::needRoot(false);
} else {
// Fork failed
return 1;
}
} elseif (!defined('CRON_NOFORK_FLAG')) {
if (extension_loaded('pcntl')) {
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
} else {
$msg = "PHP compiled without pcntl.";
}
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking backup-cron, this may take a long time!");
}
self::runFork([self::class, 'handle']);
}
public static function handle()
{
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'BackupCron: started - creating customer backup');
$result_tasks_stmt = Database::query("
@@ -113,12 +79,6 @@ class BackupCron extends FroxlorCron
'id' => $row['id']
]);
}
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
@unlink($BackupLock);
die();
}
}
/**
@@ -128,6 +88,7 @@ class BackupCron extends FroxlorCron
*
* @return void
*
* @throws Exception
*/
private static function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog = null)
{

View File

@@ -30,6 +30,7 @@ namespace Froxlor\Cron\Traffic;
* @author Froxlor team <team@froxlor.org> (2010-)
*/
use Froxlor\Cron\Forkable;
use Froxlor\Cron\FroxlorCron;
use Froxlor\Database\Database;
use Froxlor\FileDir;
@@ -42,51 +43,15 @@ use PDO;
class TrafficCron extends FroxlorCron
{
use Forkable;
public static function run()
{
// Check Traffic-Lock
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
$TrafficLock = FileDir::makeCorrectFile("/var/run/froxlor_cron_traffic.lock");
if (file_exists($TrafficLock) && is_numeric($TrafficPid = file_get_contents($TrafficLock))) {
if (function_exists('posix_kill')) {
$TrafficPidStatus = @posix_kill($TrafficPid, 0);
} else {
system("kill -CHLD " . $TrafficPid . " 1> /dev/null 2> /dev/null", $TrafficPidStatus);
$TrafficPidStatus = !$TrafficPidStatus;
}
if ($TrafficPidStatus) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Traffic Run already in progress');
return 1;
}
}
// Create Traffic Log and Fork
// We close the database - connection before we fork, so we don't share resources with the child
Database::needRoot(false); // this forces the connection to be set to null
$TrafficPid = pcntl_fork();
// Parent
if ($TrafficPid) {
file_put_contents($TrafficLock, $TrafficPid);
// unnecessary to recreate database connection here
return 0;
} elseif ($TrafficPid == 0) {
// Child
posix_setsid();
// re-create db
Database::needRoot(false);
} else {
// Fork failed
return 1;
}
} elseif (!defined('CRON_NOFORK_FLAG')) {
if (extension_loaded('pcntl')) {
$msg = "PHP compiled with pcntl but pcntl_fork function is not available.";
} else {
$msg = "PHP compiled without pcntl.";
}
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, $msg . " Not forking traffic-cron, this may take a long time!");
}
self::runFork([self::class, 'handle']);
}
public static function handle()
{
/**
* TRAFFIC AND DISKUSAGE MEASURE
*/
@@ -611,11 +576,6 @@ class TrafficCron extends FroxlorCron
}
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "` SET `value` = UNIX_TIMESTAMP() WHERE `settinggroup` = 'system' AND `varname` = 'last_traffic_run'");
if (function_exists('pcntl_fork') && !defined('CRON_NOFORK_FLAG')) {
@unlink($TrafficLock);
die();
}
}
/**

View File

@@ -314,4 +314,30 @@ class Check
}
return $returnvalue;
}
public static function checkPgpPublicKeySetting($fieldname, $fielddata, $newfieldvalue, $allnewfieldvalues)
{
// if the field is empty, we don't need to check anything
if ($newfieldvalue === '') {
return [self::FORMFIELDS_PLAUSIBILITY_CHECK_OK];
}
// check if gnupg extension is loaded
if (!extension_loaded('gnupg')) {
return [
self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR,
'gnupgextensionnotavailable'
];
}
// check if the pgp public key is a valid key
putenv('GNUPGHOME='.sys_get_temp_dir());
if (gnupg_import(gnupg_init(), $newfieldvalue) === false) {
return [
self::FORMFIELDS_PLAUSIBILITY_CHECK_ERROR,
'invalidpgppublickey'
];
}
return [self::FORMFIELDS_PLAUSIBILITY_CHECK_OK];
}
}