Skip to content
This repository has been archived by the owner on Jan 15, 2019. It is now read-only.

Commit

Permalink
* Added URL-driven Icinga-API requests (resolves #305)
Browse files Browse the repository at this point in the history
* API Requests can now be done via GET or POST requests
  • Loading branch information
jmosshammer committed May 19, 2010
1 parent bd1c977 commit f62674c
Show file tree
Hide file tree
Showing 8 changed files with 400 additions and 1 deletion.
136 changes: 136 additions & 0 deletions app/modules/Web/actions/Icinga/ApiSearchAction.class.php
@@ -0,0 +1,136 @@
<?php

class Web_Icinga_ApiSearchAction extends IcingaWebBaseAction
{
/**
* Returns the default view if the action does not serve the request
* method used.
*
* @return mixed <ul>
* <li>A string containing the view name associated
* with this action; or</li>
* <li>An array with two indices: the parent module
* of the view to be executed and the view to be
* executed.</li>
* </ul>
*/

static public $defaultColumns = array(
"host" => array("HOST_ID",'HOST_OBJECT_ID','HOST_INSTANCE_ID',"HOST_NAME","HOST_ALIAS","HOST_DISPLAY_NAME","HOST_ADDRESS","HOST_IS_ACTIVE"),
"service" => array("SERVICE_ID","SERVICE_OBJECT_ID","SERVICE_IS_ACTIVE","SERVICE_INSTANCE_ID","SERVICE_NAME","SERVICE_DISPLAY_NAME","SERVICE_OUTPUT","SERVICE_PERFDATA"),
"hostgroup" => array("HOSTGROUP_ID","HOSTGROUP_OBJECT_ID","HOSTGROUP_INSTANCE_ID","HOSTGROUP_NAME","HOSTGROUP_ALIAS"),
"servicegroup" => array("SERVICEGROUP_ID","SERVICEGROUP_OBJECT_ID","SERVICEGROUP_INSTANCE_ID","SERVICEGROUP_NAME","SERVICEGROUP_ALIAS"),
"customvariable" => array("CUSTOMVARIABLE_ID","CUSTOMVARIABLE_OBJECT_ID","CUSTOMVARIABLE_INSTANCE_ID","CUSTOMVARIABLE_NAME","CUSTOMVARIABLE_VALUE","CUSTOMVARIABLE_MODIFIED","CUSTOMVARIABLE_UPDATETIME"),
"contact" => array("CONTACT_NAME","CONTACT_CUSTOMVARIABLE_NAME","CONTACT_CUSTOMVARIABLE_VALUE"),
"contactgroup" => array("CONTACTGROUP_ID","CONTACTGROUP_OBJECT_ID","CONTACTGROUP_INSTANCE_ID","CONTACTGROUP_NAME","CONTACTGROUP_ALIAS"),
"timeperiod" => array("TIMEPERIOD_ID","TIMEPERIOD_OBJECT_ID","TIMEPERIOD_INSTANCE_ID","TIMEPERIOD_NAME","TIMEPERIOD_ALIAS","TIMEPERIOD_DAY","TIMEPERIOD_STARTTIME","TIMEPERIOD_ENDTIME"),
"hoststatus" => array(),
"servicestatus" => array(),
"hosttimes" => array(),
"servicetimes" => array(),
"config" => array("CONFIG_VAR_ID","CONFIG_VAR_INSTANCE_ID","CONFIG_VAR_NAME","CONFIG_VAR_VALUE"),
"program" => array(),
"log" => array("LOG_ID","LOG_INSTANCE_ID","LOG_TIME","LOG_ENTRY_TIME","LOG_ENTRY_TIME_USEC","LOG_TYPE","LOG_DATA","LOG_REALTIME_DATA","LOG_INFERRED_DATA"),
"host_status_summary" => array("HOST_ID",'HOST_STATUS_ALL','HOST_STATE','HOST_STATE_COUNT','HOST_LAST_CHECK'),
"service_status_summary" => array("SERVICE_ID",'SERVICE_STATUS_ALL','SERVICE_OUTPUT','SERVICE_LONG_OUTPUT','SERVICE_PERFDATA','SERVICE_LAST_CHECK'),
"host_status_history" => array("STATEHISTORY_ID","STATEHISTORY_INSTANCE_ID","STATEHISTORY_STATE_TIME","STATEHISTORY_OBJECT_ID","STATEHISTORY_STATE_CHANGE","STATEHISTORY_STATE","STATEHISTORY_OUTPUT","STATEHISTORY_LONG_OUTPUT"),
"service_status_history" => array("STATEHISTORY_ID","STATEHISTORY_INSTANCE_ID","STATEHISTORY_STATE_TIME","STATEHISTORY_OBJECT_ID","STATEHISTORY_STATE_CHANGE","STATEHISTORY_STATE","STATEHISTORY_OUTPUT","STATEHISTORY_LONG_OUTPUT"),
"host_parents" => array("HOST_ID",'HOST_OBJECT_ID',"HOST_NAME","HOST_PARENT_OBJECT_ID","HOST_PARENT_NAME"),
"notifications" => array("NOTIFICATION_ID","NOTIFICATION_TYPE","NOTIFICATION_REASON","NOTIFICATION_STARTTIME","NOTIFICATION_ENDTIME","NOTIFICATION_OUTPUT","NOTIFICATION_OBJECT_ID","NOTIFICATION_OBJECTTYPE_ID"),
"hostgroup_summary" => array('HOSTGROUP_SUMMARY_COUNT',"HOSTGROUP_ID","HOSTGROUP_OBJECT_ID","HOSTGROUP_NAME"),
"servicegroup_summary" => array('SERVICEGROUP_SUMMARY_COUNT',"SERVICEGROUP_ID","SERVICEGROUP_OBJECT_ID","SERVICEGROUP_NAME")
);


public function getDefaultViewName()
{
return 'Success';
}

public function isSecure() {
return true;
}

public function executeRead(AgaviRequestDataHolder $rd) {
$context = $this->getContext();
$API = $context->getModel("Icinga.ApiContainer","Web");
$target = $rd->getParameter("target");

$search = @$API->createSearch()->setSearchTarget($target);
$this->addFilters($search,$rd);

$this->setColumns($search,$rd);
$this->setGrouping($search,$rd);
$this->setOrder($search,$rd);
$this->setLimit($search,$rd);

$search->setResultType(IcingaApiSearch::RESULT_ARRAY);

// Adding security principal targets to the query
IcingaPrincipalTargetTool::applyApiSecurityPrincipals($search);

$search = $search->fetch()->getAll();
$rd->setParameter("searchResult",$search);
return $this->getDefaultViewName();
}

protected function addFilters(IcingaApiSearchIdo $search,AgaviRequestDataHolder $rd) {
// URL filter definitions
$field = $rd->getParameter("field",null);
$method = $rd->getParameter("method",null);
$filter = str_replace("*","%",$rd->getParameter("filter",null));

if($field)
$search->setSearchFilter($field,$filter,$method);


// POST filter definitions
$advFilter = $rd->getParameter("filters",array());

foreach($advFilter as $fl) {
$fl["filter"] = str_replace("*","%",$fl["filter"]);
$search->setSearchFilter($fl["field"],$fl["filter"],$fl["method"]);
}
}

public function setGrouping(IcingaApiSearchIdo $search,AgaviRequestDataHolder $rd) {
$groups = $rd->getParameter("groups",array());
if(!is_array($groups))
$groups = array($groups);
if(!empty($groups))
$search->setSearchGroup($groups);
}

public function setOrder(IcingaApiSearchIdo $search,AgaviRequestDataHolder $rd) {
$order_col = $rd->getParameter("order_col",null);
$order_dir = $rd->getParameter("order_dir",'asc');
if($order_col)
$search->setSearchOrder($order_col,$order_dir);

$order = $rd->getParameter("order",array());
if(!is_array($order))
$order = array($order);
if(!empty($order))
$search->setSearchOrder($order["column"],$order["dir"]);
}

public function setColumns(IcingaApiSearchIdo $search,AgaviRequestDataHolder $rd) {
$columns = $rd->getParameter("columns",self::$defaultColumns[$search->getSearchTarget()]);
if(!empty($columns))
$search->setResultColumns($columns);
}

public function setLimit(IcingaApiSearchIdo $search,AgaviRequestDataHolder $rd) {
$start = $rd->getParameter("limit_start",0);
$limit = $rd->getParameter("limit",false);

if($limit)
$search->setSearchLimit($start,$limit);
}

public function executeWrite(AgaviRequestDataHolder $rd) {
return $this->executeRead($rd);
}
}

?>
7 changes: 7 additions & 0 deletions app/modules/Web/cache/Icinga/ApiSearch.xml
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0" xmlns="http://agavi.org/agavi/config/parts/caching/1.0">
<ae:configuration>
<caching enabled="false">
</caching>
</ae:configuration>
</ae:configurations>
3 changes: 2 additions & 1 deletion app/modules/Web/config/autoload.xml
Expand Up @@ -33,5 +33,6 @@
<autoload name="IcingaTemplateXmlParser">%core.module_dir%/Web/lib/template/IcingaTemplateXmlParser.class.php</autoload>
<autoload name="IcingaTemplateWorker">%core.module_dir%/Web/lib/template/IcingaTemplateWorker.class.php</autoload>
<autoload name="IcingaBaseException">%core.module_dir%/Web/lib/IcingaBaseException.class.php</autoload>

</ae:configuration>
</ae:configurations>
</ae:configurations>
Empty file.
160 changes: 160 additions & 0 deletions app/modules/Web/validate/Icinga/ApiSearch.xml
@@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations
xmlns="http://agavi.org/agavi/config/parts/validators/1.0"
xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0"
parent="%core.module_dir%/Web/config/validators.xml"
>
<ae:configuration>

<validators>
<validator name="target" class="string" required="true">
<argument>target</argument>
<errors>
<error>Validation of target failed!</error>
</errors>
</validator>

<validator name="field" class="string" required="false">
<argument>field</argument>
<errors>
<error>Validation of target field!</error>
</errors>
</validator>
<validator name="method" class="string" required="false">
<argument>method</argument>
<errors>
<error>Validation of method failed!</error>
</errors>
</validator>
<validator name="filter" class="string" required="false">
<argument>filter</argument>
<errors>
<error>Validation of filter failed!</error>
</errors>
</validator>

<validator name="groups" class="AppKitSplitValidator" required="false">
<argument>groups</argument>
<ae:parameters>
<ae:parameter name="split">|</ae:parameter>
<ae:parameter name="export">groups</ae:parameter>
</ae:parameters>
</validator>

<validator name="order_col" class="string" required="false">
<argument>order_col</argument>
</validator>

<validator name="order_dir" class="inarray" required="false">
<argument>order_dir</argument>
<errors>
<error>Dir must be either 'desc' or 'asc'</error>
</errors>
<ae:parameters>
<ae:parameter name="type">string</ae:parameter>
<ae:parameter name="case">true</ae:parameter>
<ae:parameter name="values">
<ae:parameter>desc</ae:parameter>
<ae:parameter>asc</ae:parameter>
</ae:parameter>
</ae:parameters>
</validator>

<validator name="columns" class="AppKitSplitValidator" required="false">
<argument>columns</argument>
<errors>
<error>Validation of columns failed</error>
</errors>
<ae:parameters>
<ae:parameter name="split">|</ae:parameter>
<ae:parameter name="export">columns</ae:parameter>
</ae:parameters>
</validator>

<validator name="limit_start" class="number" required="false">
<argument>limit_start</argument>
<ae:parameter>
<ae:parameter name="min">0</ae:parameter>
</ae:parameter>
</validator>

<validator name="limit" class="number" required="false">
<argument>limit</argument>
<ae:parameter>
<ae:parameter name="min">1</ae:parameter>
</ae:parameter>
</validator>
</validators>

<validators method="write">
<validator name="filters" class="string">
<arguments base="filters[]">
<argument>field</argument>
<argument>method</argument>
<argument>filter</argument>
</arguments>
<errors>
<error>Validation of adv_filter failed</error>
</errors>
</validator>

<validator class="inarray" name="validate_method" required="false">
<arguments base="filters[]">
<argument>method</argument>
</arguments>
<errors>
<error>Only '&gt;','&lt;','&gt;=','&lt;=','!=','=' and 'like' are allowed as methods</error>
</errors>
<ae:parameters>
<ae:parameter name="type">string</ae:parameter>
<ae:parameter name="case">true</ae:parameter>
<ae:parameter name="values">
<ae:parameter>&gt;</ae:parameter>
<ae:parameter>&gt;=</ae:parameter>
<ae:parameter>&lt;</ae:parameter>
<ae:parameter>&lt;=</ae:parameter>
<ae:parameter>=</ae:parameter>
<ae:parameter>!=</ae:parameter>
<ae:parameter>like</ae:parameter>
</ae:parameter>
</ae:parameters>
</validator>

<validator name="group" class="string" required="false">
<arguments base="groups[]" />
</validator>

<validator name="order" class="string" required="false">
<arguments base="order[]">
<argument>column</argument>
<argument>dir</argument>
</arguments>
</validator>

<validator name="order_dir" class="inarray" required="false">
<arguments base="order[]">
<argument>dir</argument>
</arguments>
<errors>
<error>Dir must be either 'desc' or 'asc'</error>
</errors>
<ae:parameters>
<ae:parameter name="type">string</ae:parameter>
<ae:parameter name="case">true</ae:parameter>
<ae:parameter name="values">
<ae:parameter>desc</ae:parameter>
<ae:parameter>asc</ae:parameter>
</ae:parameter>
</ae:parameters>
</validator>

<validator name="columns" class="string" required="false">
<arguments base="columns[]" />
<errors>
<error>Validation of columns failed</error>
</errors>
</validator>
</validators>

</ae:configuration>
</ae:configurations>
30 changes: 30 additions & 0 deletions app/modules/Web/views/Icinga/ApiSearchErrorView.class.php
@@ -0,0 +1,30 @@
<?php

class Web_Icinga_ApiSearchErrorView extends IcingaWebBaseView
{
public function executeHtml(AgaviRequestDataHolder $rd)
{
return "Invalid Arguments!";
}

public function executeJson(AgaviRequestDataHolder $rd)
{
$context = $this->getContext();
$validation = $this->getContainer()->getValidationManager();
$errorMsg = array("error"=>array());
foreach($validation->getErrorMessages() as $error) {
$errorMsg["error"][] = $error;
}
return json_encode($errorMsg);
}

public function executeXml(AgaviRequestDataHolder $rd)
{
echo "<?xml version='1.0' encoding='utf-8'><error><message>Invalid arguments!</message></error>";
}

public function executeSimple(AgaviRequestDataHolder $rd)
{
echo "Invalid arguments";
}
}
43 changes: 43 additions & 0 deletions app/modules/Web/views/Icinga/ApiSearchSuccessView.class.php
@@ -0,0 +1,43 @@
<?php

class Web_Icinga_ApiSearchSuccessView extends IcingaWebBaseView
{
public function executeHtml(AgaviRequestDataHolder $rd)
{
$this->setAttribute('_title', 'Icinga.ApiSearch');
}

public function executeJson(AgaviRequestDataHolder $rd)
{
return json_encode($rd->getParameter("searchResult",null));
}

public function executeXml(AgaviRequestDataHolder $rd)
{
$results = $rd->getParameter("searchResult",null);
$DOM = new DOMDocument("1.0","UTF-8");
$root = $DOM->createElement("results");
$DOM->appendChild($root);
foreach($results as $result) {
$resultNode = $DOM->createElement("result");
$root->appendChild($resultNode);
foreach($result as $fieldname=>$field) {
$node = $DOM->createElement("column");
$node->nodeValue = $field;

$name = $DOM->createAttribute("name");
$name->nodeValue = $fieldname;
$node->appendChild($name);
$resultNode->appendChild($node);
}
}
return $DOM->saveXML();
}

public function executeSimple(AgaviRequestDataHolder $rd)
{

}
}

?>

0 comments on commit f62674c

Please sign in to comment.