Browse Source

Check for subnets correctness

This patch is updating networking-ovn to check for correctness when
creating, updating or deleting subnets.

Change-Id: I619efda775471e51bf70a63b987abf719aae995f
Partial-Bug: #1605089
changes/29/530229/10
Lucas Alvares Gomes 4 years ago
parent
commit
82a7709332
  1. 1
      networking_ovn/common/constants.py
  2. 17
      networking_ovn/common/maintenance.py
  3. 44
      networking_ovn/common/ovn_client.py
  4. 2
      networking_ovn/common/utils.py
  5. 9
      networking_ovn/ml2/mech_driver.py
  6. 15
      networking_ovn/ovsdb/commands.py
  7. 21
      networking_ovn/tests/functional/test_ovn_db_resources.py
  8. 23
      networking_ovn/tests/functional/test_ovn_db_sync.py
  9. 47
      networking_ovn/tests/functional/test_revision_numbers.py
  10. 66
      networking_ovn/tests/unit/ml2/test_mech_driver.py

1
networking_ovn/common/constants.py

@ -101,3 +101,4 @@ TYPE_SECURITY_GROUP_RULES = 'security_group_rules'
TYPE_ROUTERS = 'routers'
TYPE_SECURITY_GROUPS = 'security_groups'
TYPE_FLOATINGIPS = 'floatingips'
TYPE_SUBNETS = 'subnets'

17
networking_ovn/common/maintenance.py

@ -266,6 +266,19 @@ class DBInconsistenciesPeriodics(object):
else:
self._ovn_client.delete_floatingip(row.resource_uuid)
def _fix_create_update_subnet(self, row):
# Get the lasted version of the port in Neutron DB
admin_context = n_context.get_admin_context()
sn_db_obj = self._ovn_client._plugin.get_subnet(
admin_context, row.resource_uuid)
n_db_obj = self._ovn_client._plugin.get_network(
admin_context, sn_db_obj['network_id'])
if row.revision_number == ovn_const.INITIAL_REV_NUM:
self._ovn_client.create_subnet(sn_db_obj, n_db_obj)
else:
self._ovn_client.update_subnet(sn_db_obj, n_db_obj)
@periodics.periodic(spacing=DB_CONSISTENCY_CHECK_INTERVAL,
run_immediately=True)
def check_for_inconsistencies(self):
@ -295,6 +308,8 @@ class DBInconsistenciesPeriodics(object):
self._fix_create_security_group(row)
elif row.resource_type == ovn_const.TYPE_FLOATINGIPS:
self._fix_create_update_floatingip(row)
elif row.resource_type == ovn_const.TYPE_SUBNETS:
self._fix_create_update_subnet(row)
except Exception:
LOG.exception('Failed to fix resource %(res_uuid)s '
'(type: %(res_type)s)',
@ -316,6 +331,8 @@ class DBInconsistenciesPeriodics(object):
self._fix_delete_security_group(row)
elif row.resource_type == ovn_const.TYPE_FLOATINGIPS:
self._fix_delete_floatingip(row)
elif row.resource_type == ovn_const.TYPE_SUBNETS:
self._ovn_client.delete_subnet(row.resource_uuid)
except Exception:
LOG.exception('Failed to fix deleted resource %(res_uuid)s '
'(type: %(res_type)s)',

44
networking_ovn/common/ovn_client.py

@ -1136,11 +1136,17 @@ class OVNClient(object):
ovn_dhcp_options = self._get_ovn_dhcp_options(subnet, network)
with self._nb_idl.transaction(check_error=True) as txn:
txn.add(self._nb_idl.add_dhcp_options(
subnet['id'], **ovn_dhcp_options))
rev_num = {ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(
utils.get_revision_number(subnet, ovn_const.TYPE_SUBNETS))}
ovn_dhcp_options['external_ids'].update(rev_num)
txn.add(self._nb_idl.add_dhcp_options(subnet['id'],
**ovn_dhcp_options))
def _get_ovn_dhcp_options(self, subnet, network, server_mac=None):
external_ids = {'subnet_id': subnet['id']}
external_ids = {
'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: str(utils.get_revision_number(
subnet, ovn_const.TYPE_SUBNETS))}
dhcp_options = {'cidr': subnet['cidr'], 'options': {},
'external_ids': external_ids}
@ -1239,9 +1245,9 @@ class OVNClient(object):
filters=filters)
ports = [p for p in all_ports if not utils.is_network_device_port(p)]
subnet_dhcp_options = self._get_ovn_dhcp_options(subnet, network)
dhcp_options = self._get_ovn_dhcp_options(subnet, network)
subnet_dhcp_cmd = self._nb_idl.add_dhcp_options(subnet['id'],
**subnet_dhcp_options)
**dhcp_options)
subnet_dhcp_option = txn.add(subnet_dhcp_cmd)
# Traverse ports to add port DHCP_Options rows
for port in ports:
@ -1252,7 +1258,7 @@ class OVNClient(object):
elif not lsp_dhcp_opts:
lsp_dhcp_options = subnet_dhcp_option
else:
port_dhcp_options = copy.deepcopy(subnet_dhcp_options)
port_dhcp_options = copy.deepcopy(dhcp_options)
port_dhcp_options['options'].update(lsp_dhcp_opts)
port_dhcp_options['external_ids'].update(
{'port_id': port['id']})
@ -1285,9 +1291,7 @@ class OVNClient(object):
original_options['cidr'] == new_options['cidr'] and
original_options['options'] == new_options['options']):
return
txn.add(self._nb_idl.add_dhcp_options(subnet['id'], **new_options))
dhcp_options = self._nb_idl.get_subnet_dhcp_options(
subnet['id'], with_ports=True)
for opt in dhcp_options['ports']:
@ -1306,24 +1310,32 @@ class OVNClient(object):
self.update_metadata_port(context, network['id'])
self._add_subnet_dhcp_options(subnet, network)
db_rev.bump_revision(subnet, ovn_const.TYPE_SUBNETS)
def update_subnet(self, subnet, original_subnet, network):
if not subnet['enable_dhcp'] and not original_subnet['enable_dhcp']:
return
def update_subnet(self, subnet, network):
ovn_subnet = self._nb_idl.get_subnet_dhcp_options(
subnet['id'])['subnet']
context = n_context.get_admin_context()
self.update_metadata_port(context, network['id'])
if subnet['enable_dhcp'] or ovn_subnet:
context = n_context.get_admin_context()
self.update_metadata_port(context, network['id'])
check_rev_cmd = self._nb_idl.check_revision_number(
subnet['id'], subnet, ovn_const.TYPE_SUBNETS)
with self._nb_idl.transaction(check_error=True) as txn:
if not original_subnet['enable_dhcp']:
txn.add(check_rev_cmd)
if subnet['enable_dhcp'] and not ovn_subnet:
self._enable_subnet_dhcp_options(subnet, network, txn)
elif not subnet['enable_dhcp']:
elif not subnet['enable_dhcp'] and ovn_subnet:
self._remove_subnet_dhcp_options(subnet['id'], txn)
else:
elif subnet['enable_dhcp'] and ovn_subnet:
self._update_subnet_dhcp_options(subnet, network, txn)
db_rev.bump_revision(subnet, ovn_const.TYPE_SUBNETS)
def delete_subnet(self, subnet_id):
with self._nb_idl.transaction(check_error=True) as txn:
self._remove_subnet_dhcp_options(subnet_id, txn)
db_rev.delete_revision(subnet_id)
def create_security_group(self, security_group):
with self._nb_idl.transaction(check_error=True) as txn:

2
networking_ovn/common/utils.py

@ -208,7 +208,7 @@ def get_revision_number(resource, resource_type):
constants.TYPE_SECURITY_GROUP_RULES,
constants.TYPE_ROUTERS,
constants.TYPE_SECURITY_GROUPS,
constants.TYPE_FLOATINGIPS):
constants.TYPE_FLOATINGIPS, constants.TYPE_SUBNETS):
return resource['revision_number']
else:
raise ovn_exc.UnknownResourceType(resource_type=resource_type)

9
networking_ovn/ml2/mech_driver.py

@ -350,13 +350,18 @@ class OVNMechanismDriver(api.MechanismDriver):
"""
self._ovn_client.delete_network(context.current['id'])
def create_subnet_precommit(self, context):
db_rev.create_initial_revision(
context.current['id'], ovn_const.TYPE_SUBNETS,
context._plugin_context.session)
def create_subnet_postcommit(self, context):
self._ovn_client.create_subnet(context.current,
context.network.current)
def update_subnet_postcommit(self, context):
self._ovn_client.update_subnet(context.current, context.original,
context.network.current)
self._ovn_client.update_subnet(
context.current, context.network.current)
def delete_subnet_postcommit(self, context):
self._ovn_client.delete_subnet(context.current['id'])

15
networking_ovn/ovsdb/commands.py

@ -23,6 +23,7 @@ RESOURCE_TYPE_MAP = {
ovn_const.TYPE_PORTS: 'Logical_Switch_Port',
ovn_const.TYPE_ROUTERS: 'Logical_Router',
ovn_const.TYPE_FLOATINGIPS: 'NAT',
ovn_const.TYPE_SUBNETS: 'DHCP_Options',
}
@ -1038,12 +1039,26 @@ class CheckRevisionNumberCommand(command.BaseCommand):
raise idlutils.RowNotFound(
table='NAT', col='external_ids', match=self.name)
def _get_subnet(self):
for dhcp in self.api._tables['DHCP_Options'].rows.values():
ext_ids = getattr(dhcp, 'external_ids', {})
# Ignore ports DHCP Options
if ext_ids.get('port_id'):
continue
if ext_ids.get('subnet_id') == self.name:
return dhcp
raise idlutils.RowNotFound(
table='DHCP_Options', col='external_ids', match=self.name)
def run_idl(self, txn):
try:
ovn_table = RESOURCE_TYPE_MAP[self.resource_type]
ovn_resource = None
if self.resource_type == ovn_const.TYPE_FLOATINGIPS:
ovn_resource = self._get_floatingip()
elif self.resource_type == ovn_const.TYPE_SUBNETS:
ovn_resource = self._get_subnet()
else:
ovn_resource = self.api.lookup(ovn_table, self.name)
except idlutils.RowNotFound:

21
networking_ovn/tests/functional/test_ovn_db_resources.py

@ -22,6 +22,7 @@ from oslo_config import cfg
from ovsdbapp.backend.ovs_idl import idlutils
from networking_ovn.common import config as ovn_config
from networking_ovn.common import constants as ovn_const
from networking_ovn.common import utils
from networking_ovn.tests.functional import base
@ -39,12 +40,22 @@ class TestNBDbResources(base.TestOVNFunctionalBase):
def tearDown(self):
super(TestNBDbResources, self).tearDown()
# FIXME(lucasagomes): Map the revision numbers properly instead
# of stripping them out. Currently, tests like test_dhcp_options()
# are quite complex making it difficult to map the exact the revision
# number that the DHCP Option will be at assertion time, we need to
# refactor it a little to make it easier for mapping these updates.
def _strip_revision_number(self, ext_ids):
ext_ids.pop(ovn_const.OVN_REV_NUM_EXT_ID_KEY, None)
return ext_ids
def _verify_dhcp_option_rows(self, expected_dhcp_options_rows):
expected_dhcp_options_rows = list(expected_dhcp_options_rows.values())
observed_dhcp_options_rows = []
for row in self.nb_api.tables['DHCP_Options'].rows.values():
ext_ids = self._strip_revision_number(row.external_ids)
observed_dhcp_options_rows.append({
'cidr': row.cidr, 'external_ids': row.external_ids,
'cidr': row.cidr, 'external_ids': ext_ids,
'options': row.options})
self.assertItemsEqual(expected_dhcp_options_rows,
@ -58,17 +69,21 @@ class TestNBDbResources(base.TestOVNFunctionalBase):
None)
if lsp.dhcpv4_options:
ext_ids = self._strip_revision_number(
lsp.dhcpv4_options[0].external_ids)
observed_lsp_dhcpv4_options = {
'cidr': lsp.dhcpv4_options[0].cidr,
'external_ids': lsp.dhcpv4_options[0].external_ids,
'external_ids': ext_ids,
'options': lsp.dhcpv4_options[0].options}
else:
observed_lsp_dhcpv4_options = {}
if lsp.dhcpv6_options:
ext_ids = self._strip_revision_number(
lsp.dhcpv6_options[0].external_ids)
observed_lsp_dhcpv6_options = {
'cidr': lsp.dhcpv6_options[0].cidr,
'external_ids': lsp.dhcpv6_options[0].external_ids,
'external_ids': ext_ids,
'options': lsp.dhcpv6_options[0].options}
else:
observed_lsp_dhcpv6_options = {}

23
networking_ovn/tests/functional/test_ovn_db_sync.py

@ -108,7 +108,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
n1_s3 = self.deserialize(self.fmt, res)
self.expected_dhcp_options_rows.append({
'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': n1_s1['subnet']['id']},
'external_ids': {'subnet_id': n1_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'classless_static_route':
'{169.254.169.254/32,10.0.0.2, 0.0.0.0/0,10.0.0.1}',
'server_id': '10.0.0.1',
@ -118,7 +119,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
'router': n1_s1['subnet']['gateway_ip']}})
self.expected_dhcp_options_rows.append({
'cidr': '2001:dba::/64',
'external_ids': {'subnet_id': n1_s2['subnet']['id']},
'external_ids': {'subnet_id': n1_s2['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'server_id': '01:02:03:04:05:06'}})
n1_s1_dhcp_options_uuid = (
@ -165,6 +167,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
self.expected_dhcp_options_rows.append({
'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': n1_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0',
'port_id': port['port']['id']},
'options': {
'classless_static_route':
@ -179,6 +182,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
self.expected_dhcp_options_rows.append({
'cidr': '2001:dba::/64',
'external_ids': {'subnet_id': n1_s2['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0',
'port_id': port['port']['id']},
'options': {'server_id': '01:02:03:04:05:06',
'domain_search': 'foo-domain'}})
@ -232,6 +236,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
self.expected_dhcp_options_rows.append({
'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': n1_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0',
'port_id': port['port']['id']},
'options': {
'classless_static_route':
@ -246,6 +251,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
self.expected_dhcp_options_rows.append({
'cidr': '2001:dba::/64',
'external_ids': {'subnet_id': n1_s2['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0',
'port_id': port['port']['id']},
'options': {'server_id': '01:02:03:04:05:06',
'domain_search': 'foo-domain'}})
@ -264,7 +270,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
n2_s2 = self.deserialize(self.fmt, res)
self.expected_dhcp_options_rows.append({
'cidr': '20.0.0.0/24',
'external_ids': {'subnet_id': n2_s1['subnet']['id']},
'external_ids': {'subnet_id': n2_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'classless_static_route':
'{169.254.169.254/32,20.0.0.2, 0.0.0.0/0,20.0.0.1}',
'server_id': '20.0.0.1',
@ -274,7 +281,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
'router': n2_s1['subnet']['gateway_ip']}})
self.expected_dhcp_options_rows.append({
'cidr': '2001:dbd::/64',
'external_ids': {'subnet_id': n2_s2['subnet']['id']},
'external_ids': {'subnet_id': n2_s2['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'server_id': '01:02:03:04:05:06'}})
for p in ['p1', 'p2']:
@ -286,6 +294,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
self.expected_dhcp_options_rows.append({
'cidr': '20.0.0.0/24',
'external_ids': {'subnet_id': n2_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0',
'port_id': port['port']['id']},
'options': {
'classless_static_route':
@ -569,7 +578,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
dhcp_mac_v6 = '01:02:03:04:05:06'
self.expected_dhcp_options_rows.append({
'cidr': '30.0.0.0/24',
'external_ids': {'subnet_id': n3_s1['subnet']['id']},
'external_ids': {'subnet_id': n3_s1['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'classless_static_route':
'{169.254.169.254/32,30.0.0.2, 0.0.0.0/0,30.0.0.1}',
'server_id': '30.0.0.1',
@ -579,7 +589,8 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
'router': n3_s1['subnet']['gateway_ip']}})
self.expected_dhcp_options_rows.append({
'cidr': '2001:dbc::/64',
'external_ids': {'subnet_id': n3_s2['subnet']['id']},
'external_ids': {'subnet_id': n3_s2['subnet']['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '0'},
'options': {'server_id': dhcp_mac_v6}})
fake_port_id1 = uuidutils.generate_uuid()
fake_port_id2 = uuidutils.generate_uuid()

47
networking_ovn/tests/functional/test_revision_numbers.py

@ -75,6 +75,29 @@ class TestRevisionNumbers(base.TestOVNFunctionalBase):
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY) == name):
return row
def _create_subnet(self, net_id, cidr, name='subnet1'):
data = {'subnet': {'name': name,
'tenant_id': self._tenant_id,
'network_id': net_id,
'cidr': cidr,
'ip_version': 4,
'enable_dhcp': True}}
req = self.new_create_request('subnets', data, self.fmt)
res = req.get_response(self.api)
return self.deserialize(self.fmt, res)['subnet']
def _update_subnet_name(self, subnet_id, new_name):
data = {'subnet': {'name': new_name}}
req = self.new_update_request('subnets', data, subnet_id, self.fmt)
res = req.get_response(self.api)
return self.deserialize(self.fmt, res)['subnet']
def _find_subnet_row_by_id(self, subnet_id):
for row in self.nb_api._tables['DHCP_Options'].rows.values():
if (row.external_ids.get('subnet_id') == subnet_id and
not row.external_ids.get('port_id')):
return row
def test_create_network(self):
name = 'net1'
neutron_net = self._create_network(name)
@ -143,5 +166,29 @@ class TestRevisionNumbers(base.TestOVNFunctionalBase):
# Assert it also matches with the newest returned by neutron API
self.assertEqual(str(updated_router['revision_number']), ovn_revision)
def test_create_subnet(self):
neutron_net = self._create_network('net1')
neutron_subnet = self._create_subnet(neutron_net['id'], '10.0.0.0/24')
ovn_subnet = self._find_subnet_row_by_id(neutron_subnet['id'])
ovn_revision = ovn_subnet.external_ids[
ovn_const.OVN_REV_NUM_EXT_ID_KEY]
self.assertEqual(str(0), ovn_revision)
# Assert it also matches with the newest returned by neutron API
self.assertEqual(str(neutron_subnet['revision_number']), ovn_revision)
def test_update_subnet(self):
neutron_net = self._create_network('net1')
neutron_subnet = self._create_subnet(neutron_net['id'], '10.0.0.0/24')
updated_subnet = self._update_subnet_name(
neutron_subnet['id'], 'newsubnet')
ovn_subnet = self._find_subnet_row_by_id(neutron_subnet['id'])
ovn_revision = ovn_subnet.external_ids[
ovn_const.OVN_REV_NUM_EXT_ID_KEY]
self.assertEqual(str(1), ovn_revision)
# Assert it also matches with the newest returned by neutron API
self.assertEqual(str(updated_subnet['revision_number']), ovn_revision)
# TODO(lucasagomes): Add a test for floating IPs here when we get
# the router stuff done.

66
networking_ovn/tests/unit/ml2/test_mech_driver.py

@ -90,6 +90,12 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
return_value=True
).start()
revision_plugin.RevisionPlugin()
p = mock.patch.object(ovn_utils, 'get_revision_number', return_value=1)
p.start()
self.addCleanup(p.stop)
p = mock.patch.object(db_rev, 'bump_revision')
p.start()
self.addCleanup(p.stop)
@mock.patch.object(db_rev, 'bump_revision')
def test__create_security_group(self, mock_bump):
@ -883,7 +889,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
def test_add_subnet_dhcp_options_in_ovn_with_given_ovn_dhcp_opts(self):
subnet = {'ip_version': const.IP_VERSION_4}
self._test_add_subnet_dhcp_options_in_ovn(
subnet, ovn_dhcp_opts={'foo': 'bar'}, call_get_dhcp_opts=False)
subnet, ovn_dhcp_opts={'foo': 'bar', 'external_ids': {}},
call_get_dhcp_opts=False)
def test_add_subnet_dhcp_options_in_ovn_with_slaac_v6_subnet(self):
subnet = {'ip_version': const.IP_VERSION_6,
@ -919,7 +926,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
subnet, network, txn)
# Check adding DHCP_Options rows
subnet_dhcp_options = {
'external_ids': {'subnet_id': subnet['id']},
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'cidr': subnet['cidr'], 'options': {
'router': subnet['gateway_ip'],
'server_id': subnet['gateway_ip'],
@ -928,6 +936,7 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
'mtu': str(1000)}}
ports_dhcp_options = [{
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1',
'port_id': 'port-id-2'},
'cidr': subnet['cidr'], 'options': {
'router': '10.0.0.33',
@ -936,6 +945,7 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
'lease_time': str(12 * 60 * 60),
'mtu': str(1000)}}, {
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1',
'port_id': 'port-id-3'},
'cidr': subnet['cidr'], 'options': {
'router': subnet['gateway_ip'],
@ -992,17 +1002,20 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
subnet, network, txn)
# Check adding DHCP_Options rows
subnet_dhcp_options = {
'external_ids': {'subnet_id': subnet['id']},
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'cidr': subnet['cidr'], 'options': {
'dhcpv6_stateless': 'true',
'server_id': '01:02:03:04:05:06'}}
ports_dhcp_options = [{
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1',
'port_id': 'port-id-2'},
'cidr': subnet['cidr'], 'options': {
'dhcpv6_stateless': 'true',
'server_id': '11:22:33:44:55:66'}}, {
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1',
'port_id': 'port-id-3'},
'cidr': subnet['cidr'], 'options': {
'dhcpv6_stateless': 'true',
@ -1080,7 +1093,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
self.mech_driver._ovn_client._update_subnet_dhcp_options(
subnet, network, mock.Mock())
new_options = {
'external_ids': {'subnet_id': subnet['id']},
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'cidr': subnet['cidr'], 'options': {
'router': subnet['gateway_ip'],
'server_id': subnet['gateway_ip'],
@ -1129,7 +1143,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
subnet, network, mock.Mock())
new_options = {
'external_ids': {'subnet_id': subnet['id']},
'external_ids': {'subnet_id': subnet['id'],
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'cidr': subnet['cidr'], 'options': {
'dhcpv6_stateless': 'true',
'dns_server': '{10::3}',
@ -1166,8 +1181,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
def test_update_subnet_postcommit_ovn_do_nothing(self):
context = fakes.FakeSubnetContext(
subnet={'enable_dhcp': False, 'ip_version': 4, 'network_id': 'id'},
original_subnet={'enable_dhcp': False, 'ip_version': 4},
subnet={'enable_dhcp': False, 'ip_version': 4, 'network_id': 'id',
'id': 'subnet_id'},
network={'id': 'id'})
with mock.patch.object(
self.mech_driver._ovn_client,
@ -1193,8 +1208,8 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
def test_update_subnet_postcommit_enable_dhcp(self):
context = fakes.FakeSubnetContext(
subnet={'enable_dhcp': True, 'ip_version': 4, 'network_id': 'id'},
original_subnet={'enable_dhcp': False, 'ip_version': 4},
subnet={'enable_dhcp': True, 'ip_version': 4, 'network_id': 'id',
'id': 'subnet_id'},
network={'id': 'id'})
with mock.patch.object(
self.mech_driver._ovn_client,
@ -1208,10 +1223,11 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
umd.assert_called_once_with(mock.ANY, 'id')
def test_update_subnet_postcommit_disable_dhcp(self):
self.mech_driver._nb_ovn.get_subnet_dhcp_options.return_value = {
'subnet': mock.sentinel.subnet, 'ports': []}
context = fakes.FakeSubnetContext(
subnet={'enable_dhcp': False, 'id': 'fake_id', 'ip_version': 4,
'network_id': 'id'},
original_subnet={'enable_dhcp': True, 'ip_version': 4},
network={'id': 'id'})
with mock.patch.object(
self.mech_driver._ovn_client,
@ -1224,9 +1240,11 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
umd.assert_called_once_with(mock.ANY, 'id')
def test_update_subnet_postcommit_update_dhcp(self):
self.mech_driver._nb_ovn.get_subnet_dhcp_options.return_value = {
'subnet': mock.sentinel.subnet, 'ports': []}
context = fakes.FakeSubnetContext(
subnet={'enable_dhcp': True, 'ip_version': 4, 'network_id': 'id'},
original_subnet={'enable_dhcp': True, 'ip_version': 4},
subnet={'enable_dhcp': True, 'ip_version': 4, 'network_id': 'id',
'id': 'subnet_id'},
network={'id': 'id'})
with mock.patch.object(
self.mech_driver._ovn_client,
@ -1514,7 +1532,9 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcp_options = {'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': 'foo-subnet'}}
'external_ids': {
'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}}
expected_dhcp_options['options'] = {
'server_id': subnet['gateway_ip'],
'server_mac': '01:02:03:04:05:06',
@ -1545,7 +1565,9 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcp_options = {'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': 'foo-subnet'},
'external_ids': {
'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'options': {}}
self._test_get_ovn_dhcp_options_helper(subnet, network,
@ -1563,7 +1585,9 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcp_options = {'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': 'foo-subnet'},
'external_ids': {
'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'},
'options': {}}
self._test_get_ovn_dhcp_options_helper(subnet, network,
@ -1577,8 +1601,10 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
'dns_nameservers': ['7.7.7.7', '8.8.8.8']}
network = {'id': 'network-id', 'mtu': 1400}
ext_ids = {'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}
expected_dhcp_options = {
'cidr': 'ae70::/24', 'external_ids': {'subnet_id': 'foo-subnet'},
'cidr': 'ae70::/24', 'external_ids': ext_ids,
'options': {'server_id': '01:02:03:04:05:06',
'dns_server': '{7.7.7.7, 8.8.8.8}'}}
@ -1598,8 +1624,10 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
'ipv6_address_mode': const.DHCPV6_STATELESS}
network = {'id': 'network-id', 'mtu': 1400}
ext_ids = {'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}
expected_dhcp_options = {
'cidr': 'ae70::/24', 'external_ids': {'subnet_id': 'foo-subnet'},
'cidr': 'ae70::/24', 'external_ids': ext_ids,
'options': {'server_id': '01:02:03:04:05:06',
'dns_server': '{7.7.7.7, 8.8.8.8}',
'dhcpv6_stateless': 'true'}}
@ -1622,7 +1650,9 @@ class TestOVNMechansimDriverDHCPOptions(OVNMechanismDriverTestCase):
network = {'id': 'network-id', 'mtu': 1400}
expected_dhcp_options = {'cidr': '10.0.0.0/24',
'external_ids': {'subnet_id': 'foo-subnet'}}
'external_ids': {
'subnet_id': 'foo-subnet',
ovn_const.OVN_REV_NUM_EXT_ID_KEY: '1'}}
expected_dhcp_options['options'] = {
'server_id': subnet['gateway_ip'],
'server_mac': '01:02:03:04:05:06',

Loading…
Cancel
Save