Merge "Move ctlplane network/subnet setup to python"

This commit is contained in:
Zuul 2018-02-05 20:19:20 +00:00 committed by Gerrit Code Review
commit 9f53f0819b
3 changed files with 181 additions and 76 deletions

View File

@ -37,81 +37,6 @@ if [ -e /usr/sbin/getenforce ]; then
fi
fi
UNDERCLOUD_IP=$(os-apply-config --key local-ip --type netaddress)
export UNDERCLOUD_IP
DHCP_START=$(os-apply-config --key neutron.dhcp_start --type netaddress)
DHCP_END=$(os-apply-config --key neutron.dhcp_end --type netaddress)
NETWORK_CIDR=$(os-apply-config --key neutron.network_cidr --type raw)
NETWORK_GATEWAY=$(os-apply-config --key neutron.network_gateway --type netaddress)
METADATA_SERVER=$UNDERCLOUD_IP
PHYSICAL_NETWORK=ctlplane
# DHCP_START contains a ":" then assume a IPv6 subnet
SUBNET_VERSION_STRING="--ip-version 4"
SUBNET_ROUTE_STRING="--host-route destination=169.254.169.254/32,nexthop=$METADATA_SERVER"
if [[ $DHCP_START =~ : ]] ; then
SUBNET_VERSION_STRING="--ip-version 6 --ipv6-address-mode dhcpv6-stateless --ipv6-ra-mode dhcpv6-stateless"
SUBNET_ROUTE_STRING=""
fi
net_create=1
ctlplane_id=$(neutron net-list -f csv -c id -c name --quote none | tail -n +2 | grep ctlplane | cut -d, -f 1)
subnet_ids=$(neutron subnet-list -f csv -c id --quote none | tail -n +2)
subnet_id=
for subnet_id in $subnet_ids; do
network_id=$(neutron subnet-show -f value -c network_id $subnet_id)
if [ "$network_id" = "$ctlplane_id" ]; then
break
fi
done
if [ -n "$subnet_id" ]; then
cidr=$(neutron subnet-show $subnet_id -f value -c cidr)
# If the cidr's are equal, we can get by with just a network update
if [ "$cidr" = "$NETWORK_CIDR" ]; then
net_create=0
neutron subnet-update $subnet_id \
--allocation-pool start=$DHCP_START,end=$DHCP_END \
--gateway $NETWORK_GATEWAY $SUBNET_ROUTE_STRING
else
echo "New cidr $NETWORK_CIDR does not equal old cidr $cidr"
echo "Will attempt to delete and recreate subnet $subnet_id"
fi
fi
if [ "$net_create" -eq "1" ]; then
# Delete the route, subnet and network to make sure it doesn't already exist
if neutron router-show ctlplane-router ; then
neutron router-interface-delete ctlplane-router ctlplane-subnet
neutron router-delete ctlplane-router
fi
if neutron subnet-list | grep start; then
neutron subnet-delete $(neutron subnet-list | grep start | awk '{print $2}')
fi
if neutron net-show ctlplane; then
neutron net-delete ctlplane
fi
neutron net-create ctlplane \
--provider:network_type flat \
--provider:physical_network ctlplane
neutron subnet-create --name ctlplane-subnet \
--allocation-pool start=$DHCP_START,end=$DHCP_END \
--gateway $NETWORK_GATEWAY \
$SUBNET_VERSION_STRING $SUBNET_ROUTE_STRING \
ctlplane $NETWORK_CIDR
# If ctlplane-subnet is IPv6 we need to start a router so the router advertisments are sent out
# for statless IP addressing to work.
if [[ $DHCP_START =~ : ]] ; then
neutron router-create ctlplane-router
neutron router-interface-add ctlplane-router ctlplane-subnet
fi
fi
# Disable nova quotas
openstack quota set --cores -1 --instances -1 --ram -1 $(openstack project show admin | awk '$2=="id" {print $4}')

View File

@ -773,6 +773,9 @@ class TestPostConfig(base.BaseTestCase):
@mock.patch('os_client_config.make_client')
@mock.patch('instack_undercloud.undercloud._migrate_to_convergence')
@mock.patch('instack_undercloud.undercloud._ensure_node_resource_classes')
@mock.patch(
'instack_undercloud.undercloud._config_neutron_segments_and_subnets')
@mock.patch('instack_undercloud.undercloud._ensure_neutron_network')
@mock.patch('instack_undercloud.undercloud._member_role_exists')
@mock.patch('instack_undercloud.undercloud._get_session')
@mock.patch('ironicclient.client.get_client', autospec=True)
@ -790,6 +793,8 @@ class TestPostConfig(base.BaseTestCase):
mock_copy_stackrc, mock_delete, mock_mistral_client,
mock_swift_client, mock_nova_client, mock_ir_client,
mock_get_session, mock_member_role_exists,
mock_ensure_neutron_network,
mock_config_neutron_segments_and_subnets,
mock_resource_classes, mock_migrate_to_convergence,
mock_make_client):
instack_env = {
@ -1284,6 +1289,57 @@ class TestPostConfig(base.BaseTestCase):
mock_cmce.assert_called_once_with(instack_env, mock_mistral)
mock_create.assert_called_once_with(mock_mistral, ['hut8'])
def _neutron_mocks(self):
mock_sdk = mock.MagicMock()
mock_sdk.network.create_network = mock.Mock()
mock_sdk.network.delete_segment = mock.Mock()
mock_sdk.network.create_subnet = mock.Mock()
mock_sdk.network.update_subnet = mock.Mock()
return mock_sdk
def test_network_create(self):
mock_sdk = self._neutron_mocks()
mock_sdk.network.networks.return_value = iter([])
segment_mock = mock.Mock()
mock_sdk.network.segments.return_value = iter([segment_mock])
undercloud._ensure_neutron_network(mock_sdk)
mock_sdk.network.create_network.assert_called_with(
name='ctlplane', provider_network_type='flat',
provider_physical_network='ctlplane')
def test_network_exists(self):
mock_sdk = self._neutron_mocks()
mock_sdk.network.networks.return_value = iter(['ctlplane'])
undercloud._ensure_neutron_network(mock_sdk)
mock_sdk.network.create_network.assert_not_called()
def test_subnet_create(self):
mock_sdk = self._neutron_mocks()
host_routes = [{'destination': '169.254.169.254/32',
'nexthop': '192.168.24.1'}]
allocation_pool = [{'start': '192.168.24.5', 'end': '192.168.24.24'}]
undercloud._neutron_subnet_create(mock_sdk, 'network_id',
'192.168.24.0/24', '192.168.24.1',
host_routes, allocation_pool,
'ctlplane-subnet')
mock_sdk.network.create_subnet.assert_called_with(
name='ctlplane-subnet', cidr='192.168.24.0/24',
gateway_ip='192.168.24.1', host_routes=host_routes, enable_dhcp=True,
ip_version='4', allocation_pools=allocation_pool,
network_id='network_id')
def test_subnet_update(self):
mock_sdk = self._neutron_mocks()
host_routes = [{'destination': '169.254.169.254/32',
'nexthop': '192.168.24.1'}]
allocation_pool = [{'start': '192.168.24.5', 'end': '192.168.24.24'}]
undercloud._neutron_subnet_update(mock_sdk, 'subnet_id',
'192.168.24.1', host_routes,
allocation_pool, 'ctlplane-subnet')
mock_sdk.network.update_subnet.assert_called_with(
'subnet_id', name='ctlplane-subnet', gateway_ip='192.168.24.1',
host_routes=host_routes, allocation_pools=allocation_pool)
class TestUpgradeFact(base.BaseTestCase):
@mock.patch('instack_undercloud.undercloud._run_command')

View File

@ -21,6 +21,7 @@ import glob
import hashlib
import json
import logging
import netaddr
import os
import platform
import re
@ -111,7 +112,9 @@ log can be found at %(log_file)s.
# We need 8 GB, leave a little room for variation in what 8 GB means on
# different platforms.
REQUIRED_MB = 7680
# Control plane network name
PHYSICAL_NETWORK = 'ctlplane'
CTLPLANE_SUBNET_NAME = 'ctlplane-subnet'
# When adding new options to the lists below, make sure to regenerate the
# sample config by running "tox -e genconfig" in the project root.
@ -1808,6 +1811,16 @@ def _post_config(instack_env, upgrade):
ironic = ir_client.get_client(1, session=sess,
os_ironic_api_version='1.21')
sdk = os_client_config.make_sdk(auth_url=auth_url,
project_name=project,
username=user,
password=password,
project_domain_name='Default',
user_domain_name='Default')
network = _ensure_neutron_network(sdk)
_config_neutron_segments_and_subnets(sdk, network.id)
_configure_ssh_keys(nova)
_ensure_ssh_selinux_permission()
_delete_default_flavors(nova)
@ -1848,6 +1861,117 @@ def _post_config(instack_env, upgrade):
_migrate_to_convergence(heat)
def _ensure_neutron_network(sdk):
try:
network = list(sdk.network.networks(name=PHYSICAL_NETWORK))
if not network:
network = sdk.network.create_network(
name=PHYSICAL_NETWORK, provider_network_type='flat',
provider_physical_network=PHYSICAL_NETWORK)
LOG.info("Network created %s", network)
else:
LOG.info("Not creating %s network, because it already exists.",
PHYSICAL_NETWORK)
network = network[0]
except Exception as e:
LOG.info("Network create/update failed %s", e)
raise
return network
def _neutron_subnet_create(sdk, network_id, cidr, gateway, host_routes,
allocation_pool, name):
try:
# DHCP_START contains a ":" then assume a IPv6 subnet
if ':' in allocation_pool[0]['start']:
host_routes = ''
subnet = sdk.network.create_subnet(
name=name,
cidr=cidr,
gateway_ip=gateway,
host_routes=host_routes,
enable_dhcp=True,
ip_version='6',
ipv6_address_mode='dhcpv6-stateless',
ipv6_ra_mode='dhcpv6-stateless',
allocation_pools=allocation_pool,
network_id=network_id)
else:
subnet = sdk.network.create_subnet(
name=name,
cidr=cidr,
gateway_ip=gateway,
host_routes=host_routes,
enable_dhcp=True,
ip_version='4',
allocation_pools=allocation_pool,
network_id=network_id)
LOG.info("Subnet created %s", subnet)
except Exception as e:
LOG.error("Create subnet %s failed: %s", name, e)
raise
return subnet
def _neutron_subnet_update(sdk, subnet_id, gateway, host_routes,
allocation_pool, name):
try:
# DHCP_START contains a ":" then assume a IPv6 subnet
if ':' in allocation_pool[0]['start']:
host_routes = ''
subnet = sdk.network.update_subnet(
subnet_id,
name=name,
gateway_ip=gateway,
host_routes=host_routes,
allocation_pools=allocation_pool)
LOG.info("Subnet updated %s", subnet)
except Exception as e:
LOG.error("Update subnet %s failed: %s", name, e)
raise
def _ensure_neutron_router(sdk, name, subnet_id):
try:
router = sdk.network.create_router(name=name, admin_state_up='true')
sdk.network.add_interface_to_router(router.id, subnet_id=subnet_id)
except Exception as e:
LOG.error("Create router for subnet %s failed: %s", name, e)
raise
def _get_subnet(sdk, cidr, network_id):
try:
subnet = list(sdk.network.subnets(cidr=cidr, network_id=network_id))
except Exception:
raise
return False if not subnet else subnet[0]
def _config_neutron_segments_and_subnets(sdk, ctlplane_id):
host_routes = [{'destination': '169.254.169.254/32',
'nexthop': str(netaddr.IPNetwork(CONF.local_ip).ip)}]
allocation_pool = [{'start': CONF.dhcp_start, 'end': CONF.dhcp_end}]
subnet = _get_subnet(sdk, CONF.network_cidr, ctlplane_id)
if subnet:
_neutron_subnet_update(sdk, subnet.id, CONF.network_gateway,
host_routes, allocation_pool,
CTLPLANE_SUBNET_NAME)
else:
subnet = _neutron_subnet_create(sdk, ctlplane_id, CONF.network_cidr,
CONF.network_gateway, host_routes,
allocation_pool, CTLPLANE_SUBNET_NAME)
# If the subnet is IPv6 we need to start a router so that router
# advertisments are sent out for stateless IP addressing to work.
if ':' in CONF.dhcp_start:
_ensure_neutron_router(sdk, CTLPLANE_SUBNET_NAME, subnet.id)
def _handle_upgrade_fact(upgrade=False):
"""Create an upgrade fact for use in puppet