From c74193533baa8980fd47c78fe2ef741c1839991b Mon Sep 17 00:00:00 2001 From: Gordon Bleux <33967640+UiP9AV6Y@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:35:26 +0200 Subject: [PATCH 1/2] expose report metrics section as prometheus metrics this change parses additional sections from the report metrics. while all section have a *total* metric, some have additional information which is also exposed by the collector. for good measure additional testdata was added representing various major puppet versions. the reports where generated using `puppet apply --test` against a minimal catalog. the puppet5 report was generated by a puppet installation from Ubuntu 18.04 upstream, while the others where generated from a Puppet installation from the Puppetlabs repo (also against an Ubuntu 18.04 container) Signed-off-by: Gordon Bleux <33967640+UiP9AV6Y@users.noreply.github.com> --- puppetreport/collector.go | 55 +++ puppetreport/report.go | 70 +++- puppetreport/report_test.go | 171 +++++++++- puppetreport/testdata/.gitignore | 1 + puppetreport/testdata/generate_report.sh | 46 +++ puppetreport/testdata/input.pp | 3 + .../testdata/last_run_report-5.4.0.yaml | 282 ++++++++++++++++ .../testdata/last_run_report-6.28.0.yaml | 312 ++++++++++++++++++ .../testdata/last_run_report-7.32.1.yaml | 312 ++++++++++++++++++ .../testdata/last_run_report-8.8.1.yaml | 126 +++++++ .../{ => testdata}/last_run_report.yaml | 0 11 files changed, 1354 insertions(+), 24 deletions(-) create mode 100644 puppetreport/testdata/.gitignore create mode 100755 puppetreport/testdata/generate_report.sh create mode 100644 puppetreport/testdata/input.pp create mode 100644 puppetreport/testdata/last_run_report-5.4.0.yaml create mode 100644 puppetreport/testdata/last_run_report-6.28.0.yaml create mode 100644 puppetreport/testdata/last_run_report-7.32.1.yaml create mode 100644 puppetreport/testdata/last_run_report-8.8.1.yaml rename puppetreport/{ => testdata}/last_run_report.yaml (100%) diff --git a/puppetreport/collector.go b/puppetreport/collector.go index ffe8001..73fc5ee 100644 --- a/puppetreport/collector.go +++ b/puppetreport/collector.go @@ -44,6 +44,41 @@ var ( nil, nil, ) + + resourcesTotalDesc = prometheus.NewDesc( + "puppet_last_catalog_resources_total", + "Resources managed during the last Puppet run", + nil, + nil, + ) + + resourcesStateDesc = prometheus.NewDesc( + "puppet_last_catalog_resources", + "Resource states encountered during the last Puppet run", + []string{"state"}, + nil, + ) + + changesTotalDesc = prometheus.NewDesc( + "puppet_last_catalog_changes_total", + "Applied node changes during the last Puppet run", + nil, + nil, + ) + + eventsTotalDesc = prometheus.NewDesc( + "puppet_last_catalog_events_total", + "Events fired during the last Puppet run", + nil, + nil, + ) + + eventsStateDesc = prometheus.NewDesc( + "puppet_last_catalog_events", + "Events states encountered during the last Puppet run", + []string{"state"}, + nil, + ) ) type Collector struct { @@ -56,6 +91,10 @@ func (c Collector) Describe(ch chan<- *prometheus.Desc) { ch <- runAtDesc ch <- runDurationDesc ch <- runSuccessDesc + ch <- resourcesTotalDesc + ch <- resourcesStateDesc + ch <- changesTotalDesc + ch <- eventsTotalDesc } func (c Collector) Collect(ch chan<- prometheus.Metric) { @@ -84,6 +123,11 @@ type interpretedReport struct { RunDuration float64 CatalogVersion string RunSuccess float64 + ResourceCount float64 + ChangeCount float64 + EventCount float64 + ResourceStates map[string]float64 + EventStates map[string]float64 } func (r interpretedReport) collect(ch chan<- prometheus.Metric) { @@ -91,4 +135,15 @@ func (r interpretedReport) collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(runAtDesc, prometheus.GaugeValue, r.RunAt) ch <- prometheus.MustNewConstMetric(runDurationDesc, prometheus.GaugeValue, r.RunDuration) ch <- prometheus.MustNewConstMetric(runSuccessDesc, prometheus.GaugeValue, r.RunSuccess) + ch <- prometheus.MustNewConstMetric(resourcesTotalDesc, prometheus.GaugeValue, r.ResourceCount) + ch <- prometheus.MustNewConstMetric(changesTotalDesc, prometheus.GaugeValue, r.ChangeCount) + ch <- prometheus.MustNewConstMetric(eventsTotalDesc, prometheus.GaugeValue, r.EventCount) + + for state, count := range r.ResourceStates { + ch <- prometheus.MustNewConstMetric(resourcesStateDesc, prometheus.GaugeValue, count, state) + } + + for state, count := range r.EventStates { + ch <- prometheus.MustNewConstMetric(eventsStateDesc, prometheus.GaugeValue, count, state) + } } diff --git a/puppetreport/report.go b/puppetreport/report.go index 1355bb5..b8c11b2 100644 --- a/puppetreport/report.go +++ b/puppetreport/report.go @@ -36,30 +36,76 @@ type runReport struct { func (r runReport) interpret() interpretedReport { result := interpretedReport{ RunAt: asUnixSeconds(r.Time), - RunDuration: r.totalDuration(), + RunDuration: -1, CatalogVersion: r.ConfigurationVersion, } if r.success() { result.RunSuccess = 1 } + + resourceMetrics, ok := r.Metrics["resources"] + if ok { + interpretResourceMetrics(resourceMetrics.Values(), &result) + } + + timeMetrics, ok := r.Metrics["time"] + if ok { + interpretTimeMetrics(timeMetrics.Values(), &result) + } + + changeMetrics, ok := r.Metrics["changes"] + if ok { + interpretChangeMetrics(changeMetrics.Values(), &result) + } + + eventMetrics, ok := r.Metrics["events"] + if ok { + interpretEventMetrics(eventMetrics.Values(), &result) + } + return result } -func asUnixSeconds(t time.Time) float64 { - return float64(t.Unix()) + (float64(t.Nanosecond()) / 1e+9) +func interpretResourceMetrics(m map[string]float64, r *interpretedReport) { + r.ResourceStates = make(map[string]float64, len(m)) + + for l, v := range m { + if l == "total" { + r.ResourceCount = v + } else { + r.ResourceStates[l] = v + } + } } -func (r runReport) totalDuration() float64 { - timeMetrics, ok := r.Metrics["time"] - if !ok { - return -1 +func interpretTimeMetrics(m map[string]float64, r *interpretedReport) { + total, ok := m["total"] + if ok { + r.RunDuration = total } - values := timeMetrics.Values() - total, ok := values["total"] - if !ok { - return -1 +} + +func interpretChangeMetrics(m map[string]float64, r *interpretedReport) { + total, ok := m["total"] + if ok { + r.ChangeCount = total } - return total +} + +func interpretEventMetrics(m map[string]float64, r *interpretedReport) { + r.EventStates = make(map[string]float64, len(m)) + + for l, v := range m { + if l == "total" { + r.EventCount = v + } else { + r.EventStates[l] = v + } + } +} + +func asUnixSeconds(t time.Time) float64 { + return float64(t.Unix()) + (float64(t.Nanosecond()) / 1e+9) } func (r runReport) success() bool { diff --git a/puppetreport/report_test.go b/puppetreport/report_test.go index 098a915..f7dfe09 100644 --- a/puppetreport/report_test.go +++ b/puppetreport/report_test.go @@ -14,22 +14,169 @@ package puppetreport -import "testing" +import ( + "fmt" + "testing" +) func TestLoadReport(t *testing.T) { - report, err := load("last_run_report.yaml") - if err != nil { - t.Fatal(err) + testCases := map[string]interpretedReport{ + "last_run_report": interpretedReport{ + RunAt: 1618957125.5901103, + RunDuration: 17.199882286, + CatalogVersion: "1618957129", + RunSuccess: 1, + }, + "last_run_report-5.4.0": interpretedReport{ + RunAt: 1725776230.602652, + RunDuration: 0.03196727, + CatalogVersion: "1725776230", + RunSuccess: 1, + ResourceCount: 8, + ResourceStates: map[string]float64{ + "skipped": 0, + "failed": 0, + "failed_to_restart": 0, + "restarted": 0, + "changed": 0, + "out_of_sync": 0, + "scheduled": 0, + "corrective_change": 0, + }, + EventStates: map[string]float64{ + "failure": 0, + "success": 0, + }, + }, + "last_run_report-6.28.0": interpretedReport{ + RunAt: 1725776354.854867, + RunDuration: 0.004820335, + CatalogVersion: "1725776354", + RunSuccess: 1, + ResourceCount: 8, + ResourceStates: map[string]float64{ + "skipped": 0, + "failed": 0, + "failed_to_restart": 0, + "restarted": 0, + "changed": 0, + "out_of_sync": 0, + "scheduled": 0, + "corrective_change": 0, + }, + EventStates: map[string]float64{ + "failure": 0, + "success": 0, + }, + }, + "last_run_report-7.32.1": interpretedReport{ + RunAt: 1725776438.356112, + RunDuration: 0.006013873, + CatalogVersion: "1725776438", + RunSuccess: 1, + ResourceCount: 8, + ResourceStates: map[string]float64{ + "skipped": 0, + "failed": 0, + "failed_to_restart": 0, + "restarted": 0, + "changed": 0, + "out_of_sync": 0, + "scheduled": 0, + "corrective_change": 0, + }, + EventStates: map[string]float64{ + "failure": 0, + "success": 0, + }, + }, + "last_run_report-8.8.1": interpretedReport{ + RunAt: 1725776515.039312, + RunDuration: 0.005837204, + CatalogVersion: "1725776515", + RunSuccess: 1, + ResourceCount: 8, + ResourceStates: map[string]float64{ + "skipped": 0, + "failed": 0, + "failed_to_restart": 0, + "restarted": 0, + "changed": 0, + "out_of_sync": 0, + "scheduled": 0, + "corrective_change": 0, + }, + EventStates: map[string]float64{ + "failure": 0, + "success": 0, + }, + }, } - ir := report.interpret() - expected := interpretedReport{ - RunAt: 1618957125.5901103, - RunDuration: 17.199882286, - CatalogVersion: "1618957129", - RunSuccess: 1, + for name, tc := range testCases { + want := tc + t.Run(name, func(t *testing.T) { + report, err := load("testdata/" + name + ".yaml") + if err != nil { + t.Fatal(err) + } + + got := report.interpret() + + if want.RunAt != got.RunAt { + t.Fatalf("RunAt: want %f; got %f", want.RunAt, got.RunAt) + } + + if want.RunDuration != got.RunDuration { + t.Fatalf("RunDuration: want %f; got %f", want.RunDuration, got.RunDuration) + } + + if want.CatalogVersion != got.CatalogVersion { + t.Fatalf("CatalogVersion: want %q; got %q", want.CatalogVersion, got.CatalogVersion) + } + + if want.RunSuccess != got.RunSuccess { + t.Fatalf("RunSuccess: want %f; got %f", want.RunSuccess, got.RunSuccess) + } + + if want.ResourceCount != got.ResourceCount { + t.Fatalf("ResourceCount: want %f; got %f", want.ResourceCount, got.ResourceCount) + } + + if want.ChangeCount != got.ChangeCount { + t.Fatalf("ChangeCount: want %f; got %f", want.ChangeCount, got.ChangeCount) + } + + if want.EventCount != got.EventCount { + t.Fatalf("EventCount: want %f; got %f", want.EventCount, got.EventCount) + } + + if err := mapCompare(want.ResourceStates, got.ResourceStates); err != "" { + t.Fatalf("ResourceStates: %s", err) + } + + if err := mapCompare(want.EventStates, got.EventStates); err != "" { + t.Fatalf("EventStates: %s", err) + } + }) + } +} + +func mapCompare(l, r map[string]float64) string { + if len(l) != len(r) { + return fmt.Sprintf("length: want %d, got %d", len(l), len(r)) } - if ir != expected { - t.Fatalf("%+v != %+v", ir, expected) + + for k, want := range l { + got, ok := r[k] + if !ok { + return fmt.Sprintf("key %q is missing", k) + } + + if want != got { + return fmt.Sprintf("key %q: want %f, got %f", k, want, got) + } } + + return "" } diff --git a/puppetreport/testdata/.gitignore b/puppetreport/testdata/.gitignore new file mode 100644 index 0000000..c00df13 --- /dev/null +++ b/puppetreport/testdata/.gitignore @@ -0,0 +1 @@ +*.deb diff --git a/puppetreport/testdata/generate_report.sh b/puppetreport/testdata/generate_report.sh new file mode 100755 index 0000000..256ff9b --- /dev/null +++ b/puppetreport/testdata/generate_report.sh @@ -0,0 +1,46 @@ +#!/bin/sh -eu + +. /etc/os-release + +SELF=$(readlink -f "$0") +PROJECT_ROOT=$(dirname "$SELF") + +install_package() { + /usr/bin/apt-get update -qq + echo ">> Installing ${1}" + /usr/bin/apt-get install -y --no-install-recommends "$1" || true +} + +cd "$PROJECT_ROOT" + +if test $# -gt 0; then + PUPPET_VERSION="$1" +fi + +if test -n "${PUPPET_VERSION:-}"; then + if ! test -s "puppet${PUPPET_VERSION}-release-${VERSION_CODENAME}.deb"; then + if ! test -s /usr/bin/curl; then + install_package curl + fi + + echo ">> Downloading https://apt.puppetlabs.com/puppet${PUPPET_VERSION}-release-${VERSION_CODENAME}.deb" + /usr/bin/curl -sLO "https://apt.puppetlabs.com/puppet${PUPPET_VERSION}-release-${VERSION_CODENAME}.deb" + fi + + echo ">> Installing Puppetlabs APT configuration" + /usr/bin/apt install "./puppet${PUPPET_VERSION}-release-${VERSION_CODENAME}.deb" + install_package puppet-agent +else + install_package puppet +fi + +export PATH="${PATH}:/opt/puppetlabs/puppet/bin" + +echo ">> Running puppet with input.pp" +puppet apply --test "input.pp" || true + +PUPPET_VERSION=$(puppet --version) +PUPPET_REPORT_FILE=$(puppet config print lastrunreport) + +cp -v "$PUPPET_REPORT_FILE" "last_run_report-${PUPPET_VERSION}.yaml" + diff --git a/puppetreport/testdata/input.pp b/puppetreport/testdata/input.pp new file mode 100644 index 0000000..b17be3e --- /dev/null +++ b/puppetreport/testdata/input.pp @@ -0,0 +1,3 @@ +file { '/var/log/unattended-upgrades': + ensure => file, +} diff --git a/puppetreport/testdata/last_run_report-5.4.0.yaml b/puppetreport/testdata/last_run_report-5.4.0.yaml new file mode 100644 index 0000000..772d411 --- /dev/null +++ b/puppetreport/testdata/last_run_report-5.4.0.yaml @@ -0,0 +1,282 @@ +--- !ruby/object:Puppet::Transaction::Report +host: 68266137cc3c +time: '2024-09-08T06:17:10.602652100+00:00' +configuration_version: 1725776230 +transaction_uuid: 52735400-bc28-47e3-93e5-ce6333e652c9 +report_format: 8 +puppet_version: 5.4.0 +status: unchanged +transaction_completed: true +noop: false +noop_pending: false +environment: production +logs: +- level: info + message: Applying configuration version '1725776230' + source: Puppet + tags: + - info + time: '2024-09-08T06:17:10.602954412+00:00' + file: + line: +- level: info + message: Creating state file /var/cache/puppet/state/state.yaml + source: Puppet + tags: + - info + time: '2024-09-08T06:17:10.605238074+00:00' + file: + line: +- level: notice + message: Applied catalog in 0.00 seconds + source: Puppet + tags: + - notice + time: '2024-09-08T06:17:10.607630773+00:00' + file: + line: +metrics: + resources: + name: resources + label: Resources + values: + - - total + - Total + - 8 + - - skipped + - Skipped + - 0 + - - failed + - Failed + - 0 + - - failed_to_restart + - Failed to restart + - 0 + - - restarted + - Restarted + - 0 + - - changed + - Changed + - 0 + - - out_of_sync + - Out of sync + - 0 + - - scheduled + - Scheduled + - 0 + - - corrective_change + - Corrective change + - 0 + time: + name: time + label: Time + values: + - - file + - File + - 0.000222811 + - - schedule + - Schedule + - 0.00013191 + - - filebucket + - Filebucket + - 3.132e-05 + - - config_retrieval + - Config retrieval + - 0.031581229 + - - total + - Total + - 0.03196727 + changes: + name: changes + label: Changes + values: + - - total + - Total + - 0 + events: + name: events + label: Events + values: + - - total + - Total + - 0 + - - failure + - Failure + - 0 + - - success + - Success + - 0 +resource_statuses: + File[/etc/gaff/bac]: + title: "/etc/gaff/bac" + file: "/src/init.pp" + line: 1 + resource: File[/etc/gaff/bac] + resource_type: File + containment_path: + - Stage[main] + - Main + - File[/etc/gaff/bac] + evaluation_time: 0.000222811 + tags: + - file + - class + time: '2024-09-08T06:17:10.604315689+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[puppet]: + title: puppet + file: + line: + resource: Schedule[puppet] + resource_type: Schedule + containment_path: + - Schedule[puppet] + evaluation_time: 2.637e-05 + tags: + - schedule + - puppet + time: '2024-09-08T06:17:10.604734982+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[hourly]: + title: hourly + file: + line: + resource: Schedule[hourly] + resource_type: Schedule + containment_path: + - Schedule[hourly] + evaluation_time: 2.3825e-05 + tags: + - schedule + - hourly + time: '2024-09-08T06:17:10.604798402+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[daily]: + title: daily + file: + line: + resource: Schedule[daily] + resource_type: Schedule + containment_path: + - Schedule[daily] + evaluation_time: 2.2232e-05 + tags: + - schedule + - daily + time: '2024-09-08T06:17:10.604870268+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[weekly]: + title: weekly + file: + line: + resource: Schedule[weekly] + resource_type: Schedule + containment_path: + - Schedule[weekly] + evaluation_time: 1.9457e-05 + tags: + - schedule + - weekly + time: '2024-09-08T06:17:10.604943757+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[monthly]: + title: monthly + file: + line: + resource: Schedule[monthly] + resource_type: Schedule + containment_path: + - Schedule[monthly] + evaluation_time: 2.0219e-05 + tags: + - schedule + - monthly + time: '2024-09-08T06:17:10.604999212+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[never]: + title: never + file: + line: + resource: Schedule[never] + resource_type: Schedule + containment_path: + - Schedule[never] + evaluation_time: 1.9807e-05 + tags: + - schedule + - never + time: '2024-09-08T06:17:10.605071850+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Filebucket[puppet]: + title: puppet + file: + line: + resource: Filebucket[puppet] + resource_type: Filebucket + containment_path: + - Filebucket[puppet] + evaluation_time: 3.132e-05 + tags: + - filebucket + - puppet + time: '2024-09-08T06:17:10.605152933+00:00' + failed: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false +corrective_change: false +catalog_uuid: df324bbf-3ab5-45bb-832b-07386ad3f8d6 +cached_catalog_status: not_used diff --git a/puppetreport/testdata/last_run_report-6.28.0.yaml b/puppetreport/testdata/last_run_report-6.28.0.yaml new file mode 100644 index 0000000..01ad56d --- /dev/null +++ b/puppetreport/testdata/last_run_report-6.28.0.yaml @@ -0,0 +1,312 @@ +--- !ruby/object:Puppet::Transaction::Report +host: 9c5f2bf35c00 +time: '2024-09-08T06:19:14.854867011+00:00' +configuration_version: 1725776354 +transaction_uuid: fe0175ef-82c2-4978-83b4-28a23b56a665 +report_format: 11 +puppet_version: 6.28.0 +status: unchanged +transaction_completed: true +noop: false +noop_pending: false +environment: production +logs: +- level: info + message: Using environment 'production' + source: Puppet + tags: + - info + time: '2024-09-08T06:19:14.855056921+00:00' + file: + line: +- level: info + message: Applying configuration version '1725776354' + source: Puppet + tags: + - info + time: '2024-09-08T06:19:14.855198970+00:00' + file: + line: +- level: info + message: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml + source: Puppet + tags: + - info + time: '2024-09-08T06:19:14.857587597+00:00' + file: + line: +- level: notice + message: Applied catalog in 0.00 seconds + source: Puppet + tags: + - notice + time: '2024-09-08T06:19:14.859622283+00:00' + file: + line: +metrics: + resources: + name: resources + label: Resources + values: + - - total + - Total + - 8 + - - skipped + - Skipped + - 0 + - - failed + - Failed + - 0 + - - failed_to_restart + - Failed to restart + - 0 + - - restarted + - Restarted + - 0 + - - changed + - Changed + - 0 + - - out_of_sync + - Out of sync + - 0 + - - scheduled + - Scheduled + - 0 + - - corrective_change + - Corrective change + - 0 + time: + name: time + label: Time + values: + - - file + - File + - 0.000160554 + - - schedule + - Schedule + - 0.00020331499999999997 + - - filebucket + - Filebucket + - 4.0546e-05 + - - config_retrieval + - Config retrieval + - 0.039981014 + - - transaction_evaluation + - Transaction evaluation + - 0.0023744989998704114 + - - catalog_application + - Catalog application + - 0.004444632999820897 + - - total + - Total + - 0.004820335 + changes: + name: changes + label: Changes + values: + - - total + - Total + - 0 + events: + name: events + label: Events + values: + - - total + - Total + - 0 + - - failure + - Failure + - 0 + - - success + - Success + - 0 +resource_statuses: + File[/etc/gaff/bac]: + title: "/etc/gaff/bac" + file: "/src/init.pp" + line: 1 + resource: File[/etc/gaff/bac] + resource_type: File + provider_used: posix + containment_path: + - Stage[main] + - Main + - File[/etc/gaff/bac] + evaluation_time: 0.000160554 + tags: + - file + - class + time: '2024-09-08T06:19:14.856706277+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[puppet]: + title: puppet + file: + line: + resource: Schedule[puppet] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[puppet] + evaluation_time: 3.2652e-05 + tags: + - schedule + - puppet + time: '2024-09-08T06:19:14.857072661+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[hourly]: + title: hourly + file: + line: + resource: Schedule[hourly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[hourly] + evaluation_time: 2.7152e-05 + tags: + - schedule + - hourly + time: '2024-09-08T06:19:14.857138766+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[daily]: + title: daily + file: + line: + resource: Schedule[daily] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[daily] + evaluation_time: 4.9303e-05 + tags: + - schedule + - daily + time: '2024-09-08T06:19:14.857200654+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[weekly]: + title: weekly + file: + line: + resource: Schedule[weekly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[weekly] + evaluation_time: 2.4897e-05 + tags: + - schedule + - weekly + time: '2024-09-08T06:19:14.857282208+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[monthly]: + title: monthly + file: + line: + resource: Schedule[monthly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[monthly] + evaluation_time: 2.4737e-05 + tags: + - schedule + - monthly + time: '2024-09-08T06:19:14.857339827+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[never]: + title: never + file: + line: + resource: Schedule[never] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[never] + evaluation_time: 4.4574e-05 + tags: + - schedule + - never + time: '2024-09-08T06:19:14.857397998+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Filebucket[puppet]: + title: puppet + file: + line: + resource: Filebucket[puppet] + resource_type: Filebucket + provider_used: + containment_path: + - Filebucket[puppet] + evaluation_time: 4.0546e-05 + tags: + - filebucket + - puppet + time: '2024-09-08T06:19:14.857480845+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false +corrective_change: false +catalog_uuid: 629f4a2d-4141-462b-ba69-8a48fcd43c81 +cached_catalog_status: not_used diff --git a/puppetreport/testdata/last_run_report-7.32.1.yaml b/puppetreport/testdata/last_run_report-7.32.1.yaml new file mode 100644 index 0000000..9ec1f78 --- /dev/null +++ b/puppetreport/testdata/last_run_report-7.32.1.yaml @@ -0,0 +1,312 @@ +--- !ruby/object:Puppet::Transaction::Report +host: 9ed5cab53d0b +time: '2024-09-08T06:20:38.356112004+00:00' +configuration_version: 1725776438 +transaction_uuid: cf84c2e9-cdb2-451a-9908-f9aaf0cb92c7 +report_format: 12 +puppet_version: 7.32.1 +status: unchanged +transaction_completed: true +noop: false +noop_pending: false +environment: production +logs: +- level: info + message: Using environment 'production' + source: Puppet + tags: + - info + time: '2024-09-08T06:20:38.356331099+00:00' + file: + line: +- level: info + message: Applying configuration version '1725776438' + source: Puppet + tags: + - info + time: '2024-09-08T06:20:38.356512994+00:00' + file: + line: +- level: info + message: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml + source: Puppet + tags: + - info + time: '2024-09-08T06:20:38.359460233+00:00' + file: + line: +- level: notice + message: Applied catalog in 0.01 seconds + source: Puppet + tags: + - notice + time: '2024-09-08T06:20:38.362058870+00:00' + file: + line: +metrics: + resources: + name: resources + label: Resources + values: + - - total + - Total + - 8 + - - skipped + - Skipped + - 0 + - - failed + - Failed + - 0 + - - failed_to_restart + - Failed to restart + - 0 + - - restarted + - Restarted + - 0 + - - changed + - Changed + - 0 + - - out_of_sync + - Out of sync + - 0 + - - scheduled + - Scheduled + - 0 + - - corrective_change + - Corrective change + - 0 + time: + name: time + label: Time + values: + - - file + - File + - 0.000150676 + - - schedule + - Schedule + - 0.00019791699999999998 + - - filebucket + - Filebucket + - 4.8181e-05 + - - config_retrieval + - Config retrieval + - 0.036613366 + - - transaction_evaluation + - Transaction evaluation + - 0.002930847000243375 + - - catalog_application + - Catalog application + - 0.005560303000038402 + - - total + - Total + - 0.006013873 + changes: + name: changes + label: Changes + values: + - - total + - Total + - 0 + events: + name: events + label: Events + values: + - - total + - Total + - 0 + - - failure + - Failure + - 0 + - - success + - Success + - 0 +resource_statuses: + File[/etc/gaff/bac]: + title: "/etc/gaff/bac" + file: "/src/init.pp" + line: 1 + resource: File[/etc/gaff/bac] + resource_type: File + provider_used: posix + containment_path: + - Stage[main] + - Main + - File[/etc/gaff/bac] + evaluation_time: 0.000150676 + tags: + - file + - class + time: '2024-09-08T06:20:38.358416644+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[puppet]: + title: puppet + file: + line: + resource: Schedule[puppet] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[puppet] + evaluation_time: 3.5036e-05 + tags: + - schedule + - puppet + time: '2024-09-08T06:20:38.358811493+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[hourly]: + title: hourly + file: + line: + resource: Schedule[hourly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[hourly] + evaluation_time: 2.6441e-05 + tags: + - schedule + - hourly + time: '2024-09-08T06:20:38.358913055+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[daily]: + title: daily + file: + line: + resource: Schedule[daily] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[daily] + evaluation_time: 4.207e-05 + tags: + - schedule + - daily + time: '2024-09-08T06:20:38.358983970+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[weekly]: + title: weekly + file: + line: + resource: Schedule[weekly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[weekly] + evaluation_time: 2.6801e-05 + tags: + - schedule + - weekly + time: '2024-09-08T06:20:38.359067168+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[monthly]: + title: monthly + file: + line: + resource: Schedule[monthly] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[monthly] + evaluation_time: 2.611e-05 + tags: + - schedule + - monthly + time: '2024-09-08T06:20:38.359152850+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Schedule[never]: + title: never + file: + line: + resource: Schedule[never] + resource_type: Schedule + provider_used: + containment_path: + - Schedule[never] + evaluation_time: 4.1459e-05 + tags: + - schedule + - never + time: '2024-09-08T06:20:38.359222352+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false + Filebucket[puppet]: + title: puppet + file: + line: + resource: Filebucket[puppet] + resource_type: Filebucket + provider_used: + containment_path: + - Filebucket[puppet] + evaluation_time: 4.8181e-05 + tags: + - filebucket + - puppet + time: '2024-09-08T06:20:38.359335517+00:00' + failed: false + failed_to_restart: false + changed: false + out_of_sync: false + skipped: false + change_count: 0 + out_of_sync_count: 0 + events: [] + corrective_change: false +corrective_change: false +catalog_uuid: 323e4988-dd80-4fc2-80d9-be9047e670c6 +cached_catalog_status: not_used diff --git a/puppetreport/testdata/last_run_report-8.8.1.yaml b/puppetreport/testdata/last_run_report-8.8.1.yaml new file mode 100644 index 0000000..f5775e9 --- /dev/null +++ b/puppetreport/testdata/last_run_report-8.8.1.yaml @@ -0,0 +1,126 @@ +--- !ruby/object:Puppet::Transaction::Report +host: 974cb14fe521 +time: '2024-09-08T06:21:55.039311949+00:00' +configuration_version: 1725776515 +transaction_uuid: f70c823c-2923-4dd3-b41d-2285f844eba9 +report_format: 12 +puppet_version: 8.8.1 +status: unchanged +transaction_completed: true +noop: false +noop_pending: false +environment: production +logs: +- level: info + message: Using environment 'production' + source: Puppet + tags: + - info + time: '2024-09-08T06:21:55.039507680+00:00' + file: + line: +- level: info + message: Applying configuration version '1725776515' + source: Puppet + tags: + - info + time: '2024-09-08T06:21:55.039711367+00:00' + file: + line: +- level: info + message: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml + source: Puppet + tags: + - info + time: '2024-09-08T06:21:55.042678045+00:00' + file: + line: +- level: notice + message: Applied catalog in 0.01 seconds + source: Puppet + tags: + - notice + time: '2024-09-08T06:21:55.045080673+00:00' + file: + line: +metrics: + resources: + name: resources + label: Resources + values: + - - total + - Total + - 8 + - - skipped + - Skipped + - 0 + - - failed + - Failed + - 0 + - - failed_to_restart + - Failed to restart + - 0 + - - restarted + - Restarted + - 0 + - - changed + - Changed + - 0 + - - out_of_sync + - Out of sync + - 0 + - - scheduled + - Scheduled + - 0 + - - corrective_change + - Corrective change + - 0 + time: + name: time + label: Time + values: + - - file + - File + - 0.000149022 + - - schedule + - Schedule + - 0.00017309900000000002 + - - filebucket + - Filebucket + - 3.5647e-05 + - - config_retrieval + - Config retrieval + - 0.041649623 + - - transaction_evaluation + - Transaction evaluation + - 0.0029393660001915123 + - - catalog_application + - Catalog application + - 0.005426745000022493 + - - total + - Total + - 0.005837204 + changes: + name: changes + label: Changes + values: + - - total + - Total + - 0 + events: + name: events + label: Events + values: + - - total + - Total + - 0 + - - failure + - Failure + - 0 + - - success + - Success + - 0 +resource_statuses: {} +corrective_change: false +catalog_uuid: 961fb32f-6df1-4a47-813c-313ffcb3e7ef +cached_catalog_status: not_used diff --git a/puppetreport/last_run_report.yaml b/puppetreport/testdata/last_run_report.yaml similarity index 100% rename from puppetreport/last_run_report.yaml rename to puppetreport/testdata/last_run_report.yaml From 0e3956fcd2420701aa39280afcca5412677de51f Mon Sep 17 00:00:00 2001 From: Giacomo Tenaglia Date: Thu, 13 Nov 2025 18:28:34 +0100 Subject: [PATCH 2/2] feat: expose config retrieval duration Signed-off-by: Giacomo Tenaglia --- puppetreport/collector.go | 28 +++++++++++++++++++--------- puppetreport/report.go | 11 ++++++++--- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/puppetreport/collector.go b/puppetreport/collector.go index 73fc5ee..0907cca 100644 --- a/puppetreport/collector.go +++ b/puppetreport/collector.go @@ -79,6 +79,13 @@ var ( []string{"state"}, nil, ) + + configRetrievalDurationDesc = prometheus.NewDesc( + "puppet_config_retrieval_duration_seconds", + "Duration of the config retrieval stage.", + nil, + nil, + ) ) type Collector struct { @@ -95,6 +102,7 @@ func (c Collector) Describe(ch chan<- *prometheus.Desc) { ch <- resourcesStateDesc ch <- changesTotalDesc ch <- eventsTotalDesc + ch <- configRetrievalDurationDesc } func (c Collector) Collect(ch chan<- prometheus.Metric) { @@ -119,15 +127,16 @@ type Logger interface { } type interpretedReport struct { - RunAt float64 - RunDuration float64 - CatalogVersion string - RunSuccess float64 - ResourceCount float64 - ChangeCount float64 - EventCount float64 - ResourceStates map[string]float64 - EventStates map[string]float64 + RunAt float64 + RunDuration float64 + CatalogVersion string + RunSuccess float64 + ResourceCount float64 + ChangeCount float64 + EventCount float64 + ResourceStates map[string]float64 + EventStates map[string]float64 + ConfigRetrievalDuration float64 } func (r interpretedReport) collect(ch chan<- prometheus.Metric) { @@ -138,6 +147,7 @@ func (r interpretedReport) collect(ch chan<- prometheus.Metric) { ch <- prometheus.MustNewConstMetric(resourcesTotalDesc, prometheus.GaugeValue, r.ResourceCount) ch <- prometheus.MustNewConstMetric(changesTotalDesc, prometheus.GaugeValue, r.ChangeCount) ch <- prometheus.MustNewConstMetric(eventsTotalDesc, prometheus.GaugeValue, r.EventCount) + ch <- prometheus.MustNewConstMetric(configRetrievalDurationDesc, prometheus.GaugeValue, r.ConfigRetrievalDuration) for state, count := range r.ResourceStates { ch <- prometheus.MustNewConstMetric(resourcesStateDesc, prometheus.GaugeValue, count, state) diff --git a/puppetreport/report.go b/puppetreport/report.go index b8c11b2..5a01e5b 100644 --- a/puppetreport/report.go +++ b/puppetreport/report.go @@ -35,9 +35,10 @@ type runReport struct { func (r runReport) interpret() interpretedReport { result := interpretedReport{ - RunAt: asUnixSeconds(r.Time), - RunDuration: -1, - CatalogVersion: r.ConfigurationVersion, + RunAt: asUnixSeconds(r.Time), + RunDuration: -1, + CatalogVersion: r.ConfigurationVersion, + ConfigRetrievalDuration: -1, } if r.success() { result.RunSuccess = 1 @@ -83,6 +84,10 @@ func interpretTimeMetrics(m map[string]float64, r *interpretedReport) { if ok { r.RunDuration = total } + config_retrieval, ok := m["config_retrieval"] + if ok { + r.ConfigRetrievalDuration = config_retrieval + } } func interpretChangeMetrics(m map[string]float64, r *interpretedReport) {