blob: ff8837f8d4a6e10a7cf91d3c5b17ede20ed2e0f6 [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()
Sean Dagueed6e5862016-04-04 10:49:13 -040084 if not (CONF.network.project_networks_reachable
Matthew Treinish6c072292014-01-29 19:15:52 +000085 or 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)
Yair Fried413bf2d2014-11-19 17:07:11 +0200109 self.network, self.subnet, self.router = self.create_networks(**kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -0400110 self.check_networks()
111
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000112 self.ports = []
zhufl7a8f29d2017-02-17 10:16:45 +0800113 port_id = None
Jordan Pittierf72a1dc2015-08-04 12:50:33 +0000114 if boot_with_port:
Matt Riedemann17940732015-03-13 14:18:19 +0000115 # create a port on the network and boot with that
zhufl1e446b52017-10-16 16:54:57 +0800116 port_id = self.create_port(self.network['id'])['id']
zhufl7a8f29d2017-02-17 10:16:45 +0800117 self.ports.append({'port': port_id})
Matt Riedemann17940732015-03-13 14:18:19 +0000118
zhufl7a8f29d2017-02-17 10:16:45 +0800119 server = self._create_server(self.network, port_id)
zhufl420a0192017-09-28 11:04:50 +0800120 ssh_login = CONF.validation.image_ssh_user
121 for server in self.servers:
122 # call the common method in the parent class
123 self.check_tenant_network_connectivity(
124 server, ssh_login, self._get_server_key(server),
125 servers_for_debug=self.servers)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200126
Yair Friedae0e73d2014-11-24 11:56:26 +0200127 floating_ip = self.create_floating_ip(server)
128 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Maru Newby81f07a02012-09-05 20:21:19 -0700129
Yair Frieded8392f2014-01-15 17:21:35 +0200130 def check_networks(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000131 """Checks that we see the newly created network/subnet/router
132
133 via checking the result of list_[networks,routers,subnets]
Yair Frieded8392f2014-01-15 17:21:35 +0200134 """
135
jeremy.zhang5870ff12017-05-25 11:24:23 +0800136 seen_nets = self.os_admin.networks_client.list_networks()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100137 seen_names = [n['name'] for n in seen_nets['networks']]
138 seen_ids = [n['id'] for n in seen_nets['networks']]
Steve Heyman33735f22016-05-24 09:28:08 -0500139 self.assertIn(self.network['name'], seen_names)
140 self.assertIn(self.network['id'], seen_ids)
Yair Frieded8392f2014-01-15 17:21:35 +0200141
David Shrewsbury9bac3662014-08-07 15:07:01 -0400142 if self.subnet:
jeremy.zhang5870ff12017-05-25 11:24:23 +0800143 seen_subnets = self.os_admin.subnets_client.list_subnets()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100144 seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']]
145 seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']]
Steve Heyman33735f22016-05-24 09:28:08 -0500146 self.assertIn(self.network['id'], seen_net_ids)
147 self.assertIn(self.subnet['id'], seen_subnet_ids)
Yair Frieded8392f2014-01-15 17:21:35 +0200148
David Shrewsbury9bac3662014-08-07 15:07:01 -0400149 if self.router:
jeremy.zhang5870ff12017-05-25 11:24:23 +0800150 seen_routers = self.os_admin.routers_client.list_routers()
Jordan Pittier64e6b442017-02-20 19:29:02 +0100151 seen_router_ids = [n['id'] for n in seen_routers['routers']]
152 seen_router_names = [n['name'] for n in seen_routers['routers']]
Steve Heyman33735f22016-05-24 09:28:08 -0500153 self.assertIn(self.router['name'],
David Shrewsbury9bac3662014-08-07 15:07:01 -0400154 seen_router_names)
Steve Heyman33735f22016-05-24 09:28:08 -0500155 self.assertIn(self.router['id'],
David Shrewsbury9bac3662014-08-07 15:07:01 -0400156 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000157
zhufl24208c22016-10-25 15:23:48 +0800158 def _create_server(self, network, port_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300159 keypair = self.create_keypair()
160 self.keypairs[keypair['name']] = keypair
Jordan Pittier37b94a02017-02-21 18:11:55 +0100161 security_groups = [
162 {'name': self._create_security_group()['name']}
163 ]
Steve Heyman33735f22016-05-24 09:28:08 -0500164 network = {'uuid': network['id']}
Matt Riedemann17940732015-03-13 14:18:19 +0000165 if port_id is not None:
lanoux5fc14522015-09-21 08:17:35 +0000166 network['port'] = port_id
167
168 server = self.create_server(
lanoux5fc14522015-09-21 08:17:35 +0000169 networks=[network],
170 key_name=keypair['name'],
zhufl13c9c892017-02-10 12:04:07 +0800171 security_groups=security_groups)
Yair Fried1fc32a12014-08-04 09:11:30 +0300172 self.servers.append(server)
173 return server
174
175 def _get_server_key(self, server):
176 return self.keypairs[server['key_name']]['private_key']
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700177
Alok Maurya6384bbb2014-07-13 06:44:29 -0700178 def check_public_network_connectivity(
179 self, should_connect=True, msg=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000180 should_check_floating_ip_status=True, mtu=None):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000181 """Verifies connectivty to a VM via public network and floating IP
182
Yair Fried45f92952014-06-26 05:19:19 +0300183 and verifies floating IP has resource status is correct.
184
Yair Fried45f92952014-06-26 05:19:19 +0300185 :param should_connect: bool. determines if connectivity check is
186 negative or positive.
187 :param msg: Failure message to add to Error message. Should describe
188 the place in the test scenario where the method was called,
189 to indicate the context of the failure
Alok Maurya6384bbb2014-07-13 06:44:29 -0700190 :param should_check_floating_ip_status: bool. should status of
191 floating_ip be checked or not
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000192 :param mtu: int. MTU network to use for connectivity validation
Yair Fried45f92952014-06-26 05:19:19 +0300193 """
lanoux283273b2015-12-04 03:01:54 -0800194 ssh_login = CONF.validation.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200195 floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500196 ip_address = floating_ip['floating_ip_address']
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200197 private_key = None
Yair Fried45f92952014-06-26 05:19:19 +0300198 floatingip_status = 'DOWN'
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200199 if should_connect:
Yair Fried1fc32a12014-08-04 09:11:30 +0300200 private_key = self._get_server_key(server)
Yair Fried45f92952014-06-26 05:19:19 +0300201 floatingip_status = 'ACTIVE'
Swaminathan Vasudevandc8bcdb2015-02-28 12:47:21 -0800202 # Check FloatingIP Status before initiating a connection
203 if should_check_floating_ip_status:
204 self.check_floating_ip_status(floating_ip, floatingip_status)
Matt Riedemann343305f2014-05-27 09:55:03 -0700205 # call the common method in the parent class
Yair Friedae0e73d2014-11-24 11:56:26 +0200206 super(TestNetworkBasicOps, self).check_public_network_connectivity(
Matt Riedemann343305f2014-05-27 09:55:03 -0700207 ip_address, ssh_login, private_key, should_connect, msg,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000208 self.servers, mtu=mtu)
Matthew Treinish2b59f842013-09-09 20:32:51 +0000209
Yair Fried9a551c42013-12-15 14:59:34 +0200210 def _disassociate_floating_ips(self):
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200211 floating_ip, _ = self.floating_ip_tuple
zhuflafe96b82017-09-22 14:25:29 +0800212 floating_ip = self.floating_ips_client.update_floatingip(
213 floating_ip['id'], port_id=None)['floatingip']
214 self.assertIsNone(floating_ip['port_id'])
215 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200216
Yair Fried05db2522013-11-18 11:02:10 +0200217 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200218 floating_ip, server = self.floating_ip_tuple
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200219 # create a new server for the floating ip
zhufl24208c22016-10-25 15:23:48 +0800220 server = self._create_server(self.network)
zhuflafe96b82017-09-22 14:25:29 +0800221 port_id, _ = self._get_server_port_id_and_ip4(server)
222 floating_ip = self.floating_ips_client.update_floatingip(
223 floating_ip['id'], port_id=port_id)['floatingip']
224 self.assertEqual(port_id, floating_ip['port_id'])
225 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Yair Fried05db2522013-11-18 11:02:10 +0200226
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300227 def _create_new_network(self, create_gateway=False):
Marc Koderer410c7822016-11-08 11:47:00 +0100228 self.new_net = self._create_network()
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300229 if create_gateway:
zhufl5b0a52f2017-10-24 15:48:20 +0800230 self.new_subnet = self.create_subnet(
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300231 network=self.new_net)
232 else:
zhufl5b0a52f2017-10-24 15:48:20 +0800233 self.new_subnet = self.create_subnet(
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300234 network=self.new_net,
235 gateway_ip=None)
Yair Fried3097dc12014-01-26 08:46:43 +0200236
237 def _hotplug_server(self):
238 old_floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500239 ip_address = old_floating_ip['floating_ip_address']
Yair Fried1fc32a12014-08-04 09:11:30 +0300240 private_key = self._get_server_key(server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100241 ssh_client = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800242 ip_address, private_key=private_key, server=server)
Yair Fried3097dc12014-01-26 08:46:43 +0200243 old_nic_list = self._get_server_nics(ssh_client)
244 # get a port from a list of one item
jeremy.zhang5870ff12017-05-25 11:24:23 +0800245 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100246 device_id=server['id'])['ports']
Yair Fried3097dc12014-01-26 08:46:43 +0200247 self.assertEqual(1, len(port_list))
248 old_port = port_list[0]
David Kranzb2b0c182015-02-18 13:28:19 -0500249 interface = self.interface_client.create_interface(
Ken'ichi Ohmichi9509b962015-07-07 05:30:15 +0000250 server_id=server['id'],
Steve Heyman33735f22016-05-24 09:28:08 -0500251 net_id=self.new_net['id'])['interfaceAttachment']
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700252 self.addCleanup(self.ports_client.wait_for_resource_deletion,
253 interface['port_id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100254 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Yair Fried1fc32a12014-08-04 09:11:30 +0300255 self.interface_client.delete_interface,
256 server['id'], interface['port_id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200257
258 def check_ports():
Jordan Pittier64e6b442017-02-20 19:29:02 +0100259 self.new_port_list = [
260 port for port in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800261 self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100262 device_id=server['id'])['ports']
263 if port['id'] != old_port['id']
264 ]
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200265 return len(self.new_port_list) == 1
Yair Fried3097dc12014-01-26 08:46:43 +0200266
Jordan Pittier35a63752016-08-30 13:09:12 +0200267 if not test_utils.call_until_true(
268 check_ports, CONF.network.build_timeout,
269 CONF.network.build_interval):
Matt Riedemann892094e2015-02-05 07:24:02 -0800270 raise exceptions.TimeoutException(
271 "No new port attached to the server in time (%s sec)! "
272 "Old port: %s. Number of new ports: %d" % (
273 CONF.network.build_timeout, old_port,
274 len(self.new_port_list)))
Steve Heyman33735f22016-05-24 09:28:08 -0500275 new_port = self.new_port_list[0]
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200276
277 def check_new_nic():
278 new_nic_list = self._get_server_nics(ssh_client)
279 self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
280 return len(self.diff_list) == 1
281
Jordan Pittier35a63752016-08-30 13:09:12 +0200282 if not test_utils.call_until_true(
283 check_new_nic, CONF.network.build_timeout,
284 CONF.network.build_interval):
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200285 raise exceptions.TimeoutException("Interface not visible on the "
286 "guest after %s sec"
287 % CONF.network.build_timeout)
288
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200289 _, new_nic = self.diff_list[0]
Ken'ichi Ohmichi679f8c32017-03-17 11:05:26 -0700290 ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
291 new_port['fixed_ips'][0]['ip_address'],
292 CONF.network.project_network_mask_bits,
293 new_nic))
Ken'ichi Ohmichi126fe982017-03-17 10:41:44 -0700294 ssh_client.exec_command("sudo ip link set %s up" % new_nic)
Yair Fried3097dc12014-01-26 08:46:43 +0200295
296 def _get_server_nics(self, ssh_client):
James Pagea9366272017-06-09 12:05:09 +0100297 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
Ken'ichi Ohmichi84aeba62017-03-01 18:31:20 -0800298 ipatxt = ssh_client.exec_command("ip address")
Yair Fried3097dc12014-01-26 08:46:43 +0200299 return reg.findall(ipatxt)
300
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300301 def _check_network_internal_connectivity(self, network,
302 should_connect=True):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000303 """via ssh check VM internal connectivity:
304
Yair Fried06552292013-11-11 12:10:09 +0200305 - ping internal gateway and DHCP port, implying in-tenant connectivity
306 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200307 """
308 floating_ip, server = self.floating_ip_tuple
309 # get internal ports' ips:
310 # get all network ports in the new network
Jordan Pittier64e6b442017-02-20 19:29:02 +0100311 internal_ips = (
312 p['fixed_ips'][0]['ip_address'] for p in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800313 self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100314 tenant_id=server['tenant_id'],
315 network_id=network['id'])['ports']
316 if p['device_owner'].startswith('network')
317 )
Yair Fried3097dc12014-01-26 08:46:43 +0200318
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300319 self._check_server_connectivity(floating_ip,
320 internal_ips,
321 should_connect)
Yair Fried06552292013-11-11 12:10:09 +0200322
323 def _check_network_external_connectivity(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000324 """ping default gateway to imply external connectivity"""
Yair Fried06552292013-11-11 12:10:09 +0200325 if not CONF.network.public_network_id:
326 msg = 'public network not defined.'
327 LOG.info(msg)
328 return
329
Andrew Boik4a3daf12015-03-27 01:59:31 -0400330 # We ping the external IP from the instance using its floating IP
331 # which is always IPv4, so we must only test connectivity to
332 # external IPv4 IPs if the external network is dualstack.
Jordan Pittier64e6b442017-02-20 19:29:02 +0100333 v4_subnets = [
jeremy.zhang5870ff12017-05-25 11:24:23 +0800334 s for s in self.os_admin.subnets_client.list_subnets(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100335 network_id=CONF.network.public_network_id)['subnets']
336 if s['ip_version'] == 4
337 ]
Andrew Boik4a3daf12015-03-27 01:59:31 -0400338 self.assertEqual(1, len(v4_subnets),
339 "Found %d IPv4 subnets" % len(v4_subnets))
Yair Fried06552292013-11-11 12:10:09 +0200340
Andrew Boik4a3daf12015-03-27 01:59:31 -0400341 external_ips = [v4_subnets[0]['gateway_ip']]
Yair Fried06552292013-11-11 12:10:09 +0200342 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
343 external_ips)
344
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300345 def _check_server_connectivity(self, floating_ip, address_list,
346 should_connect=True):
Steve Heyman33735f22016-05-24 09:28:08 -0500347 ip_address = floating_ip['floating_ip_address']
Yair Fried1fc32a12014-08-04 09:11:30 +0300348 private_key = self._get_server_key(self.floating_ip_tuple.server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100349 ssh_source = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800350 ip_address, private_key=private_key,
351 server=self.floating_ip_tuple.server)
Yair Fried3097dc12014-01-26 08:46:43 +0200352
Yair Fried06552292013-11-11 12:10:09 +0200353 for remote_ip in address_list:
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900354 self.check_remote_connectivity(ssh_source, remote_ip,
355 should_connect)
Yair Fried3097dc12014-01-26 08:46:43 +0200356
zhuflafe96b82017-09-22 14:25:29 +0800357 def _update_router_admin_state(self, router, admin_state_up):
358 kwargs = dict(admin_state_up=admin_state_up)
359 router = self.routers_client.update_router(
360 router['id'], **kwargs)['router']
361 self.assertEqual(admin_state_up, router['admin_state_up'])
362
Jordan Pittier3b46d272017-04-12 16:17:28 +0200363 @decorators.attr(type='smoke')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800364 @decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49')
Andrea Frittolicd368412017-08-14 21:37:56 +0100365 @utils.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000366 def test_network_basic_ops(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000367 """Basic network operation test
368
Yair Fried3097dc12014-01-26 08:46:43 +0200369 For a freshly-booted VM with an IP address ("port") on a given
370 network:
371
372 - the Tempest host can ping the IP address. This implies, but
373 does not guarantee (see the ssh check that follows), that the
374 VM has been assigned the correct IP address and has
375 connectivity to the Tempest host.
376
377 - the Tempest host can perform key-based authentication to an
378 ssh server hosted at the IP address. This check guarantees
379 that the IP address is associated with the target VM.
380
Yair Fried3097dc12014-01-26 08:46:43 +0200381 - the Tempest host can ssh into the VM via the IP address and
382 successfully execute the following:
383
384 - ping an external IP address, implying external connectivity.
385
386 - ping an external hostname, implying that dns is correctly
387 configured.
388
389 - ping an internal IP address, implying connectivity to another
390 VM on the same network.
391
Yair Fried06552292013-11-11 12:10:09 +0200392 - detach the floating-ip from the VM and verify that it becomes
393 unreachable
394
395 - associate detached floating ip to a new VM and verify connectivity.
396 VMs are created with unique keypair so connectivity also asserts that
397 floating IP is associated with the new VM instead of the old one
398
Yair Fried45f92952014-06-26 05:19:19 +0300399 Verifies that floating IP status is updated correctly after each change
400
Yair Fried06552292013-11-11 12:10:09 +0200401
Yair Fried3097dc12014-01-26 08:46:43 +0200402 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400403 self._setup_network_and_servers()
Yair Friedae0e73d2014-11-24 11:56:26 +0200404 self.check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200405 self._check_network_internal_connectivity(network=self.network)
406 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200407 self._disassociate_floating_ips()
Yair Friedae0e73d2014-11-24 11:56:26 +0200408 self.check_public_network_connectivity(should_connect=False,
409 msg="after disassociate "
410 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200411 self._reassociate_floating_ips()
Yair Friedae0e73d2014-11-24 11:56:26 +0200412 self.check_public_network_connectivity(should_connect=True,
413 msg="after re-associate "
414 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200415
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800416 @decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0')
Andrea Frittolicd368412017-08-14 21:37:56 +0100417 @testtools.skipUnless(utils.is_extension_enabled('net-mtu', 'network'),
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000418 'No way to calculate MTU for networks')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200419 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100420 @utils.services('compute', 'network')
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000421 def test_mtu_sized_frames(self):
422 """Validate that network MTU sized frames fit through."""
423 self._setup_network_and_servers()
Ihar Hrachyshkaaca29ed2017-09-25 12:13:53 -0700424 # first check that connectivity works in general for the instance
425 self.check_public_network_connectivity(should_connect=True)
426 # now that we checked general connectivity, test that full size frames
427 # can also pass between nodes
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000428 self.check_public_network_connectivity(
429 should_connect=True, mtu=self.network['mtu'])
430
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800431 @decorators.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15')
Thiago Paiva66cded22016-08-15 14:55:58 -0300432 @testtools.skipIf(CONF.network.shared_physical_network,
433 'Connectivity can only be tested when in a '
434 'multitenant network environment')
Sean Dague17487fb2016-08-08 10:44:20 -0400435 @decorators.skip_because(bug="1610994")
Jordan Pittier3b46d272017-04-12 16:17:28 +0200436 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100437 @utils.services('compute', 'network')
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300438 def test_connectivity_between_vms_on_different_networks(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000439 """Test connectivity between VMs on different networks
440
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300441 For a freshly-booted VM with an IP address ("port") on a given
442 network:
443
444 - the Tempest host can ping the IP address.
445
446 - the Tempest host can ssh into the VM via the IP address and
447 successfully execute the following:
448
449 - ping an external IP address, implying external connectivity.
450
451 - ping an external hostname, implying that dns is correctly
452 configured.
453
454 - ping an internal IP address, implying connectivity to another
455 VM on the same network.
456
457 - Create another network on the same tenant with subnet, create
458 an VM on the new network.
459
460 - Ping the new VM from previous VM failed since the new network
461 was not attached to router yet.
462
463 - Attach the new network to the router, Ping the new VM from
464 previous VM succeed.
465
466 """
467 self._setup_network_and_servers()
468 self.check_public_network_connectivity(should_connect=True)
469 self._check_network_internal_connectivity(network=self.network)
470 self._check_network_external_connectivity()
471 self._create_new_network(create_gateway=True)
zhufl24208c22016-10-25 15:23:48 +0800472 self._create_server(self.new_net)
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300473 self._check_network_internal_connectivity(network=self.new_net,
474 should_connect=False)
Steve Heyman33735f22016-05-24 09:28:08 -0500475 router_id = self.router['id']
476 self.routers_client.add_router_interface(
477 router_id, subnet_id=self.new_subnet['id'])
478
479 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
480 self.routers_client.remove_router_interface,
481 router_id, subnet_id=self.new_subnet['id'])
Fei Long Wang05a1c4a2015-02-02 16:58:24 +1300482 self._check_network_internal_connectivity(network=self.new_net,
483 should_connect=True)
484
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800485 @decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa')
Adam Gandelman7186f7a2014-07-23 09:28:56 -0400486 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
487 'NIC hotplug not available')
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200488 @testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'],
489 'NIC hotplug not supported for '
490 'vnic_type direct or macvtap')
Andrea Frittolicd368412017-08-14 21:37:56 +0100491 @utils.services('compute', 'network')
Yair Fried3097dc12014-01-26 08:46:43 +0200492 def test_hotplug_nic(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000493 """Test hotplug network interface
494
Arief3f6e812016-09-28 16:48:20 +0300495 1. Create a network and a VM.
496 2. Check connectivity to the VM via a public network.
497 3. Create a new network, with no gateway.
498 4. Bring up a new interface
499 5. check the VM reach the new network
Yair Fried3097dc12014-01-26 08:46:43 +0200500
501 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400502 self._setup_network_and_servers()
Yair Friedae0e73d2014-11-24 11:56:26 +0200503 self.check_public_network_connectivity(should_connect=True)
Yair Fried3097dc12014-01-26 08:46:43 +0200504 self._create_new_network()
505 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200506 self._check_network_internal_connectivity(network=self.new_net)
Alok Maurya6384bbb2014-07-13 06:44:29 -0700507
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800508 @decorators.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f')
Thiago Paiva66cded22016-08-15 14:55:58 -0300509 @testtools.skipIf(CONF.network.shared_physical_network,
510 'Router state can be altered only with multitenant '
511 'networks capabilities')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200512 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100513 @utils.services('compute', 'network')
Alok Maurya6384bbb2014-07-13 06:44:29 -0700514 def test_update_router_admin_state(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000515 """Test to update admin state up of router
516
Alok Maurya6384bbb2014-07-13 06:44:29 -0700517 1. Check public connectivity before updating
518 admin_state_up attribute of router to False
519 2. Check public connectivity after updating
520 admin_state_up attribute of router to False
521 3. Check public connectivity after updating
522 admin_state_up attribute of router to True
523 """
524 self._setup_network_and_servers()
525 self.check_public_network_connectivity(
526 should_connect=True, msg="before updating "
527 "admin_state_up of router to False")
528 self._update_router_admin_state(self.router, False)
529 # TODO(alokmaurya): Remove should_check_floating_ip_status=False check
530 # once bug 1396310 is fixed
531
532 self.check_public_network_connectivity(
533 should_connect=False, msg="after updating "
534 "admin_state_up of router to False",
535 should_check_floating_ip_status=False)
536 self._update_router_admin_state(self.router, True)
537 self.check_public_network_connectivity(
538 should_connect=True, msg="after updating "
539 "admin_state_up of router to True")
Yair Fried413bf2d2014-11-19 17:07:11 +0200540
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800541 @decorators.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980')
Thiago Paiva66cded22016-08-15 14:55:58 -0300542 @testtools.skipIf(CONF.network.shared_physical_network,
543 'network isolation not available')
Yair Fried413bf2d2014-11-19 17:07:11 +0200544 @testtools.skipUnless(CONF.scenario.dhcp_client,
545 "DHCP client is not available.")
Jordan Pittier3b46d272017-04-12 16:17:28 +0200546 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100547 @utils.services('compute', 'network')
Yair Fried413bf2d2014-11-19 17:07:11 +0200548 def test_subnet_details(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000549 """Tests that subnet's extra configuration details are affecting VMs.
550
551 This test relies on non-shared, isolated tenant networks.
Yair Fried413bf2d2014-11-19 17:07:11 +0200552
553 NOTE: Neutron subnets push data to servers via dhcp-agent, so any
554 update in subnet requires server to actively renew its DHCP lease.
555
556 1. Configure subnet with dns nameserver
557 2. retrieve the VM's configured dns and verify it matches the one
558 configured for the subnet.
559 3. update subnet's dns
560 4. retrieve the VM's configured dns and verify it matches the new one
561 configured for the subnet.
562
563 TODO(yfried): add host_routes
564
565 any resolution check would be testing either:
566 * l3 forwarding (tested in test_network_basic_ops)
567 * Name resolution of an external DNS nameserver - out of scope for
568 Tempest
569 """
570 # this test check only updates (no actual resolution) so using
571 # arbitrary ip addresses as nameservers, instead of parsing CONF
572 initial_dns_server = '1.2.3.4'
573 alt_dns_server = '9.8.7.6'
Yair Friedbb0ea392015-01-19 07:26:08 +0000574
575 # renewal should be immediate.
576 # Timeouts are suggested by salvatore-orlando in
577 # https://bugs.launchpad.net/neutron/+bug/1412325/comments/3
578 renew_delay = CONF.network.build_interval
579 renew_timeout = CONF.network.build_timeout
580
Yair Fried413bf2d2014-11-19 17:07:11 +0200581 self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
582 self.check_public_network_connectivity(should_connect=True)
583
584 floating_ip, server = self.floating_ip_tuple
Steve Heyman33735f22016-05-24 09:28:08 -0500585 ip_address = floating_ip['floating_ip_address']
Yair Fried413bf2d2014-11-19 17:07:11 +0200586 private_key = self._get_server_key(server)
Jordan Pittierbbb17122016-01-26 17:10:55 +0100587 ssh_client = self.get_remote_client(
zhuflf52c7592017-05-25 13:55:24 +0800588 ip_address, private_key=private_key, server=server)
Yair Fried413bf2d2014-11-19 17:07:11 +0200589
armando-migliaccio424aa412015-02-22 17:55:17 -0800590 dns_servers = [initial_dns_server]
591 servers = ssh_client.get_dns_servers()
592 self.assertEqual(set(dns_servers), set(servers),
593 'Looking for servers: {trgt_serv}. '
594 'Retrieved DNS nameservers: {act_serv} '
595 'From host: {host}.'
596 .format(host=ssh_client.ssh_client.host,
597 act_serv=servers,
598 trgt_serv=dns_servers))
Yair Fried413bf2d2014-11-19 17:07:11 +0200599
Steve Heyman33735f22016-05-24 09:28:08 -0500600 self.subnet = self.subnets_client.update_subnet(
601 self.subnet['id'], dns_nameservers=[alt_dns_server])['subnet']
602
Yair Fried413bf2d2014-11-19 17:07:11 +0200603 # asserts that Neutron DB has updated the nameservers
Steve Heyman33735f22016-05-24 09:28:08 -0500604 self.assertEqual([alt_dns_server], self.subnet['dns_nameservers'],
Yair Fried413bf2d2014-11-19 17:07:11 +0200605 "Failed to update subnet's nameservers")
606
Yair Friedbb0ea392015-01-19 07:26:08 +0000607 def check_new_dns_server():
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000608 # NOTE: Server needs to renew its dhcp lease in order to get new
609 # definitions from subnet
610 # NOTE(amuller): we are renewing the lease as part of the retry
611 # because Neutron updates dnsmasq asynchronously after the
612 # subnet-update API call returns.
Ken'ichi Ohmichi4e337852017-03-01 12:04:23 -0800613 ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'],
614 dhcp_client=CONF.scenario.dhcp_client)
armando-migliaccio424aa412015-02-22 17:55:17 -0800615 if ssh_client.get_dns_servers() != [alt_dns_server]:
Yair Friedbb0ea392015-01-19 07:26:08 +0000616 LOG.debug("Failed to update DNS nameservers")
617 return False
618 return True
619
Jordan Pittier35a63752016-08-30 13:09:12 +0200620 self.assertTrue(test_utils.call_until_true(check_new_dns_server,
621 renew_timeout,
622 renew_delay),
Yair Friedbb0ea392015-01-19 07:26:08 +0000623 msg="DHCP renewal failed to fetch "
624 "new DNS nameservers")
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800625
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800626 @decorators.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b')
Itzik Brownbeb30d32015-03-29 09:42:54 +0300627 @testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change,
628 "Changing a port's admin state is not supported "
629 "by the test environment")
Jordan Pittier3b46d272017-04-12 16:17:28 +0200630 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100631 @utils.services('compute', 'network')
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800632 def test_update_instance_port_admin_state(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000633 """Test to update admin_state_up attribute of instance port
634
Carlos Goncalves539f8362016-11-04 14:55:02 +0100635 1. Check public and project connectivity before updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800636 admin_state_up attribute of instance port to False
Carlos Goncalves539f8362016-11-04 14:55:02 +0100637 2. Check public and project connectivity after updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800638 admin_state_up attribute of instance port to False
Carlos Goncalves539f8362016-11-04 14:55:02 +0100639 3. Check public and project connectivity after updating
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800640 admin_state_up attribute of instance port to True
641 """
642 self._setup_network_and_servers()
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200643 _, server = self.floating_ip_tuple
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800644 server_id = server['id']
jeremy.zhang5870ff12017-05-25 11:24:23 +0800645 port_id = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100646 device_id=server_id)['ports'][0]['id']
Carlos Goncalves539f8362016-11-04 14:55:02 +0100647 server_pip = server['addresses'][self.network['name']][0]['addr']
648
649 server2 = self._create_server(self.network)
650 server2_fip = self.create_floating_ip(server2)
651
652 private_key = self._get_server_key(server2)
653 ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
zhuflf52c7592017-05-25 13:55:24 +0800654 private_key=private_key,
655 server=server2)
Carlos Goncalves539f8362016-11-04 14:55:02 +0100656
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800657 self.check_public_network_connectivity(
658 should_connect=True, msg="before updating "
659 "admin_state_up of instance port to False")
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900660 self.check_remote_connectivity(ssh_client, dest=server_pip,
661 should_succeed=True)
John Warren49c0fe52015-10-22 12:35:54 -0400662 self.ports_client.update_port(port_id, admin_state_up=False)
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800663 self.check_public_network_connectivity(
664 should_connect=False, msg="after updating "
665 "admin_state_up of instance port to False",
666 should_check_floating_ip_status=False)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900667 self.check_remote_connectivity(ssh_client, dest=server_pip,
668 should_succeed=False)
John Warren49c0fe52015-10-22 12:35:54 -0400669 self.ports_client.update_port(port_id, admin_state_up=True)
Thalabathy Venkatesan76553d82015-01-07 22:54:39 -0800670 self.check_public_network_connectivity(
671 should_connect=True, msg="after updating "
672 "admin_state_up of instance port to True")
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900673 self.check_remote_connectivity(ssh_client, dest=server_pip,
674 should_succeed=True)
Matt Riedemann17940732015-03-13 14:18:19 +0000675
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800676 @decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200677 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100678 @utils.services('compute', 'network')
Matt Riedemann17940732015-03-13 14:18:19 +0000679 def test_preserve_preexisting_port(self):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000680 """Test preserve pre-existing port
681
682 Tests that a pre-existing port provided on server boot is not deleted
683 if the server is deleted.
Matt Riedemann17940732015-03-13 14:18:19 +0000684
685 Nova should unbind the port from the instance on delete if the port was
686 not created by Nova as part of the boot request.
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400687
688 We should also be able to boot another server with the same port.
Matt Riedemann17940732015-03-13 14:18:19 +0000689 """
690 # Setup the network, create a port and boot the server from that port.
691 self._setup_network_and_servers(boot_with_port=True)
692 _, server = self.floating_ip_tuple
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000693 self.assertEqual(1, len(self.ports),
694 'There should only be one port created for '
695 'server %s.' % server['id'])
696 port_id = self.ports[0]['port']
697 self.assertIsNotNone(port_id,
Matt Riedemann17940732015-03-13 14:18:19 +0000698 'Server should have been created from a '
699 'pre-existing port.')
700 # Assert the port is bound to the server.
jeremy.zhang5870ff12017-05-25 11:24:23 +0800701 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100702 device_id=server['id'], network_id=self.network['id'])['ports']
Matt Riedemann17940732015-03-13 14:18:19 +0000703 self.assertEqual(1, len(port_list),
704 'There should only be one port created for '
705 'server %s.' % server['id'])
Shuquan Huangb5c8beb2015-08-05 14:14:01 +0000706 self.assertEqual(port_id, port_list[0]['id'])
Matt Riedemann17940732015-03-13 14:18:19 +0000707 # Delete the server.
708 self.servers_client.delete_server(server['id'])
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000709 waiters.wait_for_server_termination(self.servers_client, server['id'])
Matt Riedemann17940732015-03-13 14:18:19 +0000710 # Assert the port still exists on the network but is unbound from
711 # the deleted server.
John Warren49c0fe52015-10-22 12:35:54 -0400712 port = self.ports_client.show_port(port_id)['port']
Matt Riedemann17940732015-03-13 14:18:19 +0000713 self.assertEqual(self.network['id'], port['network_id'])
714 self.assertEqual('', port['device_id'])
715 self.assertEqual('', port['device_owner'])
Yair Fried564d89d2015-08-06 17:02:12 +0300716
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400717 # Boot another server with the same port to make sure nothing was
718 # left around that could cause issues.
zhufl24208c22016-10-25 15:23:48 +0800719 server = self._create_server(self.network, port['id'])
jeremy.zhang5870ff12017-05-25 11:24:23 +0800720 port_list = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100721 device_id=server['id'], network_id=self.network['id'])['ports']
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400722 self.assertEqual(1, len(port_list),
723 'There should only be one port created for '
724 'server %s.' % server['id'])
725 self.assertEqual(port['id'], port_list[0]['id'])
726
Andrea Frittolicd368412017-08-14 21:37:56 +0100727 @utils.requires_ext(service='network', extension='l3_agent_scheduler')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800728 @decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200729 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100730 @utils.services('compute', 'network')
Yair Fried564d89d2015-08-06 17:02:12 +0300731 def test_router_rescheduling(self):
732 """Tests that router can be removed from agent and add to a new agent.
733
734 1. Verify connectivity
735 2. Remove router from all l3-agents
736 3. Verify connectivity is down
737 4. Assign router to new l3-agent (or old one if no new agent is
738 available)
739 5. Verify connectivity
740 """
741
742 # TODO(yfried): refactor this test to be used for other agents (dhcp)
743 # as well
744
jeremy.zhang5870ff12017-05-25 11:24:23 +0800745 list_hosts = (self.os_admin.routers_client.
Yair Fried564d89d2015-08-06 17:02:12 +0300746 list_l3_agents_hosting_router)
jeremy.zhang5870ff12017-05-25 11:24:23 +0800747 schedule_router = (self.os_admin.network_agents_client.
Ken'ichi Ohmichi70a24e92016-01-06 01:08:27 +0000748 create_router_on_l3_agent)
jeremy.zhang5870ff12017-05-25 11:24:23 +0800749 unschedule_router = (self.os_admin.network_agents_client.
Ken'ichi Ohmichi70a24e92016-01-06 01:08:27 +0000750 delete_router_from_l3_agent)
Yair Fried564d89d2015-08-06 17:02:12 +0300751
Jordan Pittier64e6b442017-02-20 19:29:02 +0100752 agent_list_alive = set(
753 a["id"] for a in
jeremy.zhang5870ff12017-05-25 11:24:23 +0800754 self.os_admin.network_agents_client.list_agents(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100755 agent_type="L3 agent")['agents'] if a["alive"] is True
756 )
Yair Fried564d89d2015-08-06 17:02:12 +0300757 self._setup_network_and_servers()
Kevin Benton3b63aa12015-08-27 17:15:44 -0700758
759 # NOTE(kevinbenton): we have to use the admin credentials to check
Sean Dagueed6e5862016-04-04 10:49:13 -0400760 # for the distributed flag because self.router only has a project view.
jeremy.zhang5870ff12017-05-25 11:24:23 +0800761 admin = self.os_admin.routers_client.show_router(
Steve Heyman33735f22016-05-24 09:28:08 -0500762 self.router['id'])
Kevin Benton3b63aa12015-08-27 17:15:44 -0700763 if admin['router'].get('distributed', False):
764 msg = "Rescheduling test does not apply to distributed routers."
765 raise self.skipException(msg)
766
Yair Fried564d89d2015-08-06 17:02:12 +0300767 self.check_public_network_connectivity(should_connect=True)
768
769 # remove resource from agents
770 hosting_agents = set(a["id"] for a in
Steve Heyman33735f22016-05-24 09:28:08 -0500771 list_hosts(self.router['id'])['agents'])
shipeiqic9a4a102016-04-20 17:39:03 +0800772 no_migration = agent_list_alive == hosting_agents
Yair Fried564d89d2015-08-06 17:02:12 +0300773 LOG.info("Router will be assigned to {mig} hosting agent".
774 format(mig="the same" if no_migration else "a new"))
775
776 for hosting_agent in hosting_agents:
Steve Heyman33735f22016-05-24 09:28:08 -0500777 unschedule_router(hosting_agent, self.router['id'])
Yair Fried564d89d2015-08-06 17:02:12 +0300778 self.assertNotIn(hosting_agent,
779 [a["id"] for a in
Steve Heyman33735f22016-05-24 09:28:08 -0500780 list_hosts(self.router['id'])['agents']],
Yair Fried564d89d2015-08-06 17:02:12 +0300781 'unscheduling router failed')
782
783 # verify resource is un-functional
784 self.check_public_network_connectivity(
785 should_connect=False,
786 msg='after router unscheduling',
Yair Fried564d89d2015-08-06 17:02:12 +0300787 )
788
789 # schedule resource to new agent
790 target_agent = list(hosting_agents if no_migration else
shipeiqic9a4a102016-04-20 17:39:03 +0800791 agent_list_alive - hosting_agents)[0]
Yair Fried564d89d2015-08-06 17:02:12 +0300792 schedule_router(target_agent,
piyush110786bc0faa62015-12-03 14:54:48 +0530793 router_id=self.router['id'])
Yair Fried564d89d2015-08-06 17:02:12 +0300794 self.assertEqual(
795 target_agent,
Steve Heyman33735f22016-05-24 09:28:08 -0500796 list_hosts(self.router['id'])['agents'][0]['id'],
Yair Fried564d89d2015-08-06 17:02:12 +0300797 "Router failed to reschedule. Hosting agent doesn't match "
798 "target agent")
799
800 # verify resource is functional
801 self.check_public_network_connectivity(
802 should_connect=True,
803 msg='After router rescheduling')
Yair Friedbc46f592015-11-18 16:29:34 +0200804
Andrea Frittolicd368412017-08-14 21:37:56 +0100805 @utils.requires_ext(service='network', extension='port-security')
Evgeny Antyshevaaf3fc92016-02-15 11:49:22 +0000806 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
807 'NIC hotplug not available')
Ken'ichi Ohmichic85a9512017-01-27 18:34:24 -0800808 @decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63')
Jordan Pittier3b46d272017-04-12 16:17:28 +0200809 @decorators.attr(type='slow')
Andrea Frittolicd368412017-08-14 21:37:56 +0100810 @utils.services('compute', 'network')
Yair Friedbc46f592015-11-18 16:29:34 +0200811 def test_port_security_macspoofing_port(self):
812 """Tests port_security extension enforces mac spoofing
813
Eran Kuris7969e802015-12-15 13:43:46 +0200814 Neutron security groups always apply anti-spoof rules on the VMs. This
815 allows traffic to originate and terminate at the VM as expected, but
816 prevents traffic to pass through the VM. Anti-spoof rules are not
817 required in cases where the VM routes traffic through it.
818
819 The test steps are :
820 1. Create a new network.
821 2. Connect (hotplug) the VM to a new network.
YAMAMOTO Takashic3978412015-11-30 23:55:56 +0900822 3. Check the VM can ping a server on the new network ("peer")
Eran Kuris7969e802015-12-15 13:43:46 +0200823 4. Spoof the mac address of the new VM interface.
824 5. Check the Security Group enforces mac spoofing and blocks pings via
YAMAMOTO Takashic3978412015-11-30 23:55:56 +0900825 spoofed interface (VM cannot ping the peer).
Eran Kuris7969e802015-12-15 13:43:46 +0200826 6. Disable port-security of the spoofed port- set the flag to false.
827 7. Retest 3rd step and check that the Security Group allows pings via
828 the spoofed interface.
Yair Friedbc46f592015-11-18 16:29:34 +0200829 """
Eran Kuris7969e802015-12-15 13:43:46 +0200830
Yair Friedbc46f592015-11-18 16:29:34 +0200831 spoof_mac = "00:00:00:00:00:01"
832
833 # Create server
834 self._setup_network_and_servers()
YAMAMOTO Takashic368dde2015-11-30 23:04:14 +0900835 self.check_public_network_connectivity(should_connect=True)
Yair Friedbc46f592015-11-18 16:29:34 +0200836 self._create_new_network()
837 self._hotplug_server()
838 fip, server = self.floating_ip_tuple
jeremy.zhang5870ff12017-05-25 11:24:23 +0800839 new_ports = self.os_admin.ports_client.list_ports(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100840 device_id=server["id"], network_id=self.new_net["id"])['ports']
Yair Friedbc46f592015-11-18 16:29:34 +0200841 spoof_port = new_ports[0]
842 private_key = self._get_server_key(server)
Steve Heyman33735f22016-05-24 09:28:08 -0500843 ssh_client = self.get_remote_client(fip['floating_ip_address'],
zhuflf52c7592017-05-25 13:55:24 +0800844 private_key=private_key,
845 server=server)
Evgeny Antyshev9b77ae52016-02-16 09:48:57 +0000846 spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
zhufl24208c22016-10-25 15:23:48 +0800847 peer = self._create_server(self.new_net)
Steve Heyman33735f22016-05-24 09:28:08 -0500848 peer_address = peer['addresses'][self.new_net['name']][0]['addr']
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900849 self.check_remote_connectivity(ssh_client, dest=peer_address,
850 nic=spoof_nic, should_succeed=True)
Ken'ichi Ohmichi5129c622017-03-22 11:18:42 -0700851 # Set a mac address by making nic down temporary
852 cmd = ("sudo ip link set {nic} down;"
853 "sudo ip link set dev {nic} address {mac};"
854 "sudo ip link set {nic} up").format(nic=spoof_nic,
855 mac=spoof_mac)
856 ssh_client.exec_command(cmd)
857
Yair Friedbc46f592015-11-18 16:29:34 +0200858 new_mac = ssh_client.get_mac_address(nic=spoof_nic)
859 self.assertEqual(spoof_mac, new_mac)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900860 self.check_remote_connectivity(ssh_client, dest=peer_address,
861 nic=spoof_nic, should_succeed=False)
Yair Friedbc46f592015-11-18 16:29:34 +0200862 self.ports_client.update_port(spoof_port["id"],
863 port_security_enabled=False,
864 security_groups=[])
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +0900865 self.check_remote_connectivity(ssh_client, dest=peer_address,
866 nic=spoof_nic, should_succeed=True)