Implement read VNFD API 37/98437/1
authordyh <dengyuanhong@chinamobile.com>
Fri, 15 Nov 2019 01:26:18 +0000 (09:26 +0800)
committerdyh <dengyuanhong@chinamobile.com>
Fri, 15 Nov 2019 01:26:33 +0000 (09:26 +0800)
Issue-ID: MODELING-266
Change-Id: Ib5e4a965c080329f68d407b414a347298da6a84b
Signed-off-by: dyh <dengyuanhong@chinamobile.com>
catalog/packages/biz/sdc_vnf_package.py
catalog/packages/biz/vnf_package.py
catalog/packages/tests/test_vnf_package.py
catalog/packages/urls.py
catalog/packages/views/vnf_package_views.py
catalog/pub/config/config.py
docs/index.rst
docs/introduction.rst
static/catalog/resource_test.csar

index e5be4a1..2160a00 100644 (file)
@@ -18,7 +18,9 @@ import os
 import sys
 import threading
 import traceback
+import zipfile
 
+from catalog.packages.biz.vnf_package import VnfPackage
 from catalog.packages.const import PKG_STATUS
 from catalog.pub.config.config import CATALOG_ROOT_PATH, CATALOG_URL_PATH
 from catalog.pub.config.config import REG_TO_MSB_REG_PARAM
@@ -123,7 +125,7 @@ class NfDistributeThread(threading.Thread):
         local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path, csar_name)
         if local_file_name.endswith(".csar") or local_file_name.endswith(".zip"):
             fileutil.unzip_csar(local_file_name, local_path)
-            vendor_vnf_file = ""
+            vendor_vnf_file = ''
             # find original vendor ETSI package under the ONBOARDING_PACKAGE directory
             onboarding_package_dir = os.path.join(local_path, "Artifacts/Deployment/ONBOARDED_PACKAGE")
             if os.path.exists(onboarding_package_dir):
@@ -135,13 +137,16 @@ class NfDistributeThread(threading.Thread):
                         break
 
             # find original vendor ETSI package under Artifacts/Deployment/OTHER directory
-            if vendor_vnf_file.isspace():
+            if vendor_vnf_file.strip() == '':
                 vendor_vnf_file = os.path.join(local_path, "Artifacts/Deployment/OTHER/vnf.csar")
                 if os.path.exists(vendor_vnf_file):
                     local_file_name = vendor_vnf_file
             else:
                 local_file_name = vendor_vnf_file
 
+        # create VNFD zip file
+        self.create_vnfd_zip(self.csar_id, vendor_vnf_file)
+
         vnfd_json = toscaparser.parse_vnfd(local_file_name)
         vnfd = json.JSONDecoder().decode(vnfd_json)
 
@@ -173,6 +178,32 @@ class NfDistributeThread(threading.Thread):
         ).save()
         JobUtil.add_job_status(self.job_id, 100, "CSAR(%s) distribute successfully." % self.csar_id)
 
+    def create_vnfd_zip(self, csar_id, vendor_vnf_file):
+        """
+        Create VNFD zip file.
+        :param csar_id: CSAR Id
+        :param vendor_vnf_file: the vendor original package(csar)
+        :return:
+        """
+        if os.path.exists(vendor_vnf_file):
+            # create VNFD from vendor original package
+            VnfPackage().creat_vnfd(csar_id, vendor_vnf_file)
+        else:
+            try:
+                vnf_package_path = os.path.join(CATALOG_ROOT_PATH, self.csar_id)
+                vnfd_zip_file = os.path.join(vnf_package_path, 'VNFD.zip')
+                with zipfile.ZipFile(vnfd_zip_file, 'w', zipfile.ZIP_DEFLATED) as vnfd_zip:
+                    def_path = os.path.join(vnf_package_path, "Definitions")
+                    if os.path.exists(def_path):
+                        def_files = os.listdir(def_path)
+                        for def_file in def_files:
+                            full_path = os.path.join(def_path, def_file)
+                            vnfd_zip.write(full_path, def_file)
+            except Exception as e:
+                logger.error(e)
+                if os.path.exists(vnfd_zip_file):
+                    os.remove(vnfd_zip_file)
+
     def rollback_distribute(self):
         try:
             VnfPackageModel.objects.filter(vnfPackageId=self.csar_id).delete()
index 21d5819..5a51e9a 100644 (file)
@@ -20,16 +20,16 @@ import threading
 import traceback
 import urllib
 import uuid
+import zipfile
 
+from catalog.packages import const
 from catalog.packages.biz.common import parse_file_range, read, save
+from catalog.packages.biz.notificationsutil import prepare_vnfpkg_notification, NotificationsUtil
 from catalog.pub.config.config import CATALOG_ROOT_PATH
 from catalog.pub.database.models import VnfPackageModel, NSPackageModel
 from catalog.pub.exceptions import CatalogException, ResourceNotFoundException
-from catalog.pub.utils.values import ignore_case_get
 from catalog.pub.utils import fileutil, toscaparser
-from catalog.packages import const
-from catalog.packages.biz.notificationsutil import prepare_vnfpkg_notification, NotificationsUtil
-
+from catalog.pub.utils.values import ignore_case_get
 
 logger = logging.getLogger(__name__)
 
@@ -132,6 +132,58 @@ class VnfPackage(object):
         logger.info('VNF package (%s) has been downloaded.' % vnf_pkg_id)
         return read(local_file_path, start, end)
 
+    def download_vnfd(self, vnf_pkg_id):
+        logger.info('Start to download VNFD of VNF package(%s)...' % vnf_pkg_id)
+        nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
+        if not nf_pkg.exists():
+            logger.error('VNF package(%s) does not exist.' % vnf_pkg_id)
+            raise ResourceNotFoundException('VNF package(%s) does not exist.' % vnf_pkg_id)
+        if nf_pkg[0].onboardingState != const.PKG_STATUS.ONBOARDED:
+            raise CatalogException("VNF package (%s) is not on-boarded" % vnf_pkg_id)
+
+        vnfd_zip_file = self.creat_vnfd(vnf_pkg_id, nf_pkg[0].localFilePath)
+        logger.info('VNFD of VNF package (%s) has been downloaded.' % vnf_pkg_id)
+        return read(vnfd_zip_file, 0, os.path.getsize(vnfd_zip_file))
+
+    def creat_vnfd(self, vnf_pkg_id, vendor_pkg_file):
+        """
+        Create VNFD zip file from vendor original package
+        :param self:
+        :param vnf_pkg_id: VNF package id (CSAR id)
+        :param vendor_pkg_file: vendor original package
+        :return:
+        """
+        vnf_package_path = os.path.join(CATALOG_ROOT_PATH, vnf_pkg_id)
+        if not os.path.exists(vnf_package_path):
+            os.makedirs(vnf_package_path)
+        vnfd_zip_file = os.path.join(vnf_package_path, "VNFD.zip")
+        if os.path.exists(vnfd_zip_file):
+            return vnfd_zip_file
+        else:
+            if vendor_pkg_file.endswith(".csar") or vendor_pkg_file.endswith(".zip"):
+                try:
+                    vnfd_path = os.path.join(vnf_package_path, "vnfd")
+                    with zipfile.ZipFile(vendor_pkg_file, 'r') as vendor_zip:
+                        vender_files = vendor_zip.namelist()
+                        for vender_file in vender_files:
+                            if str(vender_file).startswith("Definitions"):
+                                vendor_zip.extract(vender_file, vnfd_path)
+                    with zipfile.ZipFile(vnfd_zip_file, 'w', zipfile.ZIP_DEFLATED) as vnfd_zip:
+                        def_path = os.path.join(vnfd_path, "Definitions")
+                        if os.path.exists(def_path):
+                            def_files = os.listdir(def_path)
+                            for def_file in def_files:
+                                full_path = os.path.join(def_path, def_file)
+                                vnfd_zip.write(full_path, def_file)
+                    return vnfd_zip_file
+                except Exception as e:
+                    logger.error(e)
+                    if os.path.exists(vnfd_zip):
+                        os.remove(vnfd_zip)
+                    raise e
+                finally:
+                    fileutil.delete_dirs(vnfd_path)
+
 
 class VnfPkgUploadThread(threading.Thread):
     def __init__(self, data, vnf_pkg_id):
index b83268a..c0d6637 100644 (file)
 
 import json
 import os
-import urllib
-import mock
 import shutil
+import urllib
+import zipfile
 
+import mock
 from django.test import TestCase
 from rest_framework import status
 from rest_framework.test import APIClient
@@ -29,6 +30,8 @@ from catalog.pub.config.config import CATALOG_ROOT_PATH
 from catalog.pub.database.models import VnfPackageModel
 from catalog.pub.utils import toscaparser
 
+VNF_BASE_URL = "/api/vnfpkgm/v1/vnf_packages"
+
 
 class MockReq():
     def read(self):
@@ -55,7 +58,7 @@ class TestVnfPackage(TestCase):
             onboardingState="CREATED"
         )
         mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
+        response = self.client.put("%s/222/package_content" % VNF_BASE_URL, data=data)
         vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId="222")
         self.assertEqual("zte-hss-1.0", vnf_pkg[0].vnfdId)
         self.assertEqual(PKG_STATUS.ONBOARDED, vnf_pkg[0].onboardingState)
@@ -66,7 +69,7 @@ class TestVnfPackage(TestCase):
         VnfPackageModel.objects.create(
             vnfPackageId="222",
         )
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
+        response = self.client.put("%s/222/package_content" % VNF_BASE_URL, data=data)
         self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
 
     @mock.patch.object(toscaparser, 'parse_vnfd')
@@ -86,14 +89,14 @@ class TestVnfPackage(TestCase):
 
     def test_upload_from_uri_failed(self):
         req_data = {"username": "123"}
-        response = self.client.post("/api/vnfpkgm/v1/vnf_packages/111/package_content/upload_from_uri", data=req_data)
+        response = self.client.post("%s/111/package_content/upload_from_uri" % VNF_BASE_URL, data=req_data)
         self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
 
     def test_create_vnf_pkg(self):
         req_data = {
             "userDefinedData": {"a": "A"}
         }
-        response = self.client.post("/api/vnfpkgm/v1/vnf_packages", data=req_data, format="json")
+        response = self.client.post(VNF_BASE_URL, data=req_data, format="json")
         resp_data = json.loads(response.content)
         expect_resp_data = {
             "id": resp_data.get("id"),
@@ -120,7 +123,7 @@ class TestVnfPackage(TestCase):
             usageState="NOT_IN_USE",
             userDefinedData='{"a": "A"}'
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222")
+        response = self.client.get("%s/222" % VNF_BASE_URL)
         expect_data = {
             "id": "222",
             "vnfdId": "zte-hss-1.0",
@@ -140,7 +143,7 @@ class TestVnfPackage(TestCase):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
     def test_query_single_vnf_failed(self):
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222")
+        response = self.client.get(VNF_BASE_URL + "/222")
         self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
     def test_query_multiple_vnf(self):
@@ -170,7 +173,7 @@ class TestVnfPackage(TestCase):
             usageState="NOT_IN_USE",
             userDefinedData='{"a": "A"}'
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages")
+        response = self.client.get(VNF_BASE_URL)
         expect_data = [
             {
                 "id": "111",
@@ -220,12 +223,12 @@ class TestVnfPackage(TestCase):
             usageState="NOT_IN_USE",
             userDefinedData='{"a": "A"}'
         )
-        response = self.client.delete("/api/vnfpkgm/v1/vnf_packages/222")
+        response = self.client.delete(VNF_BASE_URL + "/222")
         self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
         self.assertEqual(response.data, None)
 
     def test_delete_when_vnf_pkg_not_exist(self):
-        response = self.client.delete("/api/vnfpkgm/v1/vnf_packages/222")
+        response = self.client.delete(VNF_BASE_URL + "/222")
         self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
         self.assertEqual(response.data, None)
 
@@ -237,7 +240,7 @@ class TestVnfPackage(TestCase):
             onboardingState="ONBOARDED",
             localFilePath="vnfPackage.csar"
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content")
+        response = self.client.get(VNF_BASE_URL + "/222/package_content")
         file_content = ''
         for data in response.streaming_content:
             file_content = file_content + data.decode()
@@ -253,7 +256,7 @@ class TestVnfPackage(TestCase):
             onboardingState="ONBOARDED",
             localFilePath="vnfPackage.csar"
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content", HTTP_RANGE="4-7")
+        response = self.client.get("%s/222/package_content" % VNF_BASE_URL, HTTP_RANGE="4-7")
         partial_file_content = ''
         for data in response.streaming_content:
             partial_file_content = partial_file_content + data.decode()
@@ -269,7 +272,7 @@ class TestVnfPackage(TestCase):
             onboardingState="ONBOARDED",
             localFilePath="vnfPackage.csar"
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content", HTTP_RANGE=" 4-")
+        response = self.client.get(VNF_BASE_URL + "/222/package_content", HTTP_RANGE=" 4-")
         partial_file_content = ''
         for data in response.streaming_content:
             partial_file_content = partial_file_content + data.decode()
@@ -278,7 +281,7 @@ class TestVnfPackage(TestCase):
         os.remove("vnfPackage.csar")
 
     def test_fetch_vnf_pkg_when_pkg_not_exist(self):
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content")
+        response = self.client.get(VNF_BASE_URL + "/222/package_content")
         self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
     def test_fetch_vnf_pkg_when_catch_cataloge_exception(self):
@@ -287,96 +290,135 @@ class TestVnfPackage(TestCase):
             onboardingState="CREATED",
             localFilePath="vnfPackage.csar"
         )
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content")
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPackage, "create_vnf_pkg")
-    def test_create_vnf_pkg_when_catch_exception(self, mock_create_vnf_pkg):
-        mock_create_vnf_pkg.side_effect = TypeError('integer type')
-        req_data = {
-            "userDefinedData": {"a": "A"}
-        }
-        response = self.client.post("/api/vnfpkgm/v1/vnf_packages", data=req_data, format="json")
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPackage, "delete_vnf_pkg")
-    def test_delete_single_when_catch_exception(self, mock_delete_vnf_pkg):
-        mock_delete_vnf_pkg.side_effect = TypeError("integer type")
-        response = self.client.delete("/api/vnfpkgm/v1/vnf_packages/222")
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPackage, "query_single")
-    def test_query_single_when_catch_exception(self, mock_query_single):
-        mock_query_single.side_effect = TypeError("integer type")
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222")
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPackage, "query_multiple")
-    def test_query_multiple_when_catch_exception(self, mock_query_muitiple):
-        mock_query_muitiple.side_effect = TypeError("integer type")
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages")
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(toscaparser, 'parse_vnfd')
-    def test_upload_when_catch_exception(self, mock_parse_vnfd):
-        data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "empty.txt"), "rb")}
-        VnfPackageModel.objects.create(
-            vnfPackageId="222",
-            onboardingState="CREATED"
-        )
-        mock_parse_vnfd.side_effect = TypeError("integer type")
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPkgUploadThread, 'start')
-    def test_upload_from_uri_when_catch_exception(self, mock_start):
-        req_data = {"addressInformation": "https://127.0.0.1:1234/sdc/v1/hss.csar"}
-        mock_start.side_effect = TypeError("integer type")
-        response = self.client.post("/api/vnfpkgm/v1/vnf_packages/111/package_content/upload_from_uri", data=req_data)
-        self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
-
-    @mock.patch.object(VnfPackage, 'download')
-    def test_fetch_vnf_pkg_when_catch_exception(self, mock_download):
-        mock_download.side_effect = TypeError("integer type")
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content")
+        response = self.client.get(VNF_BASE_URL + "/222/package_content")
         self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
 
-    @mock.patch.object(toscaparser, 'parse_vnfd')
-    def test_fetch_vnf_artifact(self, mock_parse_vnfd):
-        data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
+    def test_download_vnfd(self):
         VnfPackageModel.objects.create(
             vnfPackageId="222",
-            onboardingState="CREATED"
+            onboardingState="ONBOARDED",
+            localFilePath=os.path.join(CATALOG_ROOT_PATH, "resource_test.csar")
         )
-        mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
-        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/artifacts/image")
+        response = self.client.get(VNF_BASE_URL + "/222/vnfd")
         self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertEqual(response.getvalue(), b"ubuntu_16.04\n")
-
-    @mock.patch.object(toscaparser, 'parse_vnfd')
-    def test_fetch_vnf_artifact_not_exists(self, mock_parse_vnfd):
-        data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
-        VnfPackageModel.objects.create(
-            vnfPackageId="222",
-            onboardingState="CREATED"
-        )
-        mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
-        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/1451/artifacts/image")
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
-
-    @mock.patch.object(toscaparser, 'parse_vnfd')
-    def test_fetch_vnf_artifact_vnf_not_exists(self, mock_parse_vnfd):
-        data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
-        VnfPackageModel.objects.create(
-            vnfPackageId="222",
-            onboardingState="CREATED"
-        )
-        mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
-        response = self.client.put("/api/vnfpkgm/v1/vnf_packages/222/package_content", data=data)
-        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
-        response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/artifacts/image1")
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+        with open("vnfd.csar", 'wb') as local_file:
+            for chunk in response.streaming_content:
+                local_file.write(chunk)
+        self.assertTrue(zipfile.is_zipfile("vnfd.csar"))
+        os.remove("vnfd.csar")
+
+
+def test_download_vnfd_when_pkg_not_exist(self):
+    response = self.client.get(VNF_BASE_URL + "/222/vnfd")
+    self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+
+def test_download_vnfd_when_catch_cataloge_exception(self):
+    VnfPackageModel.objects.create(
+        vnfPackageId="222",
+        onboardingState="CREATED",
+        localFilePath="vnfPackage.csar"
+    )
+    response = self.client.get(VNF_BASE_URL + "/222/vnfd")
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPackage, "create_vnf_pkg")
+def test_create_vnf_pkg_when_catch_exception(self, mock_create_vnf_pkg):
+    mock_create_vnf_pkg.side_effect = TypeError('integer type')
+    req_data = {
+        "userDefinedData": {"a": "A"}
+    }
+    response = self.client.post(VNF_BASE_URL, data=req_data, format="json")
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPackage, "delete_vnf_pkg")
+def test_delete_single_when_catch_exception(self, mock_delete_vnf_pkg):
+    mock_delete_vnf_pkg.side_effect = TypeError("integer type")
+    response = self.client.delete(VNF_BASE_URL + "/222")
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPackage, "query_single")
+def test_query_single_when_catch_exception(self, mock_query_single):
+    mock_query_single.side_effect = TypeError("integer type")
+    response = self.client.get(VNF_BASE_URL + "/222")
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPackage, "query_multiple")
+def test_query_multiple_when_catch_exception(self, mock_query_muitiple):
+    mock_query_muitiple.side_effect = TypeError("integer type")
+    response = self.client.get(VNF_BASE_URL)
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(toscaparser, 'parse_vnfd')
+def test_upload_when_catch_exception(self, mock_parse_vnfd):
+    data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "empty.txt"), "rb")}
+    VnfPackageModel.objects.create(
+        vnfPackageId="222",
+        onboardingState="CREATED"
+    )
+    mock_parse_vnfd.side_effect = TypeError("integer type")
+    response = self.client.put(VNF_BASE_URL + "/222/package_content", data=data)
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPkgUploadThread, 'start')
+def test_upload_from_uri_when_catch_exception(self, mock_start):
+    req_data = {"addressInformation": "https://127.0.0.1:1234/sdc/v1/hss.csar"}
+    mock_start.side_effect = TypeError("integer type")
+    response = self.client.post(VNF_BASE_URL + "/111/package_content/upload_from_uri", data=req_data)
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(VnfPackage, 'download')
+def test_fetch_vnf_pkg_when_catch_exception(self, mock_download):
+    mock_download.side_effect = TypeError("integer type")
+    response = self.client.get(VNF_BASE_URL + "/222/package_content")
+    self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+@mock.patch.object(toscaparser, 'parse_vnfd')
+def test_fetch_vnf_artifact(self, mock_parse_vnfd):
+    data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
+    VnfPackageModel.objects.create(
+        vnfPackageId="222",
+        onboardingState="CREATED"
+    )
+    mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
+    response = self.client.put(VNF_BASE_URL + "/222/package_content", data=data)
+    self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
+    response = self.client.get(VNF_BASE_URL + "/222/artifacts/image")
+    self.assertEqual(response.status_code, status.HTTP_200_OK)
+    self.assertEqual(response.getvalue(), b"ubuntu_16.04\n")
+
+
+@mock.patch.object(toscaparser, 'parse_vnfd')
+def test_fetch_vnf_artifact_not_exists(self, mock_parse_vnfd):
+    data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
+    VnfPackageModel.objects.create(
+        vnfPackageId="222",
+        onboardingState="CREATED"
+    )
+    mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
+    response = self.client.put(VNF_BASE_URL + "/222/package_content", data=data)
+    self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
+    response = self.client.get(VNF_BASE_URL + "/1451/artifacts/image")
+    self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+
+@mock.patch.object(toscaparser, 'parse_vnfd')
+def test_fetch_vnf_artifact_vnf_not_exists(self, mock_parse_vnfd):
+    data = {'file': open(os.path.join(CATALOG_ROOT_PATH, "resource_test.csar"), "rb")}
+    VnfPackageModel.objects.create(
+        vnfPackageId="222",
+        onboardingState="CREATED"
+    )
+    mock_parse_vnfd.return_value = json.JSONEncoder().encode(vnfd_data)
+    response = self.client.put(VNF_BASE_URL + "/222/package_content", data=data)
+    self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
+    response = self.client.get(VNF_BASE_URL + "/222/artifacts/image1")
+    self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
index 776e940..3ed6968 100644 (file)
@@ -56,6 +56,7 @@ urlpatterns = [
     #  ETSI SOL005&SOL003 VNF Package
     url(r'^api/vnfpkgm/v1/vnf_packages$', vnf_package_views.vnf_packages_rc, name='vnf_packages_rc'),
     url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)$', vnf_package_views.vnf_package_rd, name='vnf_package_rd'),
+    url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/vnfd$', vnf_package_views.vnfd_rd, name='vnfd_rd'),
     url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/package_content$', vnf_package_views.package_content_ru, name='package_content_ru'),
     url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/package_content/upload_from_uri$', vnf_package_views.upload_from_uri_c, name='upload_from_uri_c'),
 
index 44e3df7..76891f2 100644 (file)
@@ -72,6 +72,30 @@ def vnf_packages_rc(request):
         return Response(data=data, status=status.HTTP_201_CREATED)
 
 
+@swagger_auto_schema(
+    method="GET",
+    operation_description="Read VNFD of an on-boarded VNF package",
+    tags=["VNF Package API"],
+    request_body=no_body,
+    responses={
+        status.HTTP_200_OK: VnfPkgInfosSerializer(),
+        status.HTTP_404_NOT_FOUND: "VNF package does not exist",
+        status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error"
+    }
+)
+@api_view(http_method_names=["GET"])
+@view_safe_call_with_log(logger=logger)
+def vnfd_rd(request, **kwargs):
+    vnf_pkg_id = kwargs.get("vnfPkgId")
+    logger.debug("Read VNFD for  VNF package %s" % vnf_pkg_id)
+    try:
+        file_iterator = VnfPackage().download_vnfd(vnf_pkg_id)
+        return StreamingHttpResponse(file_iterator, status=status.HTTP_200_OK)
+    except Exception as e:
+        logger.error(e)
+        raise e
+
+
 @swagger_auto_schema(
     method='PUT',
     operation_description="Upload VNF package content",
index 86585a3..e3b0062 100644 (file)
 # limitations under the License.
 
 # [MSB]
-MSB_SERVICE_IP = '127.0.0.1'
-MSB_SERVICE_PORT = '80'
+# MSB_SERVICE_IP = '127.0.0.1'
+# MSB_SERVICE_PORT = '80'
+MSB_SERVICE_IP = '192.168.235.34'
+MSB_SERVICE_PORT = '30280'
 
 # [REDIS]
 REDIS_HOST = '127.0.0.1'
@@ -69,6 +71,17 @@ REG_TO_MSB_REG_PARAM = [{
         "port": "8806",
         "ttl": 0
     }]
+}, {
+    "serviceName": "parser",
+    "version": "v1",
+    "url": "/api/parser/v1",
+    "protocol": "REST",
+    "visualRange": "1",
+    "nodes": [{
+        "ip": "127.0.0.1",
+        "port": "8806",
+        "ttl": 0
+    }]
 }]
 MSB_SVC_CALALOG_URL = "/api/microservices/v1/services/catalog/version/v1"
 MSB_SVC_NSD_URL = "/api/microservices/v1/services/nsd/version/v1"
index 7f2127e..36b2d3b 100644 (file)
@@ -1,8 +1,9 @@
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 
-TODO Add files to toctree and delete this header
+ETSI Catalog Project
 ------------------------------------------------
 .. toctree::
    :maxdepth: 1
 
    introduction
+   release-notes.rst
index a9257ac..d7336d7 100644 (file)
@@ -2,7 +2,8 @@
 .. http://creativecommons.org/licenses/by/4.0
 
 
-ETSI Catalog Project Introduction
+etsicatalog Introduction
 =================================
 
-The ETSI Catalog project provides a runtime catalog service which can be consumed by other projects or components, such as UUI, VF-C, etc. The catalog can be used to store packages distributed by the SDC, and also include a TOSCA parser service.
+The ETSI Catalog project provides a runtime catalog service which can be consumed by other projects or components, such as UUI, VF-C, etc.
+The catalog can be used to store packages distributed by the SDC, and also include a TOSCA parser service.
index 1cf038d..ec2beb0 100644 (file)
Binary files a/static/catalog/resource_test.csar and b/static/catalog/resource_test.csar differ