blob: 52a36e63620f2e8cbcfc57dae0c971d54c03424a [file] [log] [blame]
Maru Newby81f07a02012-09-05 20:21:19 -07001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
ZhiQiang Fan39f97222013-09-20 04:49:44 +08003# Copyright 2012 OpenStack Foundation
Gavin Brebner0f465a32013-03-14 13:26:09 +00004# Copyright 2013 Hewlett-Packard Development Company, L.P.
Maru Newby81f07a02012-09-05 20:21:19 -07005# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
Attila Fazekasaeeeefd2013-08-06 17:01:56 +020019from tempest.common import debug
Masayuki Igawa259c1132013-10-31 17:48:44 +090020from tempest.common.utils import data_utils
Matthew Treinishcb569942013-08-09 16:33:44 -040021from tempest import config
Brent Eaglesc26d4522013-12-02 13:28:49 -050022from tempest.openstack.common import jsonutils
Matthew Treinish2b59f842013-09-09 20:32:51 +000023from tempest.openstack.common import log as logging
Sean Dague6dbc6da2013-05-08 17:49:46 -040024from tempest.scenario import manager
Brent Eaglesc26d4522013-12-02 13:28:49 -050025
26import tempest.test
Maru Newbybd360222013-04-08 22:48:50 +000027from tempest.test import attr
Matthew Treinish2153ec02013-09-09 20:57:30 +000028from tempest.test import services
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
Maru Newby81f07a02012-09-05 20:21:19 -070033
Brent Eaglesc26d4522013-12-02 13:28:49 -050034class FloatingIPCheckTracker(object):
35 """
36 Checking VM connectivity through floating IP addresses is bound to fail
37 if the floating IP has not actually been associated with the VM yet.
38 This helper class facilitates checking for floating IP assignments on
39 VMs. It only checks for a given IP address once.
40 """
41
42 def __init__(self, compute_client, floating_ip_map):
43 self.compute_client = compute_client
Yair Fried9a551c42013-12-15 14:59:34 +020044 self.unchecked = floating_ip_map.copy()
Brent Eaglesc26d4522013-12-02 13:28:49 -050045
46 def run_checks(self):
47 """Check for any remaining unverified floating IPs
48
49 Gets VM details from nova and checks for floating IPs
50 within the returned information. Returns true when all
51 checks are complete and is suitable for use with
52 tempest.test.call_until_true()
53 """
54 to_delete = []
55 loggable_map = {}
Yair Fried9a551c42013-12-15 14:59:34 +020056 for check_addr, server in self.unchecked.iteritems():
57 serverdata = self.compute_client.servers.get(server.id)
58 ip_addr = [addr for sublist in serverdata.networks.values() for
59 addr in sublist]
60 if check_addr.floating_ip_address in ip_addr:
61 to_delete.append(check_addr)
Brent Eaglesc26d4522013-12-02 13:28:49 -050062 else:
Yair Fried9a551c42013-12-15 14:59:34 +020063 loggable_map[server.id] = check_addr
Brent Eaglesc26d4522013-12-02 13:28:49 -050064
65 for to_del in to_delete:
66 del self.unchecked[to_del]
67
68 LOG.debug('Unchecked floating IPs: %s',
69 jsonutils.dumps(loggable_map))
70 return len(self.unchecked) == 0
71
72
Sean Dague6dbc6da2013-05-08 17:49:46 -040073class TestNetworkBasicOps(manager.NetworkScenarioTest):
Maru Newby81f07a02012-09-05 20:21:19 -070074
75 """
76 This smoke test suite assumes that Nova has been configured to
Mark McClainf2982e82013-07-06 17:48:03 -040077 boot VM's with Neutron-managed networking, and attempts to
Maru Newby81f07a02012-09-05 20:21:19 -070078 verify network connectivity as follows:
79
80 * For a freshly-booted VM with an IP address ("port") on a given network:
81
Maru Newbyaf292e82013-05-20 21:32:28 +000082 - the Tempest host can ping the IP address. This implies, but
83 does not guarantee (see the ssh check that follows), that the
84 VM has been assigned the correct IP address and has
Maru Newby81f07a02012-09-05 20:21:19 -070085 connectivity to the Tempest host.
86
Maru Newbyaf292e82013-05-20 21:32:28 +000087 - the Tempest host can perform key-based authentication to an
88 ssh server hosted at the IP address. This check guarantees
89 that the IP address is associated with the target VM.
90
Yair Fried9a551c42013-12-15 14:59:34 +020091 - detach the floating-ip from the VM and verify that it becomes
92 unreachable
93
Yair Fried05db2522013-11-18 11:02:10 +020094 - associate detached floating ip to a new VM and verify connectivity.
95 VMs are created with unique keypair so connectivity also asserts that
96 floating IP is associated with the new VM instead of the old one
97
Attila Fazekasc3a095b2013-08-17 09:15:44 +020098 # TODO(mnewby) - Need to implement the following:
Maru Newby81f07a02012-09-05 20:21:19 -070099 - the Tempest host can ssh into the VM via the IP address and
100 successfully execute the following:
101
102 - ping an external IP address, implying external connectivity.
103
104 - ping an external hostname, implying that dns is correctly
105 configured.
106
107 - ping an internal IP address, implying connectivity to another
108 VM on the same network.
109
110 There are presumed to be two types of networks: tenant and
111 public. A tenant network may or may not be reachable from the
112 Tempest host. A public network is assumed to be reachable from
113 the Tempest host, and it should be possible to associate a public
114 ('floating') IP address with a tenant ('fixed') IP address to
Chang Bo Guocc1623c2013-09-13 20:11:27 -0700115 facilitate external connectivity to a potentially unroutable
Maru Newby81f07a02012-09-05 20:21:19 -0700116 tenant IP address.
117
118 This test suite can be configured to test network connectivity to
119 a VM via a tenant network, a public network, or both. If both
120 networking types are to be evaluated, tests that need to be
121 executed remotely on the VM (via ssh) will only be run against
122 one of the networks (to minimize test execution time).
123
124 Determine which types of networks to test as follows:
125
126 * Configure tenant network checks (via the
127 'tenant_networks_reachable' key) if the Tempest host should
128 have direct connectivity to tenant networks. This is likely to
129 be the case if Tempest is running on the same host as a
130 single-node devstack installation with IP namespaces disabled.
131
132 * Configure checks for a public network if a public network has
133 been configured prior to the test suite being run and if the
134 Tempest host should have connectivity to that public network.
135 Checking connectivity for a public network requires that a
136 value be provided for 'public_network_id'. A value can
137 optionally be provided for 'public_router_id' if tenants will
138 use a shared router to access a public network (as is likely to
139 be the case when IP namespaces are not enabled). If a value is
140 not provided for 'public_router_id', a router will be created
141 for each tenant and use the network identified by
142 'public_network_id' as its gateway.
143
144 """
145
146 @classmethod
147 def check_preconditions(cls):
Gavin Brebner0f465a32013-03-14 13:26:09 +0000148 super(TestNetworkBasicOps, cls).check_preconditions()
Maru Newby81f07a02012-09-05 20:21:19 -0700149 cfg = cls.config.network
Maru Newby81f07a02012-09-05 20:21:19 -0700150 if not (cfg.tenant_networks_reachable or cfg.public_network_id):
151 msg = ('Either tenant_networks_reachable must be "true", or '
152 'public_network_id must be defined.')
Gavin Brebner0f465a32013-03-14 13:26:09 +0000153 cls.enabled = False
ivan-zhu1feeb382013-01-24 10:14:39 +0800154 raise cls.skipException(msg)
Maru Newby81f07a02012-09-05 20:21:19 -0700155
156 @classmethod
157 def setUpClass(cls):
158 super(TestNetworkBasicOps, cls).setUpClass()
159 cls.check_preconditions()
Maru Newby81f07a02012-09-05 20:21:19 -0700160 # TODO(mnewby) Consider looking up entities as needed instead
161 # of storing them as collections on the class.
Maru Newby81f07a02012-09-05 20:21:19 -0700162 cls.security_groups = {}
163 cls.networks = []
Gavin Brebner851c3502013-01-18 13:14:10 +0000164 cls.subnets = []
165 cls.routers = []
Yair Fried05db2522013-11-18 11:02:10 +0200166 cls.servers = {}
Maru Newby81f07a02012-09-05 20:21:19 -0700167 cls.floating_ips = {}
168
Matthew Treinish2b59f842013-09-09 20:32:51 +0000169 def _create_security_groups(self):
Yair Friedeb69f3f2013-10-10 13:18:16 +0300170 self.security_groups[self.tenant_id] =\
171 self._create_security_group_neutron(tenant_id=self.tenant_id)
Maru Newby81f07a02012-09-05 20:21:19 -0700172
Matthew Treinish2b59f842013-09-09 20:32:51 +0000173 def _check_networks(self):
Attila Fazekasc3a095b2013-08-17 09:15:44 +0200174 # Checks that we see the newly created network/subnet/router via
175 # checking the result of list_[networks,routers,subnets]
Gavin Brebner851c3502013-01-18 13:14:10 +0000176 seen_nets = self._list_networks()
177 seen_names = [n['name'] for n in seen_nets]
178 seen_ids = [n['id'] for n in seen_nets]
179 for mynet in self.networks:
Gavin Brebner0f465a32013-03-14 13:26:09 +0000180 self.assertIn(mynet.name, seen_names)
181 self.assertIn(mynet.id, seen_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000182 seen_subnets = self._list_subnets()
183 seen_net_ids = [n['network_id'] for n in seen_subnets]
184 seen_subnet_ids = [n['id'] for n in seen_subnets]
185 for mynet in self.networks:
Gavin Brebner0f465a32013-03-14 13:26:09 +0000186 self.assertIn(mynet.id, seen_net_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000187 for mysubnet in self.subnets:
Gavin Brebner0f465a32013-03-14 13:26:09 +0000188 self.assertIn(mysubnet.id, seen_subnet_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000189 seen_routers = self._list_routers()
190 seen_router_ids = [n['id'] for n in seen_routers]
191 seen_router_names = [n['name'] for n in seen_routers]
192 for myrouter in self.routers:
Gavin Brebner0f465a32013-03-14 13:26:09 +0000193 self.assertIn(myrouter.name, seen_router_names)
194 self.assertIn(myrouter.id, seen_router_ids)
Gavin Brebner851c3502013-01-18 13:14:10 +0000195
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700196 def _create_server(self, name, network):
197 tenant_id = network.tenant_id
Yair Fried05db2522013-11-18 11:02:10 +0200198 keypair = self.create_keypair(name='keypair-%s' % name)
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700199 security_groups = [self.security_groups[tenant_id].name]
200 create_kwargs = {
201 'nics': [
202 {'net-id': network.id},
203 ],
Yair Fried05db2522013-11-18 11:02:10 +0200204 'key_name': keypair.name,
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700205 'security_groups': security_groups,
206 }
Giulio Fidente61cadca2013-09-24 18:33:37 +0200207 server = self.create_server(name=name, create_kwargs=create_kwargs)
Yair Fried05db2522013-11-18 11:02:10 +0200208 self.servers[server] = keypair
Salvatore Orlando5ed3b6e2013-09-17 01:27:26 -0700209 return server
210
Matthew Treinish2b59f842013-09-09 20:32:51 +0000211 def _create_servers(self):
Maru Newby81f07a02012-09-05 20:21:19 -0700212 for i, network in enumerate(self.networks):
Masayuki Igawa259c1132013-10-31 17:48:44 +0900213 name = data_utils.rand_name('server-smoke-%d-' % i)
Yair Fried05db2522013-11-18 11:02:10 +0200214 self._create_server(name, network)
Maru Newby81f07a02012-09-05 20:21:19 -0700215
Nachi Ueno4fb7ce62014-01-09 18:29:34 -0800216 def _log_console_output(self):
217 for server, key in self.servers.items():
218 LOG.debug('Console output for %s', server.id)
219 LOG.debug(server.get_console_output())
220
Matthew Treinish2b59f842013-09-09 20:32:51 +0000221 def _check_tenant_network_connectivity(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500222 if not CONF.network.tenant_networks_reachable:
Maru Newby81f07a02012-09-05 20:21:19 -0700223 msg = 'Tenant networks not configured to be reachable.'
Matthew Treinish2b59f842013-09-09 20:32:51 +0000224 LOG.info(msg)
225 return
Maru Newbyaf292e82013-05-20 21:32:28 +0000226 # The target login is assumed to have been configured for
227 # key-based authentication by cloud-init.
Sean Dague86bd8422013-12-20 09:56:44 -0500228 ssh_login = CONF.compute.image_ssh_user
Brent Eaglesc26d4522013-12-02 13:28:49 -0500229 try:
Yair Fried05db2522013-11-18 11:02:10 +0200230 for server, key in self.servers.items():
Brent Eaglesc26d4522013-12-02 13:28:49 -0500231 for net_name, ip_addresses in server.networks.iteritems():
232 for ip_address in ip_addresses:
233 self._check_vm_connectivity(ip_address, ssh_login,
Yair Fried05db2522013-11-18 11:02:10 +0200234 key.private_key)
Yair Frieda039f872014-01-02 12:11:10 +0200235 except Exception:
236 LOG.exception('Tenant connectivity check failed')
Nachi Ueno4fb7ce62014-01-09 18:29:34 -0800237 self._log_console_output()
Brent Eaglesc26d4522013-12-02 13:28:49 -0500238 debug.log_ip_ns()
Yair Frieda039f872014-01-02 12:11:10 +0200239 raise
Brent Eaglesc26d4522013-12-02 13:28:49 -0500240
241 def _wait_for_floating_ip_association(self):
242 ip_tracker = FloatingIPCheckTracker(self.compute_client,
243 self.floating_ips)
244
245 self.assertTrue(
246 tempest.test.call_until_true(
Sean Dague86bd8422013-12-20 09:56:44 -0500247 ip_tracker.run_checks, CONF.compute.build_timeout,
248 CONF.compute.build_interval),
Brent Eaglesc26d4522013-12-02 13:28:49 -0500249 "Timed out while waiting for the floating IP assignments "
250 "to propagate")
Maru Newby81f07a02012-09-05 20:21:19 -0700251
Yair Fried9a551c42013-12-15 14:59:34 +0200252 def _create_and_associate_floating_ips(self):
Sean Dague86bd8422013-12-20 09:56:44 -0500253 public_network_id = CONF.network.public_network_id
Yair Fried05db2522013-11-18 11:02:10 +0200254 for server in self.servers.keys():
Maru Newby81f07a02012-09-05 20:21:19 -0700255 floating_ip = self._create_floating_ip(server, public_network_id)
Yair Fried9a551c42013-12-15 14:59:34 +0200256 self.floating_ips[floating_ip] = server
Maru Newby81f07a02012-09-05 20:21:19 -0700257
Yair Fried9a551c42013-12-15 14:59:34 +0200258 def _check_public_network_connectivity(self, should_connect=True):
Maru Newbyaf292e82013-05-20 21:32:28 +0000259 # The target login is assumed to have been configured for
260 # key-based authentication by cloud-init.
Sean Dague86bd8422013-12-20 09:56:44 -0500261 ssh_login = CONF.compute.image_ssh_user
Nachi Ueno4fb7ce62014-01-09 18:29:34 -0800262 LOG.debug('checking network connections')
Attila Fazekasaeeeefd2013-08-06 17:01:56 +0200263 try:
Yair Fried9a551c42013-12-15 14:59:34 +0200264 for floating_ip, server in self.floating_ips.iteritems():
265 ip_address = floating_ip.floating_ip_address
Yair Fried05db2522013-11-18 11:02:10 +0200266 private_key = None
267 if should_connect:
268 private_key = self.servers[server].private_key
Yair Fried9a551c42013-12-15 14:59:34 +0200269 self._check_vm_connectivity(ip_address,
270 ssh_login,
271 private_key,
272 should_connect=should_connect)
Yair Frieda039f872014-01-02 12:11:10 +0200273 except Exception:
274 LOG.exception('Public network connectivity check failed')
Nachi Ueno4fb7ce62014-01-09 18:29:34 -0800275 self._log_console_output()
Attila Fazekasaeeeefd2013-08-06 17:01:56 +0200276 debug.log_ip_ns()
Yair Frieda039f872014-01-02 12:11:10 +0200277 raise
Matthew Treinish2b59f842013-09-09 20:32:51 +0000278
Yair Fried9a551c42013-12-15 14:59:34 +0200279 def _disassociate_floating_ips(self):
280 for floating_ip, server in self.floating_ips.iteritems():
281 self._disassociate_floating_ip(floating_ip)
282 self.floating_ips[floating_ip] = None
283
Yair Fried05db2522013-11-18 11:02:10 +0200284 def _reassociate_floating_ips(self):
285 network = self.networks[0]
286 for floating_ip in self.floating_ips.keys():
287 name = data_utils.rand_name('new_server-smoke-')
288 # create a new server for the floating ip
289 server = self._create_server(name, network)
290 self._associate_floating_ip(floating_ip, server)
291 self.floating_ips[floating_ip] = server
292
Matthew Treinish2b59f842013-09-09 20:32:51 +0000293 @attr(type='smoke')
Matthew Treinish2153ec02013-09-09 20:57:30 +0000294 @services('compute', 'network')
Matthew Treinish2b59f842013-09-09 20:32:51 +0000295 def test_network_basic_ops(self):
Matthew Treinish2b59f842013-09-09 20:32:51 +0000296 self._create_security_groups()
297 self._create_networks()
298 self._check_networks()
299 self._create_servers()
Yair Fried9a551c42013-12-15 14:59:34 +0200300 self._create_and_associate_floating_ips()
Brent Eaglesc26d4522013-12-02 13:28:49 -0500301 self._wait_for_floating_ip_association()
Salvatore Orlando8d076cb2013-09-16 11:00:44 -0700302 self._check_tenant_network_connectivity()
Yair Fried9a551c42013-12-15 14:59:34 +0200303 self._check_public_network_connectivity(should_connect=True)
304 self._disassociate_floating_ips()
305 self._check_public_network_connectivity(should_connect=False)
Yair Fried05db2522013-11-18 11:02:10 +0200306 self._reassociate_floating_ips()
307 self._wait_for_floating_ip_association()
308 self._check_public_network_connectivity(should_connect=True)