Added fleet management
Change-Id: I414fdbb331e2617f67bdae88f8daaa2915dc8926
This commit is contained in:
parent
b7180183a3
commit
3c7c817ea1
|
@ -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 = 'fleets'
|
||||||
|
# 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.fleets.panel.Fleets'
|
|
@ -81,6 +81,14 @@ class CreateBoardForm(forms.SelfHandlingForm):
|
||||||
class UpdateBoardForm(forms.SelfHandlingForm):
|
class UpdateBoardForm(forms.SelfHandlingForm):
|
||||||
uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput)
|
uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput)
|
||||||
name = forms.CharField(label=_("Board Name"))
|
name = forms.CharField(label=_("Board Name"))
|
||||||
|
|
||||||
|
fleet_list = forms.ChoiceField(
|
||||||
|
label=_("Fleets List"),
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-fleet'}),
|
||||||
|
help_text=_("Select fleet in this pool ")
|
||||||
|
)
|
||||||
|
|
||||||
mobile = forms.BooleanField(label=_("Mobile"), required=False)
|
mobile = forms.BooleanField(label=_("Mobile"), required=False)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -92,6 +100,7 @@ class UpdateBoardForm(forms.SelfHandlingForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
super(UpdateBoardForm, self).__init__(*args, **kwargs)
|
super(UpdateBoardForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields["fleet_list"].choices = kwargs["initial"]["fleet_list"]
|
||||||
|
|
||||||
# LOG.debug("INITIAL: %s", kwargs["initial"])
|
# LOG.debug("INITIAL: %s", kwargs["initial"])
|
||||||
|
|
||||||
|
@ -117,6 +126,8 @@ class UpdateBoardForm(forms.SelfHandlingForm):
|
||||||
# LOG.debug("IMMUTABLE FIELDS")
|
# LOG.debug("IMMUTABLE FIELDS")
|
||||||
self.fields["name"].widget.attrs = {'readonly': 'readonly'}
|
self.fields["name"].widget.attrs = {'readonly': 'readonly'}
|
||||||
self.fields["mobile"].widget.attrs = {'disabled': 'disabled'}
|
self.fields["mobile"].widget.attrs = {'disabled': 'disabled'}
|
||||||
|
self.fields["fleet_list"].widget.attrs = {'disabled':
|
||||||
|
'disabled'}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.fields["latitude"].widget.attrs = {'readonly':
|
self.fields["latitude"].widget.attrs = {'readonly':
|
||||||
|
@ -128,19 +139,20 @@ class UpdateBoardForm(forms.SelfHandlingForm):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
"""
|
# data["location"] = [{"latitude": str(data["latitude"]),
|
||||||
data["location"] = [{"latitude": str(data["latitude"]),
|
# "longitude": str(data["longitude"]),
|
||||||
"longitude": str(data["longitude"]),
|
# "altitude": str(data["altitude"])}]
|
||||||
"altitude": str(data["altitude"])}]
|
# iotronic.board_update(request, data["uuid"],
|
||||||
iotronic.board_update(request, data["uuid"],
|
# {"name": data["name"],
|
||||||
{"name": data["name"],
|
# "mobile": data["mobile"],
|
||||||
"mobile": data["mobile"],
|
# "location": data["location"]})
|
||||||
"location": data["location"]})
|
|
||||||
"""
|
|
||||||
iotronic.board_update(request, data["uuid"],
|
iotronic.board_update(request, data["uuid"],
|
||||||
{"name": data["name"],
|
{"name": data["name"],
|
||||||
|
"fleet": data["fleet_list"],
|
||||||
"mobile": data["mobile"]})
|
"mobile": data["mobile"]})
|
||||||
messages.success(request, _("Board updated successfully."))
|
messages.success(request, _("Board updated successfully."))
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -21,7 +21,7 @@ from iotronic_ui.iot import dashboard
|
||||||
class Boards(horizon.Panel):
|
class Boards(horizon.Panel):
|
||||||
name = _("Boards")
|
name = _("Boards")
|
||||||
slug = "boards"
|
slug = "boards"
|
||||||
permissions = ('openstack.services.iot', )
|
# permissions = ('openstack.services.iot', )
|
||||||
# policy_rules = (("iot", "iot:list_all_boards"),)
|
# policy_rules = (("iot", "iot:list_all_boards"),)
|
||||||
|
|
||||||
# TO BE REMOVED
|
# TO BE REMOVED
|
||||||
|
|
|
@ -175,6 +175,7 @@ class BoardsTable(tables.DataTable):
|
||||||
type = tables.Column('type', verbose_name=_('Type'))
|
type = tables.Column('type', verbose_name=_('Type'))
|
||||||
# mobile = tables.Column('mobile', verbose_name=_('Mobile'))
|
# mobile = tables.Column('mobile', verbose_name=_('Mobile'))
|
||||||
uuid = tables.Column('uuid', verbose_name=_('Board ID'))
|
uuid = tables.Column('uuid', verbose_name=_('Board ID'))
|
||||||
|
fleet = tables.Column('fleet', verbose_name=_('Fleet 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'))
|
||||||
|
|
|
@ -1,28 +1,33 @@
|
||||||
{% load i18n sizeformat %}
|
{% load i18n sizeformat %}
|
||||||
|
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>{% trans "Name" %}</dt>
|
<h4>{% trans "Info" %}</h4>
|
||||||
<dd>{{ board.name }}</dd>
|
<hr class="header_rule">
|
||||||
<dt>{% trans "Status" %}</dt>
|
<dl class="dl-horizontal">
|
||||||
<dd>{{ board.status }}</dd>
|
<dt>{% trans "Name" %}</dt>
|
||||||
<dt>{% trans "Type" %}</dt>
|
<dd>{{ board.name }}</dd>
|
||||||
<dd>{{ board.type }}</dd>
|
<dt>{% trans "Status" %}</dt>
|
||||||
<dt>{% trans "ID" %}</dt>
|
<dd>{{ board.status }}</dd>
|
||||||
<dd>{{ board.uuid }}</dd>
|
<dt>{% trans "Type" %}</dt>
|
||||||
<dt>{% trans "Code" %}</dt>
|
<dd>{{ board.type }}</dd>
|
||||||
<dd>{{ board.code }}</dd>
|
<dt>{% trans "ID" %}</dt>
|
||||||
<dt>{% trans "Creation data" %}</dt>
|
<dd>{{ board.uuid }}</dd>
|
||||||
<dd>{{ board.created_at }}</dd>
|
<dt>{% trans "Code" %}</dt>
|
||||||
<dt>{% trans "Location" %}</dt>
|
<dd>{{ board.code }}</dd>
|
||||||
<dd>Latitude: {{ coordinates.latitude }}</dd>
|
<dt>{% trans "Creation data" %}</dt>
|
||||||
<dd>Longitude: {{ coordinates.longitude }}</dd>
|
<dd>{{ board.created_at }}</dd>
|
||||||
<dd>Altitude: {{ coordinates.altitude }}</dd>
|
<dt>{% trans "Location" %}</dt>
|
||||||
<dt>{% trans "Mobile" %}</dt>
|
<dd>Latitude: {{ coordinates.latitude }}</dd>
|
||||||
<dd>{{ board.mobile }}</dd>
|
<dd>Longitude: {{ coordinates.longitude }}</dd>
|
||||||
<dt>{% trans "Extra" %}</dt>
|
<dd>Altitude: {{ coordinates.altitude }}</dd>
|
||||||
<dd>{{ board.extra }}</dd>
|
<dt>{% trans "Mobile" %}</dt>
|
||||||
</dl>
|
<dd>{{ board.mobile }}</dd>
|
||||||
|
<dt>{% trans "Extra" %}</dt>
|
||||||
|
<dd>{{ board.extra }}</dd>
|
||||||
|
<dt>{% trans "Fleet ID" %}</dt>
|
||||||
|
<dd>{{ board.fleet }}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
<h4>{% trans "Ports" %}</h4>
|
<h4>{% trans "Ports" %}</h4>
|
||||||
<hr class="header_rule">
|
<hr class="header_rule">
|
||||||
|
@ -61,7 +66,7 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<dd>--</dd>
|
<dd>--</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--<div id="mapdiv" style="min-height:300px; margin-bottom: 10px;" data-coordinates='[{"latitude": "{{ coordinates.latitude }}", "longitude": "{{ coordinates.longitude }}", "altitude": "{{ coordinates.altitude }}"}]'>-->
|
<!--<div id="mapdiv" style="min-height:300px; margin-bottom: 10px;" data-coordinates='[{"latitude": "{{ coordinates.latitude }}", "longitude": "{{ coordinates.longitude }}", "altitude": "{{ coordinates.altitude }}"}]'>-->
|
||||||
|
|
|
@ -123,10 +123,19 @@ class UpdateView(forms.ModalFormView):
|
||||||
board = self.get_object()
|
board = self.get_object()
|
||||||
location = board.location[0]
|
location = board.location[0]
|
||||||
|
|
||||||
|
# Populate fleets
|
||||||
|
fleets = api.iotronic.fleet_list(self.request, None)
|
||||||
|
fleets.sort(key=lambda b: b.name)
|
||||||
|
|
||||||
|
fleet_list = []
|
||||||
|
for fleet in fleets:
|
||||||
|
fleet_list.append((fleet.uuid, _(fleet.name)))
|
||||||
|
|
||||||
return {'uuid': board.uuid,
|
return {'uuid': board.uuid,
|
||||||
'name': board.name,
|
'name': board.name,
|
||||||
'mobile': board.mobile,
|
'mobile': board.mobile,
|
||||||
'owner': board.owner,
|
'owner': board.owner,
|
||||||
|
'fleet_list': fleet_list,
|
||||||
'latitude': location["latitude"],
|
'latitude': location["latitude"],
|
||||||
'longitude': location["longitude"],
|
'longitude': location["longitude"],
|
||||||
'altitude': location["altitude"]}
|
'altitude': location["altitude"]}
|
||||||
|
@ -461,6 +470,9 @@ class DetailView(tabs.TabView):
|
||||||
|
|
||||||
@memoized.memoized_method
|
@memoized.memoized_method
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
|
|
||||||
|
board = []
|
||||||
|
|
||||||
board_id = self.kwargs['board_id']
|
board_id = self.kwargs['board_id']
|
||||||
try:
|
try:
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import horizon
|
||||||
class Iot(horizon.Dashboard):
|
class Iot(horizon.Dashboard):
|
||||||
name = _("IoT")
|
name = _("IoT")
|
||||||
slug = "iot"
|
slug = "iot"
|
||||||
panels = ('boards', 'plugins', 'services') # Add your panels here.
|
panels = ('boards', 'plugins', 'services', 'fleets') # 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'
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
# 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 CreateFleetForm(forms.SelfHandlingForm):
|
||||||
|
name = forms.CharField(label=_("Fleet Name"))
|
||||||
|
|
||||||
|
description = forms.CharField(
|
||||||
|
label=_("Description"),
|
||||||
|
widget=forms.Textarea(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-description'})
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
iotronic.fleet_create(request, data["name"],
|
||||||
|
data["description"])
|
||||||
|
|
||||||
|
messages.success(request, _("Fleet " + str(data["name"]) +
|
||||||
|
" created successfully."))
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Unable to create fleet.'))
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateFleetForm(forms.SelfHandlingForm):
|
||||||
|
uuid = forms.CharField(label=_("Fleet ID"), widget=forms.HiddenInput)
|
||||||
|
name = forms.CharField(label=_("Fleet Name"))
|
||||||
|
description = forms.CharField(
|
||||||
|
label=_("Description"),
|
||||||
|
widget=forms.Textarea(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-description'})
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
super(UpdateFleetForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Admin
|
||||||
|
if policy.check((("iot", "iot:update_fleets"),), self.request):
|
||||||
|
# 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("NO-edit IOT ADMIN")
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Other users
|
||||||
|
else:
|
||||||
|
if self.request.user.id != kwargs["initial"]["owner"]:
|
||||||
|
# LOG.debug("IMMUTABLE FIELDS")
|
||||||
|
self.fields["name"].widget.attrs = {'readonly': 'readonly'}
|
||||||
|
self.fields["description"].widget.attrs = {'readonly': 'readonly'}
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
try:
|
||||||
|
iotronic.fleet_update(request, data["uuid"],
|
||||||
|
{"name": data["name"],
|
||||||
|
"description": data["description"]})
|
||||||
|
|
||||||
|
messages.success(request, _("Fleet updated successfully."))
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Unable to update fleet.'))
|
||||||
|
|
||||||
|
|
||||||
|
class FleetActionForm(forms.SelfHandlingForm):
|
||||||
|
|
||||||
|
uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput)
|
||||||
|
|
||||||
|
name = forms.CharField(
|
||||||
|
label=_('Fleet Name'),
|
||||||
|
widget=forms.TextInput(attrs={'readonly': 'readonly'})
|
||||||
|
)
|
||||||
|
|
||||||
|
board_list = forms.MultipleChoiceField(
|
||||||
|
label=_("Boards List"),
|
||||||
|
widget=forms.SelectMultiple(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-select-boards'}),
|
||||||
|
help_text=_("Select boards in this pool")
|
||||||
|
)
|
||||||
|
|
||||||
|
action = forms.ChoiceField(
|
||||||
|
label=_("Action"),
|
||||||
|
choices=[('FleetEnable', _('Enable')),
|
||||||
|
('FleetDisable', _('Disable')),
|
||||||
|
('FleetRestore', _('Restore'))],
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'class': 'switchable', 'data-slug': 'slug-action'},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
super(FleetActionForm, self).__init__(*args, **kwargs)
|
||||||
|
# input=kwargs.get('initial',{})
|
||||||
|
|
||||||
|
self.fields["board_list"].choices = kwargs["initial"]["board_list"]
|
||||||
|
|
||||||
|
def handle(self, request, data):
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
for board in data["board_list"]:
|
||||||
|
for key, value in self.fields["board_list"].choices:
|
||||||
|
if key == board:
|
||||||
|
|
||||||
|
try:
|
||||||
|
action = iotronic.fleet_action(request, key,
|
||||||
|
data["uuid"],
|
||||||
|
data["action"])
|
||||||
|
message_text = action
|
||||||
|
messages.success(request, _(message_text))
|
||||||
|
|
||||||
|
if counter != len(data["board_list"]) - 1:
|
||||||
|
counter += 1
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
message_text = "Unable to execute action on board " \
|
||||||
|
+ str(value) + "."
|
||||||
|
exceptions.handle(request, _(message_text))
|
||||||
|
|
||||||
|
break
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
import horizon
|
||||||
|
|
||||||
|
# from openstack_dashboard.api import keystone
|
||||||
|
from iotronic_ui.iot import dashboard
|
||||||
|
|
||||||
|
|
||||||
|
class Fleets(horizon.Panel):
|
||||||
|
name = _("Fleets")
|
||||||
|
slug = "fleets"
|
||||||
|
# permissions = ('openstack.fleets.iot', )
|
||||||
|
# policy_rules = (("iot", "iot:list_all_fleets"),)
|
||||||
|
|
||||||
|
|
||||||
|
dashboard.Iot.register(Fleets)
|
|
@ -0,0 +1,99 @@
|
||||||
|
# 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 CreateFleetLink(tables.LinkAction):
|
||||||
|
name = "create"
|
||||||
|
verbose_name = _("Create Fleet")
|
||||||
|
url = "horizon:iot:fleets:create"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "plus"
|
||||||
|
# policy_rules = (("iot", "iot:create_fleet"),)
|
||||||
|
|
||||||
|
|
||||||
|
class EditFleetLink(tables.LinkAction):
|
||||||
|
name = "edit"
|
||||||
|
verbose_name = _("Edit")
|
||||||
|
url = "horizon:iot:fleets:update"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
icon = "pencil"
|
||||||
|
# policy_rules = (("iot", "iot:update_fleet"),)
|
||||||
|
|
||||||
|
|
||||||
|
class ActionFleetLink(tables.LinkAction):
|
||||||
|
name = "action"
|
||||||
|
verbose_name = _("Fleet Action")
|
||||||
|
url = "horizon:iot:fleets:action"
|
||||||
|
classes = ("ajax-modal",)
|
||||||
|
# icon = "plus"
|
||||||
|
# policy_rules = (("iot", "iot:fleet_action"),)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteFleetsAction(tables.DeleteAction):
|
||||||
|
@staticmethod
|
||||||
|
def action_present(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Delete Fleet",
|
||||||
|
u"Delete Fleets",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def action_past(count):
|
||||||
|
return ungettext_lazy(
|
||||||
|
u"Deleted Fleet",
|
||||||
|
u"Deleted Fleets",
|
||||||
|
count
|
||||||
|
)
|
||||||
|
# policy_rules = (("iot", "iot:delete_fleet"),)
|
||||||
|
|
||||||
|
def delete(self, request, fleet_id):
|
||||||
|
api.iotronic.fleet_delete(request, fleet_id)
|
||||||
|
|
||||||
|
|
||||||
|
class FleetFilterAction(tables.FilterAction):
|
||||||
|
|
||||||
|
def filter(self, table, fleets, filter_string):
|
||||||
|
# Naive case-insensitive search.
|
||||||
|
q = filter_string.lower()
|
||||||
|
return [fleet for fleet in fleets
|
||||||
|
if q in fleet.name.lower()]
|
||||||
|
|
||||||
|
|
||||||
|
class FleetsTable(tables.DataTable):
|
||||||
|
name = tables.WrappingColumn('name', link="horizon:iot:fleets:detail",
|
||||||
|
verbose_name=_('Fleet Name'))
|
||||||
|
description = tables.Column('description', verbose_name=_('Description'))
|
||||||
|
|
||||||
|
# Overriding get_object_id method because in IoT fleet the "id" is
|
||||||
|
# identified by the field UUID
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
return datum.uuid
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "fleets"
|
||||||
|
verbose_name = _("fleets")
|
||||||
|
row_actions = (EditFleetLink, ActionFleetLink,
|
||||||
|
DeleteFleetsAction)
|
||||||
|
table_actions = (FleetFilterAction, CreateFleetLink,
|
||||||
|
DeleteFleetsAction)
|
|
@ -0,0 +1,43 @@
|
||||||
|
# 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/fleets/_detail_overview.html")
|
||||||
|
|
||||||
|
def get_context_data(self, request):
|
||||||
|
# coordinates = self.tab_group.kwargs['board'].__dict__["location"][0]
|
||||||
|
# LOG.debug('IOT INFO: %s', coordinates)
|
||||||
|
|
||||||
|
boards = self.tab_group.kwargs['fleet']._info['boards']
|
||||||
|
|
||||||
|
return {"fleet": self.tab_group.kwargs['fleet'],
|
||||||
|
"boards": boards,
|
||||||
|
"is_superuser": request.user.is_superuser}
|
||||||
|
|
||||||
|
|
||||||
|
class FleetDetailTabs(tabs.TabGroup):
|
||||||
|
slug = "fleet_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 fleet." %}</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
{% load i18n sizeformat %}
|
||||||
|
|
||||||
|
<div class="detail">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Name" %}</dt>
|
||||||
|
<dd>{{ fleet.name }}</dd>
|
||||||
|
<dt>{% trans "ID" %}</dt>
|
||||||
|
<dd>{{ fleet.uuid }}</dd>
|
||||||
|
<dt>{% trans "Description" %}</dt>
|
||||||
|
<dd>{{ fleet.description }}</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h4>{% trans "Boards" %}</h4>
|
||||||
|
<hr class="header_rule">
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
{% if boards %}
|
||||||
|
{% for board in boards %}
|
||||||
|
<dt>{{ board.name }}</dt>
|
||||||
|
<dd>{{ board.uuid }}</dd>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<dd>--</dd>
|
||||||
|
{% endif %}
|
||||||
|
</dl>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block modal-body-right %}
|
||||||
|
<h3>{% trans "Description:" %}</h3>
|
||||||
|
<p>{% trans "Edit the fleet's details." %}</p>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Execute Action" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/fleets/_action.html' %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Insert Fleet" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/fleets/_create.html' %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Fleets" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{{ table.render }}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Update Fleet" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include 'iot/fleets/_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 FleetsTests(test.TestCase):
|
||||||
|
# Unit tests for boards.
|
||||||
|
def test_me(self):
|
||||||
|
self.assertTrue(1 + 1 == 2)
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 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.fleets import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
|
url(r'^create/$', views.CreateView.as_view(), name='create'),
|
||||||
|
url(r'^(?P<fleet_id>[^/]+)/update/$', views.UpdateView.as_view(),
|
||||||
|
name='update'),
|
||||||
|
url(r'^(?P<fleet_id>[^/]+)/action/$', views.ActionView.as_view(),
|
||||||
|
name='action'),
|
||||||
|
url(r'^(?P<fleet_id>[^/]+)/detail/$', views.FleetDetailView.as_view(),
|
||||||
|
name='detail'),
|
||||||
|
]
|
|
@ -0,0 +1,220 @@
|
||||||
|
# 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.fleets import forms as project_forms
|
||||||
|
from iotronic_ui.iot.fleets import tables as project_tables
|
||||||
|
from iotronic_ui.iot.fleets import tabs as project_tabs
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class IndexView(tables.DataTableView):
|
||||||
|
table_class = project_tables.FleetsTable
|
||||||
|
template_name = 'iot/fleets/index.html'
|
||||||
|
page_title = _("Fleets")
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
fleets = []
|
||||||
|
|
||||||
|
# Admin
|
||||||
|
if policy.check((("iot", "iot:list_all_fleets"),), self.request):
|
||||||
|
try:
|
||||||
|
fleets = iotronic.fleet_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve fleets list.'))
|
||||||
|
|
||||||
|
# Admin_iot_project
|
||||||
|
elif policy.check((("iot", "iot:list_project_fleets"),),
|
||||||
|
self.request):
|
||||||
|
try:
|
||||||
|
fleets = iotronic.fleet_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve user fleets list.'))
|
||||||
|
|
||||||
|
# Other users
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
fleets = iotronic.fleet_list(self.request, None)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to retrieve user fleets list.'))
|
||||||
|
|
||||||
|
return fleets
|
||||||
|
|
||||||
|
|
||||||
|
class CreateView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/fleets/create.html'
|
||||||
|
modal_header = _("Create Fleet")
|
||||||
|
form_id = "create_fleet_form"
|
||||||
|
form_class = project_forms.CreateFleetForm
|
||||||
|
submit_label = _("Create Fleet")
|
||||||
|
submit_url = reverse_lazy("horizon:iot:fleets:create")
|
||||||
|
success_url = reverse_lazy('horizon:iot:fleets:index')
|
||||||
|
page_title = _("Create Fleet")
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/fleets/update.html'
|
||||||
|
modal_header = _("Update Fleet")
|
||||||
|
form_id = "update_fleet_form"
|
||||||
|
form_class = project_forms.UpdateFleetForm
|
||||||
|
submit_label = _("Update Fleet")
|
||||||
|
submit_url = "horizon:iot:fleets:update"
|
||||||
|
success_url = reverse_lazy('horizon:iot:fleets:index')
|
||||||
|
page_title = _("Update Fleet")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_object(self):
|
||||||
|
try:
|
||||||
|
return iotronic.fleet_get(self.request,
|
||||||
|
self.kwargs['fleet_id'],
|
||||||
|
None)
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse("horizon:iot:fleets:index")
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to get fleet information.'),
|
||||||
|
redirect=redirect)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(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):
|
||||||
|
fleet = self.get_object()
|
||||||
|
|
||||||
|
return {'uuid': fleet.uuid,
|
||||||
|
'name': fleet.name,
|
||||||
|
'description': fleet.description}
|
||||||
|
|
||||||
|
|
||||||
|
class ActionView(forms.ModalFormView):
|
||||||
|
template_name = 'iot/fleets/action.html'
|
||||||
|
modal_header = _("Fleet Action")
|
||||||
|
form_id = "fleet_action_form"
|
||||||
|
form_class = project_forms.FleetActionForm
|
||||||
|
submit_label = _("Fleet Action")
|
||||||
|
# submit_url = reverse_lazy("horizon:iot:fleets:action")
|
||||||
|
submit_url = "horizon:iot:fleets:action"
|
||||||
|
success_url = reverse_lazy('horizon:iot:fleets:index')
|
||||||
|
page_title = _("Fleet Action")
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_object(self):
|
||||||
|
try:
|
||||||
|
return iotronic.fleet_get(self.request,
|
||||||
|
self.kwargs['fleet_id'],
|
||||||
|
None)
|
||||||
|
except Exception:
|
||||||
|
redirect = reverse("horizon:iot:fleets:index")
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_('Unable to get fleet information.'),
|
||||||
|
redirect=redirect)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ActionView, self).get_context_data(**kwargs)
|
||||||
|
args = (self.get_object().uuid,)
|
||||||
|
context['submit_url'] = reverse(self.submit_url, args=args)
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
fleet = self.get_object()
|
||||||
|
|
||||||
|
# Populate boards
|
||||||
|
boards = iotronic.board_list(self.request, "online", None, None)
|
||||||
|
boards.sort(key=lambda b: b.name)
|
||||||
|
|
||||||
|
board_list = []
|
||||||
|
for board in boards:
|
||||||
|
board_list.append((board.uuid, _(board.name)))
|
||||||
|
|
||||||
|
return {'uuid': fleet.uuid,
|
||||||
|
'name': fleet.name,
|
||||||
|
'board_list': board_list}
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(tabs.TabView):
|
||||||
|
tab_group_class = project_tabs.FleetDetailTabs
|
||||||
|
template_name = 'horizon/common/_detail.html'
|
||||||
|
page_title = "{{ fleet.name|default:fleet.uuid }}"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(DetailView, self).get_context_data(**kwargs)
|
||||||
|
fleet = self.get_data()
|
||||||
|
context["fleet"] = fleet
|
||||||
|
context["url"] = reverse(self.redirect_url)
|
||||||
|
context["actions"] = self._get_actions(fleet)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def _get_actions(self, fleet):
|
||||||
|
table = project_tables.FleetsTable(self.request)
|
||||||
|
return table.render_row_actions(fleet)
|
||||||
|
|
||||||
|
@memoized.memoized_method
|
||||||
|
def get_data(self):
|
||||||
|
fleet = []
|
||||||
|
fleet_boards = []
|
||||||
|
|
||||||
|
fleet_id = self.kwargs['fleet_id']
|
||||||
|
try:
|
||||||
|
fleet = iotronic.fleet_get(self.request, fleet_id, None)
|
||||||
|
boards = iotronic.fleet_get_boards(self.request, fleet_id)
|
||||||
|
|
||||||
|
LOG.debug('XXXX: %s', boards)
|
||||||
|
|
||||||
|
for board in boards:
|
||||||
|
fleet_boards.append(board._info)
|
||||||
|
|
||||||
|
fleet._info.update(dict(boards=fleet_boards))
|
||||||
|
# LOG.debug('FLEET COMPLETE: %s', fleet)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
s = fleet.name
|
||||||
|
msg = ('Unable to retrieve fleet %s information') % {'name': s}
|
||||||
|
exceptions.handle(self.request, msg, ignore=True)
|
||||||
|
return fleet
|
||||||
|
|
||||||
|
def get_tabs(self, request, *args, **kwargs):
|
||||||
|
fleet = self.get_data()
|
||||||
|
return self.tab_group_class(request, fleet=fleet, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class FleetDetailView(DetailView):
|
||||||
|
redirect_url = 'horizon:iot:fleets:index'
|
||||||
|
|
||||||
|
def _get_actions(self, fleet):
|
||||||
|
table = project_tables.FleetsTable(self.request)
|
||||||
|
return table.render_row_actions(fleet)
|
|
@ -9,7 +9,8 @@
|
||||||
# PBR should always appear first
|
# PBR should always appear first
|
||||||
pbr>=2.0.0,!=2.1.0 # Apache-2.0
|
pbr>=2.0.0,!=2.1.0 # Apache-2.0
|
||||||
Babel>=2.3.4,!=2.4.0 # BSD
|
Babel>=2.3.4,!=2.4.0 # BSD
|
||||||
Django>=1.8,<2.0 # BSD
|
Django<2,>=1.11;python_version<'3.0' # BSD
|
||||||
django-babel>=0.5.1 # BSD
|
Django<2.1,>=1.11;python_version>='3.0' # BSD
|
||||||
|
django-babel>=0.6.2 # BSD
|
||||||
django-compressor>=2.0 # MIT
|
django-compressor>=2.0 # MIT
|
||||||
django-pyscss>=2.0.2 # BSD License (2 clause)
|
django-pyscss>=2.0.2 # BSD License (2 clause)
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
# PBR should always appear first
|
# PBR should always appear first
|
||||||
pbr>=2.0.0,!=2.1.0 # Apache-2.0
|
pbr>=2.0.0,!=2.1.0 # Apache-2.0
|
||||||
Babel>=2.3.4,!=2.4.0 # BSD
|
Babel>=2.3.4,!=2.4.0 # BSD
|
||||||
Django>=1.8,<2.0 # BSD
|
Django<2,>=1.11;python_version<'3.0' # BSD
|
||||||
django-babel>=0.5.1 # BSD
|
Django<2.1,>=1.11;python_version>='3.0' # BSD
|
||||||
|
django-babel>=0.6.2 # BSD
|
||||||
django-compressor>=2.0 # MIT
|
django-compressor>=2.0 # MIT
|
||||||
django-pyscss>=2.0.2 # BSD License (2 clause)
|
django-pyscss>=2.0.2 # BSD License (2 clause)
|
||||||
|
|
Loading…
Reference in New Issue