blob: d5ab3d38c5c6e76dc87d7ef7eeb425608c3bba2f [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
Maru Newby81f07a02012-09-05 20:21:19 -070017
Yair Fried3097dc12014-01-26 08:46:43 +020018import re
19
20from tempest.api.network import common as net_common
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
Matthew Treinish2b59f842013-09-09 20:32:51 +000024from tempest.openstack.common import log as logging
Sean Dague6dbc6da2013-05-08 17:49:46 -040025from tempest.scenario import manager
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090026from tempest import test
Maru Newby81f07a02012-09-05 20:21:19 -070027
Sean Dague86bd8422013-12-20 09:56:44 -050028CONF = config.CONF
Matthew Treinish2b59f842013-09-09 20:32:51 +000029LOG = logging.getLogger(__name__)
30
Yair Fried2d2f3fe2014-02-24 16:19:20 +020031Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
32 ['floating_ip', 'server'])
33
Maru Newby81f07a02012-09-05 20:21:19 -070034
Sean Dague6dbc6da2013-05-08 17:49:46 -040035class TestNetworkBasicOps(manager.NetworkScenarioTest):
Maru Newby81f07a02012-09-05 20:21:19 -070036
37 """
38 This smoke test suite assumes that Nova has been configured to
Mark McClainf2982e82013-07-06 17:48:03 -040039 boot VM's with Neutron-managed networking, and attempts to
Maru Newby81f07a02012-09-05 20:21:19 -070040 verify network connectivity as follows:
41
Maru Newby81f07a02012-09-05 20:21:19 -070042 There are presumed to be two types of networks: tenant and
43 public. A tenant network may or may not be reachable from the
44 Tempest host. A public network is assumed to be reachable from
45 the Tempest host, and it should be possible to associate a public
46 ('floating') IP address with a tenant ('fixed') IP address to
Chang Bo Guocc1623c2013-09-13 20:11:27 -070047 facilitate external connectivity to a potentially unroutable
Maru Newby81f07a02012-09-05 20:21:19 -070048 tenant IP address.
49
50 This test suite can be configured to test network connectivity to
51 a VM via a tenant network, a public network, or both. If both
52 networking types are to be evaluated, tests that need to be
53 executed remotely on the VM (via ssh) will only be run against
54 one of the networks (to minimize test execution time).
55
56 Determine which types of networks to test as follows:
57
58 * Configure tenant network checks (via the
59 'tenant_networks_reachable' key) if the Tempest host should
60 have direct connectivity to tenant networks. This is likely to
61 be the case if Tempest is running on the same host as a
62 single-node devstack installation with IP namespaces disabled.
63
64 * Configure checks for a public network if a public network has
65 been configured prior to the test suite being run and if the
66 Tempest host should have connectivity to that public network.
67 Checking connectivity for a public network requires that a
68 value be provided for 'public_network_id'. A value can
69 optionally be provided for 'public_router_id' if tenants will
70 use a shared router to access a public network (as is likely to
71 be the case when IP namespaces are not enabled). If a value is
72 not provided for 'public_router_id', a router will be created
73 for each tenant and use the network identified by
74 'public_network_id' as its gateway.
75
76 """
77
78 @classmethod
79 def check_preconditions(cls):
Gavin Brebner0f465a32013-03-14 13:26:09 +000080 super(TestNetworkBasicOps, cls).check_preconditions()
Matthew Treinish6c072292014-01-29 19:15:52 +000081 if not (CONF.network.tenant_networks_reachable
82 or CONF.network.public_network_id):
Maru Newby81f07a02012-09-05 20:21:19 -070083 msg = ('Either tenant_networks_reachable must be "true", or '
84 'public_network_id must be defined.')
Gavin Brebner0f465a32013-03-14 13:26:09 +000085 cls.enabled = False
ivan-zhu1feeb382013-01-24 10:14:39 +080086 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070087
88 @classmethod
89 def setUpClass(cls):
90 super(TestNetworkBasicOps, cls).setUpClass()
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090091 for ext in ['router', 'security-group']:
92 if not test.is_extension_enabled(ext, 'network'):
93 msg = "%s extension not enabled." % ext
94 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070095 cls.check_preconditions()
Maru Newby81f07a02012-09-05 20:21:19 -070096
Yair Frieded8392f2014-01-15 17:21:35 +020097 def cleanup_wrapper(self, resource):
98 self.cleanup_resource(resource, self.__class__.__name__)
99
100 def setUp(self):
101 super(TestNetworkBasicOps, self).setUp()
102 self.security_group = \
Yair Friedeb69f3f2013-10-10 13:18:16 +0300103 self._create_security_group_neutron(tenant_id=self.tenant_id)
Yair Frieded8392f2014-01-15 17:21:35 +0200104 self.addCleanup(self.cleanup_wrapper, self.security_group)
105 self.network, self.subnet, self.router = self._create_networks()
106 for r in [self.network, self.router, self.subnet]:
107 self.addCleanup(self.cleanup_wrapper, r)
108 self.check_networks()
109 self.servers = {}
110 name = data_utils.rand_name('server-smoke')
111 serv_dict = self._create_server(name, self.network)
112 self.servers[serv_dict['server']] = serv_dict['keypair']
113 self._check_tenant_network_connectivity()
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200114
Yair Frieded8392f2014-01-15 17:21:35 +0200115 self._create_and_associate_floating_ips()
Maru Newby81f07a02012-09-05 20:21:19 -0700116
Yair Frieded8392f2014-01-15 17:21:35 +0200117 def check_networks(self):
118 """
119 Checks that we see the newly created network/subnet/router via
120 checking the result of list_[networks,routers,subnets]
121 """
122
Gavin Brebner851c3502013-01-18 13:14:10 +0000123 seen_nets = self._list_networks()
124 seen_names = [n['name'] for n in seen_nets]
125 seen_ids = [n['id'] for n in seen_nets]
Yair Frieded8392f2014-01-15 17:21:35 +0200126 self.assertIn(self.network.name, seen_names)
127 self.assertIn(self.network.id, seen_ids)
128
Gavin Brebner851c3502013-01-18 13:14:10 +0000129 seen_subnets = self._list_subnets()
130 seen_net_ids = [n['network_id'] for n in seen_subnets]
131 seen_subnet_ids = [n['id'] for n in seen_subnets]
Yair Frieded8392f2014-01-15 17:21:35 +0200132 self.assertIn(self.network.id, seen_net_ids)
133 self.assertIn(self.subnet.id, seen_subnet_ids)
134
Gavin Brebner851c3502013-01-18 13:14:10 +0000135 seen_routers = self._list_routers()
136 seen_router_ids = [n['id'] for n in seen_routers]
137 seen_router_names = [n['name'] for n in seen_routers]
Yair Frieded8392f2014-01-15 17:21:35 +0200138 self.assertIn(self.router.name,
139 seen_router_names)
140 self.assertIn(self.router.id,
141 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000142
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700143 def _create_server(self, name, network):
Yair Fried05db2522013-11-18 11:02:10 +0200144 keypair = self.create_keypair(name='keypair-%s' % name)
Yair Frieded8392f2014-01-15 17:21:35 +0200145 self.addCleanup(self.cleanup_wrapper, keypair)
146 security_groups = [self.security_group.name]
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700147 create_kwargs = {
148 'nics': [
149 {'net-id': network.id},
150 ],
Yair Fried05db2522013-11-18 11:02:10 +0200151 'key_name': keypair.name,
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700152 'security_groups': security_groups,
153 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200154 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Frieded8392f2014-01-15 17:21:35 +0200155 self.addCleanup(self.cleanup_wrapper, server)
156 return dict(server=server, keypair=keypair)
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 if not CONF.network.tenant_networks_reachable:
Maru Newby81f07a02012-09-05 20:21:19 -0700160 msg = 'Tenant networks not configured to be reachable.'
Matthew Treinish2b59f842013-09-09 20:32:51 +0000161 LOG.info(msg)
162 return
Maru Newbyaf292e82013-05-20 21:32:28 +0000163 # The target login is assumed to have been configured for
164 # key-based authentication by cloud-init.
Sean Dague86bd8422013-12-20 09:56:44 -0500165 ssh_login = CONF.compute.image_ssh_user
Brent Eaglesc26d4522013-12-02 13:28:49 -0500166 try:
Yair Frieded8392f2014-01-15 17:21:35 +0200167 for server, key in self.servers.iteritems():
Brent Eaglesc26d4522013-12-02 13:28:49 -0500168 for net_name, ip_addresses in server.networks.iteritems():
169 for ip_address in ip_addresses:
170 self._check_vm_connectivity(ip_address, ssh_login,
Yair Fried05db2522013-11-18 11:02:10 +0200171 key.private_key)
Yair Frieda039f872014-01-02 12:11:10 +0200172 except Exception:
173 LOG.exception('Tenant connectivity check failed')
Salvatore Orlando728d9162014-01-19 10:33:23 -0800174 self._log_console_output(servers=self.servers.keys())
Attila Fazekas6bfd6492014-02-26 21:25:53 +0100175 debug.log_net_debug()
Yair Frieda039f872014-01-02 12:11:10 +0200176 raise
Brent Eaglesc26d4522013-12-02 13:28:49 -0500177
Yair Fried9a551c42013-12-15 14:59:34 +0200178 def _create_and_associate_floating_ips(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500179 public_network_id = CONF.network.public_network_id
Yair Fried05db2522013-11-18 11:02:10 +0200180 for server in self.servers.keys():
Maru Newby81f07a02012-09-05 20:21:19 -0700181 floating_ip = self._create_floating_ip(server, public_network_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200182 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Yair Frieded8392f2014-01-15 17:21:35 +0200183 self.addCleanup(self.cleanup_wrapper, floating_ip)
Maru Newby81f07a02012-09-05 20:21:19 -0700184
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200185 def _check_public_network_connectivity(self, should_connect=True,
186 msg=None):
Maru Newbyaf292e82013-05-20 21:32:28 +0000187 # The target login is assumed to have been configured for
188 # key-based authentication by cloud-init.
Sean Dague86bd8422013-12-20 09:56:44 -0500189 ssh_login = CONF.compute.image_ssh_user
Nachi Ueno4fb7ce62014-01-09 18:29:34 -0800190 LOG.debug('checking network connections')
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200191 floating_ip, server = self.floating_ip_tuple
192 ip_address = floating_ip.floating_ip_address
193 private_key = None
194 if should_connect:
195 private_key = self.servers[server].private_key
Attila Fazekasaeeeefd2013-08-06 17:01:56 +0200196 try:
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200197 self._check_vm_connectivity(ip_address,
198 ssh_login,
199 private_key,
200 should_connect=should_connect)
Yair Frieda039f872014-01-02 12:11:10 +0200201 except Exception:
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200202 ex_msg = 'Public network connectivity check failed'
203 if msg:
204 ex_msg += ": " + msg
205 LOG.exception(ex_msg)
Salvatore Orlando728d9162014-01-19 10:33:23 -0800206 self._log_console_output(servers=self.servers.keys())
Attila Fazekas6bfd6492014-02-26 21:25:53 +0100207 debug.log_net_debug()
Yair Frieda039f872014-01-02 12:11:10 +0200208 raise
Matthew Treinish2b59f842013-09-09 20:32:51 +0000209
Yair Fried9a551c42013-12-15 14:59:34 +0200210 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200211 floating_ip, server = self.floating_ip_tuple
212 self._disassociate_floating_ip(floating_ip)
213 self.floating_ip_tuple = Floating_IP_tuple(
214 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200215
Yair Fried05db2522013-11-18 11:02:10 +0200216 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200217 floating_ip, server = self.floating_ip_tuple
218 name = data_utils.rand_name('new_server-smoke-')
219 # create a new server for the floating ip
220 serv_dict = self._create_server(name, self.network)
221 self.servers[serv_dict['server']] = serv_dict['keypair']
222 self._associate_floating_ip(floating_ip, serv_dict['server'])
223 self.floating_ip_tuple = Floating_IP_tuple(
224 floating_ip, serv_dict['server'])
Yair Fried05db2522013-11-18 11:02:10 +0200225
Yair Fried3097dc12014-01-26 08:46:43 +0200226 def _create_new_network(self):
227 self.new_net = self._create_network(self.tenant_id)
228 self.addCleanup(self.cleanup_wrapper, self.new_net)
229 self.new_subnet = self._create_subnet(
230 network=self.new_net,
231 gateway_ip=None)
232 self.addCleanup(self.cleanup_wrapper, self.new_subnet)
233
234 def _hotplug_server(self):
235 old_floating_ip, server = self.floating_ip_tuple
236 ip_address = old_floating_ip.floating_ip_address
237 private_key = self.servers[server].private_key
238 ssh_client = self.get_remote_client(ip_address,
239 private_key=private_key)
240 old_nic_list = self._get_server_nics(ssh_client)
241 # get a port from a list of one item
242 port_list = self._list_ports(device_id=server.id)
243 self.assertEqual(1, len(port_list))
244 old_port = port_list[0]
245 self.compute_client.servers.interface_attach(server=server,
246 net_id=self.new_net.id,
247 port_id=None,
248 fixed_ip=None)
249 # move server to the head of the cleanup list
250 self.addCleanup(self.cleanup_wrapper, server)
251
252 def check_ports():
253 port_list = [port for port in
254 self._list_ports(device_id=server.id)
255 if port != old_port]
256 return len(port_list) == 1
257
258 test.call_until_true(check_ports, 60, 1)
259 new_port_list = [p for p in
260 self._list_ports(device_id=server.id)
261 if p != old_port]
262 self.assertEqual(1, len(new_port_list))
263 new_port = new_port_list[0]
264 new_port = net_common.DeletablePort(client=self.network_client,
265 **new_port)
266 new_nic_list = self._get_server_nics(ssh_client)
267 diff_list = [n for n in new_nic_list if n not in old_nic_list]
268 self.assertEqual(1, len(diff_list))
269 num, new_nic = diff_list[0]
270 ssh_client.assign_static_ip(nic=new_nic,
271 addr=new_port.fixed_ips[0]['ip_address'])
272 ssh_client.turn_nic_on(nic=new_nic)
273
274 def _get_server_nics(self, ssh_client):
275 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
276 ipatxt = ssh_client.get_ip_list()
277 return reg.findall(ipatxt)
278
Yair Fried06552292013-11-11 12:10:09 +0200279 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200280 """
281 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200282 - ping internal gateway and DHCP port, implying in-tenant connectivity
283 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200284 """
285 floating_ip, server = self.floating_ip_tuple
286 # get internal ports' ips:
287 # get all network ports in the new network
288 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
289 self._list_ports(tenant_id=server.tenant_id,
Yair Fried06552292013-11-11 12:10:09 +0200290 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200291 if p['device_owner'].startswith('network'))
292
Yair Fried06552292013-11-11 12:10:09 +0200293 self._check_server_connectivity(floating_ip, internal_ips)
294
295 def _check_network_external_connectivity(self):
296 """
297 ping public network default gateway to imply external connectivity
298
299 """
300 if not CONF.network.public_network_id:
301 msg = 'public network not defined.'
302 LOG.info(msg)
303 return
304
305 subnet = self.network_client.list_subnets(
306 network_id=CONF.network.public_network_id)['subnets']
307 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
308
309 external_ips = [subnet[0]['gateway_ip']]
310 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
311 external_ips)
312
313 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200314 ip_address = floating_ip.floating_ip_address
Yair Fried06552292013-11-11 12:10:09 +0200315 private_key = self.servers[self.floating_ip_tuple.server].private_key
Yair Fried3097dc12014-01-26 08:46:43 +0200316 ssh_source = self._ssh_to_server(ip_address, private_key)
317
Yair Fried06552292013-11-11 12:10:09 +0200318 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200319 try:
320 self.assertTrue(self._check_remote_connectivity(ssh_source,
321 remote_ip),
322 "Timed out waiting for %s to become "
323 "reachable" % remote_ip)
324 except Exception:
325 LOG.exception("Unable to access {dest} via ssh to "
326 "floating-ip {src}".format(dest=remote_ip,
327 src=floating_ip))
328 debug.log_ip_ns()
329 raise
330
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900331 @test.attr(type='smoke')
332 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000333 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200334 """
335 For a freshly-booted VM with an IP address ("port") on a given
336 network:
337
338 - the Tempest host can ping the IP address. This implies, but
339 does not guarantee (see the ssh check that follows), that the
340 VM has been assigned the correct IP address and has
341 connectivity to the Tempest host.
342
343 - the Tempest host can perform key-based authentication to an
344 ssh server hosted at the IP address. This check guarantees
345 that the IP address is associated with the target VM.
346
Yair Fried3097dc12014-01-26 08:46:43 +0200347 - the Tempest host can ssh into the VM via the IP address and
348 successfully execute the following:
349
350 - ping an external IP address, implying external connectivity.
351
352 - ping an external hostname, implying that dns is correctly
353 configured.
354
355 - ping an internal IP address, implying connectivity to another
356 VM on the same network.
357
Yair Fried06552292013-11-11 12:10:09 +0200358 - detach the floating-ip from the VM and verify that it becomes
359 unreachable
360
361 - associate detached floating ip to a new VM and verify connectivity.
362 VMs are created with unique keypair so connectivity also asserts that
363 floating IP is associated with the new VM instead of the old one
364
365
Yair Fried3097dc12014-01-26 08:46:43 +0200366 """
Yair Fried9a551c42013-12-15 14:59:34 +0200367 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200368 self._check_network_internal_connectivity(network=self.network)
369 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200370 self._disassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200371 self._check_public_network_connectivity(should_connect=False,
372 msg="after disassociate "
373 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200374 self._reassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200375 self._check_public_network_connectivity(should_connect=True,
376 msg="after re-associate "
377 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200378
379 @test.attr(type='smoke')
380 @test.services('compute', 'network')
381 def test_hotplug_nic(self):
382 """
383 1. create a new network, with no gateway (to prevent overwriting VM's
384 gateway)
385 2. connect VM to new network
386 3. set static ip and bring new nic up
387 4. check VM can ping new network dhcp port
388
389 """
390
391 self._check_public_network_connectivity(should_connect=True)
392 self._create_new_network()
393 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200394 self._check_network_internal_connectivity(network=self.new_net)