new: [server caching] Initial version WIP

pull/4033/head
iglocska 2019-01-18 09:06:23 +01:00
parent a9a47fb46c
commit 9c5fbdd7e9
7 changed files with 213 additions and 49 deletions

View File

@ -179,6 +179,54 @@ class ServerShell extends AppShell
echo $outcome['message'] . PHP_EOL;
}
public function cacheServer() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['cacheServer'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
if (empty($user)) die('Invalid user.' . PHP_EOL);
$scope = $this->args[1];
if (!empty($this->args[2])) {
$jobId = $this->args[2];
} else {
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'cache_servers',
'job_input' => 'Server: ' . $id,
'status' => 0,
'retries' => 0,
'org' => $user['Organisation']['name'],
'message' => 'Starting server caching.',
);
$this->Job->save($data);
$jobId = $this->Job->id;
}
$this->Job->read(null, $jobId);
$result = $this->Server->cacheServerInitiator($user, $id, $jobId);
$this->Job->id = $jobId;
if ($result !== true) {
$message = 'Job Failed. Reason: ';
$this->Job->save(array(
'id' => $jobId,
'message' => $message . $result,
'progress' => 0,
'status' => 3
));
} else {
$message = 'Job done.';
$this->Job->save(array(
'id' => $jobId,
'message' => $message,
'progress' => 100,
'status' => 4
));
}
echo $message . PHP_EOL;
}
public function cacheFeed() {
if (empty($this->args[0]) || empty($this->args[1])) {
die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['cacheFeed'] . PHP_EOL);

View File

@ -236,6 +236,7 @@ class ServersController extends AppController
$defaults = array(
'push' => 0,
'pull' => 0,
'caching_enabled' => 0,
'json' => '[]',
'push_rules' => '[]',
'pull_rules' => '[]',
@ -422,7 +423,7 @@ class ServersController extends AppController
}
if (!$fail) {
// say what fields are to be updated
$fieldList = array('id', 'url', 'push', 'pull', 'unpublish_event', 'publish_without_email', 'remote_org_id', 'name' ,'self_signed', 'cert_file', 'client_cert_file', 'push_rules', 'pull_rules', 'internal', 'skip_proxy');
$fieldList = array('id', 'url', 'push', 'pull', 'caching_enabled', 'unpublish_event', 'publish_without_email', 'remote_org_id', 'name' ,'self_signed', 'cert_file', 'client_cert_file', 'push_rules', 'pull_rules', 'internal', 'skip_proxy');
$this->request->data['Server']['id'] = $id;
if (isset($this->request->data['Server']['authkey']) && "" != $this->request->data['Server']['authkey']) {
$fieldList[] = 'authkey';
@ -1830,4 +1831,43 @@ misp.direct_call(relative_path, body)
}
}
public function cache($id = 'all')
{
if (Configure::read('MISP.background_jobs')) {
$this->loadModel('Job');
$this->Job->create();
$data = array(
'worker' => 'default',
'job_type' => 'cache_servers',
'job_input' => intval($id) ? $id : 'all',
'status' => 0,
'retries' => 0,
'org' => $this->Auth->user('Organisation')['name'],
'message' => __('Starting server caching.'),
);
$this->Job->save($data);
$jobId = $this->Job->id;
$process_id = CakeResque::enqueue(
'default',
'ServerShell',
array('cacheServer', $this->Auth->user('id'), $id, $jobId),
true
);
$this->Job->saveField('process_id', $process_id);
$message = 'Server caching job initiated.';
} else {
$result = $this->Server->cacheServerInitiator($this->Auth->user(), $id);
if (!$result) {
$this->Flash->error(__('Caching the servers has failed.'));
$this->redirect(array('action' => 'index'));
}
$message = __('Caching the servers has successfully completed.');
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Server', 'cache', false, $this->response->type(), $message);
} else {
$this->Flash->error($message);
$this->redirect(array('action' => 'index'));
}
}
}

View File

@ -72,7 +72,7 @@ class AppModel extends Model
7 => false, 8 => false, 9 => false, 10 => false, 11 => false, 12 => false,
13 => false, 14 => false, 15 => false, 18 => false, 19 => false, 20 => false,
21 => false, 22 => false, 23 => false, 24 => false, 25 => false, 26 => false,
27 => false
27 => false, 28 => false
);
public function afterSave($created, $options = array())
@ -1086,6 +1086,9 @@ class AppModel extends Model
case 27:
$sqlArray[] = 'ALTER TABLE `tags` CHANGE `org_id` `org_id` int(11) NOT NULL DEFAULT 0;';
break;
case 28:
$sqlArray[] = "ALTER TABLE `servers` ADD `caching_enabled` tinyint(1) NOT NULL DEFAULT 0;";
break;
case 'fixNonEmptySharingGroupID':
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';

View File

@ -4247,4 +4247,88 @@ class Server extends AppModel
}
return true;
}
public function cacheServerInitiator($user, $id = 'all', $jobId = false)
{
$params = array(
'conditions' => array('caching_enabled' => 1),
'recursive' => -1
);
$redis = $this->setupRedis();
if ($redis === false) {
return 'Redis not reachable.';
}
if ($id !== 'all') {
$params['conditions']['Server.id'] = $id;
} else {
$redis->del('misp:server_cache:combined');
$redis->del('misp:server_cache:event_uuid_lookup:');
}
$servers = $this->find('all', $params);
if ($jobId) {
$job = ClassRegistry::init('Job');
$job->id = $jobId;
if (!$job->exists()) {
$jobId = false;
}
}
foreach ($servers as $k => $server) {
$this->__cacheInstance($server, $redis, $jobId);
if ($jobId) {
$job->saveField('progress', 100 * $k / count($servers));
$job->saveField('message', 'Server ' . $server['Server']['id'] . ' cached.');
}
}
return true;
}
private function __cacheInstance($server, $redis, $jobId = false)
{
$continue = true;
$i = 0;
if ($jobId) {
$job = ClassRegistry::init('Job');
$job->id = $jobId;
}
$redis->del('misp:server_cache:' . $server['Server']['id']);
$HttpSocket = null;
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
while ($continue) {
$i++;
$pipe = $redis->multi(Redis::PIPELINE);
$chunk_size = 10000;
$data = $this->__getCachedAttributes($server, $HttpSocket, $chunk_size, $i);
if (empty($data) || count($data) < $chunk_size) {
return true;
}
foreach ($data as $entry) {
list($value, $uuid) = explode(',', $entry);
$redis->sAdd('misp:server_cache:' . $server['Server']['id'], $value);
$redis->sAdd('misp:server_cache:combined', $value);
$redis->sAdd('misp:server_cache:event_uuid_lookup:' . $value, $server['Server']['id'] . '/' . $uuid);
}
if ($jobId) {
$job->saveField('message', 'Server ' . $server['Server']['id'] . ': ' . $i * $chunk_size . ' attributes cached.');
}
$pipe->exec();
}
return true;
}
private function __getCachedAttributes($server, $HttpSocket, $chunk_size, $i)
{
$filter_rules = array(
'returnFormat' => 'cache',
'includeEventUuid',
'page' => $i,
'limit' => $chunk_size
);
$request = $this->setupSyncRequest($server);
try {
$response = $HttpSocket->post($server['Server']['url'] . '/attributes/restSearch.json', json_encode($filter_rules), $request);
} catch (SocketException $e) {
return $e->getMessage();
}
return $response->body;
}
}

View File

@ -3,6 +3,7 @@
<fieldset>
<legend><?php echo __('Add Server');?></legend>
<?php
echo '<h4 class="input clear">' . __('Instance identification') . '</h4>';
echo $this->Form->input('url', array(
'label' => __('Base URL'),
));
@ -25,8 +26,9 @@
endif;
?>
<div class="input clear" style="width:100%;">
<hr />
<p class="red"><?php echo __('Information about the organisation that will receive the events, typically the remote instance\'s host organisation.');?></p>
<hr />
<h4><?php echo __('Instance ownership and credentials'); ?></h4>
<p class="red"><?php echo __('Information about the organisation that will receive the events, typically the remote instance\'s host organisation.');?></p>
</div>
<div class = "input clear"></div>
<?php
@ -61,38 +63,25 @@
endif;
echo $this->Form->input('authkey', array(
));
?>
<div class = "input clear" style="width:100%;"><hr /></div>
<div class = "input clear"></div>
<?php
echo $this->Form->input('push', array(
));
echo $this->Form->input('pull', array(
));
?>
<div class = "input clear"></div>
<?php
echo '<div class = "input clear" style="width:100%;"><hr /></div>';
echo '<h4 class="input clear">' . __('Enabled synchronisation methods') . '</h4>';
echo $this->Form->input('push', array());
echo $this->Form->input('pull', array());
echo $this->Form->input('caching_enabled', array());
echo '<div class = "input clear" style="width:100%;"><hr /></div>';
echo $this->Form->input('unpublish_event', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('publish_without_email', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('self_signed', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('skip_proxy', array('type' => 'checkbox', 'label' => 'Skip proxy (if applicable)'));
echo $this->Form->input('Server.submitted_cert', array(
'label' => '<b>' . __('Server certificate file') . '</b>',
'type' => 'file',

View File

@ -3,6 +3,7 @@
<fieldset>
<legend><?php echo __('Edit Server');?></legend>
<?php
echo '<h4 class="input clear">' . __('Instance identification') . '</h4>';
echo $this->Form->input('url', array(
'label' => __('Base URL'),
));
@ -25,7 +26,12 @@
endif;
?>
<div class="input clear"></div>
<div class="input clear" style="width:100%;">
<hr />
<h4><?php echo __('Instance ownership and credentials'); ?></h4>
<p class="red"><?php echo __('Information about the organisation that will receive the events, typically the remote instance\'s host organisation.');?></p>
</div>
<div class = "input clear"></div>
<?php
echo $this->Form->input('organisation_type', array(
'label' => __('Organisation Type'),
@ -63,40 +69,29 @@
<label for="ServerExternalUuid"><?php echo __('Remote Organisation\'s Uuid');?></label>
<input type="text" id="ServerExternalUuid" <?php if (isset($this->request->data['Server']['external_uuid'])) echo 'value="' . $this->request->data['Server']['external_uuid'] . '"';?>>
</div>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('authkey', array(
'placeholder' => __('Leave empty to use current key')
));
?>
<div class = "input clear"></div>
<?php
echo $this->Form->input('push', array(
));
echo $this->Form->input('pull', array(
));
?>
<div class = "input clear"></div>
<?php
echo '<div class = "input clear" style="width:100%;"><hr /></div>';
echo '<h4 class="input clear">' . __('Enabled synchronisation methods') . '</h4>';
echo $this->Form->input('push', array());
echo $this->Form->input('pull', array());
echo $this->Form->input('caching_enabled', array());
echo '<div class = "input clear" style="width:100%;"><hr /><h4>' . __('Misc settings') . '</h4></div>';
echo $this->Form->input('unpublish_event', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('publish_without_email', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('self_signed', array(
'type' => 'checkbox',
));
?>
<div class = "input clear"></div>
<?php
echo '<div class="input clear"></div>';
echo $this->Form->input('skip_proxy', array('type' => 'checkbox', 'label' => 'Skip proxy (if applicable)'));
?>
<div class="clear">

View File

@ -24,6 +24,7 @@
<th><?php echo $this->Paginator->sort('internal');?></th>
<th><?php echo $this->Paginator->sort('push');?></th>
<th><?php echo $this->Paginator->sort('pull');?></th>
<th><?php echo $this->Paginator->sort('caching_enabled', 'Cache');?></th>
<th><?php echo $this->Paginator->sort('unpublish_event (push event)');?></th>
<th><?php echo $this->Paginator->sort('publish_without_email (pull event)');?></th>
<th><?php echo $this->Paginator->sort('url');?></th>
@ -71,7 +72,8 @@ foreach ($servers as $server):
<td id="connection_test_<?php echo $server['Server']['id'];?>"><span role="button" tabindex="0" aria-label="<?php echo __('Test the connection to the remote instance');?>" title="<?php echo __('Test the connection to the remote instance');?>" class="btn btn-primary" style="line-height:10px; padding: 4px 4px;" onClick="testConnection('<?php echo $server['Server']['id'];?>');"><?php echo __('Run');?></span></td>
<td><span class="<?php echo ($server['Server']['internal']? 'icon-ok' : 'icon-remove'); ?>" title="<?php echo ($server['Server']['internal']? __('Internal instance that ignores distribution level degradation *WARNING: Only use this setting if you have several internal instances and the sync link is to an internal extension of the current MISP community*') : __('Normal sync link to an external MISP instance. Distribution degradation will follow the normal rules.')); ?>"></span></td>
<td><span class="<?php echo ($server['Server']['push']? 'icon-ok' : 'icon-remove'); ?>"></span><span class="short <?php if (!$server['Server']['push'] || empty($ruleDescription['push'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['push']; ?>"> (<?php echo __('Rules');?>)</span></td>
<td><span class="<?php echo ($server['Server']['pull']? 'icon-ok' : 'icon-remove'); ?>"></span><span class="short <?php if (!$server['Server']['pull'] || empty($ruleDescription['pull'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['pull']; ?>"> (<?php echo __('Rules');?>)</span>
<td><span class="<?php echo ($server['Server']['pull']? 'icon-ok' : 'icon-remove'); ?>"></span><span class="short <?php if (!$server['Server']['pull'] || empty($ruleDescription['pull'])) echo "hidden"; ?>" data-toggle="popover" title="Distribution List" data-content="<?php echo $ruleDescription['pull']; ?>"> (<?php echo __('Rules');?>)</span></td>
<td><span class="<?php echo ($server['Server']['caching_enabled']? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td class="short"><span class="<?php echo ($server['Server']['unpublish_event'] ? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td class="short"><span class="<?php echo ($server['Server']['publish_without_email'] ? 'icon-ok' : 'icon-remove'); ?>"></span></td>
<td><?php echo h($server['Server']['url']); ?>&nbsp;</td>
@ -91,6 +93,9 @@ foreach ($servers as $server):
if ($server['Server']['push']) {
echo $this->Html->link('', array('action' => 'push', $server['Server']['id'], 'full'), array('class' => 'icon-upload', 'title' => __('Push all')));
}
if ($server['Server']['caching_enabled']) {
echo $this->Html->link('', array('action' => 'cache', $server['Server']['id']), array('class' => 'icon-download-alt', 'title' => __('Cache instance')));
}
?>
&nbsp;
<?php