4 * Class for building report sql queries
6 * Should eventually be shared between summary and status reports. Isn't currently.
8 class Report_query_builder_Model
extends Model
10 /* oh no, it leaked out from the summary report model
11 * (contains a mapping from each group to each object, so alert summary
12 * can sum up group reports)
14 public $host_hostgroup; /**< array(host => array(hgrop1, hgroupx...)) */
15 public $service_servicegroup; /**< array(service => array(sgroup1, sgroupx...))*/
17 protected $db_table = false; /**< The table we'll be operating on */
18 protected $options = false; /**< An options object (or array) to work with */
21 * Create new report query builder
22 * @param $db_table The table name
23 * @param $options The options object to work with
25 function __construct($db_table, $options) {
26 parent
::__construct();
27 $this->db_table
= $db_table;
28 $this->options
= $options;
32 * Create the base of the query to use when calculating
33 * alert summary. Each caller is responsible for adding
34 * sorting and limit options as necessary.
36 * @param $fields string Comma separated list of database columns the caller needs
37 * @return string (sql)
39 function build_alert_summary_query($fields = null)
42 // default to the most commonly used fields
43 $fields = 'host_name, service_description, state, hard';
45 $auth = op5auth
::instance();
52 $wildcard_filter = false;
56 if ($this->options
['report_type'] == 'servicegroups') {
57 $hosts = $services = array();
58 foreach ($this->options
['objects'] as $sg) {
59 $res = Livestatus
::instance()->getServices(array('columns' => array('host_name', 'description'), 'filter' => array('groups' => array('>=' => $sg))));
60 foreach ($res as $o) {
61 $name = implode(';', $o);
62 # To be able to sum up alert totals:
63 if (empty($services[$name])) {
64 $services[$name] = array();
66 $services[$name][$sg] = $sg;
67 if (empty($hosts[$o['host_name']])) {
68 $hosts[$o['host_name']] = array();
70 $hosts[$o['host_name']][$sg] = $sg;
73 $this->service_servicegroup
['host'] = $hosts;
74 $this->service_servicegroup
['service'] = $services;
75 } elseif ($this->options
['report_type'] == 'hostgroups') {
77 foreach ($this->options
['objects'] as $hg) {
78 $res = Livestatus
::instance()->getHosts(array('columns' => array('host_name'), 'filter' => array('groups' => array('>=' => $hg))));
79 foreach ($res as $row) {
80 # To be able to sum up alert totals:
81 if (empty($hosts[$row['host_name']])) {
82 $hosts[$row['host_name']] = array();
84 $hosts[$row['host_name']][$hg] = $hg;
87 $this->host_hostgroup
= $hosts;
88 } elseif ($this->options
['report_type'] == 'services') {
90 if($this->options
['objects'] === Report_options
::ALL_AUTHORIZED
) {
91 $services = Report_options
::ALL_AUTHORIZED
;
93 foreach ($this->options
['objects'] as $srv) {
94 $services[$srv] = $srv;
97 } elseif ($this->options
['report_type'] == 'hosts') {
99 if($this->options
['objects'] === Report_options
::ALL_AUTHORIZED
) {
100 $hosts = Report_options
::ALL_AUTHORIZED
;
102 if (is_array($this->options
['objects'])) {
103 foreach ($this->options
['objects'] as $hn)
106 $hosts[$this->options
['objects']] = $this->options
['objects'];
111 if (empty($hosts) && empty($services)) {
112 return "SELECT $fields FROM $this->db_table LIMIT 0";
115 $object_selection = false;
116 if(($hosts === Report_options
::ALL_AUTHORIZED
) ||
($services === Report_options
::ALL_AUTHORIZED
)) {
117 // screw filters, we're almighty
118 } elseif ($services) {
119 if ($services !== true) {
120 $object_selection .= "(";
122 # Must do this the hard way to allow host_name indices to
123 # take effect when running the query, since the construct
124 # "concat(host_name, ';', service_description)" isn't
126 foreach ($services as $srv => $discard) {
127 $ary = explode(';', $srv);
130 $object_selection .= $orstr . "(host_name = '" . $h . "'\n AND (" ;
131 if ($s) { /* this if-statement can probably just go away */
132 $object_selection .= "service_description = '" . $s . "' OR ";
134 $object_selection .= "event_type = 801))";
138 if (!empty($object_selection))
139 $object_selection .= ')';
140 } elseif ($hosts && $hosts !== true) {
141 $object_selection = "host_name IN(\n '" .
142 join("',\n '", array_keys($hosts)) . "')";
144 switch ($this->options
['state_types']) {
150 $softorhard = 'hard = 0';
153 $softorhard = 'hard = 1';
157 if (!$this->options
['host_states'] ||
$this->options
['host_states'] == Reports_Model
::HOST_ALL
) {
158 $host_states_sql = 'event_type = ' . Reports_Model
::HOSTCHECK
;
161 $host_states_sql = '(event_type = ' . Reports_Model
::HOSTCHECK
. ' ' .
163 for ($i = 0; $i < Reports_Model
::HOST_ALL
; $i++
) {
164 if (1 << $i & $this->options
['host_states']) {
168 $host_states_sql .= join(',', $x) . '))';
171 if (!$this->options
['service_states'] ||
$this->options
['service_states'] == Reports_Model
::SERVICE_ALL
) {
172 $service_states_sql = 'event_type = ' . Reports_Model
::SERVICECHECK
;
175 $service_states_sql = '(event_type = ' . Reports_Model
::SERVICECHECK
.
177 for ($i = 0; $i < Reports_Model
::SERVICE_ALL
; $i++
) {
178 if (1 << $i & $this->options
['service_states']) {
182 $service_states_sql .= join(',', $x) . '))';
185 switch ($this->options
['alert_types']) {
187 $alert_types = $host_states_sql;
190 $alert_types = $service_states_sql;
193 $alert_types = sql
::combine('or', $host_states_sql, $service_states_sql);
197 if (isset($this->options
['include_downtime']) && $this->options
['include_downtime'])
198 $downtime = 'event_type < 1200 AND event_type > 1100';
200 if (isset($this->options
['include_process']) && $this->options
['include_process'])
201 $process = 'event_type < 200';
203 if($this->options
['start_time']) {
204 $time_first = 'timestamp >= ' . $this->options
['start_time'];
206 if($this->options
['end_time']) {
207 $time_last = 'timestamp <= ' . $this->options
['end_time'];
210 if(isset($this->options
['filter_output']) && $this->options
['filter_output']) {
211 # convert fnmatch wildcards to sql ditos
212 $wc_str = $this->options
['filter_output'];
213 $wc_str = preg_replace("/(?!\\\)\*/", '\1%', $wc_str);
214 $wc_str = preg_replace("/(?!\\\)\?/", '\1_', $wc_str);
215 # case insensitive. This also works on oracle
216 $wc_str = strtoupper($wc_str);
217 $wc_str = '%' . $wc_str . '%';
218 $wc_str_esc = $this->db
->escape($wc_str);
219 $wildcard_filter = "\n UPPER(output) LIKE $wc_str_esc" .
220 "\n OR UPPER(host_name) LIKE $wc_str_esc " .
221 "\n OR UPPER(service_description) LIKE $wc_str_esc";
224 $query = "SELECT " . $fields . "\nFROM " . $this->db_table
;
242 $extra_sql = array();
243 $db = $this->db
; // for closures
244 $implode_str = ') OR (';
245 // summa summarum: Don't use the API unless you're *authorized* (this is really slow)
246 if(1 & $this->options
["alert_types"] && !$auth->authorized_for("host_view_all")) {
247 $ls = op5Livestatus
::instance();
248 $hosts = $ls->query("hosts", null, array("name"), array('auth' => $auth->get_user()));
249 $objtosql = function($e) use ($db) {
250 return $db->escape(current($e));
252 if (!empty($hosts[1])) {
253 $extra_sql[] = sql
::combine(
256 implode(", ",array_map($objtosql,$hosts[1])).")",
257 "service_description = ''"
261 $extra_sql[] = "service_description != ''";
262 $implode_str = ') AND (';
266 // summa summarum: Don't use the API unless you're *authorized* (this is really slow)
267 if(2 & $this->options
["alert_types"] && !$auth->authorized_for("service_view_all")) {
268 $ls = op5Livestatus
::instance();
269 $services = $ls->query("services", null, array("host_name", "description"), array('auth' => $auth->get_user()));
270 $objtosql = function($e) use ($db) {
271 return '('.$db->escape($e[0]).', '.$db->escape($e[1]).')';
273 if (!empty($services[1])) {
274 $extra_sql[] = "(host_name, service_description) IN (".
275 implode(", ",array_map($objtosql,$services[1])).")";
278 $extra_sql[] = "service_description = ''";
279 $implode_str = ') AND (';
283 if(count($extra_sql) > 0) {
284 /* The innermost parenthesis matches the parenthesis in $implode_str */
285 $query .= " AND ((".implode($implode_str, $extra_sql)."))";