blob: 7febc30e535512c428fdb3949f791b58ac690ff6 [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 Zadorozhna84023022021-12-30 13:00:41 +020037 cert=False, domain="Default", **kwargs):
38 self.traceback = ""
39
40 self.client_attr_names = [
41 "auth",
42 "compute",
43 "network",
44 "volume",
45 "image",
46 ]
47 self.username = username
48 self.password = password
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030049 self.project_name = project_name
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020050 self.auth_url = auth_url
51 self.endpoint_type = endpoint_type
52 self.cert = cert
53 self.domain = domain
54 self.kwargs = kwargs
55
56 # Lazy clients
57 self._auth = None
58 self._compute = None
59 self._network = None
60 self._volume = None
61 self._image = None
62
63 @classmethod
64 def _get_auth_session(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030065 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020066 domain='Default'):
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030067 if None in (username, password, project_name):
68 sys.stdout.write((username, password, project_name))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020069 msg = ("Missing required credentials for identity client. "
70 "username: {username}, password: {password}, "
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030071 "project_name: {project_name}").format(
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020072 username=username,
73 password=password,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030074 project_name=project_name
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020075 )
76 raise msg
77
78 if cert and "https" not in auth_url:
79 auth_url = auth_url.replace("http", "https")
80
81 if "v2" in auth_url:
82 raise BaseException("Keystone v2 is deprecated since OpenStack"
83 "Queens release. So current OS_AUTH_URL {} "
84 "is not valid. Please use Keystone v3."
85 "".format(auth_url))
86 else:
87 auth_url = auth_url if ("v3" in auth_url) else "{}{}".format(
88 auth_url, "/v3")
89 auth = keystone_identity.v3.Password(
90 auth_url=auth_url,
91 user_domain_name=domain,
92 username=username,
93 password=password,
94 project_domain_name=domain,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +030095 project_name=project_name)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +020096
97 auth_session = keystone_session.Session(auth=auth, verify=cert)
98 # auth_session.get_auth_headers()
99 return auth_session
100
101 @classmethod
102 def get_auth_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300103 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200104 domain='Default', **kwargs):
105 session = cls._get_auth_session(
106 username=username,
107 password=password,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300108 project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200109 auth_url=auth_url,
110 cert=cert,
111 domain=domain)
112 keystone = keystone_client.Client(version=cls.KEYSTONECLIENT_VERSION,
113 session=session, **kwargs)
114 keystone.management_url = auth_url
115 return keystone
116
117 @classmethod
118 def get_compute_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300119 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200120 domain='Default', **kwargs):
121 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300122 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200123 auth_url=auth_url, cert=cert, domain=domain)
124 service_type = 'compute'
125 compute_client = novaclient.Client(
126 version=cls.NOVACLIENT_VERSION, session=session,
127 service_type=service_type, os_cache=False, **kwargs)
128 return compute_client
129
130 @classmethod
131 def get_network_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300132 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200133 domain='Default', **kwargs):
134 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300135 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200136 auth_url=auth_url, cert=cert, domain=domain)
137 service_type = 'network'
138 return neutron_client.Client(
139 service_type=service_type, session=session,
140 interface=cls.INTERFACE, **kwargs)
141
142 @classmethod
143 def get_volume_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300144 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200145 domain='Default', **kwargs):
146 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300147 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200148 auth_url=auth_url, cert=cert, domain=domain)
149 service_type = 'volume'
150 return cinder_client.Client(
151 version=cls.CINDERCLIENT_VERSION,
152 service_type=service_type,
153 interface=cls.INTERFACE,
154 session=session, **kwargs)
155
156 @classmethod
157 def get_image_client(cls, username=None, password=None,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300158 project_name=None, auth_url=None, cert=None,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200159 domain='Default', **kwargs):
160 session = cls._get_auth_session(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300161 username=username, password=password, project_name=project_name,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200162 auth_url=auth_url, cert=cert, domain=domain)
163 service_type = 'image'
164 return glance_client.Client(
165 version=cls.GLANCECLIENT_VERSION,
166 service_type=service_type,
167 session=session, interface=cls.INTERFACE,
168 **kwargs)
169
170 @property
171 def auth(self):
172 if self._auth is None:
173 self._auth = self.get_auth_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300174 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200175 self.cert, self.domain, endpoint_type=self.endpoint_type
176 )
177 return self._auth
178
179 @property
180 def compute(self):
181 if self._compute is None:
182 self._compute = self.get_compute_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300183 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200184 self.cert, self.domain, endpoint_type=self.endpoint_type
185 )
186 return self._compute
187
188 @property
189 def network(self):
190 if self._network is None:
191 self._network = self.get_network_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300192 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200193 self.cert, self.domain, endpoint_type=self.endpoint_type
194 )
195 return self._network
196
197 @property
198 def volume(self):
199 if self._volume is None:
200 self._volume = self.get_volume_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300201 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200202 self.cert, self.domain, endpoint_type=self.endpoint_type
203 )
204 return self._volume
205
206 @property
207 def image(self):
208
209 if self._image is None:
210 self._image = self.get_image_client(
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300211 self.username, self.password, self.project_name, self.auth_url,
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200212 self.cert, self.domain
213 )
214 return self._image
215
216
217class OSCliActions(object):
218 def __init__(self, os_clients):
219 self.os_clients = os_clients
220 self.create_fake_ext_net = False
221
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300222 def get_project_by_name(self, name):
Ievgeniia Zadorozhna21517712024-07-30 14:14:08 +0200223 return self.os_clients.auth.projects.find(
224 name=name, domain_id=self.os_clients.auth.user_domain_id)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200225
226 def get_internal_network(self):
227 networks = [
228 net for net in self.os_clients.network.list_networks()["networks"]
229 if net["admin_state_up"] and not net["router:external"] and
230 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300231 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200232 if networks:
233 net = networks[0]
234 else:
235 net = self.create_network_resources()
236 return net
237
238 def create_fake_external_network(self):
239 logger.info(
240 "Could not find any external network, creating a fake one...")
241 net_name = "spt-ext-net-{}".format(random.randrange(100, 999))
242 net_body = {"network": {"name": net_name,
243 "router:external": True,
244 "provider:network_type": "local"}}
245 try:
246 ext_net = \
247 self.os_clients.network.create_network(net_body)['network']
248 logger.info("Created a fake external net {}".format(net_name))
249 except Exception as e:
250 # in case 'local' net type is absent, create with default type
251 net_body["network"].pop('provider:network_type', None)
252 ext_net = \
253 self.os_clients.network.create_network(net_body)['network']
254 subnet_name = "spt-ext-subnet-{}".format(random.randrange(100, 999))
255 subnet_body = {
256 "subnet": {
257 "name": subnet_name,
258 "network_id": ext_net["id"],
259 "ip_version": 4,
260 "cidr": "10.255.255.0/24",
261 "allocation_pools": [{"start": "10.255.255.100",
262 "end": "10.255.255.200"}]
263 }
264 }
265 self.os_clients.network.create_subnet(subnet_body)
266 self.create_fake_ext_net = True
267 return ext_net
268
269 def get_external_network(self):
270 config = utils.get_configuration()
271 ext_net = config.get('external_network') or ''
272 if not ext_net:
273 networks = [
274 net for net in
275 self.os_clients.network.list_networks()["networks"]
276 if net["admin_state_up"] and net["router:external"] and
277 len(net["subnets"])
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300278 ]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200279 else:
280 networks = [net for net in
281 self.os_clients.network.list_networks()["networks"]
282 if net["name"] == ext_net]
283
284 if networks:
285 ext_net = networks[0]
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300286 logger.info("Using external net '{}'".format(ext_net["name"]))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200287 else:
288 ext_net = self.create_fake_external_network()
289 return ext_net
290
291 def create_flavor(self, name, ram=256, vcpus=1, disk=2):
292 logger.info("Creating a flavor {}".format(name))
293 return self.os_clients.compute.flavors.create(name, ram, vcpus, disk)
294
295 def create_sec_group(self, rulesets=None):
296 if rulesets is None:
297 rulesets = [
298 {
299 # ssh
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300300 'protocol': 'tcp',
301 'port_range_max': 22,
302 'port_range_min': 22,
303 'remote_ip_prefix': '0.0.0.0/0',
304 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200305 },
306 {
307 # iperf3
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300308 'protocol': 'tcp',
309 'port_range_max': 5201,
310 'port_range_min': 5201,
311 'remote_ip_prefix': '0.0.0.0/0',
312 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200313 },
314 {
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300315 # iperf
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300316 'protocol': 'tcp',
317 'port_range_max': 5001,
318 'port_range_min': 5001,
319 'remote_ip_prefix': '0.0.0.0/0',
320 'direction': 'ingress'
Ievgeniia Zadorozhna5ed74e22022-07-26 16:56:23 +0300321 },
322 {
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200323 # ping
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300324 'protocol': 'icmp',
325 'remote_ip_prefix': '0.0.0.0/0',
326 'direction': 'ingress'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200327 }
328 ]
329 sg_name = "spt-test-secgroup-{}".format(random.randrange(100, 999))
330 sg_desc = sg_name + " SPT"
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300331 body = {"security_group": {"name": sg_name, "description": sg_desc}}
332 secgroup = self.os_clients.network.create_security_group(body=body)
333
334 rule_body_teplate = {"security_group_rule": {}}
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200335 for ruleset in rulesets:
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300336 rule_body_teplate["security_group_rule"] = ruleset
337 rule_body_teplate["security_group_rule"]["security_group_id"] = \
338 secgroup['security_group']['id']
339 self.os_clients.network.create_security_group_rule(
340 body=rule_body_teplate)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200341 logger.info("Created a security group {}".format(sg_name))
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300342 return secgroup['security_group']
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200343
344 def create_basic_server(self, image=None, flavor=None, net=None,
345 availability_zone=None, sec_groups=(),
346 keypair=None):
347 os_conn = self.os_clients
348 net = net or self.get_internal_network()
349 kwargs = {}
350 if sec_groups:
351 kwargs['security_groups'] = sec_groups
352 server = os_conn.compute.servers.create(
353 "spt-test-server-{}".format(random.randrange(100, 999)),
354 image, flavor, nics=[{"net-id": net["id"]}],
355 availability_zone=availability_zone, key_name=keypair, **kwargs)
356
357 return server
358
359 def get_vm(self, vm_id):
360 os_conn = self.os_clients
361 try:
362 vm = os_conn.compute.servers.find(id=vm_id)
363 except Exception as e:
364 raise Exception(
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300365 "Could not get the VM \"{}\": {}".format(
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200366 vm_id, e))
367 return vm
368
369 def check_vm_is_active(self, vm_uuid, retry_delay=5, timeout=500):
370 vm = None
371 timeout_reached = False
372 start_time = time.time()
373 expected_state = 'ACTIVE'
374 while not timeout_reached:
375 vm = self.get_vm(vm_uuid)
376 if vm.status == expected_state:
377 logger.info(
378 "VM {} is in {} status.".format(vm_uuid, vm.status))
379 break
380 if vm.status == 'ERROR':
381 break
382 time.sleep(retry_delay)
383 timeout_reached = (time.time() - start_time) > timeout
384 if vm.status != expected_state:
385 logger.info("VM {} is in {} status.".format(vm_uuid, vm.status))
386 raise TimeoutError(
387 "VM {vm_uuid} on is expected to be in '{expected_state}' "
388 "state, but is in '{actual}' state instead.".format(
389 vm_uuid=vm_uuid, expected_state=expected_state,
390 actual=vm.status))
391
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300392 def create_network(self, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200393 net_name = "spt-test-net-{}".format(random.randrange(100, 999))
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300394 config = utils.get_configuration()
395 mtu = config.get('custom_mtu') or 'default'
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200396 net_body = {
397 'network': {
398 'name': net_name,
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300399 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200400 }
401 }
Ievgeniia Zadorozhna040dfe82023-03-03 04:48:05 +0300402 # in TF2011 we cannot set MTU while creating the net: 400 Bad request
403 # error can happen with 'mtu' field, so we update mtu of ports later
404 if (mtu != 'default') and (not self.is_cloud_tf()):
Ievgeniia Zadorozhnafa13ba62022-06-18 02:03:09 +0300405 try:
406 net_body['network']['mtu'] = int(mtu)
407 except ValueError as e:
408 raise ValueError("MTU value '{}' is not correct. "
409 "Must be an integer at 'custom_mtu' in "
410 "global_config.yaml.\n{}".format(mtu, e))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200411 net = self.os_clients.network.create_network(net_body)['network']
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300412 # WA for TF because the network object does not have 'mtu' field by
413 # default, so this blocked running tests at TF envs with default MTU
414 if 'mtu' not in net:
415 net['mtu'] = None
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300416 logger.info("Created internal network {} in {} project".format(
417 net_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200418 return net
419
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300420 def create_subnet(self, net, project_id, cidr=None):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200421 subnet_name = "spt-test-subnet-{}".format(random.randrange(100, 999))
422 subnet_body = {
423 'subnet': {
424 "name": subnet_name,
425 'network_id': net['id'],
426 'ip_version': 4,
427 'cidr': cidr if cidr else '10.1.7.0/24',
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300428 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200429 }
430 }
431 subnet = self.os_clients.network.create_subnet(subnet_body)['subnet']
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300432 logger.info("Created subnet {} in {} project".format(
433 subnet_name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200434 return subnet
435
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300436 def create_router(self, ext_net, project_id):
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200437 name = 'spt-test-router-{}'.format(random.randrange(100, 999))
438 router_body = {
439 'router': {
440 'name': name,
441 'external_gateway_info': {
442 'network_id': ext_net['id']
443 },
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300444 'project_id': project_id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200445 }
446 }
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300447 logger.info("Created a router {} in {} project".format(
448 name, project_id))
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200449 router = self.os_clients.network.create_router(router_body)['router']
450 return router
451
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300452 def create_network_resources(self, project="admin", cidr=None):
453 project_id = self.get_project_by_name(project).id
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200454 self.get_external_network()
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300455 net = self.create_network(project_id)
456 self.create_subnet(net, project_id, cidr)
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +0200457 return net
458
459 def list_nova_computes(self):
460 nova_services = self.os_clients.compute.hosts.list()
461 computes_list = [h for h in nova_services if h.service == "compute"]
462 return computes_list
Ievgeniia Zadorozhna2c6469d2022-08-10 17:21:10 +0300463
464 def create_floating_ip(self, floating_net_id):
465 fip = self.os_clients.network.create_floatingip({"floatingip": {
466 "floating_network_id": floating_net_id}})
467 return fip['floatingip']
468
469 def delete_floating_ip(self, floatingip_id):
470 try:
471 return self.os_clients.network.delete_floatingip(floatingip_id)
472 except neutron_common.exceptions.NotFound as e:
473 msg = "Could not delete a Floating IP, UUID {}. Error: {}" \
474 "".format(floatingip_id, e)
475 logger.info(msg)
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300476
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300477 def create_project(self):
478 project_name = "spt-test-project-{}".format(random.randrange(100, 999))
479 project = self.os_clients.auth.projects.create(
480 name=project_name, domain=self.os_clients.domain,
481 description="Mirantis SPT test project")
482 logger.info("Created a project {}, uuid: {}".format(
483 project.name, project.id))
484 return project
485
486 def add_roles_to_user_in_project(self, project_id, username='admin',
487 domain='default', roles=None):
488 user_id = [
489 user.id for user in self.os_clients.auth.users.list()
490 if (user.name == username) and (user.domain_id == domain)][0]
491 if roles is None:
492 roles = ["admin", "member", "creator"]
493 for role in roles:
494 try:
495 role_id = self.os_clients.auth.roles.list(name=role)[0].id
496 self.os_clients.auth.roles.grant(
497 role=role_id, user=user_id, project=project_id)
498 except Exception as e:
499 continue
500 logger.info("Added admin user to {} project".format(project_id))
501
502 def is_project_empty(self, project_id):
503 sec_groups = [i for i in self.os_clients.network.list_security_groups(
504 tenant_id=project_id)['security_groups'] if i['name'] != 'default']
505 servers = self.os_clients.compute.servers.list(
506 search_opts={'project_id': project_id})
507 nets = self.os_clients.network.list_networks(
508 project_id=project_id)["networks"]
509 subnets = self.os_clients.network.list_subnets(
510 project_id=project_id)["subnets"]
511 ports = self.os_clients.network.list_ports(
512 project_id=project_id)["ports"]
513 routers = self.os_clients.network.list_routers(
514 project_id=project_id)["routers"]
515 resources = [*sec_groups, *servers, *nets, *subnets, *ports, *routers]
516 return not bool(resources)
517
Ievgeniia Zadorozhnac67b86b2023-02-02 18:09:12 +0300518 def is_cloud_tf(self):
519 # Detect the TF cloud by assuming it does not have any neutron
520 # agents (404 in response)
521 try:
522 self.os_clients.network.list_agents()
523 except neutron_common.exceptions.NotFound:
524 logger.info("MOS TF cloud is detected.")
525 return True
526 return False
527
528 def update_network_port_with_custom_mtu(self, vm_uuid, custom_mtu):
529 port_uuid = self.os_clients.network.list_ports(
530 device_id=vm_uuid).get("ports")[0]["id"]
531 body = {"port": {"extra_dhcp_opts": [
532 {"opt_name": "interface-mtu", "opt_value": str(custom_mtu)}]}}
533 try:
534 self.os_clients.network.update_port(port_uuid, body)
535 except Exception as e:
536 raise Exception("Could not set custom MTU by updating the port. "
537 "See detailed error: {}".format(e))
538 logger.info("The port {} is updated with custom MTU {}."
539 "".format(port_uuid, custom_mtu))
Ievgeniia Zadorozhnaf22827b2022-07-20 13:30:32 +0300540
541 def get_flavor_id_by_name(self, name):
542 flavors = [flavor for flavor in self.os_clients.compute.flavors.list()]
543 flavor_id = [f.id for f in flavors if f.name == name]
544 if not flavor_id:
545 return None
546 return str(flavor_id[0])