blob: fc6c66ccb5840c00df293ca093414723f6db2cac [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
21from tempest.api.network import common as net_common
Attila Fazekasaeeeefd2013-08-06 17:01:56 +020022from tempest.common import debug
Masayuki Igawa259c1132013-10-31 17:48:44 +090023from tempest.common.utils import data_utils
Matthew Treinishcb569942013-08-09 16:33:44 -040024from tempest import config
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
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090027from tempest import test
Maru Newby81f07a02012-09-05 20:21:19 -070028
Sean Dague86bd8422013-12-20 09:56:44 -050029CONF = config.CONF
Matthew Treinish2b59f842013-09-09 20:32:51 +000030LOG = logging.getLogger(__name__)
31
Yair Fried2d2f3fe2014-02-24 16:19:20 +020032Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
33 ['floating_ip', 'server'])
34
Maru Newby81f07a02012-09-05 20:21:19 -070035
Sean Dague6dbc6da2013-05-08 17:49:46 -040036class TestNetworkBasicOps(manager.NetworkScenarioTest):
Maru Newby81f07a02012-09-05 20:21:19 -070037
38 """
39 This smoke test suite assumes that Nova has been configured to
Mark McClainf2982e82013-07-06 17:48:03 -040040 boot VM's with Neutron-managed networking, and attempts to
Maru Newby81f07a02012-09-05 20:21:19 -070041 verify network connectivity as follows:
42
Maru Newby81f07a02012-09-05 20:21:19 -070043 There are presumed to be two types of networks: tenant and
44 public. A tenant network may or may not be reachable from the
45 Tempest host. A public network is assumed to be reachable from
46 the Tempest host, and it should be possible to associate a public
47 ('floating') IP address with a tenant ('fixed') IP address to
Chang Bo Guocc1623c2013-09-13 20:11:27 -070048 facilitate external connectivity to a potentially unroutable
Maru Newby81f07a02012-09-05 20:21:19 -070049 tenant IP address.
50
51 This test suite can be configured to test network connectivity to
52 a VM via a tenant network, a public network, or both. If both
53 networking types are to be evaluated, tests that need to be
54 executed remotely on the VM (via ssh) will only be run against
55 one of the networks (to minimize test execution time).
56
57 Determine which types of networks to test as follows:
58
59 * Configure tenant network checks (via the
60 'tenant_networks_reachable' key) if the Tempest host should
61 have direct connectivity to tenant networks. This is likely to
62 be the case if Tempest is running on the same host as a
63 single-node devstack installation with IP namespaces disabled.
64
65 * Configure checks for a public network if a public network has
66 been configured prior to the test suite being run and if the
67 Tempest host should have connectivity to that public network.
68 Checking connectivity for a public network requires that a
69 value be provided for 'public_network_id'. A value can
70 optionally be provided for 'public_router_id' if tenants will
71 use a shared router to access a public network (as is likely to
72 be the case when IP namespaces are not enabled). If a value is
73 not provided for 'public_router_id', a router will be created
74 for each tenant and use the network identified by
75 'public_network_id' as its gateway.
76
77 """
78
79 @classmethod
80 def check_preconditions(cls):
Gavin Brebner0f465a32013-03-14 13:26:09 +000081 super(TestNetworkBasicOps, cls).check_preconditions()
Matthew Treinish6c072292014-01-29 19:15:52 +000082 if not (CONF.network.tenant_networks_reachable
83 or CONF.network.public_network_id):
Maru Newby81f07a02012-09-05 20:21:19 -070084 msg = ('Either tenant_networks_reachable must be "true", or '
85 'public_network_id must be defined.')
Gavin Brebner0f465a32013-03-14 13:26:09 +000086 cls.enabled = False
ivan-zhu1feeb382013-01-24 10:14:39 +080087 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070088
89 @classmethod
90 def setUpClass(cls):
Yair Fried764610a2014-04-07 12:17:05 +030091 # Create no network resources for these tests.
92 cls.set_network_resources()
Maru Newby81f07a02012-09-05 20:21:19 -070093 super(TestNetworkBasicOps, cls).setUpClass()
Yoshihiro Kaneko05670262014-01-18 19:22:44 +090094 for ext in ['router', 'security-group']:
95 if not test.is_extension_enabled(ext, 'network'):
96 msg = "%s extension not enabled." % ext
97 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -070098 cls.check_preconditions()
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 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.network, self.subnet, self.router = self._create_networks()
Yair Frieded8392f2014-01-15 17:21:35 +0200105 self.check_networks()
106 self.servers = {}
107 name = data_utils.rand_name('server-smoke')
108 serv_dict = self._create_server(name, self.network)
109 self.servers[serv_dict['server']] = serv_dict['keypair']
110 self._check_tenant_network_connectivity()
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200111
Yair Frieded8392f2014-01-15 17:21:35 +0200112 self._create_and_associate_floating_ips()
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 Fried05db2522013-11-18 11:02:10 +0200141 keypair = self.create_keypair(name='keypair-%s' % name)
Yair Frieded8392f2014-01-15 17:21:35 +0200142 security_groups = [self.security_group.name]
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700143 create_kwargs = {
144 'nics': [
145 {'net-id': network.id},
146 ],
Yair Fried05db2522013-11-18 11:02:10 +0200147 'key_name': keypair.name,
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700148 'security_groups': security_groups,
149 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200150 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Frieded8392f2014-01-15 17:21:35 +0200151 return dict(server=server, keypair=keypair)
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700152
Matthew Treinish2b59f842013-09-09 20:32:51 +0000153 def _check_tenant_network_connectivity(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500154 ssh_login = CONF.compute.image_ssh_user
Matt Riedemann2d005be2014-05-27 10:52:35 -0700155 for server, key in self.servers.iteritems():
156 # call the common method in the parent class
157 super(TestNetworkBasicOps, self).\
158 _check_tenant_network_connectivity(
159 server, ssh_login, key.private_key,
160 servers_for_debug=self.servers.keys())
Brent Eaglesc26d4522013-12-02 13:28:49 -0500161
Yair Fried9a551c42013-12-15 14:59:34 +0200162 def _create_and_associate_floating_ips(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500163 public_network_id = CONF.network.public_network_id
Yair Fried05db2522013-11-18 11:02:10 +0200164 for server in self.servers.keys():
Maru Newby81f07a02012-09-05 20:21:19 -0700165 floating_ip = self._create_floating_ip(server, public_network_id)
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200166 self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
Maru Newby81f07a02012-09-05 20:21:19 -0700167
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200168 def _check_public_network_connectivity(self, should_connect=True,
169 msg=None):
Sean Dague86bd8422013-12-20 09:56:44 -0500170 ssh_login = CONF.compute.image_ssh_user
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200171 floating_ip, server = self.floating_ip_tuple
172 ip_address = floating_ip.floating_ip_address
173 private_key = None
174 if should_connect:
175 private_key = self.servers[server].private_key
Matt Riedemann343305f2014-05-27 09:55:03 -0700176 # call the common method in the parent class
177 super(TestNetworkBasicOps, self)._check_public_network_connectivity(
178 ip_address, ssh_login, private_key, should_connect, msg,
179 self.servers.keys())
Matthew Treinish2b59f842013-09-09 20:32:51 +0000180
Yair Fried9a551c42013-12-15 14:59:34 +0200181 def _disassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200182 floating_ip, server = self.floating_ip_tuple
183 self._disassociate_floating_ip(floating_ip)
184 self.floating_ip_tuple = Floating_IP_tuple(
185 floating_ip, None)
Yair Fried9a551c42013-12-15 14:59:34 +0200186
Yair Fried05db2522013-11-18 11:02:10 +0200187 def _reassociate_floating_ips(self):
Yair Fried2d2f3fe2014-02-24 16:19:20 +0200188 floating_ip, server = self.floating_ip_tuple
189 name = data_utils.rand_name('new_server-smoke-')
190 # create a new server for the floating ip
191 serv_dict = self._create_server(name, self.network)
192 self.servers[serv_dict['server']] = serv_dict['keypair']
193 self._associate_floating_ip(floating_ip, serv_dict['server'])
194 self.floating_ip_tuple = Floating_IP_tuple(
195 floating_ip, serv_dict['server'])
Yair Fried05db2522013-11-18 11:02:10 +0200196
Yair Fried3097dc12014-01-26 08:46:43 +0200197 def _create_new_network(self):
198 self.new_net = self._create_network(self.tenant_id)
Yair Fried3097dc12014-01-26 08:46:43 +0200199 self.new_subnet = self._create_subnet(
200 network=self.new_net,
201 gateway_ip=None)
Yair Fried3097dc12014-01-26 08:46:43 +0200202
203 def _hotplug_server(self):
204 old_floating_ip, server = self.floating_ip_tuple
205 ip_address = old_floating_ip.floating_ip_address
206 private_key = self.servers[server].private_key
207 ssh_client = self.get_remote_client(ip_address,
208 private_key=private_key)
209 old_nic_list = self._get_server_nics(ssh_client)
210 # get a port from a list of one item
211 port_list = self._list_ports(device_id=server.id)
212 self.assertEqual(1, len(port_list))
213 old_port = port_list[0]
214 self.compute_client.servers.interface_attach(server=server,
215 net_id=self.new_net.id,
216 port_id=None,
217 fixed_ip=None)
218 # move server to the head of the cleanup list
Matthew Treinishb7144eb2013-12-13 22:57:35 +0000219 self.addCleanup(self.delete_timeout,
220 self.compute_client.servers,
221 server.id)
222 self.addCleanup(self.delete_wrapper, server)
Yair Fried3097dc12014-01-26 08:46:43 +0200223
224 def check_ports():
225 port_list = [port for port in
226 self._list_ports(device_id=server.id)
227 if port != old_port]
228 return len(port_list) == 1
229
230 test.call_until_true(check_ports, 60, 1)
231 new_port_list = [p for p in
232 self._list_ports(device_id=server.id)
233 if p != old_port]
234 self.assertEqual(1, len(new_port_list))
235 new_port = new_port_list[0]
236 new_port = net_common.DeletablePort(client=self.network_client,
237 **new_port)
238 new_nic_list = self._get_server_nics(ssh_client)
239 diff_list = [n for n in new_nic_list if n not in old_nic_list]
240 self.assertEqual(1, len(diff_list))
241 num, new_nic = diff_list[0]
242 ssh_client.assign_static_ip(nic=new_nic,
243 addr=new_port.fixed_ips[0]['ip_address'])
244 ssh_client.turn_nic_on(nic=new_nic)
245
246 def _get_server_nics(self, ssh_client):
247 reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
248 ipatxt = ssh_client.get_ip_list()
249 return reg.findall(ipatxt)
250
Yair Fried06552292013-11-11 12:10:09 +0200251 def _check_network_internal_connectivity(self, network):
Yair Fried3097dc12014-01-26 08:46:43 +0200252 """
253 via ssh check VM internal connectivity:
Yair Fried06552292013-11-11 12:10:09 +0200254 - ping internal gateway and DHCP port, implying in-tenant connectivity
255 pinging both, because L3 and DHCP agents might be on different nodes
Yair Fried3097dc12014-01-26 08:46:43 +0200256 """
257 floating_ip, server = self.floating_ip_tuple
258 # get internal ports' ips:
259 # get all network ports in the new network
260 internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
261 self._list_ports(tenant_id=server.tenant_id,
Yair Fried06552292013-11-11 12:10:09 +0200262 network_id=network.id)
Yair Fried3097dc12014-01-26 08:46:43 +0200263 if p['device_owner'].startswith('network'))
264
Yair Fried06552292013-11-11 12:10:09 +0200265 self._check_server_connectivity(floating_ip, internal_ips)
266
267 def _check_network_external_connectivity(self):
268 """
269 ping public network default gateway to imply external connectivity
270
271 """
272 if not CONF.network.public_network_id:
273 msg = 'public network not defined.'
274 LOG.info(msg)
275 return
276
277 subnet = self.network_client.list_subnets(
278 network_id=CONF.network.public_network_id)['subnets']
279 self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
280
281 external_ips = [subnet[0]['gateway_ip']]
282 self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
283 external_ips)
284
285 def _check_server_connectivity(self, floating_ip, address_list):
Yair Fried3097dc12014-01-26 08:46:43 +0200286 ip_address = floating_ip.floating_ip_address
Yair Fried06552292013-11-11 12:10:09 +0200287 private_key = self.servers[self.floating_ip_tuple.server].private_key
Yair Fried3097dc12014-01-26 08:46:43 +0200288 ssh_source = self._ssh_to_server(ip_address, private_key)
289
Yair Fried06552292013-11-11 12:10:09 +0200290 for remote_ip in address_list:
Yair Fried3097dc12014-01-26 08:46:43 +0200291 try:
292 self.assertTrue(self._check_remote_connectivity(ssh_source,
293 remote_ip),
294 "Timed out waiting for %s to become "
295 "reachable" % remote_ip)
296 except Exception:
297 LOG.exception("Unable to access {dest} via ssh to "
298 "floating-ip {src}".format(dest=remote_ip,
299 src=floating_ip))
300 debug.log_ip_ns()
301 raise
302
Yoshihiro Kaneko05670262014-01-18 19:22:44 +0900303 @test.attr(type='smoke')
304 @test.services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000305 def test_network_basic_ops(self):
Yair Fried3097dc12014-01-26 08:46:43 +0200306 """
307 For a freshly-booted VM with an IP address ("port") on a given
308 network:
309
310 - the Tempest host can ping the IP address. This implies, but
311 does not guarantee (see the ssh check that follows), that the
312 VM has been assigned the correct IP address and has
313 connectivity to the Tempest host.
314
315 - the Tempest host can perform key-based authentication to an
316 ssh server hosted at the IP address. This check guarantees
317 that the IP address is associated with the target VM.
318
Yair Fried3097dc12014-01-26 08:46:43 +0200319 - the Tempest host can ssh into the VM via the IP address and
320 successfully execute the following:
321
322 - ping an external IP address, implying external connectivity.
323
324 - ping an external hostname, implying that dns is correctly
325 configured.
326
327 - ping an internal IP address, implying connectivity to another
328 VM on the same network.
329
Yair Fried06552292013-11-11 12:10:09 +0200330 - detach the floating-ip from the VM and verify that it becomes
331 unreachable
332
333 - associate detached floating ip to a new VM and verify connectivity.
334 VMs are created with unique keypair so connectivity also asserts that
335 floating IP is associated with the new VM instead of the old one
336
337
Yair Fried3097dc12014-01-26 08:46:43 +0200338 """
Yair Fried9a551c42013-12-15 14:59:34 +0200339 self._check_public_network_connectivity(should_connect=True)
Yair Fried06552292013-11-11 12:10:09 +0200340 self._check_network_internal_connectivity(network=self.network)
341 self._check_network_external_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200342 self._disassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200343 self._check_public_network_connectivity(should_connect=False,
344 msg="after disassociate "
345 "floating ip")
Yair Fried05db2522013-11-18 11:02:10 +0200346 self._reassociate_floating_ips()
Yair Frieda4b0d1d2014-01-26 13:59:54 +0200347 self._check_public_network_connectivity(should_connect=True,
348 msg="after re-associate "
349 "floating ip")
Yair Fried3097dc12014-01-26 08:46:43 +0200350
Adam Gandelman7186f7a2014-07-23 09:28:56 -0400351 @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
352 'NIC hotplug not available')
Yair Fried3097dc12014-01-26 08:46:43 +0200353 @test.attr(type='smoke')
354 @test.services('compute', 'network')
355 def test_hotplug_nic(self):
356 """
357 1. create a new network, with no gateway (to prevent overwriting VM's
358 gateway)
359 2. connect VM to new network
360 3. set static ip and bring new nic up
361 4. check VM can ping new network dhcp port
362
363 """
364
365 self._check_public_network_connectivity(should_connect=True)
366 self._create_new_network()
367 self._hotplug_server()
Yair Fried06552292013-11-11 12:10:09 +0200368 self._check_network_internal_connectivity(network=self.new_net)