Added service panel and management
Change-Id: Ibb89e33ff30be300eb32dd7f5e4ab72fb53d6022
This commit is contained in:
parent
751057898e
commit
081b93987b
|
@ -80,9 +80,8 @@ def board_delete(request, board_id):
|
||||||
def plugin_list(request, detail=None, project=None, with_public=False,
|
def plugin_list(request, detail=None, project=None, with_public=False,
|
||||||
all_plugins=False):
|
all_plugins=False):
|
||||||
"""List plugins."""
|
"""List plugins."""
|
||||||
plugin = iotronicclient(request).plugin()
|
plugins = iotronicclient(request).plugin.list(detail, project, \
|
||||||
plugins = plugin.list(detail, project,
|
with_public=with_public, \
|
||||||
with_public=with_public,
|
|
||||||
all_plugins=all_plugins)
|
all_plugins=all_plugins)
|
||||||
return plugins
|
return plugins
|
||||||
|
|
||||||
|
@ -119,15 +118,17 @@ def plugin_delete(request, plugin_id):
|
||||||
# PLUGIN MANAGEMENT (Board Side)
|
# PLUGIN MANAGEMENT (Board Side)
|
||||||
def plugin_inject(request, board_id, plugin_id, onboot):
|
def plugin_inject(request, board_id, plugin_id, onboot):
|
||||||
"""Inject plugin on board(s)."""
|
"""Inject plugin on board(s)."""
|
||||||
plugin_injection = iotronicclient(request).plugin_injection()
|
plugin = iotronicclient(request).plugin_injection. \
|
||||||
plugin = plugin_injection.plugin_inject(board_id, plugin_id, onboot)
|
plugin_inject(board_id, \
|
||||||
|
plugin_id, \
|
||||||
|
onboot)
|
||||||
return plugin
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
def plugin_action(request, board_id, plugin_id, action, params={}):
|
def plugin_action(request, board_id, plugin_id, action, params={}):
|
||||||
"""Start/Stop/Call actions on board(s)."""
|
"""Start/Stop/Call actions on board(s)."""
|
||||||
plugin_injection = iotronicclient(request).plugin_injection()
|
plugin = iotronicclient(request).plugin_injection. \
|
||||||
plugin = plugin_injection.plugin_action(board_id,
|
plugin_action(board_id,
|
||||||
plugin_id,
|
plugin_id,
|
||||||
action,
|
action,
|
||||||
params)
|
params)
|
||||||
|
@ -136,13 +137,96 @@ def plugin_action(request, board_id, plugin_id, action, params={}):
|
||||||
|
|
||||||
def plugin_remove(request, board_id, plugin_id):
|
def plugin_remove(request, board_id, plugin_id):
|
||||||
"""Inject plugin on board(s)."""
|
"""Inject plugin on board(s)."""
|
||||||
plugin_injection = iotronicclient(request).plugin_injection()
|
plugin = iotronicclient(request).plugin_injection. \
|
||||||
plugin = plugin_injection.plugin_remove(board_id, plugin_id)
|
plugin_remove(board_id, plugin_id)
|
||||||
return plugin
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
def plugins_on_board(request, board_id):
|
def plugins_on_board(request, board_id):
|
||||||
"""Plugins on board."""
|
"""Plugins on board."""
|
||||||
plugin_injection = iotronicclient(request).plugin_injection()
|
plugins = iotronicclient(request).plugin_injection. \
|
||||||
plugins = plugin_injection.plugins_on_board(board_id)
|
plugins_on_board(board_id)
|
||||||
return plugins
|
|
||||||
|
detailed_plugins = []
|
||||||
|
# fields = {"name", "public", "callable"}
|
||||||
|
fields = {"name"}
|
||||||
|
for plugin in plugins:
|
||||||
|
details = iotronicclient(request).plugin.get(plugin.plugin, fields)
|
||||||
|
detailed_plugins.append({"name": details._info["name"],
|
||||||
|
"id": plugin.plugin})
|
||||||
|
|
||||||
|
return detailed_plugins
|
||||||
|
|
||||||
|
|
||||||
|
# SERVICE MANAGEMENT
|
||||||
|
def service_list(request, detail=None):
|
||||||
|
"""List services."""
|
||||||
|
services = iotronicclient(request).service.list(detail)
|
||||||
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
def service_get(request, service_id, fields):
|
||||||
|
"""Get service info."""
|
||||||
|
service = iotronicclient(request).service.get(service_id, fields)
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def service_create(request, name, port, protocol):
|
||||||
|
"""Create service."""
|
||||||
|
params = {"name": name,
|
||||||
|
"port": port,
|
||||||
|
"protocol": protocol}
|
||||||
|
service = iotronicclient(request).service.create(**params)
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def service_update(request, service_id, patch):
|
||||||
|
"""Update service."""
|
||||||
|
service = iotronicclient(request).service.update(service_id, patch)
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def service_delete(request, service_id):
|
||||||
|
"""Delete service."""
|
||||||
|
service = iotronicclient(request).service.delete(service_id)
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def services_on_board(request, board_id, detail=False):
|
||||||
|
"""List services on board."""
|
||||||
|
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)
|
||||||
|
|
||||||
|
detailed_services.append({"name": details._info["name"],
|
||||||
|
"public_port":
|
||||||
|
service._info["public_port"],
|
||||||
|
"port": details._info["port"],
|
||||||
|
"protocol": details._info["protocol"]})
|
||||||
|
|
||||||
|
return detailed_services
|
||||||
|
|
||||||
|
else:
|
||||||
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def restore_services(request, board_id):
|
||||||
|
"""Restore services."""
|
||||||
|
service_restore = iotronicclient(request).exposed_service. \
|
||||||
|
restore_services(board_id)
|
||||||
|
return service_restore
|
||||||
|
|
||||||
|
|
|
@ -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 = 'services'
|
||||||
|
# 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.services.panel.Services'
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django import template
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ungettext_lazy
|
from django.utils.translation import ungettext_lazy
|
||||||
|
|
||||||
|
@ -45,6 +46,24 @@ class EditBoardLink(tables.LinkAction):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class RestoreServices(tables.BatchAction):
|
||||||
|
name = "restoreservices"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return u"Restore Services"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return u"Restore Services"
|
||||||
|
|
||||||
|
def allowed(self, request, board=None):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def action(self, request, board_id):
|
||||||
|
api.iotronic.restore_services(request, board_id)
|
||||||
|
|
||||||
|
|
||||||
class RemovePluginsLink(tables.LinkAction):
|
class RemovePluginsLink(tables.LinkAction):
|
||||||
name = "removeplugins"
|
name = "removeplugins"
|
||||||
verbose_name = _("Remove Plugin(s)")
|
verbose_name = _("Remove Plugin(s)")
|
||||||
|
@ -98,6 +117,13 @@ class BoardFilterAction(tables.FilterAction):
|
||||||
return [board for board in boards
|
return [board for board in boards
|
||||||
if q in board.name.lower()]
|
if q in board.name.lower()]
|
||||||
|
|
||||||
|
def show_services(board_info):
|
||||||
|
template_name = 'iot/boards/_cell_services.html'
|
||||||
|
context = board_info._info
|
||||||
|
# LOG.debug("CONTEXT: %s", context)
|
||||||
|
return template.loader.render_to_string(template_name,
|
||||||
|
context)
|
||||||
|
|
||||||
|
|
||||||
class BoardsTable(tables.DataTable):
|
class BoardsTable(tables.DataTable):
|
||||||
name = tables.WrappingColumn('name', link="horizon:iot:boards:detail",
|
name = tables.WrappingColumn('name', link="horizon:iot:boards:detail",
|
||||||
|
@ -107,7 +133,8 @@ class BoardsTable(tables.DataTable):
|
||||||
uuid = tables.Column('uuid', verbose_name=_('Board ID'))
|
uuid = tables.Column('uuid', verbose_name=_('Board ID'))
|
||||||
# code = tables.Column('code', verbose_name=_('Code'))
|
# code = tables.Column('code', verbose_name=_('Code'))
|
||||||
status = tables.Column('status', verbose_name=_('Status'))
|
status = tables.Column('status', verbose_name=_('Status'))
|
||||||
location = tables.Column('location', verbose_name=_('Geo'))
|
# location = tables.Column('location', verbose_name=_('Geo'))
|
||||||
|
services = tables.Column(show_services, verbose_name=_('Services'))
|
||||||
# extra = tables.Column('extra', verbose_name=_('Extra'))
|
# extra = tables.Column('extra', verbose_name=_('Extra'))
|
||||||
|
|
||||||
# Overriding get_object_id method because in IoT service the "id" is
|
# Overriding get_object_id method because in IoT service the "id" is
|
||||||
|
@ -118,6 +145,7 @@ class BoardsTable(tables.DataTable):
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
name = "boards"
|
name = "boards"
|
||||||
verbose_name = _("boards")
|
verbose_name = _("boards")
|
||||||
row_actions = (EditBoardLink, RemovePluginsLink, DeleteBoardsAction)
|
row_actions = (EditBoardLink, RestoreServices,
|
||||||
|
RemovePluginsLink, DeleteBoardsAction)
|
||||||
table_actions = (BoardFilterAction, CreateBoardLink,
|
table_actions = (BoardFilterAction, CreateBoardLink,
|
||||||
DeleteBoardsAction)
|
RestoreServices, DeleteBoardsAction)
|
||||||
|
|
|
@ -32,11 +32,15 @@ class OverviewTab(tabs.Tab):
|
||||||
template_name = ("iot/boards/_detail_overview.html")
|
template_name = ("iot/boards/_detail_overview.html")
|
||||||
|
|
||||||
def get_context_data(self, request):
|
def get_context_data(self, request):
|
||||||
coordinates = self.tab_group.kwargs['board'].__dict__["location"][0]
|
|
||||||
# LOG.debug('IOT INFO: %s', coordinates)
|
coordinates = self.tab_group.kwargs['board'].__dict__['location'][0]
|
||||||
|
services = self.tab_group.kwargs['board']._info['services']
|
||||||
|
plugins = self.tab_group.kwargs['board']._info['plugins']
|
||||||
|
|
||||||
return {"board": self.tab_group.kwargs['board'],
|
return {"board": self.tab_group.kwargs['board'],
|
||||||
"coordinates": coordinates,
|
"coordinates": coordinates,
|
||||||
|
"services": services,
|
||||||
|
"plugins": plugins,
|
||||||
"is_superuser": request.user.is_superuser}
|
"is_superuser": request.user.is_superuser}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% load i18n %}
|
||||||
|
{% if services %}
|
||||||
|
{% for service in services %}
|
||||||
|
<dd>{{ service.name }} [{{ service.protocol }}] {{ service.port }} --> {{ service.public_port }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>--</dd>
|
||||||
|
{% endif %}
|
|
@ -22,6 +22,22 @@
|
||||||
<dd>{{ board.mobile }}</dd>
|
<dd>{{ board.mobile }}</dd>
|
||||||
<dt>{% trans "Extra" %}</dt>
|
<dt>{% trans "Extra" %}</dt>
|
||||||
<dd>{{ board.extra }}</dd>
|
<dd>{{ board.extra }}</dd>
|
||||||
|
<dt>{% trans "Services" %}</dt>
|
||||||
|
{% if services %}
|
||||||
|
{% for service in services %}
|
||||||
|
<dd>{{ service.name }} [{{ service.protocol }}] {{ service.port }} --> {{ service.public_port }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>--</dd>
|
||||||
|
{% endif %}
|
||||||
|
<dt>{% trans "Plugins" %}</dt>
|
||||||
|
{% if plugins %}
|
||||||
|
{% for plugin in plugins %}
|
||||||
|
<dd>{{ plugin.name }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>--</dd>
|
||||||
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,11 @@ class IndexView(tables.DataTableView):
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to retrieve user boards list.'))
|
_('Unable to retrieve user boards list.'))
|
||||||
|
|
||||||
|
for board in boards:
|
||||||
|
board_services = iotronic.services_on_board(self.request, board.uuid, True)
|
||||||
|
|
||||||
|
# board.__dict__.update(dict(services=board_services))
|
||||||
|
board._info.update(dict(services=board_services))
|
||||||
return boards
|
return boards
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,7 +121,7 @@ class UpdateView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:boards:index")
|
redirect = reverse("horizon:iot:boards:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to update board.'),
|
_('Unable to get board information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -127,8 +132,6 @@ class UpdateView(forms.ModalFormView):
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
board = self.get_object()
|
board = self.get_object()
|
||||||
|
|
||||||
# LOG.debug("MELO BOARD INFO: %s", board)
|
|
||||||
location = board.location[0]
|
location = board.location[0]
|
||||||
|
|
||||||
return {'uuid': board.uuid,
|
return {'uuid': board.uuid,
|
||||||
|
@ -159,7 +162,7 @@ class RemovePluginsView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:boards:index")
|
redirect = reverse("horizon:iot:boards:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to remove plugin.'),
|
_('Unable to get board information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -301,7 +304,18 @@ class DetailView(tabs.TabView):
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
board_id = self.kwargs['board_id']
|
board_id = self.kwargs['board_id']
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
board_services = []
|
||||||
|
board_plugins = []
|
||||||
|
|
||||||
board = iotronic.board_get(self.request, board_id, None)
|
board = iotronic.board_get(self.request, board_id, None)
|
||||||
|
board_services = 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._info.update(dict(plugins=board_plugins))
|
||||||
|
# LOG.debug("BOARD: %s\n\n%s", board, board._info)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = ('Unable to retrieve board %s information') % {'name':
|
msg = ('Unable to retrieve board %s information') % {'name':
|
||||||
board.name}
|
board.name}
|
||||||
|
|
|
@ -16,9 +16,9 @@ import horizon
|
||||||
|
|
||||||
|
|
||||||
class Iot(horizon.Dashboard):
|
class Iot(horizon.Dashboard):
|
||||||
name = _("Iot")
|
name = _("IoT")
|
||||||
slug = "iot"
|
slug = "iot"
|
||||||
panels = ('boards', 'plugins') # Add your panels here.
|
panels = ('boards', 'plugins', 'services') # Add your panels here.
|
||||||
|
|
||||||
# Specify the slug of the dashboard's default panel.
|
# Specify the slug of the dashboard's default panel.
|
||||||
default_panel = 'boards'
|
default_panel = 'boards'
|
||||||
|
|
|
@ -123,7 +123,7 @@ class InjectView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to inject plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -167,7 +167,7 @@ class StartView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to start plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -211,7 +211,7 @@ class StopView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to stop plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -255,7 +255,7 @@ class CallView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to call plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -299,7 +299,7 @@ class RemoveView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to remove plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -342,7 +342,7 @@ class UpdateView(forms.ModalFormView):
|
||||||
except Exception:
|
except Exception:
|
||||||
redirect = reverse("horizon:iot:plugins:index")
|
redirect = reverse("horizon:iot:plugins:index")
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_('Unable to update plugin.'),
|
_('Unable to get plugin information.'),
|
||||||
redirect=redirect)
|
redirect=redirect)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
# 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 CreateServiceForm(forms.SelfHandlingForm):
|
||||||
|
name = forms.CharField(label=_("Service Name"))
|
||||||
|
port = forms.IntegerField(
|
||||||
|
label=_("Port"),
|
||||||
|
help_text=_("Service port")
|
||||||
|
)
|
||||||
|
|
||||||
|
protocol = forms.ChoiceField(
|
||||||
|
label=_("Protocol"),
|
||||||
|
choices=[('TCP', _('TCP')), ('UDP', _('UDP'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-protocol'},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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."))
|
||||||
|
|
||||||
|
return service
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Unable to create service.'))
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateBoardForm(forms.SelfHandlingForm):
|
||||||
|
uuid = forms.CharField(label=_("Service ID"), widget=forms.HiddenInput)
|
||||||
|
name = forms.CharField(label=_("Service Name"))
|
||||||
|
port = forms.IntegerField(label=_("Port"))
|
||||||
|
protocol = forms.ChoiceField(
|
||||||
|
label=_("Protocol"),
|
||||||
|
choices=[('TCP', _('TCP')), ('UDP', _('UDP'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-protocol'},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
super(UpdateBoardForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Admin
|
||||||
|
if policy.check((("iot", "iot:update_services"),), self.request):
|
||||||
|
# LOG.debug("MELO 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")
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Other users
|
||||||
|
else:
|
||||||
|
if self.request.user.id != kwargs["initial"]["owner"]:
|
||||||
|
# LOG.debug("MELO IMMUTABLE FIELDS")
|
||||||
|
self.fields["name"].widget.attrs = {'readonly': 'readonly'}
|
||||||
|
self.fields["port"].widget.attrs = {'readonly': 'readonly'}
|
||||||
|
self.fields["protocol"].widget.attrs = {'readonly': 'readonly'}
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
iotronic.service_update(request, data["uuid"],
|
||||||
|
{"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.'))
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceActionForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
|
uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput)
|
||||||
|
|
||||||
|
name = forms.CharField(
|
||||||
|
label=_('Service 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=[('ServiceEnable', _('Enable')), ('ServiceDisable', _('Disable')), ('ServiceRestore', _('Restore'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-action'},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
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):
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
for board in data["board_list"]:
|
||||||
|
for key, value in self.fields["board_list"].choices:
|
||||||
|
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) + "."
|
||||||
|
messages.success(request, _(message_text))
|
||||||
|
|
||||||
|
if counter != len(data["board_list"]) - 1:
|
||||||
|
counter += 1
|
||||||
|
else:
|
||||||
|
return action
|
||||||
|
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))
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
# from openstack_dashboard.api import keystone
|
||||||
|
|
||||||
|
|
||||||
|
class Services(horizon.Panel):
|
||||||
|
name = _("Services")
|
||||||
|
slug = "services"
|
||||||
|
permissions = ('openstack.services.iot', )
|
||||||
|
# policy_rules = (("iot", "iot:list_all_services"),)
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
# 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 django.utils.translation import ungettext_lazy
|
||||||
|
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CreateServiceLink(tables.LinkAction):
|
||||||
|
name = "create"
|
||||||
|
verbose_name = _("Create Service")
|
||||||
|
url = "horizon:iot:services:create"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
# policy_rules = (("iot", "iot:create_service"),)
|
||||||
|
|
||||||
|
|
||||||
|
class EditBoardLink(tables.LinkAction):
|
||||||
|
name = "edit"
|
||||||
|
verbose_name = _("Edit")
|
||||||
|
url = "horizon:iot:services:update"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "pencil"
|
||||||
|
# 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")
|
||||||
|
url = "horizon:iot:services:action"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
# icon = "plus"
|
||||||
|
# policy_rules = (("iot", "iot:service_action"),)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteServicesAction(tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Service",
|
||||||
|
u"Delete Services",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Service",
|
||||||
|
u"Deleted Services",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
# policy_rules = (("iot", "iot:delete_service"),)
|
||||||
|
|
||||||
|
def delete(self, request, service_id):
|
||||||
|
api.iotronic.service_delete(request, service_id)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceFilterAction(tables.FilterAction):
|
||||||
|
|
||||||
|
def filter(self, table, services, filter_string):
|
||||||
|
# Naive case-insensitive search.
|
||||||
|
q = filter_string.lower()
|
||||||
|
return [service for service in services
|
||||||
|
if q in service.name.lower()]
|
||||||
|
|
||||||
|
|
||||||
|
class ServicesTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn('name', link="horizon:iot:services:detail",
|
||||||
|
verbose_name=_('Service Name'))
|
||||||
|
protocol = tables.Column('protocol', verbose_name=_('Protocol'))
|
||||||
|
port = tables.Column('port', verbose_name=_('Port'))
|
||||||
|
|
||||||
|
# Overriding get_object_id method because in IoT service the "id" is
|
||||||
|
# identified by the field UUID
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
return datum.uuid
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "services"
|
||||||
|
verbose_name = _("services")
|
||||||
|
row_actions = (EditBoardLink, ActionServiceLink,
|
||||||
|
DeleteServicesAction)
|
||||||
|
table_actions = (ServiceFilterAction, CreateServiceLink,
|
||||||
|
DeleteServicesAction)
|
||||||
|
|
||||||
|
# row_actions = (EditBoardLink, RemovePluginsLink, DeleteBoardsAction)
|
||||||
|
# table_actions = (BoardFilterAction, CreateBoardLink,
|
||||||
|
# DeleteBoardsAction)
|
|
@ -0,0 +1,40 @@
|
||||||
|
# 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/services/_detail_overview.html")
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
# coordinates = self.tab_group.kwargs['board'].__dict__["location"][0]
|
||||||
|
# LOG.debug('IOT INFO: %s', coordinates)
|
||||||
|
|
||||||
|
return {"service": self.tab_group.kwargs['service'],
|
||||||
|
"is_superuser": request.user.is_superuser}
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "service_details"
|
||||||
|
# tabs = (OverviewTab, LogTab, ConsoleTab, AuditTab)
|
||||||
|
tabs = (OverviewTab,)
|
||||||
|
sticky = True
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Execute action on board(s)." %}</p>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Add a new service." %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% load i18n sizeformat %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ service.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ service.uuid }}</dd>
|
||||||
|
<dt>{% trans "Protocol" %}</dt>
|
||||||
|
<dd>{{ service.protocol }}</dd>
|
||||||
|
<dt>{% trans "Port" %}</dt>
|
||||||
|
<dd>{{ service.port }}</dd>
|
||||||
|
<dt>{% trans "Extra" %}</dt>
|
||||||
|
<dd>{{ service.extra }}</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Remove service(s)." %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Edit the service's details." %}</p>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Execute Action" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/services/_action.html' %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Insert Service" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/services/_create.html' %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Services" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Remove service(s)." %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/services/_remove.html' %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Service" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/services/_update.html' %}
|
||||||
|
{% endblock %}
|
|
@ -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 ServicesTests(test.TestCase):
|
||||||
|
# Unit tests for boards.
|
||||||
|
def test_me(self):
|
||||||
|
self.assertTrue(1 + 1 == 2)
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from iotronic_ui.iot.services import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^create/$', views.CreateView.as_view(), name='create'),
|
||||||
|
url(r'^(?P<service_id>[^/]+)/update/$', views.UpdateView.as_view(),
|
||||||
|
name='update'),
|
||||||
|
url(r'^(?P<service_id>[^/]+)/action/$', views.ActionView.as_view(),
|
||||||
|
name='action'),
|
||||||
|
url(r'^(?P<service_id>[^/]+)/remove/$',
|
||||||
|
views.RemoveServicesView.as_view(), name='remove'),
|
||||||
|
url(r'^(?P<service_id>[^/]+)/detail/$', views.ServiceDetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
]
|
|
@ -0,0 +1,242 @@
|
||||||
|
# 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.services import forms as project_forms
|
||||||
|
from iotronic_ui.iot.services import tables as project_tables
|
||||||
|
from iotronic_ui.iot.services import tabs as project_tabs
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tables.DataTableView):
|
||||||
|
table_class = project_tables.ServicesTable
|
||||||
|
template_name = 'iot/services/index.html'
|
||||||
|
page_title = _("Services")
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
services = []
|
||||||
|
|
||||||
|
# Admin
|
||||||
|
if policy.check((("iot", "iot:list_all_services"),), self.request):
|
||||||
|
try:
|
||||||
|
services = iotronic.service_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve services list.'))
|
||||||
|
|
||||||
|
# Admin_iot_project
|
||||||
|
elif policy.check((("iot", "iot:list_project_services"),), self.request):
|
||||||
|
try:
|
||||||
|
services = iotronic.service_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve user services list.'))
|
||||||
|
|
||||||
|
# Other users
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
services = iotronic.service_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve user services list.'))
|
||||||
|
|
||||||
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
class CreateView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/services/create.html'
|
||||||
|
modal_header = _("Create Service")
|
||||||
|
form_id = "create_service_form"
|
||||||
|
form_class = project_forms.CreateServiceForm
|
||||||
|
submit_label = _("Create Service")
|
||||||
|
submit_url = reverse_lazy("horizon:iot:services:create")
|
||||||
|
success_url = reverse_lazy('horizon:iot:services:index')
|
||||||
|
page_title = _("Create Service")
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/services/update.html'
|
||||||
|
modal_header = _("Update Service")
|
||||||
|
form_id = "update_service_form"
|
||||||
|
form_class = project_forms.UpdateBoardForm
|
||||||
|
submit_label = _("Update Service")
|
||||||
|
submit_url = "horizon:iot:services:update"
|
||||||
|
success_url = reverse_lazy('horizon:iot:services:index')
|
||||||
|
page_title = _("Update 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(UpdateView, 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 ActionView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/services/action.html'
|
||||||
|
modal_header = _("Service Action")
|
||||||
|
form_id = "service_action_form"
|
||||||
|
form_class = project_forms.ServiceActionForm
|
||||||
|
submit_label = _("Service Action")
|
||||||
|
# submit_url = reverse_lazy("horizon:iot:services:action")
|
||||||
|
submit_url = "horizon:iot:services:action"
|
||||||
|
success_url = reverse_lazy('horizon:iot:services:index')
|
||||||
|
page_title = _("Service Action")
|
||||||
|
|
||||||
|
@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(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):
|
||||||
|
service = 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': service.uuid,
|
||||||
|
'name': service.name,
|
||||||
|
'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'
|
||||||
|
page_title = "{{ service.name|default:service.uuid }}"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
service = self.get_data()
|
||||||
|
context["service"] = service
|
||||||
|
context["url"] = reverse(self.redirect_url)
|
||||||
|
context["actions"] = self._get_actions(service)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def _get_actions(self, service):
|
||||||
|
table = project_tables.ServicesTable(self.request)
|
||||||
|
return table.render_row_actions(service)
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
service_id = self.kwargs['service_id']
|
||||||
|
try:
|
||||||
|
service = iotronic.service_get(self.request, service_id, None)
|
||||||
|
except Exception:
|
||||||
|
msg = ('Unable to retrieve service %s information') % {'name':
|
||||||
|
service.name}
|
||||||
|
exceptions.handle(self.request, msg, ignore=True)
|
||||||
|
return service
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
service = self.get_data()
|
||||||
|
return self.tab_group_class(request, service=service, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceDetailView(DetailView):
|
||||||
|
redirect_url = 'horizon:iot:services:index'
|
||||||
|
|
||||||
|
def _get_actions(self, service):
|
||||||
|
table = project_tables.ServicesTable(self.request)
|
||||||
|
return table.render_row_actions(service)
|
Loading…
Reference in New Issue