icingaweb2-module-director/application/controllers/SuggestController.php

416 lines
13 KiB
PHP

<?php
namespace Icinga\Module\Director\Controllers;
use Icinga\Module\Director\Restriction\HostgroupRestriction;
use ipl\Html\Html;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Hook\ImportSourceHook;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Objects\ImportSource;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Objects\HostApplyMatches;
class SuggestController extends ActionController
{
protected function checkDirectorPermissions()
{
}
public function indexAction()
{
// TODO: Using some temporarily hardcoded methods, should use DataViews later on
$context = $this->getRequest()->getPost('context');
$key = null;
if (strpos($context, '!') !== false) {
list($context, $key) = preg_split('~!~', $context, 2);
}
$func = 'suggest' . ucfirst($context);
if (method_exists($this, $func)) {
if (! empty($key)) {
$all = $this->$func($key);
} else {
$all = $this->$func();
}
} else {
$all = array();
}
// TODO: also get cursor position and eventually add an asterisk in the middle
// tODO: filter also when fetching, eventually limit somehow
$search = $this->getRequest()->getPost('value');
$begins = array();
$matches = array();
$begin = Filter::expression('value', '=', $search . '*');
$middle = Filter::expression('value', '=', '*' . $search . '*')->setCaseSensitive(false);
$prefixes = array();
foreach ($all as $str) {
if (false !== ($pos = strrpos($str, '.'))) {
$prefix = substr($str, 0, $pos) . '.';
$prefixes[$prefix] = $prefix;
}
if (strlen($search)) {
$row = (object) array('value' => $str);
if ($begin->matches($row)) {
$begins[] = $this->highlight($str, $search);
} elseif ($middle->matches($row)) {
$matches[] = $this->highlight($str, $search);
}
} else {
$matches[] = Html::escape($str);
}
}
$containing = array_slice(array_merge($begins, $matches), 0, 100);
$suggestions = $containing;
if ($func === 'suggestHostFilterColumns' || $func === 'suggestHostaddresses') {
ksort($prefixes);
if (count($suggestions) < 5) {
$suggestions = array_merge($suggestions, array_keys($prefixes));
}
}
$this->view->suggestions = $suggestions;
}
/**
* One more dummy helper for tests
*
* TODO: Should not remain here
*
* @return array
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Security\SecurityException
*/
protected function suggestLocations()
{
$this->assertPermission('director/hosts');
$db = $this->db()->getDbAdapter();
$query = $db->select()
->distinct()
->from('icinga_host_var', 'varvalue')
->where('varname = ?', 'location')
->order('varvalue');
return $db->fetchCol($query);
}
protected function suggestHostnames($type = 'object')
{
$this->assertPermission('director/hosts');
$db = $this->db()->getDbAdapter();
$query = $db->select()
->from('icinga_host', 'object_name')
->order('object_name');
if ($type !== null) {
$query->where('object_type = ?', $type);
}
$restriction = new HostgroupRestriction($this->db(), $this->Auth());
$restriction->filterHostsQuery($query);
return $db->fetchCol($query);
}
protected function suggestHostsAndTemplates()
{
return $this->suggestHostnames(null);
}
protected function suggestServicenames()
{
$r = array();
$this->assertPermission('director/services');
$db = $this->db()->getDbAdapter();
$for_host = $this->getRequest()->getPost('for_host');
if (!empty($for_host)) {
$tmp_host = IcingaHost::load($for_host, $this->db());
}
$query = $db->select()->distinct()
->from('icinga_service', 'object_name')
->order('object_name')
->where("object_type IN ('object','apply')");
if (!empty($tmp_host)) {
$query->where('host_id = ?', $tmp_host->id);
}
$r = array_merge($r, $db->fetchCol($query));
if (!empty($tmp_host)) {
$resolver = $tmp_host->templateResolver();
foreach ($resolver->fetchResolvedParents() as $template_obj) {
$query = $db->select()->distinct()
->from('icinga_service', 'object_name')
->order('object_name')
->where("object_type IN ('object','apply')")
->where('host_id = ?', $template_obj->id);
$r = array_merge($r, $db->fetchCol($query));
}
$matcher = HostApplyMatches::prepare($tmp_host);
foreach ($this->getAllApplyRules() as $rule) {
if ($matcher->matchesFilter($rule->filter)) { //TODO
$r[] = $rule->name;
}
}
}
natcasesort($r);
return $r;
}
protected function suggestHosttemplates()
{
$this->assertPermission('director/hosts');
return $this->fetchTemplateNames('icinga_host', 'template_choice_id IS NULL');
}
protected function suggestServicetemplates()
{
$this->assertPermission('director/services');
return $this->fetchTemplateNames('icinga_service', 'template_choice_id IS NULL');
}
protected function suggestNotificationtemplates()
{
$this->assertPermission('director/notifications');
return $this->fetchTemplateNames('icinga_notification');
}
protected function suggestCommandtemplates()
{
$this->assertPermission('director/commands');
$db = $this->db()->getDbAdapter();
$query = $db->select()
->from('icinga_command', 'object_name')
->order('object_name');
return $db->fetchCol($query);
}
protected function suggestUsertemplates()
{
$this->assertPermission('director/users');
return $this->fetchTemplateNames('icinga_user');
}
/**
* @return array
* @throws \Icinga\Security\SecurityException
* @codingStandardsIgnoreStart
*/
protected function suggestScheduled_downtimetemplates()
{
// @codingStandardsIgnoreEnd
$this->assertPermission('director/scheduled-downtimes');
return $this->fetchTemplateNames('icinga_scheduled_downtime');
}
protected function suggestCheckcommandnames()
{
$db = $this->db()->getDbAdapter();
$query = $db->select()
->from('icinga_command', 'object_name')
->where('object_type != ?', 'template')
->order('object_name');
return $db->fetchCol($query);
}
protected function fetchTemplateNames($table, $where = null)
{
$db = $this->db()->getDbAdapter();
$query = $db->select()
->from($table, 'object_name')
->where('object_type = ?', 'template')
->order('object_name');
if ($where !== null) {
$query->where('template_choice_id IS NULL');
}
return $db->fetchCol($query);
}
protected function suggestHostgroupnames()
{
$db = $this->db()->getDbAdapter();
$query = $db->select()->from('icinga_hostgroup', 'object_name')->order('object_name');
return $db->fetchCol($query);
}
protected function suggestHostaddresses()
{
$db = $this->db()->getDbAdapter();
$query = $db->select()->from('icinga_host', 'address')->order('address');
return $db->fetchCol($query);
}
protected function suggestHostFilterColumns()
{
return $this->getFilterColumns('host.', [
$this->translate('Host properties'),
$this->translate('Custom variables')
]);
}
protected function suggestServiceFilterColumns()
{
return $this->getFilterColumns('service.', [
$this->translate('Service properties'),
$this->translate('Host properties'),
$this->translate('Host Custom variables'),
$this->translate('Custom variables')
]);
}
protected function suggestDataListValuesForListId($id)
{
$db = $this->db()->getDbAdapter();
$select = $db->select()
->from('director_datalist_entry', ['entry_name', 'entry_value'])
->where('list_id = ?', $id)
->order('entry_value ASC');
$result = $db->fetchPairs($select);
if ($result) {
return $result;
} else {
return [];
}
}
protected function suggestDataListValues($field = null)
{
if ($field === null) {
// field is required!
return [];
}
$datalistType = 'Icinga\\Module\\Director\\DataType\\DataTypeDatalist';
$db = $this->db()->getDbAdapter();
$query = $db->select()
->from(['f' => 'director_datafield'], [])
->join(
['sid' => 'director_datafield_setting'],
'sid.datafield_id = f.id AND sid.setting_name = \'datalist_id\'',
[]
)
->join(
['l' => 'director_datalist'],
'l.id = sid.setting_value',
[]
)
->join(
['e' => 'director_datalist_entry'],
'e.list_id = l.id',
['entry_name', 'entry_value']
)
->where('datatype = ?', $datalistType)
->where('varname = ?', $field)
->order('entry_value');
// TODO: respect allowed_roles
/* this implementation from DataTypeDatalist is broken
$roles = array_map('json_encode', Acl::instance()->listRoleNames());
if (empty($roles)) {
$query->where('allowed_roles IS NULL');
} else {
$query->where('(allowed_roles IS NULL OR allowed_roles IN (?))', $roles);
}
*/
$data = [];
foreach ($db->fetchPairs($query) as $key => $label) {
// TODO: find a better solution here
// $data[] = sprintf("%s [%s]", $label, $key);
$data[] = $key;
}
return $data;
}
protected function getFilterColumns($prefix, $keys)
{
if ($prefix === 'host.') {
$all = IcingaHost::enumProperties($this->db(), $prefix);
} else {
$all = IcingaService::enumProperties($this->db(), $prefix);
}
$res = [];
foreach ($keys as $key) {
if (array_key_exists($key, $all)) {
$res = array_merge($res, array_keys($all[$key]));
}
}
natsort($res);
return $res;
}
protected function suggestDependencytemplates()
{
$this->assertPermission('director/hosts');
return $this->fetchTemplateNames('icinga_dependency');
}
protected function highlight($val, $search)
{
$search = ($search);
$val = Html::escape($val);
return preg_replace(
'/(' . preg_quote($search, '/') . ')/i',
'<strong>\1</strong>',
$val
);
}
protected function getAllApplyRules()
{
$allApplyRules = $this->fetchAllApplyRules();
foreach ($allApplyRules as $rule) {
$rule->filter = Filter::fromQueryString($rule->assign_filter);
}
return $allApplyRules;
}
protected function fetchAllApplyRules()
{
$db = $this->db()->getDbAdapter();
$query = $db->select()->from(
array('s' => 'icinga_service'),
array(
'id' => 's.id',
'name' => 's.object_name',
'assign_filter' => 's.assign_filter',
)
)->where('object_type = ? AND assign_filter IS NOT NULL', 'apply');
return $db->fetchAll($query);
}
protected function suggestImportsourceproperties($sourceId = null)
{
if ($sourceId === null) {
return [];
}
try {
$importSource = ImportSource::loadWithAutoIncId($sourceId, $this->db());
$source = ImportSourceHook::loadByName($importSource->get('source_name'), $this->db());
$columns = array_merge(
$source->listColumns(),
$importSource->listProperties()
);
return array_combine($columns, $columns);
} catch (NotFoundError $e) {
return [];
}
}
}