Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/.phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
parameters:
level: 6
paths:
- .
- %currentWorkingDirectory%/setup.php
- %currentWorkingDirectory%/functions.php
- %currentWorkingDirectory%/maint.php
excludePaths:
- vendor
- locales
Expand Down
18 changes: 3 additions & 15 deletions .github/workflows/plugin-ci-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ jobs:
composer validate --strict || true
fi

- name: Install Composer Dependencies
- name: Install Composer Dependencies for Cacti
run: |
cd ${{ github.workspace }}/cacti
if [ -f composer.json ]; then
Expand Down Expand Up @@ -181,22 +181,10 @@ jobs:
exit 1
fi

- name: Verify Maint Plugin Composer Setup
run: |
ls -la ${{ github.workspace }}/cacti/plugins/maint
cat ${{ github.workspace }}/cacti/plugins/maint/composer.json

- name: Install Maint Plugin Composer Dependencies
run: composer install --prefer-dist --no-progress --no-interaction
- name: Install Plugin Composer Dependencies
run: composer install --prefer-dist --no-progress
working-directory: ${{ github.workspace }}/cacti/plugins/maint
env:
COMPOSER_NO_DEV: 0

- name: Verify Maint Plugin Vendor Binaries
run: |
ls -la ${{ github.workspace }}/cacti/plugins/maint/vendor
ls -la ${{ github.workspace }}/cacti/plugins/maint/vendor/bin

- name: Run Linter on base code
run: composer run-script lint
working-directory: ${{ github.workspace }}/cacti/plugins/maint
Expand Down
9 changes: 4 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
"description": "Cacti maintenance window plugin.",
"type": "project",
"license": "GPL-2.0-or-later",
"require": {},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.60",
"friendsofphp/php-cs-fixer": "^3.93",
"phpstan/phpstan": "^1.11",
"overtrue/phplint": "^9.2"
},
"scripts": {
"lint": "./vendor/bin/phplint -c .github/.phplint.yml",
"phpcsfixer": "./vendor/bin/php-cs-fixer fix --dry-run --diff --config .github/.php-cs-fixer.php",
"phpstan": "./vendor/bin/phpstan analyse -c .github/.phpstan.neon"
"lint": "bash -c 'cd ../../ && plugins/maint/vendor/bin/phplint plugins/maint --exclude=vendor'",
"phpcsfixer": "bash -c 'cd ../../ && plugins/maint/vendor/bin/php-cs-fixer fix --dry-run --diff --config=.php-cs-fixer.php plugins/maint'",
"phpstan": "bash -c 'cd ../../ && plugins/maint/vendor/bin/phpstan analyse --level=6 plugins/maint'"
}
}
188 changes: 115 additions & 73 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,92 +24,134 @@
+-------------------------------------------------------------------------+
*/

function plugin_maint_check_cacti_host($host)
{
return plugin_maint_check_host(1, $host);
/**
* Check if a Cacti host is in maintenance
*
* This is called via the 'is_device_in_maintenance' hook.
*
* @param int $host Host ID to check
*
* @return bool True if host is in active maintenance, false otherwise
*/
function plugin_maint_check_cacti_host(int $host): bool {
return plugin_maint_check_host(1, $host);
}

function plugin_maint_check_webseer_url($host)
{
return plugin_maint_check_host(2, $host);
/**
* Check if a WebSeer URL is in maintenance
*
* @param int $host WebSeer URL ID to check
*
* @return bool True if URL is in active maintenance, false otherwise
*/
function plugin_maint_check_webseer_url(int $host): bool {
return plugin_maint_check_host(2, $host);
}

function plugin_maint_check_servcheck_test($host)
{
return plugin_maint_check_host(3, $host);
/**
* Check if a Servcheck test is in maintenance
*
* @param int $host Servcheck test ID to check
*
* @return bool True if test is in active maintenance, false otherwise
*/
function plugin_maint_check_servcheck_test(int $host): bool {
return plugin_maint_check_host(3, $host);
}


function plugin_maint_check_host($type, $host)
{
$schedules = db_fetch_assoc_prepared(
'SELECT *
/**
* Check if a host is in maintenance based on type
*
* @param int $type Host type (1=Cacti host, 2=WebSeer URL, 3=Servcheck test)
* @param int $host Host/URL/Test ID to check
*
* @return bool True if host is in active maintenance schedule, false otherwise
*/
function plugin_maint_check_host(int $type, int $host): bool {
$schedules = db_fetch_assoc_prepared(
'SELECT *
FROM plugin_maint_hosts
WHERE TYPE = ?
AND (host = ? OR host = 0)',
[$type, $host],
);

if (!empty($schedules)) {
foreach ($schedules as $s) {
if (plugin_maint_check_schedule($s['schedule'])) {
return true;
}
}
}
return false;
[$type, $host],
);

if (!empty($schedules)) {
foreach ($schedules as $s) {
if (plugin_maint_check_schedule($s['schedule'])) {
return true;
}
}
}

return false;
}

function plugin_maint_check_schedule($schedule)
{
$sc = db_fetch_row_prepared(
'SELECT *
/**
* Check if a maintenance schedule is currently active
*
* Handles both one-time and recurring schedules.
* For recurring schedules that have passed, automatically calculates
* and updates the next occurrence.
*
* @param int $schedule Schedule ID to check
*
* @return bool True if schedule is active now, false otherwise
*/
function plugin_maint_check_schedule(int $schedule): bool {
$sc = db_fetch_row_prepared(
'SELECT *
FROM plugin_maint_schedules
WHERE enabled = \'on\' AND id = ?',
[$schedule],
);

if (!empty($sc)) {
$t = time();
switch ($sc['mtype']) {
case 1:
if ($t > $sc['stime'] && $t < $sc['etime']) {
return true;
}
break;

case 2: // Recurring
/* past, calculate next */
if ($sc['etime'] < $t) {
/* convert start and end to local so that hour stays same for add days across daylight saving time change */
$starttimelocal = (new DateTime('@' . strval($sc['stime'])))->setTimezone(new DateTimeZone(date_default_timezone_get()));
$endtimelocal = (new DateTime('@' . strval($sc['etime'])))->setTimezone(new DateTimeZone(date_default_timezone_get()));
$nowtime = new DateTime();
/* add interval days */
$addday = new DateInterval('P' . strval($sc['minterval'] / 86400) . 'D');
while ($endtimelocal < $nowtime) {
$starttimelocal = $starttimelocal->add($addday);
$endtimelocal = $endtimelocal->add($addday);
}

$sc['stime'] = $starttimelocal->getTimestamp();
$sc['etime'] = $endtimelocal->getTimestamp();
/* save next interval so not need to recalculate */
db_execute_prepared(
'UPDATE plugin_maint_schedules
[$schedule],
);

if (!empty($sc)) {
$t = time();

switch ($sc['mtype']) {
case 1:
if ($t > $sc['stime'] && $t < $sc['etime']) {
return true;
}

break;
case 2: // Recurring
// past, calculate next
if ($sc['etime'] < $t) {
// convert start and end to local so that hour stays same for add days across daylight saving time change
$starttimelocal = (new DateTime('@' . strval($sc['stime'])))->setTimezone(new DateTimeZone(date_default_timezone_get()));
$endtimelocal = (new DateTime('@' . strval($sc['etime'])))->setTimezone(new DateTimeZone(date_default_timezone_get()));
$nowtime = new DateTime();
// add interval days
$addday = new DateInterval('P' . strval($sc['minterval'] / 86400) . 'D');

while ($endtimelocal < $nowtime) {
$starttimelocal = $starttimelocal->add($addday);
$endtimelocal = $endtimelocal->add($addday);
}

$sc['stime'] = $starttimelocal->getTimestamp();
$sc['etime'] = $endtimelocal->getTimestamp();
// save next interval so not need to recalculate
db_execute_prepared(
'UPDATE plugin_maint_schedules
SET stime = ?, etime = ?
WHERE id = ?',
[$sc['stime'], $sc['etime'], $schedule],
);
/* format yyyy-mm-dd hh:mm */
cacti_log('INFO: Maintenance schedule "' . $sc['name'] . '" Next start ' . $starttimelocal->format('Y-m-d H:i')
. ' End ' . $endtimelocal->format('Y-m-d H:i'), false, 'MAINT');
}
if ($t > $sc['stime'] && $t < $sc['etime']) {
return true;
}
break;
}
}
return false;
[$sc['stime'], $sc['etime'], $schedule],
);
// format yyyy-mm-dd hh:mm
cacti_log('INFO: Maintenance schedule "' . $sc['name'] . '" Next start ' . $starttimelocal->format('Y-m-d H:i')
. ' End ' . $endtimelocal->format('Y-m-d H:i'), false, 'MAINT');
}

if ($t > $sc['stime'] && $t < $sc['etime']) {
return true;
}

break;
}
}

return false;
}
Loading