Add support for relax_scale_validation in LbService
Starting from NSX version 2.5.1, LBService will have a new property 'relax_scale_validation'. If this flag is set to true, scale validation for vs, pool, pool member and rule will be relaxed for lbs Checks are added to prevent including this flag in API calls on older versions of NSX backend. feature_supported for this new flag is added in NsxLib for MP. For Policy, ResourceDef and LBServiceDef are responsible for the checks. For MP, checks are added in _build_args() in load_balancer.py > Service class so that the new flag is only passed when NSX meets the version requirement. For Policy, ResourceDef now has a new attribute nsx_version and two new methods: _set_attr_if_supported() and _attr_supported(). get_obj_dict() will use them to check if a certain attr meets version requirement, and only include it in body if true. Change-Id: I4f9c3bfd7995bca85a51a6971fc9d784e574301a
This commit is contained in:
parent
e252900cc0
commit
093d510988
@ -628,6 +628,7 @@ class TestPolicyLBService(test_resources.NsxPolicyLibTestCase):
|
||||
obj_id = '111'
|
||||
size = 'SMALL'
|
||||
connectivity_path = 'path'
|
||||
relax_scale_validation = True
|
||||
with self.mock_create_update() as api_call:
|
||||
result = self.resourceApi.create_or_overwrite(
|
||||
name,
|
||||
@ -635,14 +636,17 @@ class TestPolicyLBService(test_resources.NsxPolicyLibTestCase):
|
||||
description=description,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation,
|
||||
tenant=TEST_TENANT)
|
||||
expected_def = (
|
||||
lb_defs.LBServiceDef(
|
||||
nsx_version=self.policy_lib.get_version(),
|
||||
lb_service_id=obj_id,
|
||||
name=name,
|
||||
description=description,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation,
|
||||
tenant=TEST_TENANT))
|
||||
self.assert_called_with_def(api_call, expected_def)
|
||||
self.assertEqual(obj_id, result)
|
||||
@ -662,6 +666,25 @@ class TestPolicyLBService(test_resources.NsxPolicyLibTestCase):
|
||||
self.assert_called_with_def(api_call, expected_def)
|
||||
self.assertIsNotNone(result)
|
||||
|
||||
def test_create_with_unsupported_attribute(self):
|
||||
name = 'd1'
|
||||
description = 'desc'
|
||||
relax_scale_validation = True
|
||||
|
||||
with self.mock_create_update() as api_call, \
|
||||
mock.patch.object(self.resourceApi, 'version', '0.0.0'):
|
||||
result = self.resourceApi.create_or_overwrite(
|
||||
name, description=description,
|
||||
relax_scale_validation=relax_scale_validation,
|
||||
tenant=TEST_TENANT)
|
||||
expected_def = (
|
||||
lb_defs.LBServiceDef(lb_service_id=mock.ANY,
|
||||
name=name,
|
||||
description=description,
|
||||
tenant=TEST_TENANT))
|
||||
self.assert_called_with_def(api_call, expected_def)
|
||||
self.assertIsNotNone(result)
|
||||
|
||||
def test_delete(self):
|
||||
obj_id = '111'
|
||||
with mock.patch.object(self.policy_api, "delete") as api_call:
|
||||
@ -708,21 +731,26 @@ class TestPolicyLBService(test_resources.NsxPolicyLibTestCase):
|
||||
description = 'new desc'
|
||||
size = 'SMALL'
|
||||
connectivity_path = 'path'
|
||||
relax_scale_validation = True
|
||||
with self.mock_get(obj_id, name), \
|
||||
self.mock_create_update() as update_call:
|
||||
self.resourceApi.update(obj_id,
|
||||
name=name,
|
||||
description=description,
|
||||
tenant=TEST_TENANT,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path)
|
||||
self.resourceApi.update(
|
||||
obj_id,
|
||||
name=name,
|
||||
description=description,
|
||||
tenant=TEST_TENANT,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation)
|
||||
expected_def = lb_defs.LBServiceDef(
|
||||
nsx_version=self.policy_lib.get_version(),
|
||||
lb_service_id=obj_id,
|
||||
name=name,
|
||||
description=description,
|
||||
tenant=TEST_TENANT,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path)
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation)
|
||||
self.assert_called_with_def(update_call, expected_def)
|
||||
|
||||
def test_get_status(self):
|
||||
|
@ -348,7 +348,8 @@ FAKE_SERVICE = {
|
||||
"attachment": {
|
||||
"target_id": FAKE_ROUTER_UUID,
|
||||
"target_type": "LogicalRouter"
|
||||
}
|
||||
},
|
||||
"relax_scale_validation": False
|
||||
}
|
||||
|
||||
FAKE_TZ_UUID = uuidutils.generate_uuid()
|
||||
|
@ -498,13 +498,17 @@ class TestService(nsxlib_testcase.NsxClientTestCase):
|
||||
'description': fake_service['description'],
|
||||
'enabled': fake_service['enabled'],
|
||||
'attachment': fake_service['attachment'],
|
||||
'relax_scale_validation': fake_service['relax_scale_validation'],
|
||||
'tags': consts.FAKE_TAGS
|
||||
}
|
||||
with mock.patch.object(self.nsxlib.client, 'create') as create:
|
||||
with mock.patch.object(self.nsxlib.client, 'create') as create, \
|
||||
mock.patch.object(self.nsxlib, 'feature_supported') as support:
|
||||
support.return_value = True
|
||||
self.nsxlib.load_balancer.service.create(
|
||||
body['display_name'], body['description'],
|
||||
consts.FAKE_TAGS, enabled=body['enabled'],
|
||||
attachment=body['attachment'])
|
||||
attachment=body['attachment'],
|
||||
relax_scale_validation=body['relax_scale_validation'])
|
||||
create.assert_called_with('loadbalancer/services',
|
||||
body)
|
||||
|
||||
|
@ -91,7 +91,7 @@ class NsxLib(lib.NsxLibBase):
|
||||
self.ip_pool = resources.IpPool(
|
||||
self.client, self.nsxlib_config, nsxlib=self)
|
||||
self.load_balancer = load_balancer.LoadBalancer(
|
||||
self.client, self.nsxlib_config)
|
||||
self.client, self.nsxlib_config, nsxlib=self)
|
||||
self.trust_management = trust_management.NsxLibTrustManagement(
|
||||
self.client, self.nsxlib_config)
|
||||
self.router = router.RouterLib(
|
||||
@ -168,7 +168,13 @@ class NsxLib(lib.NsxLibBase):
|
||||
|
||||
def feature_supported(self, feature):
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_5_0)):
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_5_1)):
|
||||
# features available since 2.5.1
|
||||
if (feature == nsx_constants.FEATURE_RELAX_SCALE_VALIDATION):
|
||||
return True
|
||||
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_5_0)):
|
||||
# features available since 2.5
|
||||
if (feature == nsx_constants.FEATURE_CONTAINER_CLUSTER_INVENTORY):
|
||||
return True
|
||||
@ -178,7 +184,7 @@ class NsxLib(lib.NsxLibBase):
|
||||
return True
|
||||
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_4_0)):
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_4_0)):
|
||||
# Features available since 2.4
|
||||
if (feature == nsx_constants.FEATURE_ENS_WITH_SEC):
|
||||
return True
|
||||
@ -188,7 +194,7 @@ class NsxLib(lib.NsxLibBase):
|
||||
return True
|
||||
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_3_0)):
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_3_0)):
|
||||
# Features available since 2.3
|
||||
if (feature == nsx_constants.FEATURE_ROUTER_ALLOCATION_PROFILE):
|
||||
return True
|
||||
|
@ -16,6 +16,7 @@
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||
from vmware_nsxlib.v3 import nsx_constants
|
||||
from vmware_nsxlib.v3 import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -411,6 +412,27 @@ class VirtualServer(LoadBalancerBase):
|
||||
class Service(LoadBalancerBase):
|
||||
resource = 'loadbalancer/services'
|
||||
|
||||
def _build_args(self, body, display_name=None, description=None,
|
||||
tags=None, resource_type=None, **kwargs):
|
||||
if display_name:
|
||||
body['display_name'] = display_name
|
||||
if description:
|
||||
body['description'] = description
|
||||
if tags:
|
||||
body['tags'] = tags
|
||||
if resource_type:
|
||||
body['resource_type'] = resource_type
|
||||
|
||||
if ('relax_scale_validation' in kwargs and
|
||||
not self.nsxlib.feature_supported(
|
||||
nsx_constants.FEATURE_RELAX_SCALE_VALIDATION)):
|
||||
kwargs.pop('relax_scale_validation')
|
||||
LOG.warning("Ignoring relax_scale_validation for new "
|
||||
"lb service %s: this feature is not supported.",
|
||||
display_name)
|
||||
body.update(kwargs)
|
||||
return body
|
||||
|
||||
def update_service_with_virtual_servers(self, service_id,
|
||||
virtual_server_ids):
|
||||
# Using internal method so we can access max_attempts in the decorator
|
||||
@ -475,8 +497,8 @@ class Service(LoadBalancerBase):
|
||||
class LoadBalancer(object):
|
||||
"""This is the class that have all load balancer resource clients"""
|
||||
|
||||
def __init__(self, client, nsxlib_config=None):
|
||||
self.service = Service(client, nsxlib_config)
|
||||
def __init__(self, client, nsxlib_config=None, nsxlib=None):
|
||||
self.service = Service(client, nsxlib_config, nsxlib)
|
||||
self.virtual_server = VirtualServer(client, nsxlib_config)
|
||||
self.pool = Pool(client, nsxlib_config)
|
||||
self.monitor = Monitor(client, nsxlib_config)
|
||||
|
@ -146,6 +146,7 @@ NSX_VERSION_2_2_0 = '2.2.0'
|
||||
NSX_VERSION_2_3_0 = '2.3.0'
|
||||
NSX_VERSION_2_4_0 = '2.4.0'
|
||||
NSX_VERSION_2_5_0 = '2.5.0'
|
||||
NSX_VERSION_2_5_1 = '2.5.1'
|
||||
NSX_VERSION_3_0_0 = '3.0.0'
|
||||
|
||||
# Features available depending on the NSX Manager backend version
|
||||
@ -169,6 +170,7 @@ FEATURE_ICMP_STRICT = 'Strict list of supported ICMP types and codes'
|
||||
FEATURE_ROUTER_ALLOCATION_PROFILE = 'Router Allocation Profile'
|
||||
FEATURE_ENABLE_STANDBY_RELOCATION = 'Router Enable standby relocation'
|
||||
FEATURE_PARTIAL_UPDATES = 'Partial Update with PATCH'
|
||||
FEATURE_RELAX_SCALE_VALIDATION = 'Relax Scale Validation for LbService'
|
||||
|
||||
# Features available depending on the Policy Manager backend version
|
||||
FEATURE_NSX_POLICY = 'NSX Policy'
|
||||
|
@ -161,8 +161,15 @@ class NsxPolicyLib(lib.NsxLibBase):
|
||||
if (feature == nsx_constants.FEATURE_ENS_WITH_QOS):
|
||||
return True
|
||||
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_5_1)):
|
||||
# features available since 2.5.1
|
||||
if (feature == nsx_constants.FEATURE_RELAX_SCALE_VALIDATION):
|
||||
return True
|
||||
|
||||
if (version.LooseVersion(self.get_version()) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)):
|
||||
# features available since 3.0.0
|
||||
if feature == nsx_constants.FEATURE_PARTIAL_UPDATES:
|
||||
return True
|
||||
|
||||
|
@ -64,9 +64,13 @@ TIER1_LOCALE_SERVICES_PATH_PATTERN = (TIER1S_PATH_PATTERN +
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ResourceDef(object):
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, nsx_version=None, **kwargs):
|
||||
self.attrs = kwargs
|
||||
|
||||
# nsx_version should be passed in on init if the resource has
|
||||
# version-dependant attributes. Otherwise this is ignored
|
||||
self.nsx_version = nsx_version
|
||||
|
||||
# init default tenant
|
||||
self.attrs['tenant'] = self.get_tenant()
|
||||
|
||||
@ -191,6 +195,41 @@ class ResourceDef(object):
|
||||
for attr in attr_list:
|
||||
self._set_attr_if_specified(body, attr)
|
||||
|
||||
# Helper to set attr in body if user specified it
|
||||
# and current nsx version supports it
|
||||
# Body name must match attr name
|
||||
def _set_attr_if_supported(self, body, attr, value=None):
|
||||
if self.has_attr(attr) and self._version_dependant_attr_supported(
|
||||
attr):
|
||||
value = value if value is not None else self.get_attr(attr)
|
||||
body[attr] = value
|
||||
|
||||
# Helper to set attrs in body if user specified them
|
||||
# and current nsx version supports it
|
||||
# Body name must match attr name
|
||||
def _set_attrs_if_supported(self, body, attr_list):
|
||||
for attr in attr_list:
|
||||
self._set_attr_if_supported(body, attr)
|
||||
|
||||
def _version_dependant_attr_supported(self, attr):
|
||||
"""Check if a version dependent attr is supported on current NSX
|
||||
|
||||
For each resource def, there could be some attributes which only exist
|
||||
on NSX after certain versions. This abstract method provides a skeleton
|
||||
to define version requirements of version-dependent attributes.
|
||||
|
||||
By design, Devs should use _set_attr_if_supported() to add any attrs
|
||||
that are only known to NSX after a certain version. This method works
|
||||
as a registry for _set_attrs_if_supported() to know the baseline
|
||||
version of each version dependent attr.
|
||||
|
||||
Non-version-dependent attributes should be added to the request body
|
||||
by using _set_attr_if_specified(). This method defaults to false since
|
||||
any version dependent attr unknown to this lib should be excluded
|
||||
for security and safety reasons.
|
||||
"""
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def get_single_entry(cls, obj_body):
|
||||
"""Return the single sub-entry from the object body.
|
||||
|
@ -125,7 +125,7 @@ class NsxPolicyResourceBase(object):
|
||||
def _init_def(self, **kwargs):
|
||||
"""Helper for update function - ignore attrs without explicit value"""
|
||||
args = self._get_user_args(**kwargs)
|
||||
return self.entry_def(**args)
|
||||
return self.entry_def(nsx_version=self.version, **args)
|
||||
|
||||
def _init_parent_def(self, **kwargs):
|
||||
"""Helper for update function - ignore attrs without explicit value"""
|
||||
@ -135,7 +135,7 @@ class NsxPolicyResourceBase(object):
|
||||
def _get_and_update_def(self, **kwargs):
|
||||
"""Helper for update function - ignore attrs without explicit value"""
|
||||
args = self._get_user_args(**kwargs)
|
||||
resource_def = self.entry_def(**args)
|
||||
resource_def = self.entry_def(nsx_version=self.version, **args)
|
||||
body = self.policy_api.get(resource_def)
|
||||
if body:
|
||||
resource_def.set_obj_dict(body)
|
||||
|
@ -14,9 +14,15 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from distutils import version
|
||||
|
||||
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 ResourceDef
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
TENANTS_PATH_PATTERN = "%s/"
|
||||
LB_VIRTUAL_SERVERS_PATH_PATTERN = TENANTS_PATH_PATTERN + "lb-virtual-servers/"
|
||||
LB_SERVICES_PATH_PATTERN = TENANTS_PATH_PATTERN + "lb-services/"
|
||||
@ -379,8 +385,24 @@ class LBServiceDef(ResourceDef):
|
||||
def get_obj_dict(self):
|
||||
body = super(LBServiceDef, self).get_obj_dict()
|
||||
self._set_attrs_if_specified(body, ['size', 'connectivity_path'])
|
||||
self._set_attrs_if_supported(body, ['relax_scale_validation'])
|
||||
return body
|
||||
|
||||
def _version_dependant_attr_supported(self, attr):
|
||||
if (version.LooseVersion(self.nsx_version) >=
|
||||
version.LooseVersion(nsx_constants.NSX_VERSION_2_5_1)):
|
||||
if attr == 'relax_scale_validation':
|
||||
return True
|
||||
else:
|
||||
LOG.warning(
|
||||
"Ignoring %s for %s %s: this feature is not supported."
|
||||
"Current NSX version: %s. Minimum supported version: %s",
|
||||
attr, self.resource_type, self.attrs.get('name', ''),
|
||||
self.nsx_version, nsx_constants.NSX_VERSION_2_5_1)
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class LBServiceStatisticsDef(ResourceDef):
|
||||
|
||||
|
@ -577,6 +577,7 @@ class NsxPolicyLoadBalancerPoolApi(NsxPolicyResourceBase):
|
||||
|
||||
class NsxPolicyLoadBalancerServiceApi(NsxPolicyResourceBase):
|
||||
"""NSX Policy LBService."""
|
||||
|
||||
@property
|
||||
def entry_def(self):
|
||||
return lb_defs.LBServiceDef
|
||||
@ -586,6 +587,7 @@ class NsxPolicyLoadBalancerServiceApi(NsxPolicyResourceBase):
|
||||
tags=IGNORE,
|
||||
size=IGNORE,
|
||||
connectivity_path=IGNORE,
|
||||
relax_scale_validation=IGNORE,
|
||||
tenant=constants.POLICY_INFRA_TENANT):
|
||||
lb_service_id = self._init_obj_uuid(lb_service_id)
|
||||
lb_service_def = self._init_def(
|
||||
@ -595,6 +597,7 @@ class NsxPolicyLoadBalancerServiceApi(NsxPolicyResourceBase):
|
||||
tags=tags,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation,
|
||||
tenant=tenant)
|
||||
|
||||
self._create_or_store(lb_service_def)
|
||||
@ -618,14 +621,18 @@ class NsxPolicyLoadBalancerServiceApi(NsxPolicyResourceBase):
|
||||
def update(self, lb_service_id, name=IGNORE,
|
||||
description=IGNORE, tags=IGNORE,
|
||||
size=IGNORE, connectivity_path=IGNORE,
|
||||
relax_scale_validation=IGNORE,
|
||||
tenant=constants.POLICY_INFRA_TENANT):
|
||||
self._update(lb_service_id=lb_service_id,
|
||||
name=name,
|
||||
description=description,
|
||||
tags=tags,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
tenant=tenant)
|
||||
|
||||
self._update(
|
||||
lb_service_id=lb_service_id,
|
||||
name=name,
|
||||
description=description,
|
||||
tags=tags,
|
||||
size=size,
|
||||
connectivity_path=connectivity_path,
|
||||
relax_scale_validation=relax_scale_validation,
|
||||
tenant=tenant)
|
||||
|
||||
def get_statistics(self, lb_service_id,
|
||||
tenant=constants.POLICY_INFRA_TENANT):
|
||||
|
Loading…
x
Reference in New Issue
Block a user