Ejemplo n.º 1
0
def silence(labels, duration=None, **kwargs):
    '''
    Post a silence message to Alert Manager
    Duration should be sent in a format like 1m 2h 1d etc
    '''
    if duration:
        start = timezone.now()
        if duration.endswith('m'):
            end = start + datetime.timedelta(minutes=int(duration[:-1]))
        elif duration.endswith('h'):
            end = start + datetime.timedelta(hours=int(duration[:-1]))
        elif duration.endswith('d'):
            end = start + datetime.timedelta(days=int(duration[:-1]))
        else:
            raise ValidationError('Unknown time modifier')
        kwargs['endsAt'] = end.isoformat()
        kwargs.pop('startsAt', False)
    else:
        local_timezone = pytz.timezone(util.setting("timezone", "UTC"))
        for key in ['startsAt', 'endsAt']:
            kwargs[key] = local_timezone.localize(parser.parse(
                kwargs[key])).isoformat()

    kwargs['matchers'] = [{
        'name': name,
        'value': value,
        'isRegex': True if value.endswith("*") else False
    } for name, value in labels.items()]

    logger.debug("Sending silence for %s", kwargs)
    url = urljoin(util.setting("alertmanager:url"), "/api/v1/silences")
    response = util.post(url, json=kwargs)
    response.raise_for_status()
    return response
Ejemplo n.º 2
0
def settings_in_view(request):
    return {
        "EXTERNAL_LINKS":
        util.setting("links", {}),
        "TIMEZONE":
        util.setting("timezone", "UTC"),
        "VERSION":
        __version__,
        "DEFAULT_EXPORTERS":
        models.DefaultExporter.objects.order_by("job", "-port"),
    }
Ejemplo n.º 3
0
def check_rules(rules):
    '''
    Use promtool to check to see if a rule is valid or not

    The command name changed slightly from 1.x -> 2.x but this uses promtool
    to verify if the rules are correct or not. This can be bypassed by setting
    a dummy command such as /usr/bin/true that always returns true
    '''

    with tempfile.NamedTemporaryFile(mode='w+b') as fp:
        logger.debug('Rendering to %s', fp.name)
        # Normally we wouldn't bother saving a copy to a variable here and would
        # leave it in the fp.write() call, but saving a copy in the variable
        # means we can see the rendered output in a Sentry stacktrace
        rendered = render_rules(rules)
        fp.write(rendered)
        fp.flush()

        # This command changed to be without a space in 2.x
        cmd = [util.setting("prometheus:promtool"), "check", "rules", fp.name]

        try:
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            raise ValidationError(
                rendered.decode('utf8') + e.output.decode('utf8'))
Ejemplo n.º 4
0
def reload_prometheus():
    from promgen import signals

    target = urljoin(util.setting("prometheus:url"), "/-/reload")
    response = util.post(target)
    response.raise_for_status()
    signals.post_reload.send(response)
Ejemplo n.º 5
0
 def delete(self, request, silence_id):
     url = urljoin(util.setting("alertmanager:url"),
                   "/api/v1/silence/%s" % silence_id)
     response = util.delete(url)
     return HttpResponse(response.text,
                         status=response.status_code,
                         content_type="application/json")
Ejemplo n.º 6
0
def promtool(**kwargs):
    try:
        path = pathlib.Path(util.setting("prometheus:promtool"))
    except TypeError:
        yield checks.Warning("Missing setting for " + key)
    else:
        if not os.access(path, os.X_OK):
            yield checks.Warning("Unable to execute file %s" % path)
Ejemplo n.º 7
0
def write_urls(path=None, reload=True, chmod=0o644):
    if path is None:
        path = util.setting("prometheus:blackbox")
    with atomic_write(path, overwrite=True) as fp:
        # Set mode on our temporary file before we write and move it
        os.chmod(fp.name, chmod)
        fp.write(prometheus.render_urls())
    if reload:
        reload_prometheus()
Ejemplo n.º 8
0
 def get(self, request):
     try:
         url = urljoin(util.setting("alertmanager:url"), "/api/v1/silences")
         response = util.get(url, params={"silenced": False})
     except requests.exceptions.ConnectionError:
         logger.error("Error connecting to %s", url)
         return JsonResponse({})
     else:
         return HttpResponse(response.content,
                             content_type="application/json")
Ejemplo n.º 9
0
def directories(**kwargs):
    for key in [
            "prometheus:rules", "prometheus:blackbox", "prometheus:targets"
    ]:
        try:
            path = pathlib.Path(util.setting(key)).parent
        except TypeError:
            yield checks.Warning("Missing setting for " + key)
        else:
            if not os.access(path, os.W_OK):
                yield checks.Warning("Unable to write to %s" % path)
Ejemplo n.º 10
0
    def config(self, key, default=KeyError):
        """
        Plugin specific configuration

        This wraps our PROMGEN settings so that a plugin author does not need to
        be concerned with how the configuration files are handled but only about
        the specific key.
        """
        try:
            return util.setting(key, default=default, domain=self.__module__)
        except KeyError as e:
            raise KeyError(f"Missing key for domain: {self.__module__} {key}") from e
Ejemplo n.º 11
0
def promtool(**kwargs):
    key = "prometheus:promtool"
    try:
        path = pathlib.Path(util.setting(key))
    except TypeError:
        yield checks.Warning(
            "Missing setting for %s in %s " % (key, settings.PROMGEN_CONFIG_FILE),
            id="promgen.W001",
        )
    else:
        if not os.access(path, os.X_OK):
            yield checks.Warning("Unable to execute file %s" % path, id="promgen.W003")
Ejemplo n.º 12
0
def directories(**kwargs):
    for key in ["prometheus:rules", "prometheus:blackbox", "prometheus:targets"]:
        try:
            path = pathlib.Path(util.setting(key)).parent
        except TypeError:
            yield checks.Warning(
                "Missing setting for %s in %s " % (key, settings.PROMGEN_CONFIG_FILE),
                id="promgen.W001",
            )
        else:
            if not os.access(path, os.W_OK):
                yield checks.Warning("Unable to write to %s" % path, id="promgen.W002")
Ejemplo n.º 13
0
    def config(self, key):
        '''
        Plugin specific configuration

        This wraps our PROMGEN settings so that a plugin author does not need to
        be concerned with how the configuration files are handled but only about
        the specific key.
        '''
        try:
            return util.setting(key, domain=self.__module__)
        except KeyError:
            logger.error(
                'Undefined setting. Please check for %s under %s in settings.yml',
                key, self.__module__)
Ejemplo n.º 14
0
def process_alert(alert_pk):
    """
    Process alert for routing and notifications

    We load our Alert from the database and expand it to determine which labels are routable

    Next we loop through all senders configured and de-duplicate sender:target pairs before
    queing the notification to actually be sent
    """
    alert = models.Alert.objects.get(pk=alert_pk)
    routable, data = alert.expand()

    # For any blacklisted label patterns, we delete them from the queue
    # and consider it done (do not send any notification)
    blacklist = util.setting("alertmanager:blacklist", {})
    for key in blacklist:
        logger.debug("Checking key %s", key)
        if key in data["commonLabels"]:
            if data["commonLabels"][key] in blacklist[key]:
                logger.debug("Blacklisted label %s", blacklist[key])
                alert.delete()
                return

    # After processing our blacklist, it should be safe to queue our
    # alert to also index the labels
    index_alert.delay(alert.pk)

    # Now that we have our routable items, we want to check which senders are
    # configured and expand those as needed
    senders = collections.defaultdict(set)
    for label, obj in routable.items():
        logger.debug("Processing %s %s", label, obj)
        for sender in models.Sender.objects.filter(obj=obj, enabled=True):
            if sender.filtered(data):
                logger.debug("Filtered out sender %s", sender)
                continue
            if hasattr(sender.driver, "splay"):
                for splay in sender.driver.splay(sender.value):
                    senders[splay.sender].add(splay.value)
            else:
                senders[sender.sender].add(sender.value)

    for driver in senders:
        for target in senders[driver]:
            send_alert.delay(driver, target, data, alert.pk)
Ejemplo n.º 15
0
def strftime(timestamp, fmt):
    tz = util.setting("timezone", "UTC")
    if isinstance(timestamp, int) or isinstance(timestamp, float):
        return timezone(tz).localize(datetime.fromtimestamp(timestamp)).strftime(fmt)
    return timestamp
Ejemplo n.º 16
0
def clear_tombstones():
    target = urljoin(util.setting("prometheus:url"),
                     "/api/v1/admin/tsdb/clean_tombstones")
    response = util.post(target)
    response.raise_for_status()