blob: ff3266d3d2fb0a21949aed10dee41d9bd711b8e6 [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
ibumarskovbbb96f42021-03-30 11:58:25 +040023import testtools
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010024
25from neutron_tempest_plugin.common import ip
26from neutron_tempest_plugin.common import ssh
27from neutron_tempest_plugin.common import utils
28from neutron_tempest_plugin import config
29from neutron_tempest_plugin.scenario import base
30
31CONF = config.CONF
32
33LOG = log.getLogger(__name__)
34
35
36def turn_nic6_on(ssh, ipv6_port):
37 """Turns the IPv6 vNIC on
38
39 Required because guest images usually set only the first vNIC on boot.
40 Searches for the IPv6 vNIC's MAC and brings it up.
41
42 @param ssh: RemoteClient ssh instance to server
43 @param ipv6_port: port from IPv6 network attached to the server
44 """
45 ip_command = ip.IPCommand(ssh)
46 nic = ip_command.get_nic_name_by_mac(ipv6_port['mac_address'])
47
48 # NOTE(slaweq): on RHEL based OS ifcfg file for new interface is
49 # needed to make IPv6 working on it, so if
50 # /etc/sysconfig/network-scripts directory exists ifcfg-%(nic)s file
51 # should be added in it
52 if sysconfig_network_scripts_dir_exists(ssh):
53 try:
54 ssh.execute_script(
55 'echo -e "DEVICE=%(nic)s\\nNAME=%(nic)s\\nIPV6INIT=yes" | '
56 'tee /etc/sysconfig/network-scripts/ifcfg-%(nic)s; '
57 'nmcli connection reload' % {'nic': nic},
58 become_root=True)
59 ssh.execute_script('nmcli connection up %s' % nic,
60 become_root=True)
61 except lib_exc.SSHExecCommandFailed as e:
62 # NOTE(slaweq): Sometimes it can happen that this SSH command
63 # will fail because of some error from network manager in
64 # guest os.
65 # But even then doing ip link set up below is fine and
66 # IP address should be configured properly.
67 LOG.debug("Error during restarting %(nic)s interface on "
68 "instance. Error message: %(error)s",
69 {'nic': nic, 'error': e})
70 ip_command.set_link(nic, "up")
71
72
73def sysconfig_network_scripts_dir_exists(ssh):
74 return "False" not in ssh.execute_script(
75 'test -d /etc/sysconfig/network-scripts/ || echo "False"')
76
77
78class IPv6Test(base.BaseTempestTestCase):
79 credentials = ['primary', 'admin']
80
81 ipv6_ra_mode = 'slaac'
82 ipv6_address_mode = 'slaac'
83
84 @classmethod
ibumarskovbbb96f42021-03-30 11:58:25 +040085 def skip_checks(cls):
86 super(IPv6Test, cls).skip_checks()
87 if not CONF.network_feature_enabled.ipv6:
88 raise cls.skipException("IPv6 is not enabled")
89
90 @classmethod
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010091 @tempest_utils.requires_ext(extension="router", service="network")
92 def resource_setup(cls):
93 super(IPv6Test, cls).resource_setup()
yangjianfeng23e40c22020-11-22 08:42:18 +000094 cls.reserve_external_subnet_cidrs()
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010095 cls._setup_basic_resources()
96
97 @classmethod
98 def _setup_basic_resources(cls):
99 cls.network = cls.create_network()
100 cls.subnet = cls.create_subnet(cls.network)
101 cls.router = cls.create_router_by_client()
102 cls.create_router_interface(cls.router['id'], cls.subnet['id'])
103 cls.keypair = cls.create_keypair()
104 cls.secgroup = cls.create_security_group(
105 name=data_utils.rand_name('secgroup'))
106 cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
107 cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
108
109 def _test_ipv6_address_configured(self, ssh_client, vm, ipv6_port):
110 ipv6_address = ipv6_port['fixed_ips'][0]['ip_address']
111 ip_command = ip.IPCommand(ssh_client)
112
113 def guest_has_address(expected_address):
114 ip_addresses = [a.address for a in ip_command.list_addresses()]
115 for ip_address in ip_addresses:
116 if expected_address in ip_address:
117 return True
118 return False
119
Slawek Kaplonski8cccfe02020-09-29 22:34:09 +0200120 try:
121 # Set NIC with IPv6 to be UP and wait until IPv6 address will be
122 # configured on this NIC
123 turn_nic6_on(ssh_client, ipv6_port)
124 # And check if IPv6 address will be properly configured on this NIC
125 utils.wait_until_true(
126 lambda: guest_has_address(ipv6_address),
127 timeout=120,
128 exception=RuntimeError(
129 "Timed out waiting for IP address {!r} to be configured "
130 "in the VM {!r}.".format(ipv6_address, vm['id'])))
131 except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e:
132 LOG.debug(ssh_e)
133 self._log_console_output([vm])
134 self._log_local_network_status()
135 raise
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100136
137 def _test_ipv6_hotplug(self, ra_mode, address_mode):
138 ipv6_networks = [self.create_network() for _ in range(2)]
139 for net in ipv6_networks:
140 subnet = self.create_subnet(
141 network=net, ip_version=6,
142 ipv6_ra_mode=ra_mode, ipv6_address_mode=address_mode)
143 self.create_router_interface(self.router['id'], subnet['id'])
144
145 server_kwargs = {
146 'flavor_ref': CONF.compute.flavor_ref,
147 'image_ref': CONF.compute.image_ref,
148 'key_name': self.keypair['name'],
149 'networks': [
150 {'uuid': self.network['id']},
151 {'uuid': ipv6_networks[0]['id']}],
152 'security_groups': [{'name': self.secgroup['name']}],
153 }
154 vm = self.create_server(**server_kwargs)['server']
155 self.wait_for_server_active(vm)
Slawek Kaplonski2211eab2020-10-20 16:43:53 +0200156 self.wait_for_guest_os_ready(vm)
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100157 ipv4_port = self.client.list_ports(
158 network_id=self.network['id'],
159 device_id=vm['id'])['ports'][0]
160 fip = self.create_floatingip(port=ipv4_port)
161 ssh_client = ssh.Client(
162 fip['floating_ip_address'], CONF.validation.image_ssh_user,
163 pkey=self.keypair['private_key'])
164
165 ipv6_port = self.client.list_ports(
166 network_id=ipv6_networks[0]['id'],
167 device_id=vm['id'])['ports'][0]
168 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
169
170 # Now remove this port IPv6 port from the VM and attach new one
171 self.delete_interface(vm['id'], ipv6_port['id'])
172
173 # And plug VM to the second IPv6 network
174 ipv6_port = self.create_port(ipv6_networks[1])
175 self.create_interface(vm['id'], ipv6_port['id'])
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000176 ip.wait_for_interface_status(
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100177 self.os_primary.interfaces_client, vm['id'],
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000178 ipv6_port['id'], lib_constants.PORT_STATUS_ACTIVE,
179 ssh_client=ssh_client, mac_address=ipv6_port['mac_address'])
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100180 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
181
ibumarskovbbb96f42021-03-30 11:58:25 +0400182 @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
183 "DHCPv6 attributes are not enabled.")
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100184 @decorators.idempotent_id('b13e5408-5250-4a42-8e46-6996ce613e91')
185 def test_ipv6_hotplug_slaac(self):
186 self._test_ipv6_hotplug("slaac", "slaac")
187
ibumarskovbbb96f42021-03-30 11:58:25 +0400188 @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
189 "DHCPv6 attributes are not enabled.")
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100190 @decorators.idempotent_id('9aaedbc4-986d-42d5-9177-3e721728e7e0')
191 def test_ipv6_hotplug_dhcpv6stateless(self):
192 self._test_ipv6_hotplug("dhcpv6-stateless", "dhcpv6-stateless")