blob: 5d65a6122f3fc49703fdf21637e2661d32ab42f6 [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
18from tempest.common import utils as tempest_utils
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010019from tempest.lib.common.utils import data_utils
20from tempest.lib import decorators
21from tempest.lib import exceptions as lib_exc
ibumarskovbbd108c2021-03-30 11:58:25 +040022import testtools
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010023
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
ibumarskovbbd108c2021-03-30 11:58:25 +040084 def skip_checks(cls):
85 super(IPv6Test, cls).skip_checks()
86 if not CONF.network_feature_enabled.ipv6:
87 raise cls.skipException("IPv6 is not enabled")
88
89 @classmethod
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +010090 @tempest_utils.requires_ext(extension="router", service="network")
91 def resource_setup(cls):
92 super(IPv6Test, cls).resource_setup()
93 cls._setup_basic_resources()
94
95 @classmethod
96 def _setup_basic_resources(cls):
97 cls.network = cls.create_network()
98 cls.subnet = cls.create_subnet(cls.network)
99 cls.router = cls.create_router_by_client()
100 cls.create_router_interface(cls.router['id'], cls.subnet['id'])
101 cls.keypair = cls.create_keypair()
102 cls.secgroup = cls.create_security_group(
103 name=data_utils.rand_name('secgroup'))
104 cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
105 cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
106
107 def _test_ipv6_address_configured(self, ssh_client, vm, ipv6_port):
108 ipv6_address = ipv6_port['fixed_ips'][0]['ip_address']
109 ip_command = ip.IPCommand(ssh_client)
110
111 def guest_has_address(expected_address):
112 ip_addresses = [a.address for a in ip_command.list_addresses()]
113 for ip_address in ip_addresses:
114 if expected_address in ip_address:
115 return True
116 return False
117
118 # Set NIC with IPv6 to be UP and wait until IPv6 address will be
119 # configured on this NIC
120 turn_nic6_on(ssh_client, ipv6_port)
121 # And check if IPv6 address will be properly configured on this NIC
122 utils.wait_until_true(
123 lambda: guest_has_address(ipv6_address),
124 timeout=120,
125 exception=RuntimeError(
126 "Timed out waiting for IP address {!r} to be configured in "
127 "the VM {!r}.".format(ipv6_address, vm['id'])))
128
129 def _test_ipv6_hotplug(self, ra_mode, address_mode):
130 ipv6_networks = [self.create_network() for _ in range(2)]
131 for net in ipv6_networks:
132 subnet = self.create_subnet(
133 network=net, ip_version=6,
134 ipv6_ra_mode=ra_mode, ipv6_address_mode=address_mode)
135 self.create_router_interface(self.router['id'], subnet['id'])
136
137 server_kwargs = {
138 'flavor_ref': CONF.compute.flavor_ref,
139 'image_ref': CONF.compute.image_ref,
140 'key_name': self.keypair['name'],
141 'networks': [
142 {'uuid': self.network['id']},
143 {'uuid': ipv6_networks[0]['id']}],
144 'security_groups': [{'name': self.secgroup['name']}],
145 }
146 vm = self.create_server(**server_kwargs)['server']
147 self.wait_for_server_active(vm)
148 ipv4_port = self.client.list_ports(
149 network_id=self.network['id'],
150 device_id=vm['id'])['ports'][0]
151 fip = self.create_floatingip(port=ipv4_port)
152 ssh_client = ssh.Client(
153 fip['floating_ip_address'], CONF.validation.image_ssh_user,
154 pkey=self.keypair['private_key'])
155
156 ipv6_port = self.client.list_ports(
157 network_id=ipv6_networks[0]['id'],
158 device_id=vm['id'])['ports'][0]
159 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
160
161 # Now remove this port IPv6 port from the VM and attach new one
162 self.delete_interface(vm['id'], ipv6_port['id'])
163
164 # And plug VM to the second IPv6 network
165 ipv6_port = self.create_port(ipv6_networks[1])
166 self.create_interface(vm['id'], ipv6_port['id'])
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000167 ip.wait_for_interface_status(
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100168 self.os_primary.interfaces_client, vm['id'],
Rodolfo Alonso Hernandez0adf8a22020-06-11 11:28:25 +0000169 ipv6_port['id'], lib_constants.PORT_STATUS_ACTIVE,
170 ssh_client=ssh_client, mac_address=ipv6_port['mac_address'])
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100171 self._test_ipv6_address_configured(ssh_client, vm, ipv6_port)
172
ibumarskovbbd108c2021-03-30 11:58:25 +0400173 @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
174 "DHCPv6 attributes are not enabled.")
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100175 @decorators.idempotent_id('b13e5408-5250-4a42-8e46-6996ce613e91')
176 def test_ipv6_hotplug_slaac(self):
177 self._test_ipv6_hotplug("slaac", "slaac")
178
ibumarskovbbd108c2021-03-30 11:58:25 +0400179 @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
180 "DHCPv6 attributes are not enabled.")
Slawek Kaplonskia1e88c42020-03-03 03:00:48 +0100181 @decorators.idempotent_id('9aaedbc4-986d-42d5-9177-3e721728e7e0')
182 def test_ipv6_hotplug_dhcpv6stateless(self):
183 self._test_ipv6_hotplug("dhcpv6-stateless", "dhcpv6-stateless")