blob: 2a5d6075e7686d7eb72af8f73f8472c988f331cc [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 Riedemann3570c1e2016-07-29 12:15:38 -040027from tempest.lib import decorators
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050028from tempest.lib import exceptions as lib_exc
Dan Smith8ad1c472013-02-26 13:03:16 -050029
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000030CONF = config.CONF
31
Dan Smith8ad1c472013-02-26 13:03:16 -050032
zhufl615e63b2018-08-01 17:23:38 +080033class AttachInterfacesTestBase(base.BaseV2ComputeTest):
Dan Smith8ad1c472013-02-26 13:03:16 -050034
35 @classmethod
Emily Hugenbruche7991d92014-12-12 16:53:36 +000036 def skip_checks(cls):
zhufl615e63b2018-08-01 17:23:38 +080037 super(AttachInterfacesTestBase, cls).skip_checks()
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000038 if not CONF.service_available.neutron:
Mark McClainf2982e82013-07-06 17:48:03 -040039 raise cls.skipException("Neutron is required")
Adam Gandelman7186f7a2014-07-23 09:28:56 -040040 if not CONF.compute_feature_enabled.interface_attach:
41 raise cls.skipException("Interface attachment is not available.")
Artom Lifshitzb4775942018-09-05 16:24:01 +030042 if not CONF.validation.run_validation:
43 raise cls.skipException('Validation should be enabled to ensure '
44 'guest OS is running and capable of '
45 'processing ACPI events.')
Emily Hugenbruche7991d92014-12-12 16:53:36 +000046
47 @classmethod
48 def setup_credentials(cls):
Salvatore Orlando5a337242014-01-15 22:49:22 +000049 # This test class requires network and subnet
Artom Lifshitzb4775942018-09-05 16:24:01 +030050 cls.set_network_resources(network=True, subnet=True, router=True,
51 dhcp=True)
zhufl615e63b2018-08-01 17:23:38 +080052 super(AttachInterfacesTestBase, cls).setup_credentials()
Emily Hugenbruche7991d92014-12-12 16:53:36 +000053
54 @classmethod
55 def setup_clients(cls):
zhufl615e63b2018-08-01 17:23:38 +080056 super(AttachInterfacesTestBase, cls).setup_clients()
Jordan Pittier8160d312017-04-18 11:52:23 +020057 cls.subnets_client = cls.os_primary.subnets_client
58 cls.ports_client = cls.os_primary.ports_client
Dan Smith8ad1c472013-02-26 13:03:16 -050059
Artom Lifshitzb4775942018-09-05 16:24:01 +030060 def _wait_for_validation(self, server, validation_resources):
61 linux_client = remote_client.RemoteClient(
62 self.get_server_ip(server, validation_resources),
63 self.image_ssh_user,
64 self.image_ssh_password,
65 validation_resources['keypair']['private_key'],
66 server=server,
67 servers_client=self.servers_client)
68 linux_client.validate_authentication()
69
zhufl615e63b2018-08-01 17:23:38 +080070 def _create_server_get_interfaces(self):
Artom Lifshitzb4775942018-09-05 16:24:01 +030071 validation_resources = self.get_test_validation_resources(
72 self.os_primary)
73 server = self.create_test_server(
74 validatable=True,
75 validation_resources=validation_resources,
76 wait_until='ACTIVE')
77 # NOTE(artom) self.create_test_server adds cleanups, but this is
78 # apparently not enough? Add cleanup here.
79 self.addCleanup(self.delete_server, server['id'])
80 self._wait_for_validation(server, validation_resources)
zhufl615e63b2018-08-01 17:23:38 +080081 ifs = (self.interfaces_client.list_interfaces(server['id'])
82 ['interfaceAttachments'])
83 body = waiters.wait_for_interface_status(
84 self.interfaces_client, server['id'], ifs[0]['port_id'], 'ACTIVE')
85 ifs[0]['port_state'] = body['port_state']
86 return server, ifs
87
88
89class AttachInterfacesTestJSON(AttachInterfacesTestBase):
90
Matt Riedemanna8c641a2016-07-12 17:07:33 -040091 def wait_for_port_detach(self, port_id):
92 """Waits for the port's device_id to be unset.
93
94 :param port_id: The id of the port being detached.
95 :returns: The final port dict from the show_port response.
96 """
97 port = self.ports_client.show_port(port_id)['port']
98 device_id = port['device_id']
99 start = int(time.time())
100
101 # NOTE(mriedem): Nova updates the port's device_id to '' rather than
102 # None, but it's not contractual so handle Falsey either way.
103 while device_id:
104 time.sleep(self.build_interval)
105 port = self.ports_client.show_port(port_id)['port']
106 device_id = port['device_id']
107
108 timed_out = int(time.time()) - start >= self.build_timeout
109
110 if device_id and timed_out:
111 message = ('Port %s failed to detach (device_id %s) within '
112 'the required time (%s s).' %
113 (port_id, device_id, self.build_timeout))
guo yunxianebb15f22016-11-01 21:03:35 +0800114 raise lib_exc.TimeoutException(message)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400115
116 return port
117
lianghao16353342017-11-28 21:08:12 +0800118 def _check_interface(self, iface, server_id=None, port_id=None,
119 network_id=None, fixed_ip=None, mac_addr=None):
120 if server_id:
121 iface = waiters.wait_for_interface_status(
122 self.interfaces_client, server_id, iface['port_id'], 'ACTIVE')
Dan Smith8ad1c472013-02-26 13:03:16 -0500123 if port_id:
124 self.assertEqual(iface['port_id'], port_id)
125 if network_id:
126 self.assertEqual(iface['net_id'], network_id)
127 if fixed_ip:
128 self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip)
venkata anil45375302014-12-30 10:41:43 +0000129 if mac_addr:
130 self.assertEqual(iface['mac_addr'], mac_addr)
Dan Smith8ad1c472013-02-26 13:03:16 -0500131
Dan Smith8ad1c472013-02-26 13:03:16 -0500132 def _test_create_interface(self, server):
lkuchlan87b5a2d2016-09-27 15:46:16 +0300133 iface = (self.interfaces_client.create_interface(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900134 ['interfaceAttachment'])
zhufl7b638332016-11-14 10:23:30 +0800135 iface = waiters.wait_for_interface_status(
136 self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
Dan Smith8ad1c472013-02-26 13:03:16 -0500137 return iface
138
139 def _test_create_interface_by_network_id(self, server, ifs):
140 network_id = ifs[0]['net_id']
lkuchlan87b5a2d2016-09-27 15:46:16 +0300141 iface = self.interfaces_client.create_interface(
ghanshyama2364f12015-08-24 15:45:37 +0900142 server['id'], net_id=network_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800143 self._check_interface(iface, server_id=server['id'],
144 network_id=network_id)
Dan Smith8ad1c472013-02-26 13:03:16 -0500145 return iface
146
Maho Koshiya3fc12462015-12-14 19:03:12 +0900147 def _test_create_interface_by_port_id(self, server, ifs):
148 network_id = ifs[0]['net_id']
149 port = self.ports_client.create_port(network_id=network_id)
150 port_id = port['port']['id']
151 self.addCleanup(self.ports_client.delete_port, port_id)
lkuchlan87b5a2d2016-09-27 15:46:16 +0300152 iface = self.interfaces_client.create_interface(
Maho Koshiya3fc12462015-12-14 19:03:12 +0900153 server['id'], port_id=port_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800154 self._check_interface(iface, server_id=server['id'], port_id=port_id,
155 network_id=network_id)
Maho Koshiya3fc12462015-12-14 19:03:12 +0900156 return iface
157
Maho Koshiya7b629582016-02-22 10:59:01 +0900158 def _test_create_interface_by_fixed_ips(self, server, ifs):
159 network_id = ifs[0]['net_id']
Ryan Tidwell1964a262016-05-04 15:13:23 -0700160 subnet_id = ifs[0]['fixed_ips'][0]['subnet_id']
161 ip_list = net_utils.get_unused_ip_addresses(self.ports_client,
162 self.subnets_client,
163 network_id,
164 subnet_id,
165 1)
Maho Koshiya7b629582016-02-22 10:59:01 +0900166
Ryan Tidwell1964a262016-05-04 15:13:23 -0700167 fixed_ips = [{'ip_address': ip_list[0]}]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300168 iface = self.interfaces_client.create_interface(
Maho Koshiya7b629582016-02-22 10:59:01 +0900169 server['id'], net_id=network_id,
170 fixed_ips=fixed_ips)['interfaceAttachment']
171 self.addCleanup(self.ports_client.delete_port, iface['port_id'])
lianghao16353342017-11-28 21:08:12 +0800172 self._check_interface(iface, server_id=server['id'],
173 fixed_ip=ip_list[0])
Maho Koshiya7b629582016-02-22 10:59:01 +0900174 return iface
175
Dan Smith8ad1c472013-02-26 13:03:16 -0500176 def _test_show_interface(self, server, ifs):
177 iface = ifs[0]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300178 _iface = self.interfaces_client.show_interface(
ghanshyama2364f12015-08-24 15:45:37 +0900179 server['id'], iface['port_id'])['interfaceAttachment']
venkata anil45375302014-12-30 10:41:43 +0000180 self._check_interface(iface, port_id=_iface['port_id'],
181 network_id=_iface['net_id'],
182 fixed_ip=_iface['fixed_ips'][0]['ip_address'],
183 mac_addr=_iface['mac_addr'])
Dan Smith8ad1c472013-02-26 13:03:16 -0500184
185 def _test_delete_interface(self, server, ifs):
186 # NOTE(danms): delete not the first or last, but one in the middle
187 iface = ifs[1]
lkuchlan87b5a2d2016-09-27 15:46:16 +0300188 self.interfaces_client.delete_interface(server['id'], iface['port_id'])
189 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900190 ['interfaceAttachments'])
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400191 start = int(time.time())
Dan Smith8ad1c472013-02-26 13:03:16 -0500192
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400193 while len(ifs) == len(_ifs):
194 time.sleep(self.build_interval)
lkuchlan87b5a2d2016-09-27 15:46:16 +0300195 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900196 ['interfaceAttachments'])
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400197 timed_out = int(time.time()) - start >= self.build_timeout
198 if len(ifs) == len(_ifs) and timed_out:
199 message = ('Failed to delete interface within '
200 'the required time: %s sec.' % self.build_timeout)
guo yunxianebb15f22016-11-01 21:03:35 +0800201 raise lib_exc.TimeoutException(message)
Oleg Bondarevee50bb12014-01-16 00:01:34 +0400202
203 self.assertNotIn(iface['port_id'], [i['port_id'] for i in _ifs])
Dan Smith8ad1c472013-02-26 13:03:16 -0500204 return _ifs
205
206 def _compare_iface_list(self, list1, list2):
207 # NOTE(danms): port_state will likely have changed, so just
208 # confirm the port_ids are the same at least
209 list1 = [x['port_id'] for x in list1]
210 list2 = [x['port_id'] for x in list2]
211
212 self.assertEqual(sorted(list1), sorted(list2))
213
Ken'ichi Ohmichi14b0ae12017-01-27 17:18:52 -0800214 @decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051')
Andrea Frittolicd368412017-08-14 21:37:56 +0100215 @utils.services('network')
zhufl607cfbf2017-12-28 14:55:08 +0800216 def test_create_list_show_delete_interfaces_by_network_port(self):
Dan Smith8ad1c472013-02-26 13:03:16 -0500217 server, ifs = self._create_server_get_interfaces()
218 interface_count = len(ifs)
zhufl080dcfb2016-10-21 17:45:38 +0800219 self.assertGreater(interface_count, 0)
Dan Smith8ad1c472013-02-26 13:03:16 -0500220
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530221 try:
222 iface = self._test_create_interface(server)
223 except lib_exc.BadRequest as e:
224 msg = ('Multiple possible networks found, use a Network ID to be '
225 'more specific.')
junbolibc2ae862017-07-29 15:46:48 +0800226 if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530227 raise
228 else:
229 ifs.append(iface)
Dan Smith8ad1c472013-02-26 13:03:16 -0500230
231 iface = self._test_create_interface_by_network_id(server, ifs)
232 ifs.append(iface)
233
Maho Koshiya3fc12462015-12-14 19:03:12 +0900234 iface = self._test_create_interface_by_port_id(server, ifs)
235 ifs.append(iface)
236
zhufl607cfbf2017-12-28 14:55:08 +0800237 _ifs = (self.interfaces_client.list_interfaces(server['id'])
238 ['interfaceAttachments'])
239 self._compare_iface_list(ifs, _ifs)
240
241 self._test_show_interface(server, ifs)
242
243 _ifs = self._test_delete_interface(server, ifs)
244 self.assertEqual(len(ifs) - 1, len(_ifs))
245
246 @decorators.idempotent_id('d290c06c-f5b3-11e7-8ec8-002293781009')
247 @utils.services('network')
248 def test_create_list_show_delete_interfaces_by_fixed_ip(self):
249 # NOTE(zhufl) By default only project that is admin or network owner
250 # or project with role advsvc is authorised to create interfaces with
251 # fixed-ip, so if we don't create network for each project, do not
252 # test _test_create_interface_by_fixed_ips.
253 if not (CONF.auth.use_dynamic_credentials and
254 CONF.auth.create_isolated_networks and
255 not CONF.network.shared_physical_network):
256 raise self.skipException("Only owner network supports "
257 "creating interface by fixed ip.")
258
259 server, ifs = self._create_server_get_interfaces()
260 interface_count = len(ifs)
261 self.assertGreater(interface_count, 0)
262
263 try:
264 iface = self._test_create_interface(server)
265 except lib_exc.BadRequest as e:
266 msg = ('Multiple possible networks found, use a Network ID to be '
267 'more specific.')
268 if not CONF.compute.fixed_network_name and six.text_type(e) == msg:
269 raise
270 else:
271 ifs.append(iface)
272
Maho Koshiya7b629582016-02-22 10:59:01 +0900273 iface = self._test_create_interface_by_fixed_ips(server, ifs)
274 ifs.append(iface)
275
lkuchlan87b5a2d2016-09-27 15:46:16 +0300276 _ifs = (self.interfaces_client.list_interfaces(server['id'])
ghanshyama2364f12015-08-24 15:45:37 +0900277 ['interfaceAttachments'])
Dan Smith8ad1c472013-02-26 13:03:16 -0500278 self._compare_iface_list(ifs, _ifs)
279
280 self._test_show_interface(server, ifs)
281
282 _ifs = self._test_delete_interface(server, ifs)
283 self.assertEqual(len(ifs) - 1, len(_ifs))
284
Ken'ichi Ohmichi14b0ae12017-01-27 17:18:52 -0800285 @decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400286 def test_reassign_port_between_servers(self):
287 """Tests the following:
288
289 1. Create a port in Neutron.
290 2. Create two servers in Nova.
291 3. Attach the port to the first server.
292 4. Detach the port from the first server.
293 5. Attach the port to the second server.
294 6. Detach the port from the second server.
295 """
296 network = self.get_tenant_network()
297 network_id = network['id']
298 port = self.ports_client.create_port(network_id=network_id)
299 port_id = port['port']['id']
300 self.addCleanup(self.ports_client.delete_port, port_id)
301
Artom Lifshitzb4775942018-09-05 16:24:01 +0300302 # NOTE(artom) We create two servers one at a time because
303 # create_test_server doesn't support multiple validatable servers.
304 validation_resources = self.get_test_validation_resources(
305 self.os_primary)
306
307 def _create_validatable_server():
308 _, servers = compute.create_test_server(
309 self.os_primary, tenant_network=network,
310 wait_until='ACTIVE', validatable=True,
311 validation_resources=validation_resources)
312 return servers[0]
313
314 servers = [_create_validatable_server(), _create_validatable_server()]
315
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400316 # add our cleanups for the servers since we bypassed the base class
317 for server in servers:
zhufl1355d982017-01-05 12:06:20 +0800318 self.addCleanup(self.delete_server, server['id'])
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400319
320 for server in servers:
Artom Lifshitzb4775942018-09-05 16:24:01 +0300321 self._wait_for_validation(server, validation_resources)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400322 # attach the port to the server
lkuchlan87b5a2d2016-09-27 15:46:16 +0300323 iface = self.interfaces_client.create_interface(
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400324 server['id'], port_id=port_id)['interfaceAttachment']
lianghao16353342017-11-28 21:08:12 +0800325 self._check_interface(iface, server_id=server['id'],
326 port_id=port_id)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400327
328 # detach the port from the server; this is a cast in the compute
329 # API so we have to poll the port until the device_id is unset.
lkuchlan87b5a2d2016-09-27 15:46:16 +0300330 self.interfaces_client.delete_interface(server['id'], port_id)
Matt Riedemanna8c641a2016-07-12 17:07:33 -0400331 self.wait_for_port_detach(port_id)
zhufl615e63b2018-08-01 17:23:38 +0800332
333
334class AttachInterfacesUnderV243Test(AttachInterfacesTestBase):
335 max_microversion = '2.43'
336
337 @decorators.attr(type='smoke')
338 @decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9')
339 @utils.services('network')
340 def test_add_remove_fixed_ip(self):
341 # Add and Remove the fixed IP to server.
342 server, ifs = self._create_server_get_interfaces()
343 interface_count = len(ifs)
344 self.assertGreater(interface_count, 0)
345 network_id = ifs[0]['net_id']
346 self.servers_client.add_fixed_ip(server['id'], networkId=network_id)
347 # Remove the fixed IP from server.
348 server_detail = self.os_primary.servers_client.show_server(
349 server['id'])['server']
350 # Get the Fixed IP from server.
351 fixed_ip = None
352 for ip_set in server_detail['addresses']:
353 for ip in server_detail['addresses'][ip_set]:
354 if ip['OS-EXT-IPS:type'] == 'fixed':
355 fixed_ip = ip['addr']
356 break
357 if fixed_ip is not None:
358 break
359 self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip)