blob: 21782eeac081bb4e1f2f6db7ec97cab32e66e8e6 [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 ssh_login = CONF.compute.image_ssh_user
Matt Riedemann2d005be2014-05-27 10:52:35 -0700160 for server, key in self.servers.iteritems():
161 # call the common method in the parent class
162 super(TestNetworkBasicOps, self).\
163 _check_tenant_network_connectivity(
164 server, ssh_login, key.private_key,
165 servers_for_debug=self.servers.keys())
Brent Eaglesc26d4522013-12-02 13:28:49 -0500166
Yair Fried9a551c42013-12-15 14:59:34 +0200167 def _create_and_associate_floating_ips(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500168 public_network_id = CONF.network.public_network_id
Yair Fried05db2522013-11-18 11:02:10 +0200169 for server in self.servers.keys():
Maru Newby81f07a02012-09-05 20:21:19 -0700170 floating_ip = self._create_floating_ip(server, public_network_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200171 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Yair Frieded8392f2014-01-15 17:21:35 +0200172 self.addCleanup(self.cleanup_wrapper, floating_ip)
Maru Newby81f07a02012-09-05 20:21:19 -0700173
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200174 def _check_public_network_connectivity(self, should_connect=True,
175 msg=None):
Sean Dague86bd8422013-12-20 09:56:44 -0500176 ssh_login = CONF.compute.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200177 floating_ip, server = self.floating_ip_tuple
178 ip_address = floating_ip.floating_ip_address
179 private_key = None
180 if should_connect:
181 private_key = self.servers[server].private_key
Matt Riedemann343305f2014-05-27 09:55:03 -0700182 # call the common method in the parent class
183 super(TestNetworkBasicOps, self)._check_public_network_connectivity(
184 ip_address, ssh_login, private_key, should_connect, msg,
185 self.servers.keys())
Matthew Treinish2b59f842013-09-09 20:32:51 +0000186
Yair Fried9a551c42013-12-15 14:59:34 +0200187 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200188 floating_ip, server = self.floating_ip_tuple
189 self._disassociate_floating_ip(floating_ip)
190 self.floating_ip_tuple = Floating_IP_tuple(
191 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200192
Yair Fried05db2522013-11-18 11:02:10 +0200193 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200194 floating_ip, server = self.floating_ip_tuple
195 name = data_utils.rand_name('new_server-smoke-')
196 # create a new server for the floating ip
197 serv_dict = self._create_server(name, self.network)
198 self.servers[serv_dict['server']] = serv_dict['keypair']
199 self._associate_floating_ip(floating_ip, serv_dict['server'])
200 self.floating_ip_tuple = Floating_IP_tuple(
201 floating_ip, serv_dict['server'])
Yair Fried05db2522013-11-18 11:02:10 +0200202
Yair Fried3097dc12014-01-26 08:46:43 +0200203 def _create_new_network(self):
204 self.new_net = self._create_network(self.tenant_id)
205 self.addCleanup(self.cleanup_wrapper, self.new_net)
206 self.new_subnet = self._create_subnet(
207 network=self.new_net,
208 gateway_ip=None)
209 self.addCleanup(self.cleanup_wrapper, self.new_subnet)
210
211 def _hotplug_server(self):
212 old_floating_ip, server = self.floating_ip_tuple
213 ip_address = old_floating_ip.floating_ip_address
214 private_key = self.servers[server].private_key
215 ssh_client = self.get_remote_client(ip_address,
216 private_key=private_key)
217 old_nic_list = self._get_server_nics(ssh_client)
218 # get a port from a list of one item
219 port_list = self._list_ports(device_id=server.id)
220 self.assertEqual(1, len(port_list))
221 old_port = port_list[0]
222 self.compute_client.servers.interface_attach(server=server,
223 net_id=self.new_net.id,
224 port_id=None,
225 fixed_ip=None)
226 # move server to the head of the cleanup list
227 self.addCleanup(self.cleanup_wrapper, server)
228
229 def check_ports():
230 port_list = [port for port in
231 self._list_ports(device_id=server.id)
232 if port != old_port]
233 return len(port_list) == 1
234
235 test.call_until_true(check_ports, 60, 1)
236 new_port_list = [p for p in
237 self._list_ports(device_id=server.id)
238 if p != old_port]
239 self.assertEqual(1, len(new_port_list))
240 new_port = new_port_list[0]
241 new_port = net_common.DeletablePort(client=self.network_client,
242 **new_port)
243 new_nic_list = self._get_server_nics(ssh_client)
244 diff_list = [n for n in new_nic_list if n not in old_nic_list]
245 self.assertEqual(1, len(diff_list))
246 num, new_nic = diff_list[0]
247 ssh_client.assign_static_ip(nic=new_nic,
248 addr=new_port.fixed_ips[0]['ip_address'])
249 ssh_client.turn_nic_on(nic=new_nic)
250
251 def _get_server_nics(self, ssh_client):
252 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
253 ipatxt = ssh_client.get_ip_list()
254 return reg.findall(ipatxt)
255
Yair Fried06552292013-11-11 12:10:09 +0200256 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200257 """
258 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200259 - ping internal gateway and DHCP port, implying in-tenant connectivity
260 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200261 """
262 floating_ip, server = self.floating_ip_tuple
263 # get internal ports' ips:
264 # get all network ports in the new network
265 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
266 self._list_ports(tenant_id=server.tenant_id,
Yair Fried06552292013-11-11 12:10:09 +0200267 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200268 if p['device_owner'].startswith('network'))
269
Yair Fried06552292013-11-11 12:10:09 +0200270 self._check_server_connectivity(floating_ip, internal_ips)
271
272 def _check_network_external_connectivity(self):
273 """
274 ping public network default gateway to imply external connectivity
275
276 """
277 if not CONF.network.public_network_id:
278 msg = 'public network not defined.'
279 LOG.info(msg)
280 return
281
282 subnet = self.network_client.list_subnets(
283 network_id=CONF.network.public_network_id)['subnets']
284 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
285
286 external_ips = [subnet[0]['gateway_ip']]
287 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
288 external_ips)
289
290 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200291 ip_address = floating_ip.floating_ip_address
Yair Fried06552292013-11-11 12:10:09 +0200292 private_key = self.servers[self.floating_ip_tuple.server].private_key
Yair Fried3097dc12014-01-26 08:46:43 +0200293 ssh_source = self._ssh_to_server(ip_address, private_key)
294
Yair Fried06552292013-11-11 12:10:09 +0200295 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200296 try:
297 self.assertTrue(self._check_remote_connectivity(ssh_source,
298 remote_ip),
299 "Timed out waiting for %s to become "
300 "reachable" % remote_ip)
301 except Exception:
302 LOG.exception("Unable to access {dest} via ssh to "
303 "floating-ip {src}".format(dest=remote_ip,
304 src=floating_ip))
305 debug.log_ip_ns()
306 raise
307
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900308 @test.attr(type='smoke')
309 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000310 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200311 """
312 For a freshly-booted VM with an IP address ("port") on a given
313 network:
314
315 - the Tempest host can ping the IP address. This implies, but
316 does not guarantee (see the ssh check that follows), that the
317 VM has been assigned the correct IP address and has
318 connectivity to the Tempest host.
319
320 - the Tempest host can perform key-based authentication to an
321 ssh server hosted at the IP address. This check guarantees
322 that the IP address is associated with the target VM.
323
Yair Fried3097dc12014-01-26 08:46:43 +0200324 - the Tempest host can ssh into the VM via the IP address and
325 successfully execute the following:
326
327 - ping an external IP address, implying external connectivity.
328
329 - ping an external hostname, implying that dns is correctly
330 configured.
331
332 - ping an internal IP address, implying connectivity to another
333 VM on the same network.
334
Yair Fried06552292013-11-11 12:10:09 +0200335 - detach the floating-ip from the VM and verify that it becomes
336 unreachable
337
338 - associate detached floating ip to a new VM and verify connectivity.
339 VMs are created with unique keypair so connectivity also asserts that
340 floating IP is associated with the new VM instead of the old one
341
342
Yair Fried3097dc12014-01-26 08:46:43 +0200343 """
Yair Fried9a551c42013-12-15 14:59:34 +0200344 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200345 self._check_network_internal_connectivity(network=self.network)
346 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200347 self._disassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200348 self._check_public_network_connectivity(should_connect=False,
349 msg="after disassociate "
350 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200351 self._reassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200352 self._check_public_network_connectivity(should_connect=True,
353 msg="after re-associate "
354 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200355
356 @test.attr(type='smoke')
357 @test.services('compute', 'network')
358 def test_hotplug_nic(self):
359 """
360 1. create a new network, with no gateway (to prevent overwriting VM's
361 gateway)
362 2. connect VM to new network
363 3. set static ip and bring new nic up
364 4. check VM can ping new network dhcp port
365
366 """
367
368 self._check_public_network_connectivity(should_connect=True)
369 self._create_new_network()
370 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200371 self._check_network_internal_connectivity(network=self.new_net)