Beispiel #1
0
 def test_get_backend_cls(self):
     res1 = get_backend_cls("Stackdriver")
     res2 = get_backend_cls("Prometheus")
     self.assertEqual(res1.__name__, "StackdriverBackend")
     self.assertEqual(res2.__name__, "PrometheusBackend")
     with self.assertRaises(SystemExit):
         get_backend_cls("UndefinedBackend")
Beispiel #2
0
 def test_get_backend_cls(self):
     res1 = get_backend_cls("Stackdriver")
     res2 = get_backend_cls("Prometheus")
     self.assertEqual(res1.__name__, "StackdriverBackend")
     self.assertEqual(res1.__module__, "slo_generator.backends.stackdriver")
     self.assertEqual(res2.__name__, "PrometheusBackend")
     self.assertEqual(res2.__module__, "slo_generator.backends.prometheus")
     with self.assertRaises(ModuleNotFoundError):
         get_backend_cls("UndefinedBackend")
def make_reports(slo_config,
                 error_budget_policy,
                 timestamp,
                 client=None,
                 backend_obj=None,
                 backend_method=None,
                 backend_config=None):
    """Run SLO reports for each step in the Error Budget config.

    Args:
        slo_config (dict): SLO configuration.
        error_budget_policy (dict): Error Budget policy.
        timestamp (int): UNIX timestamp.
        client (obj) (optional): Existing metrics backend client.
        backend_obj (obj) (optional): Backend object (if unset, will be imported
            dynamically from slo_config). Use when you want to try new backends
            that are not implemented in the backends/ folder.
        backend_method (str) (optional): Backend method (if unset, will be
            imported dynamically from slo_config). Use when you want to try new
            backends that are not implemented in the backends/ folder.
            This must return a tuple of (n_good_events[int], n_bad_events[int]).
            The method must take the following arguments:
                - timestamp (int): query timestamp.
                - window (int): query window duration.
        backend_config (dict) (optional): Backend config.

    Yields:
        list: List of SLO measurement results.
    """
    if backend_method:
        if backend_obj:
            backend_method = getattr(backend_obj, backend_method)
        LOGGER.info("Backend method: %s (from kwargs).", backend_method)
    else:
        backend_config = slo_config.get('backend', {})
        backend_cls = backend_config.get('class')
        method = backend_config.get('method')
        backend_obj = utils.get_backend_cls(backend_cls)(client=client,
                                                         **backend_config)
        backend_method = getattr(backend_obj, method)
        LOGGER.info("Backend method: %s (from SLO config file).",
                    backend_cls + '.' + backend_method.__name__)

    # Loop through steps defined in error budget policy and make measurements
    for step in error_budget_policy:
        good_event_count, bad_event_count = backend_method(
            timestamp=timestamp,
            window=step['measurement_window_seconds'],
            **slo_config['backend'])
        report = make_measurement(slo_config, step, good_event_count,
                                  bad_event_count, timestamp)
        import pprint
        pprint.pprint(report)
        yield report
Beispiel #4
0
    def run_backend(self, config, client=None, delete=False):
        """Get appropriate backend method from SLO configuration and run it on
        current SLO config and Error Budget Policy step.

        Args:
            config (dict): SLO configuration.
            client (obj, optional): Backend client initiated beforehand.
            delete (bool, optional): Set to True if we're running a delete
                action.

        Returns:
            obj: Backend data.
        """
        info = self.__get_info()

        # Grab backend class and method dynamically.
        cfg = config.get('backend', {})
        cls = cfg.get('class')
        method = cfg.get('method')
        excluded_keys = ['class', 'method', 'measurement']
        backend_cfg = {k: v for k, v in cfg.items() if k not in excluded_keys}
        instance = utils.get_backend_cls(cls)(client=client, **backend_cfg)
        method = getattr(instance, method)
        LOGGER.debug(f'{info} | '
                     f'Using backend {cls}.{method.__name__} (from '
                     f'SLO config file).')

        # Delete mode activation.
        if delete and hasattr(instance, 'delete'):
            method = instance.delete
            LOGGER.warning(f'{info} | Delete mode enabled.')

        # Run backend method and return results.
        data = method(self.timestamp, self.window, config)
        LOGGER.debug(f'{info} | Backend response: {data}')
        return data
Beispiel #5
0
 def test_get_backend_dynamic_cls(self):
     res1 = get_backend_cls("pathlib.Path")
     self.assertEqual(res1.__name__, "Path")
     self.assertEqual(res1.__module__, "pathlib")
     with self.assertRaises(ModuleNotFoundError):
         get_exporter_cls("foo.bar.DoesNotExist")