bug fix on NSD composer; enabling button compose new descriptor 80/6980/1
authorlombardofr <lombardo@everyup.it>
Tue, 27 Nov 2018 16:03:10 +0000 (17:03 +0100)
committerlombardofr <lombardo@everyup.it>
Tue, 27 Nov 2018 16:03:10 +0000 (17:03 +0100)
Change-Id: I2b50eee0e2a2c20823abf51e2fb0d40c3e1e13ff
Signed-off-by: lombardofr <lombardo@everyup.it>
descriptorhandler/template/descriptorlist.html
descriptorhandler/template/modal/choose_node_id.html [deleted file]
descriptorhandler/template/modal/choose_package_name.html [new file with mode: 0644]
descriptorhandler/urls.py
descriptorhandler/views.py
lib/osm/osm_util.py
lib/osm/osmclient/clientv2.py
projecthandler/template/project/osm/osm_project_descriptors.html

index 5285125..bbe8f21 100644 (file)
@@ -7,12 +7,10 @@
             <h3 class="box-title">
             </h3>
             <div class="box-tools">
-                {% comment %}<div class="btn-group">
-                    <button type="button" class="btn btn-default" data-container="body"
-                    data-toggle="tooltip" data-placement="top" title="Composer"
-                    onclick="">
-                <i class="fa fa-paint-brush"></i> <span> Composer</span></button>
-                </div>{% endcomment %}
+                <div class="btn-group">
+                    <button type="button" class="btn btn-default" data-toggle="modal" data-target="#modal_new_package_name_chooser" >
+                <i class="fa fa-paint-brush"></i> <span> Compose a new {{ descriptor_type|upper }}</span></button>
+                </div>
             </div>
         </div>
         <div class="box-body">
diff --git a/descriptorhandler/template/modal/choose_node_id.html b/descriptorhandler/template/modal/choose_node_id.html
deleted file mode 100644 (file)
index 91c4d20..0000000
+++ /dev/null
@@ -1 +0,0 @@
-{% extends "descriptor/modal/choose_node_id.html" %}
\ No newline at end of file
diff --git a/descriptorhandler/template/modal/choose_package_name.html b/descriptorhandler/template/modal/choose_package_name.html
new file mode 100644 (file)
index 0000000..2211026
--- /dev/null
@@ -0,0 +1,35 @@
+<div class="modal" id="modal_new_package_name_chooser">
+    <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">Create new Package</h4>
+            </div>
+            <form id="formCreatePackage" action='{% url "projects:descriptors:create_package_empty" descriptor_type=descriptor_type %}'
+                  class="form-horizontal"
+                  method="post" enctype="multipart/form-data">
+                {% csrf_token %}
+                <div class="modal-body" id="modal_new_package_name_chooser">
+                    <div class="form-group">
+                        <label for="package_name" class="col-sm-3 control-label">Package name *</label>
+                        <div class="col-sm-6">
+                            <input class="form-control" id="package_name" name="name"
+                                   placeholder="name" required>
+                        </div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-default pull-left" data-dismiss="modal">Cancel</button>
+                    <button class="btn btn-primary"
+                            data-loading-text="<i class='fa fa-circle-o-notch fa-spin'></i> Creating..."
+                            id="create_new_user">Create
+                    </button>
+
+                </div>
+            </form>
+        </div>
+        <!-- /.modal-content -->
+    </div>
+    <!-- /.modal-dialog -->
+</div>
\ No newline at end of file
index b0972d9..481211a 100644 (file)
@@ -19,9 +19,9 @@ from descriptorhandler import views
 
 urlpatterns = [
     url(r'(?P<descriptor_type>\w+)/list$', views.show_descriptors, name='list_descriptors'),
+    url(r'(?P<descriptor_type>\w+)/create', views.create_package_empty, name='create_package_empty'),
     url(r'(?P<descriptor_type>\w+)/(?P<descriptor_id>[-\w]+)(/$)', views.edit_descriptor, name='edit_descriptor'),
-    url(r'(?P<descriptor_type>\w+)/(?P<descriptor_id>[-\w]+)/delete$', views.delete_descriptor,
-        name='delete_descriptor'),
+    url(r'(?P<descriptor_type>\w+)/(?P<descriptor_id>[-\w]+)/delete$', views.delete_descriptor, name='delete_descriptor'),
     url(r'(?P<descriptor_type>\w+)/(?P<descriptor_id>[-\w]+)/clone', views.clone_descriptor, name='clone_descriptor'),
     url(r'(?P<descriptor_type>\w+)/(?P<descriptor_id>[-\w]+)/addElement/(?P<element_type>\w+)', views.addElement,
         name='addElement'),
index 064b5a5..fda9aff 100644 (file)
@@ -90,12 +90,35 @@ def delete_descriptor(request, descriptor_type=None, descriptor_id=None):
             'message': 'An error occurred while processing your request.' if result and result['error'] is True else "Record deleted successfully"}
     }, url)
 
+@login_required
+def create_package_empty(request, descriptor_type=None):
+    user = osmutils.get_user(request)
+    pkg_name = request.POST.get('name', '')
+    try:
+        client = Client()
+        if descriptor_type == 'nsd':
+            result = client.nsd_create_pkg_base(user.get_token(), pkg_name)
+        elif descriptor_type == 'vnfd':
+            result = client.vnfd_create_pkg_base(user.get_token(), pkg_name)
+        else:
+            log.debug('Update descriptor: Unknown data type')
+            result = {'error': True, 'data': 'Update descriptor: Unknown data type'}
+    except Exception as e:
+        log.exception(e)
+        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:
+        result['data']['type'] = descriptor_type
+        return __response_handler(request, result, url=None, status=200)
+
 
 @login_required
 def clone_descriptor(request, descriptor_type=None, descriptor_id=None):
     user = osmutils.get_user(request)
     project_id = user.project_id
-
     try:
         client = Client()
         if descriptor_type == 'nsd':
@@ -111,7 +134,6 @@ def clone_descriptor(request, descriptor_type=None, descriptor_id=None):
     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)
 
@@ -319,7 +341,6 @@ def edit_descriptor(request, descriptor_id=None, descriptor_type=None):
                 result = client.nsd_get(user.get_token(), descriptor_id)
             elif descriptor_type == 'vnfd':
                 result = client.vnfd_get(user.get_token(), descriptor_id)
-
         except Exception as e:
             log.exception(e)
             result = {'error': True, 'data': str(e)}
index 8cf6a4e..7e536cb 100644 (file)
@@ -116,7 +116,7 @@ class OsmUtil():
                 indexes = []
                 for cvnfd in nsd['constituent-vnfd']:
                     indexes.append(int(cvnfd["member-vnf-index"]))
-                memberindex = max(indexes) + 1
+                memberindex = max(indexes) + 1 if len(indexes) > 0 else 1
                 nsd['constituent-vnfd'].append({
                     "member-vnf-index": memberindex,
                     "vnfd-id-ref": element_id
index 414019e..8fbb0d2 100644 (file)
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 #
-
+import errno
 import requests
 import logging
-import json
 import tarfile
 import yaml
-import pyaml
 import StringIO
 from lib.util import Util
 import hashlib
@@ -32,6 +30,7 @@ logging.basicConfig(level=logging.INFO)
 log = logging.getLogger('helper.py')
 logging.getLogger("urllib3").setLevel(logging.INFO)
 
+
 class Client(object):
     def __init__(self):
         self._token_endpoint = 'admin/v1/tokens'
@@ -329,7 +328,7 @@ class Client(object):
 
         _url = "{0}/nsd/v1/ns_descriptors_content/{1}".format(self._base_path, id)
         try:
-            r = requests.delete(_url, params=None, verify=False,headers=headers)
+            r = requests.delete(_url, params=None, verify=False, headers=headers)
         except Exception as e:
             log.exception(e)
             result['data'] = str(e)
@@ -361,13 +360,13 @@ class Client(object):
         result = {'error': True, 'data': ''}
         headers = {"Content-Type": "application/gzip", "accept": "application/json",
                    'Authorization': 'Bearer {}'.format(token['id'])}
-        with open('/tmp/'+package.name, 'wb+') as destination:
+        with open('/tmp/' + package.name, 'wb+') as destination:
             for chunk in package.chunks():
                 destination.write(chunk)
-        headers['Content-File-MD5'] = self.md5(open('/tmp/'+package.name, 'rb'))
+        headers['Content-File-MD5'] = self.md5(open('/tmp/' + package.name, 'rb'))
         _url = "{0}/nsd/v1/ns_descriptors_content/".format(self._base_path)
         try:
-            r = requests.post(_url, data=open('/tmp/'+package.name, 'rb'), verify=False, headers=headers)
+            r = requests.post(_url, data=open('/tmp/' + package.name, 'rb'), verify=False, headers=headers)
         except Exception as e:
             log.exception(e)
             result['data'] = str(e)
@@ -381,13 +380,13 @@ class Client(object):
         result = {'error': True, 'data': ''}
         headers = {"Content-Type": "application/gzip", "accept": "application/json",
                    'Authorization': 'Bearer {}'.format(token['id'])}
-        with open('/tmp/'+package.name, 'wb+') as destination:
+        with open('/tmp/' + package.name, 'wb+') as destination:
             for chunk in package.chunks():
                 destination.write(chunk)
-        headers['Content-File-MD5'] = self.md5(open('/tmp/'+package.name, 'rb'))
+        headers['Content-File-MD5'] = self.md5(open('/tmp/' + package.name, 'rb'))
         _url = "{0}/vnfpkgm/v1/vnf_packages_content".format(self._base_path)
         try:
-            r = requests.post(_url, data=open('/tmp/'+package.name, 'rb'), verify=False, headers=headers)
+            r = requests.post(_url, data=open('/tmp/' + package.name, 'rb'), verify=False, headers=headers)
         except Exception as e:
             log.exception(e)
             result['data'] = str(e)
@@ -397,6 +396,48 @@ class Client(object):
         result['data'] = Util.json_loads_byteified(r.text)
         return result
 
+    def nsd_create_pkg_base(self, token, pkg_name):
+        result = {'error': True, 'data': ''}
+        headers = {"Content-Type": "application/gzip", "accept": "application/json",
+                   'Authorization': 'Bearer {}'.format(token['id'])}
+
+        _url = "{0}/nsd/v1/ns_descriptors_content/".format(self._base_path)
+
+        try:
+            self._create_base_pkg('nsd', pkg_name)
+            r = requests.post(_url, data=open('/tmp/' + pkg_name + '.tar.gz', 'rb'), 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['data'] = r.json()
+            result['error'] = False
+        if r.status_code == requests.codes.conflict:
+            result['data'] = "Invalid ID."
+        return result
+
+    def vnfd_create_pkg_base(self, token, pkg_name):
+        result = {'error': True, 'data': ''}
+        headers = {"Content-Type": "application/gzip", "accept": "application/json",
+                   'Authorization': 'Bearer {}'.format(token['id'])}
+
+        _url = "{0}/vnfpkgm/v1/vnf_packages_content".format(self._base_path)
+
+        try:
+            self._create_base_pkg('vnfd', pkg_name)
+            r = requests.post(_url, data=open('/tmp/' + pkg_name + '.tar.gz', 'rb'), 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['data'] = r.json()
+            result['error'] = False
+        if r.status_code == requests.codes.conflict:
+            result['data'] = "Invalid ID."
+        return result
+
     def nsd_clone(self, token, id):
         result = {'error': True, 'data': ''}
         headers = {"Content-Type": "application/gzip", "accept": "application/json",
@@ -412,7 +453,7 @@ class Client(object):
 
         try:
             r = requests.post(_url, data=open('/tmp/' + tarf.getnames()[0] + "_clone.tar.gz", 'rb'), verify=False,
-                             headers=headers)
+                              headers=headers)
         except Exception as e:
             log.exception(e)
             result['data'] = str(e)
@@ -440,7 +481,7 @@ class Client(object):
 
         try:
             r = requests.post(_url, data=open('/tmp/' + tarf.getnames()[0] + "_clone.tar.gz", 'rb'), verify=False,
-                             headers=headers)
+                              headers=headers)
         except Exception as e:
             log.exception(e)
             result['data'] = str(e)
@@ -506,7 +547,7 @@ class Client(object):
 
     def get_nsd_pkg(self, token, id):
         result = {'error': True, 'data': ''}
-        headers = { "accept": "application/zip",
+        headers = {"accept": "application/zip",
                    'Authorization': 'Bearer {}'.format(token['id'])}
 
         _url = "{0}/nsd/v1/ns_descriptors/{1}/nsd_content".format(self._base_path, id)
@@ -556,6 +597,59 @@ class Client(object):
         tarf_temp.close()
         return tarf
 
+    def _create_base_pkg(self, descriptor_type, pkg_name):
+        filename = '/tmp/'+pkg_name+'/' + pkg_name + '.yaml'
+        if descriptor_type == 'nsd':
+            descriptor = {
+                "nsd:nsd-catalog": {
+                    "nsd": [
+                        {
+                            "short-name": str(pkg_name),
+                            "vendor": "OSM Composer",
+                            "description": str(pkg_name) + " descriptor",
+                            "vld": [],
+                            "constituent-vnfd": [],
+                            "version": "1.0",
+                            "id": str(pkg_name),
+                            "name": str(pkg_name)
+                        }
+                    ]
+                }
+            }
+
+        elif descriptor_type == 'vnfd':
+            descriptor = {
+                "vnfd:vnfd-catalog": {
+                    "vnfd": [
+                        {
+                            "short-name": str(pkg_name),
+                            "vdu": [],
+                            "description": "",
+                            "mgmt-interface": {},
+                            "id": str(pkg_name),
+                            "version": "1.0",
+                            "internal-vld": [],
+                            "connection-point": [],
+                            "name": str(pkg_name)
+                        }
+                    ]
+                }
+            }
+
+        if not os.path.exists(os.path.dirname(filename)):
+            try:
+                os.makedirs(os.path.dirname(filename))
+            except OSError as exc:  # Guard against race condition
+                if exc.errno != errno.EEXIST:
+                    raise
+
+        with open('/tmp/' + pkg_name + '/' + pkg_name + '.yaml', 'w') as yaml_file:
+            yaml_file.write(yaml.dump(descriptor, default_flow_style=False))
+
+        tarf_temp = tarfile.open('/tmp/' + pkg_name + '.tar.gz', "w:gz")
+        tarf_temp.add('/tmp/'+pkg_name+'/' + pkg_name + '.yaml', pkg_name + '/' + pkg_name + '.yaml', recursive=False)
+        tarf_temp.close()
+
     def _descriptor_clone(self, tarf, descriptor_type):
         # extract the package on a tmp directory
         tarf.extractall('/tmp')
@@ -569,8 +663,8 @@ class Client(object):
                         nsd_list = yaml_object['nsd:nsd-catalog']['nsd']
                         for nsd in nsd_list:
                             nsd['id'] = 'clone_' + nsd['id']
-                            nsd['name'] = 'clone_' +nsd['name']
-                            nsd['short-name'] = 'clone_' +nsd['short-name']
+                            nsd['name'] = 'clone_' + nsd['name']
+                            nsd['short-name'] = 'clone_' + nsd['short-name']
                     elif descriptor_type == 'vnfd':
                         vnfd_list = yaml_object['vnfd:vnfd-catalog']['vnfd']
                         for vnfd in vnfd_list:
@@ -578,7 +672,6 @@ class Client(object):
                             vnfd['name'] = 'clone_' + vnfd['name']
                             vnfd['short-name'] = 'clone_' + vnfd['short-name']
 
-
                     with open('/tmp/' + name, 'w') as yaml_file:
                         yaml_file.write(yaml.dump(yaml_object, default_flow_style=False))
                 break
@@ -815,7 +908,7 @@ class Client(object):
             return result
         if r.status_code == requests.codes.ok:
             result['error'] = False
-        #result['data'] = Util.json_loads_byteified(r.text)
+        # result['data'] = Util.json_loads_byteified(r.text)
         result['data'] = r.text
         return result
 
@@ -832,7 +925,7 @@ class Client(object):
             return result
         if r.status_code == requests.codes.ok:
             result['error'] = False
-        #result['data'] = Util.json_loads_byteified(r.text)
+        # result['data'] = Util.json_loads_byteified(r.text)
         result['data'] = r.text
         return result
 
@@ -855,7 +948,7 @@ class Client(object):
 
     def vim_delete(self, token, id):
         result = {'error': True, 'data': ''}
-        headers = { "accept": "application/json",
+        headers = {"accept": "application/json",
                    'Authorization': 'Bearer {}'.format(token['id'])}
         _url = "{0}/admin/v1/vims/{1}".format(self._base_path, id)
         try:
@@ -957,7 +1050,6 @@ class Client(object):
         result['data'] = Util.json_loads_byteified(r.text)
         return result
 
-
     def sdn_create(self, token, sdn_data):
         result = {'error': True, 'data': ''}
         headers = {"Content-Type": "application/json", "accept": "application/json",
@@ -976,7 +1068,6 @@ class Client(object):
         result['data'] = Util.json_loads_byteified(r.text)
         return result
 
-
     @staticmethod
     def md5(f):
         hash_md5 = hashlib.md5()
index 2491bf0..bf40773 100644 (file)
@@ -35,6 +35,7 @@
        {{ block.super }}
 {% include 'osm/modal/files_list.html' %}
 {% include 'modal/instance_create.html' %}
+{% include 'modal/choose_package_name.html' %}
 <div class="row">
     {% include "descriptorlist.html" %}
 </div>
         });
 
         setInterval(refreshTable, 10000);
+
+
+        $("#formCreatePackage").submit(function (event) {
+                event.preventDefault(); //prevent default action
+                var post_url = $(this).attr("action"); //get form action url
+                var request_method = $(this).attr("method");
+                var form_data = new FormData(this); //Encode form elements for submission
+
+                $.ajax({
+                    url: post_url,
+                    type: request_method,
+                    data: form_data,
+                    headers: {
+                        "Accept": 'application/json'
+                    },
+                    contentType: false,
+                    processData: false
+                }).done(function (response, textStatus, jqXHR) {
+
+                    location.href='/projects/descriptors/composer?type=' + response['data']['type']+'&id=' + response['data']['id'];
+                }).fail(function (result) {
+                    var data = result.responseJSON;
+                    var title = "Error " + (data.code ? data.code : 'unknown');
+                    var message = data.detail ? data.detail : 'No detail available.';
+                    bootbox.alert({
+                        title: title,
+                        message: message
+                    });
+                });
+            });
     });
+
+
     </script>