Policy pass-through api support

Adding basic support and config flag for the passthrough api.
This will use the nsx manager api for handling policy resources
fine tuning when there is no policy apis available.

Change-Id: I29cbbd570b8e3eea4f52fb13d01820fddd7b1cff
This commit is contained in:
Adit Sarfaty 2018-11-28 14:53:02 +02:00
parent e562087ec3
commit 90e97c4390
6 changed files with 160 additions and 44 deletions

View File

@ -126,7 +126,8 @@ def get_default_nsxlib_config():
plugin_tag=PLUGIN_TAG, plugin_tag=PLUGIN_TAG,
plugin_ver=PLUGIN_VER, plugin_ver=PLUGIN_VER,
dns_nameservers=DNS_NAMESERVERS, dns_nameservers=DNS_NAMESERVERS,
dns_domain=DNS_DOMAIN dns_domain=DNS_DOMAIN,
allow_passthrough=True
) )

View File

@ -33,7 +33,9 @@ class NsxPolicyLibTestCase(policy_testcase.TestPolicyApi):
super(NsxPolicyLibTestCase, self).setUp() super(NsxPolicyLibTestCase, self).setUp()
nsxlib_config = nsxlib_testcase.get_default_nsxlib_config() nsxlib_config = nsxlib_testcase.get_default_nsxlib_config()
self.policy_lib = v3.NsxPolicyLib(nsxlib_config) # Mock the nsx-lib for the passthrough api
with mock.patch('vmware_nsxlib.v3.NsxLib'):
self.policy_lib = v3.NsxPolicyLib(nsxlib_config)
self.policy_api = self.policy_lib.policy_api self.policy_api = self.policy_lib.policy_api
self.policy_api.client = self.client self.policy_api.client = self.client
@ -1864,6 +1866,34 @@ class TestPolicyTier1(NsxPolicyLibTestCase):
tier1_id, tenant=TEST_TENANT) tier1_id, tenant=TEST_TENANT)
self.assertEqual(info, actual_info) self.assertEqual(info, actual_info)
def test_update_transport_zone(self):
# Test the passthrough api
tier1_id = '111'
logical_router_id = 'realized_111'
tz_uuid = 'dummy_tz'
info = {'state': policy_constants.STATE_REALIZED,
'entity_type': 'RealizedLogicalRouter',
'realization_specific_identifier': logical_router_id}
passthrough_mock = self.resourceApi.nsx_api.logical_router.update
with mock.patch.object(self.resourceApi, "_get_realization_info",
return_value=info) as realization:
self.resourceApi.update_transport_zone(tier1_id, tz_uuid,
tenant=TEST_TENANT)
realization.assert_called_once()
passthrough_mock.assert_called_once_with(
logical_router_id, transport_zone_id=tz_uuid)
def test_wait_until_realized(self):
tier1_id = '111'
logical_router_id = 'realized_111'
info = {'state': policy_constants.STATE_UNREALIZED,
'realization_specific_identifier': logical_router_id}
with mock.patch.object(self.resourceApi, "_get_realization_info",
return_value=info):
self.assertRaises(nsxlib_exc.ManagerError,
self.resourceApi.wait_until_realized,
tier1_id, tenant=TEST_TENANT)
class TestPolicyTier1NatRule(NsxPolicyLibTestCase): class TestPolicyTier1NatRule(NsxPolicyLibTestCase):
@ -2001,6 +2031,32 @@ class TestPolicyTier0(NsxPolicyLibTestCase):
self.assert_called_with_def( self.assert_called_with_def(
update_call, expected_def) update_call, expected_def)
def test_get_overlay_transport_zone(self):
# Test the passthrough api
tier0_id = '111'
logical_router_id = 'realized_111'
info = {'state': policy_constants.STATE_REALIZED,
'entity_type': 'RealizedLogicalRouter',
'realization_specific_identifier': logical_router_id}
pt_mock = self.resourceApi.nsx_api.router.get_tier0_router_overlay_tz
with mock.patch.object(self.resourceApi, "_get_realization_info",
return_value=info) as realization:
self.resourceApi.get_overlay_transport_zone(
tier0_id, tenant=TEST_TENANT)
realization.assert_called_once()
pt_mock.assert_called_once_with(logical_router_id)
def test_wait_until_realized(self):
tier1_id = '111'
logical_router_id = 'realized_111'
info = {'state': policy_constants.STATE_UNREALIZED,
'realization_specific_identifier': logical_router_id}
with mock.patch.object(self.resourceApi, "_get_realization_info",
return_value=info):
self.assertRaises(nsxlib_exc.ManagerError,
self.resourceApi.wait_until_realized,
tier1_id, tenant=TEST_TENANT)
class TestPolicySegmentProfileBase(NsxPolicyLibTestCase): class TestPolicySegmentProfileBase(NsxPolicyLibTestCase):

View File

@ -14,11 +14,11 @@
# under the License. # under the License.
# #
from vmware_nsxlib import v3 import mock
from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase
from vmware_nsxlib.tests.unit.v3 import policy_testcase from vmware_nsxlib.tests.unit.v3 import policy_testcase
from vmware_nsxlib import v3
from vmware_nsxlib.v3 import policy_transaction as trans from vmware_nsxlib.v3 import policy_transaction as trans
@ -29,7 +29,9 @@ class TestPolicyTransaction(policy_testcase.TestPolicyApi):
super(TestPolicyTransaction, self).setUp() super(TestPolicyTransaction, self).setUp()
nsxlib_config = nsxlib_testcase.get_default_nsxlib_config() nsxlib_config = nsxlib_testcase.get_default_nsxlib_config()
self.policy_lib = v3.NsxPolicyLib(nsxlib_config) # Mock the nsx-lib for the passthrough api
with mock.patch('vmware_nsxlib.v3.NsxLib'):
self.policy_lib = v3.NsxPolicyLib(nsxlib_config)
self.policy_api = self.policy_lib.policy_api self.policy_api = self.policy_lib.policy_api
self.policy_api.client = self.client self.policy_api.client = self.client

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
import abc import abc
import copy
from distutils import version from distutils import version
from oslo_log import log from oslo_log import log
@ -59,12 +60,11 @@ class NsxLibBase(object):
self.general_apis = utils.NsxLibApiBase( self.general_apis = utils.NsxLibApiBase(
self.client, self.nsxlib_config) self.client, self.nsxlib_config)
self.nsx_version = None
self.init_api() self.init_api()
super(NsxLibBase, self).__init__() super(NsxLibBase, self).__init__()
self.nsx_version = None
def set_config(self, nsxlib_config): def set_config(self, nsxlib_config):
"""Set config user provided and extend it according to application""" """Set config user provided and extend it according to application"""
self.nsxlib_config = nsxlib_config self.nsxlib_config = nsxlib_config
@ -380,46 +380,59 @@ class NsxLib(NsxLibBase):
class NsxPolicyLib(NsxLibBase): class NsxPolicyLib(NsxLibBase):
def init_api(self): def init_api(self):
# Initialize the policy client
self.policy_api = policy_defs.NsxPolicyApi(self.client) self.policy_api = policy_defs.NsxPolicyApi(self.client)
self.domain = policy_resources.NsxPolicyDomainApi(self.policy_api)
self.group = policy_resources.NsxPolicyGroupApi(self.policy_api) # NSX manager api will be used as a pass-through for apis which are
self.service = policy_resources.NsxPolicyL4ServiceApi(self.policy_api) # not implemented by the policy manager yet
if self.nsxlib_config.allow_passthrough:
config = copy.deepcopy(self.nsxlib_config)
# X-Allow-Overwrite must be set for passthrough apis
config.allow_overwrite_header = True
self.nsx_api = NsxLib(config)
else:
self.nsx_api = None
self.nsx_version = self.get_version()
args = (self.policy_api, self.nsx_api, self.nsx_version)
# Initialize all the different resources
self.domain = policy_resources.NsxPolicyDomainApi(*args)
self.group = policy_resources.NsxPolicyGroupApi(*args)
self.service = policy_resources.NsxPolicyL4ServiceApi(*args)
self.icmp_service = policy_resources.NsxPolicyIcmpServiceApi( self.icmp_service = policy_resources.NsxPolicyIcmpServiceApi(
self.policy_api) *args)
self.ip_protocol_service = ( self.ip_protocol_service = (
policy_resources.NsxPolicyIPProtocolServiceApi( policy_resources.NsxPolicyIPProtocolServiceApi(*args))
self.policy_api)) self.tier0 = policy_resources.NsxPolicyTier0Api(*args)
self.tier0 = policy_resources.NsxPolicyTier0Api(self.policy_api) self.tier1 = policy_resources.NsxPolicyTier1Api(*args)
self.tier1 = policy_resources.NsxPolicyTier1Api(self.policy_api) self.tier1_segment = policy_resources.NsxPolicyTier1SegmentApi(*args)
self.tier1_segment = policy_resources.NsxPolicyTier1SegmentApi(
self.policy_api)
self.tier1_nat_rule = policy_resources.NsxPolicyTier1NatRuleApi( self.tier1_nat_rule = policy_resources.NsxPolicyTier1NatRuleApi(
self.policy_api) *args)
self.segment = policy_resources.NsxPolicySegmentApi(self.policy_api) self.segment = policy_resources.NsxPolicySegmentApi(*args)
self.segment_port = policy_resources.NsxPolicySegmentPortApi( self.segment_port = policy_resources.NsxPolicySegmentPortApi(
self.policy_api) *args)
self.tier1_segment_port = ( self.tier1_segment_port = (
policy_resources.NsxPolicyTier1SegmentPortApi(self.policy_api)) policy_resources.NsxPolicyTier1SegmentPortApi(*args))
self.comm_map = policy_resources.NsxPolicyCommunicationMapApi( self.comm_map = policy_resources.NsxPolicyCommunicationMapApi(
self.policy_api) *args)
self.enforcement_point = policy_resources.NsxPolicyEnforcementPointApi( self.enforcement_point = policy_resources.NsxPolicyEnforcementPointApi(
self.policy_api) *args)
self.transport_zone = policy_resources.NsxPolicyTransportZoneApi( self.transport_zone = policy_resources.NsxPolicyTransportZoneApi(
self.policy_api) *args)
self.deployment_map = policy_resources.NsxPolicyDeploymentMapApi( self.deployment_map = policy_resources.NsxPolicyDeploymentMapApi(
self.policy_api) *args)
self.ip_block = policy_resources.NsxPolicyIpBlockApi(self.policy_api) self.ip_block = policy_resources.NsxPolicyIpBlockApi(*args)
self.ip_pool = policy_resources.NsxPolicyIpPoolApi(self.policy_api) self.ip_pool = policy_resources.NsxPolicyIpPoolApi(*args)
self.segment_security_profile = ( self.segment_security_profile = (
policy_resources.NsxSegmentSecurityProfileApi(self.policy_api)) policy_resources.NsxSegmentSecurityProfileApi(*args))
self.qos_profile = ( self.qos_profile = (
policy_resources.NsxQosProfileApi(self.policy_api)) policy_resources.NsxQosProfileApi(*args))
self.spoofguard_profile = ( self.spoofguard_profile = (
policy_resources.NsxSpoofguardProfileApi(self.policy_api)) policy_resources.NsxSpoofguardProfileApi(*args))
self.ip_discovery_profile = ( self.ip_discovery_profile = (
policy_resources.NsxIpDiscoveryProfileApi(self.policy_api)) policy_resources.NsxIpDiscoveryProfileApi(*args))
self.mac_discovery_profile = ( self.mac_discovery_profile = (
policy_resources.NsxMacDiscoveryProfileApi(self.policy_api)) policy_resources.NsxMacDiscoveryProfileApi(*args))
@property @property
def keepalive_section(self): def keepalive_section(self):
@ -429,20 +442,16 @@ class NsxPolicyLib(NsxLibBase):
"""Get the NSX Policy manager version """Get the NSX Policy manager version
Currently the backend does not support it, so the nsx-manager api Currently the backend does not support it, so the nsx-manager api
will be used temporarily. will be used temporarily as a passthrough.
""" """
if self.nsx_version: if self.nsx_version:
return self.nsx_version return self.nsx_version
manager_client = client.NSX3Client( if self.nsx_api:
self.cluster, self.nsx_version = self.nsx_api.get_version()
nsx_api_managers=self.nsxlib_config.nsx_api_managers, else:
max_attempts=self.nsxlib_config.max_attempts, # return the initial supported version
url_path_base=client.NSX3Client.NSX_V1_API_PREFIX, self.nsx_version = nsx_constants.NSX_VERSION_2_4_0
rate_limit_retry=self.nsxlib_config.rate_limit_retry)
node = manager_client.get('node')
self.nsx_version = node.get('node_version')
return self.nsx_version return self.nsx_version
def feature_supported(self, feature): def feature_supported(self, feature):
@ -454,6 +463,13 @@ class NsxPolicyLib(NsxLibBase):
return (feature == nsx_constants.FEATURE_NSX_POLICY) return (feature == nsx_constants.FEATURE_NSX_POLICY)
def reinitialize_cluster(self, resource, event, trigger, payload=None):
super(NsxPolicyLib, self).reinitialize_cluster(
resource, event, trigger, payload=payload)
if self.nsx_api:
self.nsx_api.reinitialize_cluster(resource, event, trigger,
payload)
@property @property
def client_url_prefix(self): def client_url_prefix(self):
return client.NSX3Client.NSX_POLICY_V1_API_PREFIX return client.NSX3Client.NSX_POLICY_V1_API_PREFIX

View File

@ -78,6 +78,10 @@ class NsxLibConfig(object):
endpoint in the NSX management cluster is endpoint in the NSX management cluster is
available to serve a request, and retry available to serve a request, and retry
the request instead. the request instead.
-- Additional parameters which are relevant only for the Policy manager:
:param allow_passthrough: If True, use nsx manager api for cases which are
not supported by the policy manager api.
""" """
def __init__(self, def __init__(self,
@ -102,7 +106,8 @@ class NsxLibConfig(object):
dhcp_profile_uuid=None, dhcp_profile_uuid=None,
allow_overwrite_header=False, allow_overwrite_header=False,
rate_limit_retry=True, rate_limit_retry=True,
cluster_unavailable_retry=False): cluster_unavailable_retry=False,
allow_passthrough=False):
self.nsx_api_managers = nsx_api_managers self.nsx_api_managers = nsx_api_managers
self._username = username self._username = username
@ -125,6 +130,7 @@ class NsxLibConfig(object):
self.allow_overwrite_header = allow_overwrite_header self.allow_overwrite_header = allow_overwrite_header
self.rate_limit_retry = rate_limit_retry self.rate_limit_retry = rate_limit_retry
self.cluster_unavailable_retry = cluster_unavailable_retry self.cluster_unavailable_retry = cluster_unavailable_retry
self.allow_passthrough = allow_passthrough
if dhcp_profile_uuid: if dhcp_profile_uuid:
# this is deprecated, and never used. # this is deprecated, and never used.

View File

@ -47,8 +47,10 @@ class NsxPolicyResourceBase(object):
""" """
SINGLE_ENTRY_ID = 'entry' SINGLE_ENTRY_ID = 'entry'
def __init__(self, policy_api): def __init__(self, policy_api, nsx_api, version):
self.policy_api = policy_api self.policy_api = policy_api
self.nsx_api = nsx_api
self.version = version
@property @property
def entry_def(self): def entry_def(self):
@ -761,6 +763,23 @@ class NsxPolicyTier1Api(NsxPolicyResourceBase):
tier1_def = self.entry_def(tier1_id=tier1_id, tenant=tenant) tier1_def = self.entry_def(tier1_id=tier1_id, tenant=tenant)
return self._wait_until_realized(tier1_def, entity_type=entity_type) return self._wait_until_realized(tier1_def, entity_type=entity_type)
def update_transport_zone(self, tier1_id, transport_zone_id,
tenant=policy_constants.POLICY_INFRA_TENANT):
"""Use the pass-through api to update the TZ zone on the NSX router"""
if not self.nsx_api:
LOG.error("Cannot update tier1 %s transport zone as the "
"passthrough api is forbidden", tier1_id)
return
realization_info = self.wait_until_realized(
tier1_id, entity_type='RealizedLogicalRouter', tenant=tenant)
nsx_router_uuid = self.get_realized_id(
tier1_id, tenant=tenant, realization_info=realization_info)
self.nsx_api.logical_router.update(
nsx_router_uuid,
transport_zone_id=transport_zone_id)
class NsxPolicyTier0Api(NsxPolicyResourceBase): class NsxPolicyTier0Api(NsxPolicyResourceBase):
"""NSX Tier0 API """ """NSX Tier0 API """
@ -838,6 +857,22 @@ class NsxPolicyTier0Api(NsxPolicyResourceBase):
if 'edge_cluster_path' in srv: if 'edge_cluster_path' in srv:
return srv['edge_cluster_path'] return srv['edge_cluster_path']
def get_overlay_transport_zone(
self, tier0_id,
tenant=policy_constants.POLICY_INFRA_TENANT):
"""Use the pass-through api to get the TZ zone of the NSX tier0"""
if not self.nsx_api:
LOG.error("Cannot get tier0 %s transport zone as the "
"passthrough api is forbidden", tier0_id)
return
realization_info = self.wait_until_realized(
tier0_id, entity_type='RealizedLogicalRouter', tenant=tenant)
nsx_router_uuid = self.get_realized_id(
tier0_id, tenant=tenant,
realization_info=realization_info)
return self.nsx_api.router.get_tier0_router_overlay_tz(
nsx_router_uuid)
def get_realized_state(self, tier0_id, entity_type=None, def get_realized_state(self, tier0_id, entity_type=None,
tenant=policy_constants.POLICY_INFRA_TENANT, tenant=policy_constants.POLICY_INFRA_TENANT,
realization_info=None): realization_info=None):