blob: 6f04c7672c43940d776d9a7fdac5256d42412c7f [file] [log] [blame]
# Copyright 2016 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Puppet metrics"""
import logging
import time
import yaml # pylint: disable=import-error
from chromite.lib import metrics
logger = logging.getLogger(__name__)
LAST_RUN_FILE = "/var/lib/cros_puppet/state/last_run_summary.yaml"
_config_version_metric = metrics.GaugeMetric(
"puppet/version/config",
description=(
"The version of the puppet configuration."
" By default this is the time that the configuration was parsed"
),
)
_puppet_version_metric = metrics.StringMetric(
"puppet/version/puppet", description="Version of puppet client installed."
)
_events_metric = metrics.GaugeMetric(
"puppet/events",
description=(
"Number of changes the puppet client made to the system in its"
" last run, by success or failure"
),
)
_resources_metric = metrics.GaugeMetric(
"puppet/resources",
description=(
"Number of resources known by the puppet client in its last run"
),
)
_times_metric = metrics.FloatMetric(
"puppet/times",
description="Time taken to perform various parts of the last puppet run",
)
_age_metric = metrics.FloatMetric(
"puppet/age", description="Time since last run"
)
class _PuppetRunSummary:
"""Puppet run summary information."""
def __init__(self, f) -> None:
"""Instantiate instance.
Args:
f: file object to read summary from
"""
self._data = yaml.safe_load(f)
@property
def _versions(self):
"""Return mapping of version information."""
return self._data.get("version", {})
@property
def config_version(self):
"""Return config version as int."""
return self._versions.get("config", -1)
@property
def puppet_version(self):
"""Return Puppet version as string."""
return self._versions.get("puppet", "")
@property
def events(self):
"""Return mapping of events information."""
events = self._data.get("events", {})
events.pop("total", None)
return events
@property
def resources(self):
"""Return mapping of resources information."""
resources = self._data.get("resources", {})
total = resources.pop("total", 0)
resources["other"] = max(0, total - sum(resources.values()))
return resources
@property
def times(self):
"""Return mapping of time information."""
times = self._data.get("time", {}).copy()
times.pop("last_run", None)
total = times.pop("total", 0)
times["other"] = max(0, total - sum(times.values()))
return times
@property
def last_run_time(self):
"""Return last run time as UNIX seconds or None."""
times = self._data.get("time", {})
return times.get("last_run")
def collect_puppet_summary() -> None:
"""Send Puppet run summary metrics."""
try:
with open(LAST_RUN_FILE, encoding="utf-8") as f:
summary = _PuppetRunSummary(f)
except Exception as e:
logger.warning("Error loading Puppet run summary: %s", e)
else:
_config_version_metric.set(summary.config_version)
_puppet_version_metric.set(str(summary.puppet_version))
for key, value in summary.events.items():
_events_metric.set(value, {"result": key})
for key, value in summary.resources.items():
_resources_metric.set(value, {"action": key})
for key, value in summary.times.items():
_times_metric.set(value, {"step": key})
if summary.last_run_time is not None:
_age_metric.set(time.time() - summary.last_run_time)