This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/data/migrations/progress.py
2019-11-12 11:09:47 -05:00

101 lines
3.1 KiB
Python

from abc import ABCMeta, abstractmethod
from six import add_metaclass
from functools import partial, wraps
from prometheus_client import CollectorRegistry, Gauge, Counter, push_to_gateway
from util.abchelpers import nooper
@add_metaclass(ABCMeta)
class ProgressReporter(object):
""" Implements an interface for reporting progress with the migrations.
"""
@abstractmethod
def report_version_complete(self, success):
""" Called when an entire migration is complete. """
@abstractmethod
def report_step_progress(self):
""" Called when a single step in the migration has been completed. """
@nooper
class NullReporter(ProgressReporter):
""" No-op version of the progress reporter, designed for use when no progress
reporting endpoint is provided. """
class PrometheusReporter(ProgressReporter):
def __init__(self, prom_pushgateway_addr, prom_job, labels, total_steps_num=None):
self._total_steps_num = total_steps_num
self._completed_steps = 0.0
registry = CollectorRegistry()
self._migration_completion_percent = Gauge(
'migration_completion_percent',
'Estimate of the completion percentage of the job',
registry=registry,
)
self._migration_complete_total = Counter(
'migration_complete_total',
'Binary value of whether or not the job is complete',
registry=registry,
)
self._migration_failed_total = Counter(
'migration_failed_total',
'Binary value of whether or not the job has failed',
registry=registry,
)
self._migration_items_completed_total = Counter(
'migration_items_completed_total',
'Number of items this migration has completed',
registry=registry,
)
self._push = partial(push_to_gateway,
prom_pushgateway_addr,
job=prom_job,
registry=registry,
grouping_key=labels,
)
def report_version_complete(self, success=True):
if success:
self._migration_complete_total.inc()
else:
self._migration_failed_total.inc()
self._migration_completion_percent.set(1.0)
self._push()
def report_step_progress(self):
self._migration_items_completed_total.inc()
if self._total_steps_num is not None:
self._completed_steps += 1
self._migration_completion_percent = self._completed_steps / self._total_steps_num
self._push()
class ProgressWrapper(object):
def __init__(self, delegate_module, progress_monitor):
self._delegate_module = delegate_module
self._progress_monitor = progress_monitor
def __getattr__(self, attr_name):
# Will raise proper attribute error
maybe_callable = self._delegate_module.__dict__[attr_name]
if callable(maybe_callable):
# Build a callable which when executed places the request
# onto a queue
@wraps(maybe_callable)
def wrapped_method(*args, **kwargs):
result = maybe_callable(*args, **kwargs)
self._progress_monitor.report_step_progress()
return result
return wrapped_method
return maybe_callable