Browse Source

Added fleet management

Change-Id: I414fdbb331e2617f67bdae88f8daaa2915dc8926
Carmelo Romeo 6 months ago
parent
commit
3c7c817ea1

+ 23
- 0
iotronic_ui/enabled/_6040_iot_fleets_panel.py View File

@@ -0,0 +1,23 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License");
2
+# you may not use this file except in compliance with the License.
3
+# You may obtain a copy of the License at
4
+#
5
+#    http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS,
9
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+# See the License for the specific language governing permissions and
11
+# limitations under the License.
12
+
13
+# The slug of the panel to be added to HORIZON_CONFIG. Required.
14
+PANEL = 'fleets'
15
+# The slug of the dashboard the PANEL associated with. Required.
16
+PANEL_DASHBOARD = 'iot'
17
+# The slug of the panel group the PANEL is associated with.
18
+PANEL_GROUP = 'iot'
19
+# If set, it will update the default panel of the PANEL_DASHBOARD.
20
+DEFAULT_PANEL = ''
21
+
22
+# Python panel class of the PANEL to be added.
23
+ADD_PANEL = 'iotronic_ui.iot.fleets.panel.Fleets'

+ 21
- 9
iotronic_ui/iot/boards/forms.py View File

@@ -81,6 +81,14 @@ class CreateBoardForm(forms.SelfHandlingForm):
81 81
 class UpdateBoardForm(forms.SelfHandlingForm):
82 82
     uuid = forms.CharField(label=_("Board ID"), widget=forms.HiddenInput)
83 83
     name = forms.CharField(label=_("Board Name"))
84
+    
85
+    fleet_list = forms.ChoiceField(
86
+        label=_("Fleets List"),
87
+        widget=forms.Select(
88
+            attrs={'class': 'switchable', 'data-slug': 'slug-fleet'}),
89
+        help_text=_("Select fleet in this pool ")
90
+    )
91
+
84 92
     mobile = forms.BooleanField(label=_("Mobile"), required=False)
85 93
 
86 94
     """
@@ -92,6 +100,7 @@ class UpdateBoardForm(forms.SelfHandlingForm):
92 100
     def __init__(self, *args, **kwargs):
93 101
 
94 102
         super(UpdateBoardForm, self).__init__(*args, **kwargs)
103
+        self.fields["fleet_list"].choices = kwargs["initial"]["fleet_list"]
95 104
 
96 105
         # LOG.debug("INITIAL: %s", kwargs["initial"])
97 106
 
@@ -117,6 +126,8 @@ class UpdateBoardForm(forms.SelfHandlingForm):
117 126
                 # LOG.debug("IMMUTABLE FIELDS")
118 127
                 self.fields["name"].widget.attrs = {'readonly': 'readonly'}
119 128
                 self.fields["mobile"].widget.attrs = {'disabled': 'disabled'}
129
+                self.fields["fleet_list"].widget.attrs = {'disabled':
130
+                                                          'disabled'}
120 131
 
121 132
                 """
122 133
                 self.fields["latitude"].widget.attrs = {'readonly':
@@ -128,19 +139,20 @@ class UpdateBoardForm(forms.SelfHandlingForm):
128 139
                 """
129 140
 
130 141
     def handle(self, request, data):
142
+
131 143
         try:
132 144
 
133
-            """
134
-            data["location"] = [{"latitude": str(data["latitude"]),
135
-                                 "longitude": str(data["longitude"]),
136
-                                 "altitude": str(data["altitude"])}]
137
-            iotronic.board_update(request, data["uuid"],
138
-                                  {"name": data["name"],
139
-                                   "mobile": data["mobile"],
140
-                                   "location": data["location"]})
141
-            """
145
+            # data["location"] = [{"latitude": str(data["latitude"]),
146
+            #                      "longitude": str(data["longitude"]),
147
+            #                      "altitude": str(data["altitude"])}]
148
+            # iotronic.board_update(request, data["uuid"],
149
+            #                       {"name": data["name"],
150
+            #                        "mobile": data["mobile"],
151
+            #                        "location": data["location"]})
152
+
142 153
             iotronic.board_update(request, data["uuid"],
143 154
                                   {"name": data["name"],
155
+                                   "fleet": data["fleet_list"],
144 156
                                    "mobile": data["mobile"]})
145 157
             messages.success(request, _("Board updated successfully."))
146 158
             return True

+ 1
- 1
iotronic_ui/iot/boards/panel.py View File

@@ -21,7 +21,7 @@ from iotronic_ui.iot import dashboard
21 21
 class Boards(horizon.Panel):
22 22
     name = _("Boards")
23 23
     slug = "boards"
24
-    permissions = ('openstack.services.iot', )
24
+    # permissions = ('openstack.services.iot', )
25 25
     # policy_rules = (("iot", "iot:list_all_boards"),)
26 26
 
27 27
     # TO BE REMOVED

+ 1
- 0
iotronic_ui/iot/boards/tables.py View File

@@ -175,6 +175,7 @@ class BoardsTable(tables.DataTable):
175 175
     type = tables.Column('type', verbose_name=_('Type'))
176 176
     # mobile = tables.Column('mobile', verbose_name=_('Mobile'))
177 177
     uuid = tables.Column('uuid', verbose_name=_('Board ID'))
178
+    fleet = tables.Column('fleet', verbose_name=_('Fleet ID'))
178 179
     # code = tables.Column('code', verbose_name=_('Code'))
179 180
     status = tables.Column('status', verbose_name=_('Status'))
180 181
     # location = tables.Column('location', verbose_name=_('Geo'))

+ 28
- 23
iotronic_ui/iot/boards/templates/boards/_detail_overview.html View File

@@ -1,28 +1,33 @@
1 1
 {% load i18n sizeformat %}
2 2
 
3 3
 <div class="detail">
4
-  <dl class="dl-horizontal">
5
-    <dt>{% trans "Name" %}</dt>
6
-    <dd>{{ board.name }}</dd>
7
-    <dt>{% trans "Status" %}</dt>
8
-    <dd>{{ board.status }}</dd>
9
-    <dt>{% trans "Type" %}</dt>
10
-    <dd>{{ board.type }}</dd>
11
-    <dt>{% trans "ID" %}</dt>
12
-    <dd>{{ board.uuid }}</dd>
13
-    <dt>{% trans "Code" %}</dt>
14
-    <dd>{{ board.code }}</dd>
15
-    <dt>{% trans "Creation data" %}</dt>
16
-    <dd>{{ board.created_at }}</dd>
17
-    <dt>{% trans "Location" %}</dt>
18
-    <dd>Latitude: {{ coordinates.latitude }}</dd>
19
-    <dd>Longitude: {{ coordinates.longitude }}</dd>
20
-    <dd>Altitude: {{ coordinates.altitude }}</dd>
21
-    <dt>{% trans "Mobile" %}</dt>
22
-    <dd>{{ board.mobile }}</dd>
23
-    <dt>{% trans "Extra" %}</dt>
24
-    <dd>{{ board.extra }}</dd>
25
-  </dl>
4
+
5
+  <h4>{% trans "Info" %}</h4>
6
+    <hr class="header_rule">
7
+    <dl class="dl-horizontal">
8
+      <dt>{% trans "Name" %}</dt>
9
+      <dd>{{ board.name }}</dd>
10
+      <dt>{% trans "Status" %}</dt>
11
+      <dd>{{ board.status }}</dd>
12
+      <dt>{% trans "Type" %}</dt>
13
+      <dd>{{ board.type }}</dd>
14
+      <dt>{% trans "ID" %}</dt>
15
+      <dd>{{ board.uuid }}</dd>
16
+      <dt>{% trans "Code" %}</dt>
17
+      <dd>{{ board.code }}</dd>
18
+      <dt>{% trans "Creation data" %}</dt>
19
+      <dd>{{ board.created_at }}</dd>
20
+      <dt>{% trans "Location" %}</dt>
21
+      <dd>Latitude: {{ coordinates.latitude }}</dd>
22
+      <dd>Longitude: {{ coordinates.longitude }}</dd>
23
+      <dd>Altitude: {{ coordinates.altitude }}</dd>
24
+      <dt>{% trans "Mobile" %}</dt>
25
+      <dd>{{ board.mobile }}</dd>
26
+      <dt>{% trans "Extra" %}</dt>
27
+      <dd>{{ board.extra }}</dd>
28
+      <dt>{% trans "Fleet ID" %}</dt>
29
+      <dd>{{ board.fleet }}</dd>
30
+    </dl>
26 31
 
27 32
   <h4>{% trans "Ports" %}</h4>
28 33
     <hr class="header_rule">
@@ -61,7 +66,7 @@
61 66
       {% else %}
62 67
           <dd>--</dd>
63 68
       {% endif %}
64
-  </dl>
69
+    </dl>
65 70
 </div>
66 71
 
67 72
 <!--<div id="mapdiv" style="min-height:300px; margin-bottom: 10px;" data-coordinates='[{"latitude": "{{ coordinates.latitude }}", "longitude": "{{ coordinates.longitude }}", "altitude": "{{ coordinates.altitude }}"}]'>-->

+ 12
- 0
iotronic_ui/iot/boards/views.py View File

@@ -123,10 +123,19 @@ class UpdateView(forms.ModalFormView):
123 123
         board = self.get_object()
124 124
         location = board.location[0]
125 125
 
126
+        # Populate fleets
127
+        fleets = api.iotronic.fleet_list(self.request, None)
128
+        fleets.sort(key=lambda b: b.name)
129
+
130
+        fleet_list = []
131
+        for fleet in fleets:
132
+            fleet_list.append((fleet.uuid, _(fleet.name)))
133
+
126 134
         return {'uuid': board.uuid,
127 135
                 'name': board.name,
128 136
                 'mobile': board.mobile,
129 137
                 'owner': board.owner,
138
+                'fleet_list': fleet_list,
130 139
                 'latitude': location["latitude"],
131 140
                 'longitude': location["longitude"],
132 141
                 'altitude': location["altitude"]}
@@ -461,6 +470,9 @@ class DetailView(tabs.TabView):
461 470
 
462 471
     @memoized.memoized_method
463 472
     def get_data(self):
473
+
474
+        board = []
475
+
464 476
         board_id = self.kwargs['board_id']
465 477
         try:
466 478
 

+ 1
- 1
iotronic_ui/iot/dashboard.py View File

@@ -18,7 +18,7 @@ import horizon
18 18
 class Iot(horizon.Dashboard):
19 19
     name = _("IoT")
20 20
     slug = "iot"
21
-    panels = ('boards', 'plugins', 'services')  # Add your panels here.
21
+    panels = ('boards', 'plugins', 'services', 'fleets')  # Add your panels here.
22 22
 
23 23
     # Specify the slug of the dashboard's default panel.
24 24
     default_panel = 'boards'

+ 0
- 0
iotronic_ui/iot/fleets/__init__.py View File


+ 151
- 0
iotronic_ui/iot/fleets/forms.py View File

@@ -0,0 +1,151 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import logging
14
+
15
+from django.utils.translation import ugettext_lazy as _
16
+
17
+from horizon import exceptions
18
+from horizon import forms
19
+from horizon import messages
20
+
21
+from openstack_dashboard.api import iotronic
22
+from openstack_dashboard import policy
23
+
24
+LOG = logging.getLogger(__name__)
25
+
26
+
27
+class CreateFleetForm(forms.SelfHandlingForm):
28
+    name = forms.CharField(label=_("Fleet Name"))
29
+
30
+    description = forms.CharField(
31
+        label=_("Description"),
32
+        widget=forms.Textarea(
33
+            attrs={'class': 'switchable', 'data-slug': 'slug-description'})
34
+    )
35
+
36
+    def handle(self, request, data):
37
+        try:
38
+            iotronic.fleet_create(request, data["name"],
39
+                                    data["description"])
40
+
41
+            messages.success(request, _("Fleet " + str(data["name"]) +
42
+                                        " created successfully."))
43
+            return True
44
+
45
+        except Exception:
46
+            exceptions.handle(request, _('Unable to create fleet.'))
47
+
48
+
49
+class UpdateFleetForm(forms.SelfHandlingForm):
50
+    uuid = forms.CharField(label=_("Fleet ID"), widget=forms.HiddenInput)
51
+    name = forms.CharField(label=_("Fleet Name"))
52
+    description = forms.CharField(
53
+        label=_("Description"),
54
+        widget=forms.Textarea(
55
+            attrs={'class': 'switchable', 'data-slug': 'slug-description'})
56
+    )
57
+
58
+    def __init__(self, *args, **kwargs):
59
+
60
+        super(UpdateFleetForm, self).__init__(*args, **kwargs)
61
+
62
+        # Admin
63
+        if policy.check((("iot", "iot:update_fleets"),), self.request):
64
+            # LOG.debug("ADMIN")
65
+            pass
66
+
67
+        # Manager or Admin of the iot project
68
+        elif (policy.check((("iot", "iot_manager"),), self.request) or
69
+              policy.check((("iot", "iot_admin"),), self.request)):
70
+            # LOG.debug("NO-edit IOT ADMIN")
71
+            pass
72
+
73
+        # Other users
74
+        else:
75
+            if self.request.user.id != kwargs["initial"]["owner"]:
76
+                # LOG.debug("IMMUTABLE FIELDS")
77
+                self.fields["name"].widget.attrs = {'readonly': 'readonly'}
78
+                self.fields["description"].widget.attrs = {'readonly': 'readonly'}
79
+
80
+    def handle(self, request, data):
81
+        try:
82
+            iotronic.fleet_update(request, data["uuid"],
83
+                                    {"name": data["name"],
84
+                                     "description": data["description"]})
85
+
86
+            messages.success(request, _("Fleet updated successfully."))
87
+            return True
88
+
89
+        except Exception:
90
+            exceptions.handle(request, _('Unable to update fleet.'))
91
+
92
+
93
+class FleetActionForm(forms.SelfHandlingForm):
94
+
95
+    uuid = forms.CharField(label=_("Plugin ID"), widget=forms.HiddenInput)
96
+
97
+    name = forms.CharField(
98
+        label=_('Fleet Name'),
99
+        widget=forms.TextInput(attrs={'readonly': 'readonly'})
100
+    )
101
+
102
+    board_list = forms.MultipleChoiceField(
103
+        label=_("Boards List"),
104
+        widget=forms.SelectMultiple(
105
+            attrs={'class': 'switchable', 'data-slug': 'slug-select-boards'}),
106
+        help_text=_("Select boards in this pool")
107
+    )
108
+
109
+    action = forms.ChoiceField(
110
+        label=_("Action"),
111
+        choices=[('FleetEnable', _('Enable')),
112
+                 ('FleetDisable', _('Disable')),
113
+                 ('FleetRestore', _('Restore'))],
114
+        widget=forms.Select(
115
+            attrs={'class': 'switchable', 'data-slug': 'slug-action'},
116
+        )
117
+    )
118
+
119
+    def __init__(self, *args, **kwargs):
120
+
121
+        super(FleetActionForm, self).__init__(*args, **kwargs)
122
+        # input=kwargs.get('initial',{})
123
+
124
+        self.fields["board_list"].choices = kwargs["initial"]["board_list"]
125
+
126
+    def handle(self, request, data):
127
+
128
+        counter = 0
129
+
130
+        for board in data["board_list"]:
131
+            for key, value in self.fields["board_list"].choices:
132
+                if key == board:
133
+
134
+                    try:
135
+                        action = iotronic.fleet_action(request, key,
136
+                                                         data["uuid"],
137
+                                                         data["action"])
138
+                        message_text = action
139
+                        messages.success(request, _(message_text))
140
+
141
+                        if counter != len(data["board_list"]) - 1:
142
+                            counter += 1
143
+                        else:
144
+                            return True
145
+
146
+                    except Exception:
147
+                        message_text = "Unable to execute action on board " \
148
+                                       + str(value) + "."
149
+                        exceptions.handle(request, _(message_text))
150
+
151
+                    break

+ 28
- 0
iotronic_ui/iot/fleets/panel.py View File

@@ -0,0 +1,28 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+from django.utils.translation import ugettext_lazy as _
14
+
15
+import horizon
16
+
17
+# from openstack_dashboard.api import keystone
18
+from iotronic_ui.iot import dashboard
19
+
20
+
21
+class Fleets(horizon.Panel):
22
+    name = _("Fleets")
23
+    slug = "fleets"
24
+    # permissions = ('openstack.fleets.iot', )
25
+    # policy_rules = (("iot", "iot:list_all_fleets"),)
26
+
27
+
28
+dashboard.Iot.register(Fleets)

+ 99
- 0
iotronic_ui/iot/fleets/tables.py View File

@@ -0,0 +1,99 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import logging
14
+
15
+from django.utils.translation import ugettext_lazy as _
16
+from django.utils.translation import ungettext_lazy
17
+
18
+from horizon import tables
19
+
20
+from openstack_dashboard import api
21
+
22
+LOG = logging.getLogger(__name__)
23
+
24
+
25
+class CreateFleetLink(tables.LinkAction):
26
+    name = "create"
27
+    verbose_name = _("Create Fleet")
28
+    url = "horizon:iot:fleets:create"
29
+    classes = ("ajax-modal",)
30
+    icon = "plus"
31
+    # policy_rules = (("iot", "iot:create_fleet"),)
32
+
33
+
34
+class EditFleetLink(tables.LinkAction):
35
+    name = "edit"
36
+    verbose_name = _("Edit")
37
+    url = "horizon:iot:fleets:update"
38
+    classes = ("ajax-modal",)
39
+    icon = "pencil"
40
+    # policy_rules = (("iot", "iot:update_fleet"),)
41
+
42
+
43
+class ActionFleetLink(tables.LinkAction):
44
+    name = "action"
45
+    verbose_name = _("Fleet Action")
46
+    url = "horizon:iot:fleets:action"
47
+    classes = ("ajax-modal",)
48
+    # icon = "plus"
49
+    # policy_rules = (("iot", "iot:fleet_action"),)
50
+
51
+
52
+class DeleteFleetsAction(tables.DeleteAction):
53
+    @staticmethod
54
+    def action_present(count):
55
+        return ungettext_lazy(
56
+            u"Delete Fleet",
57
+            u"Delete Fleets",
58
+            count
59
+        )
60
+
61
+    @staticmethod
62
+    def action_past(count):
63
+        return ungettext_lazy(
64
+            u"Deleted Fleet",
65
+            u"Deleted Fleets",
66
+            count
67
+        )
68
+    # policy_rules = (("iot", "iot:delete_fleet"),)
69
+
70
+    def delete(self, request, fleet_id):
71
+        api.iotronic.fleet_delete(request, fleet_id)
72
+
73
+
74
+class FleetFilterAction(tables.FilterAction):
75
+
76
+    def filter(self, table, fleets, filter_string):
77
+        # Naive case-insensitive search.
78
+        q = filter_string.lower()
79
+        return [fleet for fleet in fleets
80
+                if q in fleet.name.lower()]
81
+
82
+
83
+class FleetsTable(tables.DataTable):
84
+    name = tables.WrappingColumn('name', link="horizon:iot:fleets:detail",
85
+                                 verbose_name=_('Fleet Name'))
86
+    description = tables.Column('description', verbose_name=_('Description'))
87
+
88
+    # Overriding get_object_id method because in IoT fleet the "id" is
89
+    # identified by the field UUID
90
+    def get_object_id(self, datum):
91
+        return datum.uuid
92
+
93
+    class Meta(object):
94
+        name = "fleets"
95
+        verbose_name = _("fleets")
96
+        row_actions = (EditFleetLink, ActionFleetLink,
97
+                       DeleteFleetsAction)
98
+        table_actions = (FleetFilterAction, CreateFleetLink,
99
+                         DeleteFleetsAction)

+ 43
- 0
iotronic_ui/iot/fleets/tabs.py View File

@@ -0,0 +1,43 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import logging
14
+
15
+# from django.core.urlresolvers import reverse
16
+from django.utils.translation import ugettext_lazy as _
17
+
18
+from horizon import tabs
19
+
20
+LOG = logging.getLogger(__name__)
21
+
22
+
23
+class OverviewTab(tabs.Tab):
24
+    name = _("Overview")
25
+    slug = "overview"
26
+    template_name = ("iot/fleets/_detail_overview.html")
27
+
28
+    def get_context_data(self, request):
29
+        # coordinates = self.tab_group.kwargs['board'].__dict__["location"][0]
30
+        # LOG.debug('IOT INFO: %s', coordinates)
31
+
32
+        boards = self.tab_group.kwargs['fleet']._info['boards']
33
+
34
+        return {"fleet": self.tab_group.kwargs['fleet'],
35
+                "boards": boards,
36
+                "is_superuser": request.user.is_superuser}
37
+
38
+
39
+class FleetDetailTabs(tabs.TabGroup):
40
+    slug = "fleet_details"
41
+    # tabs = (OverviewTab, LogTab, ConsoleTab, AuditTab)
42
+    tabs = (OverviewTab,)
43
+    sticky = True

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/_action.html View File

@@ -0,0 +1,7 @@
1
+{% extends "horizon/common/_modal_form.html" %}
2
+{% load i18n %}
3
+
4
+{% block modal-body-right %}
5
+  <h3>{% trans "Description:" %}</h3>
6
+  <p>{% trans "Execute action on board(s)." %}</p>
7
+{% endblock %}

+ 8
- 0
iotronic_ui/iot/fleets/templates/fleets/_create.html View File

@@ -0,0 +1,8 @@
1
+{% extends "horizon/common/_modal_form.html" %}
2
+{% load i18n %}
3
+
4
+{% block modal-body-right %}
5
+  <h3>{% trans "Description:" %}</h3>
6
+  <p>{% trans "Add a new fleet." %}</p>
7
+{% endblock %}
8
+

+ 25
- 0
iotronic_ui/iot/fleets/templates/fleets/_detail_overview.html View File

@@ -0,0 +1,25 @@
1
+{% load i18n sizeformat %}
2
+
3
+<div class="detail">
4
+  <dl class="dl-horizontal">
5
+    <dt>{% trans "Name" %}</dt>
6
+    <dd>{{ fleet.name }}</dd>
7
+    <dt>{% trans "ID" %}</dt>
8
+    <dd>{{ fleet.uuid }}</dd>
9
+    <dt>{% trans "Description" %}</dt>
10
+    <dd>{{ fleet.description }}</dd>
11
+  </dl>
12
+
13
+  <h4>{% trans "Boards" %}</h4>
14
+    <hr class="header_rule">
15
+    <dl class="dl-horizontal">
16
+      {% if boards %}
17
+          {% for board in boards %}
18
+              <dt>{{ board.name }}</dt>
19
+              <dd>{{ board.uuid }}</dd>
20
+          {% endfor %}
21
+      {% else %}
22
+          <dd>--</dd>
23
+      {% endif %}
24
+    </dl>
25
+</div>

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/_update.html View File

@@ -0,0 +1,7 @@
1
+{% extends "horizon/common/_modal_form.html" %}
2
+{% load i18n %}
3
+
4
+{% block modal-body-right %}
5
+  <h3>{% trans "Description:" %}</h3>
6
+  <p>{% trans "Edit the fleet's details." %}</p>
7
+{% endblock %}

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/action.html View File

@@ -0,0 +1,7 @@
1
+{% extends 'base.html' %}
2
+{% load i18n %}
3
+{% block title %}{% trans "Execute Action" %}{% endblock %}
4
+
5
+{% block main %}
6
+    {% include 'iot/fleets/_action.html' %}
7
+{% endblock %}

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/create.html View File

@@ -0,0 +1,7 @@
1
+{% extends 'base.html' %}
2
+{% load i18n %}
3
+{% block title %}{% trans "Insert Fleet" %}{% endblock %}
4
+
5
+{% block main %}
6
+    {% include 'iot/fleets/_create.html' %}
7
+{% endblock %}

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/index.html View File

@@ -0,0 +1,7 @@
1
+{% extends 'base.html' %}
2
+{% load i18n %}
3
+{% block title %}{% trans "Fleets" %}{% endblock %}
4
+
5
+{% block main %}
6
+    {{ table.render }}
7
+{% endblock %}

+ 7
- 0
iotronic_ui/iot/fleets/templates/fleets/update.html View File

@@ -0,0 +1,7 @@
1
+{% extends 'base.html' %}
2
+{% load i18n %}
3
+{% block title %}{% trans "Update Fleet" %}{% endblock %}
4
+
5
+{% block main %}
6
+    {% include 'iot/fleets/_update.html' %}
7
+{% endblock %}

+ 19
- 0
iotronic_ui/iot/fleets/tests.py View File

@@ -0,0 +1,19 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+from horizon.test import helpers as test
14
+
15
+
16
+class FleetsTests(test.TestCase):
17
+    # Unit tests for boards.
18
+    def test_me(self):
19
+        self.assertTrue(1 + 1 == 2)

+ 27
- 0
iotronic_ui/iot/fleets/urls.py View File

@@ -0,0 +1,27 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+from django.conf.urls import url
14
+
15
+from iotronic_ui.iot.fleets import views
16
+
17
+
18
+urlpatterns = [
19
+    url(r'^$', views.IndexView.as_view(), name='index'),
20
+    url(r'^create/$', views.CreateView.as_view(), name='create'),
21
+    url(r'^(?P<fleet_id>[^/]+)/update/$', views.UpdateView.as_view(),
22
+        name='update'),
23
+    url(r'^(?P<fleet_id>[^/]+)/action/$', views.ActionView.as_view(),
24
+        name='action'),
25
+    url(r'^(?P<fleet_id>[^/]+)/detail/$', views.FleetDetailView.as_view(),
26
+        name='detail'),
27
+]

+ 220
- 0
iotronic_ui/iot/fleets/views.py View File

@@ -0,0 +1,220 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+
13
+import logging
14
+
15
+from django.core.urlresolvers import reverse
16
+from django.core.urlresolvers import reverse_lazy
17
+from django.utils.translation import ugettext_lazy as _
18
+
19
+from horizon import exceptions
20
+from horizon import forms
21
+# from horizon import messages
22
+from horizon import tables
23
+from horizon import tabs
24
+from horizon.utils import memoized
25
+
26
+from openstack_dashboard.api import iotronic
27
+from openstack_dashboard import policy
28
+
29
+from iotronic_ui.iot.fleets import forms as project_forms
30
+from iotronic_ui.iot.fleets import tables as project_tables
31
+from iotronic_ui.iot.fleets import tabs as project_tabs
32
+
33
+
34
+LOG = logging.getLogger(__name__)
35
+
36
+
37
+class IndexView(tables.DataTableView):
38
+    table_class = project_tables.FleetsTable
39
+    template_name = 'iot/fleets/index.html'
40
+    page_title = _("Fleets")
41
+
42
+    def get_data(self):
43
+        fleets = []
44
+
45
+        # Admin
46
+        if policy.check((("iot", "iot:list_all_fleets"),), self.request):
47
+            try:
48
+                fleets = iotronic.fleet_list(self.request, None)
49
+
50
+            except Exception:
51
+                exceptions.handle(self.request,
52
+                                  _('Unable to retrieve fleets list.'))
53
+
54
+        # Admin_iot_project
55
+        elif policy.check((("iot", "iot:list_project_fleets"),),
56
+                          self.request):
57
+            try:
58
+                fleets = iotronic.fleet_list(self.request, None)
59
+
60
+            except Exception:
61
+                exceptions.handle(self.request,
62
+                                  _('Unable to retrieve user fleets list.'))
63
+
64
+        # Other users
65
+        else:
66
+            try:
67
+                fleets = iotronic.fleet_list(self.request, None)
68
+
69
+            except Exception:
70
+                exceptions.handle(self.request,
71
+                                  _('Unable to retrieve user fleets list.'))
72
+
73
+        return fleets
74
+
75
+
76
+class CreateView(forms.ModalFormView):
77
+    template_name = 'iot/fleets/create.html'
78
+    modal_header = _("Create Fleet")
79
+    form_id = "create_fleet_form"
80
+    form_class = project_forms.CreateFleetForm
81
+    submit_label = _("Create Fleet")
82
+    submit_url = reverse_lazy("horizon:iot:fleets:create")
83
+    success_url = reverse_lazy('horizon:iot:fleets:index')
84
+    page_title = _("Create Fleet")
85
+
86
+
87
+class UpdateView(forms.ModalFormView):
88
+    template_name = 'iot/fleets/update.html'
89
+    modal_header = _("Update Fleet")
90
+    form_id = "update_fleet_form"
91
+    form_class = project_forms.UpdateFleetForm
92
+    submit_label = _("Update Fleet")
93
+    submit_url = "horizon:iot:fleets:update"
94
+    success_url = reverse_lazy('horizon:iot:fleets:index')
95
+    page_title = _("Update Fleet")
96
+
97
+    @memoized.memoized_method
98
+    def get_object(self):
99
+        try:
100
+            return iotronic.fleet_get(self.request,
101
+                                        self.kwargs['fleet_id'],
102
+                                        None)
103
+        except Exception:
104
+            redirect = reverse("horizon:iot:fleets:index")
105
+            exceptions.handle(self.request,
106
+                              _('Unable to get fleet information.'),
107
+                              redirect=redirect)
108
+
109
+    def get_context_data(self, **kwargs):
110
+        context = super(UpdateView, self).get_context_data(**kwargs)
111
+        args = (self.get_object().uuid,)
112
+        context['submit_url'] = reverse(self.submit_url, args=args)
113
+        return context
114
+
115
+    def get_initial(self):
116
+        fleet = self.get_object()
117
+
118
+        return {'uuid': fleet.uuid,
119
+                'name': fleet.name,
120
+                'description': fleet.description}
121
+
122
+
123
+class ActionView(forms.ModalFormView):
124
+    template_name = 'iot/fleets/action.html'
125
+    modal_header = _("Fleet Action")
126
+    form_id = "fleet_action_form"
127
+    form_class = project_forms.FleetActionForm
128
+    submit_label = _("Fleet Action")
129
+    # submit_url = reverse_lazy("horizon:iot:fleets:action")
130
+    submit_url = "horizon:iot:fleets:action"
131
+    success_url = reverse_lazy('horizon:iot:fleets:index')
132
+    page_title = _("Fleet Action")
133
+
134
+    @memoized.memoized_method
135
+    def get_object(self):
136
+        try:
137
+            return iotronic.fleet_get(self.request,
138
+                                        self.kwargs['fleet_id'],
139
+                                        None)
140
+        except Exception:
141
+            redirect = reverse("horizon:iot:fleets:index")
142
+            exceptions.handle(self.request,
143
+                              _('Unable to get fleet information.'),
144
+                              redirect=redirect)
145
+
146
+    def get_context_data(self, **kwargs):
147
+        context = super(ActionView, self).get_context_data(**kwargs)
148
+        args = (self.get_object().uuid,)
149
+        context['submit_url'] = reverse(self.submit_url, args=args)
150
+        return context
151
+
152
+    def get_initial(self):
153
+        fleet = self.get_object()
154
+
155
+        # Populate boards
156
+        boards = iotronic.board_list(self.request, "online", None, None)
157
+        boards.sort(key=lambda b: b.name)
158
+
159
+        board_list = []
160
+        for board in boards:
161
+            board_list.append((board.uuid, _(board.name)))
162
+
163
+        return {'uuid': fleet.uuid,
164
+                'name': fleet.name,
165
+                'board_list': board_list}
166
+
167
+
168
+class DetailView(tabs.TabView):
169
+    tab_group_class = project_tabs.FleetDetailTabs
170
+    template_name = 'horizon/common/_detail.html'
171
+    page_title = "{{ fleet.name|default:fleet.uuid }}"
172
+
173
+    def get_context_data(self, **kwargs):
174
+        context = super(DetailView, self).get_context_data(**kwargs)
175
+        fleet = self.get_data()
176
+        context["fleet"] = fleet
177
+        context["url"] = reverse(self.redirect_url)
178
+        context["actions"] = self._get_actions(fleet)
179
+
180
+        return context
181
+
182
+    def _get_actions(self, fleet):
183
+        table = project_tables.FleetsTable(self.request)
184
+        return table.render_row_actions(fleet)
185
+
186
+    @memoized.memoized_method
187
+    def get_data(self):
188
+        fleet = []
189
+        fleet_boards = []
190
+
191
+        fleet_id = self.kwargs['fleet_id']
192
+        try:
193
+            fleet = iotronic.fleet_get(self.request, fleet_id, None)
194
+            boards = iotronic.fleet_get_boards(self.request, fleet_id)
195
+
196
+            LOG.debug('XXXX: %s', boards)
197
+
198
+            for board in boards:
199
+                fleet_boards.append(board._info)
200
+
201
+            fleet._info.update(dict(boards=fleet_boards))
202
+            # LOG.debug('FLEET COMPLETE: %s', fleet)
203
+
204
+        except Exception:
205
+            s = fleet.name
206
+            msg = ('Unable to retrieve fleet %s information') % {'name': s}
207
+            exceptions.handle(self.request, msg, ignore=True)
208
+        return fleet
209
+
210
+    def get_tabs(self, request, *args, **kwargs):
211
+        fleet = self.get_data()
212
+        return self.tab_group_class(request, fleet=fleet, **kwargs)
213
+
214
+
215
+class FleetDetailView(DetailView):
216
+    redirect_url = 'horizon:iot:fleets:index'
217
+
218
+    def _get_actions(self, fleet):
219
+        table = project_tables.FleetsTable(self.request)
220
+        return table.render_row_actions(fleet)

+ 3
- 2
requirements.txt View File

@@ -9,7 +9,8 @@
9 9
 # PBR should always appear first
10 10
 pbr>=2.0.0,!=2.1.0  # Apache-2.0
11 11
 Babel>=2.3.4,!=2.4.0  # BSD
12
-Django>=1.8,<2.0  # BSD
13
-django-babel>=0.5.1 # BSD
12
+Django<2,>=1.11;python_version<'3.0'  # BSD
13
+Django<2.1,>=1.11;python_version>='3.0'  # BSD
14
+django-babel>=0.6.2 # BSD
14 15
 django-compressor>=2.0 # MIT
15 16
 django-pyscss>=2.0.2 # BSD License (2 clause)

+ 3
- 2
test-requirements.txt View File

@@ -9,7 +9,8 @@
9 9
 # PBR should always appear first
10 10
 pbr>=2.0.0,!=2.1.0  # Apache-2.0
11 11
 Babel>=2.3.4,!=2.4.0  # BSD
12
-Django>=1.8,<2.0  # BSD
13
-django-babel>=0.5.1 # BSD
12
+Django<2,>=1.11;python_version<'3.0'  # BSD
13
+Django<2.1,>=1.11;python_version>='3.0'  # BSD
14
+django-babel>=0.6.2 # BSD
14 15
 django-compressor>=2.0 # MIT
15 16
 django-pyscss>=2.0.2 # BSD License (2 clause)

Loading…
Cancel
Save