From 46d42afb6373d53a4d95876fc8dec4e6bbbb00e9 Mon Sep 17 00:00:00 2001 From: Bharath Thiruveedula Date: Thu, 22 Dec 2016 21:43:43 +0530 Subject: [PATCH] Add Panel for NSD Change-Id: Ib94f5197cb571a3cbccd7cff68e6ce8642878e7c Partially-implements: blueprint nsd-support --- .../openstack_dashboard/api/tacker.py | 46 +++++ .../dashboards/nfv/dashboard.py | 3 +- .../dashboards/nfv/nscatalog/__init__.py | 0 .../dashboards/nfv/nscatalog/forms.py | 105 +++++++++++ .../dashboards/nfv/nscatalog/panel.py | 25 +++ .../dashboards/nfv/nscatalog/tables.py | 68 +++++++ .../dashboards/nfv/nscatalog/tabs.py | 109 +++++++++++ .../templates/nscatalog/_onboardns.html | 9 + .../nscatalog/templates/nscatalog/detail.html | 16 ++ .../nscatalog/templates/nscatalog/index.html | 17 ++ .../templates/nscatalog/onboardns.html | 11 ++ .../templates/nscatalog/template.html | 5 + .../dashboards/nfv/nscatalog/tests.py | 20 ++ .../dashboards/nfv/nscatalog/urls.py | 25 +++ .../dashboards/nfv/nscatalog/views.py | 110 +++++++++++ .../dashboards/nfv/nsmanager/__init__.py | 0 .../dashboards/nfv/nsmanager/forms.py | 177 ++++++++++++++++++ .../dashboards/nfv/nsmanager/panel.py | 25 +++ .../dashboards/nfv/nsmanager/tables.py | 159 ++++++++++++++++ .../dashboards/nfv/nsmanager/tabs.py | 105 +++++++++++ .../templates/nsmanager/_deploy_ns.html | 15 ++ .../templates/nsmanager/deploy_ns.html | 11 ++ .../nsmanager/templates/nsmanager/detail.html | 16 ++ .../nsmanager/templates/nsmanager/index.html | 17 ++ .../dashboards/nfv/nsmanager/tests.py | 19 ++ .../dashboards/nfv/nsmanager/urls.py | 25 +++ .../dashboards/nfv/nsmanager/views.py | 100 ++++++++++ 27 files changed, 1237 insertions(+), 1 deletion(-) create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/__init__.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/forms.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/panel.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tables.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tabs.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/_onboardns.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/detail.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/index.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/onboardns.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/template.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tests.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/urls.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/views.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/__init__.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/forms.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/panel.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tables.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tabs.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/_deploy_ns.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/deploy_ns.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/detail.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/index.html create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tests.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/urls.py create mode 100644 tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/views.py diff --git a/tacker_horizon/openstack_dashboard/api/tacker.py b/tacker_horizon/openstack_dashboard/api/tacker.py index 0b17125..e576010 100644 --- a/tacker_horizon/openstack_dashboard/api/tacker.py +++ b/tacker_horizon/openstack_dashboard/api/tacker.py @@ -159,3 +159,49 @@ def delete_vnffg(request, vnffg_id): def delete_vnffgd(request, vnffgd_id): LOG.debug("delete_vnffgd():vnffgd_id=%s", str(vnffgd_id)) tackerclient(request).delete_vnffgd(vnffgd_id) + + +def create_nsd(request, tosca_body=None, **params): + LOG.debug("create_nsd(): params=%s", params) + nsd_instance = tackerclient(request).create_nsd(body=tosca_body) + return nsd_instance + + +def nsd_list(request, **params): + LOG.debug("nsd_list(): params=%s", params) + nsds = tackerclient(request).list_nsds(**params).get('nsds') + return nsds + + +def get_nsd(request, nsd_id): + LOG.debug("nsd_get(): nsd_id=%s", str(nsd_id)) + nsd = tackerclient(request).show_vnfd(nsd_id) + return nsd + + +def delete_nsd(request, nsd_id): + LOG.debug("delete_nsd():nsd_id=%s", str(nsd_id)) + tackerclient(request).delete_nsd(nsd_id) + + +def get_ns(request, ns_id): + LOG.debug("ns_get(): ns_id=%s", str(ns_id)) + ns_instance = tackerclient(request).show_ns(ns_id) + return ns_instance + + +def delete_ns(request, ns_id): + LOG.debug("delete_ns():ns_id=%s", str(ns_id)) + tackerclient(request).delete_ns(ns_id) + + +def ns_list(request, **params): + LOG.debug("ns_list(): params=%s", params) + nss = tackerclient(request).list_nss(**params).get('nss') + return nss + + +def create_ns(request, ns_arg, **params): + LOG.debug("create_ns(): ns_arg=%s", str(ns_arg)) + ns_instance = tackerclient(request).create_ns(body=ns_arg) + return ns_instance diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/dashboard.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/dashboard.py index 5134098..93c7a6e 100644 --- a/tacker_horizon/openstack_dashboard/dashboards/nfv/dashboard.py +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/dashboard.py @@ -27,7 +27,8 @@ class Vnfmgroup(horizon.PanelGroup): class Nfvogroup(horizon.PanelGroup): slug = "nfvogroup" name = _("NFV Orchestration") - panels = ('vim', 'vnffgcatalog', 'vnffgmanager',) + panels = ('vim', 'vnffgcatalog', 'vnffgmanager', + 'nscatalog', 'nsmanager') class Nfv(horizon.Dashboard): diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/__init__.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/forms.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/forms.py new file mode 100644 index 0000000..e32ab18 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/forms.py @@ -0,0 +1,105 @@ +# 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.forms import ValidationError +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import messages + +from tacker_horizon.openstack_dashboard import api + + +class OnBoardNS(forms.SelfHandlingForm): + name = forms.CharField(max_length=255, label=_("Name")) + description = forms.CharField(widget=forms.widgets.Textarea( + attrs={'rows': 4}), + label=_("Description"), + required=False) + source_type = forms.ChoiceField( + label=_('TOSCA Template Source'), + required=False, + choices=[('file', _('TOSCA Template File')), + ('raw', _('Direct Input'))], + widget=forms.Select( + attrs={'class': 'switchable', 'data-slug': 'source'})) + + toscal_file = forms.FileField( + label=_("TOSCA Template File"), + help_text=_("A local TOSCA template file to upload."), + widget=forms.FileInput( + attrs={'class': 'switched', 'data-switch-on': 'source', + 'data-source-file': _('TOSCA Template File')}), + required=False) + + direct_input = forms.CharField( + label=_('TOSCA YAML'), + help_text=_('The YAML formatted contents of a TOSCA template.'), + widget=forms.widgets.Textarea( + attrs={'class': 'switched', 'data-switch-on': 'source', + 'data-source-raw': _('TOSCA YAML')}), + required=False) + + def __init__(self, request, *args, **kwargs): + super(OnBoardNS, self).__init__(request, *args, **kwargs) + + def clean(self): + data = super(OnBoardNS, self).clean() + + # The key can be missing based on particular upload + # conditions. Code defensively for it here... + toscal_file = data.get('toscal_file', None) + toscal_raw = data.get('direct_input', None) + source_type = data.get("source_type") + if source_type == "file" and not toscal_file: + raise ValidationError( + _("No TOSCA template file selected.")) + if source_type == "raw" and not toscal_raw: + raise ValidationError( + _("No direct input specified.")) + + if toscal_file and not toscal_file.name.endswith(('.yaml', '.csar')): + raise ValidationError(_("Only .yaml or .csar file uploads \ + are supported")) + + try: + if toscal_file: + toscal_str = self.files['toscal_file'].read() + else: + toscal_str = data['direct_input'] + # toscal = yaml.loads(toscal_str) + data['tosca'] = toscal_str + except Exception as e: + msg = _('There was a problem loading the namespace: %s.') % e + raise forms.ValidationError(msg) + + return data + + def handle(self, request, data): + try: + toscal = data['tosca'] + nsd_name = data['name'] + nsd_description = data['description'] + tosca_arg = {'nsd': {'name': nsd_name, + 'description': nsd_description, + 'attributes': {'nsd': toscal}}} + nsd_instance = api.tacker.create_nsd(request, tosca_arg) + messages.success(request, + _('NS Catalog entry %s has been created.') % + nsd_instance['nsd']['name']) + return toscal + except Exception as e: + msg = _('Unable to create TOSCA. %s') + msg %= e.message.split('Failed validating', 1)[0] + exceptions.handle(request, message=msg) + return False diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/panel.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/panel.py new file mode 100644 index 0000000..7371697 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/panel.py @@ -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 tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard + + +class Nscatalog(horizon.Panel): + name = _("NS Catalog") + slug = "nscatalog" + + +dashboard.Nfv.register(Nscatalog) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tables.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tables.py new file mode 100644 index 0000000..72478b8 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tables.py @@ -0,0 +1,68 @@ +# 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 _ +from django.utils.translation import ungettext_lazy + +from horizon import tables + +from openstack_dashboard import policy +from tacker_horizon.openstack_dashboard import api + + +class MyFilterAction(tables.FilterAction): + name = "myfilter" + + +class DeleteNSD(policy.PolicyTargetMixin, tables.DeleteAction): + @staticmethod + def action_present(count): + return ungettext_lazy( + u"Delete NS", + u"Delete NSs", + count + ) + + @staticmethod + def action_past(count): + return ungettext_lazy( + u"Delete NS", + u"Delete NSs", + count + ) + + def action(self, request, obj_id): + api.tacker.delete_nsd(request, obj_id) + + +class OnBoardNS(tables.LinkAction): + name = "onboardns" + verbose_name = _("Onboard NS") + classes = ("ajax-modal",) + icon = "plus" + url = "horizon:nfv:nscatalog:onboardns" + + +class NSCatalogTable(tables.DataTable): + name = tables.Column('name', + link="horizon:nfv:nscatalog:detail", + verbose_name=_("Name")) + description = tables.Column('description', + verbose_name=_("Description")) + id = tables.Column('id', + verbose_name=_("Catalog Id")) + + class Meta(object): + name = "nscatalog" + verbose_name = _("NSCatalog") + table_actions = (OnBoardNS, DeleteNSD, MyFilterAction,) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tabs.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tabs.py new file mode 100644 index 0000000..24b93e7 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tabs.py @@ -0,0 +1,109 @@ +# 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 _ + +from horizon import exceptions +from horizon import tabs + +from tacker_horizon.openstack_dashboard import api +from tacker_horizon.openstack_dashboard.dashboards.nfv.nscatalog import tables +from tacker_horizon.openstack_dashboard.dashboards.nfv import utils + + +class NSCatalogItem(object): + def __init__(self, name, description, nsd_id): + self.id = nsd_id + self.name = name + self.description = description + + +class NSCatalogTab(tabs.TableTab): + name = _("NSCatalog Tab") + slug = "nscatalog_tab" + table_classes = (tables.NSCatalogTable,) + template_name = ("horizon/common/_detail_table.html") + preload = False + + def has_more_data(self, table): + return self._has_more + + def get_nscatalog_data(self): + try: + self._has_more = False + instances = [] + nsds = api.tacker.nsd_list(self.request) + for nsd in nsds: + item = NSCatalogItem(nsd['name'], + nsd['description'], + nsd['id']) + instances.append(item) + return instances + except Exception: + self._has_more = False + error_message = _('Unable to get instances') + exceptions.handle(self.request, error_message) + + return [] + + +class NSCatalogTabs(tabs.TabGroup): + slug = "nscatalog_tabs" + tabs = (NSCatalogTab,) + sticky = True + + +class TemplateTab(tabs.Tab): + name = _("Template") + slug = "template" + template_name = ("nfv/nscatalog/template.html") + + def get_context_data(self, request): + return {'nsd': self.tab_group.kwargs['nsd']} + + +class NSDEventsTab(tabs.TableTab): + name = _("Events Tab") + slug = "events_tab" + table_classes = (utils.EventsTable,) + template_name = ("horizon/common/_detail_table.html") + preload = False + + def has_more_data(self, table): + return self._has_more + + def get_events_data(self): + try: + self._has_more = True + utils.EventItemList.clear_list() + events = api.tacker.events_list(self.request, + self.tab_group.kwargs['nsd_id']) + for event in events: + evt_obj = utils.EventItem( + event['id'], event['resource_state'], + event['event_type'], + event['timestamp'], + event['event_details']) + utils.EventItemList.add_item(evt_obj) + return utils.EventItemList.EVTLIST_P + except Exception as e: + self._has_more = False + error_message = _('Unable to get events %s') % e + exceptions.handle(self.request, error_message) + return [] + + +class NSDDetailTabs(tabs.TabGroup): + slug = "NSD_details" + tabs = (TemplateTab, NSDEventsTab) + sticky = True diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/_onboardns.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/_onboardns.html new file mode 100644 index 0000000..b67c0f5 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/_onboardns.html @@ -0,0 +1,9 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_attrs %}enctype="multipart/form-data"{% endblock %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% trans "Onboards a NS." %}

+{% endblock %} diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/detail.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/detail.html new file mode 100644 index 0000000..2717791 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/detail.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "NSD Details" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=page_title %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} + diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/index.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/index.html new file mode 100644 index 0000000..3693a1a --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/index.html @@ -0,0 +1,17 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "NS Catalog" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("NS Catalog") %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} + + diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/onboardns.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/onboardns.html new file mode 100644 index 0000000..5f62aab --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/onboardns.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Onboard NS" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Onboard a NS") %} +{% endblock page_header %} + +{% block main %} + {% include 'nfv/nscatalog/_onboardns.html' %} +{% endblock %} diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/template.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/template.html new file mode 100644 index 0000000..99bb2d9 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/templates/nscatalog/template.html @@ -0,0 +1,5 @@ +{% load i18n %} +

{% trans "NSD Template" %}

+
+{{ nsd.template }}
+
diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tests.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tests.py new file mode 100644 index 0000000..ee13cb7 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/tests.py @@ -0,0 +1,20 @@ +# 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 openstack_dashboard.test import helpers as test + + +class NscatalogTests(test.TestCase): + # Unit tests for nscatalog. + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/urls.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/urls.py new file mode 100644 index 0000000..0c3dffb --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/urls.py @@ -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.conf.urls import patterns +from django.conf.urls import url + +from tacker_horizon.openstack_dashboard.dashboards.nfv.nscatalog import views + + +urlpatterns = patterns( + 'tacker_horizon.openstack_dashboard.dashboards.nfv.nscatalog.views', + url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^onboardns', views.OnBoardNSView.as_view(), name='onboardns'), + url(r'^(?P[^/]+)/$', views.DetailView.as_view(), name='detail'), +) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/views.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/views.py new file mode 100644 index 0000000..6096cfe --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nscatalog/views.py @@ -0,0 +1,110 @@ +# 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.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 tabs + +from horizon.utils import memoized + +from openstack_dashboard import api + +from tacker_horizon.openstack_dashboard import api as tacker_api +from tacker_horizon.openstack_dashboard.dashboards.nfv.nscatalog \ + import tabs as nfv_tabs + +from tacker_horizon.openstack_dashboard.dashboards.nfv.nscatalog \ + import forms as project_forms + + +class IndexView(tabs.TabbedTableView): + # A very simple class-based view... + tab_group_class = nfv_tabs.NSCatalogTabs + template_name = 'nfv/nscatalog/index.html' + + def get_data(self, request, context, *args, **kwargs): + # Add data to the context here... + return context + + +class OnBoardNSView(forms.ModalFormView): + form_class = project_forms.OnBoardNS + template_name = 'nfv/nscatalog/onboardns.html' + success_url = reverse_lazy("horizon:nfv:nscatalog:index") + modal_id = "onboardns_modal" + modal_header = _("OnBoard NS") + submit_label = _("OnBoard NS") + submit_url = "horizon:nfv:nscatalog:onboardns" + + @memoized.memoized_method + def get_object(self): + try: + return api.nova.server_get(self.request, + self.kwargs["instance_id"]) + except Exception: + exceptions.handle(self.request, + _("Unable to retrieve instance.")) + + def get_initial(self): + # return {"instance_id": self.kwargs["instance_id"]} + return {} + + def get_context_data(self, **kwargs): + context = super(OnBoardNSView, self).get_context_data(**kwargs) + # instance_id = self.kwargs['instance_id'] + # context['instance_id'] = instance_id + # context['instance'] = self.get_object() + context['submit_url'] = reverse(self.submit_url) + return context + + +class DetailView(tabs.TabView): + tab_group_class = nfv_tabs.NSDDetailTabs + template_name = 'nfv/nscatalog/detail.html' + redirect_url = 'horizon:nfv:nscatalog:index' + page_title = _("NSD Details: {{ nsd_id }}") + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + nsd = self.get_data() + context['nsd'] = nsd + context['nsd_id'] = kwargs['nsd_id'] + context['url'] = reverse(self.redirect_url) + return context + + @memoized.memoized_method + def get_data(self): + nsd_id = self.kwargs['nsd_id'] + + try: + template = None + nsd = tacker_api.tacker.get_nsd(self.request, nsd_id) + attributes_json = nsd['nsd']['attributes'] + template = attributes_json.get('nsd', None) + nsd['template'] = template + except Exception: + redirect = reverse(self.redirect_url) + exceptions.handle(self.request, + _('Unable to retrieve details for ' + 'NSD "%s".') % nsd_id, + redirect=redirect) + raise exceptions.Http302(redirect) + return nsd + + def get_tabs(self, request, *args, **kwargs): + nsd = self.get_data() + return self.tab_group_class(request, nsd=nsd, **kwargs) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/__init__.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/forms.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/forms.py new file mode 100644 index 0000000..0ff3fdb --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/forms.py @@ -0,0 +1,177 @@ +# 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.forms import ValidationError +from django.utils.translation import ugettext_lazy as _ + +from horizon import exceptions +from horizon import forms +from horizon import messages + +from tacker_horizon.openstack_dashboard import api + +LOG = logging.getLogger(__name__) + + +class DeployNS(forms.SelfHandlingForm): + ns_name = forms.CharField(max_length=255, label=_("NS Name")) + description = forms.CharField(widget=forms.widgets.Textarea( + attrs={'rows': 4}), + label=_("Description"), + required=False) + nsd_id = forms.ChoiceField(label=_("NS Catalog Name")) + vim_id = forms.ChoiceField(label=_("VIM Name"), required=False) + source_type = forms.ChoiceField( + label=_('Parameter Value Source'), + required=False, + choices=[('file', _('File')), + ('raw', _('Direct Input'))], + widget=forms.Select( + attrs={'class': 'switchable', 'data-slug': 'source'})) + + param_file = forms.FileField( + label=_('Parameter Value File'), + help_text=_('A local Parameter Value file to upload.'), + widget=forms.FileInput( + attrs={'class': 'switched', 'data-switch-on': 'source', + 'data-source-file': _('Parameter Value File')}), + required=False) + + direct_input = forms.CharField( + label=_('Parameter Value YAML'), + help_text=_('The YAML formatted contents of Parameter Values.'), + widget=forms.widgets.Textarea( + attrs={'class': 'switched', 'data-switch-on': 'source', + 'data-source-raw': _('Parameter Values')}), + required=False) + + config_type = forms.ChoiceField( + label=_('Configuration Value Source'), + required=False, + choices=[('file', _('File')), + ('raw', _('Direct Input'))], + widget=forms.Select( + attrs={'class': 'switchable', 'data-slug': 'config'})) + + config_file = forms.FileField( + label=_('Configuration Value File'), + help_text=_('NS Configuration file with YAML ' + 'formatted contents to upload.'), + widget=forms.FileInput( + attrs={'class': 'switched', 'data-switch-on': 'config', + 'data-config-file': _('Configuration Value File')}), + required=False) + + config_input = forms.CharField( + label=_('Configuration Value YAML'), + help_text=_('YAML formatted NS configuration text.'), + widget=forms.widgets.Textarea( + attrs={'class': 'switched', 'data-switch-on': 'config', + 'data-config-raw': _('Configuration Values')}), + required=False) + + def __init__(self, request, *args, **kwargs): + super(DeployNS, self).__init__(request, *args, **kwargs) + + try: + nsd_list = api.tacker.nsd_list(request) + available_choices_nsd = [(ns['id'], ns['name']) for ns in + nsd_list] + except Exception as e: + available_choices_nsd = [] + msg = _('Failed to retrieve available NS Catalog names: %s') % e + LOG.error(msg) + + try: + vim_list = api.tacker.vim_list(request) + available_choices_vims = [(vim['id'], vim['name']) for vim in + vim_list] + + except Exception as e: + available_choices_vims = [] + msg = _('Failed to retrieve available VIM names: %s') % e + LOG.error(msg) + + self.fields['nsd_id'].choices = [('', _('Select a NS Catalog Name')) + ]+available_choices_nsd + self.fields['vim_id'].choices = [('', + _('Select a VIM Name')) + ]+available_choices_vims + + def clean(self): + data = super(DeployNS, self).clean() + + param_file = data.get('param_file', None) + param_raw = data.get('direct_input', None) + + if param_raw and param_file: + raise ValidationError( + _("Cannot specify both file and direct input.")) + + if param_file and not param_file.name.endswith('.yaml'): + raise ValidationError( + _("Please upload .yaml file only.")) + + if param_file: + data['param_values'] = self.files['param_file'].read() + elif param_raw: + data['param_values'] = data['direct_input'] + else: + data['param_values'] = None + + config_file = data.get('config_file', None) + config_raw = data.get('config_input', None) + + if config_file and config_raw: + raise ValidationError( + _("Cannot specify both file and direct input.")) + + if config_file and not config_file.name.endswith('.yaml'): + raise ValidationError(_("Only .yaml file uploads supported")) + + if config_file: + data['config_values'] = self.files['config_file'].read() + elif config_raw: + data['config_values'] = data['config_input'] + else: + data['config_values'] = None + + return data + + def handle(self, request, data): + try: + ns_name = data['ns_name'] + description = data['description'] + nsd_id = data['nsd_id'] + vim_id = data['vim_id'] + param_val = data['param_values'] + config_val = data['config_values'] + ns_arg = {'ns': {'nsd_id': nsd_id, 'name': ns_name, + 'description': description, + 'vim_id': vim_id}} + ns_attr = ns_arg['ns'].setdefault('attributes', {}) + if param_val: + ns_attr['param_values'] = param_val + if config_val: + ns_attr['config'] = config_val + + api.tacker.create_ns(request, ns_arg) + messages.success(request, + _('NS %s create operation initiated.') % + ns_name) + return True + except Exception as e: + exceptions.handle(request, + _('Failed to create NS: %s') % + e.message) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/panel.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/panel.py new file mode 100644 index 0000000..66797c0 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/panel.py @@ -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 tacker_horizon.openstack_dashboard.dashboards.nfv import dashboard + + +class Nsmanager(horizon.Panel): + name = _("NS Manager") + slug = "nsmanager" + + +dashboard.Nfv.register(Nsmanager) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tables.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tables.py new file mode 100644 index 0000000..24cd4bd --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tables.py @@ -0,0 +1,159 @@ +# 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.http import Http404 +from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import ungettext_lazy + +from horizon import messages +from horizon import tables + +from openstack_dashboard import policy +from tacker_horizon.openstack_dashboard import api +from tackerclient.common.exceptions import NotFound + + +class NSManagerItem(object): + def __init__(self, name, description, vim, status, + ns_id, error_reason): + self.name = name + self.description = description + self.vim = vim + self.status = status + self.id = ns_id + self.error_reason = error_reason + + +class NSManagerItemList(object): + NSLIST_P = [] + + @classmethod + def get_obj_given_stack_ids(cls, ns_id): + for obj in cls.NSLIST_P: + if obj.id == ns_id: + return obj + + @classmethod + def add_item(cls, item): + cls.NSLIST_P.append(item) + + @classmethod + def clear_list(cls): + cls.NSLIST_P = [] + + +class MyFilterAction(tables.FilterAction): + name = "myfilter" + + +class NSUpdateRow(tables.Row): + ajax = True + + def can_be_selected(self, datum): + return datum.status != 'DELETE_COMPLETE' + + def get_data(self, request, ns_id): + try: + # stack = api.heat.stack_get(request, stack_id) + # if stack.stack_status == 'DELETE_COMPLETE': + # returning 404 to the ajax call removes the + # row from the table on the ui + # raise Http404 + item = NSManagerItemList.get_obj_given_stack_ids(ns_id) + ns_instance = api.tacker.get_ns(request, ns_id) + + if not ns_instance and not item: + # TODO(NAME) - bail with error + return None + + if not ns_instance and item: + # API failure, just keep the current state + return item + + ns = ns_instance['ns'] + try: + ns_desc_str = ns['description'] + except KeyError: + ns_desc_str = "" + + vim = ns['vim_id'] + if not item: + # Add an item entry + item = NSManagerItem(ns['name'], ns_desc_str, + str(vim), + ns['status'], ns['id'], + ns['error_reason']) + else: + item.description = ns_desc_str + item.status = ns['status'] + item.id = ns['id'] + return item + except (Http404, NotFound): + raise Http404 + except Exception as e: + messages.error(request, e) + raise + + +class DeleteNS(policy.PolicyTargetMixin, tables.DeleteAction): + @staticmethod + def action_present(count): + return ungettext_lazy( + u"Terminate NS", + u"Terminate NSs", + count + ) + + @staticmethod + def action_past(count): + return ungettext_lazy( + u"Terminate NS", + u"Terminate NSs", + count + ) + + def action(self, request, obj_id): + api.tacker.delete_ns(request, obj_id) + + +class DeployNS(tables.LinkAction): + name = "deployns" + verbose_name = _("Deploy NS") + classes = ("ajax-modal",) + icon = "plus" + url = "horizon:nfv:nsmanager:deployns" + + +class NSManagerTable(tables.DataTable): + STATUS_CHOICES = ( + ("ACTIVE", True), + ("ERROR", False), + ) + name = tables.Column("name", + link="horizon:nfv:nsmanager:detail", + verbose_name=_("NS Name")) + description = tables.Column("description", + verbose_name=_("Description")) + vim = tables.Column("vim", verbose_name=_("VIM")) + status = tables.Column("status", + status=True, + status_choices=STATUS_CHOICES) + error_reason = tables.Column("error_reason", + verbose_name=_("Error Reason")) + + class Meta(object): + name = "nsmanager" + verbose_name = _("NSManager") + status_columns = ["status", ] + row_class = NSUpdateRow + table_actions = (DeployNS, DeleteNS, MyFilterAction,) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tabs.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tabs.py new file mode 100644 index 0000000..26e6427 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tabs.py @@ -0,0 +1,105 @@ +# 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 tabs + +from tacker_horizon.openstack_dashboard import api +from tacker_horizon.openstack_dashboard.dashboards.nfv.nsmanager import tables +from tacker_horizon.openstack_dashboard.dashboards.nfv import utils + +LOG = logging.getLogger(__name__) + + +class NSManagerTab(tabs.TableTab): + name = _("NSManager Tab") + slug = "nsmanager_tab" + table_classes = (tables.NSManagerTable,) + template_name = ("horizon/common/_detail_table.html") + preload = False + + def has_more_data(self, table): + return self._has_more + + def get_nsmanager_data(self): + try: + self._has_more = True + tables.NSManagerItemList.clear_list() + nss = api.tacker.ns_list(self.request) + for ns in nss: + try: + ns_desc_str = ns['description'] + except KeyError: + ns_desc_str = "" + + vim = ns['vim_id'] + obj = tables.NSManagerItem( + ns['name'], + ns_desc_str, + vim, + ns['status'], + ns['id'], + ns['error_reason']) + tables.NSManagerItemList.add_item(obj) + return tables.NSManagerItemList.NSLIST_P + except Exception: + self._has_more = False + error_message = _('Unable to get instances') + exceptions.handle(self.request, error_message) + + return [] + + +class NSManagerTabs(tabs.TabGroup): + slug = "nsmanager_tabs" + tabs = (NSManagerTab,) + sticky = True + + +class NSEventsTab(tabs.TableTab): + name = _("Events Tab") + slug = "events_tab" + table_classes = (utils.EventsTable,) + template_name = ("horizon/common/_detail_table.html") + preload = False + + def has_more_data(self, table): + return self._has_more + + def get_events_data(self): + try: + self._has_more = True + utils.EventItemList.clear_list() + events = api.tacker.events_list(self.request, + self.tab_group.kwargs['ns_id']) + for event in events: + evt_obj = utils.EventItem( + event['id'], event['resource_state'], + event['event_type'], + event['timestamp'], + event['event_details']) + utils.EventItemList.add_item(evt_obj) + return utils.EventItemList.EVTLIST_P + except Exception as e: + self._has_more = False + error_message = _('Unable to get events %s') % e + exceptions.handle(self.request, error_message) + return [] + + +class NSDetailsTabs(tabs.TabGroup): + slug = "NS_details" + tabs = (NSEventsTab,) + sticky = True diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/_deploy_ns.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/_deploy_ns.html new file mode 100644 index 0000000..2e389ac --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/_deploy_ns.html @@ -0,0 +1,15 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} + +{% block form_attrs %}enctype="multipart/form-data"{% endblock %} + +{% block modal-body-right %} +

{% trans "Description:" %}

+

{% blocktrans %} Deploys a NS.
+ If the NSD template is parameterized, + upload a yaml file with values for those parameters.
+ If the NSD template is not parameterized, any + yaml file uploaded will be ignored.
+ If a configuration yaml file is uploaded, it will be + applied to the NS post its successful creation.{% endblocktrans %}

+{% endblock %} diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/deploy_ns.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/deploy_ns.html new file mode 100644 index 0000000..949cb47 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/deploy_ns.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Deploy NS" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Deploy a NS") %} +{% endblock page_header %} + +{% block main %} + {% include 'nfv/nsmanager/_deploy_ns.html' %} +{% endblock %} diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/detail.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/detail.html new file mode 100644 index 0000000..1880652 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/detail.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "NS Details" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=page_title %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} + diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/index.html b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/index.html new file mode 100644 index 0000000..813e40f --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/templates/nsmanager/index.html @@ -0,0 +1,17 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "NS Manager" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("NS Manager") %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} + + diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tests.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tests.py new file mode 100644 index 0000000..d4e43de --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/tests.py @@ -0,0 +1,19 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + + +from openstack_dashboard.test import helpers as test + + +class NsmanagerTests(test.TestCase): + def test_me(self): + self.assertTrue(1 + 1 == 2) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/urls.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/urls.py new file mode 100644 index 0000000..6d08179 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/urls.py @@ -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.conf.urls import patterns +from django.conf.urls import url + +from tacker_horizon.openstack_dashboard.dashboards.nfv.nsmanager import views + + +urlpatterns = patterns( + 'tacker_horizon.openstack_dashboard.dashboards.nfv.nsmanager.views', + url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^deployns$', views.DeployNSView.as_view(), name='deployns'), + url(r'^(?P[^/]+)/$', views.DetailView.as_view(), name='detail'), +) diff --git a/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/views.py b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/views.py new file mode 100644 index 0000000..9833719 --- /dev/null +++ b/tacker_horizon/openstack_dashboard/dashboards/nfv/nsmanager/views.py @@ -0,0 +1,100 @@ +# 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 tabs +from horizon.utils import memoized + +from tacker_horizon.openstack_dashboard import api as tacker_api +from tacker_horizon.openstack_dashboard.dashboards.nfv.nsmanager \ + import forms as project_forms + +from tacker_horizon.openstack_dashboard.dashboards.nfv.nsmanager \ + import tabs as nfv_tabs + +LOG = logging.getLogger(__name__) + + +class IndexView(tabs.TabbedTableView): + # A very simple class-based view... + tab_group_class = nfv_tabs.NSManagerTabs + template_name = 'nfv/nsmanager/index.html' + + def get_data(self, request, context, *args, **kwargs): + # Add data to the context here... + return context + + +class DeployNSView(forms.ModalFormView): + form_class = project_forms.DeployNS + template_name = 'nfv/nsmanager/deploy_ns.html' + success_url = reverse_lazy("horizon:nfv:nsmanager:index") + modal_id = "deploy_ns_modal" + modal_header = _("Deploy NS") + submit_label = _("Deploy NS") + submit_url = "horizon:nfv:nsmanager:deployns" + + def get_initial(self): + # return {"instance_id": self.kwargs["instance_id"]} + return {} + + def get_context_data(self, **kwargs): + context = super(DeployNSView, self).get_context_data(**kwargs) + # instance_id = self.kwargs['instance_id'] + # context['instance_id'] = instance_id + # context['instance'] = self.get_object() + context['submit_url'] = reverse(self.submit_url) + return context + + +class DetailView(tabs.TabView): + tab_group_class = nfv_tabs.NSDetailsTabs + template_name = 'nfv/nsmanager/detail.html' + redirect_url = 'horizon:nfv:nsmanager:index' + page_title = _("NS Details: {{ ns_id }}") + + def get_context_data(self, **kwargs): + context = super(DetailView, self).get_context_data(**kwargs) + ns = self.get_data() + context['ns'] = ns + context['ns_id'] = kwargs['ns_id'] + context['url'] = reverse(self.redirect_url) + return context + + @memoized.memoized_method + def get_data(self): + ns_id = self.kwargs['ns_id'] + + try: + ns = tacker_api.tacker.get_ns(self.request, ns_id) + return ns + except ValueError as e: + msg = _('Cannot decode json : %s') % e + LOG.error(msg) + except Exception: + redirect = reverse(self.redirect_url) + exceptions.handle(self.request, + _('Unable to retrieve details for ' + 'NS "%s".') % ns_id, + redirect=redirect) + raise exceptions.Http302(redirect) + + def get_tabs(self, request, *args, **kwargs): + ns = self.get_data() + return self.tab_group_class(request, ns=ns, **kwargs)