From dc93ae534cb6d323797a47d943400b13b2525462 Mon Sep 17 00:00:00 2001 From: Rodrigo Barbieri Date: Tue, 21 Nov 2017 11:00:45 -0200 Subject: [PATCH] Update manila plugin to support IPv6 This patch makes necessary changes to devstack manila plugin in order to be able to run IPv6 scenario tests. Part of the changes included the dependency of neutron-dynamic-routing plugin and the installation of quagga, so routes in devstack host can be created automatically for each router and private network created by tempest during the tests. Also, added a new config option "override_ip_for_nfs_access" for manila tempest plugin that overrides the access rules used for NFS scenario tests. This option can be set by exporting the environment variable "OVERRIDE_IP_FOR_NFS_ACCESS" with the intended value before running devstack. This change is enabled by a following change and tested alongside a change on manila-tempest-plugin project. Please note that we are temporarily disabling IPv6 functionality in Host-assisted Share Migration, as the Data Service is not able to handle IPv4 + IPv6 scenarios. Change-Id: I4ca727f92618998242af18908bbbda6bb5f86303 Needed-By: Id8b005cdd429d53a75624885fe7ca795746c3ede --- .zuul.yaml | 1 + contrib/ci/post_test_hook.sh | 42 +++++-- contrib/ci/pre_test_hook.sh | 10 ++ devstack/plugin.sh | 116 ++++++++++++++++++ devstack/settings | 3 + manila/share/driver.py | 8 +- manila/share/utils.py | 13 ++ manila/tests/share/test_share_utils.py | 65 ++++++++++ .../run.yaml | 4 +- 9 files changed, 252 insertions(+), 10 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index acbf02ec95..038c0f2a09 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -319,6 +319,7 @@ - openstack-infra/devstack-gate - openstack/manila - openstack/manila-tempest-plugin + - openstack/neutron-dynamic-routing - openstack/python-manilaclient - openstack/tempest diff --git a/contrib/ci/post_test_hook.sh b/contrib/ci/post_test_hook.sh index b7188c8fbf..ab11bf5138 100755 --- a/contrib/ci/post_test_hook.sh +++ b/contrib/ci/post_test_hook.sh @@ -78,6 +78,7 @@ RUN_MANILA_HOST_ASSISTED_MIGRATION_TESTS=${RUN_MANILA_HOST_ASSISTED_MIGRATION_TE RUN_MANILA_DRIVER_ASSISTED_MIGRATION_TESTS=${RUN_MANILA_DRIVER_ASSISTED_MIGRATION_TESTS:-False} RUN_MANILA_MOUNT_SNAPSHOT_TESTS=${RUN_MANILA_MOUNT_SNAPSHOT_TESTS:-False} RUN_MANILA_MIGRATION_WITH_PRESERVE_SNAPSHOTS_TESTS=${RUN_MANILA_MIGRATION_WITH_PRESERVE_SNAPSHOTS_TESTS:-False} +RUN_MANILA_IPV6_TESTS=${RUN_MANILA_IPV6_TESTS:-False} MANILA_CONF=${MANILA_CONF:-/etc/manila/manila.conf} @@ -316,18 +317,43 @@ export OS_USER_DOMAIN_NAME=$ADMIN_DOMAIN_NAME source $BASE/new/manila/contrib/ci/common.sh manila_wait_for_drivers_init $MANILA_CONF -# (aovchinnikov): extra rules are needed to allow instances talk to host. -sudo iptables -N manila-nfs -sudo iptables -I INPUT 1 -j manila-nfs + TCP_PORTS=(2049 111 32803 892 875 662) UDP_PORTS=(111 32769 892 875 662) -for port in ${TCP_PORTS[*]}; do - sudo iptables -A manila-nfs -m tcp -p tcp --dport $port -j ACCEPT -done -for port in ${UDP_PORTS[*]}; do - sudo iptables -A manila-nfs -m udp -p udp --dport $port -j ACCEPT +for ipcmd in iptables ip6tables; do + # (aovchinnikov): extra rules are needed to allow instances talk to host. + sudo $ipcmd -N manila-nfs + sudo $ipcmd -I INPUT 1 -j manila-nfs + for port in ${TCP_PORTS[*]}; do + sudo $ipcmd -A manila-nfs -m tcp -p tcp --dport $port -j ACCEPT + done + for port in ${UDP_PORTS[*]}; do + sudo $ipcmd -A manila-nfs -m udp -p udp --dport $port -j ACCEPT + done done +source $BASE/new/devstack/openrc admin admin +public_net_id=$(openstack network list --name $PUBLIC_NETWORK_NAME -f value -c ID ) +iniset $TEMPEST_CONFIG network public_network_id $public_net_id + +# Now that all plugins are loaded, setup BGP here +if [ $(trueorfalse False MANILA_SETUP_IPV6) == True ]; then + neutron bgp-speaker-create --ip-version 6 --local-as 100 bgpspeaker + neutron bgp-speaker-network-add bgpspeaker $PUBLIC_NETWORK_NAME + neutron bgp-peer-create --peer-ip ::1 --remote-as 200 bgppeer + neutron bgp-speaker-peer-add bgpspeaker bgppeer +fi + +# Set config to run IPv6 tests according to env var +iniset $TEMPEST_CONFIG share run_ipv6_tests $RUN_MANILA_IPV6_TESTS + +if ! [[ -z "$OVERRIDE_IP_FOR_NFS_ACCESS" ]]; then + # Set config to use specified IP as access rule on NFS scenario tests + # in order to workaround multiple NATs between the VMs and the storage + # controller + iniset $TEMPEST_CONFIG share override_ip_for_nfs_access $OVERRIDE_IP_FOR_NFS_ACCESS +fi + echo "Running tempest manila test suites" sudo -H -u $USER tox -eall -- $MANILA_TESTS --concurrency=$MANILA_TEMPEST_CONCURRENCY RETVAL=$? diff --git a/contrib/ci/pre_test_hook.sh b/contrib/ci/pre_test_hook.sh index 688b31dbb4..1bfd886f7b 100755 --- a/contrib/ci/pre_test_hook.sh +++ b/contrib/ci/pre_test_hook.sh @@ -174,6 +174,16 @@ echo "TEMPEST_USE_TEST_ACCOUNTS=True" >> $localconf echo "TEMPEST_ALLOW_TENANT_ISOLATION=False" >> $localconf echo "TEMPEST_CONCURRENCY=${MANILA_TEMPEST_CONCURRENCY:-8}" >> $localconf +MANILA_SETUP_IPV6=${MANILA_SETUP_IPV6:-False} +echo "MANILA_SETUP_IPV6=${MANILA_SETUP_IPV6}" >> $localconf +if [[ "$MANILA_SETUP_IPV6" == True ]]; then + # When setting up proper IPv6 networks, we should do it ourselves so we can + # use Neutron Dynamic Routing plugin with address scopes instead of the + # regular Neutron DevStack configuration. + echo "NEUTRON_CREATE_INITIAL_NETWORKS=False" >> $localconf + echo "IP_VERSION=4+6" >> $localconf +fi + if [[ "$DRIVER" == "generic"* ]]; then echo -e '[[post-config|${NOVA_CONF:-/etc/nova/nova.conf}]]\n[DEFAULT]\nquota_instances=30\n' >> $localconf echo -e '[[post-config|${NEUTRON_CONF:-/etc/neutron/neutron.conf}]]\n[DEFAULT]\nmax_fixed_ips_per_port=100\n' >> $localconf diff --git a/devstack/plugin.sh b/devstack/plugin.sh index d53f1259e4..3d17f1bb14 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -1,3 +1,5 @@ +#!/bin/bash + # Plugin file for enabling manila services # ---------------------------------------- @@ -938,6 +940,115 @@ function install_libraries { fi } +function setup_ipv6 { + + # save IPv6 default route to add back later after enabling forwarding + local default_route=$(ip -6 route | grep default | cut -d ' ' -f1,2,3,4,5) + + # make sure those system values are set + sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 + sudo sysctl -w net.ipv6.conf.all.accept_ra=2 + sudo sysctl -w net.ipv6.conf.all.forwarding=1 + + # Disable in-band as our communication is only internal + sudo ovs-vsctl set Bridge $PUBLIC_BRIDGE other_config:disable-in-band=true + + # Create address scopes and subnet pools + neutron address-scope-create --shared scope-v4 4 + neutron address-scope-create --shared scope-v6 6 + openstack subnet pool create $SUBNETPOOL_NAME_V4 --default-prefix-length $SUBNETPOOL_SIZE_V4 --pool-prefix $SUBNETPOOL_PREFIX_V4 --address-scope scope-v4 --default --share + openstack subnet pool create $SUBNETPOOL_NAME_V6 --default-prefix-length $SUBNETPOOL_SIZE_V6 --pool-prefix $SUBNETPOOL_PREFIX_V6 --address-scope scope-v6 --default --share + + # Create example private network and router + openstack router create $Q_ROUTER_NAME + openstack network create $PRIVATE_NETWORK_NAME + openstack subnet create --ip-version 6 --use-default-subnet-pool --ipv6-address-mode $IPV6_ADDRESS_MODE --ipv6-ra-mode $IPV6_RA_MODE --network $PRIVATE_NETWORK_NAME $IPV6_PRIVATE_SUBNET_NAME + openstack subnet create --ip-version 4 --use-default-subnet-pool --network $PRIVATE_NETWORK_NAME $PRIVATE_SUBNET_NAME + openstack router add subnet $Q_ROUTER_NAME $IPV6_PRIVATE_SUBNET_NAME + openstack router add subnet $Q_ROUTER_NAME $PRIVATE_SUBNET_NAME + + # Create public network + openstack network create $PUBLIC_NETWORK_NAME --external --default --provider-network-type flat --provider-physical-network $PUBLIC_PHYSICAL_NETWORK + local public_gateway_ipv6=$(openstack subnet create $IPV6_PUBLIC_SUBNET_NAME --ip-version 6 --network $PUBLIC_NETWORK_NAME --subnet-pool $SUBNETPOOL_NAME_V6 --no-dhcp -c gateway_ip -f value) + local public_gateway_ipv4=$(openstack subnet create $PUBLIC_SUBNET_NAME --ip-version 4 --network $PUBLIC_NETWORK_NAME --subnet-range $FLOATING_RANGE --no-dhcp -c gateway_ip -f value) + + # Set router to use public network + openstack router set --external-gateway $PUBLIC_NETWORK_NAME $Q_ROUTER_NAME + + # Configure interfaces due to NEUTRON_CREATE_INITIAL_NETWORKS=False + local ipv4_cidr_len=${FLOATING_RANGE#*/} + sudo ip -6 addr add "$public_gateway_ipv6"/$SUBNETPOOL_SIZE_V6 dev $PUBLIC_BRIDGE + sudo ip addr add $PUBLIC_NETWORK_GATEWAY/"$ipv4_cidr_len" dev $PUBLIC_BRIDGE + + # Enabling interface is needed due to NEUTRON_CREATE_INITIAL_NETWORKS=False + sudo ip link set $PUBLIC_BRIDGE up + + if [ "$SHARE_DRIVER" == "manila.share.drivers.lvm.LVMShareDriver" ]; then + for backend_name in ${MANILA_ENABLED_BACKENDS//,/ }; do + iniset $MANILA_CONF $backend_name lvm_share_export_ips $public_gateway_ipv4,$public_gateway_ipv6 + done + iniset $MANILA_CONF DEFAULT data_node_access_ip $public_gateway_ipv4 + fi + + # install Quagga for setting up the host routes dynamically + install_package quagga + + # set Quagga daemons + ( + echo "zebra=yes" + echo "bgpd=yes" + echo "ospfd=no" + echo "ospf6d=no" + echo "ripd=no" + echo "ripngd=no" + echo "isisd=no" + echo "babeld=no" + ) | sudo tee /etc/quagga/daemons > /dev/null + + # set Quagga zebra.conf + ( + echo "hostname dsvm" + echo "password openstack" + echo "log file /var/log/quagga/zebra.log" + ) | sudo tee /etc/quagga/zebra.conf > /dev/null + + # set Quagga bgpd.conf + ( + echo "log file /var/log/quagga/bgpd.log" + echo "bgp multiple-instance" + echo "router bgp 200" + echo " bgp router-id 1.2.3.4" + echo " neighbor ::1 remote-as 100" + echo " neighbor ::1 passive" + echo " address-family ipv6" + echo " neighbor ::1 activate" + echo "line vty" + echo "debug bgp events" + echo "debug bgp filters" + echo "debug bgp fsm" + echo "debug bgp keepalives" + echo "debug bgp updates" + ) | sudo tee /etc/quagga/bgpd.conf > /dev/null + + if is_ubuntu; then + sudo systemctl enable quagga + sudo systemctl restart quagga + else + # Disable SELinux rule that conflicts with Zebra + sudo setsebool -P zebra_write_config 1 + sudo systemctl enable zebra + sudo systemctl enable bgpd + sudo systemctl restart zebra + sudo systemctl restart bgpd + fi + + # add default IPv6 route back + if ! [[ -z $default_route ]]; then + sudo ip -6 route add $default_route + fi + +} + # Main dispatcher if [[ "$1" == "stack" && "$2" == "install" ]]; then echo_summary "Installing Manila Client" @@ -991,6 +1102,11 @@ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then echo_summary "Configure Samba server" configure_samba + echo_summary "Configuring IPv6" + if [ $(trueorfalse False MANILA_SETUP_IPV6) == True ]; then + setup_ipv6 + fi + echo_summary "Starting Manila API" start_manila_api diff --git a/devstack/settings b/devstack/settings index c9fd8cb4b2..d96e990704 100644 --- a/devstack/settings +++ b/devstack/settings @@ -199,6 +199,9 @@ else TEMPEST_PLUGINS=$MANILA_TEMPEST_PLUGIN_PATH fi +# Manila IPv6 Setup flag +MANILA_SETUP_IPV6=${MANILA_SETUP_IPV6:=False} + # Enable manila services # ---------------------- # We have to add Manila to enabled services for screen_it to work diff --git a/manila/share/driver.py b/manila/share/driver.py index 133bd38626..d101e6c35c 100644 --- a/manila/share/driver.py +++ b/manila/share/driver.py @@ -27,6 +27,7 @@ from oslo_log import log from manila import exception from manila.i18n import _ from manila import network +from manila.share import utils as share_utils from manila import utils LOG = log.getLogger(__name__) @@ -627,8 +628,13 @@ class ShareDriver(object): # NOTE(ganso): If drivers want to override the export_location IP, # they can do so using this configuration. This method can also be # overridden if necessary. + # NOTE(ganso): The data service needs to be improved to + # support IPv4 + IPv6. Until then we will support only IPv4. path = next((x['path'] for x in share_instance['export_locations'] - if x['is_admin_only']), None) + if (x['is_admin_only']) and + share_utils.is_proper_ipv4_export_location( + x['path'], + share_instance['share_proto'].lower())), None) if not path: path = share_instance['export_locations'][0]['path'] return path diff --git a/manila/share/utils.py b/manila/share/utils.py index 9b53e83f6a..5e9451d3b9 100644 --- a/manila/share/utils.py +++ b/manila/share/utils.py @@ -152,3 +152,16 @@ def _usage_from_share(share_ref, share_instance_ref, **extra_usage_info): def get_recent_db_migration_id(): return migration.version() + + +def is_proper_ipv4_export_location(export, protocol): + """Verifies if the export location is in proper IPv4 format.""" + export = export.replace('[', '').replace(']', '') + if protocol == 'nfs' and ':/' in export: + ip = export.split(':/')[0] + elif protocol == 'cifs' and export.startswith(r'\\'): + ip = export.split('\\')[2] + else: + # TODO(ganso): proper handling of other protocols is pending + ip = export.split(':')[0] if ':' in export else export.split('/')[0] + return utils.is_valid_ip_address(ip, 4) diff --git a/manila/tests/share/test_share_utils.py b/manila/tests/share/test_share_utils.py index 4238583f32..ed762318d6 100644 --- a/manila/tests/share/test_share_utils.py +++ b/manila/tests/share/test_share_utils.py @@ -16,6 +16,7 @@ """Tests For miscellaneous util methods used with share.""" +import ddt import mock from manila.common import constants @@ -23,6 +24,7 @@ from manila.share import utils as share_utils from manila import test +@ddt.ddt class ShareUtilsTestCase(test.TestCase): def test_extract_host_without_pool(self): host = 'Host@Backend' @@ -162,6 +164,69 @@ class ShareUtilsTestCase(test.TestCase): replica = share_utils.get_active_replica(replica_list) self.assertIsNone(replica) + @ddt.data({'exp': '172.24.5.1:/my_export_location', 'proto': 'nfs', + 'expected': True}, + {'exp': '\\\\172.24.5.1\\foo\\bar', 'proto': 'cifs', + 'expected': True}, + {'exp': 'fad0:88:133:/my_export_location', 'proto': 'nfs', + 'expected': False}, + {'exp': '\\\\fad0:88::133\\foo\\bar', 'proto': 'cifs', + 'expected': False}, + {'exp': 'fd01::1:/my_export_location', 'proto': 'nfs', + 'expected': False}, + {'exp': '\\\\[fd01::1]\\foo\\bar', 'proto': 'cifs', + 'expected': False}, + {'exp': '[fad0:88::133]:/my_export_location', 'proto': 'nfs', + 'expected': False}, + {'exp': '\\\\[fad0:88::133]\\foo\\bar', 'proto': 'cifs', + 'expected': False}, + {'exp': '[fd01::1]:/my_export_location', 'proto': 'nfs', + 'expected': False}, + {'exp': '\\\\fad0-88--133.ipv6-literal.net\\foo\\bar', + 'proto': 'cifs', 'expected': False}, + {'exp': '172.24.5.1:8080/my_export_location', 'proto': 'other', + 'expected': True}, + {'exp': '172.24.5.1:8080:/my_export_location', 'proto': 'other', + 'expected': True}, + {'exp': '172.24.5.1:/my_export_location', 'proto': 'other', + 'expected': True}, + {'exp': '172.24.5.1/my_export_location', 'proto': 'other', + 'expected': True}, + {'exp': '172.24.5.1/my_export_location', 'proto': 'nfs', + 'expected': True}, + {'exp': 'fd01::1:8080/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': 'fd01::1/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': 'fd01::1:8080:/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': 'fd01::1:/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': '555.555.555.555:/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': '555.555.555.555:/my_export_location', 'proto': 'nfs', + 'expected': False}, + {'exp': '555.555.555.555/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': '555.5.5.555:8080/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': '555.55.5.55:8080:/my_export_location', 'proto': 'other', + 'expected': False}, + {'exp': '[172.24.5.1]:/my_export_location', 'proto': 'nfs', + 'expected': True}, + {'exp': '172.24.5.1/my_export_location', 'proto': 'other', + 'expected': True}, + {'exp': '172.24.5.1\\foo\\bar', 'proto': 'cifs', + 'expected': False}, + {'exp': '\\172.24.5.1\\foo\\bar', 'proto': 'cifs', + 'expected': False}, + {'exp': '\\\\172.24.5.1\\foo\\bar', 'proto': 'other', + 'expected': False}) + @ddt.unpack + def test_is_proper_ipv4_export_location(self, exp, proto, expected): + result = share_utils.is_proper_ipv4_export_location(exp, proto) + self.assertEqual(expected, result) + class NotifyUsageTestCase(test.TestCase): @mock.patch('manila.share.utils._usage_from_share') diff --git a/playbooks/legacy/manila-tempest-minimal-dsvm-lvm-centos-7/run.yaml b/playbooks/legacy/manila-tempest-minimal-dsvm-lvm-centos-7/run.yaml index 926c79d9bf..cbb0767852 100644 --- a/playbooks/legacy/manila-tempest-minimal-dsvm-lvm-centos-7/run.yaml +++ b/playbooks/legacy/manila-tempest-minimal-dsvm-lvm-centos-7/run.yaml @@ -39,6 +39,7 @@ [[local|localrc]] SKIP_EPEL_INSTALL=True enable_plugin manila git://git.openstack.org/openstack/manila + enable_plugin neutron-dynamic-routing git://git.openstack.org/openstack/neutron-dynamic-routing EOF executable: /bin/bash @@ -52,6 +53,7 @@ export PYTHONUNBUFFERED=true export DEVSTACK_GATE_NEUTRON=1 export DEVSTACK_PROJECT_FROM_GIT="python-manilaclient" + # Basic services needed for minimal job OVERRIDE_ENABLED_SERVICES=key,mysql,rabbit,tempest if [ "lvm" == "lvm" ]; then @@ -71,7 +73,7 @@ # Keep localrc to be able to set some vars in pre_test_hook export KEEP_LOCALRC=1 - export PROJECTS="openstack/manila-tempest-plugin $PROJECTS" + export PROJECTS="openstack/manila-tempest-plugin openstack/neutron-dynamic-routing $PROJECTS" function pre_test_hook { # 'dhss' - acronym for 'Driver Handles Share Servers',