summaryrefslogtreecommitdiffstats
path: root/library/Director/Objects/IcingaHost.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/Director/Objects/IcingaHost.php')
-rw-r--r--library/Director/Objects/IcingaHost.php668
1 files changed, 668 insertions, 0 deletions
diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php
new file mode 100644
index 0000000..2731f4a
--- /dev/null
+++ b/library/Director/Objects/IcingaHost.php
@@ -0,0 +1,668 @@
+<?php
+
+namespace Icinga\Module\Director\Objects;
+
+use Icinga\Data\Db\DbConnection;
+use Icinga\Exception\NotFoundError;
+use Icinga\Module\Director\Data\PropertiesFilter;
+use Icinga\Module\Director\Db;
+use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
+use Icinga\Module\Director\Exception\DuplicateKeyException;
+use Icinga\Module\Director\IcingaConfig\IcingaConfig;
+use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
+use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
+use Icinga\Module\Director\Objects\Extension\FlappingSupport;
+use InvalidArgumentException;
+use RuntimeException;
+
+class IcingaHost extends IcingaObject implements ExportInterface
+{
+ use FlappingSupport;
+
+ protected $table = 'icinga_host';
+
+ protected $defaultProperties = array(
+ 'id' => null,
+ 'uuid' => null,
+ 'object_name' => null,
+ 'object_type' => null,
+ 'disabled' => 'n',
+ 'display_name' => null,
+ 'address' => null,
+ 'address6' => null,
+ 'check_command_id' => null,
+ 'max_check_attempts' => null,
+ 'check_period_id' => null,
+ 'check_interval' => null,
+ 'retry_interval' => null,
+ 'check_timeout' => null,
+ 'enable_notifications' => null,
+ 'enable_active_checks' => null,
+ 'enable_passive_checks' => null,
+ 'enable_event_handler' => null,
+ 'enable_flapping' => null,
+ 'enable_perfdata' => null,
+ 'event_command_id' => null,
+ 'flapping_threshold_high' => null,
+ 'flapping_threshold_low' => null,
+ 'volatile' => null,
+ 'zone_id' => null,
+ 'command_endpoint_id' => null,
+ 'notes' => null,
+ 'notes_url' => null,
+ 'action_url' => null,
+ 'icon_image' => null,
+ 'icon_image_alt' => null,
+ 'has_agent' => null,
+ 'master_should_connect' => null,
+ 'accept_config' => null,
+ 'custom_endpoint_name' => null,
+ 'api_key' => null,
+ 'template_choice_id' => null,
+ );
+
+ protected $relations = array(
+ 'check_command' => 'IcingaCommand',
+ 'event_command' => 'IcingaCommand',
+ 'check_period' => 'IcingaTimePeriod',
+ 'command_endpoint' => 'IcingaEndpoint',
+ 'zone' => 'IcingaZone',
+ 'template_choice' => 'IcingaTemplateChoiceHost',
+ );
+
+ protected $booleans = array(
+ 'enable_notifications' => 'enable_notifications',
+ 'enable_active_checks' => 'enable_active_checks',
+ 'enable_passive_checks' => 'enable_passive_checks',
+ 'enable_event_handler' => 'enable_event_handler',
+ 'enable_flapping' => 'enable_flapping',
+ 'enable_perfdata' => 'enable_perfdata',
+ 'volatile' => 'volatile',
+ 'has_agent' => 'has_agent',
+ 'master_should_connect' => 'master_should_connect',
+ 'accept_config' => 'accept_config',
+ );
+
+ protected $intervalProperties = array(
+ 'check_interval' => 'check_interval',
+ 'check_timeout' => 'check_timeout',
+ 'retry_interval' => 'retry_interval',
+ );
+
+ protected $supportsCustomVars = true;
+
+ protected $supportsGroups = true;
+
+ protected $supportsImports = true;
+
+ protected $supportsFields = true;
+
+ protected $supportsChoices = true;
+
+ protected $supportedInLegacy = true;
+
+ /** @var HostGroupMembershipResolver */
+ protected $hostgroupMembershipResolver;
+
+ protected $uuidColumn = 'uuid';
+
+ public static function enumProperties(
+ DbConnection $connection = null,
+ $prefix = '',
+ $filter = null
+ ) {
+ $hostProperties = array();
+ if ($filter === null) {
+ $filter = new PropertiesFilter();
+ }
+ $realProperties = array_merge(['templates'], static::create()->listProperties());
+ sort($realProperties);
+
+ if ($filter->match(PropertiesFilter::$HOST_PROPERTY, 'name')) {
+ $hostProperties[$prefix . 'name'] = 'name';
+ }
+ foreach ($realProperties as $prop) {
+ if (!$filter->match(PropertiesFilter::$HOST_PROPERTY, $prop)) {
+ continue;
+ }
+
+ if (substr($prop, -3) === '_id') {
+ if ($prop === 'template_choice_id') {
+ continue;
+ }
+ $prop = substr($prop, 0, -3);
+ }
+
+ $hostProperties[$prefix . $prop] = $prop;
+ }
+ unset($hostProperties[$prefix . 'uuid']);
+ unset($hostProperties[$prefix . 'custom_endpoint_name']);
+
+ $hostVars = array();
+
+ if ($connection instanceof Db) {
+ foreach ($connection->fetchDistinctHostVars() as $var) {
+ if ($filter->match(PropertiesFilter::$CUSTOM_PROPERTY, $var->varname, $var)) {
+ if ($var->datatype) {
+ $hostVars[$prefix . 'vars.' . $var->varname] = sprintf(
+ '%s (%s)',
+ $var->varname,
+ $var->caption
+ );
+ } else {
+ $hostVars[$prefix . 'vars.' . $var->varname] = $var->varname;
+ }
+ }
+ }
+ }
+
+ //$properties['vars.*'] = 'Other custom variable';
+ ksort($hostVars);
+
+
+ $props = mt('director', 'Host properties');
+ $vars = mt('director', 'Custom variables');
+
+ $properties = array();
+ if (!empty($hostProperties)) {
+ $properties[$props] = $hostProperties;
+ $properties[$props][$prefix . 'groups'] = 'Groups';
+ }
+
+ if (!empty($hostVars)) {
+ $properties[$vars] = $hostVars;
+ }
+
+ return $properties;
+ }
+
+ public function getCheckCommand()
+ {
+ $id = $this->getSingleResolvedProperty('check_command_id');
+ return IcingaCommand::loadWithAutoIncId(
+ $id,
+ $this->getConnection()
+ );
+ }
+
+ public function hasCheckCommand()
+ {
+ return $this->getSingleResolvedProperty('check_command_id') !== null;
+ }
+
+ public function renderToConfig(IcingaConfig $config)
+ {
+ parent::renderToConfig($config);
+
+ // TODO: We might alternatively let the whole config fail in case we have
+ // used use_agent together with a legacy config
+ if (! $config->isLegacy()) {
+ $this->renderAgentZoneAndEndpoint($config);
+ }
+ }
+
+ public function renderAgentZoneAndEndpoint(IcingaConfig $config = null)
+ {
+ if (!$this->isObject()) {
+ return;
+ }
+
+ if ($this->isDisabled()) {
+ return;
+ }
+
+ if ($this->getRenderingZone($config) === self::RESOLVE_ERROR) {
+ return;
+ }
+
+ if ($this->getSingleResolvedProperty('has_agent') !== 'y') {
+ return;
+ }
+
+ $name = $this->getEndpointName();
+
+ if (IcingaEndpoint::exists($name, $this->connection)) {
+ return;
+ }
+
+ $props = array(
+ 'object_name' => $name,
+ 'object_type' => 'object',
+ 'log_duration' => 0
+ );
+
+ if ($this->getSingleResolvedProperty('master_should_connect') === 'y') {
+ $props['host'] = $this->getSingleResolvedProperty('address');
+ }
+
+ $props['zone_id'] = $this->getSingleResolvedProperty('zone_id');
+
+ $endpoint = IcingaEndpoint::create($props, $this->connection);
+
+ $zone = IcingaZone::create(array(
+ 'object_name' => $name,
+ ), $this->connection)->setEndpointList(array($name));
+
+ if ($props['zone_id']) {
+ $zone->parent_id = $props['zone_id'];
+ } else {
+ $zone->parent = $this->connection->getMasterZoneName();
+ }
+
+ $pre = 'zones.d/' . $this->getRenderingZone($config) . '/';
+ $config->configFile($pre . 'agent_endpoints')->addObject($endpoint);
+ $config->configFile($pre . 'agent_zones')->addObject($zone);
+ }
+
+ /**
+ // @codingStandardsIgnoreStart
+ * @param $value
+ * @return string
+ */
+ protected function renderCustom_endpoint_name($value)
+ {
+ // @codingStandardsIgnoreEnd
+ // When feature flag feature_custom_endpoint is enabled, render custom var
+ if ($this->connection->settings()->get('feature_custom_endpoint') === 'y') {
+ return c::renderKeyValue('vars._director_custom_endpoint_name', c::renderString($value));
+ }
+
+ return '';
+ }
+
+ /**
+ * Returns the hostname or custom endpoint name of the Icinga agent
+ *
+ * @return string
+ */
+ public function getEndpointName()
+ {
+ $name = $this->getObjectName();
+
+ if ($this->connection->settings()->get('feature_custom_endpoint') === 'y') {
+ if (($customName = $this->get('custom_endpoint_name')) !== null) {
+ $name = $customName;
+ }
+ }
+
+ return $name;
+ }
+
+ public function getAgentListenPort()
+ {
+ $conn = $this->connection;
+ $name = $this->getObjectName();
+ if (IcingaEndpoint::exists($name, $conn)) {
+ return IcingaEndpoint::load($name, $conn)->getResolvedPort();
+ } else {
+ return 5665;
+ }
+ }
+
+ public function getUniqueIdentifier()
+ {
+ if ($this->isTemplate()) {
+ return $this->getObjectName();
+ } else {
+ throw new RuntimeException(
+ 'getUniqueIdentifier() is supported by Host Templates only'
+ );
+ }
+ }
+
+ /**
+ * @return object
+ * @deprecated please use \Icinga\Module\Director\Data\Exporter
+ * @throws \Icinga\Exception\NotFoundError
+ */
+ public function export()
+ {
+ // TODO: ksort in toPlainObject?
+ $props = (array) $this->toPlainObject();
+ $props['fields'] = $this->loadFieldReferences();
+ ksort($props);
+
+ return (object) $props;
+ }
+
+ /**
+ * @param $plain
+ * @param Db $db
+ * @param bool $replace
+ * @return IcingaHost
+ * @throws DuplicateKeyException
+ * @throws \Icinga\Exception\NotFoundError
+ */
+ public static function import($plain, Db $db, $replace = false)
+ {
+ $properties = (array) $plain;
+ $name = $properties['object_name'];
+ if ($properties['object_type'] !== 'template') {
+ throw new InvalidArgumentException(sprintf(
+ 'Can import only Templates, got "%s" for "%s"',
+ $properties['object_type'],
+ $name
+ ));
+ }
+ $key = $name;
+
+ if ($replace && static::exists($key, $db)) {
+ $object = static::load($key, $db);
+ } elseif (static::exists($key, $db)) {
+ throw new DuplicateKeyException(
+ 'Service Template "%s" already exists',
+ $name
+ );
+ } else {
+ $object = static::create([], $db);
+ }
+
+ // $object->newFields = $properties['fields'];
+ 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([
+ 'hf' => 'icinga_host_field'
+ ], [
+ 'hf.datafield_id',
+ 'hf.is_required',
+ 'hf.var_filter',
+ ])->join(['df' => 'director_datafield'], 'df.id = hf.datafield_id', [])
+ ->where('host_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;
+ }
+ }
+
+ public function beforeDelete()
+ {
+ foreach ($this->fetchServices() as $service) {
+ $service->delete();
+ }
+ foreach ($this->fetchServiceSets() as $set) {
+ $set->delete();
+ }
+
+ parent::beforeDelete();
+ }
+
+ public function hasAnyOverridenServiceVars()
+ {
+ $varname = $this->getServiceOverrivesVarname();
+ return isset($this->vars()->$varname);
+ }
+
+ public function getAllOverriddenServiceVars()
+ {
+ if ($this->hasAnyOverridenServiceVars()) {
+ $varname = $this->getServiceOverrivesVarname();
+ return $this->vars()->$varname->getValue();
+ } else {
+ return (object) array();
+ }
+ }
+
+ public function hasOverriddenServiceVars($service)
+ {
+ $all = $this->getAllOverriddenServiceVars();
+ return property_exists($all, $service);
+ }
+
+ public function getOverriddenServiceVars($service)
+ {
+ if ($this->hasOverriddenServiceVars($service)) {
+ $all = $this->getAllOverriddenServiceVars();
+ return $all->$service;
+ } else {
+ return (object) array();
+ }
+ }
+
+ public function overrideServiceVars($service, $vars)
+ {
+ // For PHP < 5.5.0:
+ $array = (array) $vars;
+ if (empty($array)) {
+ return $this->unsetOverriddenServiceVars($service);
+ }
+
+ $all = $this->getAllOverriddenServiceVars();
+ $all->$service = $vars;
+ $varname = $this->getServiceOverrivesVarname();
+ $this->vars()->$varname = $all;
+
+ return $this;
+ }
+
+ public function unsetOverriddenServiceVars($service)
+ {
+ if ($this->hasOverriddenServiceVars($service)) {
+ $all = (array) $this->getAllOverriddenServiceVars();
+ unset($all[$service]);
+
+ $varname = $this->getServiceOverrivesVarname();
+ if (empty($all)) {
+ unset($this->vars()->$varname);
+ } else {
+ $this->vars()->$varname = (object) $all;
+ }
+ }
+
+ return $this;
+ }
+
+ protected function notifyResolvers()
+ {
+ $resolver = $this->getHostGroupMembershipResolver();
+ $resolver->addObject($this);
+ $resolver->refreshDb();
+
+ return $this;
+ }
+
+ protected function getHostGroupMembershipResolver()
+ {
+ if ($this->hostgroupMembershipResolver === null) {
+ $this->hostgroupMembershipResolver = new HostGroupMembershipResolver(
+ $this->getConnection()
+ );
+ }
+
+ return $this->hostgroupMembershipResolver;
+ }
+
+ public function setHostGroupMembershipResolver(HostGroupMembershipResolver $resolver)
+ {
+ $this->hostgroupMembershipResolver = $resolver;
+ return $this;
+ }
+
+ protected function getServiceOverrivesVarname()
+ {
+ return $this->connection->settings()->override_services_varname;
+ }
+
+ /**
+ * Internal property, will not be rendered
+ *
+ * Avoid complaints for method names with underscore:
+ * @codingStandardsIgnoreStart
+ *
+ * @return string
+ */
+ protected function renderHas_Agent()
+ {
+ return '';
+ }
+
+ /**
+ * Internal property, will not be rendered
+ *
+ * @return string
+ */
+ protected function renderMaster_should_connect()
+ {
+ return '';
+ }
+
+ /**
+ * Internal property, will not be rendered
+ *
+ * @return string
+ */
+ protected function renderApi_key()
+ {
+ return '';
+ }
+
+ /**
+ * Internal property, will not be rendered
+ *
+ * @return string
+ */
+ protected function renderTemplate_choice_id()
+ {
+ return '';
+ }
+
+ /**
+ * Internal property, will not be rendered
+ *
+ * @return string
+ */
+ protected function renderAccept_config()
+ {
+ // @codingStandardsIgnoreEnd
+ return '';
+ }
+
+ /**
+ * @codingStandardsIgnoreStart
+ *
+ * @return string
+ */
+ protected function renderLegacyDisplay_Name()
+ {
+ // @codingStandardsIgnoreEnd
+ return c1::renderKeyValue('display_name', $this->display_name);
+ }
+
+ protected function renderLegacyVolatile()
+ {
+ // not available for hosts in Icinga 1.x
+ return;
+ }
+
+ protected function renderLegacyCustomExtensions()
+ {
+ $str = parent::renderLegacyCustomExtensions();
+
+ if (($alias = $this->vars()->get('alias')) !== null) {
+ $str .= c1::renderKeyValue('alias', $alias->getValue());
+ }
+
+ return $str;
+ }
+
+ /**
+ * @return IcingaService[]
+ */
+ public function fetchServices()
+ {
+ $connection = $this->getConnection();
+ $db = $connection->getDbAdapter();
+
+ /** @var IcingaService[] $services */
+ $services = IcingaService::loadAll(
+ $connection,
+ $db->select()->from('icinga_service')
+ ->where('host_id = ?', $this->get('id'))
+ );
+
+ return $services;
+ }
+
+ /**
+ * @return IcingaServiceSet[]
+ */
+ public function fetchServiceSets()
+ {
+ $connection = $this->getConnection();
+ $db = $connection->getDbAdapter();
+
+ /** @var IcingaServiceSet[] $sets */
+ $sets = IcingaServiceSet::loadAll(
+ $connection,
+ $db->select()->from('icinga_service_set')
+ ->where('host_id = ?', $this->get('id'))
+ );
+
+ return $sets;
+ }
+
+ /**
+ * @return string
+ */
+ public function generateApiKey()
+ {
+ $key = sha1(
+ (string) microtime(false)
+ . $this->getObjectName()
+ . rand(1, 1000000)
+ );
+
+ if ($this->dbHasApiKey($key)) {
+ $key = $this->generateApiKey();
+ }
+
+ $this->set('api_key', $key);
+
+ return $key;
+ }
+
+ protected function dbHasApiKey($key)
+ {
+ $db = $this->getDb();
+ $query = $db->select()->from(
+ ['o' => $this->getTableName()],
+ 'o.api_key'
+ )->where('api_key = ?', $key);
+
+ return $db->fetchOne($query) === $key;
+ }
+
+ public static function loadWithApiKey($key, Db $db)
+ {
+ $query = $db->getDbAdapter()
+ ->select()
+ ->from('icinga_host')
+ ->where('api_key = ?', $key);
+
+ $result = self::loadAll($db, $query);
+ if (count($result) !== 1) {
+ throw new NotFoundError('Got invalid API key "%s"', $key);
+ }
+
+ return current($result);
+ }
+}