blob: cbe41221516335a5396c2c09fcf233d6c6f7cd86 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Gavin Brebner0f465a32013-03-14 13:26:09 +00002# Copyright 2013 Hewlett-Packard Development Company, L.P.
Maru Newby81f07a02012-09-05 20:21:19 -07003# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
Yair Fried2d2f3fe2014-02-24 16:19:20 +020016import collections
Yair Fried3097dc12014-01-26 08:46:43 +020017import re
Matthew Treinish96e9e882014-06-09 18:37:19 -040018
Doug Hellmann583ce2c2015-03-11 14:55:46 +000019from oslo_log import log as logging
Adam Gandelman7186f7a2014-07-23 09:28:56 -040020import testtools
Yair Fried3097dc12014-01-26 08:46:43 +020021
Andrea Frittolicd368412017-08-14 21:37:56 +010022from tempest.common import utils
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +000023from tempest.common import waiters
Matthew Treinishcb569942013-08-09 16:33:44 -040024from tempest import config
Jordan Pittier9e227c52016-02-09 14:35:18 +010025from tempest.lib.common.utils import test_utils
Sean Dague17487fb2016-08-08 10:44:20 -040026from tempest.lib import decorators
guo yunxianebb15f22016-11-01 21:03:35 +080027from tempest.lib import exceptions
Sean Dague6dbc6da2013-05-08 17:49:46 -040028from tempest.scenario import manager
Maru Newby81f07a02012-09-05 20:21:19 -070029
Sean Dague86bd8422013-12-20 09:56:44 -050030CONF = config.CONF
Matthew Treinish2b59f842013-09-09 20:32:51 +000031LOG = logging.getLogger(__name__)
32
Yair Fried2d2f3fe2014-02-24 16:19:20 +020033Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
34 ['floating_ip', 'server'])
35
Maru Newby81f07a02012-09-05 20:21:19 -070036
Andrea Frittoli4971fc82014-09-25 10:22:20 +010037class TestNetworkBasicOps(manager.NetworkScenarioTest):
Maru Newby81f07a02012-09-05 20:21:19 -070038
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +000039 """The test suite of network basic operations
40
Maru Newby81f07a02012-09-05 20:21:19 -070041 This smoke test suite assumes that Nova has been configured to
Mark McClainf2982e82013-07-06 17:48:03 -040042 boot VM's with Neutron-managed networking, and attempts to
Maru Newby81f07a02012-09-05 20:21:19 -070043 verify network connectivity as follows:
44
Maru Newby81f07a02012-09-05 20:21:19 -070045 There are presumed to be two types of networks: tenant and
46 public. A tenant network may or may not be reachable from the
47 Tempest host. A public network is assumed to be reachable from
48 the Tempest host, and it should be possible to associate a public
49 ('floating') IP address with a tenant ('fixed') IP address to
Chang Bo Guocc1623c2013-09-13 20:11:27 -070050 facilitate external connectivity to a potentially unroutable
Maru Newby81f07a02012-09-05 20:21:19 -070051 tenant IP address.
52
53 This test suite can be configured to test network connectivity to
54 a VM via a tenant network, a public network, or both. If both
55 networking types are to be evaluated, tests that need to be
56 executed remotely on the VM (via ssh) will only be run against
57 one of the networks (to minimize test execution time).
58
59 Determine which types of networks to test as follows:
60
61 * Configure tenant network checks (via the
Sean Dagueed6e5862016-04-04 10:49:13 -040062 'project_networks_reachable' key) if the Tempest host should
Maru Newby81f07a02012-09-05 20:21:19 -070063 have direct connectivity to tenant networks. This is likely to
64 be the case if Tempest is running on the same host as a
65 single-node devstack installation with IP namespaces disabled.
66
67 * Configure checks for a public network if a public network has
68 been configured prior to the test suite being run and if the
69 Tempest host should have connectivity to that public network.
70 Checking connectivity for a public network requires that a
71 value be provided for 'public_network_id'. A value can
72 optionally be provided for 'public_router_id' if tenants will
73 use a shared router to access a public network (as is likely to
74 be the case when IP namespaces are not enabled). If a value is
75 not provided for 'public_router_id', a router will be created
76 for each tenant and use the network identified by
77 'public_network_id' as its gateway.
78
79 """
80
81 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000082 def skip_checks(cls):
83 super(TestNetworkBasicOps, cls).skip_checks()
Federico Ressi2d6bcaa2018-04-11 12:37:36 +020084 if not (CONF.network.project_networks_reachable or
85 CONF.network.public_network_id):
Sean Dagueed6e5862016-04-04 10:49:13 -040086 msg = ('Either project_networks_reachable must be "true", or '
Maru Newby81f07a02012-09-05 20:21:19 -070087 'public_network_id must be defined.')
ivan-zhu1feeb382013-01-24 10:14:39 +080088 raise cls.skipException(msg)
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090089 for ext in ['router', 'security-group']:
Andrea Frittolicd368412017-08-14 21:37:56 +010090 if not utils.is_extension_enabled(ext, 'network'):
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090091 msg = "%s extension not enabled." % ext
92 raise cls.skipException(msg)
Matthew Treinish3312de32017-05-19 12:08:17 -040093 if not CONF.network_feature_enabled.floating_ips:
94 raise cls.skipException("Floating ips are not available")
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000095
96 @classmethod
97 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +090098 # Create no network resources for these tests.
99 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000100 super(TestNetworkBasicOps, cls).setup_credentials()
Maru Newby81f07a02012-09-05 20:21:19 -0700101
Yair Frieded8392f2014-01-15 17:21:35 +0200102 def setUp(self):
103 super(TestNetworkBasicOps, self).setUp()
Yair Fried1fc32a12014-08-04 09:11:30 +0300104 self.keypairs = {}
105 self.servers = []
David Shrewsbury9bac3662014-08-07 15:07:01 -0400106
Yair Fried413bf2d2014-11-19 17:07:11 +0200107 def _setup_network_and_servers(self, **kwargs):
Matt Riedemann17940732015-03-13 14:18:19 +0000108 boot_with_port = kwargs.pop('boot_with_port', False)
Ghanshyam Mann071d1542021-03-24 19:10:47 -0500109 self.network, self.subnet, self.router = (
110 self.setup_network_subnet_with_router(**kwargs))
David Shrewsbury9bac3662014-08-07 15:07:01 -0400111 self.check_networks()
112
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000113 self.ports = []
zhufl7a8f29d2017-02-17 10:16:45 +0800114 port_id = None
Jordan Pittierf72a1dc2015-08-04 12:50:33 +0000115 if boot_with_port:
Matt Riedemann17940732015-03-13 14:18:19 +0000116 # create a port on the network and boot with that
zhufl1e446b52017-10-16 16:54:57 +0800117 port_id = self.create_port(self.network['id'])['id']
zhufl7a8f29d2017-02-17 10:16:45 +0800118 self.ports.append({'port': port_id})
Matt Riedemann17940732015-03-13 14:18:19 +0000119
zhufl7a8f29d2017-02-17 10:16:45 +0800120 server = self._create_server(self.network, port_id)
zhufl420a0192017-09-28 11:04:50 +0800121 ssh_login = CONF.validation.image_ssh_user
122 for server in self.servers:
123 # call the common method in the parent class
124 self.check_tenant_network_connectivity(
125 server, ssh_login, self._get_server_key(server),
126 servers_for_debug=self.servers)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200127
Yair Friedae0e73d2014-11-24 11:56:26 +0200128 floating_ip = self.create_floating_ip(server)
129 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Maru Newby81f07a02012-09-05 20:21:19 -0700130
Yair Frieded8392f2014-01-15 17:21:35 +0200131 def check_networks(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000132 """Checks that we see the newly created network/subnet/router
133
134 via checking the result of list_[networks,routers,subnets]
Yair Frieded8392f2014-01-15 17:21:35 +0200135 """
136
jeremy.zhang5870ff12017-05-25 11:24:23 +0800137 seen_nets = self.os_admin.networks_client.list_networks()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100138 seen_names = [n['name'] for n in seen_nets['networks']]
139 seen_ids = [n['id'] for n in seen_nets['networks']]
Steve Heyman33735f22016-05-24 09:28:08 -0500140 self.assertIn(self.network['name'], seen_names)
141 self.assertIn(self.network['id'], seen_ids)
Yair Frieded8392f2014-01-15 17:21:35 +0200142
David Shrewsbury9bac3662014-08-07 15:07:01 -0400143 if self.subnet:
jeremy.zhang5870ff12017-05-25 11:24:23 +0800144 seen_subnets = self.os_admin.subnets_client.list_subnets()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100145 seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']]
146 seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']]
Steve Heyman33735f22016-05-24 09:28:08 -0500147 self.assertIn(self.network['id'], seen_net_ids)
148 self.assertIn(self.subnet['id'], seen_subnet_ids)
Yair Frieded8392f2014-01-15 17:21:35 +0200149
David Shrewsbury9bac3662014-08-07 15:07:01 -0400150 if self.router:
jeremy.zhang5870ff12017-05-25 11:24:23 +0800151 seen_routers = self.os_admin.routers_client.list_routers()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100152 seen_router_ids = [n['id'] for n in seen_routers['routers']]
153 seen_router_names = [n['name'] for n in seen_routers['routers']]
Steve Heyman33735f22016-05-24 09:28:08 -0500154 self.assertIn(self.router['name'],
David Shrewsbury9bac3662014-08-07 15:07:01 -0400155 seen_router_names)
Steve Heyman33735f22016-05-24 09:28:08 -0500156 self.assertIn(self.router['id'],
David Shrewsbury9bac3662014-08-07 15:07:01 -0400157 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000158
zhufl24208c22016-10-25 15:23:48 +0800159 def _create_server(self, network, port_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300160 keypair = self.create_keypair()
161 self.keypairs[keypair['name']] = keypair
Jordan Pittier37b94a02017-02-21 18:11:55 +0100162 security_groups = [
Soniya Vyas582c1702021-02-22 18:26:17 +0530163 {'name': self.create_security_group()['name']}
Jordan Pittier37b94a02017-02-21 18:11:55 +0100164 ]
Steve Heyman33735f22016-05-24 09:28:08 -0500165 network = {'uuid': network['id']}
Matt Riedemann17940732015-03-13 14:18:19 +0000166 if port_id is not None:
lanoux5fc14522015-09-21 08:17:35 +0000167 network['port'] = port_id
168
169 server = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +0000170 networks=[network],
171 key_name=keypair['name'],
zhufl13c9c892017-02-10 12:04:07 +0800172 security_groups=security_groups)
Yair Fried1fc32a12014-08-04 09:11:30 +0300173 self.servers.append(server)
174 return server
175
176 def _get_server_key(self, server):
177 return self.keypairs[server['key_name']]['private_key']
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700178
zhufl0ec74c42017-11-15 14:02:28 +0800179 def _check_public_network_connectivity(
Alok Maurya6384bbb2014-07-13 06:44:29 -0700180 self, should_connect=True, msg=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000181 should_check_floating_ip_status=True, mtu=None):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000182 """Verifies connectivty to a VM via public network and floating IP
183
Yair Fried45f92952014-06-26 05:19:19 +0300184 and verifies floating IP has resource status is correct.
185
Yair Fried45f92952014-06-26 05:19:19 +0300186 :param should_connect: bool. determines if connectivity check is
187 negative or positive.
188 :param msg: Failure message to add to Error message. Should describe
189 the place in the test scenario where the method was called,
190 to indicate the context of the failure
Alok Maurya6384bbb2014-07-13 06:44:29 -0700191 :param should_check_floating_ip_status: bool. should status of
192 floating_ip be checked or not
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000193 :param mtu: int. MTU network to use for connectivity validation
Yair Fried45f92952014-06-26 05:19:19 +0300194 """
lanoux283273b2015-12-04 03:01:54 -0800195 ssh_login = CONF.validation.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200196 floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500197 ip_address = floating_ip['floating_ip_address']
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200198 private_key = None
Yair Fried45f92952014-06-26 05:19:19 +0300199 floatingip_status = 'DOWN'
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200200 if should_connect:
Yair Fried1fc32a12014-08-04 09:11:30 +0300201 private_key = self._get_server_key(server)
Yair Fried45f92952014-06-26 05:19:19 +0300202 floatingip_status = 'ACTIVE'
zhufl0ec74c42017-11-15 14:02:28 +0800203
Swaminathan Vasudevandc8bcdb2015-02-28 12:47:21 -0800204 # Check FloatingIP Status before initiating a connection
205 if should_check_floating_ip_status:
206 self.check_floating_ip_status(floating_ip, floatingip_status)
zhufl0ec74c42017-11-15 14:02:28 +0800207
208 message = 'Public network connectivity check failed'
209 if msg:
210 message += '. Reason: %s' % msg
211
212 self.check_vm_connectivity(
213 ip_address, ssh_login, private_key, should_connect,
214 message, server, mtu=mtu)
Matthew Treinish2b59f842013-09-09 20:32:51 +0000215
Yair Fried9a551c42013-12-15 14:59:34 +0200216 def _disassociate_floating_ips(self):
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200217 floating_ip, _ = self.floating_ip_tuple
zhuflafe96b82017-09-22 14:25:29 +0800218 floating_ip = self.floating_ips_client.update_floatingip(
219 floating_ip['id'], port_id=None)['floatingip']
220 self.assertIsNone(floating_ip['port_id'])
221 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200222
Yair Fried05db2522013-11-18 11:02:10 +0200223 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200224 floating_ip, server = self.floating_ip_tuple
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200225 # create a new server for the floating ip
zhufl24208c22016-10-25 15:23:48 +0800226 server = self._create_server(self.network)
Soniya Vyasa446d702021-02-23 15:58:53 +0530227 port_id, _ = self.get_server_port_id_and_ip4(server)
zhuflafe96b82017-09-22 14:25:29 +0800228 floating_ip = self.floating_ips_client.update_floatingip(
229 floating_ip['id'], port_id=port_id)['floatingip']
230 self.assertEqual(port_id, floating_ip['port_id'])
231 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Yair Fried05db2522013-11-18 11:02:10 +0200232
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300233 def _create_new_network(self, create_gateway=False):
Soniya Vyas3bdafd82021-02-22 18:59:27 +0530234 self.new_net = self.create_network()
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300235 if create_gateway:
zhufl5b0a52f2017-10-24 15:48:20 +0800236 self.new_subnet = self.create_subnet(
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300237 network=self.new_net)
238 else:
zhufl5b0a52f2017-10-24 15:48:20 +0800239 self.new_subnet = self.create_subnet(
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300240 network=self.new_net,
241 gateway_ip=None)
Yair Fried3097dc12014-01-26 08:46:43 +0200242
243 def _hotplug_server(self):
244 old_floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500245 ip_address = old_floating_ip['floating_ip_address']
Yair Fried1fc32a12014-08-04 09:11:30 +0300246 private_key = self._get_server_key(server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100247 ssh_client = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800248 ip_address, private_key=private_key, server=server)
Yair Fried3097dc12014-01-26 08:46:43 +0200249 old_nic_list = self._get_server_nics(ssh_client)
250 # get a port from a list of one item
jeremy.zhang5870ff12017-05-25 11:24:23 +0800251 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100252 device_id=server['id'])['ports']
Yair Fried3097dc12014-01-26 08:46:43 +0200253 self.assertEqual(1, len(port_list))
254 old_port = port_list[0]
David Kranzb2b0c182015-02-18 13:28:19 -0500255 interface = self.interface_client.create_interface(
Ken'ichi Ohmichi9509b962015-07-07 05:30:15 +0000256 server_id=server['id'],
Steve Heyman33735f22016-05-24 09:28:08 -0500257 net_id=self.new_net['id'])['interfaceAttachment']
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700258 self.addCleanup(self.ports_client.wait_for_resource_deletion,
259 interface['port_id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100260 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Yair Fried1fc32a12014-08-04 09:11:30 +0300261 self.interface_client.delete_interface,
262 server['id'], interface['port_id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200263
264 def check_ports():
Jordan Pittier64e6b442017-02-20 19:29:02 +0100265 self.new_port_list = [
266 port for port in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800267 self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100268 device_id=server['id'])['ports']
269 if port['id'] != old_port['id']
270 ]
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200271 return len(self.new_port_list) == 1
Yair Fried3097dc12014-01-26 08:46:43 +0200272
Jordan Pittier35a63752016-08-30 13:09:12 +0200273 if not test_utils.call_until_true(
274 check_ports, CONF.network.build_timeout,
275 CONF.network.build_interval):
Matt Riedemann892094e2015-02-05 07:24:02 -0800276 raise exceptions.TimeoutException(
277 "No new port attached to the server in time (%s sec)! "
278 "Old port: %s. Number of new ports: %d" % (
279 CONF.network.build_timeout, old_port,
280 len(self.new_port_list)))
Steve Heyman33735f22016-05-24 09:28:08 -0500281 new_port = self.new_port_list[0]
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200282
283 def check_new_nic():
284 new_nic_list = self._get_server_nics(ssh_client)
285 self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
286 return len(self.diff_list) == 1
287
Jordan Pittier35a63752016-08-30 13:09:12 +0200288 if not test_utils.call_until_true(
289 check_new_nic, CONF.network.build_timeout,
290 CONF.network.build_interval):
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200291 raise exceptions.TimeoutException("Interface not visible on the "
292 "guest after %s sec"
293 % CONF.network.build_timeout)
294
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200295 _, new_nic = self.diff_list[0]
Martin Kopec925188d2019-05-07 13:26:34 +0000296 ip_output = ssh_client.exec_command('ip a')
297 ip_address = new_port['fixed_ips'][0]['ip_address']
298 ip_mask = CONF.network.project_network_mask_bits
299 # check if the address is not already in use, if not, set it
300 if ' ' + ip_address + '/' + str(ip_mask) not in ip_output:
Rodolfo Alonso Hernandez15d63092020-03-31 15:34:30 +0000301 try:
302 ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
303 ip_address, ip_mask, new_nic))
304 ssh_client.exec_command("sudo ip link set %s up" % new_nic)
305 except exceptions.SSHExecCommandFailed as exc:
306 if 'RTNETLINK answers: File exists' in str(exc):
307 LOG.debug(
308 'IP address %(ip_address)s is already set in device '
309 '%(device)s\nPrevious "ip a" output: %(ip_output)s',
310 {'ip_address': ip_address, 'device': new_nic,
311 'ip_output': ip_output})
312 else:
313 raise exc
Yair Fried3097dc12014-01-26 08:46:43 +0200314
315 def _get_server_nics(self, ssh_client):
James Pagea9366272017-06-09 12:05:09 +0100316 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
Ken'ichi Ohmichi84aeba62017-03-01 18:31:20 -0800317 ipatxt = ssh_client.exec_command("ip address")
Yair Fried3097dc12014-01-26 08:46:43 +0200318 return reg.findall(ipatxt)
319
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300320 def _check_network_internal_connectivity(self, network,
321 should_connect=True):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000322 """via ssh check VM internal connectivity:
323
Yair Fried06552292013-11-11 12:10:09 +0200324 - ping internal gateway and DHCP port, implying in-tenant connectivity
325 pinging both, because L3 and DHCP agents might be on different nodes
Tong Liu589f3152016-03-24 05:56:40 +0000326 - ping internal compute port, implying connectivity to other VMs on
327 this network
Yair Fried3097dc12014-01-26 08:46:43 +0200328 """
329 floating_ip, server = self.floating_ip_tuple
330 # get internal ports' ips:
Tong Liu589f3152016-03-24 05:56:40 +0000331 # get all network and compute ports in the new network
Rodolfo Alonso Hernandez17655432021-09-09 13:55:11 +0000332 # NOTE(ralonsoh): device_owner="network:distributed" ports are OVN
333 # metadata ports and should be filtered out.
Jordan Pittier64e6b442017-02-20 19:29:02 +0100334 internal_ips = (
335 p['fixed_ips'][0]['ip_address'] for p in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800336 self.os_admin.ports_client.list_ports(
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000337 project_id=server['tenant_id'],
Jordan Pittier64e6b442017-02-20 19:29:02 +0100338 network_id=network['id'])['ports']
Rodolfo Alonso Hernandez17655432021-09-09 13:55:11 +0000339 if ((p['device_owner'].startswith('network') and
340 not p['device_owner'] == 'network:distributed') or
341 p['device_owner'].startswith('compute'))
Jordan Pittier64e6b442017-02-20 19:29:02 +0100342 )
Yair Fried3097dc12014-01-26 08:46:43 +0200343
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300344 self._check_server_connectivity(floating_ip,
345 internal_ips,
346 should_connect)
Yair Fried06552292013-11-11 12:10:09 +0200347
348 def _check_network_external_connectivity(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000349 """ping default gateway to imply external connectivity"""
Yair Fried06552292013-11-11 12:10:09 +0200350 if not CONF.network.public_network_id:
351 msg = 'public network not defined.'
352 LOG.info(msg)
353 return
354
Andrew Boik4a3daf12015-03-27 01:59:31 -0400355 # We ping the external IP from the instance using its floating IP
356 # which is always IPv4, so we must only test connectivity to
357 # external IPv4 IPs if the external network is dualstack.
Jordan Pittier64e6b442017-02-20 19:29:02 +0100358 v4_subnets = [
jeremy.zhang5870ff12017-05-25 11:24:23 +0800359 s for s in self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100360 network_id=CONF.network.public_network_id)['subnets']
361 if s['ip_version'] == 4
362 ]
Yair Fried06552292013-11-11 12:10:09 +0200363
Lukas Piwowarski2385e042020-01-31 12:28:20 +0000364 if len(v4_subnets) > 1:
365 self.assertTrue(
366 CONF.network.subnet_id,
367 "Found %d subnets. Specify subnet using configuration "
368 "option [network].subnet_id."
369 % len(v4_subnets))
370 subnet = self.os_admin.subnets_client.show_subnet(
371 CONF.network.subnet_id)['subnet']
372 external_ips = [subnet['gateway_ip']]
373 else:
374 external_ips = [v4_subnets[0]['gateway_ip']]
375
Yair Fried06552292013-11-11 12:10:09 +0200376 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
377 external_ips)
378
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300379 def _check_server_connectivity(self, floating_ip, address_list,
380 should_connect=True):
Steve Heyman33735f22016-05-24 09:28:08 -0500381 ip_address = floating_ip['floating_ip_address']
Yair Fried1fc32a12014-08-04 09:11:30 +0300382 private_key = self._get_server_key(self.floating_ip_tuple.server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100383 ssh_source = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800384 ip_address, private_key=private_key,
385 server=self.floating_ip_tuple.server)
Yair Fried3097dc12014-01-26 08:46:43 +0200386
Yair Fried06552292013-11-11 12:10:09 +0200387 for remote_ip in address_list:
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900388 self.check_remote_connectivity(ssh_source, remote_ip,
389 should_connect)
Yair Fried3097dc12014-01-26 08:46:43 +0200390
zhuflafe96b82017-09-22 14:25:29 +0800391 def _update_router_admin_state(self, router, admin_state_up):
392 kwargs = dict(admin_state_up=admin_state_up)
393 router = self.routers_client.update_router(
394 router['id'], **kwargs)['router']
395 self.assertEqual(admin_state_up, router['admin_state_up'])
396
Jordan Pittier3b46d272017-04-12 16:17:28 +0200397 @decorators.attr(type='smoke')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800398 @decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49')
Andrea Frittolicd368412017-08-14 21:37:56 +0100399 @utils.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000400 def test_network_basic_ops(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000401 """Basic network operation test
402
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600403 For a freshly-booted VM with an IP address ("port") on a given network:
Yair Fried3097dc12014-01-26 08:46:43 +0200404
405 - the Tempest host can ping the IP address. This implies, but
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600406 does not guarantee (see the ssh check that follows), that the
407 VM has been assigned the correct IP address and has
408 connectivity to the Tempest host.
Yair Fried3097dc12014-01-26 08:46:43 +0200409
410 - the Tempest host can perform key-based authentication to an
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600411 ssh server hosted at the IP address. This check guarantees
412 that the IP address is associated with the target VM.
Yair Fried3097dc12014-01-26 08:46:43 +0200413
Yair Fried3097dc12014-01-26 08:46:43 +0200414 - the Tempest host can ssh into the VM via the IP address and
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600415 successfully execute the following:
Yair Fried3097dc12014-01-26 08:46:43 +0200416
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600417 - ping an external IP address, implying external connectivity.
Yair Fried3097dc12014-01-26 08:46:43 +0200418
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600419 - ping an external hostname, implying that dns is correctly
420 configured.
Yair Fried3097dc12014-01-26 08:46:43 +0200421
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600422 - ping an internal IP address, implying connectivity to another
423 VM on the same network.
Yair Fried3097dc12014-01-26 08:46:43 +0200424
Yair Fried06552292013-11-11 12:10:09 +0200425 - detach the floating-ip from the VM and verify that it becomes
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600426 unreachable
Yair Fried06552292013-11-11 12:10:09 +0200427
428 - associate detached floating ip to a new VM and verify connectivity.
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600429 VMs are created with unique keypair so connectivity also asserts
430 that floating IP is associated with the new VM instead of the old
431 one
Yair Fried06552292013-11-11 12:10:09 +0200432
Yair Fried45f92952014-06-26 05:19:19 +0300433 Verifies that floating IP status is updated correctly after each change
Yair Fried3097dc12014-01-26 08:46:43 +0200434 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400435 self._setup_network_and_servers()
zhufl0ec74c42017-11-15 14:02:28 +0800436 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200437 self._check_network_internal_connectivity(network=self.network)
438 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200439 self._disassociate_floating_ips()
zhufl0ec74c42017-11-15 14:02:28 +0800440 self._check_public_network_connectivity(should_connect=False,
441 msg="after disassociate "
442 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200443 self._reassociate_floating_ips()
zhufl0ec74c42017-11-15 14:02:28 +0800444 self._check_public_network_connectivity(should_connect=True,
445 msg="after re-associate "
446 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200447
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800448 @decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
Andrea Frittolicd368412017-08-14 21:37:56 +0100449 @testtools.skipUnless(utils.is_extension_enabled('net-mtu', 'network'),
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000450 'No way to calculate MTU for networks')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200451 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100452 @utils.services('compute', 'network')
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000453 def test_mtu_sized_frames(self):
454 """Validate that network MTU sized frames fit through."""
455 self._setup_network_and_servers()
Ihar Hrachyshkaaca29ed2017-09-25 12:13:53 -0700456 # first check that connectivity works in general for the instance
zhufl0ec74c42017-11-15 14:02:28 +0800457 self._check_public_network_connectivity(should_connect=True)
Ihar Hrachyshkaaca29ed2017-09-25 12:13:53 -0700458 # now that we checked general connectivity, test that full size frames
459 # can also pass between nodes
zhufl0ec74c42017-11-15 14:02:28 +0800460 self._check_public_network_connectivity(
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000461 should_connect=True, mtu=self.network['mtu'])
462
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800463 @decorators.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
Thiago Paiva66cded22016-08-15 14:55:58 -0300464 @testtools.skipIf(CONF.network.shared_physical_network,
465 'Connectivity can only be tested when in a '
466 'multitenant network environment')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200467 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100468 @utils.services('compute', 'network')
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300469 def test_connectivity_between_vms_on_different_networks(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000470 """Test connectivity between VMs on different networks
471
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600472 For a freshly-booted VM with an IP address ("port") on a given network:
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300473
474 - the Tempest host can ping the IP address.
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300475 - the Tempest host can ssh into the VM via the IP address and
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600476 successfully execute the following:
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300477
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600478 - ping an external IP address, implying external connectivity.
479 - ping an external hostname, implying that dns is correctly
480 configured.
481 - ping an internal IP address, implying connectivity to another
482 VM on the same network.
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300483
484 - Create another network on the same tenant with subnet, create
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600485 an VM on the new network.
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300486
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600487 - Ping the new VM from previous VM failed since the new network
488 was not attached to router yet.
489 - Attach the new network to the router, Ping the new VM from
490 previous VM succeed.
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300491
492 """
493 self._setup_network_and_servers()
zhufl0ec74c42017-11-15 14:02:28 +0800494 self._check_public_network_connectivity(should_connect=True)
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300495 self._check_network_internal_connectivity(network=self.network)
496 self._check_network_external_connectivity()
497 self._create_new_network(create_gateway=True)
Lucas Alvares Gomesd595c362018-10-16 14:38:11 +0100498 new_server = self._create_server(self.new_net)
499 new_server_ips = [addr['addr'] for addr in
500 new_server['addresses'][self.new_net['name']]]
501
502 # Assert that pinging the new VM fails since the new network is not
503 # connected to a router
504 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
505 new_server_ips, should_connect=False)
Steve Heyman33735f22016-05-24 09:28:08 -0500506 router_id = self.router['id']
507 self.routers_client.add_router_interface(
508 router_id, subnet_id=self.new_subnet['id'])
509
510 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
511 self.routers_client.remove_router_interface,
512 router_id, subnet_id=self.new_subnet['id'])
Lucas Alvares Gomesd595c362018-10-16 14:38:11 +0100513
514 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
515 new_server_ips, should_connect=True)
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300516
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800517 @decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa')
Adam Gandelman7186f7a2014-07-23 09:28:56 -0400518 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
519 'NIC hotplug not available')
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200520 @testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'],
521 'NIC hotplug not supported for '
522 'vnic_type direct or macvtap')
Andrea Frittolicd368412017-08-14 21:37:56 +0100523 @utils.services('compute', 'network')
Yair Fried3097dc12014-01-26 08:46:43 +0200524 def test_hotplug_nic(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000525 """Test hotplug network interface
526
Arief3f6e812016-09-28 16:48:20 +0300527 1. Create a network and a VM.
528 2. Check connectivity to the VM via a public network.
529 3. Create a new network, with no gateway.
530 4. Bring up a new interface
531 5. check the VM reach the new network
Yair Fried3097dc12014-01-26 08:46:43 +0200532
533 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400534 self._setup_network_and_servers()
zhufl0ec74c42017-11-15 14:02:28 +0800535 self._check_public_network_connectivity(should_connect=True)
Yair Fried3097dc12014-01-26 08:46:43 +0200536 self._create_new_network()
537 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200538 self._check_network_internal_connectivity(network=self.new_net)
Alok Maurya6384bbb2014-07-13 06:44:29 -0700539
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800540 @decorators.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f')
Thiago Paiva66cded22016-08-15 14:55:58 -0300541 @testtools.skipIf(CONF.network.shared_physical_network,
542 'Router state can be altered only with multitenant '
543 'networks capabilities')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200544 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100545 @utils.services('compute', 'network')
Alok Maurya6384bbb2014-07-13 06:44:29 -0700546 def test_update_router_admin_state(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000547 """Test to update admin state up of router
548
Alok Maurya6384bbb2014-07-13 06:44:29 -0700549 1. Check public connectivity before updating
550 admin_state_up attribute of router to False
551 2. Check public connectivity after updating
552 admin_state_up attribute of router to False
553 3. Check public connectivity after updating
554 admin_state_up attribute of router to True
555 """
556 self._setup_network_and_servers()
zhufl0ec74c42017-11-15 14:02:28 +0800557 self._check_public_network_connectivity(
Alok Maurya6384bbb2014-07-13 06:44:29 -0700558 should_connect=True, msg="before updating "
559 "admin_state_up of router to False")
560 self._update_router_admin_state(self.router, False)
561 # TODO(alokmaurya): Remove should_check_floating_ip_status=False check
562 # once bug 1396310 is fixed
563
zhufl0ec74c42017-11-15 14:02:28 +0800564 self._check_public_network_connectivity(
Alok Maurya6384bbb2014-07-13 06:44:29 -0700565 should_connect=False, msg="after updating "
566 "admin_state_up of router to False",
567 should_check_floating_ip_status=False)
568 self._update_router_admin_state(self.router, True)
zhufl0ec74c42017-11-15 14:02:28 +0800569 self._check_public_network_connectivity(
Alok Maurya6384bbb2014-07-13 06:44:29 -0700570 should_connect=True, msg="after updating "
571 "admin_state_up of router to True")
Yair Fried413bf2d2014-11-19 17:07:11 +0200572
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800573 @decorators.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980')
Thiago Paiva66cded22016-08-15 14:55:58 -0300574 @testtools.skipIf(CONF.network.shared_physical_network,
575 'network isolation not available')
Yair Fried413bf2d2014-11-19 17:07:11 +0200576 @testtools.skipUnless(CONF.scenario.dhcp_client,
577 "DHCP client is not available.")
Jordan Pittier3b46d272017-04-12 16:17:28 +0200578 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100579 @utils.services('compute', 'network')
Yair Fried413bf2d2014-11-19 17:07:11 +0200580 def test_subnet_details(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000581 """Tests that subnet's extra configuration details are affecting VMs.
582
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600583 This test relies on non-shared, isolated tenant networks.
Yair Fried413bf2d2014-11-19 17:07:11 +0200584
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600585 NOTE: Neutron subnets push data to servers via dhcp-agent, so any
586 update in subnet requires server to actively renew its DHCP lease.
Yair Fried413bf2d2014-11-19 17:07:11 +0200587
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600588 1. Configure subnet with dns nameserver
589 2. retrieve the VM's configured dns and verify it matches the one
590 configured for the subnet.
591 3. update subnet's dns
592 4. retrieve the VM's configured dns and verify it matches the new one
593 configured for the subnet.
Yair Fried413bf2d2014-11-19 17:07:11 +0200594
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600595 TODO(yfried): add host_routes
Yair Fried413bf2d2014-11-19 17:07:11 +0200596
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600597 any resolution check would be testing either:
598
599 * l3 forwarding (tested in test_network_basic_ops)
600 * Name resolution of an external DNS nameserver - out of scope for
601 Tempest
Yair Fried413bf2d2014-11-19 17:07:11 +0200602 """
603 # this test check only updates (no actual resolution) so using
604 # arbitrary ip addresses as nameservers, instead of parsing CONF
605 initial_dns_server = '1.2.3.4'
606 alt_dns_server = '9.8.7.6'
Yair Friedbb0ea392015-01-19 07:26:08 +0000607
Bence Romsics199e0222019-01-28 14:18:00 +0100608 # Original timeouts are suggested by salvatore-orlando in
Yair Friedbb0ea392015-01-19 07:26:08 +0000609 # https://bugs.launchpad.net/neutron/+bug/1412325/comments/3
Bence Romsics199e0222019-01-28 14:18:00 +0100610 #
611 # Compared to that renew_delay was increased, because
612 # busybox's udhcpc accepts SIGUSR1 as a renew request. Internally
613 # it goes into RENEW_REQUESTED state. If it receives a 2nd SIGUSR1
614 # signal while in that state then it calls the deconfig script
615 # ("/sbin/cirros-dhcpc deconfig" in sufficiently new cirros versions)
616 # which leads to the address being transiently deconfigured which
617 # for our case is unwanted.
618 renew_delay = 3 * CONF.network.build_interval
Yair Friedbb0ea392015-01-19 07:26:08 +0000619 renew_timeout = CONF.network.build_timeout
620
Yair Fried413bf2d2014-11-19 17:07:11 +0200621 self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
zhufl0ec74c42017-11-15 14:02:28 +0800622 self._check_public_network_connectivity(should_connect=True)
Yair Fried413bf2d2014-11-19 17:07:11 +0200623
624 floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500625 ip_address = floating_ip['floating_ip_address']
Yair Fried413bf2d2014-11-19 17:07:11 +0200626 private_key = self._get_server_key(server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100627 ssh_client = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800628 ip_address, private_key=private_key, server=server)
Yair Fried413bf2d2014-11-19 17:07:11 +0200629
ccamposr3893f9d2021-03-10 13:31:50 +0100630 # NOTE: Server needs to renew its dhcp lease in order to get new
631 # definitions from subnet
632 # NOTE(amuller): we are renewing the lease as part of the retry
633 # because Neutron updates dnsmasq asynchronously after the
634 # subnet-update API call returns.
635 ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'],
636 dhcp_client=CONF.scenario.dhcp_client)
armando-migliaccio424aa412015-02-22 17:55:17 -0800637 dns_servers = [initial_dns_server]
638 servers = ssh_client.get_dns_servers()
639 self.assertEqual(set(dns_servers), set(servers),
640 'Looking for servers: {trgt_serv}. '
641 'Retrieved DNS nameservers: {act_serv} '
642 'From host: {host}.'
643 .format(host=ssh_client.ssh_client.host,
644 act_serv=servers,
645 trgt_serv=dns_servers))
Yair Fried413bf2d2014-11-19 17:07:11 +0200646
Steve Heyman33735f22016-05-24 09:28:08 -0500647 self.subnet = self.subnets_client.update_subnet(
648 self.subnet['id'], dns_nameservers=[alt_dns_server])['subnet']
649
Yair Fried413bf2d2014-11-19 17:07:11 +0200650 # asserts that Neutron DB has updated the nameservers
Steve Heyman33735f22016-05-24 09:28:08 -0500651 self.assertEqual([alt_dns_server], self.subnet['dns_nameservers'],
Yair Fried413bf2d2014-11-19 17:07:11 +0200652 "Failed to update subnet's nameservers")
653
Yair Friedbb0ea392015-01-19 07:26:08 +0000654 def check_new_dns_server():
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000655 # NOTE: Server needs to renew its dhcp lease in order to get new
656 # definitions from subnet
657 # NOTE(amuller): we are renewing the lease as part of the retry
658 # because Neutron updates dnsmasq asynchronously after the
659 # subnet-update API call returns.
Ken'ichi Ohmichi4e337852017-03-01 12:04:23 -0800660 ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'],
661 dhcp_client=CONF.scenario.dhcp_client)
armando-migliaccio424aa412015-02-22 17:55:17 -0800662 if ssh_client.get_dns_servers() != [alt_dns_server]:
Yair Friedbb0ea392015-01-19 07:26:08 +0000663 LOG.debug("Failed to update DNS nameservers")
664 return False
665 return True
666
Jordan Pittier35a63752016-08-30 13:09:12 +0200667 self.assertTrue(test_utils.call_until_true(check_new_dns_server,
668 renew_timeout,
669 renew_delay),
Yair Friedbb0ea392015-01-19 07:26:08 +0000670 msg="DHCP renewal failed to fetch "
671 "new DNS nameservers")
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800672
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800673 @decorators.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b')
Itzik Brownbeb30d32015-03-29 09:42:54 +0300674 @testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change,
675 "Changing a port's admin state is not supported "
676 "by the test environment")
Jordan Pittier3b46d272017-04-12 16:17:28 +0200677 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100678 @utils.services('compute', 'network')
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800679 def test_update_instance_port_admin_state(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000680 """Test to update admin_state_up attribute of instance port
681
Carlos Goncalves539f8362016-11-04 14:55:02 +0100682 1. Check public and project connectivity before updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800683 admin_state_up attribute of instance port to False
Carlos Goncalves539f8362016-11-04 14:55:02 +0100684 2. Check public and project connectivity after updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800685 admin_state_up attribute of instance port to False
Carlos Goncalves539f8362016-11-04 14:55:02 +0100686 3. Check public and project connectivity after updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800687 admin_state_up attribute of instance port to True
688 """
689 self._setup_network_and_servers()
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200690 _, server = self.floating_ip_tuple
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800691 server_id = server['id']
jeremy.zhang5870ff12017-05-25 11:24:23 +0800692 port_id = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100693 device_id=server_id)['ports'][0]['id']
Carlos Goncalves539f8362016-11-04 14:55:02 +0100694 server_pip = server['addresses'][self.network['name']][0]['addr']
695
696 server2 = self._create_server(self.network)
697 server2_fip = self.create_floating_ip(server2)
698
699 private_key = self._get_server_key(server2)
700 ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
zhuflf52c7592017-05-25 13:55:24 +0800701 private_key=private_key,
702 server=server2)
Carlos Goncalves539f8362016-11-04 14:55:02 +0100703
zhufl0ec74c42017-11-15 14:02:28 +0800704 self._check_public_network_connectivity(
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800705 should_connect=True, msg="before updating "
706 "admin_state_up of instance port to False")
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900707 self.check_remote_connectivity(ssh_client, dest=server_pip,
708 should_succeed=True)
John Warren49c0fe52015-10-22 12:35:54 -0400709 self.ports_client.update_port(port_id, admin_state_up=False)
zhufl0ec74c42017-11-15 14:02:28 +0800710 self._check_public_network_connectivity(
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800711 should_connect=False, msg="after updating "
712 "admin_state_up of instance port to False",
713 should_check_floating_ip_status=False)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900714 self.check_remote_connectivity(ssh_client, dest=server_pip,
715 should_succeed=False)
John Warren49c0fe52015-10-22 12:35:54 -0400716 self.ports_client.update_port(port_id, admin_state_up=True)
zhufl0ec74c42017-11-15 14:02:28 +0800717 self._check_public_network_connectivity(
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800718 should_connect=True, msg="after updating "
719 "admin_state_up of instance port to True")
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900720 self.check_remote_connectivity(ssh_client, dest=server_pip,
721 should_succeed=True)
Matt Riedemann17940732015-03-13 14:18:19 +0000722
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800723 @decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200724 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100725 @utils.services('compute', 'network')
Matt Riedemann17940732015-03-13 14:18:19 +0000726 def test_preserve_preexisting_port(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000727 """Test preserve pre-existing port
728
729 Tests that a pre-existing port provided on server boot is not deleted
730 if the server is deleted.
Matt Riedemann17940732015-03-13 14:18:19 +0000731
732 Nova should unbind the port from the instance on delete if the port was
733 not created by Nova as part of the boot request.
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400734
735 We should also be able to boot another server with the same port.
Matt Riedemann17940732015-03-13 14:18:19 +0000736 """
737 # Setup the network, create a port and boot the server from that port.
738 self._setup_network_and_servers(boot_with_port=True)
739 _, server = self.floating_ip_tuple
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000740 self.assertEqual(1, len(self.ports),
741 'There should only be one port created for '
742 'server %s.' % server['id'])
743 port_id = self.ports[0]['port']
744 self.assertIsNotNone(port_id,
Matt Riedemann17940732015-03-13 14:18:19 +0000745 'Server should have been created from a '
746 'pre-existing port.')
747 # Assert the port is bound to the server.
jeremy.zhang5870ff12017-05-25 11:24:23 +0800748 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100749 device_id=server['id'], network_id=self.network['id'])['ports']
Matt Riedemann17940732015-03-13 14:18:19 +0000750 self.assertEqual(1, len(port_list),
751 'There should only be one port created for '
752 'server %s.' % server['id'])
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000753 self.assertEqual(port_id, port_list[0]['id'])
Matt Riedemann17940732015-03-13 14:18:19 +0000754 # Delete the server.
755 self.servers_client.delete_server(server['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000756 waiters.wait_for_server_termination(self.servers_client, server['id'])
Matt Riedemann17940732015-03-13 14:18:19 +0000757 # Assert the port still exists on the network but is unbound from
758 # the deleted server.
John Warren49c0fe52015-10-22 12:35:54 -0400759 port = self.ports_client.show_port(port_id)['port']
Matt Riedemann17940732015-03-13 14:18:19 +0000760 self.assertEqual(self.network['id'], port['network_id'])
761 self.assertEqual('', port['device_id'])
762 self.assertEqual('', port['device_owner'])
Yair Fried564d89d2015-08-06 17:02:12 +0300763
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400764 # Boot another server with the same port to make sure nothing was
765 # left around that could cause issues.
zhufl24208c22016-10-25 15:23:48 +0800766 server = self._create_server(self.network, port['id'])
jeremy.zhang5870ff12017-05-25 11:24:23 +0800767 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100768 device_id=server['id'], network_id=self.network['id'])['ports']
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400769 self.assertEqual(1, len(port_list),
770 'There should only be one port created for '
771 'server %s.' % server['id'])
772 self.assertEqual(port['id'], port_list[0]['id'])
773
Andrea Frittolicd368412017-08-14 21:37:56 +0100774 @utils.requires_ext(service='network', extension='l3_agent_scheduler')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800775 @decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200776 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100777 @utils.services('compute', 'network')
Yair Fried564d89d2015-08-06 17:02:12 +0300778 def test_router_rescheduling(self):
779 """Tests that router can be removed from agent and add to a new agent.
780
781 1. Verify connectivity
782 2. Remove router from all l3-agents
783 3. Verify connectivity is down
784 4. Assign router to new l3-agent (or old one if no new agent is
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600785 available)
Yair Fried564d89d2015-08-06 17:02:12 +0300786 5. Verify connectivity
787 """
788
789 # TODO(yfried): refactor this test to be used for other agents (dhcp)
790 # as well
791
jeremy.zhang5870ff12017-05-25 11:24:23 +0800792 list_hosts = (self.os_admin.routers_client.
Yair Fried564d89d2015-08-06 17:02:12 +0300793 list_l3_agents_hosting_router)
jeremy.zhang5870ff12017-05-25 11:24:23 +0800794 schedule_router = (self.os_admin.network_agents_client.
Ken'ichi Ohmichi70a24e92016-01-06 01:08:27 +0000795 create_router_on_l3_agent)
jeremy.zhang5870ff12017-05-25 11:24:23 +0800796 unschedule_router = (self.os_admin.network_agents_client.
Ken'ichi Ohmichi70a24e92016-01-06 01:08:27 +0000797 delete_router_from_l3_agent)
Yair Fried564d89d2015-08-06 17:02:12 +0300798
Jordan Pittier64e6b442017-02-20 19:29:02 +0100799 agent_list_alive = set(
800 a["id"] for a in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800801 self.os_admin.network_agents_client.list_agents(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100802 agent_type="L3 agent")['agents'] if a["alive"] is True
803 )
Yair Fried564d89d2015-08-06 17:02:12 +0300804 self._setup_network_and_servers()
Kevin Benton3b63aa12015-08-27 17:15:44 -0700805
806 # NOTE(kevinbenton): we have to use the admin credentials to check
Sean Dagueed6e5862016-04-04 10:49:13 -0400807 # for the distributed flag because self.router only has a project view.
jeremy.zhang5870ff12017-05-25 11:24:23 +0800808 admin = self.os_admin.routers_client.show_router(
Steve Heyman33735f22016-05-24 09:28:08 -0500809 self.router['id'])
Kevin Benton3b63aa12015-08-27 17:15:44 -0700810 if admin['router'].get('distributed', False):
811 msg = "Rescheduling test does not apply to distributed routers."
812 raise self.skipException(msg)
813
zhufl0ec74c42017-11-15 14:02:28 +0800814 self._check_public_network_connectivity(should_connect=True)
Yair Fried564d89d2015-08-06 17:02:12 +0300815
816 # remove resource from agents
817 hosting_agents = set(a["id"] for a in
Steve Heyman33735f22016-05-24 09:28:08 -0500818 list_hosts(self.router['id'])['agents'])
shipeiqic9a4a102016-04-20 17:39:03 +0800819 no_migration = agent_list_alive == hosting_agents
Yair Fried564d89d2015-08-06 17:02:12 +0300820 LOG.info("Router will be assigned to {mig} hosting agent".
821 format(mig="the same" if no_migration else "a new"))
822
823 for hosting_agent in hosting_agents:
Steve Heyman33735f22016-05-24 09:28:08 -0500824 unschedule_router(hosting_agent, self.router['id'])
Yair Fried564d89d2015-08-06 17:02:12 +0300825 self.assertNotIn(hosting_agent,
826 [a["id"] for a in
Steve Heyman33735f22016-05-24 09:28:08 -0500827 list_hosts(self.router['id'])['agents']],
Yair Fried564d89d2015-08-06 17:02:12 +0300828 'unscheduling router failed')
829
830 # verify resource is un-functional
zhufl0ec74c42017-11-15 14:02:28 +0800831 self._check_public_network_connectivity(
Yair Fried564d89d2015-08-06 17:02:12 +0300832 should_connect=False,
833 msg='after router unscheduling',
Yair Fried564d89d2015-08-06 17:02:12 +0300834 )
835
836 # schedule resource to new agent
837 target_agent = list(hosting_agents if no_migration else
shipeiqic9a4a102016-04-20 17:39:03 +0800838 agent_list_alive - hosting_agents)[0]
Yair Fried564d89d2015-08-06 17:02:12 +0300839 schedule_router(target_agent,
piyush110786bc0faa62015-12-03 14:54:48 +0530840 router_id=self.router['id'])
Yair Fried564d89d2015-08-06 17:02:12 +0300841 self.assertEqual(
842 target_agent,
Steve Heyman33735f22016-05-24 09:28:08 -0500843 list_hosts(self.router['id'])['agents'][0]['id'],
Yair Fried564d89d2015-08-06 17:02:12 +0300844 "Router failed to reschedule. Hosting agent doesn't match "
845 "target agent")
846
847 # verify resource is functional
zhufl0ec74c42017-11-15 14:02:28 +0800848 self._check_public_network_connectivity(
Yair Fried564d89d2015-08-06 17:02:12 +0300849 should_connect=True,
850 msg='After router rescheduling')
Yair Friedbc46f592015-11-18 16:29:34 +0200851
Andrea Frittolicd368412017-08-14 21:37:56 +0100852 @utils.requires_ext(service='network', extension='port-security')
Evgeny Antyshevaaf3fc92016-02-15 11:49:22 +0000853 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
854 'NIC hotplug not available')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800855 @decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200856 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100857 @utils.services('compute', 'network')
Yair Friedbc46f592015-11-18 16:29:34 +0200858 def test_port_security_macspoofing_port(self):
859 """Tests port_security extension enforces mac spoofing
860
Eran Kuris7969e802015-12-15 13:43:46 +0200861 Neutron security groups always apply anti-spoof rules on the VMs. This
862 allows traffic to originate and terminate at the VM as expected, but
863 prevents traffic to pass through the VM. Anti-spoof rules are not
864 required in cases where the VM routes traffic through it.
865
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600866 The test steps are:
867
Eran Kuris7969e802015-12-15 13:43:46 +0200868 1. Create a new network.
869 2. Connect (hotplug) the VM to a new network.
YAMAMOTO Takashic3978412015-11-30 23:55:56 +0900870 3. Check the VM can ping a server on the new network ("peer")
Eran Kuris7969e802015-12-15 13:43:46 +0200871 4. Spoof the mac address of the new VM interface.
872 5. Check the Security Group enforces mac spoofing and blocks pings via
YAMAMOTO Takashic3978412015-11-30 23:55:56 +0900873 spoofed interface (VM cannot ping the peer).
Eran Kuris7969e802015-12-15 13:43:46 +0200874 6. Disable port-security of the spoofed port- set the flag to false.
875 7. Retest 3rd step and check that the Security Group allows pings via
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600876 the spoofed interface.
Yair Friedbc46f592015-11-18 16:29:34 +0200877 """
Eran Kuris7969e802015-12-15 13:43:46 +0200878
Yair Friedbc46f592015-11-18 16:29:34 +0200879 spoof_mac = "00:00:00:00:00:01"
880
881 # Create server
882 self._setup_network_and_servers()
zhufl0ec74c42017-11-15 14:02:28 +0800883 self._check_public_network_connectivity(should_connect=True)
Yair Friedbc46f592015-11-18 16:29:34 +0200884 self._create_new_network()
885 self._hotplug_server()
886 fip, server = self.floating_ip_tuple
jeremy.zhang5870ff12017-05-25 11:24:23 +0800887 new_ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100888 device_id=server["id"], network_id=self.new_net["id"])['ports']
Yair Friedbc46f592015-11-18 16:29:34 +0200889 spoof_port = new_ports[0]
890 private_key = self._get_server_key(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500891 ssh_client = self.get_remote_client(fip['floating_ip_address'],
zhuflf52c7592017-05-25 13:55:24 +0800892 private_key=private_key,
893 server=server)
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +0000894 spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
zhufl24208c22016-10-25 15:23:48 +0800895 peer = self._create_server(self.new_net)
Steve Heyman33735f22016-05-24 09:28:08 -0500896 peer_address = peer['addresses'][self.new_net['name']][0]['addr']
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900897 self.check_remote_connectivity(ssh_client, dest=peer_address,
898 nic=spoof_nic, should_succeed=True)
Ken'ichi Ohmichi5129c622017-03-22 11:18:42 -0700899 # Set a mac address by making nic down temporary
Slawek Kaplonski4e4a43e2023-01-20 12:30:05 +0100900 spoof_ip_addresses = ssh_client.get_nic_ip_addresses(spoof_nic)
Ken'ichi Ohmichi5129c622017-03-22 11:18:42 -0700901 cmd = ("sudo ip link set {nic} down;"
902 "sudo ip link set dev {nic} address {mac};"
Slawek Kaplonski4e4a43e2023-01-20 12:30:05 +0100903 "sudo ip link set {nic} up;"
904 "sudo ip address flush dev {nic};").format(nic=spoof_nic,
905 mac=spoof_mac)
906 for ip_address in spoof_ip_addresses:
907 cmd += (
908 "sudo ip addr add {ip_address} dev {nic};"
909 ).format(ip_address=ip_address, nic=spoof_nic)
910
Ken'ichi Ohmichi5129c622017-03-22 11:18:42 -0700911 ssh_client.exec_command(cmd)
912
Yair Friedbc46f592015-11-18 16:29:34 +0200913 new_mac = ssh_client.get_mac_address(nic=spoof_nic)
914 self.assertEqual(spoof_mac, new_mac)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900915 self.check_remote_connectivity(ssh_client, dest=peer_address,
916 nic=spoof_nic, should_succeed=False)
Yair Friedbc46f592015-11-18 16:29:34 +0200917 self.ports_client.update_port(spoof_port["id"],
918 port_security_enabled=False,
919 security_groups=[])
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900920 self.check_remote_connectivity(ssh_client, dest=peer_address,
921 nic=spoof_nic, should_succeed=True)