blob: c84d4b940816b9cd73fb044934437fede0669dd5 [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):
Yair Fried764610a2014-04-07 12:17:05 +030090 # Create no network resources for these tests.
91 cls.set_network_resources()
Maru Newby81f07a02012-09-05 20:21:19 -070092 super(TestNetworkBasicOps, cls).setUpClass()
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090093 for ext in ['router', 'security-group']:
94 if not test.is_extension_enabled(ext, 'network'):
95 msg = "%s extension not enabled." % ext
96 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070097 cls.check_preconditions()
Maru Newby81f07a02012-09-05 20:21:19 -070098
Yair Frieded8392f2014-01-15 17:21:35 +020099 def cleanup_wrapper(self, resource):
100 self.cleanup_resource(resource, self.__class__.__name__)
101
102 def setUp(self):
103 super(TestNetworkBasicOps, self).setUp()
104 self.security_group = \
Yair Friedeb69f3f2013-10-10 13:18:16 +0300105 self._create_security_group_neutron(tenant_id=self.tenant_id)
Yair Frieded8392f2014-01-15 17:21:35 +0200106 self.addCleanup(self.cleanup_wrapper, self.security_group)
107 self.network, self.subnet, self.router = self._create_networks()
108 for r in [self.network, self.router, self.subnet]:
109 self.addCleanup(self.cleanup_wrapper, r)
110 self.check_networks()
111 self.servers = {}
112 name = data_utils.rand_name('server-smoke')
113 serv_dict = self._create_server(name, self.network)
114 self.servers[serv_dict['server']] = serv_dict['keypair']
115 self._check_tenant_network_connectivity()
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200116
Yair Frieded8392f2014-01-15 17:21:35 +0200117 self._create_and_associate_floating_ips()
Maru Newby81f07a02012-09-05 20:21:19 -0700118
Yair Frieded8392f2014-01-15 17:21:35 +0200119 def check_networks(self):
120 """
121 Checks that we see the newly created network/subnet/router via
122 checking the result of list_[networks,routers,subnets]
123 """
124
Gavin Brebner851c3502013-01-18 13:14:10 +0000125 seen_nets = self._list_networks()
126 seen_names = [n['name'] for n in seen_nets]
127 seen_ids = [n['id'] for n in seen_nets]
Yair Frieded8392f2014-01-15 17:21:35 +0200128 self.assertIn(self.network.name, seen_names)
129 self.assertIn(self.network.id, seen_ids)
130
Gavin Brebner851c3502013-01-18 13:14:10 +0000131 seen_subnets = self._list_subnets()
132 seen_net_ids = [n['network_id'] for n in seen_subnets]
133 seen_subnet_ids = [n['id'] for n in seen_subnets]
Yair Frieded8392f2014-01-15 17:21:35 +0200134 self.assertIn(self.network.id, seen_net_ids)
135 self.assertIn(self.subnet.id, seen_subnet_ids)
136
Gavin Brebner851c3502013-01-18 13:14:10 +0000137 seen_routers = self._list_routers()
138 seen_router_ids = [n['id'] for n in seen_routers]
139 seen_router_names = [n['name'] for n in seen_routers]
Yair Frieded8392f2014-01-15 17:21:35 +0200140 self.assertIn(self.router.name,
141 seen_router_names)
142 self.assertIn(self.router.id,
143 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000144
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700145 def _create_server(self, name, network):
Yair Fried05db2522013-11-18 11:02:10 +0200146 keypair = self.create_keypair(name='keypair-%s' % name)
Yair Frieded8392f2014-01-15 17:21:35 +0200147 self.addCleanup(self.cleanup_wrapper, keypair)
148 security_groups = [self.security_group.name]
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700149 create_kwargs = {
150 'nics': [
151 {'net-id': network.id},
152 ],
Yair Fried05db2522013-11-18 11:02:10 +0200153 'key_name': keypair.name,
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700154 'security_groups': security_groups,
155 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200156 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Frieded8392f2014-01-15 17:21:35 +0200157 self.addCleanup(self.cleanup_wrapper, server)
158 return dict(server=server, keypair=keypair)
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700159
Matthew Treinish2b59f842013-09-09 20:32:51 +0000160 def _check_tenant_network_connectivity(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500161 ssh_login = CONF.compute.image_ssh_user
Matt Riedemann2d005be2014-05-27 10:52:35 -0700162 for server, key in self.servers.iteritems():
163 # call the common method in the parent class
164 super(TestNetworkBasicOps, self).\
165 _check_tenant_network_connectivity(
166 server, ssh_login, key.private_key,
167 servers_for_debug=self.servers.keys())
Brent Eaglesc26d4522013-12-02 13:28:49 -0500168
Yair Fried9a551c42013-12-15 14:59:34 +0200169 def _create_and_associate_floating_ips(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500170 public_network_id = CONF.network.public_network_id
Yair Fried05db2522013-11-18 11:02:10 +0200171 for server in self.servers.keys():
Maru Newby81f07a02012-09-05 20:21:19 -0700172 floating_ip = self._create_floating_ip(server, public_network_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200173 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Yair Frieded8392f2014-01-15 17:21:35 +0200174 self.addCleanup(self.cleanup_wrapper, floating_ip)
Maru Newby81f07a02012-09-05 20:21:19 -0700175
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200176 def _check_public_network_connectivity(self, should_connect=True,
177 msg=None):
Sean Dague86bd8422013-12-20 09:56:44 -0500178 ssh_login = CONF.compute.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200179 floating_ip, server = self.floating_ip_tuple
180 ip_address = floating_ip.floating_ip_address
181 private_key = None
182 if should_connect:
183 private_key = self.servers[server].private_key
Matt Riedemann343305f2014-05-27 09:55:03 -0700184 # call the common method in the parent class
185 super(TestNetworkBasicOps, self)._check_public_network_connectivity(
186 ip_address, ssh_login, private_key, should_connect, msg,
187 self.servers.keys())
Matthew Treinish2b59f842013-09-09 20:32:51 +0000188
Yair Fried9a551c42013-12-15 14:59:34 +0200189 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200190 floating_ip, server = self.floating_ip_tuple
191 self._disassociate_floating_ip(floating_ip)
192 self.floating_ip_tuple = Floating_IP_tuple(
193 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200194
Yair Fried05db2522013-11-18 11:02:10 +0200195 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200196 floating_ip, server = self.floating_ip_tuple
197 name = data_utils.rand_name('new_server-smoke-')
198 # create a new server for the floating ip
199 serv_dict = self._create_server(name, self.network)
200 self.servers[serv_dict['server']] = serv_dict['keypair']
201 self._associate_floating_ip(floating_ip, serv_dict['server'])
202 self.floating_ip_tuple = Floating_IP_tuple(
203 floating_ip, serv_dict['server'])
Yair Fried05db2522013-11-18 11:02:10 +0200204
Yair Fried3097dc12014-01-26 08:46:43 +0200205 def _create_new_network(self):
206 self.new_net = self._create_network(self.tenant_id)
207 self.addCleanup(self.cleanup_wrapper, self.new_net)
208 self.new_subnet = self._create_subnet(
209 network=self.new_net,
210 gateway_ip=None)
211 self.addCleanup(self.cleanup_wrapper, self.new_subnet)
212
213 def _hotplug_server(self):
214 old_floating_ip, server = self.floating_ip_tuple
215 ip_address = old_floating_ip.floating_ip_address
216 private_key = self.servers[server].private_key
217 ssh_client = self.get_remote_client(ip_address,
218 private_key=private_key)
219 old_nic_list = self._get_server_nics(ssh_client)
220 # get a port from a list of one item
221 port_list = self._list_ports(device_id=server.id)
222 self.assertEqual(1, len(port_list))
223 old_port = port_list[0]
224 self.compute_client.servers.interface_attach(server=server,
225 net_id=self.new_net.id,
226 port_id=None,
227 fixed_ip=None)
228 # move server to the head of the cleanup list
229 self.addCleanup(self.cleanup_wrapper, server)
230
231 def check_ports():
232 port_list = [port for port in
233 self._list_ports(device_id=server.id)
234 if port != old_port]
235 return len(port_list) == 1
236
237 test.call_until_true(check_ports, 60, 1)
238 new_port_list = [p for p in
239 self._list_ports(device_id=server.id)
240 if p != old_port]
241 self.assertEqual(1, len(new_port_list))
242 new_port = new_port_list[0]
243 new_port = net_common.DeletablePort(client=self.network_client,
244 **new_port)
245 new_nic_list = self._get_server_nics(ssh_client)
246 diff_list = [n for n in new_nic_list if n not in old_nic_list]
247 self.assertEqual(1, len(diff_list))
248 num, new_nic = diff_list[0]
249 ssh_client.assign_static_ip(nic=new_nic,
250 addr=new_port.fixed_ips[0]['ip_address'])
251 ssh_client.turn_nic_on(nic=new_nic)
252
253 def _get_server_nics(self, ssh_client):
254 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
255 ipatxt = ssh_client.get_ip_list()
256 return reg.findall(ipatxt)
257
Yair Fried06552292013-11-11 12:10:09 +0200258 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200259 """
260 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200261 - ping internal gateway and DHCP port, implying in-tenant connectivity
262 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200263 """
264 floating_ip, server = self.floating_ip_tuple
265 # get internal ports' ips:
266 # get all network ports in the new network
267 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
268 self._list_ports(tenant_id=server.tenant_id,
Yair Fried06552292013-11-11 12:10:09 +0200269 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200270 if p['device_owner'].startswith('network'))
271
Yair Fried06552292013-11-11 12:10:09 +0200272 self._check_server_connectivity(floating_ip, internal_ips)
273
274 def _check_network_external_connectivity(self):
275 """
276 ping public network default gateway to imply external connectivity
277
278 """
279 if not CONF.network.public_network_id:
280 msg = 'public network not defined.'
281 LOG.info(msg)
282 return
283
284 subnet = self.network_client.list_subnets(
285 network_id=CONF.network.public_network_id)['subnets']
286 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
287
288 external_ips = [subnet[0]['gateway_ip']]
289 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
290 external_ips)
291
292 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200293 ip_address = floating_ip.floating_ip_address
Yair Fried06552292013-11-11 12:10:09 +0200294 private_key = self.servers[self.floating_ip_tuple.server].private_key
Yair Fried3097dc12014-01-26 08:46:43 +0200295 ssh_source = self._ssh_to_server(ip_address, private_key)
296
Yair Fried06552292013-11-11 12:10:09 +0200297 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200298 try:
299 self.assertTrue(self._check_remote_connectivity(ssh_source,
300 remote_ip),
301 "Timed out waiting for %s to become "
302 "reachable" % remote_ip)
303 except Exception:
304 LOG.exception("Unable to access {dest} via ssh to "
305 "floating-ip {src}".format(dest=remote_ip,
306 src=floating_ip))
307 debug.log_ip_ns()
308 raise
309
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900310 @test.attr(type='smoke')
311 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000312 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200313 """
314 For a freshly-booted VM with an IP address ("port") on a given
315 network:
316
317 - the Tempest host can ping the IP address. This implies, but
318 does not guarantee (see the ssh check that follows), that the
319 VM has been assigned the correct IP address and has
320 connectivity to the Tempest host.
321
322 - the Tempest host can perform key-based authentication to an
323 ssh server hosted at the IP address. This check guarantees
324 that the IP address is associated with the target VM.
325
Yair Fried3097dc12014-01-26 08:46:43 +0200326 - the Tempest host can ssh into the VM via the IP address and
327 successfully execute the following:
328
329 - ping an external IP address, implying external connectivity.
330
331 - ping an external hostname, implying that dns is correctly
332 configured.
333
334 - ping an internal IP address, implying connectivity to another
335 VM on the same network.
336
Yair Fried06552292013-11-11 12:10:09 +0200337 - detach the floating-ip from the VM and verify that it becomes
338 unreachable
339
340 - associate detached floating ip to a new VM and verify connectivity.
341 VMs are created with unique keypair so connectivity also asserts that
342 floating IP is associated with the new VM instead of the old one
343
344
Yair Fried3097dc12014-01-26 08:46:43 +0200345 """
Yair Fried9a551c42013-12-15 14:59:34 +0200346 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200347 self._check_network_internal_connectivity(network=self.network)
348 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200349 self._disassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200350 self._check_public_network_connectivity(should_connect=False,
351 msg="after disassociate "
352 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200353 self._reassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200354 self._check_public_network_connectivity(should_connect=True,
355 msg="after re-associate "
356 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200357
358 @test.attr(type='smoke')
359 @test.services('compute', 'network')
360 def test_hotplug_nic(self):
361 """
362 1. create a new network, with no gateway (to prevent overwriting VM's
363 gateway)
364 2. connect VM to new network
365 3. set static ip and bring new nic up
366 4. check VM can ping new network dhcp port
367
368 """
369
370 self._check_public_network_connectivity(should_connect=True)
371 self._create_new_network()
372 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200373 self._check_network_internal_connectivity(network=self.new_net)