blob: d00e6620a3ce4489a0c22add943d7a92b0308309 [file] [log] [blame]
Ievgeniia Zadorozhna97dfde42022-06-17 20:05:09 +03001import logging
2import os
3import random
4import sys
5import time
6
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +02007from cinderclient import client as cinder_client
8from glanceclient import client as glance_client
9from keystoneauth1 import identity as keystone_identity
10from keystoneauth1 import session as keystone_session
11from keystoneclient.v3 import client as keystone_client
12from neutronclient.v2_0 import client as neutron_client
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +030013from neutronclient import common as neutron_common
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020014from novaclient import client as novaclient
15
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020016import utils
17
18logger = logging.getLogger(__name__)
19
20
21class OfficialClientManager(object):
22 """Manager that provides access to the official python clients for
23 calling various OpenStack APIs.
24 """
25
26 CINDERCLIENT_VERSION = 3
27 GLANCECLIENT_VERSION = 2
28 KEYSTONECLIENT_VERSION = 3
29 NEUTRONCLIENT_VERSION = 2
30 NOVACLIENT_VERSION = 2
31 INTERFACE = 'admin'
32 if "OS_ENDPOINT_TYPE" in list(os.environ.keys()):
33 INTERFACE = os.environ["OS_ENDPOINT_TYPE"]
34
35 def __init__(self, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030036 project_name=None, auth_url=None, endpoint_type="internalURL",
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +020037 interface=INTERFACE,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020038 cert=False, domain="Default", **kwargs):
39 self.traceback = ""
40
41 self.client_attr_names = [
42 "auth",
43 "compute",
44 "network",
45 "volume",
46 "image",
47 ]
48 self.username = username
49 self.password = password
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030050 self.project_name = project_name
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020051 self.auth_url = auth_url
52 self.endpoint_type = endpoint_type
53 self.cert = cert
54 self.domain = domain
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +020055 self.interface = interface
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020056 self.kwargs = kwargs
57
58 # Lazy clients
59 self._auth = None
60 self._compute = None
61 self._network = None
62 self._volume = None
63 self._image = None
64
65 @classmethod
66 def _get_auth_session(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030067 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020068 domain='Default'):
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030069 if None in (username, password, project_name):
70 sys.stdout.write((username, password, project_name))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020071 msg = ("Missing required credentials for identity client. "
72 "username: {username}, password: {password}, "
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030073 "project_name: {project_name}").format(
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020074 username=username,
75 password=password,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030076 project_name=project_name
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020077 )
78 raise msg
79
80 if cert and "https" not in auth_url:
81 auth_url = auth_url.replace("http", "https")
82
83 if "v2" in auth_url:
84 raise BaseException("Keystone v2 is deprecated since OpenStack"
85 "Queens release. So current OS_AUTH_URL {} "
86 "is not valid. Please use Keystone v3."
87 "".format(auth_url))
88 else:
89 auth_url = auth_url if ("v3" in auth_url) else "{}{}".format(
90 auth_url, "/v3")
91 auth = keystone_identity.v3.Password(
92 auth_url=auth_url,
93 user_domain_name=domain,
94 username=username,
95 password=password,
96 project_domain_name=domain,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030097 project_name=project_name)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020098
99 auth_session = keystone_session.Session(auth=auth, verify=cert)
100 # auth_session.get_auth_headers()
101 return auth_session
102
103 @classmethod
104 def get_auth_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300105 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +0200106 domain='Default', os_interface=None, **kwargs):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200107 session = cls._get_auth_session(
108 username=username,
109 password=password,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300110 project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200111 auth_url=auth_url,
112 cert=cert,
113 domain=domain)
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +0200114 endpoint_filter = {"interface": os_interface}
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200115 keystone = keystone_client.Client(version=cls.KEYSTONECLIENT_VERSION,
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +0200116 session=session, **kwargs,
117 interface=os_interface,
118 endpoint_filter=endpoint_filter)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200119 keystone.management_url = auth_url
120 return keystone
121
122 @classmethod
123 def get_compute_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300124 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200125 domain='Default', **kwargs):
126 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300127 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200128 auth_url=auth_url, cert=cert, domain=domain)
129 service_type = 'compute'
130 compute_client = novaclient.Client(
131 version=cls.NOVACLIENT_VERSION, session=session,
132 service_type=service_type, os_cache=False, **kwargs)
133 return compute_client
134
135 @classmethod
136 def get_network_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300137 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200138 domain='Default', **kwargs):
139 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300140 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200141 auth_url=auth_url, cert=cert, domain=domain)
142 service_type = 'network'
143 return neutron_client.Client(
144 service_type=service_type, session=session,
145 interface=cls.INTERFACE, **kwargs)
146
147 @classmethod
148 def get_volume_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300149 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200150 domain='Default', **kwargs):
151 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300152 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200153 auth_url=auth_url, cert=cert, domain=domain)
154 service_type = 'volume'
155 return cinder_client.Client(
156 version=cls.CINDERCLIENT_VERSION,
157 service_type=service_type,
158 interface=cls.INTERFACE,
159 session=session, **kwargs)
160
161 @classmethod
162 def get_image_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300163 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200164 domain='Default', **kwargs):
165 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300166 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200167 auth_url=auth_url, cert=cert, domain=domain)
168 service_type = 'image'
169 return glance_client.Client(
170 version=cls.GLANCECLIENT_VERSION,
171 service_type=service_type,
172 session=session, interface=cls.INTERFACE,
173 **kwargs)
174
175 @property
176 def auth(self):
177 if self._auth is None:
178 self._auth = self.get_auth_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300179 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna68d64952024-08-22 18:15:45 +0200180 self.cert, self.domain, endpoint_type=self.endpoint_type,
181 os_interface=self.interface
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200182 )
183 return self._auth
184
185 @property
186 def compute(self):
187 if self._compute is None:
188 self._compute = self.get_compute_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300189 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200190 self.cert, self.domain, endpoint_type=self.endpoint_type
191 )
192 return self._compute
193
194 @property
195 def network(self):
196 if self._network is None:
197 self._network = self.get_network_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300198 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200199 self.cert, self.domain, endpoint_type=self.endpoint_type
200 )
201 return self._network
202
203 @property
204 def volume(self):
205 if self._volume is None:
206 self._volume = self.get_volume_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300207 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200208 self.cert, self.domain, endpoint_type=self.endpoint_type
209 )
210 return self._volume
211
212 @property
213 def image(self):
214
215 if self._image is None:
216 self._image = self.get_image_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300217 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200218 self.cert, self.domain
219 )
220 return self._image
221
222
223class OSCliActions(object):
224 def __init__(self, os_clients):
225 self.os_clients = os_clients
226 self.create_fake_ext_net = False
227
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300228 def get_project_by_name(self, name):
Ievgeniia Zadorozhna21517712024-07-30 14:14:08 +0200229 return self.os_clients.auth.projects.find(
230 name=name, domain_id=self.os_clients.auth.user_domain_id)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200231
232 def get_internal_network(self):
233 networks = [
234 net for net in self.os_clients.network.list_networks()["networks"]
235 if net["admin_state_up"] and not net["router:external"] and
236 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300237 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200238 if networks:
239 net = networks[0]
240 else:
241 net = self.create_network_resources()
242 return net
243
244 def create_fake_external_network(self):
245 logger.info(
246 "Could not find any external network, creating a fake one...")
247 net_name = "spt-ext-net-{}".format(random.randrange(100, 999))
248 net_body = {"network": {"name": net_name,
249 "router:external": True,
250 "provider:network_type": "local"}}
251 try:
252 ext_net = \
253 self.os_clients.network.create_network(net_body)['network']
254 logger.info("Created a fake external net {}".format(net_name))
255 except Exception as e:
256 # in case 'local' net type is absent, create with default type
257 net_body["network"].pop('provider:network_type', None)
258 ext_net = \
259 self.os_clients.network.create_network(net_body)['network']
260 subnet_name = "spt-ext-subnet-{}".format(random.randrange(100, 999))
261 subnet_body = {
262 "subnet": {
263 "name": subnet_name,
264 "network_id": ext_net["id"],
265 "ip_version": 4,
266 "cidr": "10.255.255.0/24",
267 "allocation_pools": [{"start": "10.255.255.100",
268 "end": "10.255.255.200"}]
269 }
270 }
271 self.os_clients.network.create_subnet(subnet_body)
272 self.create_fake_ext_net = True
273 return ext_net
274
275 def get_external_network(self):
276 config = utils.get_configuration()
277 ext_net = config.get('external_network') or ''
278 if not ext_net:
279 networks = [
280 net for net in
281 self.os_clients.network.list_networks()["networks"]
282 if net["admin_state_up"] and net["router:external"] and
283 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300284 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200285 else:
286 networks = [net for net in
287 self.os_clients.network.list_networks()["networks"]
288 if net["name"] == ext_net]
289
290 if networks:
291 ext_net = networks[0]
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300292 logger.info("Using external net '{}'".format(ext_net["name"]))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200293 else:
294 ext_net = self.create_fake_external_network()
295 return ext_net
296
297 def create_flavor(self, name, ram=256, vcpus=1, disk=2):
298 logger.info("Creating a flavor {}".format(name))
299 return self.os_clients.compute.flavors.create(name, ram, vcpus, disk)
300
301 def create_sec_group(self, rulesets=None):
302 if rulesets is None:
303 rulesets = [
304 {
305 # ssh
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300306 'protocol': 'tcp',
307 'port_range_max': 22,
308 'port_range_min': 22,
309 'remote_ip_prefix': '0.0.0.0/0',
310 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200311 },
312 {
313 # iperf3
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300314 'protocol': 'tcp',
315 'port_range_max': 5201,
316 'port_range_min': 5201,
317 'remote_ip_prefix': '0.0.0.0/0',
318 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200319 },
320 {
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300321 # iperf
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300322 'protocol': 'tcp',
323 'port_range_max': 5001,
324 'port_range_min': 5001,
325 'remote_ip_prefix': '0.0.0.0/0',
326 'direction': 'ingress'
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300327 },
328 {
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200329 # ping
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300330 'protocol': 'icmp',
331 'remote_ip_prefix': '0.0.0.0/0',
332 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200333 }
334 ]
335 sg_name = "spt-test-secgroup-{}".format(random.randrange(100, 999))
336 sg_desc = sg_name + " SPT"
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300337 body = {"security_group": {"name": sg_name, "description": sg_desc}}
338 secgroup = self.os_clients.network.create_security_group(body=body)
339
340 rule_body_teplate = {"security_group_rule": {}}
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200341 for ruleset in rulesets:
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300342 rule_body_teplate["security_group_rule"] = ruleset
343 rule_body_teplate["security_group_rule"]["security_group_id"] = \
344 secgroup['security_group']['id']
345 self.os_clients.network.create_security_group_rule(
346 body=rule_body_teplate)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200347 logger.info("Created a security group {}".format(sg_name))
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300348 return secgroup['security_group']
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200349
350 def create_basic_server(self, image=None, flavor=None, net=None,
351 availability_zone=None, sec_groups=(),
352 keypair=None):
353 os_conn = self.os_clients
354 net = net or self.get_internal_network()
355 kwargs = {}
356 if sec_groups:
357 kwargs['security_groups'] = sec_groups
358 server = os_conn.compute.servers.create(
359 "spt-test-server-{}".format(random.randrange(100, 999)),
360 image, flavor, nics=[{"net-id": net["id"]}],
361 availability_zone=availability_zone, key_name=keypair, **kwargs)
362
363 return server
364
365 def get_vm(self, vm_id):
366 os_conn = self.os_clients
367 try:
368 vm = os_conn.compute.servers.find(id=vm_id)
369 except Exception as e:
370 raise Exception(
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300371 "Could not get the VM \"{}\": {}".format(
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200372 vm_id, e))
373 return vm
374
375 def check_vm_is_active(self, vm_uuid, retry_delay=5, timeout=500):
376 vm = None
377 timeout_reached = False
378 start_time = time.time()
379 expected_state = 'ACTIVE'
380 while not timeout_reached:
381 vm = self.get_vm(vm_uuid)
382 if vm.status == expected_state:
383 logger.info(
384 "VM {} is in {} status.".format(vm_uuid, vm.status))
385 break
386 if vm.status == 'ERROR':
387 break
388 time.sleep(retry_delay)
389 timeout_reached = (time.time() - start_time) > timeout
390 if vm.status != expected_state:
391 logger.info("VM {} is in {} status.".format(vm_uuid, vm.status))
392 raise TimeoutError(
393 "VM {vm_uuid} on is expected to be in '{expected_state}' "
394 "state, but is in '{actual}' state instead.".format(
395 vm_uuid=vm_uuid, expected_state=expected_state,
396 actual=vm.status))
397
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300398 def create_network(self, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200399 net_name = "spt-test-net-{}".format(random.randrange(100, 999))
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300400 config = utils.get_configuration()
401 mtu = config.get('custom_mtu') or 'default'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200402 net_body = {
403 'network': {
404 'name': net_name,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300405 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200406 }
407 }
Ievgeniia Zadorozhna040dfe82023-03-03 04:48:05 +0300408 # in TF2011 we cannot set MTU while creating the net: 400 Bad request
409 # error can happen with 'mtu' field, so we update mtu of ports later
410 if (mtu != 'default') and (not self.is_cloud_tf()):
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300411 try:
412 net_body['network']['mtu'] = int(mtu)
413 except ValueError as e:
414 raise ValueError("MTU value '{}' is not correct. "
415 "Must be an integer at 'custom_mtu' in "
416 "global_config.yaml.\n{}".format(mtu, e))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200417 net = self.os_clients.network.create_network(net_body)['network']
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300418 # WA for TF because the network object does not have 'mtu' field by
419 # default, so this blocked running tests at TF envs with default MTU
420 if 'mtu' not in net:
421 net['mtu'] = None
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300422 logger.info("Created internal network {} in {} project".format(
423 net_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200424 return net
425
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300426 def create_subnet(self, net, project_id, cidr=None):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200427 subnet_name = "spt-test-subnet-{}".format(random.randrange(100, 999))
428 subnet_body = {
429 'subnet': {
430 "name": subnet_name,
431 'network_id': net['id'],
432 'ip_version': 4,
433 'cidr': cidr if cidr else '10.1.7.0/24',
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300434 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200435 }
436 }
437 subnet = self.os_clients.network.create_subnet(subnet_body)['subnet']
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300438 logger.info("Created subnet {} in {} project".format(
439 subnet_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200440 return subnet
441
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300442 def create_router(self, ext_net, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200443 name = 'spt-test-router-{}'.format(random.randrange(100, 999))
444 router_body = {
445 'router': {
446 'name': name,
447 'external_gateway_info': {
448 'network_id': ext_net['id']
449 },
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300450 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200451 }
452 }
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300453 logger.info("Created a router {} in {} project".format(
454 name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200455 router = self.os_clients.network.create_router(router_body)['router']
456 return router
457
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300458 def create_network_resources(self, project="admin", cidr=None):
459 project_id = self.get_project_by_name(project).id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200460 self.get_external_network()
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300461 net = self.create_network(project_id)
462 self.create_subnet(net, project_id, cidr)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200463 return net
464
465 def list_nova_computes(self):
466 nova_services = self.os_clients.compute.hosts.list()
467 computes_list = [h for h in nova_services if h.service == "compute"]
468 return computes_list
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300469
470 def create_floating_ip(self, floating_net_id):
471 fip = self.os_clients.network.create_floatingip({"floatingip": {
472 "floating_network_id": floating_net_id}})
473 return fip['floatingip']
474
475 def delete_floating_ip(self, floatingip_id):
476 try:
477 return self.os_clients.network.delete_floatingip(floatingip_id)
478 except neutron_common.exceptions.NotFound as e:
479 msg = "Could not delete a Floating IP, UUID {}. Error: {}" \
480 "".format(floatingip_id, e)
481 logger.info(msg)
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300482
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300483 def create_project(self):
484 project_name = "spt-test-project-{}".format(random.randrange(100, 999))
485 project = self.os_clients.auth.projects.create(
486 name=project_name, domain=self.os_clients.domain,
487 description="Mirantis SPT test project")
488 logger.info("Created a project {}, uuid: {}".format(
489 project.name, project.id))
490 return project
491
492 def add_roles_to_user_in_project(self, project_id, username='admin',
493 domain='default', roles=None):
494 user_id = [
495 user.id for user in self.os_clients.auth.users.list()
496 if (user.name == username) and (user.domain_id == domain)][0]
497 if roles is None:
498 roles = ["admin", "member", "creator"]
499 for role in roles:
500 try:
501 role_id = self.os_clients.auth.roles.list(name=role)[0].id
502 self.os_clients.auth.roles.grant(
503 role=role_id, user=user_id, project=project_id)
504 except Exception as e:
505 continue
506 logger.info("Added admin user to {} project".format(project_id))
507
508 def is_project_empty(self, project_id):
509 sec_groups = [i for i in self.os_clients.network.list_security_groups(
510 tenant_id=project_id)['security_groups'] if i['name'] != 'default']
511 servers = self.os_clients.compute.servers.list(
512 search_opts={'project_id': project_id})
513 nets = self.os_clients.network.list_networks(
514 project_id=project_id)["networks"]
515 subnets = self.os_clients.network.list_subnets(
516 project_id=project_id)["subnets"]
517 ports = self.os_clients.network.list_ports(
518 project_id=project_id)["ports"]
519 routers = self.os_clients.network.list_routers(
520 project_id=project_id)["routers"]
521 resources = [*sec_groups, *servers, *nets, *subnets, *ports, *routers]
522 return not bool(resources)
523
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300524 def is_cloud_tf(self):
525 # Detect the TF cloud by assuming it does not have any neutron
526 # agents (404 in response)
527 try:
528 self.os_clients.network.list_agents()
529 except neutron_common.exceptions.NotFound:
530 logger.info("MOS TF cloud is detected.")
531 return True
532 return False
533
534 def update_network_port_with_custom_mtu(self, vm_uuid, custom_mtu):
535 port_uuid = self.os_clients.network.list_ports(
536 device_id=vm_uuid).get("ports")[0]["id"]
537 body = {"port": {"extra_dhcp_opts": [
538 {"opt_name": "interface-mtu", "opt_value": str(custom_mtu)}]}}
539 try:
540 self.os_clients.network.update_port(port_uuid, body)
541 except Exception as e:
542 raise Exception("Could not set custom MTU by updating the port. "
543 "See detailed error: {}".format(e))
544 logger.info("The port {} is updated with custom MTU {}."
545 "".format(port_uuid, custom_mtu))
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300546
547 def get_flavor_id_by_name(self, name):
548 flavors = [flavor for flavor in self.os_clients.compute.flavors.list()]
549 flavor_id = [f.id for f in flavors if f.name == name]
550 if not flavor_id:
551 return None
552 return str(flavor_id[0])