From ded2fb08ffed0f5901533a5161d2143857b5b62c Mon Sep 17 00:00:00 2001 From: "alejandro.campos@artica.es" Date: Tue, 16 Aug 2022 18:42:51 +0200 Subject: [PATCH 1/3] implemented cron based scheduled downtimes --- pandora_console/extras/mr/57.sql | 6 + .../agentes/planned_downtime.editor.php | 273 ++++++++++++++++++ .../godmode/agentes/planned_downtime.list.php | 16 +- pandora_console/include/functions_html.php | 219 +++++++++++++- .../include/functions_reporting.php | 4 + pandora_console/include/javascript/pandora.js | 5 + pandora_console/pandoradb.sql | 2 + pandora_server/lib/PandoraFMS/Core.pm | 128 +++++++- pandora_server/lib/PandoraFMS/Tools.pm | 125 ++++++++ 9 files changed, 754 insertions(+), 24 deletions(-) create mode 100644 pandora_console/extras/mr/57.sql diff --git a/pandora_console/extras/mr/57.sql b/pandora_console/extras/mr/57.sql new file mode 100644 index 0000000000..839e090cc3 --- /dev/null +++ b/pandora_console/extras/mr/57.sql @@ -0,0 +1,6 @@ +START TRANSACTION; + +ALTER TABLE `tplanned_downtime` ADD COLUMN `cron_interval_from` VARCHAR(100) DEFAULT ''; +ALTER TABLE `tplanned_downtime` ADD COLUMN `cron_interval_to` VARCHAR(100) DEFAULT ''; + +COMMIT; \ No newline at end of file diff --git a/pandora_console/godmode/agentes/planned_downtime.editor.php b/pandora_console/godmode/agentes/planned_downtime.editor.php index dd4a8c29b0..f2d7109406 100644 --- a/pandora_console/godmode/agentes/planned_downtime.editor.php +++ b/pandora_console/godmode/agentes/planned_downtime.editor.php @@ -49,6 +49,7 @@ if (!$agent_d && !$agent_w) { set_unless_defined($config['past_planned_downtimes'], 1); require_once 'include/functions_users.php'; +require_once $config['homedir'].'/include/functions_cron.php'; // Buttons. $buttons = [ @@ -123,6 +124,18 @@ $periodically_time_to = (string) get_parameter( date(TIME_FORMAT, ($system_time + SECONDS_1HOUR)) ); +$hour_from = get_parameter('cron_hour_from', '*'); +$minute_from = get_parameter('cron_minute_from', '*'); +$mday_from = get_parameter('cron_mday_from', '*'); +$month_from = get_parameter('cron_month_from', '*'); +$wday_from = get_parameter('cron_wday_from', '*'); + +$hour_to = get_parameter('cron_hour_to', '*'); +$minute_to = get_parameter('cron_minute_to', '*'); +$mday_to = get_parameter('cron_mday_to', '*'); +$month_to = get_parameter('cron_month_to', '*'); +$wday_to = get_parameter('cron_wday_to', '*'); + $monday = (bool) get_parameter('monday'); $tuesday = (bool) get_parameter('tuesday'); $wednesday = (bool) get_parameter('wednesday'); @@ -262,6 +275,210 @@ if ($create_downtime || $update_downtime) { ); } else { $sql = ''; + + if ($type_execution === 'cron') { + $error_cron_from = false; + $error_cron_to = false; + $error_field = ''; + + // Validate 'from' cron values. + $hour_from = io_safe_output(trim($hour_from)); + if (preg_match('/^((?:([0-1]?[0-9]|2[0-3])|\*)\s*(?:(?:[\/-]([0-1]?[0-9]|2[0-3])))?\s*)$/', $hour_from, $matches) !== 1) { + $error_cron_from = true; + $error_field = __('hour (from)'); + } else { + $interval_values = explode('-', $hour_from); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_from = true; + } + } + } + + $minute_from = io_safe_output(trim($minute_from)); + if (preg_match('/^((?:(5[0-9]|[0-5]?[0-9])|\*)\s*(?:(?:[\/-](5[0-9]|[0-5]?[0-9])))?\s*)$/', $minute_from, $matches) !== 1) { + $error_cron_from = true; + $error_field = __('minute (from)'); + } else { + $interval_values = explode('-', $minute_from); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_from = true; + } + } + } + + $mday_from = io_safe_output(trim($mday_from)); + if (preg_match('/^((?:(0?[1-9]|[12][0-9]|3[01])|\*)\s*(?:(?:[\/-](0?[1-9]|[12][0-9]|3[01])))?\s*)$/', $mday_from, $matches) !== 1) { + $error_cron_from = true; + $error_field = __('month day (from)'); + } else { + $interval_values = explode('-', $mday_from); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_from = true; + } + } + } + + $month_from = io_safe_output(trim($month_from)); + if (preg_match('/^((?:([1-9]|1[012])|\*)\s*(?:(?:[\/-]([1-9]|1[012])))?\s*)$/', $month_from, $matches) !== 1) { + $error_cron_from = true; + $error_field = __('month (from)'); + } else { + $interval_values = explode('-', $month_from); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_from = true; + } + } + } + + $wday_from = io_safe_output(trim($wday_from)); + if (preg_match('/^((?:[0-6]|\*)\s*(?:(?:[\/-][0-6]))?\s*)$/', $wday_from, $matches) !== 1) { + $error_cron_from = true; + $error_field = __('week day (from)'); + } else { + $interval_values = explode('-', $wday_from); + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_from = true; + } + } + } + + // Validate 'to' cron values. + $hour_to = io_safe_output(trim($hour_to)); + if (preg_match('/^((?:([0-1]?[0-9]|2[0-3])|\*)\s*(?:(?:[\/-]([0-1]?[0-9]|2[0-3])))?\s*)$/', $hour_to, $matches) !== 1) { + $error_cron_to = true; + $error_field = __('hour (to)'); + } else { + $interval_values = explode('-', $hour_to); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_to = true; + } + } + } + + $minute_to = io_safe_output(trim($minute_to)); + if (preg_match('/^((?:(5[0-9]|[0-5]?[0-9])|\*)\s*(?:(?:[\/-](5[0-9]|[0-5]?[0-9])))?\s*)$/', $minute_to, $matches) !== 1) { + $error_cron_to = true; + $error_field = __('minute (to)'); + } else { + $interval_values = explode('-', $minute_to); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_to = true; + } + } + } + + $mday_to = io_safe_output(trim($mday_to)); + if (preg_match('/^((?:(0?[1-9]|[12][0-9]|3[01])|\*)\s*(?:(?:[\/-](0?[1-9]|[12][0-9]|3[01])))?\s*)$/', $mday_to, $matches) !== 1) { + $error_cron_to = true; + $error_field = __('month day (to)'); + } else { + $interval_values = explode('-', $mday_to); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_to = true; + } + } + } + + $month_to = io_safe_output(trim($month_to)); + if (preg_match('/^((?:([1-9]|1[012])|\*)\s*(?:(?:[\/-]([1-9]|1[012])))?\s*)$/', $month_to, $matches) !== 1) { + $error_cron_to = true; + $error_field = __('month (to)'); + } else { + $interval_values = explode('-', $month_to); + + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_to = true; + } + } + } + + $wday_to = io_safe_output(trim($wday_to)); + if (preg_match('/^((?:[0-6]|\*)\s*(?:(?:[\/-][0-6]))?\s*)$/', $wday_to, $matches) !== 1) { + $error_cron_to = true; + $error_field = __('week day (to)'); + } else { + $interval_values = explode('-', $wday_to); + if (count($interval_values) > 1) { + $interval_from = $interval_values[0]; + $interval_to = $interval_values[1]; + + if ((int) $interval_to < (int) $interval_from) { + $error_cron_to = true; + } + } + } + + if ($error_cron_from === true) { + ui_print_error_message( + __('Downtime start cron expression is not correct').': '.$error_field + ); + } + + if ($error_cron_to === true) { + ui_print_error_message( + __('Downtime stop cron expression is not correct').': '.$error_field + ); + } + + if ($error_cron_to === true || $error_cron_from) { + return; + } + + $cron_interval_from = io_safe_output($minute_from.' '.$hour_from.' '.$mday_from.' '.$month_from.' '.$wday_from); + $cron_interval_to = io_safe_output($minute_to.' '.$hour_to.' '.$mday_to.' '.$month_to.' '.$wday_to); + } + + if (cron_check_syntax($cron_interval_from) !== 1) { + $cron_interval_from = ''; + } + + if (cron_check_syntax($cron_interval_to) !== 1) { + $cron_interval_to = ''; + } + if ($create_downtime) { // Check AD permission on new downtime. if (!in_array($id_group, $user_groups_ad)) { @@ -298,6 +515,8 @@ if ($create_downtime || $update_downtime) { 'type_execution' => $type_execution, 'type_periodicity' => $type_periodicity, 'id_user' => $config['id_user'], + 'cron_interval_from' => $cron_interval_from, + 'cron_interval_to' => $cron_interval_to, ]; if ($config['dbtype'] == 'oracle') { $values['periodically_time_from'] = '1970/01/01 '.$values['periodically_time_from']; @@ -381,6 +600,8 @@ if ($create_downtime || $update_downtime) { 'type_execution' => $type_execution, 'type_periodicity' => $type_periodicity, 'id_user' => $config['id_user'], + 'cron_interval_from' => $cron_interval_from, + 'cron_interval_to' => $cron_interval_to, ]; if ($config['dbtype'] == 'oracle') { $values['periodically_time_from'] = '1970/01/01 '.$values['periodically_time_from']; @@ -458,6 +679,8 @@ if ($id_downtime > 0) { 'type_execution', 'type_periodicity', 'id_user', + 'cron_interval_from', + 'cron_interval_to', ]; switch ($config['dbtype']) { @@ -532,6 +755,36 @@ if ($id_downtime > 0) { $saturday = (bool) $result['saturday']; $sunday = (bool) $result['sunday']; + $cron_interval_from = explode(' ', $result['cron_interval_from']); + if (isset($cron_interval_from[4]) === true) { + $minute_from = $cron_interval_from[0]; + $hour_from = $cron_interval_from[1]; + $mday_from = $cron_interval_from[2]; + $month_from = $cron_interval_from[3]; + $wday_from = $cron_interval_from[4]; + } else { + $minute_from = '*'; + $hour_from = '*'; + $mday_from = '*'; + $month_from = '*'; + $wday_from = '*'; + } + + $cron_interval_to = explode(' ', $result['cron_interval_to']); + if (isset($cron_interval_to[4]) === true) { + $minute_to = $cron_interval_to[0]; + $hour_to = $cron_interval_to[1]; + $mday_to = $cron_interval_to[2]; + $month_to = $cron_interval_to[3]; + $wday_to = $cron_interval_to[4]; + } else { + $minute_to = '*'; + $hour_to = '*'; + $mday_to = '*'; + $month_to = '*'; + $wday_to = '*'; + } + $running = (bool) $result['executed']; } @@ -611,6 +864,7 @@ $table->data[4][1] = html_print_select( [ 'once' => __('Once'), 'periodically' => __('Periodically'), + 'cron' => __('Cron from/to'), ], 'type_execution', $type_execution, @@ -740,6 +994,18 @@ $table->data[5][1] = " + + '; if ($id_downtime > 0) { @@ -1254,12 +1520,19 @@ function insert_downtime_agent($id_downtime, $user_groups_ad) switch ($("#type_execution").val()) { case 'once': $("#periodically_time").hide(); + $("#cron_time").hide(); $("#once_time").show(); break; case 'periodically': $("#once_time").hide(); + $("#cron_time").hide(); $("#periodically_time").show(); break; + case 'cron': + $("#once_time").hide(); + $("#periodically_time").hide(); + $("#cron_time").show(); + break; } } diff --git a/pandora_console/godmode/agentes/planned_downtime.list.php b/pandora_console/godmode/agentes/planned_downtime.list.php index a1e352fa1e..78f717d7d1 100755 --- a/pandora_console/godmode/agentes/planned_downtime.list.php +++ b/pandora_console/godmode/agentes/planned_downtime.list.php @@ -317,6 +317,7 @@ $row = []; $execution_type_fields = [ 'once' => __('Once'), 'periodically' => __('Periodically'), + 'cron' => __('Cron'), ]; $row[] = __('Execution type').' '.html_print_select( $execution_type_fields, @@ -460,10 +461,15 @@ if (empty($groups) === false) { strtotime($date_to.' 23:59:59') ); + $cron = sprintf( + 'type_execution = "cron"' + ); + $where_values .= sprintf( - ' AND ((%s) OR (%s))', + ' AND ((%s) OR (%s) OR (%s))', $periodically_w, - $once_w + $once_w, + $cron ); } @@ -471,6 +477,7 @@ if (empty($groups) === false) { $filter_performed = true; $where_values .= sprintf( ' AND (type_execution = "periodically" + OR type_execution = "cron" OR (type_execution = "once" AND date_to >= "%s"))', time() @@ -530,6 +537,8 @@ if (empty($groups) === false) { 'type_execution', 'type_periodicity', 'id_user', + 'cron_interval_from', + 'cron_interval_to', ]; $columns_str = implode(',', $columns); @@ -660,8 +669,9 @@ if ($downtimes === false && $filter_performed === false) { $data['type'] = $type_text[$downtime['type_downtime']]; $execution_text = [ - 'once' => __('once'), + 'once' => __('Once'), 'periodically' => __('Periodically'), + 'cron' => __('Cron'), ]; $data['execution'] = $execution_text[$downtime['type_execution']]; diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index b97e0398b6..9bf9b374b6 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -2237,7 +2237,7 @@ function html_print_extended_select_for_time( * * @return string HTML code if return parameter is true. */ -function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', $month='*', $wday='*', $return=false, $disabled=false, $to=false) +function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', $month='*', $wday='*', $return=false, $disabled=false, $to=false, $advanced=false, $adv_mode_name='') { // Hours for ($i = 0; $i < 24; $i++) { @@ -2286,18 +2286,104 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', $table->head[3] = __('Month'); $table->head[4] = __('Week day'); - if ($to) { - $table->data[0][0] = html_print_select($hours, 'hour_to', $hour, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][1] = html_print_select($minutes, 'minute_to', $minute, '', __('Any'), '*', true, false, false, '', $disabled, false, $minutes_hidden_options); - $table->data[0][2] = html_print_select($mdays, 'mday_to', $mday, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][3] = html_print_select($months, 'month_to', $month, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][4] = html_print_select($wdays, 'wday_to', $wday, '', __('Any'), '*', true, false, false, '', $disabled); + if ($advanced === false) { + if ($to) { + $table->data[0][0] = html_print_select($hours, 'hour_to', $hour, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][1] = html_print_select($minutes, 'minute_to', $minute, '', __('Any'), '*', true, false, false, '', $disabled, false, $minutes_hidden_options); + $table->data[0][2] = html_print_select($mdays, 'mday_to', $mday, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][3] = html_print_select($months, 'month_to', $month, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][4] = html_print_select($wdays, 'wday_to', $wday, '', __('Any'), '*', true, false, false, '', $disabled); + } else { + $table->data[0][0] = html_print_select($hours, 'hour_from', $hour, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][1] = html_print_select($minutes, 'minute_from', $minute, '', __('Any'), '*', true, false, false, '', $disabled, false, $minutes_hidden_options); + $table->data[0][2] = html_print_select($mdays, 'mday_from', $mday, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][3] = html_print_select($months, 'month_from', $month, '', __('Any'), '*', true, false, false, '', $disabled); + $table->data[0][4] = html_print_select($wdays, 'wday_from', $wday, '', __('Any'), '*', true, false, false, '', $disabled); + } } else { - $table->data[0][0] = html_print_select($hours, 'hour_from', $hour, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][1] = html_print_select($minutes, 'minute_from', $minute, '', __('Any'), '*', true, false, false, '', $disabled, false, $minutes_hidden_options); - $table->data[0][2] = html_print_select($mdays, 'mday_from', $mday, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][3] = html_print_select($months, 'month_from', $month, '', __('Any'), '*', true, false, false, '', $disabled); - $table->data[0][4] = html_print_select($wdays, 'wday_from', $wday, '', __('Any'), '*', true, false, false, '', $disabled); + if ($adv_mode_name !== '') { + $adv_mode_name = '_'.$adv_mode_name; + } + + $table->data[0][0] = html_print_extended_select_for_downtime_cron( + 'cron_hour'.$adv_mode_name, + $hours, + $hour, + '', + __('Any'), + '*', + false, + true, + false, + false, + false, + 0, + 'Valid values: [0-23], [0-23]-[0-23], *, or step value (example: */3, 10/5)', + ); + + $table->data[0][1] = html_print_extended_select_for_downtime_cron( + 'cron_minute'.$adv_mode_name, + $minutes, + $minute, + '', + __('Any'), + '*', + false, + true, + false, + false, + false, + 0, + 'Valid values: [0-59], [0-59]-[0-59], *, or step value (example: */5, 10/1)', + ); + + $table->data[0][2] = html_print_extended_select_for_downtime_cron( + 'cron_mday'.$adv_mode_name, + $mdays, + $mday, + '', + __('Any'), + '*', + false, + true, + false, + false, + false, + 0, + 'Valid values: [1-31], [1-31]-[1-31], *, or step value (example: */5, 7/2)', + ); + + $table->data[0][3] = html_print_extended_select_for_downtime_cron( + 'cron_month'.$adv_mode_name, + $months, + $month, + '', + __('Any'), + '*', + false, + true, + false, + false, + false, + 0, + 'Valid values: [1-12], [1-12]-[1-12], *, or step value (example: */3, 9/1)', + ); + + $table->data[0][4] = html_print_extended_select_for_downtime_cron( + 'cron_wday'.$adv_mode_name, + $wdays, + $wday, + '', + __('Any'), + '*', + false, + true, + false, + false, + false, + 0, + 'Valid values: [0-6], [0-6]-[0-6], *, or step value (example: */2, 3/1)', + ); } return html_print_table($table, $return); @@ -6171,3 +6257,112 @@ function html_print_go_back_button(string $url, array $options=[], bool $return= return $output; } + + +/** + * Render select box for numeric values and text box for complex values. + * + * @param string $name Select form name. + * @param string $fields Fields to populate select box. + * @param mixed $selected Current selected value. It can be a single value or an array of selected values (in combination with multiple). + * @param string $script Javascript onChange (select) code. + * @param string $nothing Label when nothing is selected. + * @param mixed $nothing_value Value when nothing is selected. + * @param integer $size Size of the input. + * @param boolean $return Whether to return an output string or echo now (optional, echo by default). + * @param boolean $select_style Wherter to assign to combo a unique name (to have more than one on same page, like dashboard). + * @param boolean $unique_name Uunique name value. + * @param boolean $disabled Input renders as disabled. + * @param boolean $no_change No change value. + * @param boolean $text_help Tooltip. + + * @return string HTML code if return parameter is true. + */ +function html_print_extended_select_for_downtime_cron( + $name, + $fields, + $selected='', + $script='', + $nothing='', + $nothing_value='0', + $size=false, + $return=false, + $select_style=false, + $unique_name=true, + $disabled=false, + $no_change=0, + $text_help='' +) { + global $config; + + if ($unique_name === true) { + $uniq_name = uniqid($name); + } else { + $uniq_name = $name; + } + + ob_start(); + + echo '
'; + html_print_select( + $fields, + $uniq_name.'_select', + $selected, + ''.$script, + $nothing, + $nothing_value, + false, + false, + false, + '', + $disabled, + 'font-size: xx-small;'.$select_style + ); + echo ' '.html_print_image( + 'images/pencil.png', + true, + [ + 'class' => $uniq_name.'_toggler', + 'alt' => __('Custom'), + 'title' => __('Custom'), + 'style' => 'width: 18px;', + ] + ).''; + echo '
'; + + $help_tooltip = ($text_help !== '') ? ui_print_help_tip(__($text_help), true) : ''; + + echo '
'; + html_print_input_text($uniq_name.'_text', $selected, '', 20); + + html_print_input_hidden($name, $selected, false, $uniq_name); + echo ' '.$help_tooltip.' '.html_print_image( + 'images/default_list.png', + true, + [ + 'class' => $uniq_name.'_toggler', + 'alt' => __('List'), + 'title' => __('List'), + 'style' => 'width: 18px;', + ] + ).''; + echo '
'; + + $select_init_func = (is_numeric($selected) === true || $selected === '*') ? 'post_process_select_init' : 'post_process_select_init_inv'; + + echo ""; + + $returnString = ob_get_clean(); + + if ($return) { + return $returnString; + } else { + echo $returnString; + } +} diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index c52b2bf5eb..2550625b81 100755 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -14211,6 +14211,10 @@ function reporting_format_planned_downtime_dates($planned_downtime) $dates = date('Y-m-d H:i', $planned_downtime['date_from']).' '.__('to').' '.date('Y-m-d H:i', $planned_downtime['date_to']); break; + case 'cron': + $dates = __('Start condition').': '.$planned_downtime['cron_interval_from'].' - '.__('Stop condition').': '.$planned_downtime['cron_interval_to'].''; + break; + case 'periodically': if (!isset($planned_downtime['type_periodicity'])) { return ''; diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index 690a9074ff..d55be120e6 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -737,6 +737,11 @@ function post_process_select_init(name) { $("#" + name + "_default").show(); } +function post_process_select_init_inv(name) { + $("#" + name + "_manual").show(); + $("#" + name + "_default").hide(); +} + function post_process_select_init_unit(name, selected) { // Manual mode is hidden by default diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index cb09cfb944..8e4046987e 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -1816,6 +1816,8 @@ CREATE TABLE IF NOT EXISTS `tplanned_downtime` ( `type_execution` VARCHAR(100) NOT NULL DEFAULT 'once', `type_periodicity` VARCHAR(100) NOT NULL DEFAULT 'weekly', `id_user` VARCHAR(255) NOT NULL DEFAULT '0', + `cron_interval_from` VARCHAR(100) DEFAULT '', + `cron_interval_to` VARCHAR(100) DEFAULT '', PRIMARY KEY ( `id` ) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm index 168dd1ed63..6ee263dc0f 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -228,6 +228,8 @@ our @EXPORT = qw( pandora_planned_downtime_monthly_stop pandora_planned_downtime_weekly_start pandora_planned_downtime_weekly_stop + pandora_planned_downtime_cron_start + pandora_planned_downtime_cron_stop pandora_process_alert pandora_process_module pandora_reset_server @@ -2224,6 +2226,108 @@ sub pandora_process_module ($$$$$$$$$;$) { } } +######################################################################## +=head2 C<< pandora_planned_downtime_cron_start (I<$pa_config>, I<$dbh>) >> + +Start the planned downtime, the cron type. + +=cut +######################################################################## +sub pandora_planned_downtime_cron_start($$) { + my ($pa_config, $dbh) = @_; + + my $utimestamp = time(); + + # Start pending downtimes + my @downtimes = get_db_rows($dbh, 'SELECT * + FROM tplanned_downtime + WHERE type_execution = ? + AND executed = 0', 'cron'); + + foreach my $downtime (@downtimes) { + my $start_downtime = PandoraFMS::Tools::cron_check($downtime->{'cron_interval_from'}, $utimestamp); + + if ($start_downtime) { + if (!defined($downtime->{'description'})) { + $downtime->{'description'} = "N/A"; + } + + if (!defined($downtime->{'name'})) { + $downtime->{'name'} = "N/A"; + } + + logger($pa_config, "Starting planned downtime '" . $downtime->{'name'} . "'.", 10); + + db_do($dbh, 'UPDATE tplanned_downtime + SET executed = 1 + WHERE id = ?', $downtime->{'id'}); + pandora_event ($pa_config, + "Server ".$pa_config->{'servername'}." started planned downtime: ".safe_output($downtime->{'name'}), 0, 0, 1, 0, 0, 'system', 0, $dbh); + + if ($downtime->{'type_downtime'} eq "quiet") { + pandora_planned_downtime_set_quiet_elements($pa_config, + $dbh, $downtime->{'id'}); + } + elsif (($downtime->{'type_downtime'} eq "disable_agents") + || ($downtime->{'type_downtime'} eq "disable_agents_alerts")) { + pandora_planned_downtime_set_disabled_elements($pa_config, + $dbh, $downtime); + } + } + } +} + +######################################################################## +=head2 C<< pandora_planned_downtime_cron_stop (I<$pa_config>, I<$dbh>) >> + +Stop the planned downtime, the cron type. + +=cut +######################################################################## +sub pandora_planned_downtime_cron_stop($$) { + my ($pa_config, $dbh) = @_; + + my $utimestamp = time(); + + # Stop executed downtimes + my @downtimes = get_db_rows($dbh, 'SELECT * + FROM tplanned_downtime + WHERE type_execution = ? + AND executed = 1', 'cron'); + + foreach my $downtime (@downtimes) { + my $stop_downtime = PandoraFMS::Tools::cron_check($downtime->{'cron_interval_to'}, $utimestamp); + + if ($stop_downtime) { + if (!defined($downtime->{'description'})) { + $downtime->{'description'} = "N/A"; + } + + if (!defined($downtime->{'name'})) { + $downtime->{'name'} = "N/A"; + } + + logger($pa_config, "Stopping planned cron downtime '" . $downtime->{'name'} . "'.", 10); + + db_do($dbh, 'UPDATE tplanned_downtime + SET executed = 0 + WHERE id = ?', $downtime->{'id'}); + pandora_event ($pa_config, + "Server ".$pa_config->{'servername'}." stopped planned downtime: ".safe_output($downtime->{'name'}), 0, 0, 1, 0, 0, 'system', 0, $dbh); + + if ($downtime->{'type_downtime'} eq "quiet") { + pandora_planned_downtime_unset_quiet_elements($pa_config, + $dbh, $downtime->{'id'}); + } + elsif (($downtime->{'type_downtime'} eq "disable_agents") + || ($downtime->{'type_downtime'} eq "disable_agents_alerts")) { + pandora_planned_downtime_unset_disabled_elements($pa_config, + $dbh, $downtime); + } + } + } +} + ######################################################################## =head2 C<< pandora_planned_downtime_disabled_once_stop (I<$pa_config>, I<$dbh>) >> @@ -2242,11 +2346,11 @@ sub pandora_planned_downtime_disabled_once_stop($$) { AND type_execution = ? AND executed = 1 AND date_to <= ?', 'quiet', 'once', $utimestamp); - + foreach my $downtime (@downtimes) { logger($pa_config, "Ending planned downtime '" . $downtime->{'name'} . "'.", 10); - + db_do($dbh, 'UPDATE tplanned_downtime SET executed = 0 WHERE id = ?', $downtime->{'id'}); @@ -2471,7 +2575,7 @@ sub pandora_planned_downtime_quiet_once_stop($$) { WHERE type_downtime = ? AND type_execution = ? AND executed = 1 AND date_to <= ?', 'quiet', 'once', $utimestamp); - + foreach my $downtime (@downtimes) { if (!defined($downtime->{'description'})) { $downtime->{'description'} = "N/A"; @@ -2483,7 +2587,6 @@ sub pandora_planned_downtime_quiet_once_stop($$) { logger($pa_config, "[PLANNED_DOWNTIME] " . "Starting planned downtime '" . $downtime->{'name'} . "'.", 10); - db_do($dbh, 'UPDATE tplanned_downtime SET executed = 0 WHERE id = ?', $downtime->{'id'}); @@ -2564,6 +2667,7 @@ sub pandora_planned_downtime_monthly_start($$) { WHERE type_periodicity = ? AND executed = 0 AND type_execution <> ' . $RDBMS_QUOTE_STRING . 'once' . $RDBMS_QUOTE_STRING . ' + AND type_execution <> ' . $RDBMS_QUOTE_STRING . 'cron' . $RDBMS_QUOTE_STRING . ' AND ((periodically_day_from = ? AND periodically_time_from <= ?) OR (periodically_day_from < ?)) AND ((periodically_day_to = ? AND periodically_time_to >= ?) OR (periodically_day_to > ?))', 'monthly', @@ -2641,12 +2745,13 @@ sub pandora_planned_downtime_monthly_stop($$) { WHERE type_periodicity = ? AND executed = 1 AND type_execution <> ? + AND type_execution <> ? AND (((periodically_day_from = ? AND periodically_time_from > ?) OR (periodically_day_from > ?)) OR ((periodically_day_to = ? AND periodically_time_to < ?) OR (periodically_day_to < ?)))', - 'monthly', 'once', + 'monthly', 'once', 'cron', $number_day_month, $time, $number_day_month, $number_day_month, $time, $number_day_month); - + foreach my $downtime (@downtimes) { if (!defined($downtime->{'description'})) { $downtime->{'description'} = "N/A"; @@ -2701,7 +2806,8 @@ sub pandora_planned_downtime_weekly_start($$) { FROM tplanned_downtime WHERE type_periodicity = ? AND type_execution <> ? - AND executed = 0', 'weekly', 'once'); + AND type_execution <> ? + AND executed = 0', 'weekly', 'once', 'cron'); foreach my $downtime (@downtimes) { my $across_date = $downtime->{'periodically_time_from'} gt $downtime->{'periodically_time_to'} ? 1 : 0 ; @@ -2811,8 +2917,9 @@ sub pandora_planned_downtime_weekly_stop($$) { FROM tplanned_downtime WHERE type_periodicity = ? AND type_execution <> ? - AND executed = 1', 'weekly', 'once'); - + AND type_execution <> ? + AND executed = 1', 'weekly', 'once', 'cron'); + foreach my $downtime (@downtimes) { my $across_date = $downtime->{'periodically_time_from'} gt $downtime->{'periodically_time_to'} ? 1 : 0; @@ -2922,6 +3029,9 @@ sub pandora_planned_downtime ($$) { pandora_planned_downtime_weekly_stop($pa_config, $dbh); pandora_planned_downtime_weekly_start($pa_config, $dbh); + + pandora_planned_downtime_cron_start($pa_config, $dbh); + pandora_planned_downtime_cron_stop($pa_config, $dbh); } ######################################################################## diff --git a/pandora_server/lib/PandoraFMS/Tools.pm b/pandora_server/lib/PandoraFMS/Tools.pm index 59bdf48fff..f922e75854 100755 --- a/pandora_server/lib/PandoraFMS/Tools.pm +++ b/pandora_server/lib/PandoraFMS/Tools.pm @@ -170,6 +170,12 @@ our @EXPORT = qw( p_encode_json p_decode_json get_server_name + check_cron_syntax + check_cron_interval + check_cron_skips + check_cron_value + check_cron_element + cron_check ); # ID of the different servers @@ -2688,6 +2694,125 @@ sub p_decode_json { return $decoded_data; } +################################################################################ +# Verify cron syntax +################################################################################ +sub check_cron_syntax ($) { + my ($cron) = @_; + + return 0 if !defined ($cron); + return ($cron =~ m/^(\d|\*|-|\/|,)+ (\d|\*|-|\/|,)+ (\d|\*|-|\/|,)+ (\d|\*|-|\/|,)+ (\d|\*|-|\/|,)+$/); +} + +################################################################################ +# Check if rule is interval rule +################################################################################ +sub check_cron_interval { + my ($elem, $elem_curr_time) = @_; + + # Not a range + if ($elem !~ /(\d+)\-(\d+)/) { + return 0; + } + + my ($down, $up) = ($1, $2); + + if ($elem_curr_time >= $down && $elem_curr_time <=$up) { + return 1; + } else { + return 0; + } +} + + +################################################################################ +# Check if rule is skip rule +################################################################################ +sub check_cron_skips { + my ($elem, $elem_curr_time) = @_; + + if ($elem !~ /(\d+|\*)\/(\d+)/) { + return 0; + } + + my ($init, $skip) = ($1, $2); + + if ($init eq '*') { + $init = 0; + } + + if ($elem_curr_time == $init || (($elem_curr_time - $init) % $skip == 0 && $elem_curr_time > $init)) { + return 1; + } else { + return 0; + } +} + +################################################################################ +# Check if rule is value rule +################################################################################ +sub check_cron_value { + my ($elem, $elem_curr_time) = @_; + + if ($elem eq '*' || $elem eq $elem_curr_time) { + return 1; + } else { + return 0; + } + +} + +############################################################################### +# Check if element match rules +############################################################################### +sub check_cron_element { + my ($elem_cron, $elem_curr_time) = @_; + + my @elems = (split (/,/, $elem_cron)); + + my $elem_res = 0; + foreach my $elem (@elems) { + + if (check_cron_interval($elem, $elem_curr_time) || check_cron_skips($elem, $elem_curr_time) || check_cron_value($elem, $elem_curr_time)) { + $elem_res = 1; + + last; + } + } + + return $elem_res; +} + +############################################################################### +# Check if timestamp matches cron command +############################################################################### +sub cron_check { + my ($cron, $utimestamp) = @_; + + if (!check_cron_syntax($cron)) { + return 0; + } + + my @time = localtime($utimestamp); + + my ($minute, $hour, $mday, $month, $wday) = split (/\s/, $cron); + + my $res = 0; + + $res += check_cron_element($minute, $time[1]); + $res += check_cron_element($hour, $time[2]); + $res += check_cron_element($mday, $time[3]); + $res += check_cron_element($month, $time[4]+1); + $res += check_cron_element($wday, $time[6]); + + if ($res < 5) { + return 0; + } else { + return 1; + + } +} + ################################################################################ # String name for server type. ################################################################################ From 9f28e6f7fb76e89a9463107f0ae62f7090bb2404 Mon Sep 17 00:00:00 2001 From: "alejandro.campos@artica.es" Date: Wed, 17 Aug 2022 13:31:12 +0200 Subject: [PATCH 2/3] minor fix --- .../agentes/planned_downtime.editor.php | 153 ++++++++++-------- 1 file changed, 84 insertions(+), 69 deletions(-) diff --git a/pandora_console/godmode/agentes/planned_downtime.editor.php b/pandora_console/godmode/agentes/planned_downtime.editor.php index f2d7109406..ee4848259d 100644 --- a/pandora_console/godmode/agentes/planned_downtime.editor.php +++ b/pandora_console/godmode/agentes/planned_downtime.editor.php @@ -275,12 +275,11 @@ if ($create_downtime || $update_downtime) { ); } else { $sql = ''; + $error_cron_from = false; + $error_cron_to = false; + $error_field = ''; if ($type_execution === 'cron') { - $error_cron_from = false; - $error_cron_to = false; - $error_field = ''; - // Validate 'from' cron values. $hour_from = io_safe_output(trim($hour_from)); if (preg_match('/^((?:([0-1]?[0-9]|2[0-3])|\*)\s*(?:(?:[\/-]([0-1]?[0-9]|2[0-3])))?\s*)$/', $hour_from, $matches) !== 1) { @@ -451,22 +450,6 @@ if ($create_downtime || $update_downtime) { } } - if ($error_cron_from === true) { - ui_print_error_message( - __('Downtime start cron expression is not correct').': '.$error_field - ); - } - - if ($error_cron_to === true) { - ui_print_error_message( - __('Downtime stop cron expression is not correct').': '.$error_field - ); - } - - if ($error_cron_to === true || $error_cron_from) { - return; - } - $cron_interval_from = io_safe_output($minute_from.' '.$hour_from.' '.$mday_from.' '.$month_from.' '.$wday_from); $cron_interval_to = io_safe_output($minute_to.' '.$hour_to.' '.$mday_to.' '.$month_to.' '.$wday_to); } @@ -490,52 +473,68 @@ if ($create_downtime || $update_downtime) { return; } - if (trim(io_safe_output($name)) != '') { - if (!$check) { - $values = [ - 'name' => $name, - 'description' => $description, - 'date_from' => $datetime_from, - 'date_to' => $datetime_to, - 'executed' => 0, - 'id_group' => $id_group, - 'only_alerts' => 0, - 'monday' => $monday, - 'tuesday' => $tuesday, - 'wednesday' => $wednesday, - 'thursday' => $thursday, - 'friday' => $friday, - 'saturday' => $saturday, - 'sunday' => $sunday, - 'periodically_time_from' => $periodically_time_from, - 'periodically_time_to' => $periodically_time_to, - 'periodically_day_from' => $periodically_day_from, - 'periodically_day_to' => $periodically_day_to, - 'type_downtime' => $type_downtime, - 'type_execution' => $type_execution, - 'type_periodicity' => $type_periodicity, - 'id_user' => $config['id_user'], - 'cron_interval_from' => $cron_interval_from, - 'cron_interval_to' => $cron_interval_to, - ]; - if ($config['dbtype'] == 'oracle') { - $values['periodically_time_from'] = '1970/01/01 '.$values['periodically_time_from']; - $values['periodically_time_to'] = '1970/01/01 '.$values['periodically_time_to']; - } - - $result = db_process_sql_insert( - 'tplanned_downtime', - $values - ); - } else { + if ($error_cron_to === true || $error_cron_from === true) { + if ($error_cron_from === true) { ui_print_error_message( - __('Each scheduled downtime must have a different name') + __('Downtime start cron expression is not correct').': '.$error_field ); } + + if ($error_cron_to === true) { + ui_print_error_message( + __('Downtime stop cron expression is not correct').': '.$error_field + ); + } + + $result = false; } else { - ui_print_error_message( - __('Scheduled downtime must have a name') - ); + if (trim(io_safe_output($name)) != '') { + if (!$check) { + $values = [ + 'name' => $name, + 'description' => $description, + 'date_from' => $datetime_from, + 'date_to' => $datetime_to, + 'executed' => 0, + 'id_group' => $id_group, + 'only_alerts' => 0, + 'monday' => $monday, + 'tuesday' => $tuesday, + 'wednesday' => $wednesday, + 'thursday' => $thursday, + 'friday' => $friday, + 'saturday' => $saturday, + 'sunday' => $sunday, + 'periodically_time_from' => $periodically_time_from, + 'periodically_time_to' => $periodically_time_to, + 'periodically_day_from' => $periodically_day_from, + 'periodically_day_to' => $periodically_day_to, + 'type_downtime' => $type_downtime, + 'type_execution' => $type_execution, + 'type_periodicity' => $type_periodicity, + 'id_user' => $config['id_user'], + 'cron_interval_from' => $cron_interval_from, + 'cron_interval_to' => $cron_interval_to, + ]; + if ($config['dbtype'] == 'oracle') { + $values['periodically_time_from'] = '1970/01/01 '.$values['periodically_time_from']; + $values['periodically_time_to'] = '1970/01/01 '.$values['periodically_time_to']; + } + + $result = db_process_sql_insert( + 'tplanned_downtime', + $values + ); + } else { + ui_print_error_message( + __('Each scheduled downtime must have a different name') + ); + } + } else { + ui_print_error_message( + __('Scheduled downtime must have a name') + ); + } } } else if ($update_downtime) { $old_downtime = db_get_row('tplanned_downtime', 'id', $id_downtime); @@ -609,15 +608,31 @@ if ($create_downtime || $update_downtime) { } } - if ($is_running) { + if ($error_cron_to === true || $error_cron_from === true) { + if ($error_cron_from === true) { + ui_print_error_message( + __('Downtime start cron expression is not correct').': '.$error_field + ); + } + + if ($error_cron_to === true) { + ui_print_error_message( + __('Downtime stop cron expression is not correct').': '.$error_field + ); + } + $result = false; } else { - if (!empty($values)) { - $result = db_process_sql_update( - 'tplanned_downtime', - $values, - ['id' => $id_downtime] - ); + if ($is_running) { + $result = false; + } else { + if (!empty($values)) { + $result = db_process_sql_update( + 'tplanned_downtime', + $values, + ['id' => $id_downtime] + ); + } } } } From d7ab8dcc0307fed60dbbc5c464b5aace87db0513 Mon Sep 17 00:00:00 2001 From: "alejandro.campos@artica.es" Date: Thu, 1 Sep 2022 13:23:14 +0200 Subject: [PATCH 3/3] fixed php 7 error --- pandora_console/include/functions_html.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 9bf9b374b6..c519645560 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -2318,7 +2318,7 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', false, false, 0, - 'Valid values: [0-23], [0-23]-[0-23], *, or step value (example: */3, 10/5)', + 'Valid values: [0-23], [0-23]-[0-23], *, or step value (example: */3, 10/5)' ); $table->data[0][1] = html_print_extended_select_for_downtime_cron( @@ -2334,7 +2334,7 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', false, false, 0, - 'Valid values: [0-59], [0-59]-[0-59], *, or step value (example: */5, 10/1)', + 'Valid values: [0-59], [0-59]-[0-59], *, or step value (example: */5, 10/1)' ); $table->data[0][2] = html_print_extended_select_for_downtime_cron( @@ -2350,7 +2350,7 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', false, false, 0, - 'Valid values: [1-31], [1-31]-[1-31], *, or step value (example: */5, 7/2)', + 'Valid values: [1-31], [1-31]-[1-31], *, or step value (example: */5, 7/2)' ); $table->data[0][3] = html_print_extended_select_for_downtime_cron( @@ -2366,7 +2366,7 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', false, false, 0, - 'Valid values: [1-12], [1-12]-[1-12], *, or step value (example: */3, 9/1)', + 'Valid values: [1-12], [1-12]-[1-12], *, or step value (example: */3, 9/1)' ); $table->data[0][4] = html_print_extended_select_for_downtime_cron( @@ -2382,7 +2382,7 @@ function html_print_extended_select_for_cron($hour='*', $minute='*', $mday='*', false, false, 0, - 'Valid values: [0-6], [0-6]-[0-6], *, or step value (example: */2, 3/1)', + 'Valid values: [0-6], [0-6]-[0-6], *, or step value (example: */2, 3/1)' ); }