mirror of https://github.com/MISP/MISP
Merge branch 'develop' of github.com:MISP/MISP into develop
commit
bb685e0bf9
|
@ -54,7 +54,7 @@ jobs:
|
|||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: mysql, mbstring, json, xml, opcache, readline, redis, gd
|
||||
extensions: mysql, mbstring, json, xml, opcache, readline, redis, gd, apcu
|
||||
|
||||
- name: Initialize variables
|
||||
run: |
|
||||
|
|
|
@ -255,8 +255,9 @@ Configure::write('Acl.database', 'default');
|
|||
* and their setttings.
|
||||
*/
|
||||
$engine = 'File';
|
||||
if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
|
||||
$engine = 'Apc';
|
||||
if (function_exists('apcu_dec') && (PHP_SAPI !== 'cli' || ini_get('apc.enable_cli'))) {
|
||||
require_once APP . 'Plugin/ApcuCache/Engine/ApcuEngine.php'; // it is not possible to use plugin
|
||||
$engine = 'Apcu'; // faster version of ApcEngine
|
||||
}
|
||||
|
||||
// In development mode, caches should expire quickly.
|
||||
|
|
|
@ -17,8 +17,6 @@ class StartWorkerShell extends AppShell
|
|||
|
||||
private const DEFAULT_MAX_EXECUTION_TIME = 86400; // 1 day
|
||||
|
||||
public $tasks = ['ConfigLoad'];
|
||||
|
||||
public function initialize(): void
|
||||
{
|
||||
parent::initialize();
|
||||
|
@ -30,17 +28,14 @@ class StartWorkerShell extends AppShell
|
|||
$parser = parent::getOptionParser();
|
||||
$parser
|
||||
->addArgument('queue', [
|
||||
'help' => sprintf(
|
||||
'Name of the queue to process. Must be one of [%]',
|
||||
implode(', ', $this->BackgroundJobsTool->getQueues())
|
||||
),
|
||||
'help' => 'Name of the queue to process.',
|
||||
'choices' => $this->BackgroundJobsTool->getQueues(),
|
||||
'required' => true
|
||||
])
|
||||
->addOption(
|
||||
'maxExecutionTime',
|
||||
[
|
||||
'help' => 'Worker maximum execution time (seconds) before it self-destruct.',
|
||||
'help' => 'Worker maximum execution time (seconds) before it self-destruct. Zero means unlimited.',
|
||||
'default' => self::DEFAULT_MAX_EXECUTION_TIME,
|
||||
'required' => false
|
||||
]
|
||||
|
@ -64,18 +59,17 @@ class StartWorkerShell extends AppShell
|
|||
CakeLog::info("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - starting to process background jobs...");
|
||||
|
||||
while (true) {
|
||||
$this->ConfigLoad->execute();
|
||||
$this->checkMaxExecutionTime();
|
||||
|
||||
$job = $this->BackgroundJobsTool->dequeue($this->worker->queue());
|
||||
|
||||
if ($job) {
|
||||
CakeLog::info("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - launching job with id: {$job->id()} ...");
|
||||
CakeLog::info("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - launching job with ID: {$job->id()}...");
|
||||
|
||||
try {
|
||||
$this->BackgroundJobsTool->run($job);
|
||||
} catch (Exception $exception) {
|
||||
CakeLog::error("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - job id: {$job->id()} failed with exception: {$exception->getMessage()}");
|
||||
CakeLog::error("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - job ID: {$job->id()} failed with exception: {$exception->getMessage()}");
|
||||
$job->setStatus(BackgroundJob::STATUS_FAILED);
|
||||
$this->BackgroundJobsTool->update($job);
|
||||
}
|
||||
|
@ -90,6 +84,9 @@ class StartWorkerShell extends AppShell
|
|||
*/
|
||||
private function checkMaxExecutionTime(): void
|
||||
{
|
||||
if ($this->maxExecutionTime === 0) {
|
||||
return;
|
||||
}
|
||||
if ((time() - $this->worker->createdAt()) > $this->maxExecutionTime) {
|
||||
CakeLog::info("[WORKER PID: {$this->worker->pid()}][{$this->worker->queue()}] - worker max execution time reached, exiting gracefully worker...");
|
||||
exit;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
App::uses('Model', 'Model');
|
||||
|
||||
class BackgroundJob implements JsonSerializable
|
||||
{
|
||||
public const
|
||||
|
@ -87,7 +85,9 @@ class BackgroundJob implements JsonSerializable
|
|||
$this->args()
|
||||
),
|
||||
$descriptorSpec,
|
||||
$pipes
|
||||
$pipes,
|
||||
null,
|
||||
['BACKGROUND_JOB_ID' => $this->id]
|
||||
);
|
||||
|
||||
$stdout = stream_get_contents($pipes[1]);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
App::uses('Model', 'Model');
|
||||
|
||||
class Worker implements JsonSerializable
|
||||
{
|
||||
/** @var integer|null */
|
||||
|
|
|
@ -116,7 +116,6 @@ class BackgroundJobsTool
|
|||
|
||||
if ($this->settings['enabled'] === true) {
|
||||
$this->RedisConnection = $this->createRedisConnection();
|
||||
$this->Supervisor = $this->createSupervisorConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,8 +127,8 @@ class BackgroundJobsTool
|
|||
* @param array $args Arguments passed to the job.
|
||||
* @param boolean|null $trackStatus Whether to track the status of the job.
|
||||
* @param int|null $jobId Id of the relational database record representing the job.
|
||||
* @return string Background Job Id.
|
||||
* @param array $metadata Related to the job.
|
||||
* @return string Background Job ID.
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function enqueue(
|
||||
|
@ -223,11 +222,7 @@ class BackgroundJobsTool
|
|||
$rawJob = $this->RedisConnection->blpop($queue, $timeout);
|
||||
|
||||
if (!empty($rawJob)) {
|
||||
try {
|
||||
return new BackgroundJob($rawJob[1]);
|
||||
} catch (Exception $exception) {
|
||||
CakeLog::error("Failed to parse job, invalid format: {$rawJob[1]}. exception: {$exception->getMessage()}");
|
||||
}
|
||||
return new BackgroundJob($rawJob[1]);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -236,7 +231,7 @@ class BackgroundJobsTool
|
|||
/**
|
||||
* Get the job status.
|
||||
*
|
||||
* @param string $jobId Backgroun Job Id.
|
||||
* @param string $jobId Background Job Id.
|
||||
*
|
||||
* @return BackgroundJob|null job status.
|
||||
*
|
||||
|
@ -286,7 +281,7 @@ class BackgroundJobsTool
|
|||
public function getWorkers(): array
|
||||
{
|
||||
$workers = [];
|
||||
$procs = $this->Supervisor->getAllProcesses();
|
||||
$procs = $this->getSupervisor()->getAllProcesses();
|
||||
|
||||
foreach ($procs as $proc) {
|
||||
if ($proc->offsetGet('group') === self::MISP_WORKERS_PROCESS_GROUP) {
|
||||
|
@ -374,7 +369,7 @@ class BackgroundJobsTool
|
|||
{
|
||||
$this->validateWorkerName($name);
|
||||
|
||||
return $this->Supervisor->startProcess(
|
||||
return $this->getSupervisor()->startProcess(
|
||||
sprintf(
|
||||
'%s:%s',
|
||||
self::MISP_WORKERS_PROCESS_GROUP,
|
||||
|
@ -395,13 +390,13 @@ class BackgroundJobsTool
|
|||
{
|
||||
$this->validateQueue($queue);
|
||||
|
||||
$procs = $this->Supervisor->getAllProcesses();
|
||||
$procs = $this->getSupervisor()->getAllProcesses();
|
||||
|
||||
foreach ($procs as $proc) {
|
||||
if ($proc->offsetGet('group') === self::MISP_WORKERS_PROCESS_GROUP) {
|
||||
$name = explode("_", $proc->offsetGet('name'))[0];
|
||||
if ($name === $queue && $proc->offsetGet('state') != \Supervisor\Process::RUNNING) {
|
||||
return $this->Supervisor->startProcess(
|
||||
return $this->getSupervisor()->startProcess(
|
||||
sprintf(
|
||||
'%s:%s',
|
||||
self::MISP_WORKERS_PROCESS_GROUP,
|
||||
|
@ -434,7 +429,7 @@ class BackgroundJobsTool
|
|||
|
||||
$this->validateWorkerName($name);
|
||||
|
||||
return $this->Supervisor->stopProcess(
|
||||
return $this->getSupervisor()->stopProcess(
|
||||
sprintf(
|
||||
'%s:%s',
|
||||
self::MISP_WORKERS_PROCESS_GROUP,
|
||||
|
@ -452,8 +447,8 @@ class BackgroundJobsTool
|
|||
*/
|
||||
public function restartWorkers(bool $waitForRestart = false): void
|
||||
{
|
||||
$this->Supervisor->stopProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
$this->Supervisor->startProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
$this->getSupervisor()->stopProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
$this->getSupervisor()->startProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -464,7 +459,7 @@ class BackgroundJobsTool
|
|||
*/
|
||||
public function restartDeadWorkers(bool $waitForRestart = false): void
|
||||
{
|
||||
$this->Supervisor->startProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
$this->getSupervisor()->startProcessGroup(self::MISP_WORKERS_PROCESS_GROUP, $waitForRestart);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -499,7 +494,7 @@ class BackgroundJobsTool
|
|||
}
|
||||
|
||||
try {
|
||||
$supervisorStatus = ($this->Supervisor->getState()['statecode'] === \Supervisor\Supervisor::RUNNING);
|
||||
$supervisorStatus = $this->getSupervisor()->getState()['statecode'] === \Supervisor\Supervisor::RUNNING;
|
||||
} catch (Exception $exception) {
|
||||
CakeLog::error("SimpleBackgroundJobs Supervisor error: {$exception->getMessage()}");
|
||||
$supervisorStatus = false;
|
||||
|
@ -597,6 +592,17 @@ class BackgroundJobsTool
|
|||
return $redis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Supervisor\Supervisor
|
||||
*/
|
||||
private function getSupervisor()
|
||||
{
|
||||
if (!$this->Supervisor) {
|
||||
$this->Supervisor = $this->createSupervisorConnection();
|
||||
}
|
||||
return $this->Supervisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Supervisor\Supervisor
|
||||
*/
|
||||
|
@ -644,7 +650,7 @@ class BackgroundJobsTool
|
|||
*/
|
||||
private function getProcessByPid(int $pid): \Supervisor\Process
|
||||
{
|
||||
$procs = $this->Supervisor->getAllProcesses();
|
||||
$procs = $this->getSupervisor()->getAllProcesses();
|
||||
|
||||
foreach ($procs as $proc) {
|
||||
if (
|
||||
|
|
|
@ -383,7 +383,7 @@ class Galaxy extends AppModel
|
|||
throw new NotFoundException(__('Invalid %s.', $target_type));
|
||||
}
|
||||
$target = $target[0];
|
||||
$local_only = $cluster['Galaxy']['local_only'];
|
||||
$local_only = $cluster['GalaxyCluster']['Galaxy']['local_only'];
|
||||
if ($local_only && !$local) {
|
||||
throw new MethodNotAllowedException(__("This Cluster can only be attached in a local scope"));
|
||||
}
|
||||
|
|
|
@ -3157,8 +3157,12 @@ class Server extends AppModel
|
|||
);
|
||||
foreach ($writeableDirs as $path => &$error) {
|
||||
if (!file_exists($path)) {
|
||||
$error = 1;
|
||||
} else if (!is_writable($path)) {
|
||||
// Try to create directory if not exists
|
||||
if (!mkdir($path, 0700, true)) {
|
||||
$error = 1;
|
||||
}
|
||||
}
|
||||
if (!is_writable($path)) {
|
||||
$error = 2;
|
||||
}
|
||||
if ($error !== 0) {
|
||||
|
|
|
@ -42,7 +42,11 @@ class SystemSetting extends AppModel
|
|||
*/
|
||||
public static function setGlobalSetting()
|
||||
{
|
||||
/** @var self $systemSetting */
|
||||
$systemSetting = ClassRegistry::init('SystemSetting');
|
||||
if (!$systemSetting->databaseExists()) {
|
||||
return;
|
||||
}
|
||||
$settings = $systemSetting->getSettings();
|
||||
foreach ($settings as $settingName => $settingValue) {
|
||||
$firstPart = explode('.', $settingName)[0];
|
||||
|
@ -52,6 +56,12 @@ class SystemSetting extends AppModel
|
|||
}
|
||||
}
|
||||
|
||||
public function databaseExists()
|
||||
{
|
||||
$tables = ConnectionManager::getDataSource($this->useDbConfig)->listSources();
|
||||
return in_array('system_settings', $tables, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws JsonException
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
require_once CAKE_CORE_INCLUDE_PATH . '/Cake/Cache/CacheEngine.php';
|
||||
|
||||
/**
|
||||
* APC storage engine for cache. Faster version of original ApcEngine
|
||||
*/
|
||||
class ApcuEngine extends CacheEngine {
|
||||
|
||||
/**
|
||||
* Contains the compiled group names
|
||||
* (prefixed with the global configuration prefix)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_compiledGroupNames = array();
|
||||
|
||||
/**
|
||||
* Initialize the Cache Engine
|
||||
*
|
||||
* Called automatically by the cache frontend
|
||||
* To reinitialize the settings call Cache::engine('EngineName', [optional] settings = array());
|
||||
*
|
||||
* @param array $settings array of setting for the engine
|
||||
* @return bool True if the engine has been successfully initialized, false if not
|
||||
* @see CacheEngine::__defaults
|
||||
*/
|
||||
public function init($settings = array()) {
|
||||
if (!isset($settings['prefix'])) {
|
||||
$settings['prefix'] = Inflector::slug(APP_DIR) . '_';
|
||||
}
|
||||
$settings += array('engine' => 'Apc');
|
||||
parent::init($settings);
|
||||
return function_exists('apcu_dec');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param mixed $value Data to be cached
|
||||
* @param int $duration How long to cache the data, in seconds
|
||||
* @return bool True if the data was successfully cached, false on failure
|
||||
*/
|
||||
public function write($key, $value, $duration) {
|
||||
return apcu_store($key, $value, $duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it
|
||||
*/
|
||||
public function read($key) {
|
||||
return apcu_fetch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param int $offset How much to increment
|
||||
* @return false|int New incremented value, false otherwise
|
||||
*/
|
||||
public function increment($key, $offset = 1) {
|
||||
return apcu_inc($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the value of an integer cached key
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @param int $offset How much to subtract
|
||||
* @return false|int New decremented value, false otherwise
|
||||
*/
|
||||
public function decrement($key, $offset = 1) {
|
||||
return apcu_dec($key, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a key from the cache
|
||||
*
|
||||
* @param string $key Identifier for the data
|
||||
* @return bool True if the value was successfully deleted, false if it didn't exist or couldn't be removed
|
||||
*/
|
||||
public function delete($key) {
|
||||
return apcu_delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all keys from the cache. This will clear every cache config using APC.
|
||||
*
|
||||
* @param bool $check If true, nothing will be cleared, as entries are removed
|
||||
* from APC as they expired. This flag is really only used by FileEngine.
|
||||
* @return bool True Returns true.
|
||||
*/
|
||||
public function clear($check) {
|
||||
if ($check) {
|
||||
return true;
|
||||
}
|
||||
$iterator = new APCUIterator(
|
||||
'/^' . preg_quote($this->settings['prefix'], '/') . '/',
|
||||
APC_ITER_NONE
|
||||
);
|
||||
apcu_delete($iterator);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `group value` for each of the configured groups
|
||||
* If the group initial value was not found, then it initializes
|
||||
* the group accordingly.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function groups() {
|
||||
if (empty($this->_compiledGroupNames)) {
|
||||
foreach ($this->settings['groups'] as $group) {
|
||||
$this->_compiledGroupNames[] = $this->settings['prefix'] . $group;
|
||||
}
|
||||
}
|
||||
|
||||
$groups = apcu_fetch($this->_compiledGroupNames);
|
||||
if (count($groups) !== count($this->settings['groups'])) {
|
||||
foreach ($this->_compiledGroupNames as $group) {
|
||||
if (!isset($groups[$group])) {
|
||||
apcu_store($group, 1);
|
||||
$groups[$group] = 1;
|
||||
}
|
||||
}
|
||||
ksort($groups);
|
||||
}
|
||||
|
||||
$result = array();
|
||||
$groups = array_values($groups);
|
||||
foreach ($this->settings['groups'] as $i => $group) {
|
||||
$result[] = $group . $groups[$i];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the group value to simulate deletion of all keys under a group
|
||||
* old values will remain in storage until they expire.
|
||||
*
|
||||
* @param string $group The group to clear.
|
||||
* @return bool success
|
||||
*/
|
||||
public function clearGroup($group) {
|
||||
apcu_inc($this->settings['prefix'] . $group, 1, $success);
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data for key into cache if it doesn't exist already.
|
||||
* If it already exists, it fails and returns false.
|
||||
*
|
||||
* @param string $key Identifier for the data.
|
||||
* @param mixed $value Data to be cached.
|
||||
* @param int $duration How long to cache the data, in seconds.
|
||||
* @return bool True if the data was successfully cached, false on failure.
|
||||
* @link http://php.net/manual/en/function.apc-add.php
|
||||
*/
|
||||
public function add($key, $value, $duration) {
|
||||
return apc_add($key, $value, $duration);
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@
|
|||
"ext-ssdeep": "For ssdeep hashes correlation",
|
||||
"ext-bcmath": "For faster validating IBAN numbers",
|
||||
"ext-rdkafka": "Required for publishing events to Kafka broker",
|
||||
"ext-apcu": "To cache data in memory instead of file system",
|
||||
"elasticsearch/elasticsearch": "For logging to elasticsearch",
|
||||
"aws/aws-sdk-php": "To upload samples to S3",
|
||||
"jumbojett/openid-connect-php": "For OIDC authentication",
|
||||
|
|
|
@ -244,8 +244,9 @@
|
|||
* and their setttings.
|
||||
*/
|
||||
$engine = 'File';
|
||||
if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) {
|
||||
$engine = 'Apc';
|
||||
if (function_exists('apcu_dec') && (PHP_SAPI !== 'cli' || ini_get('apc.enable_cli'))) {
|
||||
require_once APP . 'Plugin/ApcuCache/Engine/ApcuEngine.php'; // it is not possible to use plugin
|
||||
$engine = 'Apcu';
|
||||
}
|
||||
|
||||
// In development mode, caches should expire quickly.
|
||||
|
|
Loading…
Reference in New Issue