diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1539061 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.tox +.idea +iotronic_ui.egg-info +build +*.pyc +AUTHORS +Authors +ChangeLog diff --git a/iotronic_ui.egg-info/PKG-INFO b/iotronic_ui.egg-info/PKG-INFO deleted file mode 100644 index df40467..0000000 --- a/iotronic_ui.egg-info/PKG-INFO +++ /dev/null @@ -1,85 +0,0 @@ -Metadata-Version: 1.1 -Name: iotronic-ui -Version: 0.0.0 -Summary: Iotronic plugin for the OpenStack Dashboard -Home-page: http://www.openstack.org/ -Author: OpenStack -Author-email: openstack-dev@lists.openstack.org -License: UNKNOWN -Description: =============================== - IoTronic Panels - =============================== - - Iotronic plugin for the OpenStack Dashboard - - * Free software: Apache license - * Source: http://git.openstack.org/cgit/openstack/iotronic_ui - * Bugs: http://bugs.launchpad.net/None - - Features - -------- - - * TODO - - Enabling in DevStack - -------------------- - - Add this repo as an external repository into your ``local.conf`` file:: - - [[local|localrc]] - enable_plugin iotronic_ui https://github.com/openstack/iotronic_ui - - Manual Installation - ------------------- - - Begin by cloning the Horizon and IoTronic Panels repositories:: - - git clone https://github.com/openstack/horizon - git clone https://github.com/openstack/iotronic_ui - - Create a virtual environment and install Horizon dependencies:: - - cd horizon - python tools/install_venv.py - - Set up your ``local_settings.py`` file:: - - cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py - - Open up the copied ``local_settings.py`` file in your preferred text - editor. You will want to customize several settings: - - - ``OPENSTACK_HOST`` should be configured with the hostname of your - OpenStack server. Verify that the ``OPENSTACK_KEYSTONE_URL`` and - ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your - environment. (They should be correct unless you modified your - OpenStack server to change them.) - - Install IoTronic Panels with all dependencies in your virtual environment:: - - tools/with_venv.sh pip install -e ../iotronic_ui/ - - And enable it in Horizon:: - - ln -s ../iotronic_ui/iotronic_ui/enabled/_90_project_iot_panelgroup.py openstack_dashboard/local/enabled - ln -s ../iotronic_ui/iotronic_ui/enabled/_91_project_iot_boardss_panel.py openstack_dashboard/local/enabled - - To run horizon with the newly enabled IoTronic Panels plugin run:: - - ./run_tests.sh --runserver 0.0.0.0:8080 - - to have the application start on port 8080 and the horizon dashboard will be - available in your browser at http://localhost:8080/ - - -Platform: UNKNOWN -Classifier: Environment :: OpenStack -Classifier: Intended Audience :: Information Technology -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: Apache Software License -Classifier: Operating System :: POSIX :: Linux -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.5 diff --git a/iotronic_ui.egg-info/SOURCES.txt b/iotronic_ui.egg-info/SOURCES.txt deleted file mode 100644 index 1e94740..0000000 --- a/iotronic_ui.egg-info/SOURCES.txt +++ /dev/null @@ -1,88 +0,0 @@ -CONTRIBUTING.rst -HACKING.rst -LICENSE -MANIFEST.in -README.rst -babel-django.cfg -babel-djangojs.cfg -manage.py -package.json -requirements.txt -setup.cfg -setup.py -test-requirements.txt -test-shim.js -tox.ini -doc/Makefile -doc/source/conf.py -doc/source/index.rst -doc/source/configuration/index.rst -doc/source/contributor/api.rst -doc/source/contributor/index.rst -doc/source/install/index.rst -iotronic_ui/__init__.py -iotronic_ui.egg-info/PKG-INFO -iotronic_ui.egg-info/SOURCES.txt -iotronic_ui.egg-info/dependency_links.txt -iotronic_ui.egg-info/not-zip-safe -iotronic_ui.egg-info/pbr.json -iotronic_ui.egg-info/requires.txt -iotronic_ui.egg-info/top_level.txt -iotronic_ui/api/iotronic.py -iotronic_ui/enabled/_6000_iot.py -iotronic_ui/enabled/_6010_iot_boards_panel.py -iotronic_ui/enabled/_6020_iot_plugins_panel.py -iotronic_ui/iot/__init__.py -iotronic_ui/iot/dashboard.py -iotronic_ui/iot/boards/__init__.py -iotronic_ui/iot/boards/forms.py -iotronic_ui/iot/boards/panel.py -iotronic_ui/iot/boards/tables.py -iotronic_ui/iot/boards/tabs.py -iotronic_ui/iot/boards/tests.py -iotronic_ui/iot/boards/urls.py -iotronic_ui/iot/boards/views.py -iotronic_ui/iot/boards/templates/boards/_create.html -iotronic_ui/iot/boards/templates/boards/_detail_overview.html -iotronic_ui/iot/boards/templates/boards/_removeplugins.html -iotronic_ui/iot/boards/templates/boards/_update.html -iotronic_ui/iot/boards/templates/boards/create.html -iotronic_ui/iot/boards/templates/boards/index.html -iotronic_ui/iot/boards/templates/boards/removeplugins.html -iotronic_ui/iot/boards/templates/boards/update.html -iotronic_ui/iot/plugins/__init__.py -iotronic_ui/iot/plugins/forms.py -iotronic_ui/iot/plugins/panel.py -iotronic_ui/iot/plugins/tables.py -iotronic_ui/iot/plugins/tabs.py -iotronic_ui/iot/plugins/tests.py -iotronic_ui/iot/plugins/urls.py -iotronic_ui/iot/plugins/views.py -iotronic_ui/iot/plugins/templates/plugins/_call.html -iotronic_ui/iot/plugins/templates/plugins/_create.html -iotronic_ui/iot/plugins/templates/plugins/_detail_overview.html -iotronic_ui/iot/plugins/templates/plugins/_inject.html -iotronic_ui/iot/plugins/templates/plugins/_remove.html -iotronic_ui/iot/plugins/templates/plugins/_start.html -iotronic_ui/iot/plugins/templates/plugins/_stop.html -iotronic_ui/iot/plugins/templates/plugins/_update.html -iotronic_ui/iot/plugins/templates/plugins/call.html -iotronic_ui/iot/plugins/templates/plugins/create.html -iotronic_ui/iot/plugins/templates/plugins/index.html -iotronic_ui/iot/plugins/templates/plugins/inject.html -iotronic_ui/iot/plugins/templates/plugins/remove.html -iotronic_ui/iot/plugins/templates/plugins/start.html -iotronic_ui/iot/plugins/templates/plugins/stop.html -iotronic_ui/iot/plugins/templates/plugins/update.html -iotronic_ui/iot/static/iot/images/blue-circle.png -iotronic_ui/iot/static/iot/images/green-circle.png -iotronic_ui/iot/static/iot/images/marker-icon-green.png -iotronic_ui/iot/static/iot/images/marker-icon-red.png -iotronic_ui/iot/static/iot/images/marker-icon.png -iotronic_ui/iot/static/iot/images/marker-shadow.png -iotronic_ui/iot/static/iot/images/red-circle.png -iotronic_ui/iot/static/iot/js/iot.js -iotronic_ui/iot/static/iot/scss/iot.scss -iotronic_ui/iot/templates/iot/base.html -tools/tox_install.sh -tools/tox_install.sh_ORIG \ No newline at end of file diff --git a/iotronic_ui.egg-info/dependency_links.txt b/iotronic_ui.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/iotronic_ui.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/iotronic_ui.egg-info/not-zip-safe b/iotronic_ui.egg-info/not-zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/iotronic_ui.egg-info/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/iotronic_ui.egg-info/pbr.json b/iotronic_ui.egg-info/pbr.json deleted file mode 100644 index 34d2e6e..0000000 --- a/iotronic_ui.egg-info/pbr.json +++ /dev/null @@ -1 +0,0 @@ -{"git_version": "4902c1d", "is_release": false} \ No newline at end of file diff --git a/iotronic_ui.egg-info/requires.txt b/iotronic_ui.egg-info/requires.txt deleted file mode 100644 index 1725ef9..0000000 --- a/iotronic_ui.egg-info/requires.txt +++ /dev/null @@ -1,6 +0,0 @@ -pbr!=2.1.0,>=2.0.0 -Babel!=2.4.0,>=2.3.4 -Django<2.0,>=1.8 -django-babel>=0.5.1 -django-compressor>=2.0 -django-pyscss>=2.0.2 diff --git a/iotronic_ui.egg-info/top_level.txt b/iotronic_ui.egg-info/top_level.txt deleted file mode 100644 index 7d4fe56..0000000 --- a/iotronic_ui.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -iotronic_ui diff --git a/iotronic_ui/api/iotronic.py b/iotronic_ui/api/iotronic.py index cf2c825..8957f5f 100644 --- a/iotronic_ui/api/iotronic.py +++ b/iotronic_ui/api/iotronic.py @@ -43,14 +43,12 @@ def iotronicclient(request): # BOARD MANAGEMENT def board_list(request, status=None, detail=None, project=None): """List boards.""" - boards = iotronicclient(request).board.list(status, detail, project) - return boards + return iotronicclient(request).board.list(status, detail, project) def board_get(request, board_id, fields): """Get board info.""" - board = iotronicclient(request).board.get(board_id, fields) - return board + return iotronicclient(request).board.get(board_id, fields) def board_create(request, code, mobile, location, type, name): @@ -60,30 +58,26 @@ def board_create(request, code, mobile, location, type, name): "location": location, "type": type, "name": name} - board = iotronicclient(request).board.create(**params) - return board + iotronicclient(request).board.create(**params) def board_update(request, board_id, patch): """Update board.""" - board = iotronicclient(request).board.update(board_id, patch) - return board + iotronicclient(request).board.update(board_id, patch) def board_delete(request, board_id): """Delete board.""" - board = iotronicclient(request).board.delete(board_id) - return board + iotronicclient(request).board.delete(board_id) # PLUGIN MANAGEMENT (Cloud Side) def plugin_list(request, detail=None, project=None, with_public=False, all_plugins=False): """List plugins.""" - plugins = iotronicclient(request).plugin.list(detail, project, \ - with_public=with_public, \ - all_plugins=all_plugins) - return plugins + return iotronicclient(request).plugin.list(detail, project, + with_public=with_public, + all_plugins=all_plugins) def plugin_get(request, plugin_id, fields): @@ -99,53 +93,43 @@ def plugin_create(request, name, public, callable, code, parameters): "callable": callable, "code": code, "parameters": parameters} - plugin = iotronicclient(request).plugin.create(**params) - return plugin + iotronicclient(request).plugin.create(**params) def plugin_update(request, plugin_id, patch): """Update plugin.""" - plugin = iotronicclient(request).plugin.update(plugin_id, patch) - return plugin + iotronicclient(request).plugin.update(plugin_id, patch) def plugin_delete(request, plugin_id): """Delete plugin.""" - plugin = iotronicclient(request).plugin.delete(plugin_id) - return plugin + return iotronicclient(request).plugin.delete(plugin_id) # PLUGIN MANAGEMENT (Board Side) def plugin_inject(request, board_id, plugin_id, onboot): """Inject plugin on board(s).""" - plugin = iotronicclient(request).plugin_injection. \ - plugin_inject(board_id, \ - plugin_id, \ - onboot) - return plugin + return iotronicclient(request).plugin_injection.plugin_inject(board_id, + plugin_id, + onboot) def plugin_action(request, board_id, plugin_id, action, params={}): """Start/Stop/Call actions on board(s).""" - plugin = iotronicclient(request).plugin_injection. \ - plugin_action(board_id, - plugin_id, - action, - params) - return plugin + return iotronicclient(request).plugin_injection.plugin_action( + board_id, plugin_id, action, params) def plugin_remove(request, board_id, plugin_id): - """Inject plugin on board(s).""" - plugin = iotronicclient(request).plugin_injection. \ - plugin_remove(board_id, plugin_id) - return plugin + """Remove plugin from board.""" + iotronicclient(request).plugin_injection.plugin_remove(board_id, + plugin_id) def plugins_on_board(request, board_id): """Plugins on board.""" - plugins = iotronicclient(request).plugin_injection. \ - plugins_on_board(board_id) + plugins = iotronicclient(request).plugin_injection.plugins_on_board( + board_id) detailed_plugins = [] # fields = {"name", "public", "callable"} @@ -161,14 +145,12 @@ def plugins_on_board(request, board_id): # SERVICE MANAGEMENT def service_list(request, detail=None): """List services.""" - services = iotronicclient(request).service.list(detail) - return services + return iotronicclient(request).service.list(detail) def service_get(request, service_id, fields): """Get service info.""" - service = iotronicclient(request).service.get(service_id, fields) - return service + return iotronicclient(request).service.get(service_id, fields) def service_create(request, name, port, protocol): @@ -176,36 +158,34 @@ def service_create(request, name, port, protocol): params = {"name": name, "port": port, "protocol": protocol} - service = iotronicclient(request).service.create(**params) - return service + iotronicclient(request).service.create(**params) def service_update(request, service_id, patch): """Update service.""" - service = iotronicclient(request).service.update(service_id, patch) - return service + iotronicclient(request).service.update(service_id, patch) def service_delete(request, service_id): """Delete service.""" - service = iotronicclient(request).service.delete(service_id) - return service + iotronicclient(request).service.delete(service_id) def services_on_board(request, board_id, detail=False): """List services on board.""" - services = iotronicclient(request).exposed_service \ - .services_on_board(board_id) + services = iotronicclient(request).exposed_service.services_on_board( + board_id) if detail: detailed_services = [] fields = {"name", "port", "protocol"} for service in services: - details = iotronicclient(request). \ - service.get(service._info["service"], fields) + details = iotronicclient(request).service.get( + service._info["service"], fields) - detailed_services.append({"name": details._info["name"], + detailed_services.append({"uuid": service._info["service"], + "name": details._info["name"], "public_port": service._info["public_port"], "port": details._info["port"], @@ -219,14 +199,29 @@ def services_on_board(request, board_id, detail=False): def service_action(request, board_id, service_id, action): """Action on service.""" - service_action = iotronicclient(request).exposed_service. \ - service_action(board_id, service_id, action) - return service_action + return iotronicclient(request).exposed_service.service_action(board_id, + service_id, + action) def restore_services(request, board_id): """Restore services.""" - service_restore = iotronicclient(request).exposed_service. \ - restore_services(board_id) - return service_restore + return iotronicclient(request).exposed_service.restore_services(board_id) + +# PORTS MANAGEMENT +def port_list(request, board_id): + """Get ports attached to a board.""" + return iotronicclient(request).port.list() + + +def attach_port(request, board_id, network_id, subnet_id): + """Attach port to a subnet for a board.""" + return iotronicclient(request).portonboard.attach_port(board_id, + network_id, + subnet_id) + + +def detach_port(request, board_id, port_id): + """Detach port from the board.""" + iotronicclient(request).portonboard.detach_port(board_id, port_id) diff --git a/iotronic_ui/iot/boards/forms.py b/iotronic_ui/iot/boards/forms.py index 8e4ba45..e128360 100644 --- a/iotronic_ui/iot/boards/forms.py +++ b/iotronic_ui/iot/boards/forms.py @@ -67,12 +67,13 @@ class CreateBoardForm(forms.SelfHandlingForm): "longitude": str(data["longitude"]), "altitude": str(data["altitude"])}] - board = iotronic.board_create(request, data["code"], - data["mobile"], data["location"], - data["type"], data["name"]) - messages.success(request, _("Board created successfully.")) + iotronic.board_create(request, data["code"], + data["mobile"], data["location"], + data["type"], data["name"]) + + messages.success(request, _("Board created successfully.")) + return True - return board except Exception: exceptions.handle(request, _('Unable to create board.')) @@ -82,49 +83,54 @@ class UpdateBoardForm(forms.SelfHandlingForm): name = forms.CharField(label=_("Board Name")) mobile = forms.BooleanField(label=_("Mobile"), required=False) + """ latitude = forms.FloatField(label=_("Latitude")) longitude = forms.FloatField(label=_("Longitude")) altitude = forms.FloatField(label=_("Altitude")) + """ def __init__(self, *args, **kwargs): super(UpdateBoardForm, self).__init__(*args, **kwargs) - # LOG.debug("MELO INITIAL: %s", kwargs["initial"]) + # LOG.debug("INITIAL: %s", kwargs["initial"]) - LOG.debug("MELO Manager: %s", policy.check((("iot", "iot_manager"),), - self.request)) - LOG.debug("MELO Admin: %s", policy.check((("iot", "iot_admin"),), - self.request)) + # LOG.debug("Manager: %s", policy.check((("iot", "iot_manager"),), + # self.request)) + # LOG.debug("Admin: %s", policy.check((("iot", "iot_admin"),), + # self.request)) # Admin if policy.check((("iot", "iot:update_boards"),), self.request): - # LOG.debug("MELO ADMIN") + # LOG.debug("ADMIN") pass # Manager or Admin of the iot project elif (policy.check((("iot", "iot_manager"),), self.request) or policy.check((("iot", "iot_admin"),), self.request)): - # LOG.debug("MELO NO-edit IOT ADMIN") + # LOG.debug("NO-edit IOT ADMIN") pass # Other users else: if self.request.user.id != kwargs["initial"]["owner"]: - # LOG.debug("MELO IMMUTABLE FIELDS") + # LOG.debug("IMMUTABLE FIELDS") self.fields["name"].widget.attrs = {'readonly': 'readonly'} self.fields["mobile"].widget.attrs = {'disabled': 'disabled'} + """ self.fields["latitude"].widget.attrs = {'readonly': 'readonly'} self.fields["longitude"].widget.attrs = {'readonly': 'readonly'} self.fields["altitude"].widget.attrs = {'readonly': 'readonly'} + """ def handle(self, request, data): try: + """ data["location"] = [{"latitude": str(data["latitude"]), "longitude": str(data["longitude"]), "altitude": str(data["altitude"])}] @@ -132,13 +138,196 @@ class UpdateBoardForm(forms.SelfHandlingForm): {"name": data["name"], "mobile": data["mobile"], "location": data["location"]}) - + """ + iotronic.board_update(request, data["uuid"], + {"name": data["name"], + "mobile": data["mobile"]}) messages.success(request, _("Board updated successfully.")) return True + except Exception: exceptions.handle(request, _('Unable to update board.')) +class EnableServiceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + service_list = forms.MultipleChoiceField( + label=_("Services List"), + widget=forms.SelectMultiple( + attrs={'class': 'switchable', + 'data-slug': 'slug-select-services'}), + help_text=_("Add available services from this pool") + ) + + def __init__(self, *args, **kwargs): + super(EnableServiceForm, self).__init__(*args, **kwargs) + self.fields["service_list"].choices = kwargs["initial"]["service_list"] + + def handle(self, request, data): + + counter = 0 + for service in data["service_list"]: + try: + action = iotronic.service_action(request, data["uuid"], + service, "ServiceEnable") + + # message_text = "Service(s) enabled successfully." + message_text = action + messages.success(request, _(message_text)) + + if counter != len(data["service_list"]) - 1: + counter += 1 + else: + return True + + except Exception: + message_text = "Unable to enable service." + exceptions.handle(request, _(message_text)) + + +class DisableServiceForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + service_list = forms.MultipleChoiceField( + label=_("Services List"), + widget=forms.SelectMultiple( + attrs={'class': 'switchable', + 'data-slug': 'slug-select-services'}), + help_text=_("Select services to disable from this pool") + ) + + def __init__(self, *args, **kwargs): + super(DisableServiceForm, self).__init__(*args, **kwargs) + self.fields["service_list"].choices = kwargs["initial"]["service_list"] + + def handle(self, request, data): + + counter = 0 + for service in data["service_list"]: + try: + action = iotronic.service_action(request, data["uuid"], + service, "ServiceDisable") + + # message_text = "Service(s) disabled successfully." + message_text = action + messages.success(request, _(message_text)) + + if counter != len(data["service_list"]) - 1: + counter += 1 + else: + return True + + except Exception: + message_text = "Unable to disable service." + exceptions.handle(request, _(message_text)) + + +class AttachPortForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + networks_list = forms.ChoiceField( + label=_("Networks List"), + help_text=_("Select network:subnet from the list") + ) + + def __init__(self, *args, **kwargs): + + super(AttachPortForm, self).__init__(*args, **kwargs) + + net_choices = kwargs["initial"]["networks_list"] + self.fields["networks_list"].choices = net_choices + + def handle(self, request, data): + array = data["networks_list"].split(':') + LOG.debug(array) + network_id = array[0] + subnet_id = array[1] + + try: + attach = iotronic.attach_port(request, data["uuid"], + network_id, subnet_id) + + # LOG.debug("ATTACH: %s", attach) + ip = attach._info["ip"] + + message_text = "Attached port to ip " + str(ip) + \ + " on board " + str(data["name"]) + \ + " completed successfully" + messages.success(request, _(message_text)) + return True + + except Exception: + message_text = "Unable to attach port on board " + \ + str(data["name"]) + + exceptions.handle(request, _(message_text)) + + +class DetachPortForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + port_list = forms.MultipleChoiceField( + label=_("Ports List"), + widget=forms.SelectMultiple( + attrs={'class': 'switchable', 'data-slug': 'slug-detacj-ports'}), + help_text=_("Select one or more of the following attached ports") + ) + + def __init__(self, *args, **kwargs): + + super(DetachPortForm, self).__init__(*args, **kwargs) + self.fields["port_list"].choices = kwargs["initial"]["ports"] + + def handle(self, request, data): + # LOG.debug("DATA: %s %s", data, len(data["port_list"])) + + counter = 0 + + for port in data["port_list"]: + try: + iotronic.detach_port(request, data["uuid"], port) + + message_text = "Detach port " + str(port) + " from board " + \ + str(data["name"]) + " completed successfully" + messages.success(request, _(message_text)) + + if counter != len(data["port_list"]) - 1: + counter += 1 + else: + return True + + except Exception: + message_text = "Unable to detach port " + str(port) + \ + " from board " + str(data["name"]) + + exceptions.handle(request, _(message_text)) + + class RemovePluginsForm(forms.SelfHandlingForm): uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) @@ -159,11 +348,7 @@ class RemovePluginsForm(forms.SelfHandlingForm): super(RemovePluginsForm, self).__init__(*args, **kwargs) # input=kwargs.get('initial',{}) - - boardslist_length = len(kwargs["initial"]["board_list"]) - self.fields["plugin_list"].choices = kwargs["initial"]["plugin_list"] - self.fields["plugin_list"].max_length = boardslist_length def handle(self, request, data): @@ -174,13 +359,8 @@ class RemovePluginsForm(forms.SelfHandlingForm): if key == plugin: try: - board = None + iotronic.plugin_remove(request, data["uuid"], key) - # LOG.debug('INJECT: %s %s', plugin, value) - # board = iotronic.plugin_create(request, data["name"], - # data["public"], - # data["callable"], - # data["code"]) message_text = "Plugin " + str(value) + \ " removed successfully." messages.success(request, _(message_text)) @@ -188,10 +368,64 @@ class RemovePluginsForm(forms.SelfHandlingForm): if counter != len(data["plugin_list"]) - 1: counter += 1 else: - return board + return True + except Exception: message_text = "Unable to remove plugin " \ + str(value) + "." exceptions.handle(request, _(message_text)) break + + +class RemoveServicesForm(forms.SelfHandlingForm): + + uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput) + + name = forms.CharField( + label=_('Board Name'), + widget=forms.TextInput(attrs={'readonly': 'readonly'}) + ) + + service_list = forms.MultipleChoiceField( + label=_("Services List"), + widget=forms.SelectMultiple( + attrs={'class': 'switchable', + 'data-slug': 'slug-remove-services'}), + help_text=_("Select services in this pool") + ) + + def __init__(self, *args, **kwargs): + + super(RemoveServicesForm, self).__init__(*args, **kwargs) + # input=kwargs.get('initial',{}) + self.fields["service_list"].choices = kwargs["initial"]["service_list"] + + def handle(self, request, data): + + counter = 0 + + for service in data["service_list"]: + for key, value in self.fields["service_list"].choices: + if key == service: + + try: + disable = iotronic.service_action(request, + data["uuid"], + key, + "ServiceDisable") + + message_text = disable + messages.success(request, _(message_text)) + + if counter != len(data["service_list"]) - 1: + counter += 1 + else: + return True + + except Exception: + message_text = "Unable to disable service " \ + + str(value) + "." + exceptions.handle(request, _(message_text)) + + break diff --git a/iotronic_ui/iot/boards/panel.py b/iotronic_ui/iot/boards/panel.py index beb3ef9..fd23096 100644 --- a/iotronic_ui/iot/boards/panel.py +++ b/iotronic_ui/iot/boards/panel.py @@ -15,6 +15,7 @@ from django.utils.translation import ugettext_lazy as _ import horizon # from openstack_dashboard.api import keystone +from iotronic_ui.iot import dashboard class Boards(horizon.Panel): @@ -31,3 +32,6 @@ class Boards(horizon.Panel): return False return super(Roles, self).can_access(context) """ + + +dashboard.Iot.register(Boards) diff --git a/iotronic_ui/iot/boards/tables.py b/iotronic_ui/iot/boards/tables.py index c944caf..afee155 100644 --- a/iotronic_ui/iot/boards/tables.py +++ b/iotronic_ui/iot/boards/tables.py @@ -64,13 +64,56 @@ class RestoreServices(tables.BatchAction): api.iotronic.restore_services(request, board_id) +class EnableServiceLink(tables.LinkAction): + name = "enableservice" + verbose_name = _("Enable Service(s)") + url = "horizon:iot:boards:enableservice" + classes = ("ajax-modal",) + # icon = "plus" + # policy_rules = (("iot", "iot:service_action"),) + + +class DisableServiceLink(tables.LinkAction): + name = "disableservice" + verbose_name = _("Disable Service(s)") + url = "horizon:iot:boards:disableservice" + classes = ("ajax-modal",) + # icon = "plus" + # policy_rules = (("iot", "iot:service_action"),) + + class RemovePluginsLink(tables.LinkAction): name = "removeplugins" verbose_name = _("Remove Plugin(s)") url = "horizon:iot:boards:removeplugins" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:remove_plugins"),) + + +class RemoveServicesLink(tables.LinkAction): + name = "removeservices" + verbose_name = _("Remove Service(s)") + url = "horizon:iot:boards:removeservices" + classes = ("ajax-modal",) + icon = "plus" + # policy_rules = (("iot", "iot:remove_services"),) + + +class AttachPortLink(tables.LinkAction): + name = "attachport" + verbose_name = _("Attach Port") + url = "horizon:iot:boards:attachport" + classes = ("ajax-modal",) + icon = "plus" + + +class DetachPortLink(tables.LinkAction): + name = "detachport" + verbose_name = _("Detach Port") + url = "horizon:iot:boards:detachport" + classes = ("ajax-modal",) + icon = "plus" class DeleteBoardsAction(tables.DeleteAction): @@ -117,6 +160,7 @@ class BoardFilterAction(tables.FilterAction): return [board for board in boards if q in board.name.lower()] + def show_services(board_info): template_name = 'iot/boards/_cell_services.html' context = board_info._info @@ -145,7 +189,9 @@ class BoardsTable(tables.DataTable): class Meta(object): name = "boards" verbose_name = _("boards") - row_actions = (EditBoardLink, RestoreServices, - RemovePluginsLink, DeleteBoardsAction) - table_actions = (BoardFilterAction, CreateBoardLink, - RestoreServices, DeleteBoardsAction) + row_actions = (EditBoardLink, EnableServiceLink, DisableServiceLink, + RestoreServices, AttachPortLink, DetachPortLink, + RemovePluginsLink, RemoveServicesLink, + DeleteBoardsAction) + table_actions = (BoardFilterAction, CreateBoardLink, + DeleteBoardsAction) diff --git a/iotronic_ui/iot/boards/tabs.py b/iotronic_ui/iot/boards/tabs.py index 07a5528..4bdef2b 100644 --- a/iotronic_ui/iot/boards/tabs.py +++ b/iotronic_ui/iot/boards/tabs.py @@ -21,7 +21,7 @@ LOG = logging.getLogger(__name__) """ import inspect -LOG.debug('MELO CLASSES: %s', +LOG.debug('CLASSES: %s', inspect.getmembers(tabs, predicate=inspect.isclass)) """ @@ -34,12 +34,14 @@ class OverviewTab(tabs.Tab): def get_context_data(self, request): 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'] plugins = self.tab_group.kwargs['board']._info['plugins'] return {"board": self.tab_group.kwargs['board'], "coordinates": coordinates, "services": services, + "ports": ports, "plugins": plugins, "is_superuser": request.user.is_superuser} diff --git a/iotronic_ui/iot/boards/templates/boards/_attachport.html b/iotronic_ui/iot/boards/templates/boards/_attachport.html new file mode 100644 index 0000000..0fc9d03 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/_attachport.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "Attach port to the selected board." %}

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

{% trans "Description:" %}

+

{% trans "Detach one or more attached ports from the board." %}

+{% endblock %} + diff --git a/iotronic_ui/iot/boards/templates/boards/_detail_overview.html b/iotronic_ui/iot/boards/templates/boards/_detail_overview.html index 60afed2..f7e8e27 100644 --- a/iotronic_ui/iot/boards/templates/boards/_detail_overview.html +++ b/iotronic_ui/iot/boards/templates/boards/_detail_overview.html @@ -22,26 +22,50 @@
{{ board.mobile }}
{% trans "Extra" %}
{{ board.extra }}
-
{% trans "Services" %}
- {% if services %} + + +

{% trans "Ports" %}

+
+
+ {% if ports %} + {% for port in ports %} +
{{ port.VIF_name }}
+
{{ port.ip }}
+ {% endfor %} + {% else %} +
--
+ {% endif %} +
+ +

{% trans "Services" %}

+
+
+ {% if services %} {% for service in services %} -
{{ service.name }} [{{ service.protocol }}] {{ service.port }} --> {{ service.public_port }}
+
{{ service.name }} [{{ service.protocol }}] {{ service.port }}
+
{{ service.public_port }}
{% endfor %} - {% else %} + {% else %}
--
- {% endif %} -
{% trans "Plugins" %}
- {% if plugins %} - {% for plugin in plugins %} -
{{ plugin.name }}
- {% endfor %} - {% else %} -
--
- {% endif %} + {% endif %} +
+ +

{% trans "Plugins" %}

+
+
+ {% if plugins %} + {% for plugin in plugins %} +
{{ plugin.name }}
+
{{ plugin.id }}
+ {% endfor %} + {% else %} +
--
+ {% endif %}
+ diff --git a/iotronic_ui/iot/boards/templates/boards/_disableservice.html b/iotronic_ui/iot/boards/templates/boards/_disableservice.html new file mode 100644 index 0000000..21138ce --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/_disableservice.html @@ -0,0 +1,8 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

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

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

{% trans "Description:" %}

+

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

+{% endblock %} + diff --git a/iotronic_ui/iot/services/templates/services/_remove.html b/iotronic_ui/iot/boards/templates/boards/_removeservices.html similarity index 100% rename from iotronic_ui/iot/services/templates/services/_remove.html rename to iotronic_ui/iot/boards/templates/boards/_removeservices.html diff --git a/iotronic_ui/iot/boards/templates/boards/attachport.html b/iotronic_ui/iot/boards/templates/boards/attachport.html new file mode 100644 index 0000000..72b3c94 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/attachport.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Attach" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_attachport.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/boards/templates/boards/detachport.html b/iotronic_ui/iot/boards/templates/boards/detachport.html new file mode 100644 index 0000000..aa2e4a1 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/detachport.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Detach" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_detachport.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/boards/templates/boards/disableservice.html b/iotronic_ui/iot/boards/templates/boards/disableservice.html new file mode 100644 index 0000000..4280e56 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/disableservice.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Disable" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_disableservice.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/boards/templates/boards/enableservice.html b/iotronic_ui/iot/boards/templates/boards/enableservice.html new file mode 100644 index 0000000..968caf4 --- /dev/null +++ b/iotronic_ui/iot/boards/templates/boards/enableservice.html @@ -0,0 +1,7 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Enable" %}{% endblock %} + +{% block main %} + {% include 'iot/boards/_enableservice.html' %} +{% endblock %} diff --git a/iotronic_ui/iot/services/templates/services/remove.html b/iotronic_ui/iot/boards/templates/boards/removeservices.html similarity index 72% rename from iotronic_ui/iot/services/templates/services/remove.html rename to iotronic_ui/iot/boards/templates/boards/removeservices.html index d1addca..0c2f1a1 100644 --- a/iotronic_ui/iot/services/templates/services/remove.html +++ b/iotronic_ui/iot/boards/templates/boards/removeservices.html @@ -3,5 +3,5 @@ {% block title %}{% trans "Remove service(s)." %}{% endblock %} {% block main %} - {% include 'iot/services/_remove.html' %} + {% include 'iot/boards/_removeservices.html' %} {% endblock %} diff --git a/iotronic_ui/iot/boards/urls.py b/iotronic_ui/iot/boards/urls.py index 7349a04..0348d95 100644 --- a/iotronic_ui/iot/boards/urls.py +++ b/iotronic_ui/iot/boards/urls.py @@ -22,6 +22,16 @@ urlpatterns = [ name='update'), url(r'^(?P[^/]+)/removeplugins/$', views.RemovePluginsView.as_view(), name='removeplugins'), + url(r'^(?P[^/]+)/removeservices/$', + 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[^/]+)/attachport/$', + views.AttachPortView.as_view(), name='attachport'), + url(r'^(?P[^/]+)/detachport/$', + views.DetachPortView.as_view(), name='detachport'), url(r'^(?P[^/]+)/detail/$', views.BoardDetailView.as_view(), name='detail'), ] diff --git a/iotronic_ui/iot/boards/views.py b/iotronic_ui/iot/boards/views.py index df8e3af..de6a6bf 100644 --- a/iotronic_ui/iot/boards/views.py +++ b/iotronic_ui/iot/boards/views.py @@ -23,7 +23,8 @@ from horizon import tables from horizon import tabs from horizon.utils import memoized -from openstack_dashboard.api import iotronic +# from openstack_dashboard.api import iotronic +from openstack_dashboard import api from openstack_dashboard import policy from iotronic_ui.iot.boards import forms as project_forms @@ -42,25 +43,10 @@ class IndexView(tables.DataTableView): def get_data(self): boards = [] - # FROM - """ - if policy.check((("identity", "identity:list_roles"),), self.request): - try: - boards = iotronic.board_list(self.request, None, None) - # LOG.debug('IOT BOARDS: %s', boards) - except Exception: - exceptions.handle(self.request, - _('Unable to retrieve boards list.')) - else: - msg = _("Insufficient privilege level to view boards information.") - messages.info(self.request, msg) - """ - - # TO # Admin if policy.check((("iot", "iot:list_all_boards"),), self.request): try: - boards = iotronic.board_list(self.request, None, None) + boards = api.iotronic.board_list(self.request, None, None) except Exception: exceptions.handle(self.request, @@ -69,7 +55,7 @@ class IndexView(tables.DataTableView): # Admin_iot_project elif policy.check((("iot", "iot:list_project_boards"),), self.request): try: - boards = iotronic.board_list(self.request, None, None) + boards = api.iotronic.board_list(self.request, None, None) except Exception: exceptions.handle(self.request, @@ -78,14 +64,16 @@ class IndexView(tables.DataTableView): # Other users else: try: - boards = iotronic.board_list(self.request, None, None) + boards = api.iotronic.board_list(self.request, None, None) except Exception: exceptions.handle(self.request, _('Unable to retrieve user boards list.')) for board in boards: - board_services = iotronic.services_on_board(self.request, board.uuid, True) + board_services = api.iotronic.services_on_board(self.request, + board.uuid, + True) # board.__dict__.update(dict(services=board_services)) board._info.update(dict(services=board_services)) @@ -116,8 +104,9 @@ class UpdateView(forms.ModalFormView): @memoized.memoized_method def get_object(self): try: - return iotronic.board_get(self.request, self.kwargs['board_id'], - None) + return api.iotronic.board_get(self.request, + self.kwargs['board_id'], + None) except Exception: redirect = reverse("horizon:iot:boards:index") exceptions.handle(self.request, @@ -143,12 +132,226 @@ class UpdateView(forms.ModalFormView): 'altitude': location["altitude"]} +class EnableServiceView(forms.ModalFormView): + template_name = 'iot/boards/enableservice.html' + modal_header = _("Enable Service(s)") + form_id = "service_enable_form" + form_class = project_forms.EnableServiceForm + submit_label = _("Enable") + # submit_url = reverse_lazy("horizon:iot:boards:enableservice") + submit_url = "horizon:iot:boards:enableservice" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Action") + + @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(EnableServiceView, 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 available services + cloud_services = api.iotronic.service_list(self.request, None) + board_services = api.iotronic.services_on_board(self.request, + board.uuid, + True) + + service_list = [] + + for cloud_service in cloud_services: + + if len(board_services) == 0: + service_list.append((cloud_service._info["uuid"], + _(cloud_service._info["name"]))) + else: + counter = 0 + for board_service in board_services: + if board_service["uuid"] == cloud_service._info["uuid"]: + break + elif counter != len(board_services) - 1: + counter += 1 + else: + service_list.append((cloud_service._info["uuid"], + _(cloud_service._info["name"]))) + + return {'uuid': board.uuid, + 'name': board.name, + 'service_list': service_list} + + +class DisableServiceView(forms.ModalFormView): + template_name = 'iot/boards/disableservice.html' + modal_header = _("Disable Service(s)") + form_id = "service_disable_form" + form_class = project_forms.DisableServiceForm + submit_label = _("Disable") + # submit_url = reverse_lazy("horizon:iot:boards:disableservice") + submit_url = "horizon:iot:boards:disableservice" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Action") + + @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(DisableServiceView, 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 available services + cloud_services = api.iotronic.service_list(self.request, None) + board_services = api.iotronic.services_on_board(self.request, + board.uuid, + True) + + service_list = [] + + 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"]))) + + return {'uuid': board.uuid, + 'name': board.name, + 'service_list': service_list} + + +class AttachPortView(forms.ModalFormView): + template_name = 'iot/boards/attachport.html' + modal_header = _("Attach") + form_id = "attach_boardport_form" + form_class = project_forms.AttachPortForm + submit_label = _("Attach") + # submit_url = reverse_lazy("horizon:iot:boards:attachport") + submit_url = "horizon:iot:boards:attachport" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Attach port") + + @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(AttachPortView, 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 networks + networks = api.neutron.network_list(self.request) + net_choices = [] + + for net in networks: + for subnet in net["subnets"]: + net_choices.append((net["id"] + ':' + subnet["id"], + _(net["name"] + ':' + subnet["name"]))) + + return {'uuid': board.uuid, + 'name': board.name, + 'networks_list': net_choices} + + +class DetachPortView(forms.ModalFormView): + template_name = 'iot/boards/detachport.html' + modal_header = _("Detach") + form_id = "detach_boardport_form" + form_class = project_forms.DetachPortForm + submit_label = _("Detach") + # submit_url = reverse_lazy("horizon:iot:boards:detachport") + submit_url = "horizon:iot:boards:detachport" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Detach port") + + @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(DetachPortView, 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() + + ports = api.iotronic.port_list(self.request, board.uuid) + + # TO BE REMOVED (change it once the port_list per board is + # completed and tested ! + # ################################################################ + # LOG.debug("PORTS: %s", ports) + + filtered_ports = [] + for port in ports: + if port._info["board_uuid"] == board.uuid: + filtered_ports.append((port._info["uuid"], + _(port._info["ip"]))) + + ports = filtered_ports + # ################################################################ + + # Populate board ports + return {'uuid': board.uuid, + 'name': board.name, + 'ports': ports} + + class RemovePluginsView(forms.ModalFormView): template_name = 'iot/boards/removeplugins.html' modal_header = _("Remove Plugins from board") form_id = "remove_boardplugins_form" form_class = project_forms.RemovePluginsForm - submit_label = _("Remove Plugins from board") + submit_label = _("Remove") # submit_url = reverse_lazy("horizon:iot:boards:removeplugins") submit_url = "horizon:iot:boards:removeplugins" success_url = reverse_lazy('horizon:iot:boards:index') @@ -157,8 +360,9 @@ class RemovePluginsView(forms.ModalFormView): @memoized.memoized_method def get_object(self): try: - return iotronic.board_get(self.request, self.kwargs['board_id'], - None) + return api.iotronic.board_get(self.request, + self.kwargs['board_id'], + None) except Exception: redirect = reverse("horizon:iot:boards:index") exceptions.handle(self.request, @@ -176,49 +380,74 @@ class RemovePluginsView(forms.ModalFormView): # Populate plugins # TO BE DONE.....filter by available on this board!!! - # plugins = iotronic.plugin_list(self.request, None, None) - plugins = iotronic.plugins_on_board(self.request, board.uuid) + # plugins = api.iotronic.plugin_list(self.request, None, None) + plugins = api.iotronic.plugins_on_board(self.request, board.uuid) - plugins.sort(key=lambda b: b.name) + plugins.sort(key=lambda b: b["name"]) plugin_list = [] for plugin in plugins: - plugin_list.append((plugin.uuid, _(plugin.name))) + plugin_list.append((plugin["id"], _(plugin["name"]))) return {'uuid': board.uuid, 'name': board.name, 'plugin_list': plugin_list} +class RemoveServicesView(forms.ModalFormView): + template_name = 'iot/boards/removeservices.html' + modal_header = _("Remove Services from board") + form_id = "remove_boardservices_form" + form_class = project_forms.RemoveServicesForm + submit_label = _("Remove") + # submit_url = reverse_lazy("horizon:iot:boards:removeservices") + submit_url = "horizon:iot:boards:removeservices" + success_url = reverse_lazy('horizon:iot:boards:index') + page_title = _("Remove Services from board") + + @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(RemoveServicesView, 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 services + services = api.iotronic.services_on_board(self.request, + board.uuid, + True) + services.sort(key=lambda b: b["name"]) + + service_list = [] + for service in services: + service_list.append((service["uuid"], _(service["name"]))) + + return {'uuid': board.uuid, + 'name': board.name, + 'service_list': service_list} + + class DetailView(tabs.TabView): - # FROM - """ - tab_group_class = project_tabs.InstanceDetailTabs - template_name = 'horizon/common/_detail.html' - redirect_url = 'horizon:project:instances:index' - page_title = "{{ instance.name|default:instance.id }}" - image_url = 'horizon:project:images:images:detail' - volume_url = 'horizon:project:volumes:volumes:detail' - """ - # TO tab_group_class = project_tabs.BoardDetailTabs template_name = 'horizon/common/_detail.html' page_title = "{{ board.name|default:board.uuid }}" def get_context_data(self, **kwargs): context = super(DetailView, self).get_context_data(**kwargs) - # FROM - """ - instance = self.get_data() - if instance.image: - instance.image_url = reverse(self.image_url, - args=[instance.image['id']]) - instance.volume_url = self.volume_url - context["instance"] = instance - context["url"] = reverse(self.redirect_url) - context["actions"] = self._get_actions(instance) - """ - # TO board = self.get_data() context["board"] = board context["url"] = reverse(self.redirect_url) @@ -226,94 +455,38 @@ class DetailView(tabs.TabView): return context - # FROM - """ - def _get_actions(self, instance): - table = project_tables.InstancesTable(self.request) - return table.render_row_actions(instance) - """ - # TO def _get_actions(self, board): table = project_tables.BoardsTable(self.request) return table.render_row_actions(board) - # FROM - """ - @memoized.memoized_method - def get_data(self): - instance_id = self.kwargs['instance_id'] - - try: - instance = api.nova.server_get(self.request, instance_id) - except Exception: - redirect = reverse(self.redirect_url) - exceptions.handle(self.request, - _('Unable to retrieve details for ' - 'instance "%s".') % instance_id, - redirect=redirect) - # Not all exception types handled above will result in a redirect. - # Need to raise here just in case. - raise exceptions.Http302(redirect) - - choices = project_tables.STATUS_DISPLAY_CHOICES - instance.status_label = ( - filters.get_display_label(choices, instance.status)) - - try: - instance.volumes = api.nova.instance_volumes_list(self.request, - instance_id) - # Sort by device name - instance.volumes.sort(key=lambda vol: vol.device) - except Exception: - msg = _('Unable to retrieve volume list for instance ' - '"%(name)s" (%(id)s).') % {'name': instance.name, - 'id': instance_id} - exceptions.handle(self.request, msg, ignore=True) - - try: - instance.full_flavor = api.nova.flavor_get( - self.request, instance.flavor["id"]) - except Exception: - msg = _('Unable to retrieve flavor information for instance ' - '"%(name)s" (%(id)s).') % {'name': instance.name, - 'id': instance_id} - exceptions.handle(self.request, msg, ignore=True) - - try: - instance.security_groups = api.network.server_security_groups( - self.request, instance_id) - except Exception: - msg = _('Unable to retrieve security groups for instance ' - '"%(name)s" (%(id)s).') % {'name': instance.name, - 'id': instance_id} - exceptions.handle(self.request, msg, ignore=True) - - try: - api.network.servers_update_addresses(self.request, [instance]) - except Exception: - msg = _('Unable to retrieve IP addresses from Neutron for ' - 'instance "%(name)s" (%(id)s).') % {'name': instance.name, - 'id': instance_id} - exceptions.handle(self.request, msg, ignore=True) - - return instance - """ - - # TO @memoized.memoized_method def get_data(self): board_id = self.kwargs['board_id'] try: - board_services = [] - board_plugins = [] + board_ports = [] - board = iotronic.board_get(self.request, board_id, None) - board_services = iotronic.services_on_board(self.request, board_id, True) + board = api.iotronic.board_get(self.request, board_id, None) + + # FIX this problem with the new APIs + # (remove the "if" clause with a better approach) + # ################################################################# + ports = api.iotronic.port_list(self.request, board_id) + + for port in ports: + if port._info["board_uuid"] == board_id: + board_ports.append(port._info) + board._info.update(dict(ports=board_ports)) + # ################################################################# + + board_services = api.iotronic.services_on_board(self.request, + board_id, True) board._info.update(dict(services=board_services)) - board_plugins = iotronic.plugins_on_board(self.request, board_id) + board_plugins = api.iotronic.plugins_on_board(self.request, + board_id) board._info.update(dict(plugins=board_plugins)) + # LOG.debug("BOARD: %s\n\n%s", board, board._info) except Exception: @@ -322,14 +495,6 @@ class DetailView(tabs.TabView): exceptions.handle(self.request, msg, ignore=True) return board - # FROM - """ - def get_tabs(self, request, *args, **kwargs): - instance = self.get_data() - return self.tab_group_class(request, instance=instance, **kwargs) - """ - - # TO def get_tabs(self, request, *args, **kwargs): board = self.get_data() return self.tab_group_class(request, board=board, **kwargs) diff --git a/iotronic_ui/iot/dashboard.py b/iotronic_ui/iot/dashboard.py index 3660d9b..ed7ab1d 100644 --- a/iotronic_ui/iot/dashboard.py +++ b/iotronic_ui/iot/dashboard.py @@ -23,4 +23,5 @@ class Iot(horizon.Dashboard): # Specify the slug of the dashboard's default panel. default_panel = 'boards' + horizon.register(Iot) diff --git a/iotronic_ui/iot/plugins/forms.py b/iotronic_ui/iot/plugins/forms.py index 8ef14ba..5e9f3dd 100644 --- a/iotronic_ui/iot/plugins/forms.py +++ b/iotronic_ui/iot/plugins/forms.py @@ -68,18 +68,17 @@ class CreatePluginForm(forms.SelfHandlingForm): data["parameters"] = json.loads(data["parameters"]) try: - plugin = iotronic.plugin_create(request, data["name"], - data["public"], data["callable"], - data["code"], data["parameters"]) - LOG.debug("MELO API REQ: %s", request) + iotronic.plugin_create(request, data["name"], + data["public"], data["callable"], + data["code"], data["parameters"]) messages.success(request, _("Plugin created successfully.")) - return plugin + return True # except iot_exceptions.ClientException: except Exception: - # LOG.debug("MELO API REQ EXC: %s", request) - # LOG.debug("MELO API REQ (DICT): %s", exceptions.__dict__) + # LOG.debug("API REQ EXC: %s", request) + # LOG.debug("API REQ (DICT): %s", exceptions.__dict__) exceptions.handle(request, _('Unable to create plugin.')) @@ -97,7 +96,7 @@ class InjectPluginForm(forms.SelfHandlingForm): board_list = forms.MultipleChoiceField( label=_("Boards List"), widget=forms.SelectMultiple( - attrs={'class': 'switchable', 'data-slug': 'slug-inject-boards'}), + attrs={'class': 'switchable', 'data-slug': 'slug-inject-plugin'}), help_text=_("Select boards in this pool ") ) @@ -120,19 +119,18 @@ class InjectPluginForm(forms.SelfHandlingForm): if key == board: try: - plugin = None - plugin = iotronic.plugin_inject(request, key, + inject = iotronic.plugin_inject(request, key, data["uuid"], data["onboot"]) - # LOG.debug("MELO API: %s %s", plugin, request) - message_text = "Plugin injected successfully on " \ - "board " + str(value) + "." + # LOG.debug("API: %s %s", plugin, request) + message_text = inject messages.success(request, _(message_text)) if counter != len(data["board_list"]) - 1: counter += 1 else: - return plugin + return True + except Exception: message_text = "Unable to inject plugin on board " \ + str(value) + "." @@ -191,20 +189,19 @@ class StartPluginForm(forms.SelfHandlingForm): if key == board: try: - plugin = None - plugin = iotronic.plugin_action(request, key, + action = iotronic.plugin_action(request, key, data["uuid"], "PluginStart", data["parameters"]) - # LOG.debug("MELO API: %s %s", plugin, request) - message_text = "Plugin started successfully on board "\ - + str(value) + "." + # LOG.debug("API: %s %s", plugin, request) + message_text = action messages.success(request, _(message_text)) if counter != len(data["board_list"]) - 1: counter += 1 else: - return plugin + return True + except Exception: message_text = "Unable to start plugin on board " \ + str(value) + "." @@ -259,20 +256,19 @@ class StopPluginForm(forms.SelfHandlingForm): if key == board: try: - plugin = None - plugin = iotronic.plugin_action(request, key, + action = iotronic.plugin_action(request, key, data["uuid"], "PluginStop", data["delay"]) - # LOG.debug("MELO API: %s %s", plugin, request) - message_text = "Plugin stopped successfully on board "\ - + str(value) + "." + # LOG.debug("API: %s %s", plugin, request) + message_text = action messages.success(request, _(message_text)) if counter != len(data["board_list"]) - 1: counter += 1 else: - return plugin + return True + except Exception: message_text = "Unable to stop plugin on board " \ + str(value) + "." @@ -330,20 +326,19 @@ class CallPluginForm(forms.SelfHandlingForm): if key == board: try: - plugin = None - plugin = iotronic.plugin_action(request, key, + action = iotronic.plugin_action(request, key, data["uuid"], "PluginCall", data["parameters"]) - # LOG.debug("MELO API: %s %s", plugin, request) - message_text = "Plugin called successfully on board " \ - + str(value) + "." + + message_text = action messages.success(request, _(message_text)) if counter != len(data["board_list"]) - 1: - counter += 2 + counter += 1 else: - return plugin + return True + except Exception: message_text = "Unable to call plugin on board " \ + str(value) + "." @@ -387,10 +382,10 @@ class RemovePluginForm(forms.SelfHandlingForm): if key == board: try: - plugin = None - plugin = iotronic.plugin_remove(request, key, - data["uuid"]) - # LOG.debug("MELO API: %s %s", plugin, request) + iotronic.plugin_remove(request, + key, + data["uuid"]) + # LOG.debug("API: %s %s", plugin, request) message_text = "Plugin removed successfully from" \ + " board " + str(value) + "." messages.success(request, _(message_text)) @@ -398,7 +393,8 @@ class RemovePluginForm(forms.SelfHandlingForm): if counter != len(data["board_list"]) - 1: counter += 1 else: - return plugin + return True + except Exception: message_text = "Unable to remove plugin from board " \ + str(value) + "." @@ -411,34 +407,7 @@ class UpdatePluginForm(forms.SelfHandlingForm): uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput) owner = forms.CharField(label=_("Owner"), widget=forms.HiddenInput) - - """ name = forms.CharField(label=_("Plugin Name")) - public = forms.ChoiceField(label=_("Public")) - callable = forms.ChoiceField(label=_("Callable")) - code = forms.CharField(label=_("Code")) - """ - - name = forms.CharField(label=_("Plugin Name")) - - """ - public = forms.ChoiceField( - label=_("Public"), - choices =[('false', _('False')), ('true', _('True'))], - widget=forms.Select( - attrs={'class': 'switchable', 'data-slug': 'slug-public'}, - ) - ) - - - callable = forms.ChoiceField( - label=_("Callable"), - choices =[('false', _('False')), ('true', _('True'))], - widget=forms.Select( - attrs={'class': 'switchable', 'data-slug': 'slug-callable'}, - ) - ) - """ public = forms.BooleanField(label=_("Public"), required=False) callable = forms.BooleanField(label=_("Callable"), required=False) @@ -454,16 +423,16 @@ class UpdatePluginForm(forms.SelfHandlingForm): # Admin if policy.check((("iot", "iot:update_plugins"),), self.request): - # LOG.debug("MELO ADMIN") + # LOG.debug("ADMIN") pass # Admin_iot_project elif policy.check((("iot", "iot:update_project_plugins"),), self.request): - # LOG.debug("MELO IOT ADMIN") + # LOG.debug("IOT ADMIN") if self.request.user.id != kwargs["initial"]["owner"]: - # LOG.debug("MELO NO-edit IOT ADMIN") + # LOG.debug("NO-edit IOT ADMIN") self.fields["name"].widget.attrs = {'readonly': 'readonly'} self.fields["public"].widget.attrs = {'disabled': 'disabled'} self.fields["callable"].widget.attrs = {'disabled': 'disabled'} @@ -472,7 +441,7 @@ class UpdatePluginForm(forms.SelfHandlingForm): # Other users else: if self.request.user.id != kwargs["initial"]["owner"]: - # LOG.debug("MELO IMMUTABLE FIELDS") + # LOG.debug("IMMUTABLE FIELDS") self.fields["name"].widget.attrs = {'readonly': 'readonly'} self.fields["public"].widget.attrs = {'disabled': 'disabled'} self.fields["callable"].widget.attrs = {'disabled': 'disabled'} @@ -481,7 +450,6 @@ class UpdatePluginForm(forms.SelfHandlingForm): def handle(self, request, data): try: - # LOG.debug("MELO DATA: %s", data) data["code"] = cPickle.dumps(str(data["code"])) iotronic.plugin_update(request, data["uuid"], @@ -489,7 +457,10 @@ class UpdatePluginForm(forms.SelfHandlingForm): "public": data["public"], "callable": data["callable"], "code": data["code"]}) - messages.success(request, _("Plugin updated successfully.")) + + messages.success(request, _("Plugin " + str(data["name"]) + + " updated successfully.")) return True + except Exception: exceptions.handle(request, _('Unable to update plugin.')) diff --git a/iotronic_ui/iot/plugins/panel.py b/iotronic_ui/iot/plugins/panel.py index a099a3d..2625c5d 100644 --- a/iotronic_ui/iot/plugins/panel.py +++ b/iotronic_ui/iot/plugins/panel.py @@ -14,9 +14,14 @@ from django.utils.translation import ugettext_lazy as _ import horizon +from iotronic_ui.iot import dashboard + class Plugins(horizon.Panel): name = _("Plugins") slug = "plugins" # policy_rules = (("iot", "iot:list_all_plugins"), # ("iot", "iot:list_project_plugins")) + + +dashboard.Iot.register(Plugins) diff --git a/iotronic_ui/iot/plugins/tables.py b/iotronic_ui/iot/plugins/tables.py index 464ec46..362d7d6 100644 --- a/iotronic_ui/iot/plugins/tables.py +++ b/iotronic_ui/iot/plugins/tables.py @@ -28,7 +28,7 @@ class CreatePluginLink(tables.LinkAction): url = "horizon:iot:plugins:create" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:create_plugin"),) class EditPluginLink(tables.LinkAction): @@ -37,12 +37,12 @@ class EditPluginLink(tables.LinkAction): url = "horizon:iot:plugins:update" classes = ("ajax-modal",) icon = "pencil" - # policy_rules = (("iot", "iot:update_board"),) + # policy_rules = (("iot", "iot:update_plugin"),) """ def allowed(self, request, plugin): - # LOG.debug("MELO ALLOWED: %s %s %s", self, request, plugin) - # LOG.debug("MELO user: %s", request.user.id) + # LOG.debug("ALLOWED: %s %s %s", self, request, plugin) + # LOG.debug("user: %s", request.user.id) return True """ @@ -54,7 +54,7 @@ class InjectPluginLink(tables.LinkAction): url = "horizon:iot:plugins:inject" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:inject_plugin"),) class StartPluginLink(tables.LinkAction): @@ -63,7 +63,7 @@ class StartPluginLink(tables.LinkAction): url = "horizon:iot:plugins:start" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:start_plugin"),) class StopPluginLink(tables.LinkAction): @@ -72,7 +72,7 @@ class StopPluginLink(tables.LinkAction): url = "horizon:iot:plugins:stop" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:stop_plugin"),) class CallPluginLink(tables.LinkAction): @@ -81,7 +81,7 @@ class CallPluginLink(tables.LinkAction): url = "horizon:iot:plugins:call" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:call_plugin"),) class RemovePluginLink(tables.LinkAction): @@ -90,7 +90,7 @@ class RemovePluginLink(tables.LinkAction): url = "horizon:iot:plugins:remove" classes = ("ajax-modal",) icon = "plus" - # policy_rules = (("iot", "iot:create_board"),) + # policy_rules = (("iot", "iot:remove_plugin"),) class DeletePluginsAction(tables.DeleteAction): @@ -109,7 +109,7 @@ class DeletePluginsAction(tables.DeleteAction): u"Deleted Plugins", count ) - # policy_rules = (("iot", "iot:delete_board"),) + # policy_rules = (("iot", "iot:delete_plugin"),) """ def allowed(self, request, role): @@ -140,14 +140,14 @@ class PluginsTable(tables.DataTable): # Overriding get_object_id method because in IoT service the "id" is # identified by the field UUID def get_object_id(self, datum): - # LOG.debug("MELO datum %s", datum) + # LOG.debug("datum %s", datum) return datum.uuid # Overriding get_row_actions method because we need to discriminate # between Sync and Async plugins def get_row_actions(self, datum): actions = super(PluginsTable, self).get_row_actions(datum) - # LOG.debug("MELO ACTIONS: %s %s", actions[0].name, datum.name) + # LOG.debug("ACTIONS: %s %s", actions[0].name, datum.name) selected_row_actions = [] diff --git a/iotronic_ui/iot/plugins/urls.py b/iotronic_ui/iot/plugins/urls.py index 1894504..90a3d03 100644 --- a/iotronic_ui/iot/plugins/urls.py +++ b/iotronic_ui/iot/plugins/urls.py @@ -18,6 +18,8 @@ from iotronic_ui.iot.plugins import views urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^create/$', views.CreateView.as_view(), name='create'), + url(r'^(?P[^/]+)/update/$', views.UpdateView.as_view(), + name='update'), url(r'^(?P[^/]+)/inject/$', views.InjectView.as_view(), name='inject'), url(r'^(?P[^/]+)/start/$', views.StartView.as_view(), @@ -28,8 +30,6 @@ urlpatterns = [ name='call'), url(r'^(?P[^/]+)/remove/$', views.RemoveView.as_view(), name='remove'), - url(r'^(?P[^/]+)/update/$', views.UpdateView.as_view(), - name='update'), url(r'^(?P[^/]+)/detail/$', views.PluginDetailView.as_view(), name='detail'), ] diff --git a/iotronic_ui/iot/plugins/views.py b/iotronic_ui/iot/plugins/views.py index 1cb3f13..093acb8 100644 --- a/iotronic_ui/iot/plugins/views.py +++ b/iotronic_ui/iot/plugins/views.py @@ -67,13 +67,6 @@ class IndexView(tables.DataTableView): # Other users else: - # FROM - """ - msg = _("Insufficient privilege level to view - plugins information.") - messages.info(self.request, msg) - """ - # TO try: plugins = iotronic.plugin_list(self.request, None, None, with_public=True) diff --git a/iotronic_ui/iot/services/forms.py b/iotronic_ui/iot/services/forms.py index c8297c3..f3fa65f 100644 --- a/iotronic_ui/iot/services/forms.py +++ b/iotronic_ui/iot/services/forms.py @@ -41,17 +41,18 @@ class CreateServiceForm(forms.SelfHandlingForm): def handle(self, request, data): try: - # LOG.error("DATA: %s", data) - service = iotronic.service_create(request, data["name"], - data["port"], data["protocol"]) - messages.success(request, _("Service created successfully.")) + iotronic.service_create(request, data["name"], + data["port"], data["protocol"]) + + messages.success(request, _("Service " + str(data["name"]) + + " created successfully.")) + return True - return service except Exception: exceptions.handle(request, _('Unable to create service.')) -class UpdateBoardForm(forms.SelfHandlingForm): +class UpdateServiceForm(forms.SelfHandlingForm): uuid = forms.CharField(label=_("Service ID"), widget=forms.HiddenInput) name = forms.CharField(label=_("Service Name")) port = forms.IntegerField(label=_("Port")) @@ -65,23 +66,23 @@ class UpdateBoardForm(forms.SelfHandlingForm): def __init__(self, *args, **kwargs): - super(UpdateBoardForm, self).__init__(*args, **kwargs) + super(UpdateServiceForm, self).__init__(*args, **kwargs) # Admin if policy.check((("iot", "iot:update_services"),), self.request): - # LOG.debug("MELO ADMIN") + # LOG.debug("ADMIN") pass # Manager or Admin of the iot project elif (policy.check((("iot", "iot_manager"),), self.request) or policy.check((("iot", "iot_admin"),), self.request)): - # LOG.debug("MELO NO-edit IOT ADMIN") + # LOG.debug("NO-edit IOT ADMIN") pass # Other users else: if self.request.user.id != kwargs["initial"]["owner"]: - # LOG.debug("MELO IMMUTABLE FIELDS") + # LOG.debug("IMMUTABLE FIELDS") self.fields["name"].widget.attrs = {'readonly': 'readonly'} self.fields["port"].widget.attrs = {'readonly': 'readonly'} self.fields["protocol"].widget.attrs = {'readonly': 'readonly'} @@ -89,12 +90,13 @@ class UpdateBoardForm(forms.SelfHandlingForm): def handle(self, request, data): try: iotronic.service_update(request, data["uuid"], - {"name": data["name"], - "port": data["port"], - "protocol": data["protocol"]}) + {"name": data["name"], + "port": data["port"], + "protocol": data["protocol"]}) messages.success(request, _("Service updated successfully.")) return True + except Exception: exceptions.handle(request, _('Unable to update service.')) @@ -117,7 +119,9 @@ class ServiceActionForm(forms.SelfHandlingForm): action = forms.ChoiceField( label=_("Action"), - choices=[('ServiceEnable', _('Enable')), ('ServiceDisable', _('Disable')), ('ServiceRestore', _('Restore'))], + choices=[('ServiceEnable', _('Enable')), + ('ServiceDisable', _('Disable')), + ('ServiceRestore', _('Restore'))], widget=forms.Select( attrs={'class': 'switchable', 'data-slug': 'slug-action'}, ) @@ -128,10 +132,7 @@ class ServiceActionForm(forms.SelfHandlingForm): super(ServiceActionForm, self).__init__(*args, **kwargs) # input=kwargs.get('initial',{}) - boardslist_length = len(kwargs["initial"]["board_list"]) - self.fields["board_list"].choices = kwargs["initial"]["board_list"] - # self.fields["board_list"].max_length = boardslist_length def handle(self, request, data): @@ -142,60 +143,20 @@ class ServiceActionForm(forms.SelfHandlingForm): if key == board: try: - action = None action = iotronic.service_action(request, key, - data["uuid"], - data["action"]) - - message_text = "Action executed successfully on " \ - "board " + str(value) + "." + data["uuid"], + data["action"]) + message_text = action messages.success(request, _(message_text)) if counter != len(data["board_list"]) - 1: counter += 1 else: - return action + return True + except Exception: message_text = "Unable to execute action on board " \ + str(value) + "." exceptions.handle(request, _(message_text)) break - - -class RemoveServicesForm(forms.SelfHandlingForm): - - uuid = forms.CharField(label=_("Service ID"), widget=forms.HiddenInput) - - name = forms.CharField( - label=_('Service Name'), - widget=forms.TextInput(attrs={'readonly': 'readonly'}) - ) - port = forms.IntegerField( - label=_("Port"), - widget=forms.TextInput(attrs={'readonly': 'readonly'}) - ) - - protocol = forms.ChoiceField( - label=_("Protocol"), - choices=[('TCP', _('TCP')), ('UDP', _('UDP'))], - widget=forms.TextInput(attrs={'readonly': 'readonly'}) - ) - - def __init__(self, *args, **kwargs): - - super(RemoveServicesForm, self).__init__(*args, **kwargs) - # input=kwargs.get('initial',{}) - - - def handle(self, request, data): - - try: - message_text = "Service "+str(data["name"])+" deleted successfully." - - iotronic.service_delete(request, data["uuid"]) - messages.success(request, _(message_text)) - return True - except Exception: - message_text = "Unable to delete service "+str(data["name"])+"." - exceptions.handle(request, _(message_text)) diff --git a/iotronic_ui/iot/services/panel.py b/iotronic_ui/iot/services/panel.py index aa531a0..9f52117 100644 --- a/iotronic_ui/iot/services/panel.py +++ b/iotronic_ui/iot/services/panel.py @@ -15,6 +15,7 @@ from django.utils.translation import ugettext_lazy as _ import horizon # from openstack_dashboard.api import keystone +from iotronic_ui.iot import dashboard class Services(horizon.Panel): @@ -23,3 +24,5 @@ class Services(horizon.Panel): permissions = ('openstack.services.iot', ) # policy_rules = (("iot", "iot:list_all_services"),) + +dashboard.Iot.register(Services) diff --git a/iotronic_ui/iot/services/tables.py b/iotronic_ui/iot/services/tables.py index d4efc26..abe7cd9 100644 --- a/iotronic_ui/iot/services/tables.py +++ b/iotronic_ui/iot/services/tables.py @@ -22,7 +22,6 @@ from openstack_dashboard import api LOG = logging.getLogger(__name__) - class CreateServiceLink(tables.LinkAction): name = "create" verbose_name = _("Create Service") @@ -32,7 +31,7 @@ class CreateServiceLink(tables.LinkAction): # policy_rules = (("iot", "iot:create_service"),) -class EditBoardLink(tables.LinkAction): +class EditServiceLink(tables.LinkAction): name = "edit" verbose_name = _("Edit") url = "horizon:iot:services:update" @@ -41,17 +40,6 @@ class EditBoardLink(tables.LinkAction): # policy_rules = (("iot", "iot:update_service"),) -""" -class RemoveServicesLink(tables.LinkAction): - name = "remove" - verbose_name = _("Remove Service(s)") - url = "horizon:iot:services:remove" - classes = ("ajax-modal",) - icon = "plus" - # policy_rules = (("iot", "iot:delete_service"),) -""" - - class ActionServiceLink(tables.LinkAction): name = "action" verbose_name = _("Service Action") @@ -106,11 +94,7 @@ class ServicesTable(tables.DataTable): class Meta(object): name = "services" verbose_name = _("services") - row_actions = (EditBoardLink, ActionServiceLink, + row_actions = (EditServiceLink, ActionServiceLink, DeleteServicesAction) table_actions = (ServiceFilterAction, CreateServiceLink, - DeleteServicesAction) - - # row_actions = (EditBoardLink, RemovePluginsLink, DeleteBoardsAction) - # table_actions = (BoardFilterAction, CreateBoardLink, - # DeleteBoardsAction) + DeleteServicesAction) diff --git a/iotronic_ui/iot/services/urls.py b/iotronic_ui/iot/services/urls.py index b748942..fd61ed0 100644 --- a/iotronic_ui/iot/services/urls.py +++ b/iotronic_ui/iot/services/urls.py @@ -22,8 +22,6 @@ urlpatterns = [ name='update'), url(r'^(?P[^/]+)/action/$', views.ActionView.as_view(), name='action'), - url(r'^(?P[^/]+)/remove/$', - views.RemoveServicesView.as_view(), name='remove'), url(r'^(?P[^/]+)/detail/$', views.ServiceDetailView.as_view(), name='detail'), ] diff --git a/iotronic_ui/iot/services/views.py b/iotronic_ui/iot/services/views.py index b17a0f3..afc31cf 100644 --- a/iotronic_ui/iot/services/views.py +++ b/iotronic_ui/iot/services/views.py @@ -52,7 +52,8 @@ class IndexView(tables.DataTableView): _('Unable to retrieve services list.')) # Admin_iot_project - elif policy.check((("iot", "iot:list_project_services"),), self.request): + elif policy.check((("iot", "iot:list_project_services"),), + self.request): try: services = iotronic.service_list(self.request, None) @@ -87,7 +88,7 @@ class UpdateView(forms.ModalFormView): template_name = 'iot/services/update.html' modal_header = _("Update Service") form_id = "update_service_form" - form_class = project_forms.UpdateBoardForm + form_class = project_forms.UpdateServiceForm submit_label = _("Update Service") submit_url = "horizon:iot:services:update" success_url = reverse_lazy('horizon:iot:services:index') @@ -96,8 +97,9 @@ class UpdateView(forms.ModalFormView): @memoized.memoized_method def get_object(self): try: - return iotronic.service_get(self.request, self.kwargs['service_id'], - None) + return iotronic.service_get(self.request, + self.kwargs['service_id'], + None) except Exception: redirect = reverse("horizon:iot:services:index") exceptions.handle(self.request, @@ -133,8 +135,9 @@ class ActionView(forms.ModalFormView): @memoized.memoized_method def get_object(self): try: - return iotronic.service_get(self.request, self.kwargs['service_id'], - None) + return iotronic.service_get(self.request, + self.kwargs['service_id'], + None) except Exception: redirect = reverse("horizon:iot:services:index") exceptions.handle(self.request, @@ -163,43 +166,6 @@ class ActionView(forms.ModalFormView): 'board_list': board_list} -class RemoveServicesView(forms.ModalFormView): - template_name = 'iot/services/remove.html' - modal_header = _("Remove Service") - form_id = "remove_service_form" - form_class = project_forms.RemoveServicesForm - submit_label = _("Remove Service") - # submit_url = reverse_lazy("horizon:iot:boards:removeplugins") - submit_url = "horizon:iot:services:remove" - success_url = reverse_lazy('horizon:iot:services:index') - page_title = _("Remove Service") - - @memoized.memoized_method - def get_object(self): - try: - return iotronic.service_get(self.request, self.kwargs['service_id'], - None) - except Exception: - redirect = reverse("horizon:iot:services:index") - exceptions.handle(self.request, - _('Unable to get service information.'), - redirect=redirect) - - def get_context_data(self, **kwargs): - context = super(RemoveServicesView, 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): - service = self.get_object() - - return {'uuid': service.uuid, - 'name': service.name, - 'port': service.port, - 'protocol': service.protocol} - - class DetailView(tabs.TabView): tab_group_class = project_tabs.ServiceDetailTabs template_name = 'horizon/common/_detail.html' @@ -224,8 +190,8 @@ class DetailView(tabs.TabView): try: service = iotronic.service_get(self.request, service_id, None) except Exception: - msg = ('Unable to retrieve service %s information') % {'name': - service.name} + s = service.name + msg = ('Unable to retrieve service %s information') % {'name': s} exceptions.handle(self.request, msg, ignore=True) return service diff --git a/iotronic_ui/iot/static/iot/images/blue-circle.png b/iotronic_ui/iot/static/iot/images/blue-circle.png deleted file mode 100644 index 3e1f389..0000000 Binary files a/iotronic_ui/iot/static/iot/images/blue-circle.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/green-circle.png b/iotronic_ui/iot/static/iot/images/green-circle.png deleted file mode 100644 index f639e78..0000000 Binary files a/iotronic_ui/iot/static/iot/images/green-circle.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/marker-icon-green.png b/iotronic_ui/iot/static/iot/images/marker-icon-green.png deleted file mode 100644 index 56db5ea..0000000 Binary files a/iotronic_ui/iot/static/iot/images/marker-icon-green.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/marker-icon-red.png b/iotronic_ui/iot/static/iot/images/marker-icon-red.png deleted file mode 100644 index 3165a31..0000000 Binary files a/iotronic_ui/iot/static/iot/images/marker-icon-red.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/marker-icon.png b/iotronic_ui/iot/static/iot/images/marker-icon.png deleted file mode 100644 index e2e9f75..0000000 Binary files a/iotronic_ui/iot/static/iot/images/marker-icon.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/marker-shadow.png b/iotronic_ui/iot/static/iot/images/marker-shadow.png deleted file mode 100644 index d1e773c..0000000 Binary files a/iotronic_ui/iot/static/iot/images/marker-shadow.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/images/red-circle.png b/iotronic_ui/iot/static/iot/images/red-circle.png deleted file mode 100644 index bb3bbdf..0000000 Binary files a/iotronic_ui/iot/static/iot/images/red-circle.png and /dev/null differ diff --git a/iotronic_ui/iot/static/iot/js/iot.js b/iotronic_ui/iot/static/iot/js/iot.js deleted file mode 100644 index 97e3b8d..0000000 --- a/iotronic_ui/iot/static/iot/js/iot.js +++ /dev/null @@ -1,122 +0,0 @@ -/* Additional JavaScript for iot. */ - -//alert('MELO'); - -//var image_url = 'https://ing-res-17.me.trigrid.it/iotronic/'; -var images_url = 'http://'+location.host+'/dashboard/static/iot/images/'; - -var markers = []; -markers = L.markerClusterGroup({ - spiderfyOnMaxZoom: false, - disableClusteringAtZoom: 17 -}); - - -var marker_red = L.icon({ - iconUrl: images_url+'marker-icon-red.png', - iconAnchor:[12.5, 41], - shadowUrl: images_url+'marker-shadow.png' -}); - - -var marker_green = L.icon({ - iconUrl: images_url+'marker-icon-green.png', - iconAnchor:[12.5, 41], - shadowUrl: images_url+'marker-shadow.png' -}); - - -var marker_blue = L.icon({ - iconUrl: images_url+'marker-icon.png', - iconAnchor:[12.5, 41], - shadowUrl: images_url+'marker-shadow.png' -}); - - -var labels = []; -var latitude = []; -var longitude = []; -var altitude = []; -var statuses = []; -var last_update = []; - - -function render_map(map_id, coordinates){ - var osmUrl='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; - var osm = new L.TileLayer(osmUrl, {}); - - var lat = 38.20523; - var lon = 15.55972; - if(coordinates["coordinates"].length ==1){ - lat = coordinates["coordinates"][0].lat; - lon = coordinates["coordinates"][0].lon; - } - var map = L.map(map_id, {scrollWheelZoom:false, worldCopyJump: true}).setView([lat, lon], 12); - map.addLayer(osm); - - //Copyright - L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap - by MDSLab' - }).addTo(map); - - //var marker = L.marker([lat, lon]); - //marker.setIcon(marker_red); - coord = coordinates["coordinates"]; - for(var i=0;i'; - if(statuses[sel] == "online") - img = ''; - if(statuses[sel] == "offline") - img = ''; - - var open_popup = '
'; - - var default_popup = '
'+img +' '+labels[sel]+'

' + - '
'+last_update[sel]+'

'+ - 'Latitude: '+latitude[sel]+ '
' + - 'Longitude: '+longitude[sel]+'
' + - 'Altitude: '+altitude[sel]+'

'; - - global_popup = open_popup + default_popup +"
"; - var popup = L.popup().setLatLng(e.latlng).setContent(global_popup).openOn(map); - }); - markers.addLayer(marker); - } - map.addLayer(markers); - //return map; -} - - - -function choose_marker(status){ - if(status=="online") return marker_green; - else if(status =="offline") return marker_red; - else return marker_blue; -} diff --git a/iotronic_ui/iot/static/iot/scss/iot.scss b/iotronic_ui/iot/static/iot/scss/iot.scss deleted file mode 100644 index e1bd25d..0000000 --- a/iotronic_ui/iot/static/iot/scss/iot.scss +++ /dev/null @@ -1,7 +0,0 @@ -/* Additional SCSS for {{ dash_name }}. */ - -/* -#mapdiv { - min-height: 300px; -} -*/