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)
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)
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)
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)
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")
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")
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) })
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')
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)
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)