summaryrefslogtreecommitdiffstats
path: root/library/Director/Objects/IcingaCommand.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Objects/IcingaCommand.php')
-rw-r--r--library/Director/Objects/IcingaCommand.php365
1 files changed, 365 insertions, 0 deletions
diff --git a/library/Director/Objects/IcingaCommand.php b/library/Director/Objects/IcingaCommand.php
new file mode 100644
index 0000000..35f38a4
--- /dev/null
+++ b/library/Director/Objects/IcingaCommand.php
@@ -0,0 +1,365 @@
+<?php
+
+namespace Icinga\Module\Director\Objects;
+
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
+use Icinga\Module\Director\Exception\DuplicateKeyException;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
+use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
+use Icinga\Module\Director\Objects\Extension\Arguments;
+use Zend_Db_Select as DbSelect;
+
+class IcingaCommand extends IcingaObject implements ObjectWithArguments, ExportInterface
+{
+ use Arguments;
+
+ protected $table = 'icinga_command';
+
+ protected $type = 'CheckCommand';
+
+ protected $uuidColumn = 'uuid';
+
+ protected $defaultProperties = [
+ 'id' => null,
+ 'uuid' => null,
+ 'object_name' => null,
+ 'object_type' => null,
+ 'disabled' => 'n',
+ 'methods_execute' => null,
+ 'command' => null,
+ 'timeout' => null,
+ 'zone_id' => null,
+ 'is_string' => null,
+ ];
+
+ protected $booleans = [
+ 'is_string' => 'is_string',
+ ];
+
+ protected $supportsCustomVars = true;
+
+ protected $supportsFields = true;
+
+ protected $supportsImports = true;
+
+ protected $supportedInLegacy = true;
+
+ protected $intervalProperties = [
+ 'timeout' => 'timeout',
+ ];
+
+ protected $relations = [
+ 'zone' => 'IcingaZone',
+ ];
+
+ protected static $pluginDir;
+
+ protected $hiddenExecuteTemplates = [
+ 'PluginCheck' => 'plugin-check-command',
+ 'PluginNotification' => 'plugin-notification-command',
+ 'PluginEvent' => 'plugin-event-command',
+
+ // Special, internal:
+ 'IcingaCheck' => 'icinga-check-command',
+ 'ClusterCheck' => 'cluster-check-command',
+ 'ClusterZoneCheck' => 'plugin-check-command',
+ 'IdoCheck' => 'ido-check-command',
+ 'RandomCheck' => 'random-check-command',
+ ];
+
+ /**
+ * Render the 'medhods_execute' property as 'execute'
+ *
+ * Execute is a reserved word in SQL, column name was prefixed
+ *
+ * Avoid complaints for method names with underscore:
+ * @codingStandardsIgnoreStart
+ *
+ * @return string
+ */
+ protected function renderMethods_execute()
+ {
+ // @codingStandardsIgnoreEnd
+ return '';
+ }
+
+ protected function renderObjectHeader()
+ {
+ if ($execute = $this->get('methods_execute')) {
+ $itlImport = sprintf(
+ ' import "%s"' . "\n",
+ $this->hiddenExecuteTemplates[$execute]
+ );
+ } else {
+ $itlImport = '';
+ }
+
+ $execute = $this->getSingleResolvedProperty('methods_execute');
+ if ($execute === 'PluginNotification') {
+ return $this->renderObjectHeaderWithType('NotificationCommand') . $itlImport;
+ } elseif ($execute === 'PluginEvent') {
+ return $this->renderObjectHeaderWithType('EventCommand') . $itlImport;
+ } else {
+ return parent::renderObjectHeader() . $itlImport;
+ }
+ }
+
+ /**
+ * @param $type
+ * @return string
+ */
+ protected function renderObjectHeaderWithType($type)
+ {
+ return sprintf(
+ "%s %s %s {\n",
+ $this->getObjectTypeName(),
+ $type,
+ c::renderString($this->getObjectName())
+ );
+ }
+
+ public function mungeCommand($value)
+ {
+ if (is_array($value)) {
+ $value = implode(' ', $value);
+ } elseif (is_object($value)) {
+ // { type => Function } -> really??
+ return null;
+ // return $value;
+ }
+
+ if (self::$pluginDir !== null) {
+ if (($pos = strpos($value, self::$pluginDir)) === 0) {
+ $value = substr($value, strlen(self::$pluginDir) + 1);
+ }
+ }
+
+ return $value;
+ }
+
+ public function getNextSkippableKeyName()
+ {
+ $key = $this->makeSkipKey();
+ $cnt = 1;
+ while (isset($this->arguments()->$key)) {
+ $cnt++;
+ $key = $this->makeSkipKey($cnt);
+ }
+
+ return $key;
+ }
+
+ protected function makeSkipKey($num = null)
+ {
+ if ($num === null) {
+ return '(no key)';
+ }
+
+ return sprintf('(no key.%d)', $num);
+ }
+
+ protected function prefersGlobalZone()
+ {
+ return true;
+ }
+
+ /**
+ * @return string
+ * @throws \Zend_Db_Select_Exception
+ */
+ public function countDirectUses()
+ {
+ $db = $this->getDb();
+ $id = (int) $this->get('id');
+
+ $qh = $db->select()->from(
+ array('h' => 'icinga_host'),
+ array('cnt' => 'COUNT(*)')
+ )->where('h.check_command_id = ?', $id)
+ ->orWhere('h.event_command_id = ?', $id);
+ $qs = $db->select()->from(
+ array('s' => 'icinga_service'),
+ array('cnt' => 'COUNT(*)')
+ )->where('s.check_command_id = ?', $id)
+ ->orWhere('s.event_command_id = ?', $id);
+ $qn = $db->select()->from(
+ array('n' => 'icinga_notification'),
+ array('cnt' => 'COUNT(*)')
+ )->where('n.command_id = ?', $id);
+ $query = $db->select()->union(
+ [$qh, $qs, $qn],
+ DbSelect::SQL_UNION_ALL
+ );
+
+ return $db->fetchOne($db->select()->from(
+ ['all_cnts' => $query],
+ ['cnt' => 'SUM(cnt)']
+ ));
+ }
+
+ /**
+ * @return bool
+ * @throws \Zend_Db_Select_Exception
+ */
+ public function isInUse()
+ {
+ return $this->countDirectUses() > 0;
+ }
+
+ public function getUniqueIdentifier()
+ {
+ return $this->getObjectName();
+ }
+
+ /**
+ * @return object
+ * @deprecated please use \Icinga\Module\Director\Data\Exporter
+ * @throws \Icinga\Exception\NotFoundError
+ */
+ public function export()
+ {
+ $props = (array) $this->toPlainObject();
+ if (isset($props['arguments'])) {
+ foreach ($props['arguments'] as $key => $argument) {
+ if (property_exists($argument, 'command_id')) {
+ unset($props['arguments'][$key]->command_id);
+ }
+ }
+ }
+ $props['fields'] = $this->loadFieldReferences();
+ ksort($props);
+
+ return (object) $props;
+ }
+
+ /**
+ * @param $plain
+ * @param Db $db
+ * @param bool $replace
+ * @return IcingaCommand
+ * @throws DuplicateKeyException
+ * @throws \Icinga\Exception\NotFoundError
+ */
+ public static function import($plain, Db $db, $replace = false)
+ {
+ $properties = (array) $plain;
+ $name = $properties['object_name'];
+ $key = $name;
+
+ if ($replace && static::exists($key, $db)) {
+ $object = static::load($key, $db);
+ } elseif (static::exists($key, $db)) {
+ throw new DuplicateKeyException(
+ 'Command "%s" already exists',
+ $name
+ );
+ } else {
+ $object = static::create([], $db);
+ }
+
+ unset($properties['fields']);
+ $object->setProperties($properties);
+
+ return $object;
+ }
+
+ /**
+ * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader
+ * @return array
+ */
+ protected function loadFieldReferences()
+ {
+ $db = $this->getDb();
+
+ $res = $db->fetchAll(
+ $db->select()->from([
+ 'cf' => 'icinga_command_field'
+ ], [
+ 'cf.datafield_id',
+ 'cf.is_required',
+ 'cf.var_filter',
+ ])->join(['df' => 'director_datafield'], 'df.id = cf.datafield_id', [])
+ ->where('command_id = ?', $this->get('id'))
+ ->order('varname ASC')
+ );
+
+ if (empty($res)) {
+ return [];
+ } else {
+ foreach ($res as $field) {
+ $field->datafield_id = (int) $field->datafield_id;
+ }
+
+ return $res;
+ }
+ }
+
+ protected function renderCommand()
+ {
+ $command = $this->get('command');
+ $prefix = '';
+ if (preg_match('~^([A-Z][A-Za-z0-9_]+\s\+\s)(.+?)$~', $command, $m)) {
+ $prefix = $m[1];
+ $command = $m[2];
+ } elseif (! $this->isAbsolutePath($command)) {
+ $prefix = 'PluginDir + ';
+ $command = '/' . $command;
+ }
+
+ $inherited = $this->getInheritedProperties();
+
+ if ($this->get('is_string') === 'y' || ($this->get('is_string') === null
+ && property_exists($inherited, 'is_string') && $inherited->is_string === 'y')) {
+ return c::renderKeyValue('command', $prefix . c::renderString($command));
+ } else {
+ $parts = preg_split('/\s+/', $command, -1, PREG_SPLIT_NO_EMPTY);
+ array_unshift($parts, c::alreadyRendered($prefix . c::renderString(array_shift($parts))));
+
+ return c::renderKeyValue('command', c::renderArray($parts));
+ }
+ }
+
+ /**
+ * @codingStandardsIgnoreStart
+ */
+ protected function renderIs_string()
+ {
+ // @codingStandardsIgnoreEnd
+ return '';
+ }
+
+ protected function isAbsolutePath($path)
+ {
+ return $path[0] === '/'
+ || $path[0] === '\\'
+ || preg_match('/^[A-Za-z]:\\\/', substr($path, 0, 3))
+ || preg_match('/^%[A-Z][A-Za-z0-9\(\)-]*%/', $path);
+ }
+
+ public static function setPluginDir($pluginDir)
+ {
+ self::$pluginDir = $pluginDir;
+ }
+
+ public function getLegacyObjectType()
+ {
+ // there is only one type of command in Icinga 1.x
+ return 'command';
+ }
+
+ protected function renderLegacyCommand()
+ {
+ $command = $this->get('command');
+ if (preg_match('~^(\$USER\d+\$/?)(.+)$~', $command)) {
+ // should be fine, since the user decided to use a macro
+ } elseif (! $this->isAbsolutePath($command)) {
+ $command = '$USER1$/'.$command;
+ }
+
+ return c1::renderKeyValue(
+ $this->getLegacyObjectType().'_line',
+ c1::renderString($command)
+ );
+ }
+}