From 524819e212c34aaba5a9340926374ec52bfbf3e6 Mon Sep 17 00:00:00 2001 From: nzxl101 Date: Fri, 27 Dec 2024 13:04:09 +0100 Subject: [PATCH] Add minimum age check for updates --- root/app/www/public/ajax/containers.php | 20 ++++++++++++---- root/app/www/public/crons/pulls.php | 19 ++++++++++++++- root/app/www/public/functions/regctl.php | 23 +++++++++++++++++++ root/app/www/public/js/containers.js | 19 +++++++++++++++ .../migrations/009_container_min_age.php | 23 +++++++++++++++++++ 5 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 root/app/www/public/migrations/009_container_min_age.php diff --git a/root/app/www/public/ajax/containers.php b/root/app/www/public/ajax/containers.php index 30833c4..7d71c63 100644 --- a/root/app/www/public/ajax/containers.php +++ b/root/app/www/public/ajax/containers.php @@ -937,6 +937,7 @@ Name Update Frequency + Minimum Age (Days) @@ -961,6 +962,9 @@ + + +
-
+
+
+ + + +
$hash])['result']; - if ($container['updates'] != $updates || $container['frequency'] != $frequency) { - apiRequest('database-updateContainer', [], ['hash' => $hash, 'updates' => $updates, 'frequency' => $database->prepare($frequency)]); + if ($container['updates'] != $updates || $container['frequency'] != $frequency || $container['minage'] != $minage) { + apiRequest('database-updateContainer', [], ['hash' => $hash, 'updates' => $updates, 'frequency' => $database->prepare($frequency), 'minage' => $database->prepare($minage)]); } } } diff --git a/root/app/www/public/crons/pulls.php b/root/app/www/public/crons/pulls.php index a489a73..815a255 100644 --- a/root/app/www/public/crons/pulls.php +++ b/root/app/www/public/crons/pulls.php @@ -114,6 +114,19 @@ 'imageDigest' => $imageDigest ]; + //-- SKIP IF AGE < MINAGE + $digestTag = explode(':', $image)[0] . '@' . $regctlDigest; + $checkImageAge = regctlGetCreatedDate($digestTag); + if ($checkImageAge < $containerSettings['minage']) { + $msg = 'Skipping container update: ' . $containerState['Names'] . ' (does not meet the minimum age requirement of '.$containerSettings['minage'].' days, got '.$checkImageAge.' days)'; + logger(CRON_PULLS_LOG, $msg); + echo date('c') . ' ' . $msg . "\n"; + + if ($containerSettings['updates'] == 1) { + $containerSettings['updates'] = 2; + } + } + //-- DONT AUTO UPDATE THIS CONTAINER, CHECK ONLY if (skipContainerActions($image, $skipContainerActions)) { if ($isDockwatch) { @@ -314,7 +327,11 @@ break; case 2: //-- Check for updates if (apiRequest('database-isNotificationTriggerEnabled', ['trigger' => 'updates'])['result'] && !$containerSettings['disableNotifications'] && $inspectImage[0]['Id'] != $inspectContainer[0]['Image']) { - $notify['available'][] = ['container' => $containerState['Names']]; + $notify['available'][] = [ + 'container' => $containerState['Names'], + 'minage' => $containerSettings['minage'] ?? 0, + 'currentage' => $checkImageAge ?? 0 + ]; } break; } diff --git a/root/app/www/public/functions/regctl.php b/root/app/www/public/functions/regctl.php index 865ef68..a2c482d 100644 --- a/root/app/www/public/functions/regctl.php +++ b/root/app/www/public/functions/regctl.php @@ -25,3 +25,26 @@ function regctlCheck($image) return $regctl; } + +function regctlGetCreatedDate($image) +{ + global $shell; + + if (!file_exists(REGCTL_PATH . REGCTL_BINARY)) { + return 'Error: regctl binary (\'' . REGCTL_PATH . REGCTL_BINARY . '\') is not avaialable or there is a permissions error'; + } + + $regctl = $shell->exec(REGCTL_PATH . REGCTL_BINARY . ' image inspect ' . $image . ' | jq -r \'.created\''); + + //-- RETRY + if (!$regctl) { + sleep(3); + $regctl = $shell->exec(REGCTL_PATH . REGCTL_BINARY . ' image inspect ' . $image . ' | jq -r \'.created\''); + } + + $created = new DateTime($regctl); + $now = new DateTime(); + $diff = $created->diff($now); + + return $diff->days; +} diff --git a/root/app/www/public/js/containers.js b/root/app/www/public/js/containers.js index f532151..d0f70d3 100644 --- a/root/app/www/public/js/containers.js +++ b/root/app/www/public/js/containers.js @@ -567,6 +567,25 @@ function massChangeFrequency(option) } } // --------------------------------------------------------------------------------------------- +function massChangeMinAge(option) +{ + const minage = $('#container-update-minage-all').val(); + + switch (option) { + case 1: //-- SELECTED + $.each($('.container-update-checkbox'), function () { + if ($(this).prop('checked')) { + const hash = $(this).attr('id').match(/container-update-(.+)-checkbox/); + $('#container-update-minage-' + hash[1]).val(minage); + } + }); + break; + case 2: //-- ALL + $('.container-update-minage').val(minage) + break; + } +} +// --------------------------------------------------------------------------------------------- function containerInfo(hash) { pageLoadingStart(); diff --git a/root/app/www/public/migrations/009_container_min_age.php b/root/app/www/public/migrations/009_container_min_age.php new file mode 100644 index 0000000..4a28bb8 --- /dev/null +++ b/root/app/www/public/migrations/009_container_min_age.php @@ -0,0 +1,23 @@ +[Q] ' . preg_replace('!\s+!', ' ', $query)); + + $database->query($query); + + if ($database->error() != 'not an error') { + logger(MIGRATION_LOG, '[R] ' . $database->error(), 'error'); + } else { + logger(MIGRATION_LOG, '[R] query applied!'); + } +}