blob: eeb58d622a13744f2c06aedcff1369f5593ca350 [file] [log] [blame]
Dan Smith8ad1c472013-02-26 13:03:16 -05001# Copyright 2013 IBM Corp.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Rohan Kanade9ce97df2013-12-10 18:59:35 +053016import time
17
junbolibc2ae862017-07-29 15:46:48 +080018import six
19
Sean Dague1937d092013-05-17 16:36:38 -040020from tempest.api.compute import base
Matt Riedemanna8c641a2016-07-12 17:07:33 -040021from tempest.common import compute
Andrea Frittolicd368412017-08-14 21:37:56 +010022from tempest.common import utils
Ryan Tidwell1964a262016-05-04 15:13:23 -070023from tempest.common.utils import net_utils
Matt Riedemanna8c641a2016-07-12 17:07:33 -040024from tempest.common import waiters
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000025from tempest import config
Lucas Alvares Gomes692422b2018-10-10 10:33:45 +010026from tempest.lib.common.utils.linux import remote_client
Matt Riedemannd4cb10f2018-09-26 13:03:08 -040027from tempest.lib.common.utils import test_utils
Matt Riedemann3570c1e2016-07-29 12:15:38 -040028from tempest.lib import decorators
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050029from tempest.lib import exceptions as lib_exc
Dan Smith8ad1c472013-02-26 13:03:16 -050030
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000031CONF = config.CONF
32
Dan Smith8ad1c472013-02-26 13:03:16 -050033
zhufl615e63b2018-08-01 17:23:38 +080034class AttachInterfacesTestBase(base.BaseV2ComputeTest):
Dan Smith8ad1c472013-02-26 13:03:16 -050035
36 @classmethod
Emily Hugenbruche7991d92014-12-12 16:53:36 +000037 def skip_checks(cls):
zhufl615e63b2018-08-01 17:23:38 +080038 super(AttachInterfacesTestBase, cls).skip_checks()
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000039 if not CONF.service_available.neutron:
Mark McClainf2982e82013-07-06 17:48:03 -040040 raise cls.skipException("Neutron is required")
Adam Gandelman7186f7a2014-07-23 09:28:56 -040041 if not CONF.compute_feature_enabled.interface_attach:
42 raise cls.skipException("Interface attachment is not available.")
Artom Lifshitzb4775942018-09-05 16:24:01 +030043 if not CONF.validation.run_validation:
44 raise cls.skipException('Validation should be enabled to ensure '
45 'guest OS is running and capable of '
46 'processing ACPI events.')
Emily Hugenbruche7991d92014-12-12 16:53:36 +000047
48 @classmethod
49 def setup_credentials(cls):
Salvatore Orlando5a337242014-01-15 22:49:22 +000050 # This test class requires network and subnet
Artom Lifshitzb4775942018-09-05 16:24:01 +030051 cls.set_network_resources(network=True, subnet=True, router=True,
52 dhcp=True)
zhufl615e63b2018-08-01 17:23:38 +080053 super(AttachInterfacesTestBase, cls).setup_credentials()
Emily Hugenbruche7991d92014-12-12 16:53:36 +000054
55 @classmethod
56 def setup_clients(cls):
zhufl615e63b2018-08-01 17:23:38 +080057 super(AttachInterfacesTestBase, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +020058 cls.subnets_client = cls.os_primary.subnets_client
59 cls.ports_client = cls.os_primary.ports_client
Dan Smith8ad1c472013-02-26 13:03:16 -050060
Artom Lifshitzb4775942018-09-05 16:24:01 +030061 def _wait_for_validation(self, server, validation_resources):
62 linux_client = remote_client.RemoteClient(
63 self.get_server_ip(server, validation_resources),
64 self.image_ssh_user,
65 self.image_ssh_password,
66 validation_resources['keypair']['private_key'],
67 server=server,
68 servers_client=self.servers_client)
69 linux_client.validate_authentication()
70
zhufl615e63b2018-08-01 17:23:38 +080071 def _create_server_get_interfaces(self):
Artom Lifshitzb4775942018-09-05 16:24:01 +030072 validation_resources = self.get_test_validation_resources(
73 self.os_primary)
74 server = self.create_test_server(
75 validatable=True,
76 validation_resources=validation_resources,
77 wait_until='ACTIVE')
78 # NOTE(artom) self.create_test_server adds cleanups, but this is
79 # apparently not enough? Add cleanup here.
80 self.addCleanup(self.delete_server, server['id'])
81 self._wait_for_validation(server, validation_resources)
zhufl615e63b2018-08-01 17:23:38 +080082 ifs = (self.interfaces_client.list_interfaces(server['id'])
83 ['interfaceAttachments'])
84 body = waiters.wait_for_interface_status(
85 self.interfaces_client, server['id'], ifs[0]['port_id'], 'ACTIVE')
86 ifs[0]['port_state'] = body['port_state']
87 return server, ifs
88
89
90class AttachInterfacesTestJSON(AttachInterfacesTestBase):
91
Matt Riedemanna8c641a2016-07-12 17:07:33 -040092 def wait_for_port_detach(self, port_id):
93 """Waits for the port's device_id to be unset.
94
95 :param port_id: The id of the port being detached.
96 :returns: The final port dict from the show_port response.
97 """
98 port = self.ports_client.show_port(port_id)['port']
99 device_id = port['device_id']
100 start = int(time.time())
101
102 # NOTE(mriedem): Nova updates the port's device_id to '' rather than
103 # None, but it's not contractual so handle Falsey either way.
104 while device_id:
105 time.sleep(self.build_interval)
106 port = self.ports_client.show_port(port_id)['port']
107 device_id = port['device_id']
108
109 timed_out = int(time.time()) - start >= self.build_timeout
110
111 if device_id and timed_out:
112 message = ('Port %s failed to detach (device_id %s) within '
113 'the required time (%s s).' %
114 (port_id, device_id, self.build_timeout))
guo yunxianebb15f22016-11-01 21:03:35 +0800115 raise lib_exc.TimeoutException(message)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400116
117 return port
118
lianghao16353342017-11-28 21:08:12 +0800119 def _check_interface(self, iface, server_id=None, port_id=None,
120 network_id=None, fixed_ip=None, mac_addr=None):
121 if server_id:
122 iface = waiters.wait_for_interface_status(
123 self.interfaces_client, server_id, iface['port_id'], 'ACTIVE')
Dan Smith8ad1c472013-02-26 13:03:16 -0500124 if port_id:
125 self.assertEqual(iface['port_id'], port_id)
126 if network_id:
127 self.assertEqual(iface['net_id'], network_id)
128 if fixed_ip:
129 self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip)
venkata anil45375302014-12-30 10:41:43 +0000130 if mac_addr:
131 self.assertEqual(iface['mac_addr'], mac_addr)
Dan Smith8ad1c472013-02-26 13:03:16 -0500132
Dan Smith8ad1c472013-02-26 13:03:16 -0500133 def _test_create_interface(self, server):
lkuchlan87b5a2d2016-09-27 15:46:16 +0300134 iface = (self.interfaces_client.create_interface(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900135 ['interfaceAttachment'])
zhufl7b638332016-11-14 10:23:30 +0800136 iface = waiters.wait_for_interface_status(
137 self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
Dan Smith8ad1c472013-02-26 13:03:16 -0500138 return iface
139
140 def _test_create_interface_by_network_id(self, server, ifs):
141 network_id = ifs[0]['net_id']
lkuchlan87b5a2d2016-09-27 15:46:16 +0300142 iface = self.interfaces_client.create_interface(
ghanshyama2364f12015-08-24 15:45:37 +0900143 server['id'], net_id=network_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800144 self._check_interface(iface, server_id=server['id'],
145 network_id=network_id)
Dan Smith8ad1c472013-02-26 13:03:16 -0500146 return iface
147
Maho Koshiya3fc12462015-12-14 19:03:12 +0900148 def _test_create_interface_by_port_id(self, server, ifs):
149 network_id = ifs[0]['net_id']
150 port = self.ports_client.create_port(network_id=network_id)
151 port_id = port['port']['id']
152 self.addCleanup(self.ports_client.delete_port, port_id)
lkuchlan87b5a2d2016-09-27 15:46:16 +0300153 iface = self.interfaces_client.create_interface(
Maho Koshiya3fc12462015-12-14 19:03:12 +0900154 server['id'], port_id=port_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800155 self._check_interface(iface, server_id=server['id'], port_id=port_id,
156 network_id=network_id)
Maho Koshiya3fc12462015-12-14 19:03:12 +0900157 return iface
158
Maho Koshiya7b629582016-02-22 10:59:01 +0900159 def _test_create_interface_by_fixed_ips(self, server, ifs):
160 network_id = ifs[0]['net_id']
Ryan Tidwell1964a262016-05-04 15:13:23 -0700161 subnet_id = ifs[0]['fixed_ips'][0]['subnet_id']
162 ip_list = net_utils.get_unused_ip_addresses(self.ports_client,
163 self.subnets_client,
164 network_id,
165 subnet_id,
166 1)
Maho Koshiya7b629582016-02-22 10:59:01 +0900167
Ryan Tidwell1964a262016-05-04 15:13:23 -0700168 fixed_ips = [{'ip_address': ip_list[0]}]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300169 iface = self.interfaces_client.create_interface(
Maho Koshiya7b629582016-02-22 10:59:01 +0900170 server['id'], net_id=network_id,
171 fixed_ips=fixed_ips)['interfaceAttachment']
Attila Fazekas3588bb32018-11-04 12:40:27 +0100172 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
173 self.ports_client.delete_port,
174 iface['port_id'])
lianghao16353342017-11-28 21:08:12 +0800175 self._check_interface(iface, server_id=server['id'],
176 fixed_ip=ip_list[0])
Maho Koshiya7b629582016-02-22 10:59:01 +0900177 return iface
178
Dan Smith8ad1c472013-02-26 13:03:16 -0500179 def _test_show_interface(self, server, ifs):
180 iface = ifs[0]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300181 _iface = self.interfaces_client.show_interface(
ghanshyama2364f12015-08-24 15:45:37 +0900182 server['id'], iface['port_id'])['interfaceAttachment']
venkata anil45375302014-12-30 10:41:43 +0000183 self._check_interface(iface, port_id=_iface['port_id'],
184 network_id=_iface['net_id'],
185 fixed_ip=_iface['fixed_ips'][0]['ip_address'],
186 mac_addr=_iface['mac_addr'])
Dan Smith8ad1c472013-02-26 13:03:16 -0500187
188 def _test_delete_interface(self, server, ifs):
189 # NOTE(danms): delete not the first or last, but one in the middle
190 iface = ifs[1]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300191 self.interfaces_client.delete_interface(server['id'], iface['port_id'])
192 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900193 ['interfaceAttachments'])
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400194 start = int(time.time())
Dan Smith8ad1c472013-02-26 13:03:16 -0500195
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400196 while len(ifs) == len(_ifs):
197 time.sleep(self.build_interval)
lkuchlan87b5a2d2016-09-27 15:46:16 +0300198 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900199 ['interfaceAttachments'])
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400200 timed_out = int(time.time()) - start >= self.build_timeout
201 if len(ifs) == len(_ifs) and timed_out:
202 message = ('Failed to delete interface within '
203 'the required time: %s sec.' % self.build_timeout)
guo yunxianebb15f22016-11-01 21:03:35 +0800204 raise lib_exc.TimeoutException(message)
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400205
206 self.assertNotIn(iface['port_id'], [i['port_id'] for i in _ifs])
Dan Smith8ad1c472013-02-26 13:03:16 -0500207 return _ifs
208
209 def _compare_iface_list(self, list1, list2):
210 # NOTE(danms): port_state will likely have changed, so just
211 # confirm the port_ids are the same at least
212 list1 = [x['port_id'] for x in list1]
213 list2 = [x['port_id'] for x in list2]
214
215 self.assertEqual(sorted(list1), sorted(list2))
216
Ken'ichi Ohmichi14b0ae12017-01-27 17:18:52 -0800217 @decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051')
Andrea Frittolicd368412017-08-14 21:37:56 +0100218 @utils.services('network')
zhufl607cfbf2017-12-28 14:55:08 +0800219 def test_create_list_show_delete_interfaces_by_network_port(self):
Dan Smith8ad1c472013-02-26 13:03:16 -0500220 server, ifs = self._create_server_get_interfaces()
221 interface_count = len(ifs)
zhufl080dcfb2016-10-21 17:45:38 +0800222 self.assertGreater(interface_count, 0)
Dan Smith8ad1c472013-02-26 13:03:16 -0500223
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530224 try:
225 iface = self._test_create_interface(server)
226 except lib_exc.BadRequest as e:
227 msg = ('Multiple possible networks found, use a Network ID to be '
228 'more specific.')
junbolibc2ae862017-07-29 15:46:48 +0800229 if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530230 raise
231 else:
232 ifs.append(iface)
Dan Smith8ad1c472013-02-26 13:03:16 -0500233
234 iface = self._test_create_interface_by_network_id(server, ifs)
235 ifs.append(iface)
236
Maho Koshiya3fc12462015-12-14 19:03:12 +0900237 iface = self._test_create_interface_by_port_id(server, ifs)
238 ifs.append(iface)
239
zhufl607cfbf2017-12-28 14:55:08 +0800240 _ifs = (self.interfaces_client.list_interfaces(server['id'])
241 ['interfaceAttachments'])
242 self._compare_iface_list(ifs, _ifs)
243
244 self._test_show_interface(server, ifs)
245
246 _ifs = self._test_delete_interface(server, ifs)
247 self.assertEqual(len(ifs) - 1, len(_ifs))
248
249 @decorators.idempotent_id('d290c06c-f5b3-11e7-8ec8-002293781009')
250 @utils.services('network')
251 def test_create_list_show_delete_interfaces_by_fixed_ip(self):
252 # NOTE(zhufl) By default only project that is admin or network owner
253 # or project with role advsvc is authorised to create interfaces with
254 # fixed-ip, so if we don't create network for each project, do not
255 # test _test_create_interface_by_fixed_ips.
256 if not (CONF.auth.use_dynamic_credentials and
257 CONF.auth.create_isolated_networks and
258 not CONF.network.shared_physical_network):
Matt Riedemann91d92422019-01-29 16:19:49 -0500259 raise self.skipException("Only owner network supports "
260 "creating interface by fixed ip.")
zhufl607cfbf2017-12-28 14:55:08 +0800261
262 server, ifs = self._create_server_get_interfaces()
263 interface_count = len(ifs)
264 self.assertGreater(interface_count, 0)
265
Maho Koshiya7b629582016-02-22 10:59:01 +0900266 iface = self._test_create_interface_by_fixed_ips(server, ifs)
267 ifs.append(iface)
268
lkuchlan87b5a2d2016-09-27 15:46:16 +0300269 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900270 ['interfaceAttachments'])
Dan Smith8ad1c472013-02-26 13:03:16 -0500271 self._compare_iface_list(ifs, _ifs)
272
273 self._test_show_interface(server, ifs)
274
275 _ifs = self._test_delete_interface(server, ifs)
276 self.assertEqual(len(ifs) - 1, len(_ifs))
277
Ken'ichi Ohmichi14b0ae12017-01-27 17:18:52 -0800278 @decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400279 def test_reassign_port_between_servers(self):
280 """Tests the following:
281
282 1. Create a port in Neutron.
283 2. Create two servers in Nova.
284 3. Attach the port to the first server.
285 4. Detach the port from the first server.
286 5. Attach the port to the second server.
287 6. Detach the port from the second server.
288 """
289 network = self.get_tenant_network()
290 network_id = network['id']
291 port = self.ports_client.create_port(network_id=network_id)
292 port_id = port['port']['id']
293 self.addCleanup(self.ports_client.delete_port, port_id)
294
Artom Lifshitzb4775942018-09-05 16:24:01 +0300295 # NOTE(artom) We create two servers one at a time because
296 # create_test_server doesn't support multiple validatable servers.
297 validation_resources = self.get_test_validation_resources(
298 self.os_primary)
299
300 def _create_validatable_server():
301 _, servers = compute.create_test_server(
302 self.os_primary, tenant_network=network,
303 wait_until='ACTIVE', validatable=True,
304 validation_resources=validation_resources)
305 return servers[0]
306
307 servers = [_create_validatable_server(), _create_validatable_server()]
308
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400309 # add our cleanups for the servers since we bypassed the base class
310 for server in servers:
zhufl1355d982017-01-05 12:06:20 +0800311 self.addCleanup(self.delete_server, server['id'])
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400312
313 for server in servers:
Artom Lifshitzb4775942018-09-05 16:24:01 +0300314 self._wait_for_validation(server, validation_resources)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400315 # attach the port to the server
lkuchlan87b5a2d2016-09-27 15:46:16 +0300316 iface = self.interfaces_client.create_interface(
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400317 server['id'], port_id=port_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800318 self._check_interface(iface, server_id=server['id'],
319 port_id=port_id)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400320
321 # detach the port from the server; this is a cast in the compute
322 # API so we have to poll the port until the device_id is unset.
lkuchlan87b5a2d2016-09-27 15:46:16 +0300323 self.interfaces_client.delete_interface(server['id'], port_id)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400324 self.wait_for_port_detach(port_id)
zhufl615e63b2018-08-01 17:23:38 +0800325
326
327class AttachInterfacesUnderV243Test(AttachInterfacesTestBase):
328 max_microversion = '2.43'
329
330 @decorators.attr(type='smoke')
331 @decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9')
332 @utils.services('network')
333 def test_add_remove_fixed_ip(self):
Matthew Treinishc68546f2018-10-12 10:53:45 -0400334 # NOTE(zhufl) By default only project that is admin or network owner
335 # or project with role advsvc is authorised to add interfaces with
336 # fixed-ip, so if we don't create network for each project, do not
337 # test
338 if not (CONF.auth.use_dynamic_credentials and
339 CONF.auth.create_isolated_networks and
340 not CONF.network.shared_physical_network):
341 raise self.skipException("Only owner network supports "
342 "creating interface by fixed ip.")
343
zhufl615e63b2018-08-01 17:23:38 +0800344 # Add and Remove the fixed IP to server.
345 server, ifs = self._create_server_get_interfaces()
Matt Riedemannd4cb10f2018-09-26 13:03:08 -0400346 original_interface_count = len(ifs) # This is the number of ports.
347 self.assertGreater(original_interface_count, 0)
348 # Get the starting list of IPs on the server.
349 addresses = self.os_primary.servers_client.list_addresses(
350 server['id'])['addresses']
351 # There should be one entry for the single network mapped to a list of
352 # addresses, which at this point should have at least one entry.
353 # Note that we could start with two addresses depending on how tempest
354 # is configured for using floating IPs.
355 self.assertEqual(1, len(addresses), addresses) # number of networks
356 # Keep track of the original addresses so we can know which IP is new.
357 original_ips = [addr['addr'] for addr in list(addresses.values())[0]]
358 original_ip_count = len(original_ips)
359 self.assertGreater(original_ip_count, 0, addresses) # at least 1
zhufl615e63b2018-08-01 17:23:38 +0800360 network_id = ifs[0]['net_id']
Matt Riedemannd4cb10f2018-09-26 13:03:08 -0400361 # Add another fixed IP to the server. This should result in another
362 # fixed IP on the same network (and same port since we only have one
363 # port).
zhufl615e63b2018-08-01 17:23:38 +0800364 self.servers_client.add_fixed_ip(server['id'], networkId=network_id)
Matt Riedemannd4cb10f2018-09-26 13:03:08 -0400365 # Wait for the ips count to increase by one.
366
367 def _wait_for_ip_increase():
368 _addresses = self.os_primary.servers_client.list_addresses(
369 server['id'])['addresses']
370 return len(list(_addresses.values())[0]) == original_ip_count + 1
371
372 if not test_utils.call_until_true(
373 _wait_for_ip_increase, CONF.compute.build_timeout,
374 CONF.compute.build_interval):
375 raise lib_exc.TimeoutException(
376 'Timed out while waiting for IP count to increase.')
377
378 # Remove the fixed IP that we just added.
zhufl615e63b2018-08-01 17:23:38 +0800379 server_detail = self.os_primary.servers_client.show_server(
380 server['id'])['server']
381 # Get the Fixed IP from server.
382 fixed_ip = None
383 for ip_set in server_detail['addresses']:
384 for ip in server_detail['addresses'][ip_set]:
Matt Riedemannd4cb10f2018-09-26 13:03:08 -0400385 if (ip['OS-EXT-IPS:type'] == 'fixed' and
386 ip['addr'] not in original_ips):
zhufl615e63b2018-08-01 17:23:38 +0800387 fixed_ip = ip['addr']
388 break
389 if fixed_ip is not None:
390 break
391 self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip)
Matt Riedemannd4cb10f2018-09-26 13:03:08 -0400392 # Wait for the interface count to decrease by one.
393
394 def _wait_for_ip_decrease():
395 _addresses = self.os_primary.servers_client.list_addresses(
396 server['id'])['addresses']
397 return len(list(_addresses.values())[0]) == original_ip_count
398
399 if not test_utils.call_until_true(
400 _wait_for_ip_decrease, CONF.compute.build_timeout,
401 CONF.compute.build_interval):
402 raise lib_exc.TimeoutException(
403 'Timed out while waiting for IP count to decrease.')