Browse Source

Fix IPv6 router on UC re-install

Running 'openstack undercloud install' a second
time failed with a ConflictException because a subnet
with a router port cannot have the gateway_ip updated.

Ensure that the router port is always deleted prior to
the subnet update and then add the router port again
after updating the subnet

Closes-Bug: #1955417
Change-Id: I0e075153e99876ddf613caecc92b4442e8b6ca03
(cherry picked from commit 62ded067d5)
changes/90/822790/1
Harald Jensås 5 months ago
parent
commit
31a431d351
  1. 73
      extraconfig/post_deploy/undercloud_ctlplane_network.py

73
extraconfig/post_deploy/undercloud_ctlplane_network.py

@ -175,16 +175,42 @@ def _neutron_segment_update(sdk, segment_id, name):
raise
def _ensure_neutron_router(sdk, name, subnet_id):
# If the router already exist, don't try to create it again.
if list(sdk.network.routers(name=name)):
return
def _ensure_neutron_router(sdk, subnet):
try:
router = sdk.network.find_router(name_or_id=subnet.name)
if router is None:
sdk.network.create_router(name=subnet.name,
admin_state_up='true')
except Exception:
print('ERROR: Create router for subnet %s failed.' % subnet.name)
raise
def _add_router_port(sdk, subnet):
try:
router = sdk.network.find_router(name_or_id=subnet.name)
sdk.network.add_interface_to_router(router.id, subnet_id=subnet.id)
except Exception:
print('ERROR: Add router port for subnet %s failed.' % subnet.name)
raise
def _remove_router_port(sdk, subnet):
try:
router = sdk.network.create_router(name=name, admin_state_up='true')
sdk.network.add_interface_to_router(router.id, subnet_id=subnet_id)
router = sdk.network.find_router(name_or_id=subnet.name)
if router is None:
return
router_port = next(sdk.network.ports(
network_id=subnet.network_id,
device_owner='network:router_interface'))
sdk.network.remove_interface_from_router(router.id, subnet.id,
router_port.id)
except StopIteration:
# There is no router port
pass
except Exception:
print('ERROR: Create router for subnet %s failed.' % name)
print('ERROR: Delete router %s failed.' % subnet.name)
raise
@ -224,11 +250,20 @@ def _local_neutron_segments_and_subnets(sdk, ctlplane_id, net_cidrs):
"""Create's and updates the ctlplane subnet on the segment that is local to
the underclud.
"""
s = CONF['subnets'][CONF['local_subnet']]
# If the subnet is IPv6 we need to start a router so that router
# advertisements are sent out for stateless IP addressing to work.
# NOTE(hjensas): Don't do this for routed networks. The router will
# use the address defined as gateway for the subnet, and in a
# deployment with routed networks this will conflict with the router
# in the infrastructure. The router in the infrastructure must be
# configured to send router advertisements.
enable_ipv6_router = (CONF['enable_routed_networks'] is False
and netaddr.IPNetwork(s['NetworkCidr']).version == 6)
name = CONF['local_subnet']
subnet = _get_subnet(sdk, s['NetworkCidr'], ctlplane_id)
segment = _get_segment(sdk, CONF['physical_network'], ctlplane_id)
if subnet:
if CONF['enable_routed_networks'] and subnet.segment_id is None:
# The subnet exists and does not have a segment association. Since
@ -237,6 +272,12 @@ def _local_neutron_segments_and_subnets(sdk, ctlplane_id, net_cidrs):
# networks subnet by associating the network segment_id with the
# subnet.
_neutron_add_subnet_segment_association(sdk, subnet.id, segment.id)
# The router interface must be removed prior to updating the subnet
# in case the gateway_ip of the subnet changed.
if enable_ipv6_router:
_remove_router_port(sdk, subnet)
_neutron_subnet_update(
sdk, subnet.id, s['NetworkCidr'], s['NetworkGateway'],
s['HostRoutes'], s.get('AllocationPools'), name,
@ -246,20 +287,16 @@ def _local_neutron_segments_and_subnets(sdk, ctlplane_id, net_cidrs):
segment_id = segment.id
else:
segment_id = None
subnet = _neutron_subnet_create(
sdk, ctlplane_id, s['NetworkCidr'], s['NetworkGateway'],
s['HostRoutes'], s.get('AllocationPools'), name, segment_id,
s['DnsNameServers'])
# If the subnet is IPv6 we need to start a router so that router
# advertisments are sent out for stateless IP addressing to work.
# NOTE(hjensas): Don't do this for routed networks. The router will
# use the address defined as gateway for the subnet, and in a
# deployment with routed networks this will conflict with the router
# in the infrastructure. The router in the infrastucture must be
# configured to send router advertisements.
if not CONF['enable_routed_networks']:
if netaddr.IPNetwork(s['NetworkCidr']).version == 6:
_ensure_neutron_router(sdk, name, subnet.id)
if enable_ipv6_router:
_ensure_neutron_router(sdk, subnet)
_add_router_port(sdk, subnet)
net_cidrs.append(s['NetworkCidr'])
return net_cidrs

Loading…
Cancel
Save