From 8ad2cb7a2ca93e2e8646e18c3e0d86238ba767cf Mon Sep 17 00:00:00 2001
From: Yasufumi Ogawa <yasufum.o@gmail.com>
Date: Tue, 18 Jun 2024 19:12:11 +0900
Subject: [PATCH] Fix issue of the paging of v1 vnflcm list

- When Enhanced Tacker Policy is enabled, the paging of v1 vnflcm list
  does not work properly.
- As the result, all the vnf instances that match the condition of
  Enhanced Tacker Policy cannot be shown in the vnflcm list.
- Fix so that nextpage is properly set when Enhanced Tacker Policy
  is enabled.

Closes-Bug: #2069392
Change-Id: I1731106f4a66f9bd7166f94c2815c7acd0e02994
Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
Co-Authored-By: Takahiro Miyajima <fj6257jz@fujitsu.com>
---
 tacker/api/vnflcm/v1/controller.py           |  6 ++-
 tacker/api/vnfpkgm/v1/controller.py          |  6 ++-
 tacker/tests/unit/vnflcm/test_controller.py  | 41 ++++++++++++++++
 tacker/tests/unit/vnfpkgm/test_controller.py | 49 ++++++++++++++++++++
 4 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/tacker/api/vnflcm/v1/controller.py b/tacker/api/vnflcm/v1/controller.py
index cac9dde19..3def7fcd9 100644
--- a/tacker/api/vnflcm/v1/controller.py
+++ b/tacker/api/vnflcm/v1/controller.py
@@ -660,7 +660,8 @@ class VnfLcmController(wsgi.Controller):
 
         # get maximum record size per page
         if allrecords != 'yes':
-            limit = CONF.vnf_lcm.vnf_instance_num
+            if not CONF.oslo_policy.enhanced_tacker_policy:
+                limit = CONF.vnf_lcm.vnf_instance_num
 
             # get next page marker object from nextpage id
             if nextpage:
@@ -682,6 +683,9 @@ class VnfLcmController(wsgi.Controller):
                     vnf_lcm_policies.VNFLCM % 'index',
                     target=self._get_policy_target(vnf_instance),
                     fatal=False)]
+            if allrecords != 'yes':
+                limit = CONF.vnf_lcm.vnf_instance_num
+                result = result[:limit]
 
         result = self._view_builder.index(result)
 
diff --git a/tacker/api/vnfpkgm/v1/controller.py b/tacker/api/vnfpkgm/v1/controller.py
index e9392547a..a07847eb9 100644
--- a/tacker/api/vnfpkgm/v1/controller.py
+++ b/tacker/api/vnfpkgm/v1/controller.py
@@ -181,7 +181,8 @@ class VnfPkgmController(wsgi.Controller):
         marker_obj = None
 
         if allrecords != 'yes':
-            limit = CONF.vnf_package.vnf_package_num
+            if not CONF.oslo_policy.enhanced_tacker_policy:
+                limit = CONF.vnf_package.vnf_package_num
 
             # get next page marker object from nextpage id
             if nextpage:
@@ -204,6 +205,9 @@ class VnfPkgmController(wsgi.Controller):
                           vnf_package_policies.VNFPKGM % 'index',
                           target=self._get_policy_target(vnf_package),
                           fatal=False)]
+            if allrecords != 'yes':
+                limit = CONF.vnf_package.vnf_package_num
+                result = result[:limit]
 
         results = self._view_builder.index(result,
                 all_fields=all_fields,
diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py
index e84659f77..22907a365 100644
--- a/tacker/tests/unit/vnflcm/test_controller.py
+++ b/tacker/tests/unit/vnflcm/test_controller.py
@@ -28,6 +28,7 @@ from webob import exc
 from oslo_config import cfg
 from oslo_policy import policy as oslo_policy
 from oslo_serialization import jsonutils
+from oslo_utils import uuidutils
 
 from tacker.api.views import vnf_subscriptions as vnf_subscription_view
 from tacker.api.vnflcm.v1 import controller
@@ -43,6 +44,7 @@ from tacker.manager import TackerManager
 from tacker import objects
 from tacker.objects import fields
 from tacker.objects import vnf_lcm_subscriptions as subscription_obj
+from tacker.policies import vnf_lcm as vnf_lcm_policies
 from tacker import policy
 from tacker.tests import constants
 from tacker.tests.unit import base
@@ -5598,6 +5600,45 @@ class TestControllerEnhancedPolicy(TestController):
         self.assertEqual(
             expected_vnf_inst_ids, [inst.get('id') for inst in resp.json])
 
+    @mock.patch.object(objects.VnfInstance, "get_by_id")
+    @mock.patch.object(objects.VnfInstanceList, "get_by_marker_filter")
+    def test_index_enhanced_policy_paging(self, mock_vnf_list, mock_vnf_by_id):
+        cfg.CONF.set_override('vnf_instance_num', 1, group='vnf_lcm')
+        inst_a_1 = fakes.make_vnf_instance('openstack', 'provider_A',
+            area='area_A@region_A', tenant='tenant_A')
+        inst_a_2 = copy.deepcopy(inst_a_1)
+        inst_a_2.id = uuidutils.generate_uuid()
+        inst_b = fakes.make_vnf_instance('openstack', 'provider_B',
+            area='area_B@region_B', tenant='tenant_B')
+        rules = {vnf_lcm_policies.VNFLCM % 'index':
+                 "area:%(area)s and vendor:%(vendor)s and tenant:%(tenant)s"}
+        roles = ['AREA_area_A@region_A', 'VENDOR_provider_A',
+                 'TENANT_tenant_A']
+        policy.set_rules(oslo_policy.Rules.from_dict(rules), overwrite=True)
+        ctx = context.Context('fake', 'fake', roles=roles)
+
+        # first request
+        mock_vnf_list.return_value = [inst_a_1, inst_b, inst_a_2]
+        req = fake_request.HTTPRequest.blank('/vnf_instances')
+        req.headers['Content-Type'] = 'application/json'
+        req.method = 'GET'
+        resp = req.get_response(fakes.wsgi_app_v1(fake_auth_context=ctx))
+        self.assertEqual(http_client.OK, resp.status_code)
+        self.assertEqual(
+            [inst_a_1.id], [inst.get('id') for inst in resp.json])
+
+        # second request with nextpage_opaque_marker
+        mock_vnf_list.return_value = [inst_b, inst_a_2]
+        mock_vnf_by_id.return_value = inst_a_1
+        req = fake_request.HTTPRequest.blank('/vnf_instances?'
+            f'nextpage_opaque_marker={inst_a_1.id}')
+        req.headers['Content-Type'] = 'application/json'
+        req.method = 'GET'
+        resp = req.get_response(fakes.wsgi_app_v1(fake_auth_context=ctx))
+        self.assertEqual(http_client.OK, resp.status_code)
+        self.assertEqual(
+            [inst_a_2.id], [inst.get('id') for inst in resp.json])
+
     @mock.patch.object(TackerManager, 'get_service_plugins',
                        return_value={'VNFM': FakeVNFMPlugin()})
     @mock.patch('tacker.api.vnflcm.v1.controller.VnfLcmController.'
diff --git a/tacker/tests/unit/vnfpkgm/test_controller.py b/tacker/tests/unit/vnfpkgm/test_controller.py
index 9e1c085c6..9480daeff 100644
--- a/tacker/tests/unit/vnfpkgm/test_controller.py
+++ b/tacker/tests/unit/vnfpkgm/test_controller.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 
+import copy
 import ddt
 from http import client as http_client
 import json
@@ -26,6 +27,7 @@ from webob import exc
 from oslo_config import cfg
 from oslo_policy import policy as oslo_policy
 from oslo_serialization import jsonutils
+from oslo_utils import uuidutils
 
 from tacker._i18n import _
 from tacker.api.vnfpkgm.v1 import controller
@@ -1726,3 +1728,50 @@ class TestControllerEnhancedPolicy(TestController):
         self.assertEqual(http_client.OK, resp.status_code)
         self.assertEqual(
             expected_pkg_ids, [pkg.get('id') for pkg in resp.json])
+
+    @mock.patch.object(vnf_package.VnfPackage, "get_by_id")
+    @mock.patch.object(VnfPackagesList, "get_by_marker_filter")
+    def test_index_enhanced_policy_paging(self, mock_pkg_list, mock_pkg_by_id):
+        cfg.CONF.set_override('vnf_package_num', 1, group='vnf_package')
+        pkg_a_1 = fakes.return_vnfpkg_obj(
+            vnf_package_updates={'id': uuidutils.generate_uuid()},
+            vnfd_updates={
+                'vnf_provider': 'provider_A',
+                'id': uuidutils.generate_uuid(),
+            })
+        pkg_a_2 = copy.deepcopy(pkg_a_1)
+        pkg_a_2.id = uuidutils.generate_uuid()
+        pkg_a_2.vnfd.id = uuidutils.generate_uuid()
+        pkg_b = fakes.return_vnfpkg_obj(
+            vnf_package_updates={'id': uuidutils.generate_uuid()},
+            vnfd_updates={
+                'vnf_provider': 'provider_B',
+                'id': uuidutils.generate_uuid(),
+            })
+        rules = {
+            vnf_package_policies.VNFPKGM % 'index': "vendor:%(vendor)s"}
+        roles = ['VENDOR_provider_A']
+        policy.set_rules(oslo_policy.Rules.from_dict(rules), overwrite=True)
+        ctx = context.Context('fake', 'fake', roles=roles)
+
+        # first request
+        mock_pkg_list.return_value = [pkg_a_1, pkg_b, pkg_a_2]
+        req = fake_request.HTTPRequest.blank('/vnf_packages')
+        req.headers['Content-Type'] = 'application/json'
+        req.method = 'GET'
+        resp = req.get_response(fakes.wsgi_app_v1(fake_auth_context=ctx))
+        self.assertEqual(http_client.OK, resp.status_code)
+        self.assertEqual(
+            [pkg_a_1.id], [pkg.get('id') for pkg in resp.json])
+
+        # second request with nextpage_opaque_marker
+        mock_pkg_list.return_value = [pkg_b, pkg_a_2]
+        mock_pkg_by_id.return_value = pkg_a_1
+        req = fake_request.HTTPRequest.blank('/vnf_packages?'
+            f'nextpage_opaque_marker={pkg_a_1.id}')
+        req.headers['Content-Type'] = 'application/json'
+        req.method = 'GET'
+        resp = req.get_response(fakes.wsgi_app_v1(fake_auth_context=ctx))
+        self.assertEqual(http_client.OK, resp.status_code)
+        self.assertEqual(
+            [pkg_a_2.id], [pkg.get('id') for pkg in resp.json])