Merge "Refactor the FM panel to leverage AngularJS"

This commit is contained in:
Zuul 2019-01-23 16:45:01 +00:00 committed by Gerrit Code Review
commit 96e49c9a91
64 changed files with 2348 additions and 1099 deletions

View File

@ -1,2 +1,2 @@
SRC_DIR="starlingx-dashboard"
TIS_PATCH_VER=22
TIS_PATCH_VER=23

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
# Copyright (c) 2018-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -248,9 +248,14 @@ class EventSuppression(base.APIResourceWrapper):
super(EventSuppression, self).__init__(apiresource)
def event_suppression_list(request):
def event_suppression_list(request, include_unsuppressed=False):
q = []
if not include_unsuppressed:
q.append(
dict(field='suppression_status', value='suppressed', op='eq',
type='string'))
suppression_list = fmclient(request).event_suppression.list()
suppression_list = fmclient(request).event_suppression.list(q)
return [EventSuppression(n) for n in suppression_list]

View File

@ -1,8 +1,9 @@
#
# Copyright (c) 2018 Wind River Systems, Inc.
# Copyright (c) 2018-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
from django.views import generic
@ -11,6 +12,9 @@ from openstack_dashboard.api.rest import utils as rest_utils
from starlingx_dashboard.api import fm
LOG = logging.getLogger(__name__)
@urls.register
class AlarmSummary(generic.View):
"""API for retrieving alarm summaries."""
@ -22,3 +26,81 @@ class AlarmSummary(generic.View):
include_suppress = request.GET.get('include_suppress', False)
result = fm.alarm_summary_get(request, include_suppress)
return result.to_dict()
@urls.register
class Alarms(generic.View):
"""API for retrieving alarms."""
url_regex = r'fm/alarm_list/$'
@rest_utils.ajax()
def get(self, request):
search_opts = {'suppression': 'SUPPRESS_SHOW'}
result = fm.alarm_list(request, search_opts=search_opts)
return {'items': [sc.to_dict() for sc in result]}
@urls.register
class Alarm(generic.View):
"""API for retrieving one alarm."""
url_regex = r'fm/alarm_get/(?P<uuid>[^/]+|default)/$'
@rest_utils.ajax()
def get(self, request, uuid):
result = fm.alarm_get(request, uuid)
return result.to_dict()
@urls.register
class Events(generic.View):
"""API for retrieving events."""
url_regex = r'fm/event_log_list/$'
@rest_utils.ajax()
def get(self, request):
search_opts = {'suppression': 'SUPPRESS_SHOW'}
result, _more = fm.event_log_list(request, search_opts=search_opts)
return {'items': [sc.to_dict() for sc in result]}
@urls.register
class Event(generic.View):
"""API for retrieving one event."""
url_regex = r'fm/event_log_get/(?P<uuid>[^/]+|default)/$'
@rest_utils.ajax()
def get(self, request, uuid):
result = fm.event_log_get(request, uuid)
return result.to_dict()
@urls.register
class EventsSuppression(generic.View):
"""API for retrieving events suppression."""
url_regex = r'fm/events_suppression_list/$'
@rest_utils.ajax()
def get(self, request):
if 'include_unsuppressed' in request.GET:
include_unsuppressed = True
else:
include_unsuppressed = False
result = fm.event_suppression_list(
request, include_unsuppressed=include_unsuppressed)
return {'items': [sc.to_dict() for sc in result]}
@urls.register
class EventSuppression(generic.View):
"""API for updating the event suppression."""
url_regex = r'fm/event_suppression/(?P<uuid>[^/]+)$'
@rest_utils.ajax(data_required=True)
def patch(self, request, uuid):
result = fm.event_suppression_update(request, uuid, **(request.DATA))
return result.to_dict()

View File

@ -1,9 +1,3 @@
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, Inc.
#
# 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
@ -16,7 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2017 Wind River Systems, Inc.
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.utils.translation import ugettext_lazy as _ # noqa
@ -26,10 +22,9 @@ from openstack_dashboard.api import base
from openstack_dashboard.dashboards.admin import dashboard
class FaultManagement(horizon.Panel):
name = _("Fault Management")
slug = 'fault_management'
permissions = ('openstack.services.platform',)
class ActiveAlarms(horizon.Panel):
name = _("Active Alarms")
slug = "active_alarms"
def allowed(self, context):
if context['request'].user.services_region == 'SystemController':
@ -37,7 +32,7 @@ class FaultManagement(horizon.Panel):
if not base.is_service_enabled(context['request'], 'platform'):
return False
else:
return super(FaultManagement, self).allowed(context)
return super(ActiveAlarms, self).allowed(context)
def nav(self, context):
if context['request'].user.services_region == 'SystemController':
@ -48,4 +43,4 @@ class FaultManagement(horizon.Panel):
return True
dashboard.Admin.register(FaultManagement)
dashboard.Admin.register(ActiveAlarms)

View File

@ -0,0 +1,29 @@
# 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.
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
from starlingx_dashboard.dashboards.admin.active_alarms import \
views as viewsDjango
title = _("Active Alarms")
urlpatterns = [
url(r'^$', views.AngularIndexView.as_view(title=title), name='index'),
url(r'^banner/$', viewsDjango.BannerView.as_view(), name='banner')
]

View File

@ -0,0 +1,76 @@
# 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.
#
# Copyright (c) 2013-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
from django.utils.translation import ugettext_lazy as _ # noqa
from django.views.generic import TemplateView
from horizon import exceptions
from openstack_dashboard.api.base import is_service_enabled
from starlingx_dashboard.api import dc_manager
from starlingx_dashboard.api import fm
LOG = logging.getLogger(__name__)
class BannerView(TemplateView):
template_name = 'header/_alarm_banner.html'
def get_context_data(self, **kwargs):
context = super(BannerView, self).get_context_data(**kwargs)
if not self.request.is_ajax():
raise exceptions.NotFound()
if (not self.request.user.is_authenticated() or
not self.request.user.is_superuser):
context["alarmbanner"] = False
elif 'dc_admin' in self.request.META.get('HTTP_REFERER'):
summaries = self.get_subcloud_data()
central_summary = self.get_data()
summaries.append(central_summary)
context["dc_admin"] = True
context["alarmbanner"] = True
context["OK"] = len(
[s for s in summaries if s.status == 'OK'])
context["degraded"] = len(
[s for s in summaries if s.status == 'degraded'])
context["critical"] = len(
[s for s in summaries if s.status == 'critical'])
context["disabled"] = len(
[s for s in summaries if s.status == 'disabled'])
elif is_service_enabled(self.request, 'platform'):
context["summary"] = self.get_data()
context["alarmbanner"] = True
return context
def get_data(self):
summary = None
try:
summary = fm.alarm_summary_get(self.request)
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve alarm summary.'))
return summary
def get_subcloud_data(self):
return dc_manager.alarm_summary_list(self.request)

View File

@ -0,0 +1,41 @@
# 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.
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.api import base
class Events(horizon.Panel):
name = _("Events")
slug = "events"
def allowed(self, context):
if context['request'].user.services_region == 'SystemController':
return False
if not base.is_service_enabled(context['request'], 'platform'):
return False
else:
return super(Events, self).allowed(context)
def nav(self, context):
if context['request'].user.services_region == 'SystemController':
return False
if not base.is_service_enabled(context['request'], 'platform'):
return False
else:
return True

View File

@ -0,0 +1,25 @@
# 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.
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
title = _("Events")
urlpatterns = [
url('', views.AngularIndexView.as_view(title=title), name='index'),
]

View File

@ -0,0 +1,41 @@
# 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.
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.api import base
class EventsSuppression(horizon.Panel):
name = _("Events Suppression")
slug = "events_suppression"
def allowed(self, context):
if context['request'].user.services_region == 'SystemController':
return False
if not base.is_service_enabled(context['request'], 'platform'):
return False
else:
return super(EventsSuppression, self).allowed(context)
def nav(self, context):
if context['request'].user.services_region == 'SystemController':
return False
if not base.is_service_enabled(context['request'], 'platform'):
return False
else:
return True

View File

@ -0,0 +1,25 @@
# 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.
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
title = _("Events Suppression")
urlpatterns = [
url('', views.AngularIndexView.as_view(title=title), name='index'),
]

View File

@ -1,280 +0,0 @@
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, Inc.
#
# 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.
#
# Copyright (c) 2013-2018 Wind River Systems, Inc.
#
from django.utils.html import escape as escape_html
from django.utils.safestring import mark_safe
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _ # noqa
from django.utils.translation import ungettext_lazy
from horizon import exceptions
from horizon import tables
from horizon.utils import filters as utils_filters
from starlingx_dashboard import api as stx_api
SUPPRESSION_STATUS_CHOICES = (
("suppressed", False),
("unsuppressed", True),
("None", True),
)
SUPPRESSION_STATUS_DISPLAY_CHOICES = (
("suppressed", pgettext_lazy("Indicates this type of alarm \
is suppressed", "suppressed")),
("unsuppressed", pgettext_lazy("Indicates this type of alarm \
is unsuppressed", "unsuppressed")),
("None", pgettext_lazy("Indicates an event type", "None")),
)
class AlarmsLimitAction(tables.LimitAction):
verbose_name = _("Alarms")
class AlarmFilterAction(tables.FixedWithQueryFilter):
def __init__(self, **kwargs):
super(AlarmFilterAction, self).__init__(**kwargs)
self.filter_choices = [
(
(stx_api.fm.FM_SUPPRESS_SHOW, _("Show Suppressed"), True),
(stx_api.fm.FM_SUPPRESS_HIDE, _('Hide Suppressed'), True)
)
]
self.default_value = stx_api.fm.FM_SUPPRESS_HIDE
self.disabled_choices = ['enabled']
class AlarmsTable(tables.DataTable):
alarm_id = tables.Column('alarm_id',
link="horizon:admin:fault_management:detail",
verbose_name=_('Alarm ID'))
reason_text = tables.Column('reason_text',
verbose_name=_('Reason Text'))
entity_instance_id = tables.Column('entity_instance_id',
verbose_name=_('Entity Instance ID'))
suppression_status = \
tables.Column('suppression_status',
verbose_name=_('Suppression Status'),
status=True,
status_choices=SUPPRESSION_STATUS_CHOICES,
display_choices=SUPPRESSION_STATUS_DISPLAY_CHOICES)
severity = tables.Column('severity',
verbose_name=_('Severity'))
timestamp = tables.Column('timestamp',
attrs={'data-type': 'timestamp'},
filters=(utils_filters.parse_isotime,),
verbose_name=_('Timestamp'))
def get_object_id(self, obj):
return obj.uuid
class Meta(object):
name = "alarms"
verbose_name = _("Active Alarms")
status_columns = ["suppression_status"]
limit_param = "alarm_limit"
pagination_param = "alarm_marker"
prev_pagination_param = 'prev_alarm_marker'
table_actions = (AlarmFilterAction, AlarmsLimitAction)
multi_select = False
hidden_title = False
class EventLogsLimitAction(tables.LimitAction):
verbose_name = _("Events")
class EventLogsFilterAction(tables.FixedWithQueryFilter):
def __init__(self, **kwargs):
super(EventLogsFilterAction, self).__init__(**kwargs)
self.filter_choices = [
(
(stx_api.fm.FM_ALL, _("All Events"), True),
(stx_api.fm.FM_ALARM, _('Alarm Events'), True),
(stx_api.fm.FM_LOG, _('Log Events'), True),
),
(
(stx_api.fm.FM_SUPPRESS_SHOW, _("Show Suppressed"), True),
(stx_api.fm.FM_SUPPRESS_HIDE, _('Hide Suppressed'), True)
)
]
self.default_value = stx_api.fm.FM_ALL_SUPPRESS_HIDE
self.disabled_choices = ['enabled', 'enabled']
class EventLogsTable(tables.DataTable):
timestamp = tables.Column('timestamp',
attrs={'data-type': 'timestamp'},
filters=(utils_filters.parse_isotime,),
verbose_name=_('Timestamp'))
state = tables.Column('state', verbose_name=_('State'))
event_log_id = tables.Column('event_log_id',
link="horizon:admin:fault_management:"
"eventlogdetail",
verbose_name=_('ID'))
reason_text = tables.Column('reason_text', verbose_name=_('Reason Text'))
entity_instance_id = tables.Column('entity_instance_id',
verbose_name=_('Entity Instance ID'))
suppression_status = \
tables.Column('suppression_status',
verbose_name=_('Suppression Status'),
status=True,
status_choices=SUPPRESSION_STATUS_CHOICES,
display_choices=SUPPRESSION_STATUS_DISPLAY_CHOICES)
severity = tables.Column('severity', verbose_name=_('Severity'))
def get_object_id(self, obj):
return obj.uuid
class Meta(object):
name = "eventLogs"
verbose_name = _("Events")
status_columns = ["suppression_status"]
table_actions = (EventLogsFilterAction,
EventLogsLimitAction,)
limit_param = "event_limit"
pagination_param = "event_marker"
prev_pagination_param = 'prev_event_marker'
multi_select = False
class SuppressEvent(tables.BatchAction):
name = "suppress"
action_type = 'danger'
icon = "remove"
help_text = _("Events with selected Alarm ID will be suppressed.")
@staticmethod
def action_present(count):
return ungettext_lazy(
"Suppress Event",
"Suppress Event",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
"Events suppressed for Alarm ID",
"Events suppressed for Alarm ID",
count
)
def allowed(self, request, datum):
"""Allow suppress action if Alarm ID is unsuppressed."""
if datum.suppression_status == stx_api.fm.FM_SUPPRESSED:
return False
return True
def action(self, request, obj_id):
kwargs = {"suppression_status": stx_api.fm.FM_SUPPRESSED}
try:
stx_api.fm.event_suppression_update(request, obj_id, **kwargs)
except Exception:
exceptions.handle(request,
_('Unable to set specified alarm type to \
suppressed\'s.'))
class UnsuppressEvent(tables.BatchAction):
name = "unsuppress"
action_type = 'danger'
icon = "remove"
help_text = _("Events with selected Alarm ID will be unsuppressed.")
@staticmethod
def action_present(count):
return ungettext_lazy(
"Unsuppress Event",
"Unsuppress Event",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
"Events unsuppressed for Alarm ID",
"Events unsuppressed for Alarm ID",
count
)
def allowed(self, request, datum):
"""Allow unsuppress action if Alarm ID is suppressed."""
if datum.suppression_status == stx_api.fm.FM_UNSUPPRESSED:
return False
return True
def action(self, request, obj_id):
kwargs = {"suppression_status": stx_api.fm.FM_UNSUPPRESSED}
try:
stx_api.fm.event_suppression_update(request, obj_id, **kwargs)
except Exception:
exceptions.handle(request,
_('Unable to set specified alarm type to \
unsuppressed\'s.'))
class EventsSuppressionTable(tables.DataTable):
# noinspection PyMethodParameters
def description_inject(row_data): # pylint: disable=no-self-argument
description = \
escape_html(str(row_data.description)).replace("\n", "<br/>")
description = description.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;")
description = description.replace(" " * 4, "&nbsp;" * 4)
description = description.replace(" " * 3, "&nbsp;" * 3)
description = description.replace(" " * 2, "&nbsp;" * 2)
return mark_safe(description)
alarm_id = tables.Column('alarm_id',
verbose_name=_('Event ID'))
description = tables.Column(description_inject,
verbose_name=_('Description'))
status = tables.Column('suppression_status',
verbose_name=_('Status'))
def get_object_id(self, obj):
# return obj.alarm_id
return obj.uuid
def get_object_display(self, datum):
"""Returns a display name that identifies this object."""
if hasattr(datum, 'alarm_id'):
return datum.alarm_id
return None
class Meta(object):
name = "eventsSuppression"
limit_param = "events_suppression_limit"
pagination_param = "events_suppression_marker"
prev_pagination_param = 'prev_event_ids_marker'
verbose_name = _("Events Suppression")
row_actions = (SuppressEvent, UnsuppressEvent,)
multi_select = False

View File

@ -1,309 +0,0 @@
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, Inc.
#
# 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.
#
# Copyright (c) 2013-2018 Wind River Systems, Inc.
#
from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions
from horizon import tabs
from starlingx_dashboard import api as stx_api
from starlingx_dashboard.dashboards.admin.fault_management import tables
ALARMS_SUPPRESSION_FILTER_GROUP = 0
EVENT_SUPPRESSION_FILTER_GROUP = 1
class ActiveAlarmsTab(tabs.TableTab):
table_classes = (tables.AlarmsTable,)
name = _("Active Alarms")
slug = "alarms"
template_name = 'admin/fault_management/_active_alarms.html'
def has_more_data(self, table):
return self._more
def get_limit_count(self, table):
return self._limit
def getTableFromName(self, tableName):
table = self._tables[tableName]
return table
def set_suppression_filter(self, disabled_status):
alarmsTable = self.getTableFromName('alarms')
filter_action = alarmsTable._meta._filter_action
filter_action.set_disabled_filter_field_for_group(
ALARMS_SUPPRESSION_FILTER_GROUP, disabled_status)
filter_action.updateFromRequestDataToSession(self.request)
def get_context_data(self, request):
context = super(ActiveAlarmsTab, self).get_context_data(request)
summary = stx_api.fm.alarm_summary_get(
self.request, include_suppress=False)
context["total"] = summary.critical + summary.major + summary.minor \
+ summary.warnings
context["summary"] = summary
events_types = self.get_event_suppression_data()
suppressed_events_types = len([etype for etype
in events_types
if etype.suppression_status ==
'suppressed'])
alarms_table = self.getTableFromName('alarms')
suppress_filter = self.get_filters()
suppress_filter_state = suppress_filter.get('suppression')
hidden_found = 'hidden' in alarms_table.columns["suppression_status"].\
classes
if not hidden_found:
if suppressed_events_types == 0:
self.set_suppression_filter('disabled')
alarms_table.columns["suppression_status"]\
.classes.append('hidden')
elif suppress_filter_state == stx_api.fm.FM_SUPPRESS_HIDE:
self.set_suppression_filter('enabled')
alarms_table.columns["suppression_status"].classes\
.append('hidden')
else:
if suppressed_events_types == 0:
self.set_suppression_filter('disabled')
else:
self.set_suppression_filter('enabled')
if suppress_filter_state == stx_api.fm.FM_SUPPRESS_SHOW:
alarms_table.columns["suppression_status"].classes\
.remove('hidden')
return context
def get_filters(self, filters=None):
filters = filters or {}
alarmsTable = self.getTableFromName('alarms')
filter_action = alarmsTable._meta._filter_action
filter_action.updateFromRequestDataToSession(self.request)
filter_field = filter_action.get_filter_field(self.request)
if filter_field:
suppression = filter_action.get_filter_field_for_group(0)
filters["suppression"] = suppression
return filters
def get_alarms_data(self):
search_opts = {}
# get retrieve parameters from request/session env
limit = \
self.request.GET.get(tables.AlarmsTable.Meta.limit_param,
None)
search_opts = self.get_filters()
search_opts.update({
'paginate': True,
'sort_key': 'severity,entity_instance_id',
'sort_dir': 'asc'})
alarms = []
try:
if 'paginate' in search_opts:
alarms, self._more = stx_api.fm.alarm_list(
self.request, search_opts=search_opts)
else:
alarms = stx_api.fm.alarm_list(
self.request, search_opts=search_opts)
self._limit = limit
except Exception:
self._more = False
self._limit = None
exceptions.handle(self.request,
_('Unable to retrieve alarms list.'))
return alarms
def get_event_suppression_data(self):
event_types = []
try:
if 'suppression_list' not in self.tab_group.kwargs:
self.tab_group.kwargs['suppression_list'] = \
stx_api.fm.event_suppression_list(self.request)
event_types = self.tab_group.kwargs['suppression_list']
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve event suppression table'
' list.'))
return event_types
class EventLogTab(tabs.TableTab):
table_classes = (tables.EventLogsTable,)
name = _("Events")
slug = "eventLogs"
template_name = 'admin/fault_management/_summary.html'
preload = False
def has_more_data(self, table):
return self._more
def get_limit_count(self, table):
return self._limit
def getTableFromName(self, tableName):
table = self._tables[tableName]
return table
def set_suppression_filter(self, disabled_status):
alarmsTable = self.getTableFromName('eventLogs')
filter_action = alarmsTable._meta._filter_action
filter_action.set_disabled_filter_field_for_group(
EVENT_SUPPRESSION_FILTER_GROUP, disabled_status)
filter_action.updateFromRequestDataToSession(self.request)
def get_context_data(self, request):
context = super(EventLogTab, self).get_context_data(request)
events_types = self.get_event_suppression_data()
suppressed_events_types = len([etype for etype in events_types
if etype.suppression_status ==
'suppressed'])
event_log_table = self.getTableFromName('eventLogs')
filters = self.get_filters({'marker': None,
'limit': None,
'paginate': True})
suppress_filter_state = filters.get('suppression')
hidden_found = 'hidden' in event_log_table\
.columns["suppression_status"].classes
if not hidden_found:
if suppressed_events_types == 0:
self.set_suppression_filter('disabled')
event_log_table.columns["suppression_status"]\
.classes.append('hidden')
elif suppress_filter_state == stx_api.fm.FM_SUPPRESS_HIDE:
self.set_suppression_filter('enabled')
event_log_table.columns["suppression_status"].\
classes.append('hidden')
else:
if suppressed_events_types == 0:
self.set_suppression_filter('disabled')
else:
self.set_suppression_filter('enabled')
if suppress_filter_state == stx_api.fm.FM_SUPPRESS_SHOW:
event_log_table.columns["suppression_status"]\
.classes.remove('hidden')
return context
def get_filters(self, filters):
eventLogsTable = self.getTableFromName('eventLogs')
filter_action = eventLogsTable._meta._filter_action
filter_action.updateFromRequestDataToSession(self.request)
filter_field = filter_action.get_filter_field(self.request)
if filter_field:
filters["evtType"] = filter_action.get_filter_field_for_group(0)
filters["suppression"] = filter_action\
.get_filter_field_for_group(1)
return filters
def get_eventLogs_data(self):
# get retrieve parameters from request/session env
marker = \
self.request.GET.get(tables.EventLogsTable.Meta.pagination_param,
None)
limit = \
self.request.GET.get(tables.EventLogsTable.Meta.limit_param,
None)
search_opts = self.get_filters({'marker': marker,
'limit': limit,
'paginate': True})
events = []
try:
# now retrieve data from rest API
events, self._more = \
stx_api.fm.event_log_list(self.request,
search_opts=search_opts)
self._limit = limit
return events
except Exception:
events = []
self._more = False
self._limit = None
exceptions.handle(self.request,
_('Unable to retrieve Event Log list.'))
return events
def get_event_suppression_data(self):
event_types = []
try:
if 'suppression_list' not in self.tab_group.kwargs:
self.tab_group.kwargs['suppression_list'] = \
stx_api.fm.event_suppression_list(self.request)
event_types = self.tab_group.kwargs['suppression_list']
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve event suppression \
table list.'))
return event_types
class EventsSuppressionTab(tabs.TableTab):
table_classes = (tables.EventsSuppressionTable,)
name = _("Events Suppression")
slug = "eventsSuppression"
template_name = 'admin/fault_management/_summary.html'
preload = False
def get_eventsSuppression_data(self):
event_suppression_list = []
try:
if 'suppression_list' not in self.tab_group.kwargs:
self.tab_group.kwargs['suppression_list'] = \
stx_api.fm.event_suppression_list(self.request)
event_suppression_list = self.tab_group.kwargs['suppression_list']
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve event suppression \
list\'s.'))
event_suppression_list.sort(key=lambda a: (a.alarm_id))
return event_suppression_list
class AlarmsTabs(tabs.TabGroup):
slug = "alarms_tabs"
tabs = (ActiveAlarmsTab, EventLogTab, EventsSuppressionTab)
sticky = True

View File

@ -1,26 +0,0 @@
{% load i18n %}
<div id="active-alarm-stats" class="info details">
<span>
<strong>{% trans "Active Alarms" %}:</strong>
<span class="badge {% if total != 0 %} badge-success{% endif %}">{{ total }}</span>
</span>
<span>
<strong>{% trans "Critical" %}:</strong>
<span class="badge{% if summary.critical != 0 %} badge-danger{% endif %}">{{ summary.critical }}</span>
</span>
<span>
<strong>{% trans "Major" %}:</strong>
<span class="badge{% if summary.major != 0 %} badge-danger{% endif %}">{{ summary.major }}</span>
</span>
<span>
<strong>{% trans "Minor" %}:</strong>
<span class="badge{% if summary.minor != 0 %} badge-warning{% endif %}">{{ summary.minor }}</span>
</span>
<span>
<strong>{% trans "Warning" %}:</strong>
<span class="badge{% if summary.warnings != 0 %} badge-success{% endif %}">{{ summary.warnings }}</span>
</span>
</div>
{{ table.render }}

View File

@ -1,58 +0,0 @@
{% extends 'base.html' %}
{% load i18n breadcrumb_nav %}
{% block title %}{% trans "Historical Alarm Details" %}{% endblock %}
{% block main %}
{% if history.event_log_id == '' or history.event_log_id == ' ' %}
<h3> {{history.reason_text }} </h3>
{% else %}
<h3> {{history.state }} - {{history.event_log_id }} - {{history.reason_text }} </h3>
{% endif %}
<div class="row">
<div class="col-sm-12">
<div class="info row-fluid detail">
<h4>{% trans "Info" %}</h4>
<hr class="header_rule">
<dl>
<dt>{% trans "Alarm UUID" %}</dt>
<dd>{{ history.uuid }}</dd>
{% if history.event_log_id != '' and history.event_log_id != ' ' %}
<dt>{% trans "Alarm ID" %}</dt>
<dd>{{ history.event_log_id }}</dd>
{% endif %}
<dt>{% trans "Severity" %}</dt>
<dd>{{ history.severity }}</dd>
<dt>{% trans "Alarm State" %}</dt>
<dd>{{ history.state }}</dd>
<dt>{% trans "Alarm Type" %}</dt>
<dd>{{ history.event_log_type }}</dd>
<dt>{% trans "Timestamp" %}</dt>
<dd>{{ history.timestamp|parse_isotime }}</dd>
<dt>{% trans "Suppression" %}</dt>
<dd>{{ history.suppression }}</dd>
</dl>
<dl>
<dt>{% trans "Entity Instance ID" %}</dt>
<dd>{{ history.entity_instance_id }}</dd>
{% if history.entity_type_id != '' and history.entity_type_id != ' ' %}
<dt>{% trans "Entity Type ID" %}</dt>
<dd>{{ history.entity_type_id }}</dd>
{% endif %}
<dt>{% trans "Probable Cause" %}</dt>
<dd>{{ history.probable_cause }}</dd>
{% if history.proposed_repair_action != '' and history.proposed_repair_action != ' ' %}
<dt>{% trans "Proposed Repair Action" %}</dt>
<dd>{{ history.proposed_repair_action }}</dd>
{% endif %}
<dt>{% trans "Service Affecting" %}</dt>
<dd>{{ history.service_affecting }}</dd>
{% if history.reason_text != '' and history.reason_text != ' ' %}
<dt>{% trans "Reason" %}</dt>
<dd>{{ history.reason_text }}</dd>
{% endif %}
</dl>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,50 +0,0 @@
{% extends 'base.html' %}
{% load i18n breadcrumb_nav %}
{% block title %}{% trans "Customer Log Details" %}{% endblock %}
{% block main %}
{% if log.event_log_id == '' or log.event_log_id == ' ' %}
<h3> {{log.reason_text }} </h3>
{% else %}
<h3> {{log.event_log_id }} - {{log.reason_text }} </h3>
{% endif %}
<div class="row">
<div class="col-sm-12">
<div class="info row-fluid detail">
<h4>{% trans "Info" %}</h4>
<hr class="header_rule">
<dl>
<dt>{% trans "Log UUID" %}</dt>
<dd>{{ log.uuid }}</dd>
{% if log.event_log_id != '' and log.event_log_id != ' ' %}
<dt>{% trans "Log ID" %}</dt>
<dd>{{ log.event_log_id }}</dd>
{% endif %}
<dt>{% trans "Severity" %}</dt>
<dd>{{ log.severity }}</dd>
<dt>{% trans "Log Type" %}</dt>
<dd>{{ log.event_log_type }}</dd>
<dt>{% trans "Timestamp" %}</dt>
<dd>{{ log.timestamp|parse_isotime }}</dd>
</dl>
<dl>
<dt>{% trans "Entity Instance ID" %}</dt>
<dd>{{ log.entity_instance_id }}</dd>
{% if log.entity_type_id != '' and log.entity_type_id != ' ' %}
<dt>{% trans "Entity Type ID" %}</dt>
<dd>{{ log.entity_type_id }}</dd>
{% endif %}
<dt>{% trans "Probable Cause" %}</dt>
<dd>{{ log.probable_cause }}</dd>
<dt>{% trans "Service Affecting" %}</dt>
<dd>{{ log.service_affecting }}</dd>
{% if log.reason_text != '' and log.reason_text != ' ' %}
<dt>{% trans "Reason" %}</dt>
<dd>{{ log.reason_text }}</dd>
{% endif %}
</dl>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,52 +0,0 @@
{% extends 'base.html' %}
{% load i18n breadcrumb_nav %}
{% block title %}{% trans "Alarm Details" %}{% endblock %}
{% block main %}
<h3> {{alarm.alarm_id }} - {{alarm.reason_text }}</h3>
<div class="row">
<div class="col-sm-12">
<div class="info row-fluid detail">
<h4>{% trans "Info" %}</h4>
<hr class="header_rule">
<dl>
<dt>{% trans "Alarm UUID" %}</dt>
<dd>{{ alarm.uuid }}</dd>
<dt>{% trans "Alarm ID" %}</dt>
<dd>{{ alarm.alarm_id }}</dd>
<dt>{% trans "Severity" %}</dt>
<dd>{{ alarm.severity }}</dd>
<dt>{% trans "Alarm State" %}</dt>
<dd>{{ alarm.alarm_state }}</dd>
<dt>{% trans "Alarm Type" %}</dt>
<dd>{{ alarm.alarm_type }}</dd>
<dt>{% trans "Timestamp" %}</dt>
<dd>{{ alarm.timestamp|parse_isotime }}</dd>
<dt>{% trans "Suppression" %}</dt>
<dd>{{ alarm.suppression }}</dd>
</dl>
<dl>
<dt>{% trans "Entity Instance ID" %}</dt>
<dd>{{ alarm.entity_instance_id }}</dd>
<dt>{% trans "Entity Type ID" %}</dt>
<dd>{{ alarm.entity_type_id }}</dd>
<dt>{% trans "Probable Cause" %}</dt>
<dd>{{ alarm.probable_cause }}</dd>
<dt>{% trans "Proposed Repair Action" %}</dt>
<dd>{{ alarm.proposed_repair_action }}</dd>
<dt>{% trans "Service Affecting" %}</dt>
<dd>{{ alarm.service_affecting }}</dd>
<dt>{% trans "Management Affecting" %}</dt>
<dd>{{ alarm.mgmt_affecting }}</dd>
{% if alarm.reason_text != '' and alarm.reason_text != ' ' %}
<dt>{% trans "Reason" %}</dt>
<dd>{{ alarm.reason_text }}</dd>
{% endif %}
</dl>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,5 +0,0 @@
{% load i18n %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -1,29 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Fault Management" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Fault Management")%}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">
{{ tab_group.render }}
</div>
</div>
{% endblock %}
{% block js %}
{{ block.super }}
<script type="text/javascript" charset="utf-8">
horizon.refresh.addRefreshFunction(function (html) {
var $old_stats = $('#active-alarm-stats');
var $new_stats = $(html).find('#active-alarm-stats');
if ($new_stats.html() != $old_stats.html()) {
$old_stats.replaceWith($new_stats);
}
});
</script>
{% endblock %}

View File

@ -1,35 +0,0 @@
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, Inc.
#
# 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.
#
# Copyright (c) 2013-2015 Wind River Systems, Inc.
#
from django.conf.urls import url # noqa
from starlingx_dashboard.dashboards.admin.fault_management import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<id>[^/]+)/detail/$',
views.DetailView.as_view(), name='detail'),
url(r'^(?P<id>[^/]+)/eventlogdetail/$',
views.EventLogDetailView.as_view(), name='eventlogdetail'),
url(r'^banner/$', views.BannerView.as_view(),
name='banner')
]

View File

@ -1,175 +0,0 @@
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, Inc.
#
# 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.
#
# Copyright (c) 2013-2018 Wind River Systems, Inc.
#
import logging
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _ # noqa
from django.views.generic import TemplateView
from horizon import exceptions
from horizon import tabs
from horizon import views
from openstack_dashboard.api.base import is_service_enabled
from starlingx_dashboard.api import dc_manager
from starlingx_dashboard.api import fm
from starlingx_dashboard.dashboards.admin.fault_management import \
tabs as project_tabs
LOG = logging.getLogger(__name__)
class IndexView(tabs.TabbedTableView):
tab_group_class = project_tabs.AlarmsTabs
template_name = 'admin/fault_management/index.html'
page_title = _("Fault Management")
class DetailView(views.HorizonTemplateView):
template_name = 'admin/fault_management/_detail_overview.html'
page_title = 'Alarm Details'
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
context["alarm"] = self.get_data()
return context
def get_data(self):
if not hasattr(self, "_alarm"):
alarm_uuid = self.kwargs['id']
try:
alarm = fm.alarm_get(self.request, alarm_uuid)
except Exception:
redirect = reverse('horizon:admin:fault_management:index')
exceptions.handle(self.request,
_('Unable to retrieve details for '
'alarm "%s".') % alarm_uuid,
redirect=redirect)
self._alarm = alarm
return self._alarm
class EventLogDetailView(views.HorizonTemplateView):
# Strategy behind this event log detail view is to
# first retrieve the event_log data, then examine the event's
# state property, and from that, determine if it should use
# the _detail_history.html (alarmhistory) template or
# or use the _detail_log.html (customer log) template
def get_template_names(self):
if self.type == "alarmhistory":
template_name = 'admin/fault_management/_detail_history.html'
else:
template_name = 'admin/fault_management/_detail_log.html'
return template_name
def _detectEventLogType(self):
if hasattr(self, "type"):
return self.type
if not self._eventlog:
raise Exception("Cannot determine Event Log type for "
"EventLogDetailView. First retrieve "
"Eventlog data")
if self._eventlog.state == "log":
self.type = "log"
elif self._eventlog.state in ["set", "clear"]:
self.type = "alarmhistory"
else:
raise Exception("Invalid state = '{}'. Cannot "
"determine Event log type for "
"event log".format(self._eventlog.state))
return self.type
def get_context_data(self, **kwargs):
context = super(EventLogDetailView, self).get_context_data(**kwargs)
data = self.get_data()
if self.type == "alarmhistory":
self.page_title = 'Historical Alarm Details'
self.template_name = 'admin/fault_management/_detail_history.html'
context["history"] = data
else:
self.page_title = 'Customer Log Detail'
self.template_name = 'admin/fault_management/_detail_log.html'
context["log"] = data
return context
def get_data(self):
if not hasattr(self, "_eventlog"):
uuid = self.kwargs['id']
try:
self._eventlog = fm.event_log_get(self.request, uuid)
self._detectEventLogType()
except Exception:
redirect = reverse('horizon:admin:fault_management:index')
exceptions.handle(self.request,
_('Unable to retrieve details for '
'event log "%s".') % uuid,
redirect=redirect)
return self._eventlog
class BannerView(TemplateView):
template_name = 'header/_alarm_banner.html'
def get_context_data(self, **kwargs):
context = super(BannerView, self).get_context_data(**kwargs)
if not self.request.is_ajax():
raise exceptions.NotFound()
if (not self.request.user.is_authenticated() or
not self.request.user.is_superuser):
context["alarmbanner"] = False
elif 'dc_admin' in self.request.META.get('HTTP_REFERER'):
summaries = self.get_subcloud_data()
central_summary = self.get_data()
summaries.append(central_summary)
context["dc_admin"] = True
context["alarmbanner"] = True
context["OK"] = len(
[s for s in summaries if s.status == 'OK'])
context["degraded"] = len(
[s for s in summaries if s.status == 'degraded'])
context["critical"] = len(
[s for s in summaries if s.status == 'critical'])
context["disabled"] = len(
[s for s in summaries if s.status == 'disabled'])
elif is_service_enabled(self.request, 'platform'):
context["summary"] = self.get_data()
context["alarmbanner"] = True
return context
def get_data(self):
summary = None
try:
summary = fm.alarm_summary_get(self.request)
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve alarm summary.'))
return summary
def get_subcloud_data(self):
return dc_manager.alarm_summary_list(self.request)

View File

@ -1,15 +1,16 @@
#
# Copyright (c) 2016-2018 Wind River Systems, Inc.
# Copyright (c) 2016-2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from horizon import tables
from horizon.utils import filters as utils_filters
import logging
from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _
from starlingx_dashboard.dashboards.admin.fault_management import \
tables as fm_tables
from starlingx_dashboard.dashboards.admin.inventory.interfaces import \
tables as if_tables
from starlingx_dashboard.dashboards.admin.providernets.providernets.ranges \
@ -17,6 +18,19 @@ from starlingx_dashboard.dashboards.admin.providernets.providernets.ranges \
LOG = logging.getLogger(__name__)
SUPPRESSION_STATUS_CHOICES = (
("suppressed", False),
("unsuppressed", True),
("None", True),
)
SUPPRESSION_STATUS_DISPLAY_CHOICES = (
("suppressed", pgettext_lazy("Indicates this type of alarm \
is suppressed", "suppressed")),
("unsuppressed", pgettext_lazy("Indicates this type of alarm \
is unsuppressed", "unsuppressed")),
("None", pgettext_lazy("Indicates an event type", "None")),
)
class ProviderNetworkRangeTable(sr_tables.ProviderNetworkRangeTable):
class Meta(object):
@ -26,7 +40,34 @@ class ProviderNetworkRangeTable(sr_tables.ProviderNetworkRangeTable):
row_actions = ()
class AlarmsTable(fm_tables.AlarmsTable):
def get_alarm_link_url(alarm):
return "/ngdetails/OS::StarlingX::ActiveAlarms/" + alarm.uuid
class AlarmsTable(tables.DataTable):
alarm_id = tables.Column('alarm_id',
verbose_name=_('Alarm ID'),
link=get_alarm_link_url)
reason_text = tables.Column('reason_text',
verbose_name=_('Reason Text'))
entity_instance_id = tables.Column('entity_instance_id',
verbose_name=_('Entity Instance ID'))
suppression_status = \
tables.Column('suppression_status',
verbose_name=_('Suppression Status'),
status=True,
status_choices=SUPPRESSION_STATUS_CHOICES,
display_choices=SUPPRESSION_STATUS_DISPLAY_CHOICES)
severity = tables.Column('severity',
verbose_name=_('Severity'))
timestamp = tables.Column('timestamp',
attrs={'data-type': 'timestamp'},
filters=(utils_filters.parse_isotime,),
verbose_name=_('Timestamp'))
def get_object_id(self, obj):
return obj.uuid
class Meta(object):
name = "alarms"
verbose_name = _("Related Alarms")

View File

@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 Wind River Systems, Inc.
* Copyright (c) 2017-2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
@ -105,7 +105,7 @@
/////////////
function goToCentralAlarmDetails(cloud) {
$window.location.href = "/auth/switch_services_region/RegionOne/?next=/admin/fault_management/";
$window.location.href = "/auth/switch_services_region/RegionOne/?next=/admin/active_alarms/";
}
function goToCentralHostDetails(cloud) {

View File

@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 Wind River Systems, Inc.
* Copyright (c) 2017-2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
@ -386,7 +386,7 @@
keystone.getCurrentUserSession().success(function(session){
session.available_services_regions.indexOf(cloud.name)
if (session.available_services_regions.indexOf(cloud.name) > -1) {
$window.location.href = "/auth/switch_services_region/"+ cloud.name + "/?next=/admin/fault_management/";
$window.location.href = "/auth/switch_services_region/"+ cloud.name + "/?next=/admin/active_alarms/";
} else {
toast.add('error', ctrl.endpointErrorMsg);
// TODO(tsmith) should we force a logout here with an reason message?

View File

@ -1,48 +0,0 @@
/**
* Copyright (c) 2018 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function () {
'use strict';
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.fm', FmAPI);
FmAPI.$inject = [
'$q',
'horizon.framework.util.http.service',
'horizon.framework.widgets.toast.service',
'$http'
];
function FmAPI($q, apiService, toastService, $http) {
var service = {
getAlarmSummary: getAlarmSummary
};
var csrf_token = $('input[name=csrfmiddlewaretoken]').val();
$http.defaults.headers.post['X-CSRFToken'] = csrf_token;
$http.defaults.headers.common['X-CSRFToken'] = csrf_token;
$http.defaults.headers.put['X-CSRFToken'] = csrf_token;
return service;
///////////////////
// Alarm Summary //
///////////////////
function getAlarmSummary() {
return apiService.get('/api/fm/alarm_summary/')
.error(function () {
toastService.clearErrors();
toastService.add('error', gettext("Unable to retrieve the System Controller's alarm summary."));
});
}
}
}());

View File

@ -0,0 +1,6 @@
# A list of applications to be added to INSTALLED_APPS.
ADD_INSTALLED_APPS = ['starlingx_dashboard']
FEATURE = ['starlingx_dashboard']
AUTO_DISCOVER_STATIC_FILES = True

View File

@ -0,0 +1,18 @@
from django.utils.translation import ugettext_lazy as _
# The slug of the panel group to be added to HORIZON_CONFIG. Required.
PANEL_GROUP = 'fault_management'
# The display name of the PANEL_GROUP. Required.
PANEL_GROUP_NAME = _('Fault Management')
# The slug of the dashboard the PANEL_GROUP associated with. Required.
PANEL_GROUP_DASHBOARD = 'admin'
ADD_ANGULAR_MODULES = [
'horizon.dashboard.fault_management'
]
ADD_SCSS_FILES = [
'dashboard/fault_management/fault_management.scss'
]
AUTO_DISCOVER_STATIC_FILES = True

View File

@ -1,10 +1,10 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'fault_management'
PANEL = 'active_alarms'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'fault_management'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'platform'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'starlingx_dashboard.dashboards.admin.' \
'fault_management.panel.FaultManagement'
'active_alarms.panel.ActiveAlarms'

View File

@ -0,0 +1,9 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'events'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'fault_management'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'starlingx_dashboard.dashboards.admin.events.panel.Events'

View File

@ -0,0 +1,10 @@
# The slug of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'events_suppression'
# The slug of the panel group the PANEL is associated with.
PANEL_GROUP = 'fault_management'
# The slug of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# Python panel class of the PANEL to be added.
ADD_PANEL = 'starlingx_dashboard.dashboards.admin.events_suppression.panel.' \
'EventsSuppression'

View File

@ -0,0 +1,116 @@
/**
* Copyright (c) 2018-2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function () {
'use strict';
angular
.module('horizon.app.core.openstack-service-api')
.factory('horizon.app.core.openstack-service-api.fm', FmAPI);
FmAPI.$inject = [
'$q',
'horizon.framework.util.http.service',
'horizon.framework.widgets.toast.service',
'$http'
];
function FmAPI($q, apiService, toastService, $http) {
var service = {
getAlarmSummary: getAlarmSummary,
getAlarms: getAlarms,
getAlarm: getAlarm,
getEvents: getEvents,
getEvent: getEvent,
getEventsSuppression: getEventsSuppression,
updateEventSuppression: updateEventSuppression
};
var csrf_token = $('input[name=csrfmiddlewaretoken]').val();
$http.defaults.headers.post['X-CSRFToken'] = csrf_token;
$http.defaults.headers.common['X-CSRFToken'] = csrf_token;
$http.defaults.headers.put['X-CSRFToken'] = csrf_token;
return service;
///////////////////////////////
// Alarms
function getAlarmSummary() {
return apiService.get('/api/fm/alarm_summary/')
.error(function () {
toastService.clearErrors();
toastService.add('error', gettext("Unable to retrieve alarm summary."));
});
}
function getAlarms() {
var results = apiService.get('/api/fm/alarm_list/?include_suppress=True')
return results
.error(function () {
toastService.clearErrors();
toastService.add('error', gettext("Unable to retrieve alarms."));
});
}
function getAlarm(uuid) {
var results = apiService.get('/api/fm/alarm_get/' + uuid)
return results
.error(function() {
var msg = gettext("Unable to retrieve alarm with uuid: %(uuid)s.");
toastService.add('error', interpolate(msg, {uuid: uuid}, true));
});
}
///////////////////////////////
// Events
function getEvents() {
var results = apiService.get('/api/fm/event_log_list/')
return results
.error(function () {
toastService.clearErrors();
toastService.add('error', gettext("Unable to retrieve events."));
});
}
function getEvent(uuid) {
var results = apiService.get('/api/fm/event_log_get/' + uuid)
return results
.error(function() {
var msg = gettext("Unable to retrieve event with uuid: %(uuid)s.");
toastService.add('error', interpolate(msg, {uuid: uuid}, true));
});
}
///////////////////////////////
// Events Suppression
function getEventsSuppression(include_unsuppressed) {
var query_string = '/api/fm/events_suppression_list/'
if (include_unsuppressed) {
query_string = query_string + '?include_unsuppressed'
}
var results = apiService.get(query_string);
return results
.error(function () {
toastService.clearErrors();
toastService.add('error', gettext("Unable to retrieve events suppression."));
});
}
function updateEventSuppression(uuid, params) {
var results = apiService.patch('/api/fm/event_suppression/' + uuid, params)
// Errors are expected to be processed by the caller, just return
return results;
}
}
}());

View File

@ -0,0 +1,194 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.fault_management.active_alarms
* @ngModule
* @description
* Provides all the services and widgets require to display the Alarm
* panel
*/
angular
.module('horizon.dashboard.fault_management.active_alarms', [
'ngRoute',
'horizon.dashboard.fault_management.active_alarms.details'
])
.constant('horizon.dashboard.fault_management.active_alarms.resourceType', 'OS::StarlingX::ActiveAlarms')
.run(run)
.config(config);
run.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.fault_management.active_alarms.service',
'horizon.dashboard.fault_management.active_alarms.basePath',
'horizon.dashboard.fault_management.active_alarms.resourceType'
];
function run(registry, service, basePath, resourceType) {
registry.getResourceType(resourceType)
.setNames(gettext('Active Alarm'), gettext('Active Alarms'))
// for detail summary view on table row
.setSummaryTemplateUrl(basePath + 'details/drawer.html')
// set default url for index view. this will be used for reproducing
// sidebar and breadcrumb when refreshing or accessing directly
// details view.
// TODO(kbujold): Uncomment when we rebase to Stein, to fix upstream bug 1746706
//.setDefaultIndexUrl('/admin/fault_management/')
// specify items for table row items, summary view and details view
.setProperties(properties())
// get items for table
.setListFunction(service.getPromise)
// specify table columns
.tableColumns
.append({
id: 'alarm_id',
priority: 1,
urlFunction: service.urlFunction
})
.append({
id: 'reason_text',
priority: 1
})
.append({
id: 'entity_instance_id',
priority: 1
})
.append({
id: 'severity',
priority: 1,
sortDefault: 'true'
})
.append({
id: 'suppression_status',
priority: 1,
allowed: service.suppressColAllowedPromiseFunction
})
.append({
id: 'timestamp',
priority: 1
});
// for magic-search
registry.getResourceType(resourceType).filterFacets
.append({
'label': gettext('Alarm ID'),
'name': 'alarm_id',
'singleton': true
})
.append({
'label': gettext('Entity Instance ID'),
'name': 'entity_instance_id',
'singleton': true
})
.append({
'label': gettext('Reason Text'),
'name': 'reason_text',
'singleton': true
})
.append({
'label': gettext('Severity'),
'name': 'severity',
'singleton': true,
'options': [
{label: gettext('critical'), key: 'critical'},
{label: gettext('major'), key: 'major'},
{label: gettext('minor'), key: 'minor'},
{label: gettext('warning'), key: 'warning'}
]
})
.append({
'label': gettext('Timestamp'),
'name': 'timestamp',
'singleton': true
})
.append({
'label': gettext('Management Affecting'),
'name': 'mgmt_affecting',
'singleton': true,
'options': [
{label: gettext('True'), key: 'True'},
{label: gettext('False'), key: 'False'}
]
})
.append({
'label': gettext('UUID'),
'name': 'uuid',
'singleton': true
});
}
function properties() {
return {
uuid: { label: gettext('Alarm UUID'), filters: ['noValue'] },
alarm_id: { label: gettext('Alarm ID'), filters: ['noValue'] },
reason_text: { label: gettext('Reason Text'), filters: ['noValue'] },
entity_instance_id: { label: gettext('Entity Instance ID'), filters: ['noValue'] },
severity: { label: gettext('Severity'), filters: ['noValue'] },
timestamp: { label: gettext('Timestamp'), filters: ['noValue'] },
mgmt_affecting: { label: gettext('Management Affecting'), filters: ['noValue'] },
suppression_status: { label: gettext('Suppression Status'), filters: ['noValue'] },
alarm_state: { label: gettext('Alarm State'), filters: ['noValue'] },
service_affecting: { label: gettext('Service Affecting'), filters: ['noValue'] },
alarm_type: { label: gettext('Alarm Type'), filters: ['noValue'] },
probable_cause: { label: gettext('Probable Cause'), filters: ['noValue'] },
entity_type_id: { label: gettext('Entity Type ID'), filters: ['noValue'] },
proposed_repair_action: { label: gettext('Proposed Repair Action'), filters: ['noValue'] },
is_suppressed: { label: gettext('IsSuppressed'), filters: ['noValue'] },
};
}
config.$inject = [
'$provide',
'$windowProvider',
'$routeProvider'
];
/**
* @name config
* @param {Object} $provide
* @param {Object} $windowProvider
* @param {Object} $routeProvider
* @description Routes used by this module.
* @returns {undefined} Returns nothing
*/
function config($provide, $windowProvider, $routeProvider) {
var path = $windowProvider.$get().STATIC_URL + 'dashboard/fault_management/active_alarms/';
$provide.constant('horizon.dashboard.fault_management.active_alarms.basePath', path);
$routeProvider.when('/admin/active_alarms', {
templateUrl: path + 'panel.html',
resolve: {
searchResults: ['horizon.dashboard.fault_management.active_alarms.service', function (searchService) {
return searchService.getSuppressionList();
}]
}
});
}
})();

View File

@ -0,0 +1,30 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
describe('horizon.dashboard.fault_management.active_alarms', function() {
it('should exist', function() {
expect(angular.module('horizon.dashboard.fault_management.active_alarms')).toBeDefined();
});
});
})();

View File

@ -0,0 +1,136 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
angular.module('horizon.dashboard.fault_management.active_alarms')
.factory('horizon.dashboard.fault_management.active_alarms.service',
service);
service.$inject = [
'$filter',
'horizon.app.core.detailRoute',
'horizon.app.core.openstack-service-api.fm',
'$q',
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.fault_management.active_alarms.resourceType'
];
/*
* @ngdoc factory
* @name horizon.dashboard.fault_management.active_alarms.service
*
* @description
* This service provides functions that are used through the Alarms
* features. These are primarily used in the module registrations
* but do not need to be restricted to such use. Each exposed function
* is documented below.
*/
function service($filter, detailRoute, api, $q, registry, resourceType) {
var showSuppressColumn = null;
return {
getPromise: getPromise,
urlFunction: urlFunction,
suppressColAllowedPromiseFunction: suppressColAllowedPromiseFunction,
getSuppressionList: getSuppressionList
};
function getPromise(params) {
return api.getAlarms(params).then(modifyResponse);
}
function modifyResponse(response) {
return {data: {items: response.data.items.map(modifyItem)}};
function modifyItem(item) {
item.trackBy = item.uuid;
if (item.suppression_status == 'suppressed') {
item.is_suppressed = true;
}
else {
item.is_suppressed = false;
}
return item;
}
}
function urlFunction(item) {
return detailRoute + 'OS::StarlingX::ActiveAlarms/' + item.uuid;
}
function getSuppressionList() {
var include_unsuppressed = false;
return api.getEventsSuppression(include_unsuppressed).then(modifyResponseSupp);
}
function modifyResponseSupp(response) {
if (response.data.items.length == 0) {
showSuppressColumn = false;
}
else {
showSuppressColumn = true;
}
return;
}
/**
* @name suppressColAllowedPromiseFunction
* @description
* If there are no unsuppressed events then we do not show the Suppression
* Status column. We also do show the the filter associated with that column.
*/
function suppressColAllowedPromiseFunction() {
var filters = registry.getResourceType(resourceType).filterFacets;
var index = filters.findIndex(obj => obj['id'] === 'suppression_status');
if (showSuppressColumn === false) {
if (index >= 0) {
filters.remove('suppression_status')
}
return $q.reject();
}
else {
if (index < 0) {
filters.append({
'label': gettext('Suppression Status'),
'id': 'suppression_status',
'name': 'is_suppressed',
'singleton': false,
'options': [
{label: gettext('suppressed'), key: 'true'},
{label: gettext('unsuppressed'), key: 'false'}
]
});
}
return $q.resolve();
}
}
}
})();

View File

@ -0,0 +1,59 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
describe('Active Alarms service', function() {
var service;
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.fault_management.active_alarms'));
beforeEach(inject(function($injector) {
service = $injector.get('horizon.dashboard.fault_management.active_alarms.service');
}));
describe('getPromise', function() {
it("provides a promise", inject(function($q, $injector, $timeout) {
var api = $injector.get('horizon.app.core.openstack-service-api.fm');
var deferred = $q.defer();
spyOn(api, 'getAlarms').and.returnValue(deferred.promise);
var result = service.getPromise({});
deferred.resolve({
data:{
items: [{uuid: '123abc', reason_text: 'resource1'}]
}
});
$timeout.flush();
expect(api.getAlarms).toHaveBeenCalled();
expect(result.$$state.value.data.items[0].reason_text).toBe('resource1');
}));
});
describe('urlFunction', function() {
it("get url", inject(function($injector) {
var detailRoute = $injector.get('horizon.app.core.detailRoute');
var result = service.urlFunction({uuid:"123abc"});
expect(result).toBe(detailRoute + "OS::StarlingX::ActiveAlarms/123abc");
}));
});
});
})();

View File

@ -0,0 +1,64 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @ngname horizon.dashboard.fault_management.active_alarms.details
*
* @description
* Provides details features for Alarm.
*/
angular
.module('horizon.dashboard.fault_management.active_alarms.details', [
'horizon.app.core',
'horizon.framework.conf'
])
.run(registerDetails);
registerDetails.$inject = [
'horizon.app.core.openstack-service-api.fm',
'horizon.dashboard.fault_management.active_alarms.basePath',
'horizon.dashboard.fault_management.active_alarms.resourceType',
'horizon.framework.conf.resource-type-registry.service'
];
function registerDetails(
api,
basePath,
resourceType,
registry
) {
registry.getResourceType(resourceType)
.setLoadFunction(loadFunction)
.detailsViews.append({
id: 'alarmsDetailsOverview',
name: gettext('Overview'),
template: basePath + 'details/overview.html'
});
function loadFunction(uuid) {
return api.getAlarm(uuid);
}
}
})();

View File

@ -0,0 +1,5 @@
<hz-resource-property-list
resource-type-name="OS::StarlingX::ActiveAlarms"
item="item"
property-groups="[['uuid', 'mgmt_affecting']]">
</hz-resource-property-list>

View File

@ -0,0 +1,44 @@
/*
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
angular
.module('horizon.dashboard.fault_management.active_alarms')
.controller('horizon.dashboard.fault_management.active_alarms.OverviewController', controller);
controller.$inject = [
'$scope'
];
function controller(
$scope
) {
var ctrl = this;
ctrl.alarm = {};
$scope.context.loadPromise.then(onGetAlarm);
function onGetAlarm(item) {
ctrl.alarm = item.data;
}
}
})();

View File

@ -0,0 +1,17 @@
<div ng-controller="horizon.dashboard.fault_management.active_alarms.OverviewController as ctrl">
<div class="row">
<div class="col-md-12 detail">
<h3> {$ ctrl.alarm.alarm_id $} - {$ ctrl.alarm.reason_text $} </h3>
<hr>
<hz-resource-property-list
resource-type-name="OS::StarlingX::ActiveAlarms"
cls="dl-horizontal"
item="ctrl.alarm"
property-groups="[['uuid', 'alarm_id', 'severity', 'alarm_state', 'alarm_type', 'timestamp',
'suppression_status', 'entity_instance_id', 'entity_type_id',
'probable_cause', 'proposed_repair_action', 'service_affecting',
'mgmt_affecting', 'reason_text']]">
</hz-resource-property-list>
</div>
</div>
</div>

View File

@ -0,0 +1,6 @@
<hz-resource-panel resource-type-name="OS::StarlingX::ActiveAlarms">
<hz-resource-table resource-type-name="OS::StarlingX::ActiveAlarms"
track-by="trackBy">
</hz-resource-table>
</hz-resource-panel>

View File

@ -0,0 +1,64 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @ngname horizon.dashboard.fault_management.events.details
*
* @description
* Provides details features for Event.
*/
angular
.module('horizon.dashboard.fault_management.events.details', [
'horizon.app.core',
'horizon.framework.conf'
])
.run(registerDetails);
registerDetails.$inject = [
'horizon.app.core.openstack-service-api.fm',
'horizon.dashboard.fault_management.events.basePath',
'horizon.dashboard.fault_management.events.resourceType',
'horizon.framework.conf.resource-type-registry.service'
];
function registerDetails(
api,
basePath,
resourceType,
registry
) {
registry.getResourceType(resourceType)
.setLoadFunction(loadFunction)
.detailsViews.append({
id: 'eventsDetailsOverview',
name: gettext('Overview'),
template: basePath + 'details/overview.html'
});
function loadFunction(uuid) {
return api.getEvent(uuid);
}
}
})();

View File

@ -0,0 +1,5 @@
<hz-resource-property-list
resource-type-name="OS::StarlingX::Events"
item="item"
property-groups="[['uuid', 'event_type']]">
</hz-resource-property-list>

View File

@ -0,0 +1,48 @@
/*
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
angular
.module('horizon.dashboard.fault_management.events')
.controller('horizon.dashboard.fault_management.events.OverviewController', controller);
controller.$inject = [
'$scope',
'horizon.dashboard.fault_management.events.service'
];
function controller(
$scope, eventService
) {
var ctrl = this;
ctrl.event = {};
$scope.context.loadPromise.then(onGetEvent);
function onGetEvent(item) {
eventService.setEventType(item.data);
ctrl.event = item.data;
}
}
})();

View File

@ -0,0 +1,17 @@
<div ng-controller="horizon.dashboard.fault_management.events.OverviewController as ctrl">
<div class="row">
<div class="col-md-12 detail">
<h3> {$ ctrl.event.state $} - {$ ctrl.event.event_log_id $} - {$ctrl.event.reason_text $} </h3>
<hr>
<hz-resource-property-list
resource-type-name="OS::StarlingX::Events"
cls="dl-horizontal"
item="ctrl.event"
property-groups="[['uuid', 'event_log_id', 'severity', 'state', 'event_log_type', 'timestamp',
'suppression', 'entity_instance_id', 'entity_type_id',
'probable_cause', 'proposed_repair_action', 'service_affecting',
'reason_text', 'event_type']]">
</hz-resource-property-list>
</div>
</div>
</div>

View File

@ -0,0 +1,208 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.fault_management.events
* @ngModule
* @description
* Provides all the services and widgets require to display the Event panel
*/
angular
.module('horizon.dashboard.fault_management.events', [
'ngRoute',
'horizon.dashboard.fault_management.events.details'
])
.constant('horizon.dashboard.fault_management.events.resourceType', 'OS::StarlingX::Events')
.run(run)
.config(config);
run.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.fault_management.events.service',
'horizon.dashboard.fault_management.events.basePath',
'horizon.dashboard.fault_management.events.resourceType'
];
function run(registry, service, basePath, resourceType) {
registry.getResourceType(resourceType)
.setNames(gettext('Event'), gettext('Events'))
// for detail summary view on table row
.setSummaryTemplateUrl(basePath + 'details/drawer.html')
// set default url for index view. this will be used for reproducing
// sidebar and breadcrumb when refreshing or accessing directly
// details view.
// TODO(kbujold): Uncomment when we rebase to Stein, to fix upstream bug 1746706
//.setDefaultIndexUrl('/admin/fault_management/')
// specify items for table row items, summary view and details view
.setProperties(properties())
// get items for table
.setListFunction(service.getPromise)
// specify table columns
.tableColumns
.append({
id: 'timestamp',
priority: 1,
sortDefault: 'reverse'
})
.append({
id: 'state',
priority: 1
})
.append({
id: 'event_log_id',
priority: 1,
urlFunction: service.urlFunction
})
.append({
id: 'reason_text',
priority: 1
})
.append({
id: 'entity_instance_id',
priority: 1
})
.append({
id: 'suppression_status',
priority: 1,
allowed: service.suppressColAllowedPromiseFunction
})
.append({
id: 'severity',
priority: 2
});
// for magic-search
registry.getResourceType(resourceType).filterFacets
.append({
'label': gettext('Event Type'),
'name': 'event_type',
'singleton': true,
'options': [
{label: gettext('log'), key: 'log'},
{label: gettext('alarm'), key: 'alarm'}
]
})
.append({
'label': gettext('ID'),
'name': 'event_log_id',
'singleton': true
})
.append({
'label': gettext('Entity Instance ID'),
'name': 'entity_instance_id',
'singleton': true
})
.append({
'label': gettext('Reason Text'),
'name': 'reason_text',
'singleton': true
})
.append({
'label': gettext('State'),
'name': 'state',
'singleton': true,
'options': [
{label: gettext('clear'), key: 'clear'},
{label: gettext('log'), key: 'log'},
{label: gettext('set'), key: 'set'}
]
})
.append({
'label': gettext('Severity'),
'name': 'severity',
'singleton': true,
'options': [
{label: gettext('critical'), key: 'critical'},
{label: gettext('major'), key: 'major'},
{label: gettext('minor'), key: 'minor'},
{label: gettext('warning'), key: 'warning'},
{label: gettext('not-applicable'), key: 'not-applicable'}
]
})
.append({
'label': gettext('Timestamp'),
'name': 'timestamp',
'singleton': true
})
.append({
'label': gettext('UUID'),
'name': 'uuid',
'singleton': true
});
}
function properties() {
return {
uuid: { label: gettext('Event UUID'), filters: ['noValue'] },
event_log_id: { label: gettext('ID'), filters: ['noValue'] },
reason_text: { label: gettext('Reason Text'), filters: ['noValue'] },
entity_instance_id: { label: gettext('Entity Instance ID'), filters: ['noValue'] },
severity: { label: gettext('Severity'), filters: ['noValue'] },
timestamp: { label: gettext('Timestamp'), filters: ['noValue'] },
suppression_status: { label: gettext('Suppression Status'), filters: ['noValue'] },
suppression: { label: gettext('Suppression'), filters: ['noValue'] },
state: { label: gettext('State'), filters: ['noValue'] },
service_affecting: { label: gettext('Service Affecting'), filters: ['noValue'] },
event_log_type: { label: gettext('Alarm Type'), filters: ['noValue'] },
probable_cause: { label: gettext('Probable Cause'), filters: ['noValue'] },
entity_type_id: { label: gettext('Entity Type ID'), filters: ['noValue'] },
proposed_repair_action: { label: gettext('Proposed Repair Action'), filters: ['noValue'] },
event_type: { label: gettext('Event Type'), filters: ['noValue'] },
_suppression_status: { label: gettext('_suppression_status'), filters: ['noValue'] }
};
}
config.$inject = [
'$provide',
'$windowProvider',
'$routeProvider'
];
/**
* @name config
* @param {Object} $provide
* @param {Object} $windowProvider
* @param {Object} $routeProvider
* @description Routes used by this module.
* @returns {undefined} Returns nothing
*/
function config($provide, $windowProvider, $routeProvider) {
var path = $windowProvider.$get().STATIC_URL + 'dashboard/fault_management/events/';
$provide.constant('horizon.dashboard.fault_management.events.basePath', path);
$routeProvider.when('/admin/events', {
templateUrl: path + 'panel.html',
resolve: {
searchResults: ['horizon.dashboard.fault_management.events.service', function (searchService) {
return searchService.getSuppressionList();
}]
}
});
}
})();

View File

@ -0,0 +1,30 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
describe('horizon.dashboard.fault_management.events', function() {
it('should exist', function() {
expect(angular.module('horizon.dashboard.fault_management.events')).toBeDefined();
});
});
})();

View File

@ -0,0 +1,157 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
angular.module('horizon.dashboard.fault_management.events')
.factory('horizon.dashboard.fault_management.events.service',
service);
service.$inject = [
'$filter',
'horizon.app.core.detailRoute',
'horizon.app.core.openstack-service-api.fm',
'$q',
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.fault_management.events.resourceType'
];
/*
* @ngdoc factory
* @name horizon.dashboard.fault_management.events.service
*
* @description
* This service provides functions that are used through the Events
* features. These are primarily used in the module registrations
* but do not need to be restricted to such use. Each exposed function
* is documented below.
*/
function service($filter, detailRoute, api, $q, registry, resourceType) {
var showSuppressColumn = null;
return {
getPromise: getPromise,
urlFunction: urlFunction,
suppressColAllowedPromiseFunction: suppressColAllowedPromiseFunction,
getSuppressionList: getSuppressionList,
setEventType: setEventType
};
function getPromise(params) {
return api.getEvents(params).then(modifyResponse);
}
function modifyResponse(response) {
return {data: {items: response.data.items.map(modifyItem)}};
function modifyItem(item) {
var timestamp = item.updated_at ? item.updated_at : item.created_at;
item.trackBy = item.uuid + timestamp;
setEventType(item);
if (item.suppression_status == 'suppressed') {
item._suppression_status = 'True';
}
else if (item.suppression_status == 'unsuppressed') {
item._suppression_status = 'False';
}
else {
item._suppression_status = 'None';
}
return item;
}
}
function urlFunction(item) {
return detailRoute + 'OS::StarlingX::Events/' + item.uuid;
}
function getSuppressionList() {
var include_unsuppressed = false;
return api.getEventsSuppression(include_unsuppressed).then(modifyResponseSupp);
}
function modifyResponseSupp(response) {
if (response.data.items.length == 0) {
showSuppressColumn = false;
}
else {
showSuppressColumn = true;
}
return;
}
/**
* @name suppressColAllowedPromiseFunction
* @description
* If there are no unsuppressed events then we do not show the Suppression
* Status column. We also do show the the filter associated with that column.
*/
function suppressColAllowedPromiseFunction() {
var filters = registry.getResourceType(resourceType).filterFacets;
var index = filters.findIndex(obj => obj['id'] === 'suppression_status');
if (showSuppressColumn === false) {
if (index >= 0) {
filters.remove('suppression_status')
}
return $q.reject();
}
else {
if (index < 0) {
filters.append({
'label': gettext('Suppression Status'),
'id': 'suppression_status',
'name': '_suppression_status',
'singleton': false,
'options': [
{label: gettext('suppressed'), key: 'True'},
{label: gettext('unsuppressed'), key: 'False'},
{label: gettext('None'), key: 'None'}
]
});
}
return $q.resolve();
}
}
///////////
// Utils //
///////////
function setEventType(item) {
if (item.state == "clear" || item.state == "set") {
item.event_type = "alarm"
}
else if (item.state == "log" ) {
item.event_type = "log"
}
return item;
}
}
})();

View File

@ -0,0 +1,60 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
describe('Event service', function() {
var service;
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.fault_management.events'));
beforeEach(inject(function($injector) {
service = $injector.get('horizon.dashboard.fault_management.events.service');
}));
describe('getPromise', function() {
it("provides a promise", inject(function($q, $injector, $timeout) {
var api = $injector.get('horizon.app.core.openstack-service-api.fm');
var deferred = $q.defer();
spyOn(api, 'getEvents').and.returnValue(deferred.promise);
var result = service.getPromise({});
deferred.resolve({
data:{
items: [{uuid: '123abc', reason_text: 'resource1'}]
}
});
$timeout.flush();
expect(api.getEvents).toHaveBeenCalled();
expect(result.$$state.value.data.items[0].reason_text).toBe('resource1');
}));
});
describe('urlFunction', function() {
it("get url", inject(function($injector) {
var detailRoute = $injector.get('horizon.app.core.detailRoute');
var result = service.urlFunction({uuid:"123abc"});
expect(result).toBe(detailRoute + "OS::StarlingX::Events/123abc");
}));
});
});
})();

View File

@ -0,0 +1,6 @@
<hz-resource-panel resource-type-name="OS::StarlingX::Events">
<hz-resource-table resource-type-name="OS::StarlingX::Events"
track-by="trackBy">
</hz-resource-table>
</hz-resource-panel>

View File

@ -0,0 +1,76 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @ngname horizon.dashboard.fault_management.events_suppression.actions
*
* @description
* Provides all of the actions for Events Suppression.
*/
angular
.module('horizon.dashboard.fault_management.events_suppression.actions', [
'horizon.framework',
'horizon.dashboard.fault_management'
])
.run(registerEventsSuppressionActions);
registerEventsSuppressionActions.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.framework.util.i18n.gettext',
'horizon.dashboard.fault_management.events_suppression.suppress_event.service',
'horizon.dashboard.fault_management.events_suppression.unsuppress_event.service',
'horizon.dashboard.fault_management.events_suppression.resourceType'
];
function registerEventsSuppressionActions (
registry,
gettext,
suppressEventService,
unsuppressEventService,
resourceType
) {
var eventSuppressionResourceType = registry.getResourceType(resourceType);
eventSuppressionResourceType.itemActions
.append({
id: 'suppressEventAction',
service: suppressEventService,
template: {
type: 'danger',
text: gettext('Suppress Event')
}
});
eventSuppressionResourceType.itemActions
.append({
id: 'unsuppressEventAction',
service: unsuppressEventService,
template: {
type: 'danger',
text: gettext('Unsuppress Event')
}
});
}
})();

View File

@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
angular
.module('horizon.dashboard.fault_management')
.factory('horizon.dashboard.fault_management.events_suppression.suppress_event.service', updateService);
updateService.$inject = [
'$location',
'horizon.app.core.openstack-service-api.fm',
'horizon.framework.widgets.modal.simple-modal.service',
'horizon.framework.widgets.toast.service',
'horizon.framework.util.q.extensions'
];
function updateService($location, api, simpleModalService, toastService, $qExtensions) {
var scope;
var service = {
perform: perform,
allowed: allowed
};
var suppressedText = "Suppress Event";
var suppressed = "suppressed";
return service;
function perform(selected, newScope) {
var alarm_id = selected.alarm_id;
var options = {
title: 'Confirm ' + suppressedText,
body: 'You have selected: "' + alarm_id +
'". Please confirm your selection. Events with selected Alarm ID will be ' +
suppressed + '.',
submit: suppressedText,
cancel: 'Cancel'
};
selected = angular.isArray(selected) ? selected : [selected];
return simpleModalService.modal(options).result.then(onModalSubmit);
function onModalSubmit() {
return $qExtensions.allSettled(selected.map(updateEntityPromise)).then(notify);
}
function updateEntityPromise(selected) {
var status = {'suppression_status': suppressed};
return {promise: api.updateEventSuppression(selected.uuid, status)};
}
function notify(result) {
if (result.pass.length > 0) {
var msg = gettext("Events %(suppressed)s for Alarm ID: %(alarm_id)s");
toastService.add('success', interpolate(msg, {suppressed: suppressed, alarm_id: alarm_id}, true));
$location.path('/admin/events_suppression');
}
if (result.fail.length > 0) {
var msg = gettext("Failed to %(suppressed)s events for Alarm ID: %(alarm_id)s");
toastService.add('error', interpolate(msg, {suppressed: suppressed, alarm_id: alarm_id}, true));
return result;
}
}
}
function allowed($scope) {
if ($scope.suppression_status == suppressed) {
return $qExtensions.booleanAsPromise(false);
}
else {
return $qExtensions.booleanAsPromise(true);
}
}
}
})();

View File

@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
angular
.module('horizon.dashboard.fault_management')
.factory('horizon.dashboard.fault_management.events_suppression.unsuppress_event.service', updateService);
updateService.$inject = [
'$location',
'horizon.app.core.openstack-service-api.fm',
'horizon.framework.widgets.modal.simple-modal.service',
'horizon.framework.widgets.toast.service',
'horizon.framework.util.q.extensions'
];
function updateService($location, api, simpleModalService, toastService, $qExtensions) {
var scope;
var service = {
perform: perform,
allowed: allowed
};
var unsuppressedText = "Unsuppress Event";
var unsuppressed = "unsuppressed";
return service;
function perform(selected, newScope) {
var alarm_id = selected.alarm_id;
var options = {
title: 'Confirm ' + unsuppressedText,
body: 'You have selected: "' + alarm_id +
'". Please confirm your selection. Events with selected Alarm ID will be ' +
unsuppressed + '.',
submit: unsuppressedText,
cancel: 'Cancel'
};
selected = angular.isArray(selected) ? selected : [selected];
return simpleModalService.modal(options).result.then(onModalSubmit);
function onModalSubmit() {
return $qExtensions.allSettled(selected.map(updateEntityPromise)).then(notify);
}
function updateEntityPromise(selected) {
var status = {'suppression_status': unsuppressed};
return {promise: api.updateEventSuppression(selected.uuid, status)};
}
function notify(result) {
if (result.pass.length > 0) {
var msg = gettext("Events %(unsuppressed)s for Alarm ID: %(alarm_id)s");
toastService.add('success', interpolate(msg, {unsuppressed: unsuppressed, alarm_id: alarm_id}, true));
$location.path('/admin/events_suppression');
}
if (result.fail.length > 0) {
var msg = gettext("Failed to %(unsuppressed)s events for Alarm ID: %(alarm_id)s");
toastService.add('error', interpolate(msg, {unsuppressed: unsuppressed, alarm_id: alarm_id}, true));
return result;
}
}
}
function allowed($scope) {
if ($scope.suppression_status == unsuppressed) {
return $qExtensions.booleanAsPromise(false);
}
else {
return $qExtensions.booleanAsPromise(true);
}
}
}
})();

View File

@ -0,0 +1,131 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.fault_management.events_suppression
* @ngModule
* @description
* Provides all the services and widgets require to display the Events Suppression
* panel
*/
angular
.module('horizon.dashboard.fault_management.events_suppression', [
'ngRoute',
'horizon.dashboard.fault_management.events_suppression.actions'
])
.constant('horizon.dashboard.fault_management.events_suppression.resourceType', 'OS::StarlingX::EventsSuppression')
.run(run)
.config(config);
run.$inject = [
'horizon.framework.conf.resource-type-registry.service',
'horizon.dashboard.fault_management.events_suppression.service',
'horizon.dashboard.fault_management.events_suppression.basePath',
'horizon.dashboard.fault_management.events_suppression.resourceType'
];
function run(registry, service, basePath, resourceType) {
registry.getResourceType(resourceType)
.setNames(gettext('Events Suppression'), gettext('Events Suppression'))
// specify items for table row items, summary view and details view
.setProperties(properties())
// get items for table
.setListFunction(service.getPromise)
// specify table columns
.tableColumns
.append({
id: 'alarm_id',
priority: 1,
sortDefault: true
})
.append({
id: 'description',
priority: 1
})
.append({
id: 'suppression_status',
priority: 1
});
// for magic-search
registry.getResourceType(resourceType).filterFacets
.append({
'label': gettext('Event ID'),
'name': 'alarm_id',
'singleton': true
})
.append({
'label': gettext('Description'),
'name': 'description',
'singleton': true
})
.append({
'label': gettext('Status'),
'name': 'is_suppressed',
'singleton': true,
'options': [
{label: gettext('suppressed'), key: 'true'},
{label: gettext('unsuppressed'), key: 'false'}
]
})
;
}
function properties() {
return {
alarm_id: { label: gettext('Event ID'), filters: ['noValue'] },
description: { label: gettext('Description'), filters: ['noValue'] },
uuid: { label: gettext('Event UUID'), filters: ['noValue'] },
suppression_status: { label: gettext('Status'), filters: ['noValue'] },
links: { label: gettext('Links'), filters: ['noValue'] },
is_suppressed: { label: gettext('IsSuppressed'), filters: ['noValue'] }
};
}
config.$inject = [
'$provide',
'$windowProvider',
'$routeProvider'
];
/**
* @name config
* @param {Object} $provide
* @param {Object} $windowProvider
* @param {Object} $routeProvider
* @description Routes used by this module.
* @returns {undefined} Returns nothing
*/
function config($provide, $windowProvider, $routeProvider) {
var path = $windowProvider.$get().STATIC_URL + 'dashboard/fault_management/events_suppression/';
$provide.constant('horizon.dashboard.fault_management.events_suppression.basePath', path);
$routeProvider.when('/admin/events_suppression', {
templateUrl: path + 'panel.html'
});
}
})();

View File

@ -0,0 +1,30 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
describe('horizon.dashboard.fault_management.events_suppression', function() {
it('should exist', function() {
expect(angular.module('horizon.dashboard.fault_management.events_suppression')).toBeDefined();
});
});
})();

View File

@ -0,0 +1,4 @@
// This enables \n to render properly, we use this for the description col
[resource-type-name="OS::StarlingX::EventsSuppression"] table hz-field.ng-scope.ng-isolate-scope {
white-space: pre-wrap;
}

View File

@ -0,0 +1,78 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
angular.module('horizon.dashboard.fault_management.events_suppression')
.factory('horizon.dashboard.fault_management.events_suppression.service',
service);
service.$inject = [
'$filter',
'horizon.app.core.detailRoute',
'horizon.app.core.openstack-service-api.fm'
];
/*
* @ngdoc factory
* @name horizon.dashboard.fault_management.events_suppression.service
*
* @description
* This service provides functions that are used through the Events Suppression
* features. These are primarily used in the module registrations
* but do not need to be restricted to such use. Each exposed function
* is documented below.
*/
function service($filter, detailRoute, api) {
return {
getPromise: getPromise
};
function getPromise(params) {
var include_unsuppressed = true;
return api.getEventsSuppression(include_unsuppressed).then(modifyResponse);
}
function modifyResponse(response) {
return {data: {items: response.data.items.map(modifyItem)}};
function modifyItem(item) {
// This enables the items to be updated on the view
item.trackBy = [
item.uuid,
item.suppression_status,
item.alarm_id
].join('/');
if (item.suppression_status == 'suppressed') {
item.is_suppressed = true;
}
else {
item.is_suppressed = false;
}
return item;
}
}
}
})();

View File

@ -0,0 +1,60 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
"use strict";
describe('Events Suppression service', function() {
var service;
beforeEach(module('horizon.app.core.openstack-service-api'));
beforeEach(module('horizon.dashboard.fault_management.events_suppression'));
beforeEach(inject(function($injector) {
service = $injector.get('horizon.dashboard.fault_management.events_suppression.service');
}));
describe('getPromise', function() {
it("provides a promise", inject(function($q, $injector, $timeout) {
var api = $injector.get('horizon.app.core.openstack-service-api.fm');
var deferred = $q.defer();
spyOn(api, 'getEventsSuppression').and.returnValue(deferred.promise);
var result = service.getPromise({});
deferred.resolve({
data:{
items: [{uuid: '123abc', description: 'resource1'}]
}
});
$timeout.flush();
expect(api.getEventsSuppression).toHaveBeenCalled();
expect(result.$$state.value.data.items[0].description).toBe('resource1');
}));
});
describe('urlFunction', function() {
it("get url", inject(function($injector) {
var detailRoute = $injector.get('horizon.app.core.detailRoute');
var result = service.urlFunction({id:"123abc"});
expect(result).toBe(detailRoute + "OS::StarlingX::EventsSuppression/123abc");
}));
});
});
})();

View File

@ -0,0 +1,6 @@
<hz-resource-panel resource-type-name="OS::StarlingX::EventsSuppression">
<hz-resource-table resource-type-name="OS::StarlingX::EventsSuppression"
track-by="trackBy">
</hz-resource-table>
</hz-resource-panel>

View File

@ -0,0 +1,48 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
/**
* @ngdoc overview
* @name horizon.dashboard.fault_management
* @description
* Dashboard module to host various platform panels.
*/
// fixme: if ngRoute and $routeProvider are unnecessary, remove them
/* eslint-disable no-unused-vars */
angular
.module('horizon.dashboard.fault_management', [
'horizon.dashboard.fault_management.active_alarms',
'horizon.dashboard.fault_management.events',
'horizon.dashboard.fault_management.events_suppression',
'ngRoute'
])
.config(config);
config.$inject = ['$provide', '$windowProvider', '$routeProvider'];
function config($provide, $windowProvider, $routeProvider) {
var path = $windowProvider.$get().STATIC_URL + 'dashboard/fault_management/';
$provide.constant('horizon.dashboard.fault_management.basePath', path);
}
/* eslint-disable no-unused-vars */
})();

View File

@ -0,0 +1,30 @@
/**
* 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.
*/
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
(function() {
'use strict';
describe('horizon.dashboard.fault_management', function() {
it('should exist', function() {
expect(angular.module('horizon.dashboard.fault_management')).toBeDefined();
});
});
})();

View File

@ -0,0 +1 @@
@import "events_suppression/events_suppression";

View File

@ -1,3 +1,10 @@
/**
* Copyright (c) 2019 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
/* Core functionality related to alam-banner. */
horizon.alarmbanner = {
@ -6,7 +13,7 @@ horizon.alarmbanner = {
var $old = $(location).attr('pathname');
var $url = $(location).attr('href');
$url = $url.replace($old, "/admin/fault_management/banner");
$url = $url.replace($old, "/admin/active_alarms/banner");
horizon.ajax.queue({
url: $url,
@ -49,7 +56,7 @@ horizon.alarmbanner = {
},
onclick: function() {
var $fm = "/admin/fault_management";
var $fm = "/admin/active_alarms";
var $dc = "/dc_admin/";
var $cur = document.location.href;
var $path = document.location.pathname;