From c3051ef2b123e21b3856ff474db39569230cb0ec Mon Sep 17 00:00:00 2001 From: lombardofr Date: Wed, 16 Jan 2019 10:59:18 +0100 Subject: [PATCH] Network Slice Templates Change-Id: I9453c518cc717e514598e40e2b1ce5ff60b76108 Signed-off-by: lombardofr --- bower.json | 2 +- build-debpkg.sh | 3 +- descriptorhandler/views.py | 1 - lib/osm/osmclient/clientv2.py | 105 +++++++++ netslicehandler/__init__.py | 13 ++ netslicehandler/apps.py | 21 ++ netslicehandler/migrations/__init__.py | 13 ++ .../template/modal/nst_details.html | 23 ++ netslicehandler/template/nst_edit.html | 177 +++++++++++++++ netslicehandler/template/nst_list.html | 211 ++++++++++++++++++ netslicehandler/urls.py | 26 +++ netslicehandler/views.py | 119 ++++++++++ packagehandler/template/package_list.html | 4 +- packagehandler/template/package_list_ns.html | 2 +- packagehandler/template/package_list_vnf.html | 2 +- .../project/osm/osm_project_left_sidebar.html | 6 + sf_t3d/settings.py | 4 +- sf_t3d/urls.py | 1 + static/src/drop_zone.js | 32 +++ .../src/netslicehandler/onboard_template.js | 70 ++++++ static/src/netslicehandler/templates_list.js | 78 +++++++ static/src/packagehandler/onboard_package.js | 18 -- 22 files changed, 906 insertions(+), 25 deletions(-) create mode 100644 netslicehandler/__init__.py create mode 100644 netslicehandler/apps.py create mode 100644 netslicehandler/migrations/__init__.py create mode 100644 netslicehandler/template/modal/nst_details.html create mode 100644 netslicehandler/template/nst_edit.html create mode 100644 netslicehandler/template/nst_list.html create mode 100644 netslicehandler/urls.py create mode 100644 netslicehandler/views.py create mode 100644 static/src/drop_zone.js create mode 100644 static/src/netslicehandler/onboard_template.js create mode 100644 static/src/netslicehandler/templates_list.js diff --git a/bower.json b/bower.json index 0a2e2a3..acfbc66 100644 --- a/bower.json +++ b/bower.json @@ -23,7 +23,7 @@ "codemirror": "^5.36.0", "d3": "^4", "bootbox.js": "bootbox#^4.4.0", - "components-font-awesome": "^5.0.6", + "components-font-awesome": "^5.2.0", "moment": "^2.22.2" } } diff --git a/build-debpkg.sh b/build-debpkg.sh index 710edf5..d1becda 100755 --- a/build-debpkg.sh +++ b/build-debpkg.sh @@ -14,7 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. -PKG_DIRECTORIES="authosm descriptorhandler instancehandler lib projecthandler sdnctrlhandler sf_t3d static template userhandler vimhandler packagehandler" + +PKG_DIRECTORIES="authosm descriptorhandler instancehandler lib projecthandler sdnctrlhandler sf_t3d static template userhandler vimhandler packagehandler netslicehandler" PKG_FILES="bower.json django.ini LICENSE manage.py nginx-app.conf README.md requirements.txt supervisor-app.conf .bowerrc" MDG_NAME=lightui DEB_INSTALL=debian/osm-${MDG_NAME}.install diff --git a/descriptorhandler/views.py b/descriptorhandler/views.py index e5728fb..4c49a6d 100644 --- a/descriptorhandler/views.py +++ b/descriptorhandler/views.py @@ -182,7 +182,6 @@ def edit_descriptor(request, descriptor_id=None, descriptor_type=None): result = {'error': True, 'data': str(e)} if result['error'] == True: return __response_handler(request, result['data'], url=None, status=result['data']['status'] if 'status' in result['data'] else 500) - else: return __response_handler(request, {}, url=None, status=200) diff --git a/lib/osm/osmclient/clientv2.py b/lib/osm/osmclient/clientv2.py index d900af6..191385e 100644 --- a/lib/osm/osmclient/clientv2.py +++ b/lib/osm/osmclient/clientv2.py @@ -251,6 +251,58 @@ class Client(object): result['data'] = Util.json_loads_byteified(r.text) return result + def nst_details(self, token, id): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/json", "accept": "application/json", + 'Authorization': 'Bearer {}'.format(token['id'])} + _url = "{0}/nst/v1/netslice_templates/{1}".format(self._base_path,id) + try: + r = requests.get(_url, params=None, verify=False, stream=True, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.ok: + result['error'] = False + result['data'] = Util.json_loads_byteified(r.text) + + return result + + def nst_content(self, token, id): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/json", "accept": "text/plain", + 'Authorization': 'Bearer {}'.format(token['id'])} + _url = "{0}/nst/v1/netslice_templates/{1}/nst".format(self._base_path,id) + try: + r = requests.get(_url, params=None, verify=False, stream=True, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.ok: + result['error'] = False + result['data'] = Util.json2yaml(yaml.load(str(r.text))) + + return result + + def nst_list(self, token): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/yaml", "accept": "application/json", + 'Authorization': 'Bearer {}'.format(token['id'])} + + _url = "{0}/nst/v1/netslice_templates".format(self._base_path) + try: + r = requests.get(_url, params=None, verify=False, stream=True, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.ok: + result['error'] = False + result['data'] = Util.json_loads_byteified(r.text) + + return result + def nsd_list(self, token, filter=None): result = {'error': True, 'data': ''} headers = {"Content-Type": "application/yaml", "accept": "application/json", @@ -342,6 +394,23 @@ class Client(object): return result + def nst_delete(self, token, id): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/yaml", "accept": "application/json", + 'Authorization': 'Bearer {}'.format(token['id'])} + + _url = "{0}/nst/v1/netslice_templates/{1}?FORCE=True".format(self._base_path, id) + try: + r = requests.delete(_url, params=None, verify=False, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.no_content: + result['error'] = False + + return result + def nsd_delete(self, token, id): result = {'error': True, 'data': ''} headers = {"Content-Type": "application/yaml", "accept": "application/json", @@ -377,6 +446,27 @@ class Client(object): result['data'] = Util.json_loads_byteified(r.text) return result + def nst_onboard(self, token, template): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/gzip", "accept": "application/json", + 'Authorization': 'Bearer {}'.format(token['id'])} + _url = "{0}/nst/v1/netslice_templates_content".format(self._base_path) + try: + fileName, fileExtension = os.path.splitext(template.name) + if fileExtension == '.gz': + headers["Content-Type"] = "application/gzip" + else: + headers["Content-Type"] = "application/yaml" + r = requests.post(_url, data=template, verify=False, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.created: + result['error'] = False + result['data'] = Util.json_loads_byteified(r.text) + return result + def nsd_onboard(self, token, package): result = {'error': True, 'data': ''} headers = {"Content-Type": "application/gzip", "accept": "application/json", @@ -515,6 +605,21 @@ class Client(object): return result + def nst_content_update(self, token, id, template): + result = {'error': True, 'data': ''} + headers = {"Content-Type": "application/yaml", "accept": "application/json", + 'Authorization': 'Bearer {}'.format(token['id'])} + _url = "{0}/nst/v1/netslice_templates/{1}/nst_content".format(self._base_path,id) + try: + r = requests.put(_url, data=template, verify=False, headers=headers) + except Exception as e: + log.exception(e) + result['data'] = str(e) + return result + if r.status_code == requests.codes.no_content: + result['error'] = False + return result + def nsd_update(self, token, id, data): result = {'error': True, 'data': ''} headers = {"Content-Type": "application/gzip", "accept": "application/json", diff --git a/netslicehandler/__init__.py b/netslicehandler/__init__.py new file mode 100644 index 0000000..00de7ab --- /dev/null +++ b/netslicehandler/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 EveryUP Srl +# +# 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 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. \ No newline at end of file diff --git a/netslicehandler/apps.py b/netslicehandler/apps.py new file mode 100644 index 0000000..e887243 --- /dev/null +++ b/netslicehandler/apps.py @@ -0,0 +1,21 @@ +# Copyright 2018 EveryUP Srl +# +# 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 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 __future__ import unicode_literals + +from django.apps import AppConfig + + +class NetslicehandlerConfig(AppConfig): + name = 'netslicehandler' diff --git a/netslicehandler/migrations/__init__.py b/netslicehandler/migrations/__init__.py new file mode 100644 index 0000000..00de7ab --- /dev/null +++ b/netslicehandler/migrations/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2018 EveryUP Srl +# +# 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 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. \ No newline at end of file diff --git a/netslicehandler/template/modal/nst_details.html b/netslicehandler/template/modal/nst_details.html new file mode 100644 index 0000000..6537008 --- /dev/null +++ b/netslicehandler/template/modal/nst_details.html @@ -0,0 +1,23 @@ + diff --git a/netslicehandler/template/nst_edit.html b/netslicehandler/template/nst_edit.html new file mode 100644 index 0000000..3cce0a8 --- /dev/null +++ b/netslicehandler/template/nst_edit.html @@ -0,0 +1,177 @@ +{% extends "base.html" %} +{% load get %} +{% load staticfiles %} + + +{% block head_block %} +{{ block.super }} + + + + + +{% endblock %} +{% block title_header_big %} +{{ block.super }} +Network Slices Templates +{% endblock %} +{% block left_sidebar %} + +{% include 'osm/osm_project_left_sidebar.html' %} + +{% endblock %} + + +{% block breadcrumb_body %} +{{ block.super }} +
  • NetSlice Templates
  • +{% endblock %} + +{% block content_body %} +{{ block.super }} + +{% csrf_token %} +
    +
    + + + +
    +
    + +{% endblock %} + +{% block resource_block %} +{{ block.super }} + + + + + + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/netslicehandler/template/nst_list.html b/netslicehandler/template/nst_list.html new file mode 100644 index 0000000..41525ef --- /dev/null +++ b/netslicehandler/template/nst_list.html @@ -0,0 +1,211 @@ +{% extends "base.html" %} +{% load get %} +{% load staticfiles %} + + +{% block head_block %} +{{ block.super }} + + + + + + + +{% endblock %} +{% block title_header_big %} +{{ block.super }} +Network Slices Templates +{% endblock %} +{% block left_sidebar %} + +{% include 'osm/osm_project_left_sidebar.html' %} + +{% endblock %} + + +{% block breadcrumb_body %} +{{ block.super }} +
  • NetSlice Templates
  • +{% endblock %} + +{% block content_body %} +{{ block.super }} +{% include 'modal/nst_details.html' %} +{% csrf_token %} +
    +
    + +
    +
    +

    +
    +
    +
    + + + + + + + + + + + + + +
    NameIdentifierUsage StateActions
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + Just drag and drop files here +
    +
    +
    +
    +
    + +{% endblock %} + +{% block resource_block %} +{{ block.super }} + + + + + + + + + + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/netslicehandler/urls.py b/netslicehandler/urls.py new file mode 100644 index 0000000..097fba8 --- /dev/null +++ b/netslicehandler/urls.py @@ -0,0 +1,26 @@ +# Copyright 2018 EveryUP Srl +# +# 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 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 netslicehandler import views + +urlpatterns = [ + url(r'templates/list$', views.list, name='list_templates'), + url(r'templates/create', views.create_template, name='create_template'), + url(r'templates/onboard', views.onboard_template, name='onboard_template'), + url(r'templates/(?P[-\w]+)/details', views.details, name='details'), + url(r'templates/(?P[-\w]+)/edit', views.edit, name='edit'), + url(r'templates/(?P[-\w]+)/delete', views.delete_template, name='delete_template'), + url(r'templates/(?P[-\w]+)/download', views.download_template, name='download_template'), +] \ No newline at end of file diff --git a/netslicehandler/views.py b/netslicehandler/views.py new file mode 100644 index 0000000..4385cc0 --- /dev/null +++ b/netslicehandler/views.py @@ -0,0 +1,119 @@ +# Copyright 2018 EveryUP Srl +# +# 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 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 yaml +import json +import logging +from sf_t3d.decorators import login_required +from django.http import HttpResponse +from django.shortcuts import render, redirect + +from lib.util import Util +import authosm.utils as osmutils +from lib.osm.osmclient.clientv2 import Client + +logging.basicConfig(level=logging.DEBUG) +log = logging.getLogger('instancehandler/view.py') + +@login_required +def list(request): + user = osmutils.get_user(request) + client = Client() + result = {} + result_client = client.nst_list(user.get_token()) + + result['templates'] = result_client['data'] if result_client and result_client['error'] is False else [] + + return __response_handler(request, result, 'nst_list.html') + +@login_required +def create_template(request, template_id=None): + return + +@login_required +def edit(request, template_id=None): + user = osmutils.get_user(request) + client = Client() + if request.method == 'GET': + page = 'nst_edit.html' + result = client.nst_content(user.get_token(), template_id) + if result['error']: + return __response_handler(request, result, url=page, status=500) + else: + return __response_handler(request, {'template': {'template_id': str(template_id), 'data': result['data']}}, url=page, status=200) + elif request.method == 'POST': + result = client.nst_content_update(user.get_token(), template_id, request.POST.get('text')) + if result['error'] == True: + return __response_handler(request, result['data'], url=None, status=result['data']['status'] if 'status' in result['data'] else 500) + else: + return __response_handler(request, {}, url=None, status=200) + + +@login_required +def details(request, template_id=None): + user = osmutils.get_user(request) + client = Client() + result = client.nst_details(user.get_token(), template_id) + if result['error']: + return __response_handler(request, result['data'], url=None, status=result['data']['status'] if 'status' in result['data'] else 500) + else: + return __response_handler(request, result, url=None, status=200) + +@login_required +def delete_template(request, template_id=None): + user = osmutils.get_user(request) + + client = Client() + result = client.nst_delete(user.get_token(), template_id) + + if result['error']: + return __response_handler(request, result['data'], url=None, status=result['data']['status'] if 'status' in result['data'] else 500) + else: + return __response_handler(request, {}, url=None, status=200) + + +@login_required +def download_template(request, package_id=None): + return + +@login_required +def onboard_template(request): + user = osmutils.get_user(request) + if request.method == 'POST': + data_type = request.POST.get('type') + if data_type == "file": + file_uploaded = request.FILES['file'] + try: + client = Client() + result = client.nst_onboard(user.get_token(), file_uploaded) + except Exception as e: + log.exception(e) + result = {'error': True, 'data': str(e)} + else: + result = {'error': True, 'data': 'Create descriptor: Unknown data type'} + + if result['error']: + return __response_handler(request, result['data'], url=None, status=result['data']['status'] if 'status' in result['data'] else 500) + else: + return __response_handler(request, {}, url=None, status=200) + + +def __response_handler(request, data_res, url=None, to_redirect=None, *args, **kwargs): + raw_content_types = request.META.get('HTTP_ACCEPT', '*/*').split(',') + if not to_redirect and ('application/json' in raw_content_types or url is None): + return HttpResponse(json.dumps(data_res), content_type="application/json", *args, **kwargs) + elif to_redirect: + return redirect(url, *args, **kwargs) + else: + return render(request, url, data_res) \ No newline at end of file diff --git a/packagehandler/template/package_list.html b/packagehandler/template/package_list.html index 7befd12..7ffd8d4 100644 --- a/packagehandler/template/package_list.html +++ b/packagehandler/template/package_list.html @@ -52,6 +52,7 @@ +