From 33f92086f4cf7d42ddd51507a1c00c78315ed5c1 Mon Sep 17 00:00:00 2001 From: tpatil Date: Wed, 12 Feb 2020 02:45:20 +0000 Subject: [PATCH] Delete vnf package if operationalState is DISABLED Presently, vnf package can be deleted when it's operationalState is 'ENABLED'. As per pre-condition rule, vnf package can be deleted only when it's operationalState is 'DISABLED' and it's usageState is 'NOT_IN_USE. This patch fixes this issue and now vnf package will be deleted only when it's operationalState is 'DISABLED' and it's usageState is 'NOT_IN_USE. Note: I have fixed windows style line ending issue in vnf_packages.inc. Also, updated 'Delete VNF Package' API doc to include 409 error. Change-Id: Id4d50264d1052a09e6ce527b6aab1bb941fdc6af Closes-Bug: #1862864 --- api-ref/source/v1/vnf_packages.inc | 492 ++++++++++--------- tacker/api/vnfpkgm/v1/controller.py | 16 +- tacker/tests/unit/vnfpkgm/test_controller.py | 26 + 3 files changed, 286 insertions(+), 248 deletions(-) diff --git a/api-ref/source/v1/vnf_packages.inc b/api-ref/source/v1/vnf_packages.inc index d2c4380e8..71719119d 100644 --- a/api-ref/source/v1/vnf_packages.inc +++ b/api-ref/source/v1/vnf_packages.inc @@ -1,243 +1,249 @@ -.. -*- rst -*- - -==================================================== -Virtualized Network Function Packages (VNF packages) -==================================================== - -Manages Virtualized Network Function Packages (VNF Packages) and their resources. - -A VNF Package is a tar-archive containing all the information required for managing -the lifecycle of a VNF. - -Create VNF Package -================== - -.. rest_method:: POST /vnfpkgm/v1/vnf_packages - -Creates a VNF Package. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 201 - -.. rest_status_code:: error status.yaml - - - 400 - - 401 - - 403 - -Request Parameters ------------------- - -.. rest_parameters:: parameters.yaml - - - userDefinedData: userDefinedData - -Request Example ---------------- - -.. literalinclude:: samples/vnf_packages/vnf-packages-create-request.json - :language: javascript - -Response Parameters -------------------- - -.. rest_parameters:: parameters.yaml - - - id: vnf_package_id - - _links: vnf_pkg_links - - onboardingState: onboardingState - - operationalState: operationalState - - usageState: usageState - - userDefinedData: userDefinedData - -Response Example ----------------- - -.. literalinclude:: samples/vnf_packages/vnf-packages-create-response.json - :language: javascript - -List VNF Packages -================= - -.. rest_method:: GET /vnfpkgm/v1/vnf_packages - -Lists VNF Packages. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 200 - -.. rest_status_code:: error status.yaml - - - 401 - - 403 - -Response Parameters -------------------- - -.. rest_parameters:: parameters.yaml - - - id: vnf_package_id - - vnfdId: vnf_pkg_vnfd_id - - vnfProvider: vnf_provider - - vnfProductName: vnf_product_name - - vnfSoftwareVersion: vnf_software_version - - vnfdVersion: vnfd_version - - softwareImages: software_images - - onboardingState: onboardingState - - operationalState: operationalState - - usageState: usageState - - userDefinedData: userDefinedData - - _links: vnf_pkg_links - -Response Example ----------------- - -.. literalinclude:: samples/vnf_packages/vnf-packages-list-response.json - :language: javascript - -Show VNF Package -================= - -.. rest_method:: GET /vnfpkgm/v1/vnf_packages/{vnf_package_id} - -Shows information of a given VNF Package. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 200 - -.. rest_status_code:: error status.yaml - - - 401 - - 403 - - 404 - -Request Parameters ------------------- - -.. rest_parameters:: parameters.yaml - - - vnf_package_id: vnf_package_id_path - -Response Parameters -------------------- - -.. rest_parameters:: parameters.yaml - - - id: vnf_package_id - - vnfdId: vnf_pkg_vnfd_id - - vnfProvider: vnf_provider - - vnfProductName: vnf_product_name - - vnfSoftwareVersion: vnf_software_version - - vnfdVersion: vnfd_version - - softwareImages: software_images - - onboardingState: onboardingState - - operationalState: operationalState - - usageState: usageState - - userDefinedData: userDefinedData - - _links: vnf_pkg_links - -Response Example ----------------- - -.. literalinclude:: samples/vnf_packages/vnf-packages-show-response.json - :language: javascript - -Delete VNF Package -================== - -.. rest_method:: DELETE /vnfpkgm/v1/vnf_packages/{vnf_package_id} - -Deletes a given VNF Package. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 204 - -.. rest_status_code:: error status.yaml - - - 401 - - 403 - - 404 - -Request Parameters ------------------- - -.. rest_parameters:: parameters.yaml - - - vnf_package_id: vnf_package_id_path - -Upload VNF Package from content -=============================== - -.. rest_method:: PUT /vnfpkgm/v1/vnf_packages/{vnf_package_id}/package_content - -Upload a given VNF Package from content. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 202 - -.. rest_status_code:: error status.yaml - - - 401 - - 403 - - 404 - - 409 - -Request Parameters ------------------- - -.. rest_parameters:: parameters.yaml - - - vnf_package_id: vnf_package_id_path - - vnf_package_content: vnf_pkg_content - -Upload VNF Package from uri -=========================== - -.. rest_method:: POST /vnf_packages/{vnf_package_id}/package_content/upload_from_uri - -Upload a given VNF Package from content. - -Response Codes --------------- - -.. rest_status_code:: success status.yaml - - - 202 - -.. rest_status_code:: error status.yaml - - - 401 - - 400 - - 403 - - 404 - - 409 - -Request Parameters ------------------- - -.. rest_parameters:: parameters.yaml - - - vnf_package_id: vnf_package_id_path - - addressInformation: addressInformation - - userName: userName - - password: password \ No newline at end of file +.. -*- rst -*- + +==================================================== +Virtualized Network Function Packages (VNF packages) +==================================================== + +Manages Virtualized Network Function Packages (VNF Packages) and their resources. + +A VNF Package is a tar-archive containing all the information required for managing +the lifecycle of a VNF. + +Create VNF Package +================== + +.. rest_method:: POST /vnfpkgm/v1/vnf_packages + +Creates a VNF Package. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 201 + +.. rest_status_code:: error status.yaml + + - 400 + - 401 + - 403 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - userDefinedData: userDefinedData + +Request Example +--------------- + +.. literalinclude:: samples/vnf_packages/vnf-packages-create-request.json + :language: javascript + +Response Parameters +------------------- + +.. rest_parameters:: parameters.yaml + + - id: vnf_package_id + - _links: vnf_pkg_links + - onboardingState: onboardingState + - operationalState: operationalState + - usageState: usageState + - userDefinedData: userDefinedData + +Response Example +---------------- + +.. literalinclude:: samples/vnf_packages/vnf-packages-create-response.json + :language: javascript + +List VNF Packages +================= + +.. rest_method:: GET /vnfpkgm/v1/vnf_packages + +Lists VNF Packages. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 200 + +.. rest_status_code:: error status.yaml + + - 401 + - 403 + +Response Parameters +------------------- + +.. rest_parameters:: parameters.yaml + + - id: vnf_package_id + - vnfdId: vnf_pkg_vnfd_id + - vnfProvider: vnf_provider + - vnfProductName: vnf_product_name + - vnfSoftwareVersion: vnf_software_version + - vnfdVersion: vnfd_version + - softwareImages: software_images + - onboardingState: onboardingState + - operationalState: operationalState + - usageState: usageState + - userDefinedData: userDefinedData + - _links: vnf_pkg_links + +Response Example +---------------- + +.. literalinclude:: samples/vnf_packages/vnf-packages-list-response.json + :language: javascript + +Show VNF Package +================= + +.. rest_method:: GET /vnfpkgm/v1/vnf_packages/{vnf_package_id} + +Shows information of a given VNF Package. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 200 + +.. rest_status_code:: error status.yaml + + - 401 + - 403 + - 404 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - vnf_package_id: vnf_package_id_path + +Response Parameters +------------------- + +.. rest_parameters:: parameters.yaml + + - id: vnf_package_id + - vnfdId: vnf_pkg_vnfd_id + - vnfProvider: vnf_provider + - vnfProductName: vnf_product_name + - vnfSoftwareVersion: vnf_software_version + - vnfdVersion: vnfd_version + - softwareImages: software_images + - onboardingState: onboardingState + - operationalState: operationalState + - usageState: usageState + - userDefinedData: userDefinedData + - _links: vnf_pkg_links + +Response Example +---------------- + +.. literalinclude:: samples/vnf_packages/vnf-packages-show-response.json + :language: javascript + +Delete VNF Package +================== + +.. rest_method:: DELETE /vnfpkgm/v1/vnf_packages/{vnf_package_id} + +Deletes a given VNF Package. + +**Preconditions** + +The vnf package ``operationalState`` value must be ``DISABLED`` and it's +``usageState`` value must be ``NOT_IN_USE``. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 204 + +.. rest_status_code:: error status.yaml + + - 401 + - 403 + - 404 + - 409 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - vnf_package_id: vnf_package_id_path + +Upload VNF Package from content +=============================== + +.. rest_method:: PUT /vnfpkgm/v1/vnf_packages/{vnf_package_id}/package_content + +Upload a given VNF Package from content. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 202 + +.. rest_status_code:: error status.yaml + + - 401 + - 403 + - 404 + - 409 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - vnf_package_id: vnf_package_id_path + - vnf_package_content: vnf_pkg_content + +Upload VNF Package from uri +=========================== + +.. rest_method:: POST /vnf_packages/{vnf_package_id}/package_content/upload_from_uri + +Upload a given VNF Package from content. + +Response Codes +-------------- + +.. rest_status_code:: success status.yaml + + - 202 + +.. rest_status_code:: error status.yaml + + - 401 + - 400 + - 403 + - 404 + - 409 + +Request Parameters +------------------ + +.. rest_parameters:: parameters.yaml + + - vnf_package_id: vnf_package_id_path + - addressInformation: addressInformation + - userName: userName + - password: password diff --git a/tacker/api/vnfpkgm/v1/controller.py b/tacker/api/vnfpkgm/v1/controller.py index 4ceb15f3f..fb4882143 100644 --- a/tacker/api/vnfpkgm/v1/controller.py +++ b/tacker/api/vnfpkgm/v1/controller.py @@ -102,7 +102,8 @@ class VnfPkgmController(wsgi.Controller): return self._view_builder.index(request, vnf_packages) @wsgi.response(http_client.NO_CONTENT) - @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) + @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND, + http_client.CONFLICT)) def delete(self, request, id): context = request.environ['tacker.context'] context.can(vnf_package_policies.VNFPKGM % 'delete') @@ -119,13 +120,18 @@ class VnfPkgmController(wsgi.Controller): msg = _("Can not find requested vnf package: %s") % id raise webob.exc.HTTPNotFound(explanation=msg) - if vnf_package.operational_state == \ - fields.PackageUsageStateType.IN_USE: - msg = _("VNF Package %(id)s usage state is %(state)s") + if (vnf_package.operational_state == + fields.PackageOperationalStateType.ENABLED or + vnf_package.usage_state == + fields.PackageUsageStateType.IN_USE): + msg = _("VNF Package %(id)s cannot be deleted as it's " + "operational state is %(operational_state)s and usage " + "state is %(usage_state)s.") raise webob.exc.HTTPConflict( explanation=msg % { "id": id, - "state": fields.PackageOperationalStateType.ENABLED}) + "operational_state": vnf_package.operational_state, + "usage_state": vnf_package.usage_state}) # Delete vnf_package self.rpc_api.delete_vnf_package(context, vnf_package) diff --git a/tacker/tests/unit/vnfpkgm/test_controller.py b/tacker/tests/unit/vnfpkgm/test_controller.py index 7b2a7e33b..02d60dfc3 100644 --- a/tacker/tests/unit/vnfpkgm/test_controller.py +++ b/tacker/tests/unit/vnfpkgm/test_controller.py @@ -22,6 +22,8 @@ from webob import exc from tacker.api.vnfpkgm.v1 import controller from tacker.conductor.conductorrpc.vnf_pkgm_rpc import VNFPackageRPCAPI from tacker.glance_store import store as glance_store +from tacker import objects +from tacker.objects import fields from tacker.objects import vnf_package from tacker.objects.vnf_package import VnfPackagesList from tacker.tests import constants @@ -121,6 +123,30 @@ class TestController(base.TestCase): self.assertRaises(exc.HTTPNotFound, self.controller.delete, req, constants.INVALID_UUID) + @mock.patch.object(objects.VnfPackage, "get_by_id") + def test_delete_with_operational_state_enabled(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + vnf_package_dict = fakes.fake_vnf_package() + vnf_package_dict['operational_state'] = \ + fields.PackageOperationalStateType.ENABLED + vnf_package = objects.VnfPackage(**vnf_package_dict) + mock_vnf_by_id.return_value = vnf_package + self.assertRaises(exc.HTTPConflict, self.controller.delete, + req, constants.UUID) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_delete_with_usage_state_in_use(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + vnf_package_dict = fakes.fake_vnf_package() + vnf_package_dict['usage_state'] = \ + fields.PackageUsageStateType.IN_USE + vnf_package = objects.VnfPackage(**vnf_package_dict) + mock_vnf_by_id.return_value = vnf_package + self.assertRaises(exc.HTTPConflict, self.controller.delete, + req, constants.UUID) + @mock.patch.object(glance_store, 'store_csar') @mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_content") @mock.patch.object(vnf_package.VnfPackage, "get_by_id")