Network Slice Templates 04/7104/1
authorlombardofr <lombardo@everyup.it>
Wed, 16 Jan 2019 09:59:18 +0000 (10:59 +0100)
committerlombardofr <lombardo@everyup.it>
Wed, 16 Jan 2019 09:59:18 +0000 (10:59 +0100)
Change-Id: I9453c518cc717e514598e40e2b1ce5ff60b76108
Signed-off-by: lombardofr <lombardo@everyup.it>
22 files changed:
bower.json
build-debpkg.sh
descriptorhandler/views.py
lib/osm/osmclient/clientv2.py
netslicehandler/__init__.py [new file with mode: 0644]
netslicehandler/apps.py [new file with mode: 0644]
netslicehandler/migrations/__init__.py [new file with mode: 0644]
netslicehandler/template/modal/nst_details.html [new file with mode: 0644]
netslicehandler/template/nst_edit.html [new file with mode: 0644]
netslicehandler/template/nst_list.html [new file with mode: 0644]
netslicehandler/urls.py [new file with mode: 0644]
netslicehandler/views.py [new file with mode: 0644]
packagehandler/template/package_list.html
packagehandler/template/package_list_ns.html
packagehandler/template/package_list_vnf.html
projecthandler/template/project/osm/osm_project_left_sidebar.html
sf_t3d/settings.py
sf_t3d/urls.py
static/src/drop_zone.js [new file with mode: 0644]
static/src/netslicehandler/onboard_template.js [new file with mode: 0644]
static/src/netslicehandler/templates_list.js [new file with mode: 0644]
static/src/packagehandler/onboard_package.js

index 0a2e2a3..acfbc66 100644 (file)
@@ -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"
   }
 }
index 710edf5..d1becda 100755 (executable)
@@ -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
index e5728fb..4c49a6d 100644 (file)
@@ -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)
 
index d900af6..191385e 100644 (file)
@@ -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 (file)
index 0000000..00de7ab
--- /dev/null
@@ -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 (file)
index 0000000..e887243
--- /dev/null
@@ -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 (file)
index 0000000..00de7ab
--- /dev/null
@@ -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 (file)
index 0000000..6537008
--- /dev/null
@@ -0,0 +1,23 @@
+<div class="modal" id="modal_show_nst" xmlns="http://www.w3.org/1999/html">
+    <div   class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">×</span></button>
+                <h4 class="modal-title" >Network Slices Template details</h4>
+            </div>
+
+            <div class="modal-body" id="modal_show_nst_body" >
+                <textarea id="nst_view_json">
+                </textarea>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
+
+            </div>
+
+        </div>
+        <!-- /.modal-content -->
+    </div>
+    <!-- /.modal-dialog -->
+</div>
diff --git a/netslicehandler/template/nst_edit.html b/netslicehandler/template/nst_edit.html
new file mode 100644 (file)
index 0000000..3cce0a8
--- /dev/null
@@ -0,0 +1,177 @@
+{% extends "base.html" %}
+{% load get %}
+{% load staticfiles %}
+
+
+{% block head_block %}
+{{ block.super }}
+<link rel="stylesheet" href="/static/bower_components/codemirror/lib/codemirror.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/fold/foldgutter.css" />
+<link rel="stylesheet" href="/static/bower_components/codemirror/theme/neat.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/dialog/dialog.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/display/fullscreen.css">
+{% 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 }}
+<li><a href="{% url "netslices:list_templates" %}">NetSlice Templates</a></li>
+{% endblock %}
+
+{% block content_body %}
+{{ block.super }}
+
+{% csrf_token %}
+<div class="row">
+    <div class="col-md-12">
+        <div class="nav-tabs-custom" style="position: relative;">
+            <ul class="nav nav-tabs" >
+                <li class="active" id="yaml_li"><a href="#yaml" data-toggle="tab"><i class="fa fa-file-code-o"></i> YAML</a></li>
+                <li class="pull-right"><button id="save" type="button" class="btn btn-block btn-primary btn-sm"  onclick="update()" ><i class="fa fa-save"></i> Update</button></li>
+
+            </ul>
+            <div class="alert alert-success" id="success-alert" style="position: absolute; z-index: 100; top: 44px; left: 0; width: 100%;
+            border-radius: 1px;
+            background-color: rgba(0, 166, 90, 0.8) !important;
+            text-align: center;
+            border-color: rgba(0, 141, 76, 0.4);" hidden>
+            <button type="button" class="close" onclick="$('#success-alert').toggle()">x</button>
+            <strong>Success! </strong>
+            Template updated!
+            </div>
+            <div class="tab-content">
+                    <div class="active tab-pane" id="yaml">
+                            <textarea id="code_editor_yaml">
+                            </textarea>
+                        </div>
+            </div>
+        </div>
+        
+        <!-- <div class="box">
+            <div class="box-header with-border">
+                <h3 class="box-title"></h3>
+                <div class="box-tools"></div>
+            </div>
+            <div class="box-body">
+                <textarea id="code_editor_yaml">
+                </textarea>
+            </div>
+        </div> -->
+    </div>
+</div>
+
+{% endblock %}
+
+{% block resource_block %}
+{{ block.super }}
+<script src="/static/bower_components/codemirror/lib/codemirror.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/fold/foldcode.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/fold/foldgutter.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/fold/brace-fold.js" ></script>
+    <script src="/static/bower_components/codemirror/mode/javascript/javascript.js" ></script>
+    <script src="/static/bower_components/codemirror/mode/yaml/yaml.js" ></script>
+    <script src="/static/bower_components/codemirror/mode/markdown/markdown.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/search/searchcursor.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/search/search.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/dialog/dialog.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/display/autorefresh.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/edit/matchbrackets.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/edit/closebrackets.js" ></script>
+    <script src="/static/bower_components/codemirror/addon/display/fullscreen.js" ></script>
+    <script src="/static/bower_components/codemirror/keymap/sublime.js" ></script>
+<script>
+    var csrf_token = '{{csrf_token}}';
+    
+    var table;
+    var yaml_editor_settings = {
+            mode: "yaml",
+            showCursorWhenSelecting: true,
+            autofocus: true,
+            autoRefresh: true,
+            lineNumbers: true,
+            lineWrapping: true,
+            foldGutter: true,
+            gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
+            autoCloseBrackets: true,
+            matchBrackets: true,
+            extraKeys: {
+                "F11": function (cm) {
+                    cm.setOption("fullScreen", !cm.getOption("fullScreen"));
+                },
+                "Esc": function (cm) {
+                    if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
+                },
+                "Ctrl-Q": function (cm) {
+                    cm.foldCode(cm.getCursor());
+                }
+            },
+            theme: "neat",
+            keyMap: "sublime"
+        };
+
+    
+        var myYamlTextArea = document.getElementById("code_editor_yaml");
+        var editorYaml = CodeMirror(function (elt) {
+                myYamlTextArea.parentNode.replaceChild(elt, myYamlTextArea);
+            }, yaml_editor_settings);
+
+    var template = {{ template | safe}};
+
+    $(document).ready(function () {
+        
+        editorYaml.setValue(template.data);
+        editorYaml.setSize("auto", "auto");
+       
+    });
+
+    function update() {
+        var dialog = bootbox.dialog({
+            message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i> Loading...</div>',
+            closeButton: false
+        });
+
+        
+        text = editorYaml.getValue();
+       
+        $.ajax({
+            url: window.location.href,
+            type: 'POST',
+            dataType: 'json',
+            data: {
+                'csrfmiddlewaretoken': '{{csrf_token}}',
+                'text': text
+            },
+            success: function (result) {
+                
+                dialog.modal('hide');
+                $("#success-alert").fadeTo(2000, 500).slideDown(500, function(){
+                    setTimeout(function () {
+                        $("#success-alert").slideUp(500);
+                    }, 2000);
+
+                });
+            },
+            error: function (result) {
+                dialog.modal('hide');
+                var data = result.responseJSON;
+                var title = "Error " + (data && data.code ? data.code : 'unknown');
+                var message = data && data.detail ? data.detail : 'No detail available.';
+                bootbox.alert({
+                    title: title,
+                    message: message
+                });
+            }
+        });
+    }
+</script>
+
+{% 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 (file)
index 0000000..41525ef
--- /dev/null
@@ -0,0 +1,211 @@
+{% extends "base.html" %}
+{% load get %}
+{% load staticfiles %}
+
+
+{% block head_block %}
+{{ block.super }}
+<link rel="stylesheet" href="/static/bower_components/codemirror/lib/codemirror.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/fold/foldgutter.css" />
+<link rel="stylesheet" href="/static/bower_components/codemirror/theme/neat.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/dialog/dialog.css">
+<link rel="stylesheet" href="/static/bower_components/codemirror/addon/display/fullscreen.css">
+<link rel="stylesheet" href="/static/bower_components/select2/dist/css/select2.min.css">
+<link rel="stylesheet" href="/static/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
+{% 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 }}
+<li><a href="{% url "netslices:list_templates" %}">NetSlice Templates</a></li>
+{% endblock %}
+
+{% block content_body %}
+{{ block.super }}
+{% include 'modal/nst_details.html' %}
+{% csrf_token %}
+<div class="row">
+    <div class="col-md-12">
+
+        <div class="box">
+            <div class="box-header with-border">
+                <h3 class="box-title"></h3>
+                <div class="box-tools"></div>
+            </div>
+            <div class="box-body">
+                <table id="templates_table" class="table table-bordered table-striped dataTable" role="grid">
+                    <thead>
+                        <tr role="row">
+                            <th>Name</th>
+                            <th>Identifier</th>
+                            <th>Usage State</th>
+                            <th>Actions</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+
+                    </tbody>
+
+                </table>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="row">
+    <div class="col-sm-12">
+        <div class="box box-solid">
+            <div class="box-body">
+
+                <div class="upload-drop-zone" id="drop-zone">
+                    <i class="fa fa-upload"></i> Just drag and drop files here
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+
+{% endblock %}
+
+{% block resource_block %}
+{{ block.super }}
+<script src="/static/bower_components/select2/dist/js/select2.js"></script>
+<script src="/static/bower_components/codemirror/lib/codemirror.js"></script>
+<script src="/static/bower_components/codemirror/addon/fold/foldcode.js"></script>
+<script src="/static/bower_components/codemirror/addon/fold/foldgutter.js"></script>
+<script src="/static/bower_components/codemirror/addon/fold/brace-fold.js"></script>
+<script src="/static/bower_components/codemirror/mode/javascript/javascript.js"></script>
+<script src="/static/bower_components/codemirror/addon/search/searchcursor.js"></script>
+<script src="/static/bower_components/codemirror/addon/search/search.js"></script>
+<script src="/static/bower_components/codemirror/addon/dialog/dialog.js"></script>
+<script src="/static/bower_components/codemirror/addon/display/autorefresh.js"></script>
+<script src="/static/bower_components/codemirror/addon/edit/matchbrackets.js"></script>
+<script src="/static/bower_components/codemirror/addon/edit/closebrackets.js"></script>
+<script src="/static/bower_components/codemirror/addon/display/fullscreen.js"></script>
+<script src="/static/bower_components/codemirror/keymap/sublime.js"></script>
+<script src="/static/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
+<script src="/static/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
+<script src="/static/src/drop_zone.js"></script>
+<script src="/static/src/netslicehandler/onboard_template.js"></script>
+<script src="/static/src/netslicehandler/templates_list.js"></script>
+<script>
+    var csrf_token = '{{csrf_token}}';
+    var table;
+
+    var editorJSON;
+
+
+
+    $(document).ready(function () {
+        table = $('#templates_table').DataTable({
+            responsive: true,
+            "ajax": {
+                "url": "netslices/templates/list",
+                "dataSrc": function (json) {
+                    return json['templates'];
+                },
+                statusCode: {
+                    401: function () {
+                        console.log("no auth");
+                        moveToLogin(window.location.pathname);
+                    }
+                },
+                "error": function (hxr, error, thrown) {
+                    console.log(hxr)
+                    console.log(thrown)
+                    console.log(error);
+                }
+
+            },
+            "columns": [
+                {
+                    "render": function (data, type, row) {
+                        return row['name'] || '';
+                    },
+                    "targets": 0
+                },
+                {
+                    "render": function (data, type, row) {
+                        return row['_id'];
+                    },
+                    "targets": 1
+                },
+                {
+                    "render": function (data, type, row) {
+                        return row['_admin']['usageState'];
+                    },
+                    "targets": 2
+                },
+                {
+                    "render": function (data, type, row) {
+                        return '<div class="btn-group">' +
+                            '     <button type="button" class="btn btn-default"' +
+                            '             onclick="javascript:showNstDetails(\'' + row["_id"] + '\')"' +
+                            '             data-toggle="tooltip" data-placement="top" data-container="body" title="Open">' +
+                            '         <i class="fa fa-info"></i>' +
+                            '     </button>' +
+                            '     <button type="button" class="btn btn-default"' +
+                            '             onclick="window.location.href=\'/netslices/templates/'+row["_id"]+'/edit\'"' +
+                            '             data-toggle="tooltip" data-placement="top" data-container="body" title="Edit">' +
+                            '         <i class="fa fa-edit"></i>' +
+                            '     </button>' +
+                            '<button type="button" class="btn btn-default"' +
+                            '         onclick="javascript:deleteTemplate(\'' + row["name"] + '\', \'' + row["_id"] + '\')"' +
+                            '         data-toggle="tooltip" data-placement="top" data-container="body" title="Delete"><i' +
+                            '         class="far fa-trash-alt"></i></button>' +
+                            ' </div>';
+                    },
+                    "targets": 3,
+                    "orderable": false
+                }
+            ]
+        });
+
+        setInterval(function () {
+            refreshTable();
+        }, 10000);
+
+        var json_editor_settings = {
+            mode: "javascript",
+            showCursorWhenSelecting: true,
+            autofocus: true,
+            lineNumbers: true,
+            lineWrapping: true,
+            foldGutter: true,
+            gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
+            autoCloseBrackets: true,
+            matchBrackets: true,
+            extraKeys: {
+                "F11": function (cm) {
+                    cm.setOption("fullScreen", !cm.getOption("fullScreen"));
+                },
+                "Esc": function (cm) {
+                    if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
+                },
+                "Ctrl-Q": function (cm) {
+                    cm.foldCode(cm.getCursor());
+                }
+            },
+            theme: "neat",
+            keyMap: "sublime"
+        };
+        var myJsonTextArea = document.getElementById("nst_view_json");
+        editorJSON = CodeMirror(function (elt) {
+            myJsonTextArea.parentNode.replaceChild(elt, myJsonTextArea);
+        }, json_editor_settings);
+    });
+
+    function refreshTable() {
+        table.ajax.reload();
+    }
+</script>
+
+{% endblock %}
\ No newline at end of file
diff --git a/netslicehandler/urls.py b/netslicehandler/urls.py
new file mode 100644 (file)
index 0000000..097fba8
--- /dev/null
@@ -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<template_id>[-\w]+)/details', views.details, name='details'),
+    url(r'templates/(?P<template_id>[-\w]+)/edit', views.edit, name='edit'),
+    url(r'templates/(?P<template_id>[-\w]+)/delete', views.delete_template, name='delete_template'),
+    url(r'templates/(?P<template_id>[-\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 (file)
index 0000000..4385cc0
--- /dev/null
@@ -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
index 7befd12..7ffd8d4 100644 (file)
@@ -52,6 +52,7 @@
      <script src="/static/bower_components/select2/dist/js/select2.js"></script>
     <script src="/static/src/instancehandler/instance_create.js"></script>
     <script src="/static/src/packagehandler/packages_list.js"></script>
+    <script src="/static/src/drop_zone.js"></script>
     <script src="/static/src/packagehandler/onboard_package.js"></script>
 
     <script>
                     },
                     "targets": 6,
                     "orderable": false
-                }]
+                }
+            ]
     };
     function refreshTable() {
         var type_vnf = $('#type_vnf').val()
index 3fae096..eb12c7e 100644 (file)
@@ -19,7 +19,7 @@
                 <thead>
                 <tr role="row">
                     <th>Short Name</th>
-                    <th>Identified</th>
+                    <th>Identifier</th>
                     <th>Description</th>
                     <th style="width:10%">Vendor</th>
                     <th style="width:5%">Version</th>
index ead7d94..c33663f 100644 (file)
@@ -19,7 +19,7 @@
                 <thead>
                 <tr role="row">
                     <th>Short Name</th>
-                    <th>Identified</th>
+                    <th>Identifier</th>
                     <th>
                         <select name="type" id="type_vnf" class="form-control">
                         <option value="">Type</option>
index ba649a9..1855827 100644 (file)
 
                 </ul>
             </li>
+            {% url "netslices:list_templates"   as netslices_temaplates %}
+            <li {% if request.get_full_path == netslices_temaplates %} class="active" {% endif %}>
+                <a href='{% url "netslices:list_templates"   %}'>
+                    <i class="fas fa-layer-group fa-fw""></i> <span>NetSlice Templates</span>
+                </a>
+            </li>
             {% url "instances:list"  type='ns' as  instance_ns_list_url %}
             {% url "instances:list"  type='vnf' as  instance_vnf_list_url %}
             {% url "instances:list"  type='pdu' as  instance_vnf_list_url %}
index aae8b5e..21563af 100644 (file)
@@ -58,7 +58,8 @@ INSTALLED_APPS = [
     'vimhandler',
     'instancehandler',
     'sdnctrlhandler',
-    'userhandler'
+    'userhandler',
+    'netslicehandler'
 
 ]
 
@@ -97,6 +98,7 @@ TEMPLATES = [
             os.path.join(BASE_DIR, 'instancehandler', 'template'),
             os.path.join(BASE_DIR, 'sdnctrlhandler', 'template'),
             os.path.join(BASE_DIR, 'userhandler', 'templates'),
+            os.path.join(BASE_DIR, 'netslicehandler', 'template'),
         ],
         'APP_DIRS': True,
         'OPTIONS': {
index c5b3ae0..8333b5d 100644 (file)
@@ -28,6 +28,7 @@ urlpatterns = [
     url(r'^vims/', include('vimhandler.urls', namespace='vims'), name='vims_base'),
     url(r'^packages/', include('packagehandler.urls', namespace='packages'), name='packages_base'),
     url(r'^instances/', include('instancehandler.urls', namespace='instances'), name='instances_base'),
+    url(r'^netslices/', include('netslicehandler.urls', namespace='netslices'), name='netslices_base'),
     url(r'^admin/users/', include('userhandler.urls', namespace='users'), name='users_base'),
     url(r'^forbidden', views.forbidden, name='forbidden'),
 
diff --git a/static/src/drop_zone.js b/static/src/drop_zone.js
new file mode 100644 (file)
index 0000000..469ce60
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+   Copyright 2019 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.
+*/
+
+var dropZone = document.getElementById('drop-zone');
+dropZone.ondrop = function (e) {
+    e.preventDefault();
+    this.className = 'upload-drop-zone';
+    create(e.dataTransfer.files, true);
+};
+
+dropZone.ondragover = function () {
+    this.className = 'upload-drop-zone drop';
+    return false;
+};
+
+dropZone.ondragleave = function () {
+    this.className = 'upload-drop-zone';
+    return false;
+};
\ No newline at end of file
diff --git a/static/src/netslicehandler/onboard_template.js b/static/src/netslicehandler/onboard_template.js
new file mode 100644 (file)
index 0000000..e999e1a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+   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.
+*/
+
+function create(fs, dropzone) {
+    var url = '/netslices/templates/onboard';
+    var id = $('.nav-tabs .active').attr('id');
+    if (dropzone) id = 'file_li';
+    var type, text;
+    var data = new FormData();
+    switch (id) {
+
+        case 'file_li':
+            type = 'file';
+
+            var files = dropzone ? fs : document.getElementById('js-upload-files').files;
+            if (!files || !files.length) {
+                files = document.getElementById('drop-zone').files;
+                if (!files || !files.length) {
+                    alert("Select a file");
+                    return
+                }
+            }
+            console.log(files[0])
+            var patt1 = /\.([0-9a-z]+)(?:[\?#]|$)/i;
+            console.log(files[0].name.match(patt1));
+            var extension = files[0].name.substr(files[0].name.lastIndexOf('.') + 1);
+            console.log(extension);
+
+            data.append('file', files[0]);
+            break;
+    }
+    data.append('csrfmiddlewaretoken', csrf_token);
+    data.append('type', type);
+    data.append('text', text);
+    data.append('id', '{{descriptor_id}}');
+    console.log(text);
+    var dialog = bootbox.dialog({
+                message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i> Onboarding...</div>',
+                closeButton: true
+            });
+    $.ajax({
+        url: url,
+        type: 'POST',
+        data: data,
+        cache: false,
+        contentType: false,
+        processData: false,
+        success: function (result) {
+            dialog.modal('hide');
+            refreshTable();
+        },
+        error: function (result) {
+            dialog.modal('hide');
+            showAlert(result);
+        }
+    });
+}
\ No newline at end of file
diff --git a/static/src/netslicehandler/templates_list.js b/static/src/netslicehandler/templates_list.js
new file mode 100644 (file)
index 0000000..813b395
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+   Copyright 2019 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.
+*/
+
+function deleteTemplate(template_name, template_id) {
+    var url = '/netslices/templates/'+template_id+'/delete';
+    bootbox.confirm("Are you sure want to delete " + template_name + "?", function (result) {
+        if (result) {
+            var dialog = bootbox.dialog({
+                message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i> Loading...</div>',
+                closeButton: true
+            });
+            $.ajax({
+                url: url,
+                type: 'GET',
+                dataType: "json",
+                contentType: "application/json;charset=utf-8",
+                success: function (result) {
+                    if (result['error'] == true){
+                        dialog.modal('hide');
+                        bootbox.alert("An error occurred.");
+                    }
+                    else {
+                        dialog.modal('hide');
+                        location.reload();
+                    }
+                },
+                error: function (error) {
+                    dialog.modal('hide');
+                    bootbox.alert("An error occurred.");
+                }
+            });
+        }
+    })
+}
+
+function showNstDetails(template_id) {
+    var url_info = '/netslices/templates/'+template_id+'/details';
+    var dialog = bootbox.dialog({
+        message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i> Loading...</div>',
+        closeButton: true
+    });
+    $.ajax({
+        url: url_info,
+        type: 'GET',
+        dataType: "json",
+        contentType: "application/json;charset=utf-8",
+        success: function (result) {
+            console.log(result)
+            if (result['data'] !== undefined) {
+                editorJSON.setValue(JSON.stringify(result['data'], null, "\t"));
+                editorJSON.setOption("autoRefresh", true);
+                dialog.modal('hide');
+                $('#modal_show_nst').modal('show');
+            }
+            else {
+                dialog.modal('hide');
+                bootbox.alert("An error occurred while retrieving the information.");
+            }
+        },
+        error: function (result) {
+            dialog.modal('hide');
+            bootbox.alert("An error occurred while retrieving the information.");
+        }
+    });
+}
\ No newline at end of file
index d18be5b..194bcdc 100644 (file)
    limitations under the License.
 */
 
-var dropZone = document.getElementById('drop-zone');
-dropZone.ondrop = function (e) {
-    e.preventDefault();
-    this.className = 'upload-drop-zone';
-    create(e.dataTransfer.files, true);
-};
-
-dropZone.ondragover = function () {
-    this.className = 'upload-drop-zone drop';
-    return false;
-};
-
-dropZone.ondragleave = function () {
-    this.className = 'upload-drop-zone';
-    return false;
-};
-
-
 function create(fs, dropzone) {
     var id = $('.nav-tabs .active').attr('id');
     if (dropzone) id = 'file_li';