diff --git a/README.rst b/README.rst index 6960fa5..d9cff7d 100644 --- a/README.rst +++ b/README.rst @@ -43,7 +43,7 @@ If you want to enable logs for a better debug follow the following steps or just mkdir /var/log/horizon touch /var/log/horizon/horizon.log - chown -R horizon:horizon horizon + chown -R horizon:horizon /var/log/horizon vim /etc/openstack-dashboard/local_settings.py diff --git a/iotronic_ui/api/iotronic.py b/iotronic_ui/api/iotronic.py index 664d01d..52d0ec7 100644 --- a/iotronic_ui/api/iotronic.py +++ b/iotronic_ui/api/iotronic.py @@ -15,7 +15,7 @@ from iotronicclient import client as iotronic_client # from django.conf import settings -# from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ugettext_lazy as _ # from horizon import exceptions from horizon.utils.memoized import memoized # noqa @@ -260,3 +260,96 @@ def fleet_get_boards(request, fleet_id): """Get fleet boards.""" return iotronicclient(request).fleet.boards_in_fleet(fleet=fleet_id) + +# WEBSERVICES MANAGEMENT +def webservice_list(request, detail=None): + """Get web services list.""" + return iotronicclient(request).webservice.list() + + +def webservice_enabled_list(request): + """Get enabled web services list.""" + return iotronicclient(request).enabledwebservice.list() + + +def webservice_get_enabled_info(request, board_id, detail=None): + """Get the information of the enabled webservices.""" + ws_info = [] + + ws_enabled = iotronicclient(request).enabledwebservice.list() + + for ws in ws_enabled: + if ws.board_uuid == board_id: + ws_info = ws + break + + return ws_info + + +def webservices_on_board(request, board_id, fields=None): + """Get web services on board list.""" + webservices = iotronicclient(request).webserviceonboard.list(board_id, + fields) + + detailed_webservices = [] + # fields = {"name", "port", "uuid"} + + for ws in webservices: + detailed_webservices.append({"name": ws._info["name"], + "port": ws._info["port"], + "uuid": ws._info["uuid"]}) + + return detailed_webservices + + +def webservice_get(request, webservice_id, fields): + """Get web service info.""" + return iotronicclient(request).webservice.get(webservice_id, fields) + + +def webservice_expose(request, board_id, name, port, secure): + """Expose a web service.""" + return iotronicclient(request).webserviceonboard.expose(board_id, + name, + port, + secure) + + +def webservice_unexpose(request, webservice_id): + """Unexpose a web service from a board.""" + return iotronicclient(request).webservice.delete(webservice_id) + + +def webservice_enable(request, board, dns, zone, email): + """Enable web service.""" + return iotronicclient(request).webserviceonboard.enable_webservice(board, + dns, + zone, + email) + + +def webservice_disable(request, board): + """Disable web service.""" + return iotronicclient(request).webserviceonboard.disable_webservice(board) + + +def boards_no_webservice(request): + """Get all the boards that have not webservice enabled.""" + + boards_no_ws_enabled = [] + + board_list = iotronicclient(request).board.list() + board_list.sort(key=lambda b: b.name) + + board_ws_list = iotronicclient(request).enabledwebservice.list() + + for board in board_list: + for i in range(len(board_ws_list)): + if board.uuid == board_ws_list[i].board_uuid: + break + elif ((board.uuid != board_ws_list[i].board_uuid) and + (i==len(board_ws_list)-1)): + boards_no_ws_enabled.append((board.uuid, _(board.name))) + + # LOG.debug('COMPLEMENTARY %s', boards_no_ws_enabled) + return boards_no_ws_enabled diff --git a/iotronic_ui/enabled/_6040_iot_webservices_panel.py b/iotronic_ui/enabled/_6040_iot_webservices_panel.py new file mode 100644 index 0000000..02f7f49 --- /dev/null +++ b/iotronic_ui/enabled/_6040_iot_webservices_panel.py @@ -0,0 +1,23 @@ +# 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. + +# The slug of the panel to be added to HORIZON_CONFIG. Required. +PANEL = 'webservices' +# The slug of the dashboard the PANEL associated with. Required. +PANEL_DASHBOARD = 'iot' +# The slug of the panel group the PANEL is associated with. +PANEL_GROUP = 'iot' +# If set, it will update the default panel of the PANEL_DASHBOARD. +DEFAULT_PANEL = '' + +# Python panel class of the PANEL to be added. +ADD_PANEL = 'iotronic_ui.iot.webservices.panel.Webservices' diff --git a/iotronic_ui/enabled/_6040_iot_fleets_panel.py b/iotronic_ui/enabled/_6050_iot_fleets_panel.py similarity index 100% rename from iotronic_ui/enabled/_6040_iot_fleets_panel.py rename to iotronic_ui/enabled/_6050_iot_fleets_panel.py diff --git a/iotronic_ui/iot/boards/forms.py b/iotronic_ui/iot/boards/forms.py index fc3b3dc..6af8a9c 100644 --- a/iotronic_ui/iot/boards/forms.py +++ b/iotronic_ui/iot/boards/forms.py @@ -34,7 +34,8 @@ class CreateBoardForm(forms.SelfHandlingForm): # MODIFY ---> options: yun, server type = forms.ChoiceField( label=_("Type"), - choices=[('yun', _('YUN')), ('server', _('Server'))], + # choices=[('yun', _('YUN')), ('server', _('Server'))], + choices=[('gateway', _('Gateway')), ('server', _('Server'))], widget=forms.Select( attrs={'class': 'switchable', 'data-slug': 'slug-type'}, ) @@ -175,7 +176,7 @@ class UpdateBoardForm(forms.SelfHandlingForm): class EnableServiceForm(forms.SelfHandlingForm): - uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) name = forms.CharField( label=_('Board Name'), @@ -216,9 +217,10 @@ class EnableServiceForm(forms.SelfHandlingForm): exceptions.handle(request, _(message_text)) +""" class DisableServiceForm(forms.SelfHandlingForm): - uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) name = forms.CharField( label=_('Board Name'), @@ -257,6 +259,7 @@ class DisableServiceForm(forms.SelfHandlingForm): except Exception: message_text = "Unable to disable service." exceptions.handle(request, _(message_text)) +""" class AttachPortForm(forms.SelfHandlingForm): @@ -352,6 +355,64 @@ class DetachPortForm(forms.SelfHandlingForm): exceptions.handle(request, _(message_text)) +class EnableWebServiceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + dns = forms.CharField(label=_("Domain Name Server")) + zone = forms.CharField(label=_("Zone")) + email = forms.CharField(label=_("Email")) + + def __init__(self, *args, **kwargs): + super(EnableWebServiceForm, self).__init__(*args, **kwargs) + + def handle(self, request, data): + + try: + iotronic.webservice_enable(request, data["uuid"], + data["dns"], data["zone"], + data["email"]) + + messages.success(request, _("Web Service enabled on board " + + str(data["name"]) + ".")) + return True + + except Exception: + message_text = "Unable to enable web service." + exceptions.handle(request, _(message_text)) + + +class DisableWebServiceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + def __init__(self, *args, **kwargs): + super(DisableWebServiceForm, self).__init__(*args, **kwargs) + + def handle(self, request, data): + + try: + iotronic.webservice_disable(request, data["uuid"]) + + messages.success(request, _("Web Service disabled on board " + + str(data["name"]) + ".")) + return True + + except Exception: + message_text = "Unable to disable web service." + exceptions.handle(request, _(message_text)) + + class RemovePluginsForm(forms.SelfHandlingForm): uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) diff --git a/iotronic_ui/iot/boards/tables.py b/iotronic_ui/iot/boards/tables.py index 3432a77..da022ca 100644 --- a/iotronic_ui/iot/boards/tables.py +++ b/iotronic_ui/iot/boards/tables.py @@ -73,6 +73,7 @@ class EnableServiceLink(tables.LinkAction): # policy_rules = (("iot", "iot:service_action"),) +""" class DisableServiceLink(tables.LinkAction): name = "disableservice" verbose_name = _("Disable Service(s)") @@ -80,6 +81,7 @@ class DisableServiceLink(tables.LinkAction): classes = ("ajax-modal",) # icon = "plus" # policy_rules = (("iot", "iot:service_action"),) +""" class RemovePluginsLink(tables.LinkAction): @@ -116,6 +118,22 @@ class DetachPortLink(tables.LinkAction): icon = "plus" +class EnableWebServiceLink(tables.LinkAction): + name = "enablewebservice" + verbose_name = _("Enable Web Services") + url = "horizon:iot:boards:enablewebservice" + classes = ("ajax-modal",) + icon = "plus" + + +class DisableWebServiceLink(tables.LinkAction): + name = "disablewebservice" + verbose_name = _("Disable Web Services") + url = "horizon:iot:boards:disablewebservice" + classes = ("ajax-modal",) + icon = "plus" + + class DeleteBoardsAction(tables.DeleteAction): @staticmethod def action_present(count): @@ -191,8 +209,10 @@ class BoardsTable(tables.DataTable): class Meta(object): name = "boards" verbose_name = _("boards") - row_actions = (EditBoardLink, EnableServiceLink, DisableServiceLink, + # row_actions = (EditBoardLink, EnableServiceLink, DisableServiceLink, + row_actions = (EditBoardLink, EnableServiceLink, RestoreServices, AttachPortLink, DetachPortLink, + EnableWebServiceLink, DisableWebServiceLink, RemovePluginsLink, RemoveServicesLink, DeleteBoardsAction) table_actions = (BoardFilterAction, CreateBoardLink, diff --git a/iotronic_ui/iot/boards/tabs.py b/iotronic_ui/iot/boards/tabs.py index 4bdef2b..54f0b74 100644 --- a/iotronic_ui/iot/boards/tabs.py +++ b/iotronic_ui/iot/boards/tabs.py @@ -36,11 +36,13 @@ class OverviewTab(tabs.Tab): coordinates = self.tab_group.kwargs['board'].__dict__['location'][0] ports = self.tab_group.kwargs['board']._info['ports'] services = self.tab_group.kwargs['board']._info['services'] + webservices = self.tab_group.kwargs['board']._info['webservices'] plugins = self.tab_group.kwargs['board']._info['plugins'] return {"board": self.tab_group.kwargs['board'], "coordinates": coordinates, "services": services, + "webservices": webservices, "ports": ports, "plugins": plugins, "is_superuser": request.user.is_superuser} diff --git a/iotronic_ui/iot/boards/templates/boards/_detail_overview.html b/iotronic_ui/iot/boards/templates/boards/_detail_overview.html index 70cd7fb..241725b 100644 --- a/iotronic_ui/iot/boards/templates/boards/_detail_overview.html +++ b/iotronic_ui/iot/boards/templates/boards/_detail_overview.html @@ -57,6 +57,19 @@ {% endif %} +

{% trans "Web Services" %}

+
+
+ {% if webservices %} + {% for ws in webservices %} +
{{ ws.name }} [{{ ws.port }}]
+
{{ ws.uuid }}
+ {% endfor %} + {% else %} +
--
+ {% endif %} +
+

{% trans "Plugins" %}


diff --git a/iotronic_ui/iot/boards/templates/boards/_disablewebservice.html b/iotronic_ui/iot/boards/templates/boards/_disablewebservice.html new file mode 100644 index 0000000..5d65d95 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/_disablewebservice.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "Disable web service(s) on the selected board." %}

+{% endblock %} + diff --git a/iotronic_ui/iot/boards/templates/boards/_enablewebservice.html b/iotronic_ui/iot/boards/templates/boards/_enablewebservice.html new file mode 100644 index 0000000..92d6927 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/_enablewebservice.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "Enable web service(s) on the selected board." %}

+{% endblock %} + diff --git a/iotronic_ui/iot/boards/templates/boards/disablewebservice.html b/iotronic_ui/iot/boards/templates/boards/disablewebservice.html new file mode 100644 index 0000000..890ee0d --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/disablewebservice.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Disable" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_disablewebservice.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/boards/templates/boards/enablewebservice.html b/iotronic_ui/iot/boards/templates/boards/enablewebservice.html new file mode 100644 index 0000000..a190352 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/enablewebservice.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Enable" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_enablewebservice.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/boards/urls.py b/iotronic_ui/iot/boards/urls.py index 0348d95..679a7b4 100644 --- a/iotronic_ui/iot/boards/urls.py +++ b/iotronic_ui/iot/boards/urls.py @@ -26,9 +26,13 @@ urlpatterns = [ views.RemoveServicesView.as_view(), name='removeservices'), url(r'^(?P[^/]+)/enableservice/$', views.EnableServiceView.as_view(), name='enableservice'), - url(r'^(?P[^/]+)/disableservice/$', - views.DisableServiceView.as_view(), name='disableservice'), + # url(r'^(?P[^/]+)/disableservice/$', + # views.DisableServiceView.as_view(), name='disableservice'), url(r'^(?P[^/]+)/attachport/$', + views.EnableWebServiceView.as_view(), name='enablewebservice'), + url(r'^(?P[^/]+)/enablewebservice/$', + views.DisableWebServiceView.as_view(), name='disablewebservice'), + url(r'^(?P[^/]+)/disablewebservice/$', views.AttachPortView.as_view(), name='attachport'), url(r'^(?P[^/]+)/detachport/$', views.DetachPortView.as_view(), name='detachport'), diff --git a/iotronic_ui/iot/boards/views.py b/iotronic_ui/iot/boards/views.py index cb320da..1b660c9 100644 --- a/iotronic_ui/iot/boards/views.py +++ b/iotronic_ui/iot/boards/views.py @@ -75,6 +75,18 @@ class IndexView(tables.DataTableView): board.uuid, True) + # TO BE REMOVED + # We are filtering the services that starts with "webservice" + # ------------------------------------------------------------ + filter_ws = [] + for service in board_services: + if ((service["name"] != "webservice") and + (service["name"] != "webservice_ssl")): + filter_ws.append(service) + + board_services = filter_ws + # ------------------------------------------------------------ + # board.__dict__.update(dict(services=board_services)) board._info.update(dict(services=board_services)) @@ -205,6 +217,7 @@ class EnableServiceView(forms.ModalFormView): 'service_list': service_list} +""" class DisableServiceView(forms.ModalFormView): template_name = 'iot/boards/disableservice.html' modal_header = _("Disable Service(s)") @@ -246,15 +259,31 @@ class DisableServiceView(forms.ModalFormView): service_list = [] + + # BEFORE filtering necessity + # for cloud_service in cloud_services: + # for board_service in board_services: + # if board_service["uuid"] == cloud_service._info["uuid"]: + # service_list.append((cloud_service._info["uuid"], + # _(cloud_service._info["name"]))) + + # AFTER filtering necessity + # We are filtering the services that starts with "webservice" + # ------------------------------------------------------------ + for cloud_service in cloud_services: for board_service in board_services: - if board_service["uuid"] == cloud_service._info["uuid"]: + if ((board_service["uuid"] == cloud_service._info["uuid"]) and + ((board_service["name"] != "webservice") and + (board_service["name"] != "webservice_ssl"))): service_list.append((cloud_service._info["uuid"], _(cloud_service._info["name"]))) + # ------------------------------------------------------------ return {'uuid': board.uuid, 'name': board.name, 'service_list': service_list} +""" class AttachPortView(forms.ModalFormView): @@ -357,6 +386,80 @@ class DetachPortView(forms.ModalFormView): 'ports': ports} +class EnableWebServiceView(forms.ModalFormView): + template_name = 'iot/boards/enablewebservice.html' + modal_header = _("Enable Web Service(s)") + form_id = "webservice_enable_form" + form_class = project_forms.EnableWebServiceForm + submit_label = _("Enable") + # submit_url = reverse_lazy("horizon:iot:boards:enablewebservice") + submit_url = "horizon:iot:boards:enablewebservice" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Enable") + + @memoized.memoized_method + def get_object(self): + try: + return api.iotronic.board_get(self.request, + self.kwargs['board_id'], + None) + + except Exception: + redirect = reverse("horizon:iot:boards:index") + exceptions.handle(self.request, + _('Unable to get board information.'), + redirect=redirect) + + def get_context_data(self, **kwargs): + context = super(EnableWebServiceView, self).get_context_data(**kwargs) + args = (self.get_object().uuid,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + board = self.get_object() + + return {'uuid': board.uuid, + 'name': board.name} + + +class DisableWebServiceView(forms.ModalFormView): + template_name = 'iot/boards/disablewebservice.html' + modal_header = _("Disable Web Service(s)") + form_id = "webservice_disable_form" + form_class = project_forms.DisableWebServiceForm + submit_label = _("Disable") + # submit_url = reverse_lazy("horizon:iot:boards:disablewebservice") + submit_url = "horizon:iot:boards:disablewebservice" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Disable") + + @memoized.memoized_method + def get_object(self): + try: + return api.iotronic.board_get(self.request, + self.kwargs['board_id'], + None) + + except Exception: + redirect = reverse("horizon:iot:boards:index") + exceptions.handle(self.request, + _('Unable to get board information.'), + redirect=redirect) + + def get_context_data(self, **kwargs): + context = super(DisableWebServiceView, self).get_context_data(**kwargs) + args = (self.get_object().uuid,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + board = self.get_object() + + return {'uuid': board.uuid, + 'name': board.name} + + class RemovePluginsView(forms.ModalFormView): template_name = 'iot/boards/removeplugins.html' modal_header = _("Remove Plugins from board") @@ -445,7 +548,15 @@ class RemoveServicesView(forms.ModalFormView): service_list = [] for service in services: - service_list.append((service["uuid"], _(service["name"]))) + # service_list.append((service["uuid"], _(service["name"]))) + + # TO BE REMOVED + # ########################################################### + # We are filtering the services that starts with "webservice" + if ((service["name"] != "webservice") and + (service["name"] != "webservice_ssl")): + service_list.append((service["uuid"], _(service["name"]))) + # ########################################################### return {'uuid': board.uuid, 'name': board.name, @@ -501,6 +612,10 @@ class DetailView(tabs.TabView): board_id) board._info.update(dict(plugins=board_plugins)) + board_webservices = api.iotronic.webservices_on_board(self.request, + board_id) + board._info.update(dict(webservices=board_webservices)) + # Adding fleet name if board.fleet != None: fleet_info = api.iotronic.fleet_get(self.request, diff --git a/iotronic_ui/iot/dashboard.py b/iotronic_ui/iot/dashboard.py index 962c4ad..a5abbaa 100644 --- a/iotronic_ui/iot/dashboard.py +++ b/iotronic_ui/iot/dashboard.py @@ -18,7 +18,8 @@ import horizon class Iot(horizon.Dashboard): name = _("IoT") slug = "iot" - panels = ('boards', 'plugins', 'services', 'fleets') # Add your panels here. + panels = ('boards', 'plugins', 'services', + 'webservices', 'fleets') # Add your panels here. # Specify the slug of the dashboard's default panel. default_panel = 'boards' diff --git a/iotronic_ui/iot/fleets/forms.py b/iotronic_ui/iot/fleets/forms.py index 435553e..5be0af7 100644 --- a/iotronic_ui/iot/fleets/forms.py +++ b/iotronic_ui/iot/fleets/forms.py @@ -88,64 +88,3 @@ class UpdateFleetForm(forms.SelfHandlingForm): except Exception: exceptions.handle(request, _('Unable to update fleet.')) - - -class FleetActionForm(forms.SelfHandlingForm): - - uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) - - name = forms.CharField( - label=_('Fleet Name'), - widget=forms.TextInput(attrs={'readonly': 'readonly'}) - ) - - board_list = forms.MultipleChoiceField( - label=_("Boards List"), - widget=forms.SelectMultiple( - attrs={'class': 'switchable', 'data-slug': 'slug-select-boards'}), - help_text=_("Select boards in this pool") - ) - - action = forms.ChoiceField( - label=_("Action"), - choices=[('FleetEnable', _('Enable')), - ('FleetDisable', _('Disable')), - ('FleetRestore', _('Restore'))], - widget=forms.Select( - attrs={'class': 'switchable', 'data-slug': 'slug-action'}, - ) - ) - - def __init__(self, *args, **kwargs): - - super(FleetActionForm, self).__init__(*args, **kwargs) - # input=kwargs.get('initial',{}) - - self.fields["board_list"].choices = kwargs["initial"]["board_list"] - - def handle(self, request, data): - - counter = 0 - - for board in data["board_list"]: - for key, value in self.fields["board_list"].choices: - if key == board: - - try: - action = iotronic.fleet_action(request, key, - data["uuid"], - data["action"]) - message_text = action - messages.success(request, _(message_text)) - - if counter != len(data["board_list"]) - 1: - counter += 1 - else: - return True - - except Exception: - message_text = "Unable to execute action on board " \ - + str(value) + "." - exceptions.handle(request, _(message_text)) - - break diff --git a/iotronic_ui/iot/fleets/tables.py b/iotronic_ui/iot/fleets/tables.py index 0b6ac58..7b12d28 100644 --- a/iotronic_ui/iot/fleets/tables.py +++ b/iotronic_ui/iot/fleets/tables.py @@ -40,15 +40,6 @@ class EditFleetLink(tables.LinkAction): # policy_rules = (("iot", "iot:update_fleet"),) -class ActionFleetLink(tables.LinkAction): - name = "action" - verbose_name = _("Fleet Action") - url = "horizon:iot:fleets:action" - classes = ("ajax-modal",) - # icon = "plus" - # policy_rules = (("iot", "iot:fleet_action"),) - - class DeleteFleetsAction(tables.DeleteAction): @staticmethod def action_present(count): @@ -93,8 +84,6 @@ class FleetsTable(tables.DataTable): class Meta(object): name = "fleets" verbose_name = _("fleets") - # row_actions = (EditFleetLink, ActionFleetLink, - # DeleteFleetsAction) row_actions = (EditFleetLink, DeleteFleetsAction) table_actions = (FleetFilterAction, CreateFleetLink, DeleteFleetsAction) diff --git a/iotronic_ui/iot/fleets/templates/fleets/action.html b/iotronic_ui/iot/fleets/templates/fleets/action.html deleted file mode 100644 index 130a9a5..0000000 --- a/iotronic_ui/iot/fleets/templates/fleets/action.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Execute Action" %}{% endblock %} - -{% block main %} - {% include 'iot/fleets/_action.html' %} -{% endblock %} diff --git a/iotronic_ui/iot/fleets/urls.py b/iotronic_ui/iot/fleets/urls.py index 17d40f2..a02b52d 100644 --- a/iotronic_ui/iot/fleets/urls.py +++ b/iotronic_ui/iot/fleets/urls.py @@ -20,8 +20,6 @@ urlpatterns = [ url(r'^create/$', views.CreateView.as_view(), name='create'), url(r'^(?P[^/]+)/update/$', views.UpdateView.as_view(), name='update'), - url(r'^(?P[^/]+)/action/$', views.ActionView.as_view(), - name='action'), url(r'^(?P[^/]+)/detail/$', views.FleetDetailView.as_view(), name='detail'), ] diff --git a/iotronic_ui/iot/fleets/views.py b/iotronic_ui/iot/fleets/views.py index b2a42d2..e70829a 100644 --- a/iotronic_ui/iot/fleets/views.py +++ b/iotronic_ui/iot/fleets/views.py @@ -120,51 +120,6 @@ class UpdateView(forms.ModalFormView): 'description': fleet.description} -class ActionView(forms.ModalFormView): - template_name = 'iot/fleets/action.html' - modal_header = _("Fleet Action") - form_id = "fleet_action_form" - form_class = project_forms.FleetActionForm - submit_label = _("Fleet Action") - # submit_url = reverse_lazy("horizon:iot:fleets:action") - submit_url = "horizon:iot:fleets:action" - success_url = reverse_lazy('horizon:iot:fleets:index') - page_title = _("Fleet Action") - - @memoized.memoized_method - def get_object(self): - try: - return iotronic.fleet_get(self.request, - self.kwargs['fleet_id'], - None) - except Exception: - redirect = reverse("horizon:iot:fleets:index") - exceptions.handle(self.request, - _('Unable to get fleet information.'), - redirect=redirect) - - def get_context_data(self, **kwargs): - context = super(ActionView, self).get_context_data(**kwargs) - args = (self.get_object().uuid,) - context['submit_url'] = reverse(self.submit_url, args=args) - return context - - def get_initial(self): - fleet = self.get_object() - - # Populate boards - boards = iotronic.board_list(self.request, "online", None, None) - boards.sort(key=lambda b: b.name) - - board_list = [] - for board in boards: - board_list.append((board.uuid, _(board.name))) - - return {'uuid': fleet.uuid, - 'name': fleet.name, - 'board_list': board_list} - - class DetailView(tabs.TabView): tab_group_class = project_tabs.FleetDetailTabs template_name = 'horizon/common/_detail.html' diff --git a/iotronic_ui/iot/webservices/__init__.py b/iotronic_ui/iot/webservices/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/iotronic_ui/iot/webservices/forms.py b/iotronic_ui/iot/webservices/forms.py new file mode 100644 index 0000000..8a18f01 --- /dev/null +++ b/iotronic_ui/iot/webservices/forms.py @@ -0,0 +1,103 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import messages + +from openstack_dashboard.api import iotronic +from openstack_dashboard import policy + +LOG = logging.getLogger(__name__) + + +class ExposeWebserviceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + ws_name = forms.CharField(label=_("Web Service Name")) + + port = forms.IntegerField( + label=_("Port"), + help_text=_("The port used by the service") + ) + + secure = forms.BooleanField(label=_("Secure"), initial=True) + + def __init__(self, *args, **kwargs): + super(ExposeWebserviceForm, self).__init__(*args, **kwargs) + + def handle(self, request, data): + try: + iotronic.webservice_expose(request, data["uuid"], + data["ws_name"], data["port"], + data["secure"]) + + messages.success(request, _("Web Service " + str(data["name"]) + + " exposed successfully on port " + + str(data["port"]) + ".")) + return True + + except Exception: + exceptions.handle(request, _('Unable to expose web service.')) + + +class UnexposeWebserviceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + ws_onboard = forms.MultipleChoiceField( + label=_("Web Services on board"), + widget=forms.SelectMultiple( + attrs={'class': 'switchable', + 'data-slug': 'slug-select-webservices'}), + help_text=_("Select a webservice from the list") + ) + + def __init__(self, *args, **kwargs): + + super(UnexposeWebserviceForm, self).__init__(*args, **kwargs) + self.fields["ws_onboard"].choices = kwargs["initial"]["ws_onboard"] + + def handle(self, request, data): + + counter = 0 + for ws in data["ws_onboard"]: + try: + iotronic.webservice_unexpose(request, ws) + + message_text = "Web Service(s) unexposed successfully." + messages.success(request, _(message_text)) + + if counter != len(data["ws_onboard"]) - 1: + counter += 1 + else: + return True + + except Exception: + LOG.debug("HERE") + message_text = "Unable to unexpose web service." + exceptions.handle(request, _(message_text)) diff --git a/iotronic_ui/iot/webservices/panel.py b/iotronic_ui/iot/webservices/panel.py new file mode 100644 index 0000000..7ff3523 --- /dev/null +++ b/iotronic_ui/iot/webservices/panel.py @@ -0,0 +1,28 @@ +# 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. + +from django.utils.translation import ugettext_lazy as _ + +import horizon + +# from openstack_dashboard.api import keystone +from iotronic_ui.iot import dashboard + + +class Webservices(horizon.Panel): + name = _("Web Services") + slug = "webservices" + # permissions = ('openstack.webservices.iot', ) + # policy_rules = (("iot", "iot:list_all_webservices"),) + + +dashboard.Iot.register(Webservices) diff --git a/iotronic_ui/iot/webservices/tables.py b/iotronic_ui/iot/webservices/tables.py new file mode 100644 index 0000000..541393d --- /dev/null +++ b/iotronic_ui/iot/webservices/tables.py @@ -0,0 +1,121 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from django import template +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ungettext_lazy + +from horizon import tables + +from openstack_dashboard import api + +LOG = logging.getLogger(__name__) + + +class ExposeWebserviceLink(tables.LinkAction): + name = "expose" + verbose_name = _("Expose") + url = "horizon:iot:webservices:expose" + classes = ("ajax-modal",) + icon = "plus" + # policy_rules = (("iot", "iot:expose_webservice"),) + + +class UnexposeWebserviceLink(tables.LinkAction): + name = "unexpose" + verbose_name = _("Unexpose") + url = "horizon:iot:webservices:unexpose" + classes = ("ajax-modal",) + icon = "plus" + # policy_rules = (("iot", "iot:unexpose_webservice"),) + + +""" +class DisableWebservicesAction(tables.DeleteAction): + @staticmethod + def action_present(count): + return ungettext_lazy( + u"Disable", + u"Disable Web Services", + count + ) + + @staticmethod + def action_past(count): + return ungettext_lazy( + u"Disabled Web Service", + u"Disabled Web Services", + count + ) + # policy_rules = (("iot", "iot:disable_webservice"),) + + def delete(self, request, board_id): + api.iotronic.webservice_disable(request, board_id) +""" + + +class WebserviceFilterAction(tables.FilterAction): + + def filter(self, table, webservices, filter_string): + # Naive case-insensitive search. + q = filter_string.lower() + return [webservice for webservice in webservices + if q in webservice.name.lower()] + + +def show_webservices(board_info): + template_name = 'iot/webservices/_cell_webservices.html' + context = board_info._info + # LOG.debug("CONTEXT: %s", context) + return template.loader.render_to_string(template_name, + context) + + +class WebservicesTable(tables.DataTable): + + """ + uuid = tables.WrappingColumn('uuid', + link="horizon:iot:webservices:detail", + verbose_name=_('UUID')) + """ + board = tables.Column('name', verbose_name=_('Board Name')) + + board_uuid = tables.Column('board_uuid', + verbose_name=_('Board UUID'), + hidden=True) + + webservices = tables.Column(show_webservices, + verbose_name=_('Web Services')) + + http = tables.Column('http_port', verbose_name=_('HTTP')) + https = tables.Column('https_port', verbose_name=_('HTTPS')) + + # Overriding get_object_id method because in IoT webservice the "id" is + # identified by the field UUID + def get_object_id(self, datum): + # LOG.debug('SELF: %s', self) + return datum.board_uuid + + class Meta(object): + name = "webservices" + verbose_name = _("Web Services") + """ + row_actions = (ExposeWebserviceLink, + UnexposeWebserviceLink, + DisableWebservicesAction) + table_actions = (WebserviceFilterAction, DisableWebservicesAction) + """ + row_actions = (ExposeWebserviceLink, + UnexposeWebserviceLink) + table_actions = (WebserviceFilterAction,) diff --git a/iotronic_ui/iot/webservices/tabs.py b/iotronic_ui/iot/webservices/tabs.py new file mode 100644 index 0000000..60207fa --- /dev/null +++ b/iotronic_ui/iot/webservices/tabs.py @@ -0,0 +1,47 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +# from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ + +from horizon import tabs + +LOG = logging.getLogger(__name__) + + +""" +class OverviewTab(tabs.Tab): + name = _("Overview") + slug = "overview" + template_name = ("iot/webservices/_detail_overview.html") + + def get_context_data(self, request): + # coordinates = self.tab_group.kwargs['board'].__dict__["location"][0] + # LOG.debug('IOT INFO: %s', coordinates) + + board_name = self.tab_group.kwargs['webservice']._info['board_name'] + board_uuid = self.tab_group.kwargs['webservice']._info['board_uuid'] + + return {"webservice": self.tab_group.kwargs['webservice'], + "board_uuid": board_uuid, + "board_name": board_name, + "is_superuser": request.user.is_superuser} + + +class WebserviceDetailTabs(tabs.TabGroup): + slug = "webservice_details" + # tabs = (OverviewTab, LogTab, ConsoleTab, AuditTab) + tabs = (OverviewTab,) + sticky = True +""" diff --git a/iotronic_ui/iot/webservices/templates/webservices/_cell_webservices.html b/iotronic_ui/iot/webservices/templates/webservices/_cell_webservices.html new file mode 100644 index 0000000..2040153 --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/_cell_webservices.html @@ -0,0 +1,8 @@ +{% load i18n %} +{% if webservices %} + {% for ws in webservices %} +
{{ ws.service_url}}
+ {% endfor %} +{% else %} +
--
+{% endif %} diff --git a/iotronic_ui/iot/webservices/templates/webservices/_detail_overview.html b/iotronic_ui/iot/webservices/templates/webservices/_detail_overview.html new file mode 100644 index 0000000..02893c8 --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/_detail_overview.html @@ -0,0 +1,27 @@ +{% load i18n sizeformat %} + +
+
+
{% trans "Name" %}
+
{{ webservice.name }}
+
{% trans "Port" %}
+
{{ webservice.port }}
+
{% trans "ID" %}
+
{{ webservice.uuid }}
+
{% trans "Created At" %}
+
{{ webservice.created_at }}
+
{% trans "extra" %}
+
{{ webservice.extra }}
+
+ +

{% trans "Board" %}

+
+
+ {% if board_uuid %} +
{{ board_name }}
+
{{ board_uuid }}
+ {% else %} +
--
+ {% endif %} +
+
diff --git a/iotronic_ui/iot/fleets/templates/fleets/_action.html b/iotronic_ui/iot/webservices/templates/webservices/_expose.html similarity index 74% rename from iotronic_ui/iot/fleets/templates/fleets/_action.html rename to iotronic_ui/iot/webservices/templates/webservices/_expose.html index 37fb87d..130fd63 100644 --- a/iotronic_ui/iot/fleets/templates/fleets/_action.html +++ b/iotronic_ui/iot/webservices/templates/webservices/_expose.html @@ -3,5 +3,6 @@ {% block modal-body-right %}

{% trans "Description:" %}

-

{% trans "Execute action on board(s)." %}

+

{% trans "Expose a new Web Service." %}

{% endblock %} + diff --git a/iotronic_ui/iot/webservices/templates/webservices/_unexpose.html b/iotronic_ui/iot/webservices/templates/webservices/_unexpose.html new file mode 100644 index 0000000..ed87ede --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/_unexpose.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "Unexpose Web Service(s)." %}

+{% endblock %} + diff --git a/iotronic_ui/iot/webservices/templates/webservices/expose.html b/iotronic_ui/iot/webservices/templates/webservices/expose.html new file mode 100644 index 0000000..224da45 --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/expose.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Insert Web Service" %}{% endblock %} + +{% block main %} + {% include 'iot/webservices/_expose.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/webservices/templates/webservices/index.html b/iotronic_ui/iot/webservices/templates/webservices/index.html new file mode 100644 index 0000000..30c5893 --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/index.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Web Services" %}{% endblock %} + +{% block main %} + {{ table.render }} +{% endblock %} diff --git a/iotronic_ui/iot/webservices/templates/webservices/unexpose.html b/iotronic_ui/iot/webservices/templates/webservices/unexpose.html new file mode 100644 index 0000000..133ee64 --- /dev/null +++ b/iotronic_ui/iot/webservices/templates/webservices/unexpose.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Unexpose Web Service" %}{% endblock %} + +{% block main %} + {% include 'iot/webservices/_unexpose.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/webservices/tests.py b/iotronic_ui/iot/webservices/tests.py new file mode 100644 index 0000000..d1a529b --- /dev/null +++ b/iotronic_ui/iot/webservices/tests.py @@ -0,0 +1,19 @@ +# 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. + +from horizon.test import helpers as test + + +class FleetsTests(test.TestCase): + # Unit tests for boards. + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/iotronic_ui/iot/webservices/urls.py b/iotronic_ui/iot/webservices/urls.py new file mode 100644 index 0000000..e582fc9 --- /dev/null +++ b/iotronic_ui/iot/webservices/urls.py @@ -0,0 +1,26 @@ +# 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. + +from django.conf.urls import url + +from iotronic_ui.iot.webservices import views + + +urlpatterns = [ + url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^(?P[^/]+)/expose/$', + views.ExposeView.as_view(), name='expose'), + url(r'^(?P[^/]+)/unexpose/$', + views.UnexposeView.as_view(), name='unexpose'), + # url(r'^(?P[^/]+)/detail/$', views.WebserviceDetailView.as_view(), + # name='detail'), +] diff --git a/iotronic_ui/iot/webservices/views.py b/iotronic_ui/iot/webservices/views.py new file mode 100644 index 0000000..0b84bcc --- /dev/null +++ b/iotronic_ui/iot/webservices/views.py @@ -0,0 +1,234 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse_lazy +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +# from horizon import messages +from horizon import tables +from horizon import tabs +from horizon.utils import memoized + +from openstack_dashboard.api import iotronic +from openstack_dashboard import policy + +from iotronic_ui.iot.webservices import forms as project_forms +from iotronic_ui.iot.webservices import tables as project_tables +from iotronic_ui.iot.webservices import tabs as project_tabs + + +LOG = logging.getLogger(__name__) + + +class IndexView(tables.DataTableView): + table_class = project_tables.WebservicesTable + template_name = 'iot/webservices/index.html' + page_title = _("Web Services") + + def get_data(self): + webservices = [] + en_webservices = [] + + # Admin + if policy.check((("iot", "iot:list_all_webservices"),), self.request): + try: + webservices = iotronic.webservice_list(self.request, + None) + en_webservices = iotronic.webservice_enabled_list(self.request) + + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve webservices list.')) + + # Admin_iot_project + elif policy.check((("iot", "iot:list_project_webservices"),), + self.request): + try: + webservices = iotronic.webservice_list(self.request, + None) + en_webservices = iotronic.webservice_enabled_list(self.request) + + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve webservices list.')) + + # Other users + else: + try: + webservices = iotronic.webservice_list(self.request, + None) + en_webservices = iotronic.webservice_enabled_list(self.request) + + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve webservices list.')) + + # Append some information to the webservice + # LOG.debug('WSS: %s', webservices) + for ws_en in en_webservices: + + ws_list = [] + + for ws in webservices: + if ws_en.board_uuid == ws.board_uuid: + + service_url = "https://" + ws.name + "." + ws_en.dns + "." + ws_en.zone + ws_list.append({"service_url": service_url}) + + ws_en.uuid = ws.uuid + + board = iotronic.board_get(self.request, ws_en.board_uuid, None) + ws_en.name = board.name + ws_en._info.update(dict(webservices=ws_list)) + + # LOG.debug('WS: %s', en_webservices) + return en_webservices + + +class ExposeView(forms.ModalFormView): + template_name = 'iot/webservices/expose.html' + modal_header = _("Expose Web Service") + form_id = "expose_webservice_form" + form_class = project_forms.ExposeWebserviceForm + submit_label = _("Expose") + submit_url = "horizon:iot:webservices:expose" + success_url = reverse_lazy('horizon:iot:webservices:index') + page_title = _("Expose Web Service") + + @memoized.memoized_method + def get_object(self): + try: + return iotronic.board_get(self.request, + self.kwargs['board_id'], + None) + except Exception: + redirect = reverse("horizon:iot:webservices:index") + exceptions.handle(self.request, + _('Unable to get webservice information.'), + redirect=redirect) + + def get_context_data(self, **kwargs): + context = super(ExposeView, self).get_context_data(**kwargs) + args = (self.get_object().uuid,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + board = self.get_object() + + return {'uuid': board.uuid, 'name': board.name} + + +class UnexposeView(forms.ModalFormView): + template_name = 'iot/webservices/unexpose.html' + modal_header = _("Unexpose Web Service") + form_id = "unexpose_webservice_form" + form_class = project_forms.UnexposeWebserviceForm + submit_label = _("Unexpose") + submit_url = "horizon:iot:webservices:unexpose" + success_url = reverse_lazy('horizon:iot:webservices:index') + page_title = _("Unexpose Web Service") + + @memoized.memoized_method + def get_object(self): + try: + return iotronic.board_get(self.request, + self.kwargs['board_id'], + None) + except Exception: + redirect = reverse("horizon:iot:webservices:index") + exceptions.handle(self.request, + _('Unable to get webservice information.'), + redirect=redirect) + + def get_context_data(self, **kwargs): + context = super(UnexposeView, self).get_context_data(**kwargs) + args = (self.get_object().uuid,) + context['submit_url'] = reverse(self.submit_url, args=args) + return context + + def get_initial(self): + board = self.get_object() + + # Populate web services on board + ws_onboard = iotronic.webservices_on_board(self.request, board.uuid) + ws_onboard.sort(key=lambda b: b["name"]) + + ws_onboard_list = [] + for ws in ws_onboard: + ws_onboard_list.append((ws["uuid"], _(ws["name"]))) + + return {'uuid': board.uuid, + 'name': board.name, + 'ws_onboard': ws_onboard_list} + + +""" +class DetailView(tabs.TabView): + tab_group_class = project_tabs.WebserviceDetailTabs + template_name = 'horizon/common/_detail.html' + page_title = "{{ webservice.name|default:webservice.uuid }}" + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + webservice = self.get_data() + context["webservice"] = webservice + context["url"] = reverse(self.redirect_url) + context["actions"] = self._get_actions(webservice) + + return context + + def _get_actions(self, webservice): + table = project_tables.WebservicesTable(self.request) + return table.render_row_actions(webservice) + + @memoized.memoized_method + def get_data(self): + webservice = [] + + webservice_id = self.kwargs['webservice_id'] + try: + webservice = iotronic.webservice_get(self.request, + webservice_id, + None) + board = iotronic.board_get(self.request, + webservice.board_uuid, + None) + + webservice._info.update({u'board_name': board.name}) + webservice.board_name = board.name + # LOG.debug('WS: %s', webservice) + + except Exception: + s = webservice.name + msg = ('Unable to retrieve webservice %s information') % {'name': s} + exceptions.handle(self.request, msg, ignore=True) + + return webservice + + def get_tabs(self, request, *args, **kwargs): + webservice = self.get_data() + return self.tab_group_class(request, webservice=webservice, **kwargs) + + +class WebserviceDetailView(DetailView): + redirect_url = 'horizon:iot:webservices:index' + + def _get_actions(self, webservice): + table = project_tables.WebservicesTable(self.request) + return table.render_row_actions(webservice) +"""