diff options
-rw-r--r-- | catalog/packages/biz/vnf_package.py | 66 | ||||
-rw-r--r-- | catalog/packages/serializers/vnf_pkg_infos.py | 2 | ||||
-rw-r--r-- | catalog/packages/tests/test_vnf_package.py | 100 | ||||
-rw-r--r-- | catalog/packages/views/vnf_package_views.py | 74 | ||||
-rw-r--r-- | catalog/pub/utils/tests.py | 6 | ||||
-rwxr-xr-x | docker/build_image.sh | 2 | ||||
-rw-r--r-- | pom.xml | 4 | ||||
-rw-r--r-- | version.properties | 2 |
8 files changed, 209 insertions, 47 deletions
diff --git a/catalog/packages/biz/vnf_package.py b/catalog/packages/biz/vnf_package.py index d63df9ae..d3f1f587 100644 --- a/catalog/packages/biz/vnf_package.py +++ b/catalog/packages/biz/vnf_package.py @@ -21,6 +21,8 @@ import traceback import urllib2 import uuid +from rest_framework import status +from django.http import FileResponse, StreamingHttpResponse from catalog.pub.config.config import CATALOG_ROOT_PATH from catalog.pub.database.models import VnfPackageModel from catalog.pub.exceptions import CatalogException @@ -58,30 +60,16 @@ def query_multiple(): if not nf_pkgs.exists(): raise CatalogException('VNF packages do not exist.') for nf_pkg in nf_pkgs: - ret = query_single(nf_pkg.vnfPackageId) + ret = fill_response_data(nf_pkg) pkgs_info.append(ret) return pkgs_info def query_single(vnf_pkg_id): - pkg_info = {} nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id) if not nf_pkg.exists(): raise CatalogException('VNF package(%s) does not exist.' % vnf_pkg_id) - pkg_info["id"] = nf_pkg[0].vnfPackageId - pkg_info["vnfdId"] = nf_pkg[0].vnfdId - pkg_info["vnfProductName"] = nf_pkg[0].vnfdProductName - pkg_info["vnfSoftwareVersion"] = nf_pkg[0].vnfSoftwareVersion - pkg_info["vnfdVersion"] = nf_pkg[0].vnfdVersion - pkg_info["checksum"] = json.JSONDecoder().decode(nf_pkg[0].checksum) - pkg_info["softwareImages"] = None # TODO - pkg_info["additionalArtifacts"] = None # TODO - pkg_info["onboardingState"] = nf_pkg[0].onboardingState - pkg_info["operationalState"] = nf_pkg[0].operationalState - pkg_info["usageState"] = nf_pkg[0].usageState - pkg_info["userDefinedData"] = json.JSONDecoder().decode(nf_pkg[0].userDefinedData) - pkg_info["_links"] = None # TODO - return pkg_info + return fill_response_data(nf_pkg[0]) def delete_vnf_pkg(vnf_pkg_id): @@ -160,3 +148,49 @@ class VnfPkgUploadThread(threading.Thread): save_file.write(req.read()) save_file.close() req.close() + + +def fill_response_data(nf_pkg): + pkg_info = {} + pkg_info["id"] = nf_pkg.vnfPackageId + pkg_info["vnfdId"] = nf_pkg.vnfdId + pkg_info["vnfProductName"] = nf_pkg.vnfdProductName + pkg_info["vnfSoftwareVersion"] = nf_pkg.vnfSoftwareVersion + pkg_info["vnfdVersion"] = nf_pkg.vnfdVersion + if nf_pkg.checksum: + pkg_info["checksum"] = json.JSONDecoder().decode(nf_pkg.checksum) + pkg_info["softwareImages"] = None # TODO + pkg_info["additionalArtifacts"] = None # TODO + pkg_info["onboardingState"] = nf_pkg.onboardingState + pkg_info["operationalState"] = nf_pkg.operationalState + pkg_info["usageState"] = nf_pkg.usageState + if nf_pkg.userDefinedData: + pkg_info["userDefinedData"] = json.JSONDecoder().decode(nf_pkg.userDefinedData) + pkg_info["_links"] = None # TODO + return pkg_info + + +def fetch_vnf_pkg(request, vnf_pkg_id): + nf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id) + if not nf_pkg.exists(): + raise CatalogException("VNF package (%s) does not exist" % vnf_pkg_id) + if nf_pkg[0].onboardingState != "ONBOARDED": + raise CatalogException("VNF package (%s) is not on-boarded" % vnf_pkg_id) + file_path = nf_pkg[0].localFilePath + file_name = file_path.split('/')[-1] + file_name = file_name.split('\\')[-1] + file_range = request.META.get('RANGE') + if file_range: + start_end = file_range.split('-') + start = int(start_end[0]) + end = int(start_end[1]) + f = open(file_path, "rb") + f.seek(start, 0) + fs = f.read(end - start + 1) + response = StreamingHttpResponse(fs, status=status.HTTP_200_OK) + response['Content-Type'] = 'application/octet-stream' + response['Content-Range'] = file_range + else: + response = FileResponse(open(file_path, 'rb'), status=status.HTTP_200_OK) + response['Content-Disposition'] = 'attachment; filename=%s' % file_name.encode('utf-8') + return response diff --git a/catalog/packages/serializers/vnf_pkg_infos.py b/catalog/packages/serializers/vnf_pkg_infos.py index 592ed071..d4cbc655 100644 --- a/catalog/packages/serializers/vnf_pkg_infos.py +++ b/catalog/packages/serializers/vnf_pkg_infos.py @@ -16,5 +16,5 @@ from rest_framework import serializers from vnf_pkg_info import VnfPkgInfoSerializer -class VnfPkgInfosSerializer(serializers.Serializer): +class VnfPkgInfosSerializer(serializers.ListSerializer): child = VnfPkgInfoSerializer() diff --git a/catalog/packages/tests/test_vnf_package.py b/catalog/packages/tests/test_vnf_package.py index cf49b89d..efde444d 100644 --- a/catalog/packages/tests/test_vnf_package.py +++ b/catalog/packages/tests/test_vnf_package.py @@ -328,3 +328,103 @@ class TestVnfPackage(TestCase): } self.assertEqual(response.data, expect_data) self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_query_multiple_vnf(self): + VnfPackageModel.objects.create( + vnfPackageId="111", + vnfdId="zte-hss-1.0", + vnfVendor="zte", + vnfdProductName="hss", + vnfSoftwareVersion="1.0.0", + vnfdVersion="1.0.0", + checksum='{"algorithm":"111", "hash": "11"}', + onboardingState="CREATED", + operationalState="DISABLED", + usageState="NOT_IN_USE", + userDefinedData='{"a": "A"}' + ) + VnfPackageModel.objects.create( + vnfPackageId="222", + vnfdId="zte-hss-1.0", + vnfVendor="zte", + vnfdProductName="hss", + vnfSoftwareVersion="1.0.0", + vnfdVersion="1.0.0", + checksum='{"algorithm":"111", "hash": "11"}', + onboardingState="CREATED", + operationalState="DISABLED", + usageState="NOT_IN_USE", + userDefinedData='{"a": "A"}' + ) + response = self.client.get("/api/vnfpkgm/v1/vnf_packages") + expect_data = [ + { + "id": "111", + "vnfdId": "zte-hss-1.0", + "vnfProductName": "hss", + "vnfSoftwareVersion": "1.0.0", + "vnfdVersion": "1.0.0", + "checksum": {"algorithm": "111", "hash": "11"}, + "softwareImages": None, + "additionalArtifacts": None, + "onboardingState": "CREATED", + "operationalState": "DISABLED", + "usageState": "NOT_IN_USE", + "userDefinedData": {"a": "A"}, + "_links": None + }, + { + "id": "222", + "vnfdId": "zte-hss-1.0", + "vnfProductName": "hss", + "vnfSoftwareVersion": "1.0.0", + "vnfdVersion": "1.0.0", + "checksum": {"algorithm": "111", "hash": "11"}, + "softwareImages": None, + "additionalArtifacts": None, + "onboardingState": "CREATED", + "operationalState": "DISABLED", + "usageState": "NOT_IN_USE", + "userDefinedData": {"a": "A"}, + "_links": None + } + ] + self.assertEqual(response.data, expect_data) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_delete_single_vnf_pkg(self): + VnfPackageModel.objects.create( + vnfPackageId="222", + vnfdId="zte-hss-1.0", + vnfVendor="zte", + vnfdProductName="hss", + vnfSoftwareVersion="1.0.0", + vnfdVersion="1.0.0", + checksum='{"algorithm":"111", "hash": "11"}', + onboardingState="CREATED", + operationalState="DISABLED", + usageState="NOT_IN_USE", + userDefinedData='{"a": "A"}' + ) + response = self.client.delete("/api/vnfpkgm/v1/vnf_packages/222") + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) + self.assertEqual(response.data, None) + + def test_fetch_vnf_pkg(self): + pass + + def test_fetch_partical_vnf_pkg(self): + with open("vnfPackage.csar", "wb") as fp: + fp.writelines("AAAABBBBCCCCDDDD") + VnfPackageModel.objects.create( + vnfPackageId="222", + onboardingState="ONBOARDED", + localFilePath="vnfPackage.csar" + ) + response = self.client.get("/api/vnfpkgm/v1/vnf_packages/222/package_content", RANGE="4-7") + partial_file_content = '' + for data in response.streaming_content: + partial_file_content = partial_file_content + data + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual('BBBB', partial_file_content) + os.remove("vnfPackage.csar") diff --git a/catalog/packages/views/vnf_package_views.py b/catalog/packages/views/vnf_package_views.py index 7defc347..2bdd3eb8 100644 --- a/catalog/packages/views/vnf_package_views.py +++ b/catalog/packages/views/vnf_package_views.py @@ -27,7 +27,7 @@ from catalog.packages.serializers.create_vnf_pkg_info_req import CreateVnfPkgInf from catalog.packages.serializers.vnf_pkg_info import VnfPkgInfoSerializer from catalog.packages.serializers.vnf_pkg_infos import VnfPkgInfosSerializer from catalog.packages.biz.vnf_package import create_vnf_pkg, query_multiple, VnfPkgUploadThread, \ - query_single, delete_vnf_pkg, parse_vnfd_and_save + query_single, delete_vnf_pkg, parse_vnfd_and_save, fetch_vnf_pkg from catalog.pub.database.models import VnfPackageModel logger = logging.getLogger(__name__) @@ -98,32 +98,56 @@ def vnf_packages_rc(request): status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error" } ) -@api_view(http_method_names=['PUT']) +@swagger_auto_schema( + method="GET", + operation_description="Fetch VNF package content", + request_body=no_body, + responses={ + status.HTTP_200_OK: VnfPkgInfosSerializer(), + status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error" + } +) +@api_view(http_method_names=["PUT", "GET"]) def upload_vnf_pkg_content(request, vnfPkgId): - logger.debug("Upload VNF package %s" % vnfPkgId) - try: - vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnfPkgId) - if vnf_pkg[0].onboardingState != "CREATED": - raise CatalogException("VNF package (%s) is not created" % vnfPkgId) - file_object = request.FILES.get('file') - upload_path = os.path.join(CATALOG_ROOT_PATH, vnfPkgId) - if not os.path.exists(upload_path): - os.makedirs(upload_path, 0o777) - - upload_file_name = os.path.join(upload_path, file_object.name) - with open(upload_file_name, 'wb+') as dest_file: - for chunk in file_object.chunks(): - dest_file.write(chunk) - - parse_vnfd_and_save(vnfPkgId, upload_file_name) - return Response(None, status=status.HTTP_202_ACCEPTED) - except CatalogException: + if request.method == "PUT": + logger.debug("Upload VNF package %s" % vnfPkgId) + try: + vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnfPkgId) + if vnf_pkg[0].onboardingState != "CREATED": + raise CatalogException("VNF package (%s) is not created" % vnfPkgId) + file_object = request.FILES.get('file') + upload_path = os.path.join(CATALOG_ROOT_PATH, vnfPkgId) + if not os.path.exists(upload_path): + os.makedirs(upload_path, 0o777) + + upload_file_name = os.path.join(upload_path, file_object.name) + with open(upload_file_name, 'wb+') as dest_file: + for chunk in file_object.chunks(): + dest_file.write(chunk) + + parse_vnfd_and_save(vnfPkgId, upload_file_name) + return Response(None, status=status.HTTP_202_ACCEPTED) + except CatalogException: + logger.error(traceback.format_exc()) + return Response(data={'error': 'Upload VNF package failed.'}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + except Exception as e: + logger.error(e.message) logger.error(traceback.format_exc()) - return Response(data={'error': 'Upload VNF package failed.'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - except Exception as e: - logger.error(e.message) - logger.error(traceback.format_exc()) - return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + if request.method == "GET": + try: + response = fetch_vnf_pkg(request, vnfPkgId) + return response + except CatalogException: + logger.error(traceback.format_exc()) + return Response(data={'error': 'Fetch VNF package failed.'}, + status=status.HTTP_500_INTERNAL_SERVER_ERROR) + except Exception as e: + logger.error(e.message) + logger.error(traceback.format_exc()) + return Response(data={'error': 'unexpected exception'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @swagger_auto_schema( diff --git a/catalog/pub/utils/tests.py b/catalog/pub/utils/tests.py index 0fe8310d..73029fa6 100644 --- a/catalog/pub/utils/tests.py +++ b/catalog/pub/utils/tests.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import platform import unittest import mock import fileutil @@ -51,7 +52,10 @@ class UtilsTest(unittest.TestCase): fileutil.delete_dirs("abc") is_ok, f_name = fileutil.download_file_from_http("1", "abc", "1.txt") self.assertTrue(is_ok) - self.assertTrue(f_name.endswith("abc/1.txt")) + if 'Windows' in platform.system(): + self.assertTrue(f_name.endswith("abc\\1.txt")) + else: + self.assertTrue(f_name.endswith("abc/1.txt")) fileutil.delete_dirs("abc") def test_query_job_status(self): diff --git a/docker/build_image.sh b/docker/build_image.sh index b42369f1..57fa076f 100755 --- a/docker/build_image.sh +++ b/docker/build_image.sh @@ -6,7 +6,7 @@ cd ${DOCKER_BUILD_DIR} BUILD_ARGS="--no-cache" ORG="onap" -VERSION="1.1.0" +VERSION="1.2.0" PROJECT="vfc" IMAGE="catalog" DOCKER_REPOSITORY="nexus3.onap.org:10003" @@ -18,12 +18,12 @@ <parent> <groupId>org.onap.oparent</groupId> <artifactId>oparent</artifactId> - <version>1.1.0</version> + <version>1.2.0</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>org.onap.vfc.nfvo.catalog</groupId> <artifactId>vfc-nfvo-catalog</artifactId> - <version>1.1.0-SNAPSHOT</version> + <version>1.2.0-SNAPSHOT</version> <packaging>pom</packaging> <name>vfc-nfvo-catalog</name> <description>vfc nfvo catalog</description> diff --git a/version.properties b/version.properties index e1751011..ad491ae4 100644 --- a/version.properties +++ b/version.properties @@ -17,7 +17,7 @@ # because they are used in Jenkins, whose plug-in doesn't support major=1 -minor=1 +minor=2 patch=0 base_version=${major}.${minor}.${patch} |