blob: 0e2ab23be79be56b89032f57b449f299046c6b04 [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
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200226
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300227 def get_project_by_name(self, name):
Ievgeniia Zadorozhna21517712024-07-30 14:14:08 +0200228 return self.os_clients.auth.projects.find(
229 name=name, domain_id=self.os_clients.auth.user_domain_id)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200230
231 def get_internal_network(self):
232 networks = [
233 net for net in self.os_clients.network.list_networks()["networks"]
234 if net["admin_state_up"] and not net["router:external"] and
235 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300236 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200237 if networks:
238 net = networks[0]
239 else:
240 net = self.create_network_resources()
241 return net
242
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200243 def get_external_network(self):
244 config = utils.get_configuration()
245 ext_net = config.get('external_network') or ''
246 if not ext_net:
247 networks = [
248 net for net in
249 self.os_clients.network.list_networks()["networks"]
250 if net["admin_state_up"] and net["router:external"] and
251 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300252 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200253 else:
254 networks = [net for net in
255 self.os_clients.network.list_networks()["networks"]
256 if net["name"] == ext_net]
257
258 if networks:
259 ext_net = networks[0]
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300260 logger.info("Using external net '{}'".format(ext_net["name"]))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200261 else:
Ievgeniia Zadorozhnaf210baa2025-03-28 00:04:45 +0100262 return None
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200263 return ext_net
264
265 def create_flavor(self, name, ram=256, vcpus=1, disk=2):
266 logger.info("Creating a flavor {}".format(name))
267 return self.os_clients.compute.flavors.create(name, ram, vcpus, disk)
268
269 def create_sec_group(self, rulesets=None):
270 if rulesets is None:
271 rulesets = [
272 {
273 # ssh
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300274 'protocol': 'tcp',
275 'port_range_max': 22,
276 'port_range_min': 22,
277 'remote_ip_prefix': '0.0.0.0/0',
278 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200279 },
280 {
281 # iperf3
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300282 'protocol': 'tcp',
283 'port_range_max': 5201,
284 'port_range_min': 5201,
285 'remote_ip_prefix': '0.0.0.0/0',
286 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200287 },
288 {
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300289 # iperf
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300290 'protocol': 'tcp',
291 'port_range_max': 5001,
292 'port_range_min': 5001,
293 'remote_ip_prefix': '0.0.0.0/0',
294 'direction': 'ingress'
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300295 },
296 {
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200297 # ping
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300298 'protocol': 'icmp',
299 'remote_ip_prefix': '0.0.0.0/0',
300 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200301 }
302 ]
303 sg_name = "spt-test-secgroup-{}".format(random.randrange(100, 999))
304 sg_desc = sg_name + " SPT"
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300305 body = {"security_group": {"name": sg_name, "description": sg_desc}}
306 secgroup = self.os_clients.network.create_security_group(body=body)
307
308 rule_body_teplate = {"security_group_rule": {}}
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200309 for ruleset in rulesets:
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300310 rule_body_teplate["security_group_rule"] = ruleset
311 rule_body_teplate["security_group_rule"]["security_group_id"] = \
312 secgroup['security_group']['id']
313 self.os_clients.network.create_security_group_rule(
314 body=rule_body_teplate)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200315 logger.info("Created a security group {}".format(sg_name))
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300316 return secgroup['security_group']
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200317
318 def create_basic_server(self, image=None, flavor=None, net=None,
319 availability_zone=None, sec_groups=(),
320 keypair=None):
321 os_conn = self.os_clients
322 net = net or self.get_internal_network()
323 kwargs = {}
324 if sec_groups:
325 kwargs['security_groups'] = sec_groups
326 server = os_conn.compute.servers.create(
327 "spt-test-server-{}".format(random.randrange(100, 999)),
328 image, flavor, nics=[{"net-id": net["id"]}],
329 availability_zone=availability_zone, key_name=keypair, **kwargs)
330
331 return server
332
333 def get_vm(self, vm_id):
334 os_conn = self.os_clients
335 try:
336 vm = os_conn.compute.servers.find(id=vm_id)
337 except Exception as e:
338 raise Exception(
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300339 "Could not get the VM \"{}\": {}".format(
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200340 vm_id, e))
341 return vm
342
343 def check_vm_is_active(self, vm_uuid, retry_delay=5, timeout=500):
344 vm = None
345 timeout_reached = False
346 start_time = time.time()
347 expected_state = 'ACTIVE'
348 while not timeout_reached:
349 vm = self.get_vm(vm_uuid)
350 if vm.status == expected_state:
351 logger.info(
352 "VM {} is in {} status.".format(vm_uuid, vm.status))
353 break
354 if vm.status == 'ERROR':
355 break
356 time.sleep(retry_delay)
357 timeout_reached = (time.time() - start_time) > timeout
358 if vm.status != expected_state:
359 logger.info("VM {} is in {} status.".format(vm_uuid, vm.status))
360 raise TimeoutError(
361 "VM {vm_uuid} on is expected to be in '{expected_state}' "
362 "state, but is in '{actual}' state instead.".format(
363 vm_uuid=vm_uuid, expected_state=expected_state,
364 actual=vm.status))
365
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300366 def create_network(self, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200367 net_name = "spt-test-net-{}".format(random.randrange(100, 999))
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300368 config = utils.get_configuration()
369 mtu = config.get('custom_mtu') or 'default'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200370 net_body = {
371 'network': {
372 'name': net_name,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300373 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200374 }
375 }
Ievgeniia Zadorozhna040dfe82023-03-03 04:48:05 +0300376 # in TF2011 we cannot set MTU while creating the net: 400 Bad request
377 # error can happen with 'mtu' field, so we update mtu of ports later
378 if (mtu != 'default') and (not self.is_cloud_tf()):
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300379 try:
380 net_body['network']['mtu'] = int(mtu)
381 except ValueError as e:
382 raise ValueError("MTU value '{}' is not correct. "
383 "Must be an integer at 'custom_mtu' in "
384 "global_config.yaml.\n{}".format(mtu, e))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200385 net = self.os_clients.network.create_network(net_body)['network']
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300386 # WA for TF because the network object does not have 'mtu' field by
387 # default, so this blocked running tests at TF envs with default MTU
388 if 'mtu' not in net:
389 net['mtu'] = None
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300390 logger.info("Created internal network {} in {} project".format(
391 net_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200392 return net
393
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300394 def create_subnet(self, net, project_id, cidr=None):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200395 subnet_name = "spt-test-subnet-{}".format(random.randrange(100, 999))
396 subnet_body = {
397 'subnet': {
398 "name": subnet_name,
399 'network_id': net['id'],
400 'ip_version': 4,
401 'cidr': cidr if cidr else '10.1.7.0/24',
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300402 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200403 }
404 }
405 subnet = self.os_clients.network.create_subnet(subnet_body)['subnet']
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300406 logger.info("Created subnet {} in {} project".format(
407 subnet_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200408 return subnet
409
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300410 def create_router(self, ext_net, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200411 name = 'spt-test-router-{}'.format(random.randrange(100, 999))
412 router_body = {
413 'router': {
414 'name': name,
415 'external_gateway_info': {
416 'network_id': ext_net['id']
417 },
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300418 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200419 }
420 }
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300421 logger.info("Created a router {} in {} project".format(
422 name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200423 router = self.os_clients.network.create_router(router_body)['router']
424 return router
425
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300426 def create_network_resources(self, project="admin", cidr=None):
427 project_id = self.get_project_by_name(project).id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200428 self.get_external_network()
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300429 net = self.create_network(project_id)
430 self.create_subnet(net, project_id, cidr)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200431 return net
432
433 def list_nova_computes(self):
434 nova_services = self.os_clients.compute.hosts.list()
435 computes_list = [h for h in nova_services if h.service == "compute"]
436 return computes_list
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300437
438 def create_floating_ip(self, floating_net_id):
439 fip = self.os_clients.network.create_floatingip({"floatingip": {
440 "floating_network_id": floating_net_id}})
441 return fip['floatingip']
442
443 def delete_floating_ip(self, floatingip_id):
444 try:
445 return self.os_clients.network.delete_floatingip(floatingip_id)
446 except neutron_common.exceptions.NotFound as e:
447 msg = "Could not delete a Floating IP, UUID {}. Error: {}" \
448 "".format(floatingip_id, e)
449 logger.info(msg)
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300450
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300451 def create_project(self):
452 project_name = "spt-test-project-{}".format(random.randrange(100, 999))
453 project = self.os_clients.auth.projects.create(
454 name=project_name, domain=self.os_clients.domain,
455 description="Mirantis SPT test project")
456 logger.info("Created a project {}, uuid: {}".format(
457 project.name, project.id))
458 return project
459
460 def add_roles_to_user_in_project(self, project_id, username='admin',
461 domain='default', roles=None):
462 user_id = [
463 user.id for user in self.os_clients.auth.users.list()
464 if (user.name == username) and (user.domain_id == domain)][0]
465 if roles is None:
466 roles = ["admin", "member", "creator"]
467 for role in roles:
468 try:
469 role_id = self.os_clients.auth.roles.list(name=role)[0].id
470 self.os_clients.auth.roles.grant(
471 role=role_id, user=user_id, project=project_id)
472 except Exception as e:
473 continue
474 logger.info("Added admin user to {} project".format(project_id))
475
476 def is_project_empty(self, project_id):
477 sec_groups = [i for i in self.os_clients.network.list_security_groups(
478 tenant_id=project_id)['security_groups'] if i['name'] != 'default']
479 servers = self.os_clients.compute.servers.list(
480 search_opts={'project_id': project_id})
481 nets = self.os_clients.network.list_networks(
482 project_id=project_id)["networks"]
483 subnets = self.os_clients.network.list_subnets(
484 project_id=project_id)["subnets"]
485 ports = self.os_clients.network.list_ports(
486 project_id=project_id)["ports"]
487 routers = self.os_clients.network.list_routers(
488 project_id=project_id)["routers"]
489 resources = [*sec_groups, *servers, *nets, *subnets, *ports, *routers]
490 return not bool(resources)
491
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300492 def is_cloud_tf(self):
493 # Detect the TF cloud by assuming it does not have any neutron
494 # agents (404 in response)
495 try:
496 self.os_clients.network.list_agents()
497 except neutron_common.exceptions.NotFound:
498 logger.info("MOS TF cloud is detected.")
499 return True
500 return False
501
502 def update_network_port_with_custom_mtu(self, vm_uuid, custom_mtu):
503 port_uuid = self.os_clients.network.list_ports(
504 device_id=vm_uuid).get("ports")[0]["id"]
505 body = {"port": {"extra_dhcp_opts": [
506 {"opt_name": "interface-mtu", "opt_value": str(custom_mtu)}]}}
507 try:
508 self.os_clients.network.update_port(port_uuid, body)
509 except Exception as e:
510 raise Exception("Could not set custom MTU by updating the port. "
511 "See detailed error: {}".format(e))
512 logger.info("The port {} is updated with custom MTU {}."
513 "".format(port_uuid, custom_mtu))
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300514
515 def get_flavor_id_by_name(self, name):
516 flavors = [flavor for flavor in self.os_clients.compute.flavors.list()]
517 flavor_id = [f.id for f in flavors if f.name == name]
518 if not flavor_id:
519 return None
520 return str(flavor_id[0])