blob: 9618124990a8b3d8867f47d414ffb84640da531c [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
Andrea Frittoli4971fc82014-09-25 10:22:20 +010037class TestNetworkBasicOps(manager.NetworkScenarioTest):
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
Andrea Frittoliac20b5e2014-09-15 13:31:14 +010091 def resource_setup(cls):
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090092 for ext in ['router', 'security-group']:
93 if not test.is_extension_enabled(ext, 'network'):
94 msg = "%s extension not enabled." % ext
95 raise cls.skipException(msg)
Masayuki Igawa60ea6c52014-10-15 17:32:14 +090096 # Create no network resources for these tests.
97 cls.set_network_resources()
98 super(TestNetworkBasicOps, cls).resource_setup()
Maru Newby81f07a02012-09-05 20:21:19 -070099
Yair Frieded8392f2014-01-15 17:21:35 +0200100 def setUp(self):
101 super(TestNetworkBasicOps, self).setUp()
Yair Fried1fc32a12014-08-04 09:11:30 +0300102 self.keypairs = {}
103 self.servers = []
David Shrewsbury9bac3662014-08-07 15:07:01 -0400104
105 def _setup_network_and_servers(self):
106 self.security_group = \
107 self._create_security_group(tenant_id=self.tenant_id)
108 self.network, self.subnet, self.router = self.create_networks()
109 self.check_networks()
110
Yair Frieded8392f2014-01-15 17:21:35 +0200111 name = data_utils.rand_name('server-smoke')
Yair Fried1fc32a12014-08-04 09:11:30 +0300112 server = self._create_server(name, self.network)
Yair Frieded8392f2014-01-15 17:21:35 +0200113 self._check_tenant_network_connectivity()
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200114
Yair Friedae0e73d2014-11-24 11:56:26 +0200115 floating_ip = self.create_floating_ip(server)
116 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Maru Newby81f07a02012-09-05 20:21:19 -0700117
Yair Frieded8392f2014-01-15 17:21:35 +0200118 def check_networks(self):
119 """
120 Checks that we see the newly created network/subnet/router via
121 checking the result of list_[networks,routers,subnets]
122 """
123
Gavin Brebner851c3502013-01-18 13:14:10 +0000124 seen_nets = self._list_networks()
125 seen_names = [n['name'] for n in seen_nets]
126 seen_ids = [n['id'] for n in seen_nets]
Yair Frieded8392f2014-01-15 17:21:35 +0200127 self.assertIn(self.network.name, seen_names)
128 self.assertIn(self.network.id, seen_ids)
129
David Shrewsbury9bac3662014-08-07 15:07:01 -0400130 if self.subnet:
131 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]
134 self.assertIn(self.network.id, seen_net_ids)
135 self.assertIn(self.subnet.id, seen_subnet_ids)
Yair Frieded8392f2014-01-15 17:21:35 +0200136
David Shrewsbury9bac3662014-08-07 15:07:01 -0400137 if self.router:
138 seen_routers = self._list_routers()
139 seen_router_ids = [n['id'] for n in seen_routers]
140 seen_router_names = [n['name'] for n in seen_routers]
141 self.assertIn(self.router.name,
142 seen_router_names)
143 self.assertIn(self.router.id,
144 seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000145
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700146 def _create_server(self, name, network):
Yair Fried1fc32a12014-08-04 09:11:30 +0300147 keypair = self.create_keypair()
148 self.keypairs[keypair['name']] = keypair
Ken'ichi Ohmichi1b3461e2014-12-02 03:41:07 +0000149 security_groups = [{'name': self.security_group['name']}]
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700150 create_kwargs = {
Dirk Mueller8cf79722014-09-12 17:37:15 +0200151 'networks': [
152 {'uuid': network.id},
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700153 ],
Yair Fried1fc32a12014-08-04 09:11:30 +0300154 'key_name': keypair['name'],
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700155 'security_groups': security_groups,
156 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200157 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300158 self.servers.append(server)
159 return server
160
161 def _get_server_key(self, server):
162 return self.keypairs[server['key_name']]['private_key']
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700163
Matthew Treinish2b59f842013-09-09 20:32:51 +0000164 def _check_tenant_network_connectivity(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500165 ssh_login = CONF.compute.image_ssh_user
Yair Fried1fc32a12014-08-04 09:11:30 +0300166 for server in self.servers:
Matt Riedemann2d005be2014-05-27 10:52:35 -0700167 # call the common method in the parent class
168 super(TestNetworkBasicOps, self).\
169 _check_tenant_network_connectivity(
Yair Fried1fc32a12014-08-04 09:11:30 +0300170 server, ssh_login, self._get_server_key(server),
171 servers_for_debug=self.servers)
Brent Eaglesc26d4522013-12-02 13:28:49 -0500172
Yair Friedae0e73d2014-11-24 11:56:26 +0200173 def check_public_network_connectivity(self, should_connect=True,
174 msg=None):
Yair Fried45f92952014-06-26 05:19:19 +0300175 """Verifies connectivty to a VM via public network and floating IP,
176 and verifies floating IP has resource status is correct.
177
Yair Fried45f92952014-06-26 05:19:19 +0300178 :param should_connect: bool. determines if connectivity check is
179 negative or positive.
180 :param msg: Failure message to add to Error message. Should describe
181 the place in the test scenario where the method was called,
182 to indicate the context of the failure
183 """
Sean Dague86bd8422013-12-20 09:56:44 -0500184 ssh_login = CONF.compute.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200185 floating_ip, server = self.floating_ip_tuple
186 ip_address = floating_ip.floating_ip_address
187 private_key = None
Yair Fried45f92952014-06-26 05:19:19 +0300188 floatingip_status = 'DOWN'
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200189 if should_connect:
Yair Fried1fc32a12014-08-04 09:11:30 +0300190 private_key = self._get_server_key(server)
Yair Fried45f92952014-06-26 05:19:19 +0300191 floatingip_status = 'ACTIVE'
Matt Riedemann343305f2014-05-27 09:55:03 -0700192 # call the common method in the parent class
Yair Friedae0e73d2014-11-24 11:56:26 +0200193 super(TestNetworkBasicOps, self).check_public_network_connectivity(
Matt Riedemann343305f2014-05-27 09:55:03 -0700194 ip_address, ssh_login, private_key, should_connect, msg,
Yair Fried1fc32a12014-08-04 09:11:30 +0300195 self.servers)
Yair Fried45f92952014-06-26 05:19:19 +0300196 self.check_floating_ip_status(floating_ip, floatingip_status)
Matthew Treinish2b59f842013-09-09 20:32:51 +0000197
Yair Fried9a551c42013-12-15 14:59:34 +0200198 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200199 floating_ip, server = self.floating_ip_tuple
200 self._disassociate_floating_ip(floating_ip)
201 self.floating_ip_tuple = Floating_IP_tuple(
202 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200203
Yair Fried05db2522013-11-18 11:02:10 +0200204 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200205 floating_ip, server = self.floating_ip_tuple
206 name = data_utils.rand_name('new_server-smoke-')
207 # create a new server for the floating ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300208 server = self._create_server(name, self.network)
209 self._associate_floating_ip(floating_ip, server)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200210 self.floating_ip_tuple = Floating_IP_tuple(
Yair Fried1fc32a12014-08-04 09:11:30 +0300211 floating_ip, server)
Yair Fried05db2522013-11-18 11:02:10 +0200212
Yair Fried3097dc12014-01-26 08:46:43 +0200213 def _create_new_network(self):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300214 self.new_net = self._create_network(tenant_id=self.tenant_id)
Yair Fried3097dc12014-01-26 08:46:43 +0200215 self.new_subnet = self._create_subnet(
216 network=self.new_net,
217 gateway_ip=None)
Yair Fried3097dc12014-01-26 08:46:43 +0200218
219 def _hotplug_server(self):
220 old_floating_ip, server = self.floating_ip_tuple
221 ip_address = old_floating_ip.floating_ip_address
Yair Fried1fc32a12014-08-04 09:11:30 +0300222 private_key = self._get_server_key(server)
Yair Fried3097dc12014-01-26 08:46:43 +0200223 ssh_client = self.get_remote_client(ip_address,
224 private_key=private_key)
225 old_nic_list = self._get_server_nics(ssh_client)
226 # get a port from a list of one item
Yair Fried1fc32a12014-08-04 09:11:30 +0300227 port_list = self._list_ports(device_id=server['id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200228 self.assertEqual(1, len(port_list))
229 old_port = port_list[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300230 _, interface = self.interface_client.create_interface(
231 server=server['id'],
232 network_id=self.new_net.id)
233 self.addCleanup(self.network_client.wait_for_resource_deletion,
234 'port',
235 interface['port_id'])
236 self.addCleanup(self.delete_wrapper,
237 self.interface_client.delete_interface,
238 server['id'], interface['port_id'])
Yair Fried3097dc12014-01-26 08:46:43 +0200239
240 def check_ports():
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200241 self.new_port_list = [port for port in
Yair Fried1fc32a12014-08-04 09:11:30 +0300242 self._list_ports(device_id=server['id'])
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200243 if port != old_port]
244 return len(self.new_port_list) == 1
Yair Fried3097dc12014-01-26 08:46:43 +0200245
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200246 if not test.call_until_true(check_ports, CONF.network.build_timeout,
247 CONF.network.build_interval):
248 raise exceptions.TimeoutException("No new port attached to the "
249 "server in time (%s sec) !"
250 % CONF.network.build_timeout)
Yair Fried1fc32a12014-08-04 09:11:30 +0300251 new_port = net_resources.DeletablePort(client=self.network_client,
252 **self.new_port_list[0])
Attila Fazekasa8bb3942014-08-19 09:06:30 +0200253
254 def check_new_nic():
255 new_nic_list = self._get_server_nics(ssh_client)
256 self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
257 return len(self.diff_list) == 1
258
259 if not test.call_until_true(check_new_nic, CONF.network.build_timeout,
260 CONF.network.build_interval):
261 raise exceptions.TimeoutException("Interface not visible on the "
262 "guest after %s sec"
263 % CONF.network.build_timeout)
264
265 num, new_nic = self.diff_list[0]
Yair Fried3097dc12014-01-26 08:46:43 +0200266 ssh_client.assign_static_ip(nic=new_nic,
267 addr=new_port.fixed_ips[0]['ip_address'])
268 ssh_client.turn_nic_on(nic=new_nic)
269
270 def _get_server_nics(self, ssh_client):
271 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
272 ipatxt = ssh_client.get_ip_list()
273 return reg.findall(ipatxt)
274
Yair Fried06552292013-11-11 12:10:09 +0200275 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200276 """
277 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200278 - ping internal gateway and DHCP port, implying in-tenant connectivity
279 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200280 """
281 floating_ip, server = self.floating_ip_tuple
282 # get internal ports' ips:
283 # get all network ports in the new network
284 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
Yair Fried1fc32a12014-08-04 09:11:30 +0300285 self._list_ports(tenant_id=server['tenant_id'],
Yair Fried06552292013-11-11 12:10:09 +0200286 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200287 if p['device_owner'].startswith('network'))
288
Yair Fried06552292013-11-11 12:10:09 +0200289 self._check_server_connectivity(floating_ip, internal_ips)
290
291 def _check_network_external_connectivity(self):
292 """
293 ping public network default gateway to imply external connectivity
294
295 """
296 if not CONF.network.public_network_id:
297 msg = 'public network not defined.'
298 LOG.info(msg)
299 return
300
Yair Fried1fc32a12014-08-04 09:11:30 +0300301 subnet = self._list_subnets(
302 network_id=CONF.network.public_network_id)
Yair Fried06552292013-11-11 12:10:09 +0200303 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
304
305 external_ips = [subnet[0]['gateway_ip']]
306 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
307 external_ips)
308
309 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200310 ip_address = floating_ip.floating_ip_address
Yair Fried1fc32a12014-08-04 09:11:30 +0300311 private_key = self._get_server_key(self.floating_ip_tuple.server)
Yair Fried3097dc12014-01-26 08:46:43 +0200312 ssh_source = self._ssh_to_server(ip_address, private_key)
313
Yair Fried06552292013-11-11 12:10:09 +0200314 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200315 try:
316 self.assertTrue(self._check_remote_connectivity(ssh_source,
317 remote_ip),
318 "Timed out waiting for %s to become "
319 "reachable" % remote_ip)
320 except Exception:
321 LOG.exception("Unable to access {dest} via ssh to "
322 "floating-ip {src}".format(dest=remote_ip,
323 src=floating_ip))
324 debug.log_ip_ns()
325 raise
326
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900327 @test.attr(type='smoke')
328 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000329 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200330 """
331 For a freshly-booted VM with an IP address ("port") on a given
332 network:
333
334 - the Tempest host can ping the IP address. This implies, but
335 does not guarantee (see the ssh check that follows), that the
336 VM has been assigned the correct IP address and has
337 connectivity to the Tempest host.
338
339 - the Tempest host can perform key-based authentication to an
340 ssh server hosted at the IP address. This check guarantees
341 that the IP address is associated with the target VM.
342
Yair Fried3097dc12014-01-26 08:46:43 +0200343 - the Tempest host can ssh into the VM via the IP address and
344 successfully execute the following:
345
346 - ping an external IP address, implying external connectivity.
347
348 - ping an external hostname, implying that dns is correctly
349 configured.
350
351 - ping an internal IP address, implying connectivity to another
352 VM on the same network.
353
Yair Fried06552292013-11-11 12:10:09 +0200354 - detach the floating-ip from the VM and verify that it becomes
355 unreachable
356
357 - associate detached floating ip to a new VM and verify connectivity.
358 VMs are created with unique keypair so connectivity also asserts that
359 floating IP is associated with the new VM instead of the old one
360
Yair Fried45f92952014-06-26 05:19:19 +0300361 Verifies that floating IP status is updated correctly after each change
362
Yair Fried06552292013-11-11 12:10:09 +0200363
Yair Fried3097dc12014-01-26 08:46:43 +0200364 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400365 self._setup_network_and_servers()
Yair Friedae0e73d2014-11-24 11:56:26 +0200366 self.check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200367 self._check_network_internal_connectivity(network=self.network)
368 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200369 self._disassociate_floating_ips()
Yair Friedae0e73d2014-11-24 11:56:26 +0200370 self.check_public_network_connectivity(should_connect=False,
371 msg="after disassociate "
372 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200373 self._reassociate_floating_ips()
Yair Friedae0e73d2014-11-24 11:56:26 +0200374 self.check_public_network_connectivity(should_connect=True,
375 msg="after re-associate "
376 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200377
Adam Gandelman7186f7a2014-07-23 09:28:56 -0400378 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
379 'NIC hotplug not available')
Yair Fried3097dc12014-01-26 08:46:43 +0200380 @test.attr(type='smoke')
381 @test.services('compute', 'network')
382 def test_hotplug_nic(self):
383 """
384 1. create a new network, with no gateway (to prevent overwriting VM's
385 gateway)
386 2. connect VM to new network
387 3. set static ip and bring new nic up
388 4. check VM can ping new network dhcp port
389
390 """
David Shrewsbury9bac3662014-08-07 15:07:01 -0400391 self._setup_network_and_servers()
Yair Friedae0e73d2014-11-24 11:56:26 +0200392 self.check_public_network_connectivity(should_connect=True)
Yair Fried3097dc12014-01-26 08:46:43 +0200393 self._create_new_network()
394 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200395 self._check_network_internal_connectivity(network=self.new_net)