# Copyright 2013 Hewlett-Packard Development Company, L.P. # Copyright 2016 Cray Inc. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import json from django.conf import settings from django import template from django.urls import reverse from django.urls import reverse_lazy from django.utils.translation import ugettext_lazy as _ # noqa from django.utils.translation import ungettext_lazy from horizon import tables from monitoring.alarms import constants from monitoring import api from monitoring.overview import constants as ov_constants STATUS = ["OK", "WARNING", "CRITICAL", "UNKNOWN"] def get_status(index): if index < len(STATUS): return STATUS[index] else: return "UNKNOWN: %d" % index def show_status(data): status = data.upper() img_tag = '{label}' if status == 'CRITICAL': return img_tag.format(img=constants.CRITICAL_ICON, label=status) if status in ('LOW', 'MEDIUM', 'HIGH'): return img_tag.format(img=constants.WARNING_ICON, label=status) if status == 'OK': return img_tag.format(img=constants.OK_ICON, label=status) if status == 'UNKNOWN' or status == 'UNDETERMINED': return img_tag.format(img=constants.UNKNOWN_ICON, label=status) return status def show_severity(data): severity = data['alarm_definition']['severity'] state = data['state'] if state == 'ALARM': return severity.upper() else: return state.upper() def show_alarm_id(data): return data['id'] def show_metric_names(data): names = set(metric['name'] for metric in data['metrics']) return ', '.join(names) def show_def_name(data): return data['alarm_definition']['name'] def show_def_severity(data): return data['alarm_definition']['severity'] def show_metric_dimensions(data): if len(data['metrics']) > 1: commondimensions = data['metrics'][0]['dimensions'] for metric in data['metrics'][1:]: for k in tuple(commondimensions): if k not in metric['dimensions'].keys() or \ commondimensions[k] != metric['dimensions'][k]: del commondimensions[k] return ','.join(["%s=%s" % (n, v) for n, v in commondimensions.items()]) else: return ','.join(["%s=%s" % (n, v) for n, v in data['metrics'][0]['dimensions'].items()]) def get_service(data): if len(data['metrics']) == 1 and 'service'in\ data['metrics'][0]['dimensions']: return data['metrics'][0]['dimensions']['service'] else: return '' class ShowAlarmHistory(tables.LinkAction): name = 'history' verbose_name = _('Show History') classes = ('btn-edit',) def get_link_url(self, datum): return reverse(constants.URL_PREFIX + 'history', args=(datum['alarm_definition']['id'], datum['id'], )) def allowed(self, request, datum=None): return True class CreateAlarm(tables.LinkAction): name = "create_alarm" verbose_name = _("Create Alarm") classes = ("ajax-modal",) icon = "plus" policy_rules = (("alarm", "alarm:create"),) ajax = True def get_link_url(self): return reverse(constants.URL_PREFIX + 'alarm_create', args=(self.table.kwargs['service'],)) def allowed(self, request, datum=None): return True class EditAlarm(tables.LinkAction): name = "edit_alarm" verbose_name = _("Edit Alarm") classes = ("ajax-modal", "btn-create") def get_link_url(self, datum): return reverse(constants.URL_PREFIX + 'alarm_edit', args=(self.table.kwargs['service'], datum['id'], )) def allowed(self, request, datum=None): return True class GraphMetric(tables.LinkAction): name = "graph_alarm" verbose_name = _("Graph Metric") icon = "dashboard" def render(self): self.attrs['target'] = 'newtab' return super(self, GraphMetric).render() def get_link_url(self, datum): url = '' query = '' self.attrs['target'] = '_blank' try: region = self.table.request.user.services_region grafana_url = getattr(settings, 'GRAFANA_URL').get(region, '') url = grafana_url + \ '/dashboard/script/drilldown.js' metric = datum['metrics'][0]['name'] dimensions = datum['metrics'][0].get('dimensions', {}) query = "?metric=%s" % metric for key, value in dimensions.items(): query += "&%s=%s" % (key, value) except AttributeError: # Catches case where Grafana 2 is not enabled. name = datum['metrics'][0]['name'] threshold = json.dumps(datum['metrics']) endpoint = str(reverse_lazy(ov_constants.URL_PREFIX + 'proxy')) endpoint = self.table.request.build_absolute_uri(endpoint) url = '/grafana/index.html#/dashboard/script/detail.js' query = "?name=%s&threshold=%s&api=%s" % \ (name, threshold, endpoint) return url + query def allowed(self, request, datum=None): return (getattr(settings, 'GRAFANA_URL', None) is not None and datum['metrics']) class ShowAlarmDefinition(tables.LinkAction): name = "show_alarm_definition" verbose_name = _("Show Alarm Definition") def get_link_url(self, datum=None): url = 'horizon:monitoring:alarmdefs:alarm_detail' args = (datum['alarm_definition']['id'],) return reverse_lazy(url, args=args) class DeleteAlarm(tables.DeleteAction): name = "delete_alarm" verbose_name = _("Delete Alarm") @staticmethod def action_present(count): return ungettext_lazy( u"Delete Alarm", u"Delete Alarms", count ) @staticmethod def action_past(count): return ungettext_lazy( u"Deleted Alarm", u"Deleted Alarms", count ) def allowed(self, request, datum=None): return True def delete(self, request, obj_id): api.monitor.alarm_delete(request, obj_id) class AlarmsFilterAction(tables.LinkAction): name = "filter" verbose_name = _("Filter Alarms") classes = ("ajax-modal",) icon = "plus" policy_rules = (("alarm", "alarm:filter"),) ajax = True def get_link_url(self): return reverse(constants.URL_PREFIX + 'alarm_filter', args=()) def allowed(self, request, datum=None): return True class AlarmsTable(tables.DataTable): state = tables.Column(transform=show_severity, verbose_name=_('Status'), status_choices={(show_status('OK'), True)}, filters=[show_status, template.defaultfilters.safe]) name = tables.Column(transform=show_def_name, verbose_name=_('Name')) alarmId = tables.Column(transform=show_alarm_id, verbose_name=_('Alarm Id')) metrics = tables.Column(transform=show_metric_names, verbose_name=_('Metric Names')) dimensions = tables.Column(transform=show_metric_dimensions, verbose_name=_('Metric Dimensions')) def get_object_id(self, obj): return obj['id'] def get_object_display(self, obj): return obj['id'] class Meta(object): name = "alarms" verbose_name = _("Alarms") row_actions = (GraphMetric, ShowAlarmHistory, ShowAlarmDefinition, DeleteAlarm, ) table_actions = (AlarmsFilterAction, DeleteAlarm, ) def show_timestamp(data): return data['timestamp'].replace('.000Z', '').replace('T', ' ') class AlarmHistoryTable(tables.DataTable): timestamp = tables.Column(transform=show_timestamp, verbose_name=_('Timestamp'), attrs={"data-type": "timestamp"}) old_state = tables.Column('old_state', verbose_name=_('Old State')) new_state = tables.Column('new_state', verbose_name=_('New State')) alarmDimensions = tables.Column(transform=show_metric_dimensions, verbose_name=_('Alarm Metric Dimensions')) reason = tables.Column('reason', verbose_name=_('Reason')) # reason_data = tables.Column('reason_data', verbose_name=_('Reason Data')) def get_object_id(self, obj): return obj['alarm_id'] + obj['timestamp'] class Meta(object): name = "history" verbose_name = _("Alarm History")