[OVN] Use new distributed device_owner for OVN distributed services
OVN distributed services like Metadata and DHCP uses now DEVICE_OWNER_DHCP device_owner which isn't distributed by its nature. To fully use benefits of OVN Distributed ports (localports) [1] and to not overlap with Neutron logic created for not-distributed ports we should use new device_owner. In this change we need also to bump minimum required neutron-lib to 2.4.0. [1] https://www.ovn.org/support/dist-docs/ovn-nb.5.txt Change-Id: I0a69f1bddaa7030c7287216e62ec1ac6dd381475
This commit is contained in:
parent
da45bbbff4
commit
b2b40b6a8c
|
@ -51,7 +51,7 @@ msgpack-python==0.4.0
|
||||||
munch==2.1.0
|
munch==2.1.0
|
||||||
netaddr==0.7.18
|
netaddr==0.7.18
|
||||||
netifaces==0.10.4
|
netifaces==0.10.4
|
||||||
neutron-lib==2.3.0
|
neutron-lib==2.4.0
|
||||||
openstacksdk==0.31.2
|
openstacksdk==0.31.2
|
||||||
os-client-config==1.28.0
|
os-client-config==1.28.0
|
||||||
os-ken==0.3.0
|
os-ken==0.3.0
|
||||||
|
|
|
@ -75,4 +75,5 @@ IDPOOL_SELECT_SIZE = 100
|
||||||
# finds out that all existing IP Allocations are associated with ports
|
# finds out that all existing IP Allocations are associated with ports
|
||||||
# with these owners, it will allow subnet deletion to proceed with the
|
# with these owners, it will allow subnet deletion to proceed with the
|
||||||
# IP allocations being cleaned up by cascade.
|
# IP allocations being cleaned up by cascade.
|
||||||
AUTO_DELETE_PORT_OWNERS = [constants.DEVICE_OWNER_DHCP]
|
AUTO_DELETE_PORT_OWNERS = [constants.DEVICE_OWNER_DHCP,
|
||||||
|
constants.DEVICE_OWNER_DISTRIBUTED]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
dfe425060830
|
fd6107509ccd
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Copyright 2020 OpenStack Foundation
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
from neutron_lib import constants
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
"""ovn_distributed_device_owner
|
||||||
|
|
||||||
|
Revision ID: fd6107509ccd
|
||||||
|
Revises: 5c85685d616d
|
||||||
|
Create Date: 2020-06-01 11:16:58.312355
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'fd6107509ccd'
|
||||||
|
down_revision = 'dfe425060830'
|
||||||
|
|
||||||
|
PORTS_TABLE = 'ports'
|
||||||
|
OVN_METADATA_PREFIX = 'ovnmeta'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
update_device_owner_ovn_distributed_ports()
|
||||||
|
|
||||||
|
|
||||||
|
def update_device_owner_ovn_distributed_ports():
|
||||||
|
ports = sa.Table(PORTS_TABLE,
|
||||||
|
sa.MetaData(),
|
||||||
|
sa.Column('device_owner', sa.String(255)),
|
||||||
|
sa.Column('device_id', sa.String(255)))
|
||||||
|
|
||||||
|
session = sa.orm.Session(bind=op.get_bind())
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
session.execute(ports.update().values(
|
||||||
|
device_owner=constants.DEVICE_OWNER_DISTRIBUTED).where(
|
||||||
|
ports.c.device_owner == constants.DEVICE_OWNER_DHCP).where(
|
||||||
|
ports.c.device_id.like('{}%'.format(OVN_METADATA_PREFIX))))
|
||||||
|
session.commit()
|
|
@ -285,7 +285,8 @@ class AddressRequestFactory(object):
|
||||||
elif ip_dict.get('eui64_address'):
|
elif ip_dict.get('eui64_address'):
|
||||||
return AutomaticAddressRequest(prefix=ip_dict['subnet_cidr'],
|
return AutomaticAddressRequest(prefix=ip_dict['subnet_cidr'],
|
||||||
mac=ip_dict['mac'])
|
mac=ip_dict['mac'])
|
||||||
elif port['device_owner'] == constants.DEVICE_OWNER_DHCP:
|
elif (port['device_owner'] == constants.DEVICE_OWNER_DHCP or
|
||||||
|
port['device_owner'] == constants.DEVICE_OWNER_DISTRIBUTED):
|
||||||
# preserve previous behavior of DHCP ports choosing start of pool
|
# preserve previous behavior of DHCP ports choosing start of pool
|
||||||
return PreferNextAddressRequest()
|
return PreferNextAddressRequest()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -259,7 +259,11 @@ class OVNClient(object):
|
||||||
|
|
||||||
# Only adjust the OVN type if the port is not owned by Neutron
|
# Only adjust the OVN type if the port is not owned by Neutron
|
||||||
# DHCP agents.
|
# DHCP agents.
|
||||||
if (port['device_owner'] == const.DEVICE_OWNER_DHCP and
|
# TODO(mjozefcz): Remove const.DEVICE_OWNER_DHCP
|
||||||
|
# from get_ports in W-release.
|
||||||
|
if (port['device_owner'] in [
|
||||||
|
const.DEVICE_OWNER_DISTRIBUTED,
|
||||||
|
const.DEVICE_OWNER_DHCP] and
|
||||||
not utils.is_neutron_dhcp_agent_port(port)):
|
not utils.is_neutron_dhcp_agent_port(port)):
|
||||||
port_type = 'localport'
|
port_type = 'localport'
|
||||||
|
|
||||||
|
@ -2030,9 +2034,19 @@ class OVNClient(object):
|
||||||
if not ovn_conf.is_ovn_metadata_enabled():
|
if not ovn_conf.is_ovn_metadata_enabled():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO(mjozefcz): Remove const.DEVICE_OWNER_DHCP
|
||||||
|
# from get_ports in W-release.
|
||||||
ports = self._plugin.get_ports(context, filters=dict(
|
ports = self._plugin.get_ports(context, filters=dict(
|
||||||
network_id=[network_id], device_owner=[const.DEVICE_OWNER_DHCP]))
|
network_id=[network_id],
|
||||||
|
device_owner=[
|
||||||
|
const.DEVICE_OWNER_DHCP,
|
||||||
|
const.DEVICE_OWNER_DISTRIBUTED]))
|
||||||
|
# TODO(mjozefcz): Remove this compatibility code in W release.
|
||||||
|
# First look for const.DEVICE_OWNER_DISTRIBUTED and then for
|
||||||
|
# const.DEVICE_OWNER_DHCP.
|
||||||
|
for port in ports:
|
||||||
|
if port['device_owner'] == const.DEVICE_OWNER_DISTRIBUTED:
|
||||||
|
return port
|
||||||
# Metadata ports are DHCP ports not belonging to the Neutron
|
# Metadata ports are DHCP ports not belonging to the Neutron
|
||||||
# DHCP agents
|
# DHCP agents
|
||||||
for port in ports:
|
for port in ports:
|
||||||
|
@ -2054,7 +2068,7 @@ class OVNClient(object):
|
||||||
port = {'port':
|
port = {'port':
|
||||||
{'network_id': network['id'],
|
{'network_id': network['id'],
|
||||||
'tenant_id': network['project_id'],
|
'tenant_id': network['project_id'],
|
||||||
'device_owner': const.DEVICE_OWNER_DHCP,
|
'device_owner': const.DEVICE_OWNER_DISTRIBUTED,
|
||||||
'device_id': 'ovnmeta-%s' % network['id']}}
|
'device_id': 'ovnmeta-%s' % network['id']}}
|
||||||
# TODO(boden): rehome create_port into neutron-lib
|
# TODO(boden): rehome create_port into neutron-lib
|
||||||
p_utils.create_port(self._plugin, context, port)
|
p_utils.create_port(self._plugin, context, port)
|
||||||
|
|
|
@ -742,10 +742,14 @@ class OvnNbSynchronizer(OvnDbSynchronizer):
|
||||||
if not ovn_conf.is_ovn_metadata_enabled():
|
if not ovn_conf.is_ovn_metadata_enabled():
|
||||||
return
|
return
|
||||||
LOG.debug('OVN sync metadata ports started')
|
LOG.debug('OVN sync metadata ports started')
|
||||||
|
# TODO(mjozefcz): Remove constants.DEVICE_OWNER_DHCP
|
||||||
|
# from get_ports in W-release.
|
||||||
for net in self.core_plugin.get_networks(ctx):
|
for net in self.core_plugin.get_networks(ctx):
|
||||||
dhcp_ports = self.core_plugin.get_ports(ctx, filters=dict(
|
dhcp_ports = self.core_plugin.get_ports(ctx, filters=dict(
|
||||||
network_id=[net['id']],
|
network_id=[net['id']],
|
||||||
device_owner=[constants.DEVICE_OWNER_DHCP]))
|
device_owner=[
|
||||||
|
constants.DEVICE_OWNER_DISTRIBUTED,
|
||||||
|
constants.DEVICE_OWNER_DHCP]))
|
||||||
|
|
||||||
for port in dhcp_ports:
|
for port in dhcp_ports:
|
||||||
# Do not touch the Neutron DHCP agents ports
|
# Do not touch the Neutron DHCP agents ports
|
||||||
|
|
|
@ -879,7 +879,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
|
||||||
db_metadata_ports_ids = set()
|
db_metadata_ports_ids = set()
|
||||||
db_metadata_ports_nets = set()
|
db_metadata_ports_nets = set()
|
||||||
for port in db_ports['ports']:
|
for port in db_ports['ports']:
|
||||||
if (port['device_owner'] == constants.DEVICE_OWNER_DHCP and
|
if (port['device_owner'] == constants.DEVICE_OWNER_DISTRIBUTED and
|
||||||
port['device_id'].startswith('ovnmeta')):
|
port['device_id'].startswith('ovnmeta')):
|
||||||
db_metadata_ports_ids.add(port['id'])
|
db_metadata_ports_ids.add(port['id'])
|
||||||
db_metadata_ports_nets.add(port['network_id'])
|
db_metadata_ports_nets.add(port['network_id'])
|
||||||
|
@ -1341,7 +1341,7 @@ class TestOvnNbSync(base.TestOVNFunctionalBase):
|
||||||
db_ports = self._list('ports')
|
db_ports = self._list('ports')
|
||||||
db_metadata_ports = [port for port in db_ports['ports'] if
|
db_metadata_ports = [port for port in db_ports['ports'] if
|
||||||
port['device_owner'] ==
|
port['device_owner'] ==
|
||||||
constants.DEVICE_OWNER_DHCP and
|
constants.DEVICE_OWNER_DISTRIBUTED and
|
||||||
port['device_id'].startswith('ovnmeta')]
|
port['device_id'].startswith('ovnmeta')]
|
||||||
lswitches = {}
|
lswitches = {}
|
||||||
ports_to_delete = len(db_metadata_ports) / 2
|
ports_to_delete = len(db_metadata_ports) / 2
|
||||||
|
|
|
@ -317,6 +317,13 @@ class TestAddressRequestFactory(base.BaseTestCase):
|
||||||
ipam_req.AddressRequestFactory.get_request(None, port, ip),
|
ipam_req.AddressRequestFactory.get_request(None, port, ip),
|
||||||
ipam_req.PreferNextAddressRequest)
|
ipam_req.PreferNextAddressRequest)
|
||||||
|
|
||||||
|
def test_prefernext_address_request_on_distributed_port(self):
|
||||||
|
ip = {}
|
||||||
|
port = {'device_owner': constants.DEVICE_OWNER_DISTRIBUTED}
|
||||||
|
self.assertIsInstance(
|
||||||
|
ipam_req.AddressRequestFactory.get_request(None, port, ip),
|
||||||
|
ipam_req.PreferNextAddressRequest)
|
||||||
|
|
||||||
|
|
||||||
class TestSubnetRequestFactory(IpamSubnetRequestTestCase):
|
class TestSubnetRequestFactory(IpamSubnetRequestTestCase):
|
||||||
|
|
||||||
|
|
|
@ -2906,16 +2906,21 @@ class TestOVNMechanismDriverMetadataPort(test_plugin.Ml2PluginV2TestCase):
|
||||||
p.start()
|
p.start()
|
||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
|
|
||||||
def _create_fake_dhcp_port(self, device_id):
|
def _create_fake_dhcp_port(self, device_id, neutron_port=False):
|
||||||
return {'network_id': 'fake', 'device_owner': const.DEVICE_OWNER_DHCP,
|
port = {'network_id': 'fake',
|
||||||
|
'device_owner': const.DEVICE_OWNER_DISTRIBUTED,
|
||||||
'device_id': device_id}
|
'device_id': device_id}
|
||||||
|
if neutron_port:
|
||||||
|
port['device_owner'] = const.DEVICE_OWNER_DHCP
|
||||||
|
return port
|
||||||
|
|
||||||
@mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2, 'get_ports')
|
@mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2, 'get_ports')
|
||||||
def test__find_metadata_port(self, mock_get_ports):
|
def test__find_metadata_port(self, mock_get_ports):
|
||||||
ports = [
|
ports = [
|
||||||
self._create_fake_dhcp_port('dhcp-0'),
|
self._create_fake_dhcp_port('dhcp-0', neutron_port=True),
|
||||||
self._create_fake_dhcp_port('dhcp-1'),
|
self._create_fake_dhcp_port('dhcp-1', neutron_port=True),
|
||||||
self._create_fake_dhcp_port(const.DEVICE_ID_RESERVED_DHCP_PORT),
|
self._create_fake_dhcp_port(const.DEVICE_ID_RESERVED_DHCP_PORT,
|
||||||
|
neutron_port=True),
|
||||||
self._create_fake_dhcp_port('ovnmeta-0')]
|
self._create_fake_dhcp_port('ovnmeta-0')]
|
||||||
mock_get_ports.return_value = ports
|
mock_get_ports.return_value = ports
|
||||||
|
|
||||||
|
@ -2923,6 +2928,20 @@ class TestOVNMechanismDriverMetadataPort(test_plugin.Ml2PluginV2TestCase):
|
||||||
self.ctx, 'fake-net-id')
|
self.ctx, 'fake-net-id')
|
||||||
self.assertEqual('ovnmeta-0', md_port['device_id'])
|
self.assertEqual('ovnmeta-0', md_port['device_id'])
|
||||||
|
|
||||||
|
@mock.patch.object(db_base_plugin_v2.NeutronDbPluginV2, 'get_ports')
|
||||||
|
def test__find_metadata_port_compat(self, mock_get_ports):
|
||||||
|
ports = [
|
||||||
|
self._create_fake_dhcp_port('dhcp-0', neutron_port=True),
|
||||||
|
self._create_fake_dhcp_port('dhcp-1', neutron_port=True),
|
||||||
|
self._create_fake_dhcp_port(const.DEVICE_ID_RESERVED_DHCP_PORT,
|
||||||
|
neutron_port=True),
|
||||||
|
self._create_fake_dhcp_port('ovnmeta-0', neutron_port=True)]
|
||||||
|
mock_get_ports.return_value = ports
|
||||||
|
|
||||||
|
md_port = self.mech_driver._ovn_client._find_metadata_port(
|
||||||
|
self.ctx, 'fake-net-id')
|
||||||
|
self.assertEqual('ovnmeta-0', md_port['device_id'])
|
||||||
|
|
||||||
def test_metadata_port_on_network_create(self):
|
def test_metadata_port_on_network_create(self):
|
||||||
"""Check metadata port create.
|
"""Check metadata port create.
|
||||||
|
|
||||||
|
@ -2958,7 +2977,7 @@ class TestOVNMechanismDriverMetadataPort(test_plugin.Ml2PluginV2TestCase):
|
||||||
# Create a network:dhcp owner port just as how Neutron DHCP
|
# Create a network:dhcp owner port just as how Neutron DHCP
|
||||||
# agent would do.
|
# agent would do.
|
||||||
with self.port(subnet=subnet1,
|
with self.port(subnet=subnet1,
|
||||||
device_owner=const.DEVICE_OWNER_DHCP,
|
device_owner=const.DEVICE_OWNER_DISTRIBUTED,
|
||||||
device_id='dhcpxxxx',
|
device_id='dhcpxxxx',
|
||||||
set_context=True, tenant_id='test'):
|
set_context=True, tenant_id='test'):
|
||||||
with self.subnet(network=net1, cidr='20.0.0.0/24'):
|
with self.subnet(network=net1, cidr='20.0.0.0/24'):
|
||||||
|
|
|
@ -16,7 +16,7 @@ Jinja2>=2.10 # BSD License (3 clause)
|
||||||
keystonemiddleware>=4.17.0 # Apache-2.0
|
keystonemiddleware>=4.17.0 # Apache-2.0
|
||||||
netaddr>=0.7.18 # BSD
|
netaddr>=0.7.18 # BSD
|
||||||
netifaces>=0.10.4 # MIT
|
netifaces>=0.10.4 # MIT
|
||||||
neutron-lib>=2.3.0 # Apache-2.0
|
neutron-lib>=2.4.0 # Apache-2.0
|
||||||
python-neutronclient>=6.7.0 # Apache-2.0
|
python-neutronclient>=6.7.0 # Apache-2.0
|
||||||
tenacity>=4.4.0 # Apache-2.0
|
tenacity>=4.4.0 # Apache-2.0
|
||||||
SQLAlchemy>=1.2.0 # MIT
|
SQLAlchemy>=1.2.0 # MIT
|
||||||
|
|
Loading…
Reference in New Issue