blob: 06d2723024912240742961a7ba1a7b6ac2871f8b [file] [log] [blame]
Solio Sarabia60095ff2017-02-28 18:18:26 -06001# Copyright 2012 OpenStack Foundation
2# Copyright 2013 IBM Corp.
3# 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.
16
17# NOTE(soliosg) Do not edit this file. It will only stay temporarily
18# in ironic, while QA refactors the tempest.scenario interface. This
19# file was copied from openstack/tempest/tempest/scenario/manager.py,
20# openstack/tempest commit: 82a278e88c9e9f9ba49f81c1f8dba0bca7943daf
21
Solio Sarabia60095ff2017-02-28 18:18:26 -060022from oslo_log import log
Solio Sarabia60095ff2017-02-28 18:18:26 -060023from oslo_utils import netutils
Solio Sarabia60095ff2017-02-28 18:18:26 -060024from tempest import config
25from tempest import exceptions
26from tempest.lib.common.utils import data_utils
27from tempest.lib.common.utils import test_utils
28from tempest.lib import exceptions as lib_exc
29import tempest.test
30
31CONF = config.CONF
32
33LOG = log.getLogger(__name__)
34
35
Roman Popelka7e962d62022-02-28 09:10:31 +010036class ScenarioTest(tempest.scenario.manager.ScenarioTest):
Solio Sarabia60095ff2017-02-28 18:18:26 -060037 """Base class for scenario tests. Uses tempest own clients. """
38
Julia Kreger3a07c4d2021-06-22 10:27:56 -070039 credentials = ['primary', 'admin', 'system_admin']
Solio Sarabia60095ff2017-02-28 18:18:26 -060040
41 @classmethod
42 def setup_clients(cls):
43 super(ScenarioTest, cls).setup_clients()
44 # Clients (in alphabetical order)
Vu Cong Tuanf825d192017-06-21 18:32:15 +070045 cls.flavors_client = cls.os_primary.flavors_client
Solio Sarabia60095ff2017-02-28 18:18:26 -060046 cls.compute_floating_ips_client = (
Vu Cong Tuanf825d192017-06-21 18:32:15 +070047 cls.os_primary.compute_floating_ips_client)
Solio Sarabia60095ff2017-02-28 18:18:26 -060048 if CONF.service_available.glance:
49 # Check if glance v1 is available to determine which client to use.
50 if CONF.image_feature_enabled.api_v1:
Vu Cong Tuanf825d192017-06-21 18:32:15 +070051 cls.image_client = cls.os_primary.image_client
Solio Sarabia60095ff2017-02-28 18:18:26 -060052 elif CONF.image_feature_enabled.api_v2:
Vu Cong Tuanf825d192017-06-21 18:32:15 +070053 cls.image_client = cls.os_primary.image_client_v2
Solio Sarabia60095ff2017-02-28 18:18:26 -060054 else:
55 raise lib_exc.InvalidConfiguration(
56 'Either api_v1 or api_v2 must be True in '
57 '[image-feature-enabled].')
58 # Compute image client
Vu Cong Tuanf825d192017-06-21 18:32:15 +070059 cls.compute_images_client = cls.os_primary.compute_images_client
60 cls.keypairs_client = cls.os_primary.keypairs_client
Solio Sarabia60095ff2017-02-28 18:18:26 -060061 # Nova security groups client
62 cls.compute_security_groups_client = (
Vu Cong Tuanf825d192017-06-21 18:32:15 +070063 cls.os_primary.compute_security_groups_client)
Solio Sarabia60095ff2017-02-28 18:18:26 -060064 cls.compute_security_group_rules_client = (
Vu Cong Tuanf825d192017-06-21 18:32:15 +070065 cls.os_primary.compute_security_group_rules_client)
66 cls.servers_client = cls.os_primary.servers_client
67 cls.interface_client = cls.os_primary.interfaces_client
Solio Sarabia60095ff2017-02-28 18:18:26 -060068 # Neutron network client
Vu Cong Tuanf825d192017-06-21 18:32:15 +070069 cls.networks_client = cls.os_primary.networks_client
70 cls.ports_client = cls.os_primary.ports_client
71 cls.routers_client = cls.os_primary.routers_client
72 cls.subnets_client = cls.os_primary.subnets_client
73 cls.floating_ips_client = cls.os_primary.floating_ips_client
74 cls.security_groups_client = cls.os_primary.security_groups_client
Solio Sarabia60095ff2017-02-28 18:18:26 -060075 cls.security_group_rules_client = (
Vu Cong Tuanf825d192017-06-21 18:32:15 +070076 cls.os_primary.security_group_rules_client)
Solio Sarabia60095ff2017-02-28 18:18:26 -060077
Ghanshyam Mann3b663f62019-12-12 17:01:16 +000078 cls.volumes_client = cls.os_primary.volumes_client_latest
79 cls.snapshots_client = cls.os_primary.snapshots_client_latest
Solio Sarabia60095ff2017-02-28 18:18:26 -060080
81 # ## Test functions library
82 #
83 # The create_[resource] functions only return body and discard the
84 # resp part which is not used in scenario tests
85
Solio Sarabia60095ff2017-02-28 18:18:26 -060086 def create_floating_ip(self, thing, pool_name=None):
87 """Create a floating IP and associates to a server on Nova"""
88
89 if not pool_name:
90 pool_name = CONF.network.floating_network_name
Julia Kreger3a07c4d2021-06-22 10:27:56 -070091 client = self.os_primary.compute_floating_ips_client
92 floating_ip = (client.
Solio Sarabia60095ff2017-02-28 18:18:26 -060093 create_floating_ip(pool=pool_name)['floating_ip'])
94 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Julia Kreger3a07c4d2021-06-22 10:27:56 -070095 client.delete_floating_ip,
Solio Sarabia60095ff2017-02-28 18:18:26 -060096 floating_ip['id'])
Julia Kreger3a07c4d2021-06-22 10:27:56 -070097 client.associate_floating_ip_to_server(
Solio Sarabia60095ff2017-02-28 18:18:26 -060098 floating_ip['ip'], thing['id'])
99 return floating_ip
100
Solio Sarabia60095ff2017-02-28 18:18:26 -0600101 def get_server_ip(self, server):
102 """Get the server fixed or floating IP.
103
104 Based on the configuration we're in, return a correct ip
105 address for validating that a guest is up.
106 """
107 if CONF.validation.connect_method == 'floating':
108 # The tests calling this method don't have a floating IP
109 # and can't make use of the validation resources. So the
110 # method is creating the floating IP there.
111 return self.create_floating_ip(server)['ip']
112 elif CONF.validation.connect_method == 'fixed':
113 # Determine the network name to look for based on config or creds
114 # provider network resources.
115 if CONF.validation.network_for_ssh:
116 addresses = server['addresses'][
117 CONF.validation.network_for_ssh]
118 else:
119 creds_provider = self._get_credentials_provider()
120 net_creds = creds_provider.get_primary_creds()
121 network = getattr(net_creds, 'network', None)
122 addresses = (server['addresses'][network['name']]
123 if network else [])
124 for address in addresses:
125 if (address['version'] == CONF.validation.ip_version_for_ssh
126 and address['OS-EXT-IPS:type'] == 'fixed'):
127 return address['addr']
128 raise exceptions.ServerUnreachable(server_id=server['id'])
129 else:
130 raise lib_exc.InvalidConfiguration()
131
Pavlo Shchelokovskyy40db0332017-03-21 08:00:17 +0000132 def _get_router(self, client=None, tenant_id=None):
133 """Retrieve a router for the given tenant id.
134
135 If a public router has been configured, it will be returned.
136
137 If a public router has not been configured, but a public
138 network has, a tenant router will be created and returned that
139 routes traffic to the public network.
140 """
141 if not client:
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700142 client = self.os_primary.routers_client
Pavlo Shchelokovskyy40db0332017-03-21 08:00:17 +0000143 if not tenant_id:
144 tenant_id = client.tenant_id
145 router_id = CONF.network.public_router_id
146 network_id = CONF.network.public_network_id
147 if router_id:
148 body = client.show_router(router_id)
149 return body['router']
150 elif network_id:
151 router = self._create_router(client, tenant_id)
152 kwargs = {'external_gateway_info': dict(network_id=network_id)}
153 router = client.update_router(router['id'], **kwargs)['router']
154 return router
155 else:
156 raise Exception("Neither of 'public_router_id' or "
157 "'public_network_id' has been defined.")
158
159 def _create_router(self, client=None, tenant_id=None,
160 namestart='router-smoke'):
161 if not client:
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700162 client = self.os_primary.routers_client
Pavlo Shchelokovskyy40db0332017-03-21 08:00:17 +0000163 if not tenant_id:
164 tenant_id = client.tenant_id
165 name = data_utils.rand_name(namestart)
166 result = client.create_router(name=name,
167 admin_state_up=True,
168 tenant_id=tenant_id)
169 router = result['router']
170 self.assertEqual(router['name'], name)
171 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
172 client.delete_router,
173 router['id'])
174 return router
175
Solio Sarabia60095ff2017-02-28 18:18:26 -0600176
177class NetworkScenarioTest(ScenarioTest):
178 """Base class for network scenario tests.
179
180 This class provide helpers for network scenario tests, using the neutron
181 API. Helpers from ancestor which use the nova network API are overridden
182 with the neutron API.
183
184 This Class also enforces using Neutron instead of novanetwork.
185 Subclassed tests will be skipped if Neutron is not enabled
186
187 """
188
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700189 credentials = ['primary', 'admin', 'system_admin']
Solio Sarabia60095ff2017-02-28 18:18:26 -0600190
191 @classmethod
192 def skip_checks(cls):
193 super(NetworkScenarioTest, cls).skip_checks()
194 if not CONF.service_available.neutron:
195 raise cls.skipException('Neutron not available')
196
197 def _create_network(self, networks_client=None,
198 tenant_id=None,
199 namestart='network-smoke-',
200 port_security_enabled=True):
201 if not networks_client:
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700202 networks_client = self.os_primary.networks_client
Solio Sarabia60095ff2017-02-28 18:18:26 -0600203 if not tenant_id:
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700204 tenant_id = self.os_primary.networks_client.tenant_id
Solio Sarabia60095ff2017-02-28 18:18:26 -0600205 name = data_utils.rand_name(namestart)
206 network_kwargs = dict(name=name, tenant_id=tenant_id)
207 # Neutron disables port security by default so we have to check the
208 # config before trying to create the network with port_security_enabled
209 if CONF.network_feature_enabled.port_security:
210 network_kwargs['port_security_enabled'] = port_security_enabled
211 result = networks_client.create_network(**network_kwargs)
212 network = result['network']
213
214 self.assertEqual(network['name'], name)
215 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
216 networks_client.delete_network,
217 network['id'])
218 return network
219
Solio Sarabia60095ff2017-02-28 18:18:26 -0600220 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Hongbin Lu43015f02018-07-19 15:17:19 +0000221 if ip_addr:
222 ports = self.os_admin.ports_client.list_ports(
223 device_id=server['id'],
224 fixed_ips='ip_address=%s' % ip_addr)['ports']
225 else:
226 ports = self.os_admin.ports_client.list_ports(
227 device_id=server['id'])['ports']
Solio Sarabia60095ff2017-02-28 18:18:26 -0600228 # A port can have more than one IP address in some cases.
229 # If the network is dual-stack (IPv4 + IPv6), this port is associated
230 # with 2 subnets
231 p_status = ['ACTIVE']
232 # NOTE(vsaienko) With Ironic, instances live on separate hardware
233 # servers. Neutron does not bind ports for Ironic instances, as a
234 # result the port remains in the DOWN state.
235 # TODO(vsaienko) remove once bug: #1599836 is resolved.
236 if getattr(CONF.service_available, 'ironic', False):
237 p_status.append('DOWN')
238 port_map = [(p["id"], fxip["ip_address"])
239 for p in ports
240 for fxip in p["fixed_ips"]
241 if netutils.is_valid_ipv4(fxip["ip_address"])
242 and p['status'] in p_status]
243 inactive = [p for p in ports if p['status'] != 'ACTIVE']
244 if inactive:
245 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
246
247 self.assertNotEqual(0, len(port_map),
248 "No IPv4 addresses found in: %s" % ports)
249 self.assertEqual(len(port_map), 1,
250 "Found multiple IPv4 addresses: %s. "
251 "Unable to determine which port to target."
252 % port_map)
253 return port_map[0]
254
Solio Sarabia60095ff2017-02-28 18:18:26 -0600255 def create_floating_ip(self, thing, external_network_id=None,
256 port_id=None, client=None):
257 """Create a floating IP and associates to a resource/port on Neutron"""
258 if not external_network_id:
259 external_network_id = CONF.network.public_network_id
260 if not client:
Julia Kreger3a07c4d2021-06-22 10:27:56 -0700261 client = self.os_primary.floating_ips_client
Solio Sarabia60095ff2017-02-28 18:18:26 -0600262 if not port_id:
263 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
264 else:
265 ip4 = None
266 result = client.create_floatingip(
267 floating_network_id=external_network_id,
268 port_id=port_id,
269 tenant_id=thing['tenant_id'],
270 fixed_ip_address=ip4
271 )
272 floating_ip = result['floatingip']
273 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
274 client.delete_floatingip,
275 floating_ip['id'])
276 return floating_ip