Support HAPI for lb-pool and lb-virtual-server

In this patch, we support HAPI for lb-pool and lb-virtual-server whose tenant is org-root
We also fix a bug in func _build_wrapper_dict where the children array of wrapper_dict and the children array of node should be the same one.

Change-Id: Iaaf392f7e6904605e8ddd84d6691c92fc845dda6
Signed-off-by: Yun-Tang Hsu <hsuy@vmware.com>
Signed-off-by: Yun-Tang Hsu <yun-tang.hsu@broadcom.com>
This commit is contained in:
Yun-Tang Hsu 2024-08-05 13:14:25 -07:00 committed by Yun-Tang Hsu
parent 1fa9910c1b
commit b3f79b5af5
8 changed files with 309 additions and 37 deletions

View File

@ -23,7 +23,11 @@ from vmware_nsxlib.v3 import exceptions as nsxlib_exc
from vmware_nsxlib.v3 import nsx_constants
from vmware_nsxlib.v3.policy import constants
from vmware_nsxlib.v3.policy import lb_defs
from vmware_nsxlib.v3.policy.lb_defs import VPC_LB_POOL_PATH_HAPI_PATTERN
from vmware_nsxlib.v3.policy.lb_defs import VPC_LB_SERVICES_PATH_PATTERN
from vmware_nsxlib.v3.policy.lb_defs import \
VPC_LB_VIRTUAL_SERVERS_HAPI_PATH_PATTERN
from vmware_nsxlib.v3.policy import transaction as trans
TEST_TENANT = 'test'
TEST_VPC_TENANT = 'orgs/default/projects/proj-2/vpcs/vpc-1234'
@ -1306,6 +1310,47 @@ class TestPolicyLBVirtualServer(test_resources.NsxPolicyLibTestCase):
self.assertEqual(body['lb_service_path'],
lb_service_path)
def test_create_delete_with_vpc_tenant_hapi(self):
name = 'd1'
obj_id = '111'
with trans.NsxPolicyTransaction() as t:
self.resourceApi.create_or_overwrite(
name=name,
virtual_server_id=obj_id,
tenant=TEST_VPC_TENANT)
expected_def = lb_defs.LBVirtualServerDef(
nsx_version=self.policy_lib.get_version(),
virtual_server_id=obj_id, name=name,
tenant=constants.POLICY_ORG_ROOT_TENANT,
)
actual_def = t.defs[1]
self._compare_def(expected_def, actual_def)
self.assertEqual(actual_def.get_attr('org_id'), 'default')
self.assertEqual(actual_def.get_attr('project_id'), 'proj-2')
self.assertEqual(actual_def.get_attr('vpc_id'), 'vpc-1234')
self.assertEqual(actual_def.path_pattern,
VPC_LB_VIRTUAL_SERVERS_HAPI_PATH_PATTERN)
with trans.NsxPolicyTransaction() as t:
self.resourceApi.delete(
virtual_server_id=obj_id,
tenant=TEST_VPC_TENANT)
expected_def = lb_defs.LBVirtualServerDef(
nsx_version=self.policy_lib.get_version(),
virtual_server_id=obj_id,
tenant=constants.POLICY_ORG_ROOT_TENANT,
)
actual_def = t.defs[1]
self._compare_def(expected_def, actual_def)
self.assertEqual(actual_def.get_attr('org_id'), 'default')
self.assertEqual(actual_def.get_attr('project_id'), 'proj-2')
self.assertEqual(actual_def.get_attr('vpc_id'), 'vpc-1234')
self.assertEqual(actual_def.path_pattern,
VPC_LB_VIRTUAL_SERVERS_HAPI_PATH_PATTERN)
def test_delete(self):
obj_id = '111'
with mock.patch.object(self.policy_api, "delete") as api_call:
@ -1796,6 +1841,47 @@ class TestPolicyLBPoolApi(test_resources.NsxPolicyLibTestCase):
self.assert_called_with_def(api_call, expected_def)
self.assertIsNotNone(result)
def test_create_delete_with_vpc_tenant_hapi(self):
name = 'd1'
obj_id = '111'
with trans.NsxPolicyTransaction() as t:
self.resourceApi.create_or_overwrite(
name=name,
lb_pool_id=obj_id,
tenant=TEST_VPC_TENANT)
expected_def = lb_defs.LBPoolDef(
nsx_version=self.policy_lib.get_version(),
lb_pool_id=obj_id, name=name,
tenant=constants.POLICY_ORG_ROOT_TENANT,
)
actual_def = t.defs[1]
self._compare_def(expected_def, actual_def)
self.assertEqual(actual_def.get_attr('org_id'), 'default')
self.assertEqual(actual_def.get_attr('project_id'), 'proj-2')
self.assertEqual(actual_def.get_attr('vpc_id'), 'vpc-1234')
self.assertEqual(actual_def.path_pattern,
VPC_LB_POOL_PATH_HAPI_PATTERN)
with trans.NsxPolicyTransaction() as t:
self.resourceApi.delete(
lb_pool_id=obj_id,
tenant=TEST_VPC_TENANT)
expected_def = lb_defs.LBPoolDef(
nsx_version=self.policy_lib.get_version(),
lb_pool_id=obj_id,
tenant=constants.POLICY_ORG_ROOT_TENANT,
)
actual_def = t.defs[1]
self._compare_def(expected_def, actual_def)
self.assertEqual(actual_def.get_attr('org_id'), 'default')
self.assertEqual(actual_def.get_attr('project_id'), 'proj-2')
self.assertEqual(actual_def.get_attr('vpc_id'), 'vpc-1234')
self.assertEqual(actual_def.path_pattern,
VPC_LB_POOL_PATH_HAPI_PATTERN)
def test_create_with_retry_stale_revision(self):
name = 'd1'
description = 'desc'

View File

@ -207,10 +207,15 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
'Group': g})
expected_body = {'resource_type': 'Infra',
'children': [{'resource_type': 'ChildDomain',
'Domain': d1},
{'resource_type': 'ChildDomain',
'Domain': d2}]}
'children': [
{'resource_type': 'ChildResourceReference',
'id': d1.get('id'),
'target_type': d1.get('resource_type'),
'children': d1.get('children')},
{'resource_type': 'ChildResourceReference',
'id': d2.get('id'),
'target_type': d2.get('resource_type'),
'children': d2.get('children')}]}
self.assert_infra_patch_call(expected_body)
@ -260,10 +265,15 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
traffic_tag=port2['attachment']['traffic_tag'])
expected_body = {'resource_type': 'Infra',
'children': [{'resource_type': 'ChildSegment',
'Segment': seg1},
{'resource_type': 'ChildSegment',
'Segment': seg2}]}
'children': [
{'resource_type': 'ChildResourceReference',
'id': seg1.get('id'),
'target_type': seg1.get('resource_type'),
'children': seg1.get('children')},
{'resource_type': 'ChildResourceReference',
'id': seg2.get('id'),
'target_type': seg2.get('resource_type'),
'children': seg2.get('children')}]}
self.assert_infra_patch_call(expected_body)
@ -292,8 +302,11 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
"resource_type": "ChildPolicyNatRule"}]}
tier1_dict = {"id": tier1_id,
"resource_type": "Tier1",
"children": [{"PolicyNat": policy_nat,
"resource_type": "ChildPolicyNat"}]}
"children": [
{'resource_type': 'ChildResourceReference',
'id': policy_nat.get('id'),
'target_type': policy_nat.get('resource_type'),
'children': policy_nat.get('children')}]}
with trans.NsxPolicyTransaction():
self.policy_lib.tier1_nat_rule.create_or_overwrite(
@ -309,8 +322,11 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
action=constants.NAT_ACTION_DNAT)
expected_body = {"resource_type": "Infra",
"children": [{"Tier1": tier1_dict,
"resource_type": "ChildTier1"}]}
"children": [
{'resource_type': 'ChildResourceReference',
'id': tier1_dict.get('id'),
'target_type': tier1_dict.get('resource_type'),
'children': tier1_dict.get('children')}]}
self.assert_infra_patch_call(expected_body)
@ -337,8 +353,11 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
"resource_type": "ChildPolicyNatRule"}]}
tier1_dict = {"id": tier1_id,
"resource_type": "Tier1",
"children": [{"PolicyNat": policy_nat,
"resource_type": "ChildPolicyNat"}]}
"children": [
{'resource_type': 'ChildResourceReference',
'id': policy_nat.get('id'),
'target_type': policy_nat.get('resource_type'),
'children': policy_nat.get('children')}]}
with trans.NsxPolicyTransaction():
self.policy_lib.tier1_nat_rule.delete(
@ -350,8 +369,11 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
nat_rule_id=nat_rule_id2)
expected_body = {"resource_type": "Infra",
"children": [{"Tier1": tier1_dict,
"resource_type": "ChildTier1"}]}
"children": [
{'resource_type': 'ChildResourceReference',
'id': tier1_dict.get('id'),
'target_type': tier1_dict.get('resource_type'),
'children': tier1_dict.get('children')}]}
self.assert_infra_patch_call(expected_body)
@ -401,8 +423,12 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
'SecurityPolicy': security_policy
}]
domain.update({'children': child_security_policies})
child_domains = [{'resource_type': 'ChildDomain',
'Domain': domain}]
child_domains = [{
'resource_type': 'ChildResourceReference',
'id': domain.get('id'),
'target_type': domain.get('resource_type'),
'children': domain.get('children')
}]
expected_body = {'resource_type': 'Infra',
'children': child_domains}
self.assert_infra_patch_call(expected_body)
@ -487,8 +513,10 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
}]
domain.update({'children': child_security_policies})
child_domains = [{
'resource_type': 'ChildDomain',
'Domain': domain
'resource_type': 'ChildResourceReference',
'id': domain.get('id'),
'target_type': domain.get('resource_type'),
'children': domain.get('children')
}]
expected_body = {'resource_type': 'Infra',
'children': child_domains}
@ -571,8 +599,10 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
child_security_policies[0].update({'children': child_rules})
domain.update({'children': child_security_policies})
child_domains = [{
'resource_type': 'ChildDomain',
'Domain': domain
'resource_type': 'ChildResourceReference',
'id': domain.get('id'),
'target_type': domain.get('resource_type'),
'children': domain.get('children')
}]
expected_body = {'resource_type': 'Infra',
'children': child_domains}
@ -624,8 +654,10 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
}]
domain.update({'children': child_security_policies})
child_domains = [{
'resource_type': 'ChildDomain',
'Domain': domain
'resource_type': 'ChildResourceReference',
'id': domain.get('id'),
'target_type': domain.get('resource_type'),
'children': domain.get('children')
}]
expected_body = {'resource_type': 'Infra',
'children': child_domains}

View File

@ -17,6 +17,7 @@ TCP = 'TCP'
UDP = 'UDP'
POLICY_INFRA_TENANT = 'infra'
POLICY_ORG_ROOT_TENANT = 'org-root'
POLICY_AAA_TENANT = 'aaa'
ACTION_ALLOW = 'ALLOW'

View File

@ -28,6 +28,9 @@ from vmware_nsxlib.v3 import utils
LOG = logging.getLogger(__name__)
TENANTS_PATH_PATTERN = "%s/"
ORGS_PATH_PATTERN = TENANTS_PATH_PATTERN + "orgs/"
PROJECTS_PATH_PATTERN = ORGS_PATH_PATTERN + "%s/projects/"
VPCS_PATH_PATTERN = PROJECTS_PATH_PATTERN + "%s/vpcs/"
DOMAINS_PATH_PATTERN = TENANTS_PATH_PATTERN + "domains/"
SHARES_PATH_PATTERN = TENANTS_PATH_PATTERN + "shares/"
IP_BLOCKS_PATH_PATTERN = TENANTS_PATH_PATTERN + "ip-blocks/"
@ -321,6 +324,9 @@ class ResourceDef(object, metaclass=abc.ABCMeta):
else:
return False
def is_org_root_tenant(self):
return self.get_tenant() == 'org-root'
class TenantDef(ResourceDef):
@property
@ -345,6 +351,82 @@ class TenantDef(ResourceDef):
return 'infra/'
class TenantOrgRootDef(ResourceDef):
@property
def path_pattern(self):
return TENANTS_PATH_PATTERN
@staticmethod
def resource_type():
return 'OrgRoot'
def path_defs(self):
return ()
@property
def path_ids(self):
return ('tenant',)
def get_resource_path(self):
return 'org-root/'
def get_section_path(self):
return 'org-root/'
class TenantOrgDef(ResourceDef):
@property
def path_pattern(self):
return ORGS_PATH_PATTERN
@property
def path_ids(self):
return ('tenant', 'org_id')
@staticmethod
def resource_type():
return 'Org'
def path_defs(self):
return (TenantOrgRootDef)
class ProjectDef(ResourceDef):
@property
def path_pattern(self):
return PROJECTS_PATH_PATTERN
@property
def path_ids(self):
return ('tenant', 'org_id', 'project_id')
@staticmethod
def resource_type():
return 'Project'
def path_defs(self):
return (TenantOrgRootDef, TenantOrgDef)
class VPCDef(ResourceDef):
@property
def path_pattern(self):
return VPCS_PATH_PATTERN
@property
def path_ids(self):
return ('tenant', 'org_id', 'project_id', 'vpc_id')
@staticmethod
def resource_type():
return 'Vpc'
def path_defs(self):
return (TenantOrgRootDef, TenantOrgDef, ProjectDef)
class DomainDef(ResourceDef):
@property

View File

@ -516,6 +516,23 @@ class NsxPolicyResourceBase(object, metaclass=abc.ABCMeta):
do_delete(force=force)
def is_vpc_tenant(self, tenant):
return tenant and '/projects/' in tenant
def is_vpc_hapi(self, tenant):
transaction = trans.NsxPolicyTransaction.get_current()
return self.is_vpc_tenant(tenant) and transaction
def get_ids(self, tenant):
if self.is_vpc_hapi(tenant):
ids = tenant.split('/')
org_id = ids[1]
project_id = ids[3]
vpc_id = ids[5]
return org_id, project_id, vpc_id,\
constants.POLICY_ORG_ROOT_TENANT
return None, None, None, tenant
class NsxPolicyDomainApi(NsxPolicyResourceBase):
"""NSX Policy Domain."""

View File

@ -17,7 +17,13 @@
from oslo_log import log as logging
from vmware_nsxlib.v3 import nsx_constants
from vmware_nsxlib.v3.policy import constants
from vmware_nsxlib.v3.policy.core_defs import ProjectDef
from vmware_nsxlib.v3.policy.core_defs import ResourceDef
from vmware_nsxlib.v3.policy.core_defs import TenantOrgDef
from vmware_nsxlib.v3.policy.core_defs import TenantOrgRootDef
from vmware_nsxlib.v3.policy.core_defs import VPCDef
from vmware_nsxlib.v3.policy.core_defs import VPCS_PATH_PATTERN
LOG = logging.getLogger(__name__)
@ -25,10 +31,14 @@ TENANTS_PATH_PATTERN = "%s/"
LB_VIRTUAL_SERVERS_PATH_PATTERN = TENANTS_PATH_PATTERN + "lb-virtual-servers/"
VPC_LB_VIRTUAL_SERVERS_PATH_PATTERN = (TENANTS_PATH_PATTERN +
"vpc-lb-virtual-servers/")
VPC_LB_VIRTUAL_SERVERS_HAPI_PATH_PATTERN = (VPCS_PATH_PATTERN +
'%s/vpc-lb-virtual-servers/')
LB_SERVICES_PATH_PATTERN = TENANTS_PATH_PATTERN + "lb-services/"
VPC_LB_SERVICES_PATH_PATTERN = TENANTS_PATH_PATTERN + "vpc-lbs/"
LB_POOL_PATH_PATTERN = TENANTS_PATH_PATTERN + "lb-pools/"
VPC_LB_POOL_PATH_PATTERN = TENANTS_PATH_PATTERN + "vpc-lb-pools/"
VPC_LB_POOL_PATH_HAPI_PATTERN = (VPCS_PATH_PATTERN +
'%s/vpc-lb-pools/')
LB_APP_PROFILE_PATTERN = TENANTS_PATH_PATTERN + "lb-app-profiles/"
LB_MONITOR_PROFILE_PATTERN = TENANTS_PATH_PATTERN + "lb-monitor-profiles/"
LB_CLIENT_SSL_PROFILE_PATTERN = (TENANTS_PATH_PATTERN +
@ -232,13 +242,22 @@ class LBPoolDef(ResourceDef):
@property
def path_pattern(self):
if self.is_vpc_tenant():
if self.is_org_root_tenant():
return VPC_LB_POOL_PATH_HAPI_PATTERN
elif self.is_vpc_tenant():
return VPC_LB_POOL_PATH_PATTERN
return LB_POOL_PATH_PATTERN
@property
def path_ids(self):
return ('tenant', 'lb_pool_id')
if self.is_org_root_tenant():
return ('tenant', 'org_id', 'project_id', 'vpc_id', 'lb_pool_id')
else:
return ('tenant', 'lb_pool_id')
def path_defs(self):
if self.is_org_root_tenant():
return (TenantOrgRootDef, TenantOrgDef, ProjectDef, VPCDef)
@staticmethod
def resource_type():
@ -268,13 +287,23 @@ class LBVirtualServerDef(ResourceDef):
@property
def path_pattern(self):
if self.is_vpc_tenant():
if self.is_org_root_tenant():
return VPC_LB_VIRTUAL_SERVERS_HAPI_PATH_PATTERN
elif self.is_vpc_tenant():
return VPC_LB_VIRTUAL_SERVERS_PATH_PATTERN
return LB_VIRTUAL_SERVERS_PATH_PATTERN
@property
def path_ids(self):
return ('tenant', 'virtual_server_id')
if self.is_org_root_tenant():
return ('tenant', 'org_id', 'project_id',
'vpc_id', 'virtual_server_id')
else:
return ('tenant', 'virtual_server_id')
def path_defs(self):
if self.is_org_root_tenant():
return (TenantOrgRootDef, TenantOrgDef, ProjectDef, VPCDef)
@staticmethod
def resource_type():

View File

@ -480,6 +480,7 @@ class NsxPolicyLoadBalancerPoolApi(NsxPolicyResourceBase):
tcp_multiplexing_number=IGNORE,
tenant=constants.POLICY_INFRA_TENANT):
lb_pool_id = self._init_obj_uuid(lb_pool_id)
org_id, project_id, vpc_id, tenant = self.get_ids(tenant)
lb_pool_def = self._init_def(
lb_pool_id=lb_pool_id,
name=name,
@ -492,15 +493,25 @@ class NsxPolicyLoadBalancerPoolApi(NsxPolicyResourceBase):
snat_translation=snat_translation,
tcp_multiplexing_enabled=tcp_multiplexing_enabled,
tcp_multiplexing_number=tcp_multiplexing_number,
tenant=tenant)
tenant=tenant,
org_id=org_id,
project_id=project_id,
vpc_id=vpc_id
)
self._create_or_store(lb_pool_def)
return lb_pool_id
def delete(self, lb_pool_id,
tenant=constants.POLICY_INFRA_TENANT):
org_id, project_id, vpc_id, tenant = self.get_ids(tenant)
lb_pool_def = self.entry_def(
lb_pool_id=lb_pool_id, tenant=tenant)
lb_pool_id=lb_pool_id,
tenant=tenant,
org_id=org_id,
project_id=project_id,
vpc_id=vpc_id
)
self._delete_or_store(lb_pool_def)
def get(self, lb_pool_id, tenant=constants.POLICY_INFRA_TENANT,
@ -807,6 +818,7 @@ class NsxPolicyLoadBalancerVirtualServerAPI(NsxPolicyResourceBase):
tags=IGNORE, access_log_enabled=IGNORE,
log_significant_event_only=IGNORE):
virtual_server_id = self._init_obj_uuid(virtual_server_id)
org_id, project_id, vpc_id, tenant = self.get_ids(tenant)
lbvs_def = self._init_def(
virtual_server_id=virtual_server_id,
name=name,
@ -826,15 +838,24 @@ class NsxPolicyLoadBalancerVirtualServerAPI(NsxPolicyResourceBase):
access_list_control=access_list_control,
tags=tags,
access_log_enabled=access_log_enabled,
log_significant_event_only=log_significant_event_only
log_significant_event_only=log_significant_event_only,
org_id=org_id,
project_id=project_id,
vpc_id=vpc_id
)
self._create_or_store(lbvs_def)
return virtual_server_id
def delete(self, virtual_server_id,
tenant=constants.POLICY_INFRA_TENANT):
org_id, project_id, vpc_id, tenant = self.get_ids(tenant)
lbvs_def = self.entry_def(
virtual_server_id=virtual_server_id, tenant=tenant)
virtual_server_id=virtual_server_id,
tenant=tenant,
org_id=org_id,
project_id=project_id,
vpc_id=vpc_id
)
self._delete_or_store(lbvs_def)
def get(self, virtual_server_id,

View File

@ -40,10 +40,13 @@ class NsxPolicyTransaction(object):
data = threading.local()
def __init__(self):
def __init__(self, tenant=constants.POLICY_INFRA_TENANT):
# For now only infra tenant is supported
self.defs = [core_defs.TenantDef(
tenant=constants.POLICY_INFRA_TENANT)]
# Org-root tenant is supported only for lb-pool and lb-virtual-server
if tenant == constants.POLICY_ORG_ROOT_TENANT:
self.defs = [core_defs.TenantOrgRootDef(tenant=tenant)]
else:
self.defs = [core_defs.TenantDef(tenant=tenant)]
self.client = None
def __enter__(self):
@ -111,7 +114,7 @@ class NsxPolicyTransaction(object):
wrapper_dict = {'resource_type': 'ChildResourceReference',
'target_type': resource_class,
'id': node['id'],
'children': []}
'children': node.get('children', [])}
else:
wrapper_dict = {'resource_type': 'Child%s' % resource_class,
resource_class: node}
@ -136,7 +139,8 @@ class NsxPolicyTransaction(object):
node = {'resource_type': resource_type,
'id': parent_id,
'children': []}
return self._build_wrapper_dict(resource_class, node), node
return self._build_wrapper_dict(
resource_class, node, child_resource_ref=True), node
# iterate over all objects in d, and look for resource type
for child in d: