Skip to content

Commit

Permalink
MemoryUsage: new Monitoring Rule Definition
Browse files Browse the repository at this point in the history
fixes #406
  • Loading branch information
Thomas-Gelf committed Sep 28, 2022
1 parent 934f6d6 commit 06880c2
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 4 deletions.
7 changes: 6 additions & 1 deletion application/clicommands/DaemonCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Icinga\Module\Vspheredb\Clicommands;

use gipfl\SimpleDaemon\Daemon;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceProcess;
use Icinga\Module\Vspheredb\Daemon\VsphereDbDaemon;

class DaemonCommand extends Command
Expand All @@ -20,7 +21,11 @@ public function runAction()
$this->assertNoVcenterParam();
$daemon = new Daemon();
$daemon->setLogger($this->logger);
$daemon->attachTask(new VsphereDbDaemon());
$vSphereDb = new VsphereDbDaemon();
$vSphereDb->on(RpcNamespaceProcess::ON_RESTART, function () use ($daemon) {
$daemon->reload();
});
$daemon->attachTask($vSphereDb);
$daemon->run($this->loop());
$this->eventuallyStartMainLoop();
}
Expand Down
11 changes: 10 additions & 1 deletion application/controllers/DaemonController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
use gipfl\Web\Widget\Hint;
use Icinga\Date\DateFormatter;
use Icinga\Module\Vspheredb\Web\Form\LogLevelForm;
use Icinga\Module\Vspheredb\Web\Form\RestartDaemonForm;
use Icinga\Module\Vspheredb\Web\Table\ControlSocketConnectionsTable;
use Icinga\Module\Vspheredb\Format;
use Icinga\Module\Vspheredb\Web\Controller;
use Icinga\Module\Vspheredb\Web\Table\VsphereApiConnectionTable;
use Icinga\Module\Vspheredb\Web\Tabs\MainTabs;
use Icinga\Module\Vspheredb\WebUtil;
use Icinga\Web\Notification;
use ipl\Html\Html;
use ipl\Html\Table;

Expand Down Expand Up @@ -70,7 +72,14 @@ protected function prepareDaemonInfo()
WebUtil::timeAgo($daemon->ts_last_refresh / 1000)
));
} else {
return $this->prepareProcessTable(JsonString::decode($daemon->process_info));
$restartForm = new RestartDaemonForm($this->remoteClient(), $this->loop());
$restartForm->on($restartForm::ON_SUCCESS, function () {
Notification::success('Daemon has been asked to restart');
$this->redirectNow($this->url());
});
$restartForm->handleRequest($this->getServerRequest());

return [$restartForm, $this->prepareProcessTable(JsonString::decode($daemon->process_info))];
}
} else {
return Hint::error($this->translate('Daemon is either not running or not connected to the Database'));
Expand Down
2 changes: 2 additions & 0 deletions doc/84-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ place.

### UI
* FEATURE: connection health icons now show more details (#400)
* FEATURE: the daemon can now be restarted from the web UI (#406)
* FIX: links pointing to the VMware HTML5 UI have now work on v6.7 and v7.x (#209)
* FIX: issues with dark/light mode in Icinga Web have been addressed (#355)
* FIX: Monitoring Rules documentation link was missing (#360)
Expand All @@ -26,6 +27,7 @@ place.
* FEATURE: now also Host Systems and Datastores have a Monitoring tab (#395)
* FEATURE: the UI now reflects all Check Command details (#398)
* FEATURE: improved Rule set naming (#402)
* FEATURE: it's now possible to define memory usage rules (#405)
* FIX: Monitoring Rule inheritance had some bugs (#363)
* FIX: Rules for different types on the same folder (DC only) conflicted (#365)

Expand Down
11 changes: 10 additions & 1 deletion library/Vspheredb/Daemon/RemoteApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Icinga\Module\Vspheredb\Daemon;

use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
use Exception;
use gipfl\Curl\CurlAsync;
use gipfl\Log\Logger;
Expand All @@ -12,6 +14,7 @@
use gipfl\Protocol\NetString\StreamWrapper;
use gipfl\Socket\UnixSocketInspection;
use gipfl\Socket\UnixSocketPeer;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceProcess;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceCurl;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceInfluxDb;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceLogger;
Expand All @@ -21,10 +24,13 @@
use Psr\Log\LoggerInterface;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface;
use React\Stream\Util;
use function posix_getegid;

class RemoteApi
class RemoteApi implements EventEmitterInterface
{
use EventEmitterTrait;

/** @var LoggerInterface */
protected $logger;

Expand Down Expand Up @@ -106,7 +112,10 @@ protected function addSocketEventHandlers(ControlSocket $socket)
return;
}

$rpcProcess = new RpcNamespaceProcess($this->loop);
Util::forwardEvents($rpcProcess, $this, [RpcNamespaceProcess::ON_RESTART]);
$handler = new NamespacedPacketHandler();
$handler->registerNamespace('process', $rpcProcess);
$handler->registerNamespace('system', new RpcNamespaceSystem());
$handler->registerNamespace('vsphere', new RpcNamespaceVsphere($this->apiConnectionHandler));
$handler->registerNamespace('influxdb', new RpcNamespaceInfluxDb($this->curl, $this->loop, $this->logger));
Expand Down
53 changes: 53 additions & 0 deletions library/Vspheredb/Daemon/RpcNamespace/RpcNamespaceProcess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Icinga\Module\Vspheredb\Daemon\RpcNamespace;

use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
use React\EventLoop\LoopInterface;

class RpcNamespaceProcess implements EventEmitterInterface
{
use EventEmitterTrait;

const ON_RESTART = 'restart';

/** @var LoopInterface */
protected $loop;

public function __construct(LoopInterface $loop)
{
$this->loop = $loop;
}

/*
public function infoRequest()
{
return $this->prepareProcessInfo($this->daemon);
}
protected function prepareProcessInfo(Daemon $daemon)
{
$details = $this->daemon->getProcessDetails()->getPropertiesToInsert();
$details['process_info'] = \json_decode($details['process_info']);
return (object) [
'state' => $this->daemon->getProcessState()->getInfo(),
'details' => (object) $details,
];
}
*/

/**
* @return bool
*/
public function restartRequest()
{
// Grant some time to ship the response
$this->loop->addTimer(0.1, function () {
$this->emit(self::ON_RESTART);
});

return true;
}
}
8 changes: 7 additions & 1 deletion library/Vspheredb/Daemon/VsphereDbDaemon.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Icinga\Module\Vspheredb\Daemon;

use Evenement\EventEmitterInterface;
use Evenement\EventEmitterTrait;
use Exception;
use gipfl\Cli\Process;
use gipfl\Curl\CurlAsync;
Expand All @@ -17,6 +19,7 @@
use Icinga\Data\ConfigObject;
use Icinga\Module\Vspheredb\Application\MemoryLimit;
use Icinga\Module\Vspheredb\Configuration;
use Icinga\Module\Vspheredb\Daemon\RpcNamespace\RpcNamespaceProcess;
use Icinga\Module\Vspheredb\Db;
use Icinga\Module\Vspheredb\Db\DbUtil;
use Icinga\Module\Vspheredb\DbObject\VCenter;
Expand All @@ -33,11 +36,13 @@
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use React\EventLoop\LoopInterface;
use React\Stream\Util as StreamUtil;
use RuntimeException;
use function React\Promise\resolve;

class VsphereDbDaemon implements DaemonTask, SystemdAwareTask, LoggerAwareInterface
class VsphereDbDaemon implements DaemonTask, SystemdAwareTask, LoggerAwareInterface, EventEmitterInterface
{
use EventEmitterTrait;
use LoggerAwareTrait;

const PROCESS_NAME = 'Icinga::vSphereDB';
Expand Down Expand Up @@ -419,6 +424,7 @@ protected function prepareApi(LoopInterface $loop, LoggerInterface $logger)
$this->curl = $curl;
$this->apiConnectionHandler = $connection = new ApiConnectionHandler($curl, $logger);
$this->remoteApi = new RemoteApi($connection, $curl, $loop, $logger);
StreamUtil::forwardEvents($this->remoteApi, $this, [RpcNamespaceProcess::ON_RESTART]);
$connection->on(
ApiConnectionHandler::ON_INITIALIZED_SERVER,
function (ServerInfo $server, AboutInfo $info, UuidInterface $uuid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Icinga\Module\Vspheredb\Monitoring\Rule\Definition;

use Icinga\Module\Vspheredb\DbObject\BaseDbObject;
use Icinga\Module\Vspheredb\Monitoring\Rule\Enum\ObjectType;

class ActiveMemoryUsageRuleDefinition extends MemoryUsageRuleDefinition
{
public const SUPPORTED_OBJECT_TYPES = [
ObjectType::VIRTUAL_MACHINE,
];

public static function getIdentifier(): string
{
return 'ActiveMemoryUsage';
}

public function getLabel(): string
{
return $this->translate('Active Memory Usage');
}

protected function getUsedMemory(BaseDbObject $quickStats)
{
return $quickStats->get('guest_memory_usage_mb') * MemoryUsageHelper::MEGA_BYTE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Icinga\Module\Vspheredb\Monitoring\Rule\Definition;

class ComputeResourceUsageRuleSet extends MonitoringRuleSetDefinition
{
public const RULE_CLASSES = [
MemoryUsageRuleDefinition::class,
ActiveMemoryUsageRuleDefinition::class,
];

public function getLabel(): string
{
return $this->translate('Compute Resource Usage');
}

public static function getIdentifier(): string
{
return 'ComputeResourceUsage';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Icinga\Module\Vspheredb\Monitoring\Rule\Definition;

use Icinga\Module\Vspheredb\DbObject\BaseDbObject;
use Icinga\Module\Vspheredb\DbObject\HostQuickStats;
use Icinga\Module\Vspheredb\DbObject\HostSystem;
use Icinga\Module\Vspheredb\DbObject\VirtualMachine;
use Icinga\Module\Vspheredb\DbObject\VmQuickStats;
use Icinga\Module\Vspheredb\Monitoring\Rule\Enum\ObjectType;
use Icinga\Module\Vspheredb\Monitoring\Rule\Settings;

class MemoryUsageRuleDefinition extends MonitoringRuleDefinition
{
public const SUPPORTED_OBJECT_TYPES = [
ObjectType::HOST_SYSTEM,
ObjectType::VIRTUAL_MACHINE,
];

public static function getIdentifier(): string
{
return 'MemoryUsage';
}

public function getLabel(): string
{
return $this->translate('Memory Usage');
}

public function getInternalDefaults(): array
{
return [
'threshold_precedence' => 'best_wins'
];
}

protected function getUsedMemory(BaseDbObject $quickStats)
{
if ($quickStats instanceof VmQuickStats) {
return $quickStats->get('host_memory_usage_mb') * MemoryUsageHelper::MEGA_BYTE;
}

return $quickStats->get('overall_memory_usage_mb') * MemoryUsageHelper::MEGA_BYTE;
}

public function checkObject(BaseDbObject $object, Settings $settings): array
{
$this->assertSupportedObject($object);
if ($object instanceof HostSystem) {
$quickStats = HostQuickStats::loadFor($object);
$capacity = $object->get('hardware_memory_size_mb') * MemoryUsageHelper::MEGA_BYTE;
} elseif ($object instanceof VirtualMachine) {
$quickStats = VmQuickStats::loadFor($object);
$capacity = $object->get('hardware_memorymb') * MemoryUsageHelper::MEGA_BYTE;
} else {
throw new \InvalidArgumentException('Cannot load QuickStats for ' . get_class($object));
}
$used = $this->getUsedMemory($quickStats);
$free = $capacity - $used;
return [
MemoryUsageHelper::prepareState($settings, $free, $capacity)
];
}

public function getParameters(): array
{
return MemoryUsageHelper::getParameters();
}
}
44 changes: 44 additions & 0 deletions library/Vspheredb/Web/Form/RestartDaemonForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Icinga\Module\Vspheredb\Web\Form;

use gipfl\IcingaWeb2\Icon;
use gipfl\Translation\TranslationHelper;
use gipfl\Web\Form\Feature\NextConfirmCancel;
use gipfl\Web\InlineForm;
use Icinga\Module\Vspheredb\Daemon\RemoteClient;
use React\EventLoop\LoopInterface;
use function Clue\React\Block\await;

class RestartDaemonForm extends InlineForm
{
use TranslationHelper;

/** @var RemoteClient */
protected $client;

/** @var LoopInterface */
protected $loop;

public function __construct(RemoteClient $client, LoopInterface $loop)
{
$this->client = $client;
$this->loop = $loop;
}

protected function assemble()
{
(new NextConfirmCancel(
NextConfirmCancel::buttonNext($this->translate('Restart'), [
'title' => $this->translate('Click to restart the vSphereDB background daemon'),
]),
NextConfirmCancel::buttonConfirm($this->translate('Yes, please restart')),
NextConfirmCancel::buttonCancel($this->translate('Cancel'))
))->addToForm($this);
}

protected function onSuccess()
{
await($this->client->request('process.restart'), $this->loop);
}
}

0 comments on commit 06880c2

Please sign in to comment.