diff --git a/README.md b/README.md index b47dac6..76619ef 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ Additionally, `pkg_reboot_required` is exported to indicate that an reboot is ne # HELP pkg_reboot_required Node Requires an Reboot # TYPE pkg_reboot_required gauge pkg_reboot_required 1.0 +# HELP pkg_update_start_time timestamp of last apt update start +# TYPE pkg_update_start_time gauge +pkg_update_start_time 1.641382890503045e+09 +# HELP pkg_update_end_time Timestamp of last apt update finish +# TYPE pkg_update_end_time gauge +pkg_update_end_time 1.641382892755024e+09 +# HELP pkg_update_time_available Availability of the apt update timestamp +# TYPE pkg_update_time_available gauge +pkg_update_time_available 1.0 # HELP pkg_installed Installed packages per origin # TYPE pkg_installed gauge pkg_installed{archive="focal-updates",component="main",label="Ubuntu",origin="Ubuntu",site="ftp.fau.de",trusted="True"} 672.0 @@ -58,6 +67,11 @@ The exporter needs to be executed with appropriate privileges, which are not nec An example configuration will be provided in this repository in the future. +### apt hook +To enable monitoring for apt update calls, place the file under `docs/00-pve-exporter` in `/etc/apt/apt.conf.d` on your system. It will place files under `/tmp`, you can see the success of monitoring the apt update timestamps if the following metric is 1: `pkg_update_time_available 1.0` + +Please not that the presence of an timestamp does not mean that all repositories were updated without issues. + ## Alerting Example alerting rules will be provided in the future. @@ -65,5 +79,4 @@ Example alerting rules will be provided in the future. ## Roadmap - Support for other pkg managers -- Timestamp Support ("Last List/Cache Update") - Deployment as dpkg-Packet \ No newline at end of file diff --git a/docs/00-pve-exporter b/docs/00-pve-exporter new file mode 100644 index 0000000..35685ef --- /dev/null +++ b/docs/00-pve-exporter @@ -0,0 +1,4 @@ +# this is the apt hook provided by the pve exporter. This file shall be placed under /etc/apt/apt.conf.d +APT::Update::Pre-Invoke {"touch /tmp/pkg-exporter-apt-update-pre"; }; +APT::Update::Post-Invoke {"touch /tmp/pkg-exporter-apt-update-post"; }; +APT::Periodic::Update-Package-Lists "1"; diff --git a/src/pkg_exporter/pkgmanager/apt.py b/src/pkg_exporter/pkgmanager/apt.py index 5970a5c..8fb34e8 100644 --- a/src/pkg_exporter/pkgmanager/apt.py +++ b/src/pkg_exporter/pkgmanager/apt.py @@ -1,5 +1,6 @@ import apt import apt.progress +from pathlib import Path class AptPkgManager: @@ -14,6 +15,11 @@ def __init__(self): self.metricDict["broken"] = \ {"description": "Broken packages per origin"} self.metricsByOrigin = {} + self.metaMetrics = {} + self.metaMetrics["update_time_available"] = 0 + self.metaMetrics["update_start_time"] = 0 + self.metaMetrics["update_end_time"] = 0 + self.cache = apt.Cache() self.cache.open(None) @@ -25,6 +31,16 @@ def labelValues(self, origin): def getMetricDict(self): return self.metricDict + def getMetaMetricDict(self): + updateMetrics = {} + updateMetrics["update_start_time"] = \ + {"description": "timestamp of last apt update start"} + updateMetrics["update_end_time"] = \ + {"description": "Timestamp of last apt update finish"} + updateMetrics["update_time_available"] = \ + {"description": "Availability of the apt update timestamp"} + return updateMetrics + def getLabelNames(self): labelNames = ["archive", "component", "label", "origin", "site", "trusted"] @@ -54,6 +70,15 @@ def query(self): self.metricsByOrigin[key]["auto_removable"] += 1 if selected_package.is_now_broken: self.metricsByOrigin[key]["broken"] += 1 + # apt update time + preUpdatePath = Path("/tmp/pkg-exporter-apt-update-pre") + postUpdatePath = Path("/tmp/pkg-exporter-apt-update-post") + if preUpdatePath.is_file() and postUpdatePath.is_file(): + self.metaMetrics["update_time_available"] = 1 + self.metaMetrics["update_start_time"] = \ + preUpdatePath.stat().st_mtime + self.metaMetrics["update_end_time"] = \ + postUpdatePath.stat().st_mtime def getMetricValue(self, name): metricValue = [] @@ -66,3 +91,6 @@ def getMetricValue(self, name): continue metricValue.append(v) return metricValue + + def getMetaValue(self, name): + return self.metaMetrics[name] diff --git a/src/pkg_exporter/textfile.py b/src/pkg_exporter/textfile.py index fa4edba..1f0473b 100755 --- a/src/pkg_exporter/textfile.py +++ b/src/pkg_exporter/textfile.py @@ -15,6 +15,8 @@ def main(): # initially, check which metrics and labels are available metrics = pkgmanager.getMetricDict() labels = pkgmanager.getLabelNames() + gauges = {} + meta_gauges = {} # also add reboot metrics rebootmanager = reboot.RebootManager() @@ -23,8 +25,15 @@ def main(): [], registry=registry ) + # add update statistics + meta_metric = pkgmanager.getMetaMetricDict() + for key, value in meta_metric.items(): + meta_gauges[key] = Gauge( + f'pkg_{key}', value["description"], + registry=registry + ) + # Create all the gauge metrics - gauges = {} for key, value in metrics.items(): gauges[key] = Gauge( f'pkg_{key}', value["description"], @@ -40,6 +49,9 @@ def main(): for m in metricList: gauge.labels(*m["label"]).set(m["value"]) + for name, gauge in meta_gauges.items(): + gauge.set(pkgmanager.getMetaValue(name)) + rebootmanager.query() reboot_gauge.set(rebootmanager.getMetricValue())