Esempio n. 1
0
    def get(self, request):
        alerts = []
        try:
            url = urljoin(settings.PROMGEN["alertmanager"]["url"],
                          "/api/v1/alerts")
            response = util.get(url)
        except requests.exceptions.ConnectionError:
            logger.error("Error connecting to %s", url)
            return JsonResponse({})

        data = response.json().get("data", [])
        if data is None:
            # Return an empty alert-all if there are no active alerts from AM
            return JsonResponse({})

        for alert in data:
            alert.setdefault("annotations", {})
            # Humanize dates for frontend
            for key in ["startsAt", "endsAt"]:
                if key in alert:
                    alert[key] = parser.parse(alert[key])
            # Convert any links to <a> for frontend
            for k, v in alert["annotations"].items():
                alert["annotations"][k] = defaultfilters.urlize(v)
            alerts.append(alert)
        return JsonResponse({"data": data}, safe=False)
Esempio n. 2
0
    def post(self, request):
        silences = collections.defaultdict(list)
        try:
            url = urljoin(settings.PROMGEN['alertmanager']['url'], '/api/v1/silences')
            response = util.get(url)
        except requests.exceptions.ConnectionError:
            logger.error('Error connecting to %s', url)
            return JsonResponse({})

        data = response.json().get('data', [])
        if data is None:
            # Return an empty silence-all if there are no active silences from AM
            return JsonResponse({})

        currentAt = datetime.datetime.now(datetime.timezone.utc)

        for silence in data:
            # Since there is no status field, compare endsAt with the current time
            if 'endsAt' in silence:
                silence['endsAt'] = parser.parse(silence['endsAt'])
                if silence['endsAt'] < currentAt:
                    continue

            silences['silence-all'].append(silence)
            for matcher in silence.get('matchers'):
                if matcher.get('name') in ['service', 'project']:
                    silences['silence-{}-{}'.format(matcher.get('name'), matcher.get('value'))].append(silence)

        context = {'#' + slugify(key): render_to_string('promgen/ajax_silence.html', {'silences': silences[key], 'key': key}, request).strip() for key in silences}
        context['#silence-load'] = render_to_string('promgen/ajax_silence_button.html', {'silences': silences['silence-all'], 'key': 'silence-all'}).strip()

        return JsonResponse(context)
Esempio n. 3
0
    def get(self, request):
        alerts = []
        try:
            url = urljoin(settings.PROMGEN['alertmanager']['url'], '/api/v1/alerts')
            response = util.get(url)
        except requests.exceptions.ConnectionError:
            logger.error('Error connecting to %s', url)
            return JsonResponse({})

        data = response.json().get('data', [])
        if data is None:
            # Return an empty alert-all if there are no active alerts from AM
            return JsonResponse({})

        for alert in data:
            alert.setdefault('annotations', {})
            # Humanize dates for frontend
            for key in ['startsAt', 'endsAt']:
                if key in alert:
                    alert[key] = parser.parse(alert[key])
            # Convert any links to <a> for frontend
            for k, v in alert['annotations'].items():
                alert['annotations'][k] = defaultfilters.urlize(v)
            alerts.append(alert)
        return JsonResponse(alerts, safe=False)
Esempio n. 4
0
    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = form_class(request.POST, request.FILES)

        if 'rules' in request.POST:
            form = forms.ImportRuleForm(request.POST)
            if form.is_valid():
                data = form.clean()
                counters = prometheus.import_rules(data['rules'])
                messages.info(request, 'Imported %s' % counters)
                return self.form_valid(form)
            else:
                return self.form_invalid(form)

        if form.is_valid():
            data = form.clean()
            if data.get('file_field'):
                messages.info(request, 'Importing config from file')
                config = data['file_field'].read().decode('utf8')
            elif data.get('url'):
                messages.info(request, 'Importing config from url')
                response = util.get(data['url'])
                response.raise_for_status()
                config = response.text
            else:
                messages.info(request, 'Importing config')
                config = data['config']

            kwargs = {}
            # This also lets us catch passing an empty string to signal using
            # the shard value from the post request
            if data.get('shard'):
                kwargs['replace_shard'] = data.get('shard')

            imported, skipped = prometheus.import_config(json.loads(config), **kwargs)

            if imported:
                counters = {key: len(imported[key]) for key in imported}
                messages.info(request, 'Imported %s' % counters)

            if skipped:
                counters = {key: len(skipped[key]) for key in skipped}
                messages.info(request, 'Skipped %s' % counters)

            # If we only have a single object in a category, automatically
            # redirect to that category to make things easier to understand
            if len(imported['Project']) == 1:
                return HttpResponseRedirect(imported['Project'][0].get_absolute_url())
            if len(imported['Service']) == 1:
                return HttpResponseRedirect(imported['Service'][0].get_absolute_url())
            if len(imported['Shard']) == 1:
                return HttpResponseRedirect(imported['Shard'][0].get_absolute_url())

            # otherwise we can just use the default behavior
            return self.form_valid(form)
        else:
            return self.form_invalid(form)
Esempio n. 5
0
 def get(self, request):
     try:
         url = urljoin(settings.PROMGEN["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")
Esempio n. 6
0
 def get(self, request):
     try:
         url = urljoin(util.setting("alertmanager:url"), "/api/v1/alerts")
         response = util.get(url)
     except requests.exceptions.ConnectionError:
         logger.error("Error connecting to %s", url)
         return JsonResponse({})
     else:
         return HttpResponse(response.content,
                             content_type="application/json")
Esempio n. 7
0
    def post(self, request, pk):
        if pk == 0:
            rule = models.Rule()
            rule.set_object(request.POST['content_type'],
                            request.POST['object_id'])
        else:
            rule = get_object_or_404(models.Rule, id=pk)

        query = macro.rulemacro(rule, request.POST['query'])
        # Since our rules affect all servers we use Promgen's proxy-query to test our rule
        # against all the servers at once
        url = resolve_domain('proxy-query')

        logger.debug('Querying %s with %s', url, query)
        start = time.time()
        result = util.get(url, {'query': query}).json()
        duration = datetime.timedelta(seconds=(time.time() - start))

        context = {
            'status': result['status'],
            'duration': duration,
            'query': query
        }
        context['data'] = result.get('data', {})

        context['errors'] = {}

        metrics = context['data'].get('result', [])
        if metrics:
            context['collapse'] = len(metrics) > 5
            for row in metrics:
                if 'service' not in row['metric'] and \
                        'project' not in row['metric']:
                    context['errors'][
                        'routing'] = 'Some metrics are missing service and project labels so Promgen will be unable to route message'
                    context['status'] = 'warning'
        else:
            context['status'] = 'info'
            context['errors'][
                'no_results'] = 'No Results. May need to remove conditional check (> < ==) to verity'

        # Place this at the bottom to have a query error show up as danger
        if result['status'] != 'success':
            context['status'] = 'danger'
            context['errors']['Query'] = result['error']

        return JsonResponse({
            request.POST['target']:
            render_to_string('promgen/ajax_clause_check.html', context)
        })
Esempio n. 8
0
    def form_valid(self, form):
        data = form.clean()
        if data.get('file_field'):
            messages.info(self.request, 'Importing config from file')
            config = data['file_field'].read().decode('utf8')
        elif data.get('url'):
            messages.info(self.request, 'Importing config from url')
            response = util.get(data['url'])
            response.raise_for_status()
            config = response.text
        elif data.get('config'):
            messages.info(self.request, 'Importing config')
            config = data['config']
        else:
            messages.warning(self.request, 'Missing config')
            return self.form_invalid(form)

        kwargs = {}
        # This also lets us catch passing an empty string to signal using
        # the shard value from the post request
        if data.get('shard'):
            kwargs['replace_shard'] = data.get('shard')

        imported, skipped = prometheus.import_config(json.loads(config),
                                                     **kwargs)

        if imported:
            counters = {key: len(imported[key]) for key in imported}
            messages.info(self.request, 'Imported %s' % counters)

        if skipped:
            counters = {key: len(skipped[key]) for key in skipped}
            messages.info(self.request, 'Skipped %s' % counters)

        # If we only have a single object in a category, automatically
        # redirect to that category to make things easier to understand
        if len(imported['Project']) == 1:
            return HttpResponseRedirect(
                imported['Project'][0].get_absolute_url())
        if len(imported['Service']) == 1:
            return HttpResponseRedirect(
                imported['Service'][0].get_absolute_url())
        if len(imported['Shard']) == 1:
            return HttpResponseRedirect(
                imported['Shard'][0].get_absolute_url())

        return redirect('service-list')
Esempio n. 9
0
    def get(self, request):
        alerts = collections.defaultdict(list)
        try:
            url = urljoin(settings.PROMGEN['alertmanager']['url'],
                          '/api/v1/alerts')
            response = util.get(url)
        except requests.exceptions.ConnectionError:
            logger.error('Error connecting to %s', url)
            return JsonResponse({})

        data = response.json().get('data', [])
        if data is None:
            # Return an empty alert-all if there are no active alerts from AM
            return JsonResponse({})
        for alert in data:
            for key in ['startsAt', 'endsAt']:
                if key in alert:
                    alert[key] = parser.parse(alert[key])

            alerts['alert-all'].append(alert)
            for key in ['project', 'service']:
                # Requires newer 0.7 alert manager release to have the status
                # information with silenced and inhibited alerts
                if 'status' in alert:
                    if alert['status'].get('silencedBy') or alert[
                            'status'].get('inhibitedBy'):
                        continue
                if key in alert['labels'] and alert['labels'][key]:
                    alerts['alert-{}-{}'.format(
                        key, alert['labels'][key])].append(alert)

        context = {
            '#' + slugify(key): render_to_string('promgen/ajax_alert.html', {
                'alerts': alerts[key],
                'key': key
            }, request).strip()
            for key in alerts
        }
        context['#alert-load'] = render_to_string(
            'promgen/ajax_alert_button.html', {
                'alerts': alerts['alert-all'],
                'key': 'alert-all'
            }).strip()

        return JsonResponse(context)
Esempio n. 10
0
    def handle(self, target_file, replace_shard, **kwargs):
        if target_file.startswith('http'):
            config = util.get(target_file).json()
        else:
            config = json.load(open(target_file), encoding='utf8')

        imported, skipped = prometheus.import_config(config, replace_shard)

        if imported:
            counters = {key: len(imported[key]) for key in imported}
            self.stdout.write('Imported {}'.format(counters))

        if skipped:
            counters = {key: len(skipped[key]) for key in skipped}
            self.stdout.write('Skipped {}'.format(counters))

        trigger_write_config.send(self, force=True)
        trigger_write_rules.send(self, force=True)
        trigger_write_urls.send(self, force=True)