blob: 81cfd910edd022eeaf742f08510c8c31d24c552e [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
Adam Gandelman7186f7a2014-07-23 09:28:56 -040019import testtools
Yair Fried3097dc12014-01-26 08:46:43 +020020
Attila Fazekasaeeeefd2013-08-06 17:01:56 +020021from tempest.common import debug
Masayuki Igawa259c1132013-10-31 17:48:44 +090022from tempest.common.utils import data_utils
Matthew Treinishcb569942013-08-09 16:33:44 -040023from tempest import config
Attila Fazekasa8bb3942014-08-19 09:06:30 +020024from tempest import exceptions
Matthew Treinish2b59f842013-09-09 20:32:51 +000025from tempest.openstack.common import log as logging
Sean Dague6dbc6da2013-05-08 17:49:46 -040026from tempest.scenario import manager
Yair Fried1fc32a12014-08-04 09:11:30 +030027from tempest.services.network import resources as net_resources
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090028from tempest import test
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
Yair Fried1fc32a12014-08-04 09:11:30 +030037class TestNetworkBasicOps(manager.NeutronScenarioTest):
Maru Newby81f07a02012-09-05 20:21:19 -070038
39 """
40 This smoke test suite assumes that Nova has been configured to
Mark McClainf2982e82013-07-06 17:48:03 -040041 boot VM's with Neutron-managed networking, and attempts to
Maru Newby81f07a02012-09-05 20:21:19 -070042 verify network connectivity as follows:
43
Maru Newby81f07a02012-09-05 20:21:19 -070044 There are presumed to be two types of networks: tenant and
45 public. A tenant network may or may not be reachable from the
46 Tempest host. A public network is assumed to be reachable from
47 the Tempest host, and it should be possible to associate a public
48 ('floating') IP address with a tenant ('fixed') IP address to
Chang Bo Guocc1623c2013-09-13 20:11:27 -070049 facilitate external connectivity to a potentially unroutable
Maru Newby81f07a02012-09-05 20:21:19 -070050 tenant IP address.
51
52 This test suite can be configured to test network connectivity to
53 a VM via a tenant network, a public network, or both. If both
54 networking types are to be evaluated, tests that need to be
55 executed remotely on the VM (via ssh) will only be run against
56 one of the networks (to minimize test execution time).
57
58 Determine which types of networks to test as follows:
59
60 * Configure tenant network checks (via the
61 'tenant_networks_reachable' key) if the Tempest host should
62 have direct connectivity to tenant networks. This is likely to
63 be the case if Tempest is running on the same host as a
64 single-node devstack installation with IP namespaces disabled.
65
66 * Configure checks for a public network if a public network has
67 been configured prior to the test suite being run and if the
68 Tempest host should have connectivity to that public network.
69 Checking connectivity for a public network requires that a
70 value be provided for 'public_network_id'. A value can
71 optionally be provided for 'public_router_id' if tenants will
72 use a shared router to access a public network (as is likely to
73 be the case when IP namespaces are not enabled). If a value is
74 not provided for 'public_router_id', a router will be created
75 for each tenant and use the network identified by
76 'public_network_id' as its gateway.
77
78 """
79
80 @classmethod
81 def check_preconditions(cls):
Gavin Brebner0f465a32013-03-14 13:26:09 +000082 super(TestNetworkBasicOps, cls).check_preconditions()
Matthew Treinish6c072292014-01-29 19:15:52 +000083 if not (CONF.network.tenant_networks_reachable
84 or CONF.network.public_network_id):
Maru Newby81f07a02012-09-05 20:21:19 -070085 msg = ('Either tenant_networks_reachable must be "true", or '
86 'public_network_id must be defined.')
Gavin Brebner0f465a32013-03-14 13:26:09 +000087 cls.enabled = False
ivan-zhu1feeb382013-01-24 10:14:39 +080088 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070089
90 @classmethod
91 def setUpClass(cls):
Yair Fried764610a2014-04-07 12:17:05 +030092 # Create no network resources for these tests.
93 cls.set_network_resources()
Maru Newby81f07a02012-09-05 20:21:19 -070094 super(TestNetworkBasicOps, cls).setUpClass()
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090095 for ext in ['router', 'security-group']:
96 if not test.is_extension_enabled(ext, 'network'):
97 msg = "%s extension not enabled." % ext
98 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070099
Yair Frieded8392f2014-01-15 17:21:35 +0200100 def setUp(self):
101 super(TestNetworkBasicOps, self).setUp()
102 self.security_group = \
Yair Fried1fc32a12014-08-04 09:11:30 +0300103 self._create_security_group(tenant_id=self.tenant_id)
Yair Frieded8392f2014-01-15 17:21:35 +0200104 self.network, self.subnet, self.router = self._create_networks()
Yair Frieded8392f2014-01-15 17:21:35 +0200105 self.check_networks()
Yair Fried1fc32a12014-08-04 09:11:30 +0300106 self.keypairs = {}
107 self.servers = []
Yair Frieded8392f2014-01-15 17:21:35 +0200108 name = data_utils.rand_name('server-smoke')
Yair Fried1fc32a12014-08-04 09:11:30 +0300109 server = self._create_server(name, self.network)
Yair Frieded8392f2014-01-15 17:21:35 +0200110 self._check_tenant_network_connectivity()
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200111
Yair Fried1fc32a12014-08-04 09:11:30 +0300112 self._create_and_associate_floating_ips(server)
Maru Newby81f07a02012-09-05 20:21:19 -0700113
Yair Frieded8392f2014-01-15 17:21:35 +0200114 def check_networks(self):
115 """
116 Checks that we see the newly created network/subnet/router via
117 checking the result of list_[networks,routers,subnets]
118 """
119
Gavin Brebner851c3502013-01-18 13:14:10 +0000120 seen_nets = self._list_networks()
121 seen_names = [n['name'] for n in seen_nets]
122 seen_ids = [n['id'] for n in seen_nets]
Yair Frieded8392f2014-01-15 17:21:35 +0200123 self.assertIn(self.network.name, seen_names)
124 self.assertIn(self.network.id, seen_ids)
125
Gavin Brebner851c3502013-01-18 13:14:10 +0000126 seen_subnets = self._list_subnets()
127 seen_net_ids = [n['network_id'] for n in seen_subnets]
128 seen_subnet_ids = [n['id'] for n in seen_subnets]
Yair Frieded8392f2014-01-15 17:21:35 +0200129 self.assertIn(self.network.id, seen_net_ids)
130 self.assertIn(self.subnet.id, seen_subnet_ids)
131
Gavin Brebner851c3502013-01-18 13:14:10 +0000132 seen_routers = self._list_routers()
133 seen_router_ids = [n['id'] for n in seen_routers]
134 seen_router_names = [n['name'] for n in seen_routers]
Yair Frieded8392f2014-01-15 17:21:35 +0200135 self.assertIn(self.router.name,
136 seen_router_names)
137 self.assertIn(self.router.id,
138 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000139
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700140 def _create_server(self, name, network):
Yair Fried1fc32a12014-08-04 09:11:30 +0300141 keypair = self.create_keypair()
142 self.keypairs[keypair['name']] = keypair
143 security_groups = [self.security_group]
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700144 create_kwargs = {
145 'nics': [
146 {'net-id': network.id},
147 ],
Yair Fried1fc32a12014-08-04 09:11:30 +0300148 'key_name': keypair['name'],
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700149 'security_groups': security_groups,
150 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200151 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300152 self.servers.append(server)
153 return server
154
155 def _get_server_key(self, server):
156 return self.keypairs[server['key_name']]['private_key']
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700157
Matthew Treinish2b59f842013-09-09 20:32:51 +0000158 def _check_tenant_network_connectivity(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500159 ssh_login = CONF.compute.image_ssh_user
Yair Fried1fc32a12014-08-04 09:11:30 +0300160 for server in self.servers:
Matt Riedemann2d005be2014-05-27 10:52:35 -0700161 # call the common method in the parent class
162 super(TestNetworkBasicOps, self).\
163 _check_tenant_network_connectivity(
Yair Fried1fc32a12014-08-04 09:11:30 +0300164 server, ssh_login, self._get_server_key(server),
165 servers_for_debug=self.servers)
Brent Eaglesc26d4522013-12-02 13:28:49 -0500166
Yair Fried1fc32a12014-08-04 09:11:30 +0300167 def _create_and_associate_floating_ips(self, server):
Sean Dague86bd8422013-12-20 09:56:44 -0500168 public_network_id = CONF.network.public_network_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300169 floating_ip = self._create_floating_ip(server, public_network_id)
170 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Maru Newby81f07a02012-09-05 20:21:19 -0700171
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200172 def _check_public_network_connectivity(self, should_connect=True,
173 msg=None):
Sean Dague86bd8422013-12-20 09:56:44 -0500174 ssh_login = CONF.compute.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200175 floating_ip, server = self.floating_ip_tuple
176 ip_address = floating_ip.floating_ip_address
177 private_key = None
178 if should_connect:
Yair Fried1fc32a12014-08-04 09:11:30 +0300179 private_key = self._get_server_key(server)
Matt Riedemann343305f2014-05-27 09:55:03 -0700180 # call the common method in the parent class
181 super(TestNetworkBasicOps, self)._check_public_network_connectivity(
182 ip_address, ssh_login, private_key, should_connect, msg,
Yair Fried1fc32a12014-08-04 09:11:30 +0300183 self.servers)
Matthew Treinish2b59f842013-09-09 20:32:51 +0000184
Yair Fried9a551c42013-12-15 14:59:34 +0200185 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200186 floating_ip, server = self.floating_ip_tuple
187 self._disassociate_floating_ip(floating_ip)
188 self.floating_ip_tuple = Floating_IP_tuple(
189 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200190
Yair Fried05db2522013-11-18 11:02:10 +0200191 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200192 floating_ip, server = self.floating_ip_tuple
193 name = data_utils.rand_name('new_server-smoke-')
194 # create a new server for the floating ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300195 server = self._create_server(name, self.network)
196 self._associate_floating_ip(floating_ip, server)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200197 self.floating_ip_tuple = Floating_IP_tuple(
Yair Fried1fc32a12014-08-04 09:11:30 +0300198 floating_ip, server)
Yair Fried05db2522013-11-18 11:02:10 +0200199
Yair Fried3097dc12014-01-26 08:46:43 +0200200 def _create_new_network(self):
201 self.new_net = self._create_network(self.tenant_id)
Yair Fried3097dc12014-01-26 08:46:43 +0200202 self.new_subnet = self._create_subnet(
203 network=self.new_net,
204 gateway_ip=None)
Yair Fried3097dc12014-01-26 08:46:43 +0200205
206 def _hotplug_server(self):
207 old_floating_ip, server = self.floating_ip_tuple
208 ip_address = old_floating_ip.floating_ip_address
Yair Fried1fc32a12014-08-04 09:11:30 +0300209 private_key = self._get_server_key(server)
Yair Fried3097dc12014-01-26 08:46:43 +0200210 ssh_client = self.get_remote_client(ip_address,
211 private_key=private_key)
212 old_nic_list = self._get_server_nics(ssh_client)
213 # get a port from a list of one item
Yair Fried1fc32a12014-08-04 09:11:30 +0300214 port_list = self._list_ports(device_id=server['id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200215 self.assertEqual(1, len(port_list))
216 old_port = port_list[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300217 _, interface = self.interface_client.create_interface(
218 server=server['id'],
219 network_id=self.new_net.id)
220 self.addCleanup(self.network_client.wait_for_resource_deletion,
221 'port',
222 interface['port_id'])
223 self.addCleanup(self.delete_wrapper,
224 self.interface_client.delete_interface,
225 server['id'], interface['port_id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200226
227 def check_ports():
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200228 self.new_port_list = [port for port in
Yair Fried1fc32a12014-08-04 09:11:30 +0300229 self._list_ports(device_id=server['id'])
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200230 if port != old_port]
231 return len(self.new_port_list) == 1
Yair Fried3097dc12014-01-26 08:46:43 +0200232
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200233 if not test.call_until_true(check_ports, CONF.network.build_timeout,
234 CONF.network.build_interval):
235 raise exceptions.TimeoutException("No new port attached to the "
236 "server in time (%s sec) !"
237 % CONF.network.build_timeout)
Yair Fried1fc32a12014-08-04 09:11:30 +0300238 new_port = net_resources.DeletablePort(client=self.network_client,
239 **self.new_port_list[0])
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200240
241 def check_new_nic():
242 new_nic_list = self._get_server_nics(ssh_client)
243 self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
244 return len(self.diff_list) == 1
245
246 if not test.call_until_true(check_new_nic, CONF.network.build_timeout,
247 CONF.network.build_interval):
248 raise exceptions.TimeoutException("Interface not visible on the "
249 "guest after %s sec"
250 % CONF.network.build_timeout)
251
252 num, new_nic = self.diff_list[0]
Yair Fried3097dc12014-01-26 08:46:43 +0200253 ssh_client.assign_static_ip(nic=new_nic,
254 addr=new_port.fixed_ips[0]['ip_address'])
255 ssh_client.turn_nic_on(nic=new_nic)
256
257 def _get_server_nics(self, ssh_client):
258 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
259 ipatxt = ssh_client.get_ip_list()
260 return reg.findall(ipatxt)
261
Yair Fried06552292013-11-11 12:10:09 +0200262 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200263 """
264 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200265 - ping internal gateway and DHCP port, implying in-tenant connectivity
266 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200267 """
268 floating_ip, server = self.floating_ip_tuple
269 # get internal ports' ips:
270 # get all network ports in the new network
271 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
Yair Fried1fc32a12014-08-04 09:11:30 +0300272 self._list_ports(tenant_id=server['tenant_id'],
Yair Fried06552292013-11-11 12:10:09 +0200273 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200274 if p['device_owner'].startswith('network'))
275
Yair Fried06552292013-11-11 12:10:09 +0200276 self._check_server_connectivity(floating_ip, internal_ips)
277
278 def _check_network_external_connectivity(self):
279 """
280 ping public network default gateway to imply external connectivity
281
282 """
283 if not CONF.network.public_network_id:
284 msg = 'public network not defined.'
285 LOG.info(msg)
286 return
287
Yair Fried1fc32a12014-08-04 09:11:30 +0300288 subnet = self._list_subnets(
289 network_id=CONF.network.public_network_id)
Yair Fried06552292013-11-11 12:10:09 +0200290 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
291
292 external_ips = [subnet[0]['gateway_ip']]
293 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
294 external_ips)
295
296 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200297 ip_address = floating_ip.floating_ip_address
Yair Fried1fc32a12014-08-04 09:11:30 +0300298 private_key = self._get_server_key(self.floating_ip_tuple.server)
Yair Fried3097dc12014-01-26 08:46:43 +0200299 ssh_source = self._ssh_to_server(ip_address, private_key)
300
Yair Fried06552292013-11-11 12:10:09 +0200301 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200302 try:
303 self.assertTrue(self._check_remote_connectivity(ssh_source,
304 remote_ip),
305 "Timed out waiting for %s to become "
306 "reachable" % remote_ip)
307 except Exception:
308 LOG.exception("Unable to access {dest} via ssh to "
309 "floating-ip {src}".format(dest=remote_ip,
310 src=floating_ip))
311 debug.log_ip_ns()
312 raise
313
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900314 @test.attr(type='smoke')
315 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000316 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200317 """
318 For a freshly-booted VM with an IP address ("port") on a given
319 network:
320
321 - the Tempest host can ping the IP address. This implies, but
322 does not guarantee (see the ssh check that follows), that the
323 VM has been assigned the correct IP address and has
324 connectivity to the Tempest host.
325
326 - the Tempest host can perform key-based authentication to an
327 ssh server hosted at the IP address. This check guarantees
328 that the IP address is associated with the target VM.
329
Yair Fried3097dc12014-01-26 08:46:43 +0200330 - the Tempest host can ssh into the VM via the IP address and
331 successfully execute the following:
332
333 - ping an external IP address, implying external connectivity.
334
335 - ping an external hostname, implying that dns is correctly
336 configured.
337
338 - ping an internal IP address, implying connectivity to another
339 VM on the same network.
340
Yair Fried06552292013-11-11 12:10:09 +0200341 - detach the floating-ip from the VM and verify that it becomes
342 unreachable
343
344 - associate detached floating ip to a new VM and verify connectivity.
345 VMs are created with unique keypair so connectivity also asserts that
346 floating IP is associated with the new VM instead of the old one
347
348
Yair Fried3097dc12014-01-26 08:46:43 +0200349 """
Yair Fried9a551c42013-12-15 14:59:34 +0200350 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200351 self._check_network_internal_connectivity(network=self.network)
352 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200353 self._disassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200354 self._check_public_network_connectivity(should_connect=False,
355 msg="after disassociate "
356 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200357 self._reassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200358 self._check_public_network_connectivity(should_connect=True,
359 msg="after re-associate "
360 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200361
Adam Gandelman7186f7a2014-07-23 09:28:56 -0400362 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
363 'NIC hotplug not available')
Yair Fried3097dc12014-01-26 08:46:43 +0200364 @test.attr(type='smoke')
365 @test.services('compute', 'network')
366 def test_hotplug_nic(self):
367 """
368 1. create a new network, with no gateway (to prevent overwriting VM's
369 gateway)
370 2. connect VM to new network
371 3. set static ip and bring new nic up
372 4. check VM can ping new network dhcp port
373
374 """
375
376 self._check_public_network_connectivity(should_connect=True)
377 self._create_new_network()
378 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200379 self._check_network_internal_connectivity(network=self.new_net)