blob: 4237d4f3c9626cf1d2da9d9ef2eda7e079adcd9d [file] [log] [blame]
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +01001# Copyright 2020 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from neutron_lib import constants as lib_constants
17from oslo_log import log
Slawek Kaplonski8cccfe02020-09-29 22:34:09 +020018from paramiko import ssh_exception as ssh_exc
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010019from tempest.common import utils as tempest_utils
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010020from tempest.lib.common.utils import data_utils
21from tempest.lib import decorators
22from tempest.lib import exceptions as lib_exc
23
24from neutron_tempest_plugin.common import ip
25from neutron_tempest_plugin.common import ssh
26from neutron_tempest_plugin.common import utils
27from neutron_tempest_plugin import config
28from neutron_tempest_plugin.scenario import base
29
30CONF = config.CONF
31
32LOG = log.getLogger(__name__)
33
34
35def turn_nic6_on(ssh, ipv6_port):
36 """Turns the IPv6 vNIC on
37
38 Required because guest images usually set only the first vNIC on boot.
39 Searches for the IPv6 vNIC's MAC and brings it up.
40
41 @param ssh: RemoteClient ssh instance to server
42 @param ipv6_port: port from IPv6 network attached to the server
43 """
44 ip_command = ip.IPCommand(ssh)
45 nic = ip_command.get_nic_name_by_mac(ipv6_port['mac_address'])
46
47 # NOTE(slaweq): on RHEL based OS ifcfg file for new interface is
48 # needed to make IPv6 working on it, so if
49 # /etc/sysconfig/network-scripts directory exists ifcfg-%(nic)s file
50 # should be added in it
51 if sysconfig_network_scripts_dir_exists(ssh):
52 try:
53 ssh.execute_script(
54 'echo -e "DEVICE=%(nic)s\\nNAME=%(nic)s\\nIPV6INIT=yes" | '
55 'tee /etc/sysconfig/network-scripts/ifcfg-%(nic)s; '
56 'nmcli connection reload' % {'nic': nic},
57 become_root=True)
58 ssh.execute_script('nmcli connection up %s' % nic,
59 become_root=True)
60 except lib_exc.SSHExecCommandFailed as e:
61 # NOTE(slaweq): Sometimes it can happen that this SSH command
62 # will fail because of some error from network manager in
63 # guest os.
64 # But even then doing ip link set up below is fine and
65 # IP address should be configured properly.
66 LOG.debug("Error during restarting %(nic)s interface on "
67 "instance. Error message: %(error)s",
68 {'nic': nic, 'error': e})
69 ip_command.set_link(nic, "up")
70
71
72def sysconfig_network_scripts_dir_exists(ssh):
73 return "False" not in ssh.execute_script(
74 'test -d /etc/sysconfig/network-scripts/ || echo "False"')
75
76
77class IPv6Test(base.BaseTempestTestCase):
78 credentials = ['primary', 'admin']
79
80 ipv6_ra_mode = 'slaac'
81 ipv6_address_mode = 'slaac'
82
83 @classmethod
84 @tempest_utils.requires_ext(extension="router", service="network")
85 def resource_setup(cls):
86 super(IPv6Test, cls).resource_setup()
yangjianfeng23e40c22020-11-22 08:42:18 +000087 cls.reserve_external_subnet_cidrs()
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010088 cls._setup_basic_resources()
89
90 @classmethod
91 def _setup_basic_resources(cls):
92 cls.network = cls.create_network()
93 cls.subnet = cls.create_subnet(cls.network)
94 cls.router = cls.create_router_by_client()
95 cls.create_router_interface(cls.router['id'], cls.subnet['id'])
96 cls.keypair = cls.create_keypair()
97 cls.secgroup = cls.create_security_group(
98 name=data_utils.rand_name('secgroup'))
99 cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
100 cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
101
102 def _test_ipv6_address_configured(self, ssh_client, vm, ipv6_port):
103 ipv6_address = ipv6_port['fixed_ips'][0]['ip_address']
104 ip_command = ip.IPCommand(ssh_client)
105
106 def guest_has_address(expected_address):
107 ip_addresses = [a.address for a in ip_command.list_addresses()]
108 for ip_address in ip_addresses:
109 if expected_address in ip_address:
110 return True
111 return False
112
Slawek Kaplonski8cccfe02020-09-29 22:34:09 +0200113 try:
114 # Set NIC with IPv6 to be UP and wait until IPv6 address will be
115 # configured on this NIC
116 turn_nic6_on(ssh_client, ipv6_port)
117 # And check if IPv6 address will be properly configured on this NIC
118 utils.wait_until_true(
119 lambda: guest_has_address(ipv6_address),
120 timeout=120,
121 exception=RuntimeError(
122 "Timed out waiting for IP address {!r} to be configured "
123 "in the VM {!r}.".format(ipv6_address, vm['id'])))
124 except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
125 LOG.debug(ssh_e)
126 self._log_console_output([vm])
127 self._log_local_network_status()
128 raise
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100129
130 def _test_ipv6_hotplug(self, ra_mode, address_mode):
131 ipv6_networks = [self.create_network() for _ in range(2)]
132 for net in ipv6_networks:
133 subnet = self.create_subnet(
134 network=net, ip_version=6,
135 ipv6_ra_mode=ra_mode, ipv6_address_mode=address_mode)
136 self.create_router_interface(self.router['id'], subnet['id'])
137
138 server_kwargs = {
139 'flavor_ref': CONF.compute.flavor_ref,
140 'image_ref': CONF.compute.image_ref,
141 'key_name': self.keypair['name'],
142 'networks': [
143 {'uuid': self.network['id']},
144 {'uuid': ipv6_networks[0]['id']}],
145 'security_groups': [{'name': self.secgroup['name']}],
146 }
147 vm = self.create_server(**server_kwargs)['server']
148 self.wait_for_server_active(vm)
Slawek Kaplonski2211eab2020-10-20 16:43:53 +0200149 self.wait_for_guest_os_ready(vm)
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100150 ipv4_port = self.client.list_ports(
151 network_id=self.network['id'],
152 device_id=vm['id'])['ports'][0]
153 fip = self.create_floatingip(port=ipv4_port)
154 ssh_client = ssh.Client(
155 fip['floating_ip_address'], CONF.validation.image_ssh_user,
156 pkey=self.keypair['private_key'])
157
158 ipv6_port = self.client.list_ports(
159 network_id=ipv6_networks[0]['id'],
160 device_id=vm['id'])['ports'][0]
161 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
162
163 # Now remove this port IPv6 port from the VM and attach new one
164 self.delete_interface(vm['id'], ipv6_port['id'])
165
166 # And plug VM to the second IPv6 network
167 ipv6_port = self.create_port(ipv6_networks[1])
168 self.create_interface(vm['id'], ipv6_port['id'])
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000169 ip.wait_for_interface_status(
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100170 self.os_primary.interfaces_client, vm['id'],
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000171 ipv6_port['id'], lib_constants.PORT_STATUS_ACTIVE,
172 ssh_client=ssh_client, mac_address=ipv6_port['mac_address'])
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100173 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
174
175 @decorators.idempotent_id('b13e5408-5250-4a42-8e46-6996ce613e91')
176 def test_ipv6_hotplug_slaac(self):
177 self._test_ipv6_hotplug("slaac", "slaac")
178
179 @decorators.idempotent_id('9aaedbc4-986d-42d5-9177-3e721728e7e0')
180 def test_ipv6_hotplug_dhcpv6stateless(self):
181 self._test_ipv6_hotplug("dhcpv6-stateless", "dhcpv6-stateless")