diff options
Diffstat (limited to 'modules-available/systemstatus')
18 files changed, 632 insertions, 150 deletions
diff --git a/modules-available/systemstatus/hooks/cron.inc.php b/modules-available/systemstatus/hooks/cron.inc.php new file mode 100644 index 00000000..91e069d4 --- /dev/null +++ b/modules-available/systemstatus/hooks/cron.inc.php @@ -0,0 +1,6 @@ +<?php + +if ((int)gmdate('i') < 5) { + // Don't care about task, this will register a callback + SystemStatus::getUpgradableTask(); +}
\ No newline at end of file diff --git a/modules-available/systemstatus/hooks/main-warning.inc.php b/modules-available/systemstatus/hooks/main-warning.inc.php index 5707c7d2..6b0ac981 100644 --- a/modules-available/systemstatus/hooks/main-warning.inc.php +++ b/modules-available/systemstatus/hooks/main-warning.inc.php @@ -1,9 +1,19 @@ <?php -if (file_exists('/run/reboot-required.pkgs')) { - $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $lines = array_unique($lines); - Message::addInfo('systemstatus.update-reboot-required', true, implode(', ', $lines)); +$cnt = SystemStatus::getUpgradableSecurityCount(); +if ($cnt > 0) { + Message::addWarning('systemstatus.security-updates-available', true, $cnt); +} + +$pkgs = SystemStatus::getPackagesRequiringReboot(); +if (!empty($pkgs)) { + Message::addInfo('systemstatus.update-reboot-required', true, implode(', ', $pkgs)); +} + +$aptTs = SystemStatus::getAptLastDbUpdateTime(); +if ($aptTs + 864000 < time()) { + // No update for 10 days + Message::addWarning('systemstatus.apt-db-out-of-date', true, Util::prettyTime($aptTs)); } if (SystemStatus::diskStat($systemUsage, $storeUsage, $current, $wanted)) { diff --git a/modules-available/systemstatus/inc/systemstatus.inc.php b/modules-available/systemstatus/inc/systemstatus.inc.php index 4413af5f..c50e0ef6 100644 --- a/modules-available/systemstatus/inc/systemstatus.inc.php +++ b/modules-available/systemstatus/inc/systemstatus.inc.php @@ -3,6 +3,8 @@ class SystemStatus { + const PROP_UPGRADABLE_COUNT = 'systemstatus.upgradable-count'; + /** * Collect status about the disk and vmstore. * The *Usage vars are filled with arrays with keys mountPoint, fileSystem, @@ -13,27 +15,28 @@ class SystemStatus * @param string|false $wantedSource What should be mounted as vmstore (false if nothing configured) * @return bool false if querying fs data from taskmanager failed */ - public static function diskStat(&$systemUsage, &$storeUsage, &$currentSource = false, &$wantedSource = false) + public static function diskStat(&$systemUsage, &$storeUsage, &$currentSource = false, &$wantedSource = false): bool { $task = Taskmanager::submit('DiskStat'); if ($task === false) return false; $task = Taskmanager::waitComplete($task, 3000); - if (!isset($task['data']['list']) || empty($task['data']['list'])) + if (empty($task['data']['list'])) return false; $wantedSource = Property::getVmStoreUrl(); - $currentSource = false; $storeUsage = false; $systemUsage = false; if ($wantedSource === '<local>') { $storePoint = '/'; + $currentSource = $wantedSource; } else { $storePoint = CONFIG_VMSTORE_DIR; + $currentSource = false; } // Collect free space information foreach ($task['data']['list'] as $entry) { - // StorePoint is either the atual directory of the vmstore, or / if we use internal storage + // StorePoint is either the actual directory of the vmstore, or / if we use internal storage if ($entry['mountPoint'] === $storePoint) { $storeUsage = $entry; } @@ -42,12 +45,116 @@ class SystemStatus $systemUsage = $entry; } // Record what's mounted at destination, regardless of config, to indicate something is wrong - if (($currentSource === false && $wantedSource === '<local>' && $entry['mountPoint'] === '/') - || $entry['mountPoint'] === CONFIG_VMSTORE_DIR) { + if ($entry['mountPoint'] === CONFIG_VMSTORE_DIR) { $currentSource = $entry['fileSystem']; + + // If internal/local storage is used but there is a mount on CONFIG_VMSTORE_DIR, + // we assume it's on purpose like a second hdd and use that + if ($wantedSource === '<local>') { + $wantedSource = $currentSource; + $storeUsage = $entry; + } } } return true; } + /** + * Get timestamp of the available updates. This is an estimate; the downloaded apt data usually + * preserves the Last-Modified timestamp from the HTTP download of the according data. Note + * that this list gets updated whenever any available package changes, so it does not necessarily + * mean that any currently installed package can be updated when the list changes. + */ + public static function getAptLastDbUpdateTime(): int + { + $osRelease = parse_ini_file('/etc/os-release'); + $updateDbTime = 0; + foreach (glob('/var/lib/apt/lists/*_dists_' . ($osRelease['VERSION_CODENAME'] ?? '') . '*_InRelease', GLOB_NOSORT) as $f) { + $b = basename($f); + if (preg_match('/dists_[a-z]+(?:[\-_](?:updates|security))?_InRelease$/', $b)) { + $updateDbTime = max($updateDbTime, filemtime($f)); + } + } + return $updateDbTime; + } + + /** + * Get timestamp when the apt database was last attempted to be updated. This does not + * imply that the operation was successful. + */ + public static function getAptLastUpdateAttemptTime(): int + { + return (int)filemtime('/var/lib/apt/lists/partial'); + } + + /** + * Get when the dpkg database was last changed, i.e. when a package was last installed, updated or removed. + * This is an estimate as it just looks at the modification time of relevant files. It is possible these + * files get modified for other reasons. + */ + public static function getDpkgLastPackageChanges(): int + { + return (int)filemtime(file_exists('/var/log/dpkg.log') ? '/var/log/dpkg.log' : '/var/lib/dpkg/status'); + } + + /** + * Get list of packages that have been updated, but require a reboot of the system + * to fully take effect. + * @return string[] + */ + public static function getPackagesRequiringReboot(): array + { + if (!file_exists('/run/reboot-required.pkgs')) + return []; + $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + return array_unique($lines); + } + + /** + * Get a task struct querying upgradable packages. This adds + * a hook to the task to cache the number of upgradable packages + * that are security upgrades, so it is preferred to call this + * wrapper instead of running the task directly. + */ + public static function getUpgradableTask() + { + $task = Taskmanager::submit('AptGetUpgradable'); + if (Taskmanager::isTask($task)) { + TaskmanagerCallback::addCallback($task, 'ssUpgradable'); + } + return $task; + } + + /** + * Called from Taskmanager callback after invoking getUpgradableTask(). + */ + public static function setUpgradableData(array $task) + { + if (Taskmanager::isFailed($task) || !Taskmanager::isFinished($task) || !isset($task['data']['packages'])) + return; + $count = 0; + foreach ($task['data']['packages'] as $package) { + if (substr($package['source'], -9) === '-security') { + $count++; + } + } + error_log("Upgradable security count: $count, total count: " . count($task['data']['packages'])); + Property::set(self::PROP_UPGRADABLE_COUNT, $count . '|' . count($task['data']['packages']), 61); + } + + /** + * Get number of packages that can be upgraded and are security updates. + * This is a cached value and should be updated at least once an hour. + */ + public static function getUpgradableSecurityCount(): int + { + $str = Property::get(self::PROP_UPGRADABLE_COUNT); + if ($str === false) + return 0; + $p = explode('|', $str); + if (empty($p) || !is_numeric($p[0])) + return 0; + return (int)$p[0]; + } + }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/de/messages.json b/modules-available/systemstatus/lang/de/messages.json index 0aaefd23..551e937a 100644 --- a/modules-available/systemstatus/lang/de/messages.json +++ b/modules-available/systemstatus/lang/de/messages.json @@ -1,4 +1,6 @@ { + "apt-db-out-of-date": "Die Systemupdate-Datenbank ist veraltet ({{0}}). Erw\u00e4gen Sie, nach neuen Updates zu suchen, und diese zu installieren.", + "security-updates-available": "Ausstehende Sicherheitsupdates: {{0}}", "storage-low-system": "Dem Betriebssystem geht der freie Speicher aus. Nur noch {{0}} frei. Versuchen Sie, alte \"Netboot Grundsystem\"-Versionen zu l\u00f6schen.", "storage-low-vmstore": "Auf dem VMstore sind nur noch {{0}} frei", "update-reboot-required": "Das Update der folgenden Pakete erfordert einen Reboot des Servers: {{0}}" diff --git a/modules-available/systemstatus/lang/de/module.json b/modules-available/systemstatus/lang/de/module.json index 22be8a1d..3b310b1d 100644 --- a/modules-available/systemstatus/lang/de/module.json +++ b/modules-available/systemstatus/lang/de/module.json @@ -5,6 +5,7 @@ "tab_Dnbd3Log": "DNBD3 Server Log", "tab_LdadpLog": "LDAP\/AD", "tab_LighttpdLog": "lighttpd Log", + "tab_ListUpgradable": "System-Updates", "tab_Netstat": "netstat -tulpn", "tab_PsList": "ps auxf" }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/de/permissions.json b/modules-available/systemstatus/lang/de/permissions.json index 9e7c5be9..f2dd9a21 100644 --- a/modules-available/systemstatus/lang/de/permissions.json +++ b/modules-available/systemstatus/lang/de/permissions.json @@ -1,4 +1,8 @@ { + "apt.autoremove": "Nicht mehr ben\u00f6tigte Pakete deinstallieren.", + "apt.fix": "Installalations- und Abh\u00e4ngigkeitsprobleme beheben lassen.", + "apt.update": "Das System updaten.", + "apt.upgrade": "Das System mittels \"full-upgrade\" updaten.", "restart.dmsd": "bwLehrpool-Suite neustarten.", "restart.dnbd3-server": "DNBD3-Server neustarten.", "restart.ldadp": "LDADP neustarten.", @@ -12,6 +16,7 @@ "tab.dnbd3log": "Zugriff auf DNBD3 Log.", "tab.ldadplog": "Zugriff auf LDAP\/AD-Proxy Logs.", "tab.lighttpdlog": "Zugriff auf Webserver-Logs.", + "tab.listupgradable": "Zugriff auf System-Update-\u00dcbersicht.", "tab.netstat": "Zeige Ausgabe von netstat.", "tab.pslist": "Zeige Prozessliste." }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/de/template-tags.json b/modules-available/systemstatus/lang/de/template-tags.json index 6641b9e1..c94720a6 100644 --- a/modules-available/systemstatus/lang/de/template-tags.json +++ b/modules-available/systemstatus/lang/de/template-tags.json @@ -1,17 +1,28 @@ { "lang_OK": "OK", "lang_addressConfiguration": "Adresskonfiguration", + "lang_aptOutput": "apt-get Ausgabe", "lang_areYouSureReboot": "Server jetzt neustarten?", "lang_attention": "Achtung!", "lang_average": "Durchschnitt", + "lang_backToPackagelist": "Zur\u00fcck zur Update-\u00dcbersicht", "lang_capacity": "Kapazit\u00e4t", + "lang_checkForUpdates": "Auf neue Updates pr\u00fcfen", "lang_confirmRestart": "Diesen Dienst wirklich neustarten? Dies kann Auswirkungen auf den Betrieb haben.", "lang_cpuLoad": "CPU-Last", + "lang_distribution": "Distribution", "lang_dmsdUnreachable": "dmsd nicht erreichbar", + "lang_everythingUpToDate": "Das System ist auf dem aktuellen Stand", "lang_failure": "Fehler", + "lang_fixDependencies": "Installationsprobleme beheben", "lang_foundStore": "Vorgefunden:", "lang_free": "Frei", "lang_goToStoreConf": "Zur VM-Store-Konfiguration wechseln", + "lang_kernel": "Kernel", + "lang_lastPackageInstall": "Updates installiert", + "lang_lastUpdateCheck": "Letzter Update-Check", + "lang_lastestUpdate": "Neuste Updates von", + "lang_listOldWarning": "Die Update-Datenbank scheint veraltet. Es wird empfohlen, zun\u00e4chst nach Updates zu suchen.", "lang_logicCPUs": "Logische CPUs", "lang_maintenance": "Maintenance", "lang_moduleHeading": "System-Status", @@ -19,12 +30,18 @@ "lang_occupied": "Belegt", "lang_onlyOS": "Nur OS", "lang_overview": "\u00dcbersicht", + "lang_package": "Paket", + "lang_packagesNeedingReboot": "Pakete, die einen Systemneustart erfordern", "lang_ramUsage": "RAM-Nutzung", + "lang_removeUnusedPackages": "Nicht mehr ben\u00f6tigte Pakete entfernen", "lang_restart": "Neustarten", + "lang_runFullUpdate": "\"Full-Upgrade\" durchf\u00fchren", + "lang_runUpdate": "Update durchf\u00fchren", "lang_runningDownloads": "Aktive Downloads", "lang_runningUploads": "Aktive Uploads", "lang_serverReboot": "Server neustarten", "lang_services": "Dienste", + "lang_showPackageList": "Zur Update- und Paket-\u00dcbersicht", "lang_space": "Speicherplatz", "lang_storeMissingExpected": "VM-Store nicht eingebunden. Erwartet:", "lang_storeNotConfigured": "Kein VM-Store konfiguriert!", @@ -35,7 +52,9 @@ "lang_systemStoreError": "Fehler beim Ermitteln des verf\u00fcgbaren Systemspeichers", "lang_total": "Gesamt", "lang_updatedPackages": "Ausstehende Updates", + "lang_updatesWikiLink": "Mehr Informationen zu Updates im bwLehrpool-Wiki", "lang_uptimeOS": "OS Uptime", + "lang_versionFromTo": "Update-Details", "lang_vmStore": "VM-Speicher", "lang_vmStoreError": "Fehler beim Ermitteln des verf\u00fcgbaren Speicherplatzes am VM-Speicherort. Bitte \u00fcberpr\u00fcfen Sie die Konfiguration." }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/en/messages.json b/modules-available/systemstatus/lang/en/messages.json index dc9d3dd0..2afc3431 100644 --- a/modules-available/systemstatus/lang/en/messages.json +++ b/modules-available/systemstatus/lang/en/messages.json @@ -1,4 +1,6 @@ { + "apt-db-out-of-date": "The system update database is out of date ({{0}}). Consider checking for new updates and installing them.", + "security-updates-available": "Pending security updates: {{0}}", "storage-low-system": "System storage running out. Only {{0}} free. You could try deleting old Net-boot OS versions.", "storage-low-vmstore": "VMstore space is running out. Only {{0}} left.", "update-reboot-required": "Updating the following system packages requires reboot: {{0}}" diff --git a/modules-available/systemstatus/lang/en/module.json b/modules-available/systemstatus/lang/en/module.json index f5fec515..cc2b5283 100644 --- a/modules-available/systemstatus/lang/en/module.json +++ b/modules-available/systemstatus/lang/en/module.json @@ -5,6 +5,7 @@ "tab_Dnbd3Log": "DNBD3 server log", "tab_LdadpLog": "LDAP\/AD", "tab_LighttpdLog": "lighttpd log", + "tab_ListUpgradable": "System updates", "tab_Netstat": "netstat -tulpn", "tab_PsList": "ps auxf" }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/en/permissions.json b/modules-available/systemstatus/lang/en/permissions.json index d510e257..21e7538f 100644 --- a/modules-available/systemstatus/lang/en/permissions.json +++ b/modules-available/systemstatus/lang/en/permissions.json @@ -1,4 +1,8 @@ { + "apt.autoremove": "Remove packages that are no longer required.", + "apt.fix": "Try to fix installation and dependency problems.", + "apt.update": "Update system.", + "apt.upgrade": "Update system via \"full-upgrade\".", "restart.dmsd": "Restart bwLehrpool-Suite.", "restart.dnbd3-server": "Restart DNBD3 server.", "restart.ldadp": "Restart LDADP.", @@ -12,6 +16,7 @@ "tab.dnbd3log": "Show DNBD3 log.", "tab.ldadplog": "Show LDAP\/AD proxy logs.", "tab.lighttpdlog": "Show web server logs.", + "tab.listupgradable": "Show system update status.", "tab.netstat": "Show output of netstat.", "tab.pslist": "Show process list." }
\ No newline at end of file diff --git a/modules-available/systemstatus/lang/en/template-tags.json b/modules-available/systemstatus/lang/en/template-tags.json index b7f9867a..7758c71c 100644 --- a/modules-available/systemstatus/lang/en/template-tags.json +++ b/modules-available/systemstatus/lang/en/template-tags.json @@ -1,17 +1,28 @@ { "lang_OK": "OK", "lang_addressConfiguration": "Address Configuration", + "lang_aptOutput": "apt-get output", "lang_areYouSureReboot": "Reboot server now?", "lang_attention": "Attention!", "lang_average": "Average", + "lang_backToPackagelist": "Back up update page", "lang_capacity": "Capacity", + "lang_checkForUpdates": "Check for updates", "lang_confirmRestart": "Are you sure you want to restart this service? This can lead to interruptions.", "lang_cpuLoad": "CPU Load", + "lang_distribution": "Distribution", "lang_dmsdUnreachable": "dmsd not reachable", + "lang_everythingUpToDate": "Everything is up to date", "lang_failure": "Failure", + "lang_fixDependencies": "Fix installation\/dependency problems", "lang_foundStore": "Found:", "lang_free": "Free", "lang_goToStoreConf": "Go to VM store configuration", + "lang_kernel": "Kernel", + "lang_lastPackageInstall": "Updates installed", + "lang_lastUpdateCheck": "Last update check", + "lang_lastestUpdate": "Latest updates from", + "lang_listOldWarning": "The package database is out of date. Consider checking for updates before updating.", "lang_logicCPUs": "Logical CPUs", "lang_maintenance": "Maintenance", "lang_moduleHeading": "System Status", @@ -19,12 +30,18 @@ "lang_occupied": "In use", "lang_onlyOS": "OS only", "lang_overview": "Overview", + "lang_package": "Package", + "lang_packagesNeedingReboot": "Packages that require a system reboot", "lang_ramUsage": "RAM usage", + "lang_removeUnusedPackages": "Remove unused packages", "lang_restart": "Restart", + "lang_runFullUpdate": "Run \"full-upgrade\"", + "lang_runUpdate": "Run update", "lang_runningDownloads": "Running downloads", "lang_runningUploads": "Running uploads", "lang_serverReboot": "Reboot Server", "lang_services": "Services", + "lang_showPackageList": "Show updates and packages", "lang_space": "Space", "lang_storeMissingExpected": "VM store not mounted. Expected:", "lang_storeNotConfigured": "No VM store configured!", @@ -35,7 +52,9 @@ "lang_systemStoreError": "Error querying available system storage", "lang_total": "Total", "lang_updatedPackages": "Pending updates", + "lang_updatesWikiLink": "See bwLehrpool Wiki for more information regarding updates", "lang_uptimeOS": "OS uptime", + "lang_versionFromTo": "Update details", "lang_vmStore": "VM store", "lang_vmStoreError": "Error determining available space of the VM storage. Please check the configuration." }
\ No newline at end of file diff --git a/modules-available/systemstatus/page.inc.php b/modules-available/systemstatus/page.inc.php index 238537d8..f774c4e0 100644 --- a/modules-available/systemstatus/page.inc.php +++ b/modules-available/systemstatus/page.inc.php @@ -3,6 +3,8 @@ class Page_SystemStatus extends Page { + const TM_UPDATE_UUID = '345-45763457-24356-234324556'; + protected function doPreprocess() { User::load(); @@ -13,14 +15,47 @@ class Page_SystemStatus extends Page } $action = Request::post('action', false, 'string'); - if ($action === 'reboot') { + $aptAction = null; + switch ($action) { + case 'reboot': User::assertPermission("serverreboot"); $task = Taskmanager::submit('Reboot'); if (Taskmanager::isTask($task)) { Util::redirect('?do=systemstatus&taskid=' . $task['id']); } - } elseif ($action === 'service-start' || $action === 'service-restart') { + break; + case 'service-start': + case 'service-restart': $this->handleServiceAction(substr($action, 8)); + break; + case 'apt-update': + User::assertPermission('apt.update'); + $aptAction = 'UPDATE'; + break; + case 'apt-upgrade': + User::assertPermission('apt.upgrade'); + $aptAction = 'UPGRADE'; + break; + case 'apt-full-upgrade': + User::assertPermission('apt.upgrade'); + $aptAction = 'FULL_UPGRADE'; + break; + case 'apt-autoremove': + User::assertPermission('apt.autoremove'); + $aptAction = 'AUTOREMOVE'; + break; + case 'apt-fix': + User::assertPermission('apt.fix'); + $aptAction = 'FIX'; + break; + default: + } + if ($aptAction !== null) { + if (!Taskmanager::isRunning(Taskmanager::status(self::TM_UPDATE_UUID))) { + $task = Taskmanager::submit('AptUpgrade', ['mode' => $aptAction, 'id' => self::TM_UPDATE_UUID]); + Taskmanager::release($task); + } + Util::redirect('?do=systemstatus#id-ListUpgradable_pane'); } if (Request::isPost()) { Util::redirect('?do=systemstatus'); @@ -50,22 +85,24 @@ class Page_SystemStatus extends Page $data = array(); $data['taskid'] = Request::get('taskid', '', 'string'); $data['taskname'] = Request::get('taskname', 'Reboot', 'string'); - $tabs = array('DmsdLog', 'Netstat', 'PsList', 'LdadpLog', 'LighttpdLog', 'Dnbd3Log'); + $tabs = ['DmsdLog', 'Netstat', 'PsList', 'LdadpLog', 'LighttpdLog', 'Dnbd3Log', 'ListUpgradable']; $data['tabs'] = array(); // Dictionary::translate('tab_DmsdLog') Dictionary::translate('tab_LdadpLog') Dictionary::translate('tab_Netstat') // Dictionary::translate('tab_LighttpdLog') Dictionary::translate('tab_PsList') Dictionary::translate('tab_Dnbd3Log') + // Dictionary::translate('tab_ListUpgradable') foreach ($tabs as $tab) { $data['tabs'][] = array( 'type' => $tab, - 'name' => Dictionary::translate('tab_' . $tab, true), + 'name' => Dictionary::translate('tab_' . $tab), 'enabled' => User::hasPermission('tab.' . $tab), + 'important' => $tab === 'ListUpgradable' + && (SystemStatus::getAptLastDbUpdateTime() + 864000 < time() || SystemStatus::getUpgradableSecurityCount() > 0), ); } Permission::addGlobalTags($data['perms'], null, ['serverreboot']); - if (file_exists('/run/reboot-required.pkgs')) { - $lines = file('/run/reboot-required.pkgs', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - $lines = array_unique($lines); - $data['packages'] = implode(', ', $lines); + $pkgs = SystemStatus::getPackagesRequiringReboot(); + if (!empty($pkgs)) { + $data['packages'] = implode(', ', $pkgs); } Render::addTemplate('_page', $data); } @@ -82,20 +119,78 @@ class Page_SystemStatus extends Page $this->$action(); Message::renderList(); } else { - echo "Action $action not known in " . get_class(); + // get_class() !== get_class($this) + echo "Action $action not known in " . get_class($this); } } + protected function ajaxListUpgradable() + { + User::assertPermission("tab.listupgradable"); + + if (User::hasPermission('apt.update') + && Taskmanager::isRunning(Taskmanager::status(self::TM_UPDATE_UUID))) { + echo Render::parse('sys-update-update', [ + 'taskid' => self::TM_UPDATE_UUID, + 'rnd' => mt_rand(), + ]); + return; + } + + $task = SystemStatus::getUpgradableTask(); + + // Estimate last time package list was updated + $lastPackageInstalled = SystemStatus::getDpkgLastPackageChanges(); + $lastListDownloadAttempt = SystemStatus::getAptLastUpdateAttemptTime(); + $updateDbTime = SystemStatus::getAptLastDbUpdateTime(); + + $perms = []; + Permission::addGlobalTags($perms, 0, ['apt.update', 'apt.upgrade', 'apt.autoremove', 'apt.fix']); + + if ($task !== false) { + $task = Taskmanager::waitComplete($task, 30000); + + if (Taskmanager::isFailed($task) || !Taskmanager::isFinished($task)) { + Taskmanager::addErrorMessage($task); + return; + } + if (!Taskmanager::isFailed($task) && empty($task['data']['packages'])) { + $task['data']['error'] = ''; + } + } else { + $task['data']['error'] = 'ECONNREFUSED'; + } + + foreach ($task['data']['packages'] as &$pkg) { + if (substr($pkg['source'], -9) === '-security') { + $pkg['row_class'] = 'bg-danger'; + } else { + $pkg['row_class'] = ''; + } + } + unset($pkg); + + echo Render::parse('sys-update-main', [ + 'task' => $task['data'], + 'lastDownload' => Util::prettyTime($lastListDownloadAttempt), + 'lastChanged' => Util::prettyTime($updateDbTime), + 'lastInstalled' => Util::prettyTime($lastPackageInstalled), + 'perm' => $perms, + 'list_old' => $lastListDownloadAttempt + 86400 < time(), + 'needReboot' => implode(', ', SystemStatus::getPackagesRequiringReboot()), + ]); + } + protected function ajaxDiskStat() { User::assertPermission("show.overview.diskstat"); if (!SystemStatus::diskStat($systemUsage, $storeUsage, $currentSource, $wantedSource)) return; - $data = ['system' => $this->convertDiskStat($systemUsage)]; + $data = ['system' => $this->convertDiskStat($systemUsage, 3000)]; if ($wantedSource === false) { // Not configured yet, nothing to display $data['notConfigured'] = true; } elseif ($wantedSource === $currentSource) { // Fine and dandy - $data['store'] = $this->convertDiskStat($storeUsage); + $data['store'] = $this->convertDiskStat($storeUsage, 250000); } elseif ($currentSource === false) { // No current source, nothing mounted $data['storeMissing'] = true; } else { // Something else mounted @@ -112,7 +207,7 @@ class Page_SystemStatus extends Page return; $task = Taskmanager::waitComplete($task, 3000); - if (!isset($task['data']['addresses']) || empty($task['data']['addresses'])) { + if (empty($task['data']['addresses'])) { Taskmanager::addErrorMessage($task); return; } @@ -129,16 +224,17 @@ class Page_SystemStatus extends Page 'addresses' => $task['data']['addresses'] )); } - - private function sysInfo() + + private function sysInfo(): array { $data = array(); $memInfo = file_get_contents('/proc/meminfo'); $stat = file_get_contents('/proc/stat'); - preg_match_all('/\b(\w+):\s+(\d+)\s/s', $memInfo, $out, PREG_SET_ORDER); + preg_match_all('/\b(\w+):\s+(\d+)\s/', $memInfo, $out, PREG_SET_ORDER); foreach ($out as $e) { $data[$e[1]] = $e[2]; } + /** @var array{user: numeric, nice: numeric, system: numeric, idle: numeric, iowait: numeric, irq: numeric, softirq: numeric} $out */ if (preg_match('/\bcpu\s+(?<user>\d+)\s+(?<nice>\d+)\s+(?<system>\d+)\s+(?<idle>\d+)\s+(?<iowait>\d+)\s+(?<irq>\d+)\s+(?<softirq>\d+)(\s|$)/', $stat, $out)) { $data['CpuTotal'] = $out['user'] + $out['nice'] + $out['system'] + $out['idle'] + $out['iowait'] + $out['irq'] + $out['softirq']; $data['CpuIdle'] = $out['idle'] + $out['iowait']; @@ -153,27 +249,32 @@ class Page_SystemStatus extends Page $cpuInfo = file_get_contents('/proc/cpuinfo'); $uptime = file_get_contents('/proc/uptime'); $cpuCount = preg_match_all('/\bprocessor\s/', $cpuInfo, $out); - //$cpuCount = count($out); + $out = parse_ini_file('/etc/os-release'); $data = array( 'cpuCount' => $cpuCount, 'memTotal' => '???', 'memFree' => '???', 'swapTotal' => '???', 'swapUsed' => '???', - 'uptime' => '???' + 'uptime' => '???', + 'kernel' => php_uname('r'), + 'distribution' => $out['PRETTY_NAME'] ?? (($out['NAME'] ?? '???') . ' ' . ($out['VERSION'] ?? '???')), ); if (preg_match('/^(\d+)\D/', $uptime, $out)) { $data['uptime'] = floor($out[1] / 86400) . ' ' . Dictionary::translate('lang_days') . ', ' . floor(($out[1] % 86400) / 3600) . ' ' . Dictionary::translate('lang_hours'); } $info = $this->sysInfo(); if (isset($info['MemTotal']) && isset($info['MemFree']) && isset($info['SwapTotal'])) { + $avail = $info['MemAvailable'] ?? ($info['MemFree'] + $info['Buffers'] + $info['Cached']); $data['memTotal'] = Util::readableFileSize($info['MemTotal'] * 1024); - $data['memFree'] = Util::readableFileSize(($info['MemFree'] + $info['Buffers'] + $info['Cached']) * 1024); - $data['memPercent'] = 100 - round((($info['MemFree'] + $info['Buffers'] + $info['Cached']) / $info['MemTotal']) * 100); + $data['memFree'] = Util::readableFileSize($avail * 1024); + $data['memPercent'] = 100 - round(($avail / $info['MemTotal']) * 100); $data['swapTotal'] = Util::readableFileSize($info['SwapTotal'] * 1024); $data['swapUsed'] = Util::readableFileSize(($info['SwapTotal'] - $info['SwapFree']) * 1024); $data['swapPercent'] = 100 - round(($info['SwapFree'] / $info['SwapTotal']) * 100); - $data['swapWarning'] = ($data['swapPercent'] > 50 || $info['SwapFree'] < 400000); + if ($data['swapTotal'] > 0 && $data['memPercent'] > 75) { + $data['swapWarning'] = ($data['swapPercent'] > 80 || $info['SwapFree'] < 400000); + } } if (isset($info['CpuIdle']) && isset($info['CpuSystem']) && isset($info['CpuTotal'])) { $data['cpuLoad'] = 100 - round(($info['CpuIdle'] / $info['CpuTotal']) * 100); @@ -305,37 +406,38 @@ class Page_SystemStatus extends Page echo Render::parse('ajax-journal', ['modules' => [$output]]); } - protected function ajaxLighttpdLog() + private function grepLighttpdLog(string $file, int $num): array { - User::assertPermission("tab.lighttpdlog"); - $fh = @fopen('/var/log/lighttpd/error.log', 'r'); - if ($fh === false) { - echo 'Error opening log file'; - return; - } - fseek($fh, -6000, SEEK_END); - $data = fread($fh, 6000); - @fclose($fh); - if ($data === false) { - echo 'Error reading from log file'; - return; + $fh = @fopen($file, 'r'); + if ($fh === false) + return ['Error opening ' . $file]; + $ret = []; + fseek($fh, -($num * 2000), SEEK_END); + if (ftell($fh) > 0) { + // Throw away first line, as it's most likely incomplete + fgets($fh, 1000); } - // If we could read less, try the .1 file too - $amount = 6000 - strlen($data); - if ($amount > 100) { - $fh = @fopen('/var/log/lighttpd/error.log.1', 'r'); - if ($fh !== false) { - fseek($fh, -$amount, SEEK_END); - $data = fread($fh, $amount) . $data; - @fclose($fh); + while (($line = fgets($fh, 1000))) { + if (strpos($line, ':SSL routines:') === false + && strpos($line, ' SSL: -1 5 104 Connection reset by peer') === false + && strpos($line, 'GET/HEAD with content-length') === false + && strpos($line, 'POST-request, but content-length missing') === false) { + $ret[] = $line; } } - if (strlen($data) < 5990) { - $start = 0; - } else { - $start = strpos($data, "\n") + 1; + fclose($fh); + return array_slice($ret, -$num); + } + + protected function ajaxLighttpdLog() + { + User::assertPermission("tab.lighttpdlog"); + $lines = $this->grepLighttpdLog('/var/log/lighttpd/error.log', 60); + if (count($lines) < 50) { + $lines = array_merge( + $this->grepLighttpdLog('/var/log/lighttpd/error.log.1', 60 - count($lines)), $lines); } - echo '<pre>', htmlspecialchars(substr($data, $start), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; + echo '<pre>', htmlspecialchars(implode('', $lines), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } protected function ajaxLdadpLog() @@ -349,7 +451,7 @@ class Page_SystemStatus extends Page $output = []; foreach ($ids as $id) { $module = ConfigModule::get($id); - if ($module === false) { + if ($module === null) { $name = "#$id"; } else { $name = $module->title(); @@ -373,10 +475,7 @@ class Page_SystemStatus extends Page return; $status = Taskmanager::waitComplete($taskId, 3500); - if (isset($status['data']['messages'])) - $data = $status['data']['messages']; - else - $data = 'Taskmanager error'; + $data = $status['data']['messages'] ?? 'Taskmanager error'; echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } @@ -389,43 +488,52 @@ class Page_SystemStatus extends Page return; $status = Taskmanager::waitComplete($taskId, 3500); - if (isset($status['data']['messages'])) - $data = $status['data']['messages']; - else - $data = 'Taskmanager error'; + $data = $status['data']['messages'] ?? 'Taskmanager error'; echo '<pre>', htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), '</pre>'; } - private function convertDiskStat($stat) + /** + * @return array{percent: numeric, size: string, free: string, color: string, filesystem: string} + */ + private function convertDiskStat(array $stat, int $minFreeMb): array { - if (!is_array($stat)) - return false; return [ 'percent' => $stat['usedPercent'], 'size' => Util::readableFileSize($stat['sizeKb'] * 1024), 'free' => Util::readableFileSize($stat['freeKb'] * 1024), - 'color' => $this->usageColor($stat['usedPercent']), + 'color' => $this->usageColor($stat, $minFreeMb), + 'filesystem' => $stat['fileSystem'], ]; } - private function usageColor($percent) + private function usageColor(array $stat, int $minFreeMb): string { - if ($percent <= 50) { - $r = $b = $percent / 3; - $g = (100 - $percent * (50 / 80)); - } elseif ($percent <= 70) { - $r = 55 + ($percent - 50) * (30 / 20); + $freeMb = round($stat['freeKb'] / 1024); + // All good is half space free, or 4x the min free amount, whatever is more + $okFreeMb = max($minFreeMb * 4, round($stat['sizeKb']) / (1024 * 2)); + if ($freeMb > $okFreeMb) { + $usedPercent = 0; + } elseif ($freeMb < $minFreeMb) { + $usedPercent = 100; + } else { + $usedPercent = 100 - round(($freeMb - $minFreeMb) / ($okFreeMb - $minFreeMb) * 100); + } + if ($usedPercent <= 50) { + $r = $b = $usedPercent / 3; + $g = (100 - $usedPercent * (50 / 80)); + } elseif ($usedPercent <= 70) { + $r = 55 + ($usedPercent - 50) * (30 / 20); $g = 60; $b = 0; } else { - $r = ($percent - 70) / 3 + 90; - $g = (100 - $percent) * (60 / 30); + $r = ($usedPercent - 70) / 3 + 90; + $g = (100 - $usedPercent) * (60 / 30); $b = 0; } - $r = dechex(round($r * 2.55)); - $g = dechex(round($g * 2.55)); - $b = dechex(round($b * 2.55)); + $r = dechex((int)round($r * 2.55)); + $g = dechex((int)round($g * 2.55)); + $b = dechex((int)round($b * 2.55)); return sprintf("%02s%02s%02s", $r, $g, $b); } diff --git a/modules-available/systemstatus/permissions/permissions.json b/modules-available/systemstatus/permissions/permissions.json index a116fd56..0be0a8c5 100644 --- a/modules-available/systemstatus/permissions/permissions.json +++ b/modules-available/systemstatus/permissions/permissions.json @@ -20,6 +20,9 @@ "tab.lighttpdlog": { "location-aware": false }, + "tab.listupgradable": { + "location-aware": false + }, "show.overview.addresses": { "location-aware": false }, @@ -43,5 +46,17 @@ }, "restart.dmsd": { "location-aware": false + }, + "apt.update": { + "location-aware": false + }, + "apt.upgrade": { + "location-aware": false + }, + "apt.autoremove": { + "location-aware": false + }, + "apt.fix": { + "location-aware": false } }
\ No newline at end of file diff --git a/modules-available/systemstatus/templates/_page.html b/modules-available/systemstatus/templates/_page.html index 4b62104c..dedcf01a 100644 --- a/modules-available/systemstatus/templates/_page.html +++ b/modules-available/systemstatus/templates/_page.html @@ -14,6 +14,9 @@ {{^enabled}} <li class="disabled"> <a> + {{#important}} + <span class="glyphicon glyphicon-warning-sign text-danger"></span> + {{/important}} {{name}} </a> </li> @@ -21,6 +24,9 @@ {{#enabled}} <li> <a href="#id-{{type}}_pane" class="ajax-tab" id="id-{{type}}" data-toggle="tab" role="tab"> + {{#important}} + <span class="glyphicon glyphicon-warning-sign text-danger"></span> + {{/important}} {{name}} </a> </li> diff --git a/modules-available/systemstatus/templates/diskstat.html b/modules-available/systemstatus/templates/diskstat.html index 528d9792..1cb8a3ef 100644 --- a/modules-available/systemstatus/templates/diskstat.html +++ b/modules-available/systemstatus/templates/diskstat.html @@ -1,6 +1,7 @@ <div class="slx-storechart"> {{#system}} <b>{{lang_systemPartition}}</b> + <span class="glyphicon glyphicon-info-sign" title={{filesystem}}/> <div id="circles-system"></div> <div>{{lang_capacity}}: {{size}}</div> <div>{{lang_free}}: {{free}}</div> @@ -12,6 +13,7 @@ <div class="slx-storechart"> {{#store}} <b>{{lang_vmStore}}</b> + <span class="glyphicon glyphicon-info-sign" title={{filesystem}}/> <div id="circles-store"></div> <div>{{lang_capacity}}: {{size}}</div> <div>{{lang_free}}: {{free}}</div> diff --git a/modules-available/systemstatus/templates/sys-update-main.html b/modules-available/systemstatus/templates/sys-update-main.html new file mode 100644 index 00000000..ca502ddb --- /dev/null +++ b/modules-available/systemstatus/templates/sys-update-main.html @@ -0,0 +1,118 @@ +<div class="panel panel-default"> + <div class="panel-body"> + <div class="pull-right"> + <form action="?do=systemstatus" method="post"> + <input type="hidden" name="token" value="{{token}}"> + <div> + <button type="submit" class="btn btn-success" name="action" + value="apt-update" {{perm.apt.update.disabled}}> + <span class="glyphicon glyphicon-refresh"></span> + {{lang_checkForUpdates}} + </button> + </div> + <div class="slx-smallspace"></div> + <div class="btn-group dropdown"> + <button type="submit" class="btn btn-primary" name="action" + value="apt-upgrade" {{perm.apt.upgrade.disabled}}> + <span class="glyphicon glyphicon-play"></span> + {{lang_runUpdate}} + </button> + <button type="button" class="btn btn-primary dropdown-toggle" + data-toggle="dropdown" aria-haspopup="true"> + <span class="caret"></span> + <span class="sr-only">Toggle Dropdown</span> + </button> + <div class="dropdown-menu" style="padding:0"> + <div class="btn-group-vertical"> + <button type="submit" name="action" value="apt-full-upgrade" class="btn btn-primary" + style="text-align: left !important" {{perm.apt.upgrade.disabled}}> + <span class="glyphicon glyphicon-play"></span> + {{lang_runFullUpdate}} + </button> + <button type="submit" name="action" value="apt-autoremove" class="btn btn-primary" + style="text-align: left !important" {{perm.apt.autoremove.disabled}}> + <span class="glyphicon glyphicon-trash"></span> + {{lang_removeUnusedPackages}} + </button> + <button type="submit" name="action" value="apt-fix" class="btn btn-primary" + style="text-align: left !important" {{perm.apt.fix.disabled}}> + <span class="glyphicon glyphicon-wrench"></span> + {{lang_fixDependencies}} + </button> + </div> + </div> + </div> + </form> + </div> + <table> + <tr> + <td>{{lang_lastestUpdate}}: </td> + <td>{{lastChanged}}</td> + <tr> + <tr> + <td>{{lang_lastUpdateCheck}}: </td> + <td>{{lastDownload}}</td> + </tr> + <tr> + <td>{{lang_lastPackageInstall}}: </td> + <td>{{lastInstalled}}</td> + <tr> + </table> + {{#list_old}} + <div class="slx-smallspace"></div> + <div class="text-danger"> + {{lang_listOldWarning}} + </div> + {{/list_old}} + </div> +</div> + +{{#task.packages.0}} + <table class="table table-condensed"> + <thead> + <tr> + <th>{{lang_package}}</th> + <th colspan="3">{{lang_versionFromTo}}</th> + </tr> + </thead> + {{#task.packages}} + <tr class="{{row_class}}"> + <td><strong>{{name}}</strong><span class="text-muted">/{{source}}</span></td> + <td class="slx-smallcol">{{oldVersion}}</td> + <td class="slx-smallcol">→</td> + <td class="slx-smallcol">{{newVersion}}</td> + </tr> + {{/task.packages}} + </table> +{{/task.packages.0}} + +{{^task.packages}} + {{^task.error}} + <div class="alert alert-success"> + <span class="glyphicon glyphicon-ok"></span> + {{lang_everythingUpToDate}} + </div> + {{/task.error}} +{{/task.packages}} + +{{#needReboot}} + <div class="alert alert-warning"> + <span class="glyphicon glyphicon-exclamation-sign"></span> + {{lang_packagesNeedingReboot}}: + <a href="#id-default_pane"> + {{.}} + </a> + </div> +{{/needReboot}} + +{{#task.error}} + <div class="alert alert-warning">{{task.error}}</div> +{{/task.error}} + +<div> + <a href="https://www.bwlehrpool.de/wiki/doku.php/satellite/system_updates" target="_blank"> + {{lang_updatesWikiLink}} + <span class="glyphicon glyphicon-new-window"></span> + </a> +</div> +<div class="clearfix"></div>
\ No newline at end of file diff --git a/modules-available/systemstatus/templates/sys-update-update.html b/modules-available/systemstatus/templates/sys-update-update.html new file mode 100644 index 00000000..7be4e648 --- /dev/null +++ b/modules-available/systemstatus/templates/sys-update-update.html @@ -0,0 +1,35 @@ +<div id="apt-output" data-tm-id="{{taskid}}" data-tm-log="output" + data-tm-callback="aptUpdate">{{lang_aptOutput}}</div> + +<div class="buttonbar pull-right" id="btn-bar"> + <a id="fail-button" href="?do=systemstatus&rnd={{rnd}}#id-ListUpgradable_pane" class="btn btn-warning collapse"> + <span class="glyphicon glyphicon-arrow-left"></span> + {{lang_backToPackagelist}} + </a> + <a id="success-button" href="?do=systemstatus&rnd={{rnd}}#id-ListUpgradable_pane" class="btn btn-success + collapse"> + <span class="glyphicon glyphicon-arrow-right"></span> + {{lang_showPackageList}} + </a> +</div> +<div class="clearfix"></div> + +<script> + function aptUpdate(task) { + if (task.statusCode === 'TASK_ERROR') { + if (task.data && task.data.error) { + $('#apt-output').append($('<pre class="text-danger slx-bold">').text(task.data.error)); + } + $('#fail-button').show(); + } + if (task.statusCode === 'TASK_FINISHED') { + $('#success-button').show(); + } + } + + tmInit(); + $('#btn-bar a').click(function () { + window.location.reload(); + return false; + }); +</script>
\ No newline at end of file diff --git a/modules-available/systemstatus/templates/systeminfo.html b/modules-available/systemstatus/templates/systeminfo.html index cf3f0cc2..2489bcaa 100644 --- a/modules-available/systemstatus/templates/systeminfo.html +++ b/modules-available/systemstatus/templates/systeminfo.html @@ -1,6 +1,6 @@ -<div> - {{lang_uptimeOS}}: {{uptime}} -</div> +<div>{{lang_uptimeOS}}: <b>{{uptime}}</b></div> +<div>{{lang_distribution}}: <b>{{distribution}}</b></div> +<div>{{lang_kernel}}: <b>{{kernel}}</b></div> <div class="slx-storechart"> <b>{{lang_cpuLoad}}</b> @@ -48,73 +48,94 @@ {{/swapWarning}} <script type="text/javascript"> - {{#cpuLoadOk}} - var cpuCircle = Circles.create({ - id: 'circles-cpuload', - radius: 60, - value: {{{cpuLoad}}}, - maxValue: 100, - width: 10, - text: function(value){return value + '%'; }, - colors: ['#dbc', '#33f'], - duration: 400, - wrpClass: 'circles-wrp', - textClass: 'circles-text' - }); - var $cpu = $(cpuCircle._el); - var lastCpuTotal = {{CpuTotal}}; - var lastCpuIdle = {{CpuIdle}}; - var lastCpuPercent = {{cpuLoad}}; - {{/cpuLoadOk}} - {{#memTotal}} - var memCircle = Circles.create({ - id: 'circles-mem', - radius: 60, - value: {{{memPercent}}}, - maxValue: 100, - width: 10, - text: function(value){return value + '%'; }, - colors: ['#dbc', '#33f'], - duration: 400, - wrpClass: 'circles-wrp', - textClass: 'circles-text' - }); - var swapCircle = Circles.create({ - id: 'circles-swap', - radius: 60, - value: {{{swapPercent}}}, - maxValue: 100, - width: 10, - text: function(value){return value + '%'; }, - colors: ['#dbc', '#f33'], - duration: 400, - wrpClass: 'circles-wrp', - textClass: 'circles-text' - }); - {{/memTotal}} - function updateSystem() { - if (!cpuCircle && !memCircle) return; - if (!$cpu.is(':visible')) { - setTimeout(updateSystem, 1200); - return; + (function () { + var hiddenProp; + if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support + hiddenProp = "hidden"; + } else if (typeof document.msHidden !== "undefined") { + hiddenProp = "msHidden"; + } else if (typeof document.webkitHidden !== "undefined") { + hiddenProp = "webkitHidden"; + } else { + hiddenProp = null; } - $.post('?do=SystemStatus&action=SysPoll', { token: TOKEN }, function(data) { - if (memCircle && data.MemPercent) memCircle.update(data.MemPercent); - if (swapCircle && data.SwapPercent) swapCircle.update(data.SwapPercent); - if (cpuCircle && data.CpuIdle) { - var total = data.CpuTotal - lastCpuTotal; - var load = total - (data.CpuIdle - lastCpuIdle); - var percent = Math.round(100 * load / total); - cpuCircle.update(percent, Math.abs(percent - lastCpuPercent) < 5 ? 0 : 250); - lastCpuTotal = data.CpuTotal; - lastCpuIdle = data.CpuIdle; - lastCpuPercent = percent; + + {{#cpuLoadOk}} + var cpuCircle = Circles.create({ + id: 'circles-cpuload', + radius: 60, + value: {{{cpuLoad}}}, + maxValue: 100, + width: 10, + text: function (value) { + return value + '%'; + }, + colors: ['#dbc', '#33f'], + duration: 400, + wrpClass: 'circles-wrp', + textClass: 'circles-text' + }); + var $cpu = $(cpuCircle._el); + var lastCpuTotal = {{CpuTotal}}; + var lastCpuIdle = {{CpuIdle}}; + var lastCpuPercent = {{cpuLoad}}; + {{/cpuLoadOk}} + {{#memTotal}} + var memCircle = Circles.create({ + id: 'circles-mem', + radius: 60, + value: {{{memPercent}}}, + maxValue: 100, + width: 10, + text: function (value) { + return value + '%'; + }, + colors: ['#dbc', '#33f'], + duration: 400, + wrpClass: 'circles-wrp', + textClass: 'circles-text' + }); + var swapCircle = Circles.create({ + id: 'circles-swap', + radius: 60, + value: {{{swapPercent}}}, + maxValue: 100, + width: 10, + text: function (value) { + return value + '%'; + }, + colors: ['#dbc', '#f33'], + duration: 400, + wrpClass: 'circles-wrp', + textClass: 'circles-text' + }); + {{/memTotal}} + + function updateSystem() { + if (!cpuCircle && !memCircle) return; + if (!$cpu.is(':visible') || (hiddenProp && document[hiddenProp])) { + setTimeout(updateSystem, 2500); + return; } - }, 'json').fail(function(data) { - console.log(data); - }).always(function() { - setTimeout(updateSystem, 1200); - }); - } - setTimeout(updateSystem, 1000); + $.post('?do=SystemStatus&action=SysPoll', {token: TOKEN}, function (data) { + if (memCircle && data.MemPercent) memCircle.update(data.MemPercent); + if (swapCircle && data.SwapPercent) swapCircle.update(data.SwapPercent); + if (cpuCircle && data.CpuIdle) { + var total = data.CpuTotal - lastCpuTotal; + var load = total - (data.CpuIdle - lastCpuIdle); + var percent = Math.round(100 * load / total); + cpuCircle.update(percent, Math.abs(percent - lastCpuPercent) < 5 ? 0 : 250); + lastCpuTotal = data.CpuTotal; + lastCpuIdle = data.CpuIdle; + lastCpuPercent = percent; + } + }, 'json').fail(function (data) { + console.log(data); + }).always(function () { + setTimeout(updateSystem, 1200); + }); + } + + setTimeout(updateSystem, 1000); + })(); </script> |