Skip to content

Commit

Permalink
nb: add support for lb health checks API
Browse files Browse the repository at this point in the history
This change adds functions and commands to add, delete, list, get and
update health checks of load balancers. Also added a method to get one
load balancer by name or uuid and methods to modify 'ip_port_mappings'
column in the load balancer.

Closes-Bug: 1964382
Change-Id: I3f8b63c64c7ac9c570dbd400c562fa97840429ca
  • Loading branch information
0x5b authored and otherwiseguy committed Jul 29, 2022
1 parent e9c6c6c commit f3c5da5
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 0 deletions.
82 changes: 82 additions & 0 deletions ovsdbapp/schema/ovn_northbound/api.py
Expand Up @@ -885,6 +885,88 @@ def lb_del(self, lb, vip=None, if_exists=False):
def lb_list(self):
"""Get the UUIDs of all load balanacers"""

@abc.abstractmethod
def lb_get(self, lb):
"""Get load balancer for 'lb'
:returns: :class:`Command` with RowView result
"""

@abc.abstractmethod
def lb_add_health_check(self, lb, vip, **options):
"""Add health check for 'lb'
:param lb: The name or uuid of a load balancer
:type lb: string or uuid.UUID
:param vip: A virtual IP
:type vip: string
:param options: keys and values for the port 'options' dict
:type options: key: string, value: string
:returns: :class:`Command` with no result
"""

@abc.abstractmethod
def lb_del_health_check(self, lb, hc_uuid, if_exists=False):
"""Remove health check from 'lb'
:param lb: The name or uuid of a load balancer
:type lb: string or uuid.UUID
:param hc_uuid: uuid of a health check
:type hc_uuid: uuid.UUID
:param if_exists: If True, don't fail if the hc_uuid doesn't exist
:type if_exists: boolean
:returns: :class:`Command` with no result
"""

@abc.abstractmethod
def lb_add_ip_port_mapping(self, lb, endpoint_ip, port_name, source_ip):
"""Add IP port mapping to 'lb'
Maps from endpoint IP to a colon-separated pair of logical port name
and source IP, e.g. port_name:sourc_ip.
:param lb: The name or uuid of a load balancer
:type lb: string or uuid.UUID
:param endpoint_ip: IPv4 address
:type endpoint_ip: string
:param port_name: The name of a logical port
:type port_name: string
:param source_ip: IPv4 address
:type source_ip: string
:returns: :class:`Command` with no result
"""

@abc.abstractmethod
def lb_del_ip_port_mapping(self, lb, endpoint_ip):
"""Remove IP port mapping from 'lb'
:param lb: The name or uuid of a load balancer
:type lb: string or uuid.UUID
:param endpoint_ip: IPv4 address
:type endpoint_ip: string
:returns: :class:`Command` with no result
"""

@abc.abstractmethod
def health_check_set_options(self, hc_uuid, **options):
"""Set options to the 'health_check'
:param hc_uuid: uuid of the health check
:type hc_uuid: uuid.UUID
:param options: keys and values for the port 'options' dict
:type options: key: string, value: string
:returns: :class:`Command` with no result
"""

@abc.abstractmethod
def health_check_get_options(self, hc_uuid):
"""Get the options for 'health_check'
:param hc_uuid: uuid of the health check
:type hc_uuid: uuid.UUID
:returns: :class:`Command` with dict result
"""

@abc.abstractmethod
def lr_lb_add(self, router, lb, may_exist=False):
"""Add a load-balancer to 'router'
Expand Down
94 changes: 94 additions & 0 deletions ovsdbapp/schema/ovn_northbound/commands.py
Expand Up @@ -1341,6 +1341,100 @@ def run_idl(self, txn):
for r in self.api.tables['Load_Balancer'].rows.values()]


class LbGetCommand(cmd.BaseGetRowCommand):
table = 'Load_Balancer'


class LbAddHealthCheckCommand(cmd.BaseCommand):
table = 'Load_Balancer'

def __init__(self, api, lb, vip, **options):
super().__init__(api)
self.lb = lb
self.vip = vip
self.options = options

def run_idl(self, txn):
lb = self.api.lookup(self.table, self.lb)
cmd = HealthCheckAddCommand(self.api, self.vip, **self.options)
cmd.run_idl(txn)
lb.addvalue('health_check', cmd.result)


class LbDelHealthCheckCommand(cmd.BaseCommand):
table = 'Load_Balancer'

def __init__(self, api, lb, hc_uuid, if_exists=False):
super().__init__(api)
self.lb = lb
self.hc_uuid = hc_uuid
self.if_exists = if_exists

def run_idl(self, txn):
lb = self.api.lookup(self.table, self.lb)
for health_check in lb.health_check:
if health_check.uuid == self.hc_uuid:
lb.delvalue('health_check', health_check)
health_check.delete()
return
if not self.if_exists:
msg = "Health check '%s' on lb %s does not exist" % (
self.hc_uuid, self.lb)
raise RuntimeError(msg)


class LbAddIpPortMappingСommand(cmd.BaseCommand):
table = 'Load_Balancer'

def __init__(self, api, lb, endpoint_ip, port_name, source_ip):
super().__init__(api)
self.lb = lb
self.endpoint_ip = str(netaddr.IPAddress(endpoint_ip))
self.port_name = port_name
self.source_ip = str(netaddr.IPAddress(source_ip))

def run_idl(self, txn):
lb = self.api.lookup(self.table, self.lb)
lb.setkey('ip_port_mappings', self.endpoint_ip,
'%s:%s' % (self.port_name, self.source_ip))


class LbDelIpPortMappingCommand(cmd.BaseCommand):
table = 'Load_Balancer'

def __init__(self, api, lb, endpoint_ip):
super().__init__(api)
self.lb = lb
self.endpoint_ip = str(netaddr.IPAddress(endpoint_ip))

def run_idl(self, txn):
lb = self.api.lookup(self.table, self.lb)
lb.delkey('ip_port_mappings', self.endpoint_ip)


class HealthCheckAddCommand(cmd.AddCommand):
table_name = 'Load_Balancer_Health_Check'

def __init__(self, api, vip, **options):
super().__init__(api)
self.vip = utils.normalize_ip_port(vip)
self.options = options

def run_idl(self, txn):
hc = txn.insert(self.api.tables[self.table_name])
hc.vip = self.vip
hc.options = self.options
self.result = hc


class HealthCheckSetOptionsCommand(cmd.BaseSetOptionsCommand):
table = 'Load_Balancer_Health_Check'


class HealthCheckGetOptionsCommand(cmd.BaseGetOptionsCommand):
table = 'Load_Balancer_Health_Check'


class LrLbAddCommand(cmd.BaseCommand):
def __init__(self, api, router, lb, may_exist=False):
super().__init__(api)
Expand Down
22 changes: 22 additions & 0 deletions ovsdbapp/schema/ovn_northbound/impl_idl.py
Expand Up @@ -273,6 +273,28 @@ def lb_del(self, lb, vip=None, if_exists=False):
def lb_list(self):
return cmd.LbListCommand(self)

def lb_get(self, lb):
return cmd.LbGetCommand(self, lb)

def lb_add_health_check(self, lb, vip, **options):
return cmd.LbAddHealthCheckCommand(self, lb, vip, **options)

def lb_del_health_check(self, lb, hc_uuid, if_exists=False):
return cmd.LbDelHealthCheckCommand(self, lb, hc_uuid, if_exists)

def lb_add_ip_port_mapping(self, lb, endport_ip, port_name, source_ip):
return cmd.LbAddIpPortMappingСommand(self, lb, endport_ip,
port_name, source_ip)

def lb_del_ip_port_mapping(self, lb, endport_ip):
return cmd.LbDelIpPortMappingCommand(self, lb, endport_ip)

def health_check_set_options(self, hc_uuid, **options):
return cmd.HealthCheckSetOptionsCommand(self, hc_uuid, **options)

def health_check_get_options(self, hc_uuid):
return cmd.HealthCheckGetOptionsCommand(self, hc_uuid)

def lr_lb_add(self, router, lb, may_exist=False):
return cmd.LrLbAddCommand(self, router, lb, may_exist)

Expand Down
103 changes: 103 additions & 0 deletions ovsdbapp/tests/functional/schema/ovn_northbound/test_impl_idl.py
Expand Up @@ -1669,6 +1669,109 @@ def test_lb_list(self):
lbset = self.api.lb_list().execute(check_error=True)
self.assertTrue(lbs.issubset(lbset))

def _test_lb_get(self, col):
lb = self._lb_add(utils.get_rand_device_name(),
'192.0.0.1', ['10.0.0.1'])
val = getattr(lb, col)
found = self.api.lb_get(val).execute(check_error=True)
self.assertEqual(lb, found)

def test_lb_get_uuid(self):
self._test_lb_get('uuid')

def test_lb_get_name(self):
self._test_lb_get('name')

def _test_lb_add_del_health_check(self, col):
hc_options = {
'interval': '2',
'timeout': '10',
'success_count': '3',
'failure_count': '3',
}
hc_vip = '172.31.0.1'

lb = self._lb_add(utils.get_rand_device_name(),
'192.0.0.1', ['10.0.0.1'])
self.assertEqual(lb.health_check, [])
val = getattr(lb, col)
self.api.lb_add_health_check(val,
hc_vip,
**hc_options).execute(check_error=True)
self.assertEqual(len(lb.health_check), 1)
hc = self.api.lookup('Load_Balancer_Health_Check',
lb.health_check[0].uuid)
self.assertEqual(hc.vip, hc_vip)
self.assertEqual(hc.options, hc_options)

self.api.lb_del_health_check(val, hc.uuid).execute(check_error=True)
self.assertEqual(len(lb.health_check), 0)
self.assertNotIn(hc.uuid,
self.api.tables['Load_Balancer_Health_Check'].rows)

def test_lb_add_del_health_check_uuid(self):
self._test_lb_add_del_health_check('uuid')

def test_lb_add_del_health_check_name(self):
self._test_lb_add_del_health_check('name')

def test_lb_del_health_check_if_exists(self):
lb = self._lb_add(utils.get_rand_device_name(),
'192.0.0.1', ['10.0.0.1'])
self.api.lb_del_health_check(lb.name, uuid.uuid4(),
if_exists=True).execute(check_error=True)

def _test_lb_add_del_ip_port_mapping(self, col):
endpoint_ip = '172.31.0.4'
port_name = 'sw1-p1'
source_ip = '172.31.0.6'
lb = self._lb_add(utils.get_rand_device_name(),
'192.0.0.1', ['10.0.0.1'])
self.assertEqual(lb.ip_port_mappings, {})
val = getattr(lb, col)
self.api.lb_add_ip_port_mapping(val,
endpoint_ip,
port_name,
source_ip).execute(check_error=True)
self.assertEqual(lb.ip_port_mappings[endpoint_ip],
'%s:%s' % (port_name, source_ip))

self.api.lb_del_ip_port_mapping(val,
endpoint_ip).execute(check_error=True)
self.assertEqual(lb.ip_port_mappings, {})

def test_lb_add_del_ip_port_mapping_uuid(self):
self._test_lb_add_del_ip_port_mapping('uuid')

def test_lb_add_del_ip_port_mapping_name(self):
self._test_lb_add_del_ip_port_mapping('name')

def test_hc_get_set_options(self):
hc_options = {
'interval': '2',
'timeout': '10',
'success_count': '3',
'failure_count': '3',
}
lb = self._lb_add(utils.get_rand_device_name(),
'192.0.0.1', ['10.0.0.1'])
self.api.lb_add_health_check(lb.uuid,
'172.31.0.1',
**hc_options).execute(check_error=True)
hc = self.api.lookup('Load_Balancer_Health_Check',
lb.health_check[0].uuid)
options = self.api.health_check_get_options(
hc.uuid).execute(check_error=True)
self.assertEqual(hc_options, options)

options.update({
'interval': '5',
'new-option': 'option',
})
self.api.health_check_set_options(hc.uuid,
**options).execute(check_error=True)
self.assertEqual(hc.options, options)


class TestObLbOps(testscenarios.TestWithScenarios, OvnNorthboundTest):
scenarios = [
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/provide-lb-hc-api-8ff13ccaf75f1eee.yaml
@@ -0,0 +1,6 @@
---
features:
- |
Added functions and commands to add, delete, list and update records of
'Load_Balancer_Health_Check' table. Also added a method to get one load balancer
by name or uuid and methods to modify 'ip_port_mappings' column in the load balancer.

0 comments on commit f3c5da5

Please sign in to comment.