blob: 6e9305a55a6efc065ac3f50846a536910fc9ad24 [file] [log] [blame]
Dmitriy Kruglovb811e642022-10-06 12:24:33 +02001import argparse
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +03002import json
Dmitriy Kruglovb811e642022-10-06 12:24:33 +02003import os
4import re
5import sys
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +03006import time
7
8from types import SimpleNamespace
Dmitriy Kruglovb811e642022-10-06 12:24:33 +02009
10import openstack
11
12
13# Send logs to both, a log file and stdout
14openstack.enable_logging(debug=False, path='openstack.log', stream=sys.stdout)
15
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +030016volume_api_version = "3.43"
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +010017manila_api_version = "2.75"
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +030018
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020019# Connect to cloud
20TEST_CLOUD = os.getenv('OS_TEST_CLOUD', 'os-cloud')
21cloud = openstack.connect(cloud=TEST_CLOUD)
22log = cloud.log
23
24# Get cloud config (clouds.yaml vars)
25config_obj = openstack.config.loader.OpenStackConfig()
26cloud_config = config_obj.get_one(cloud=TEST_CLOUD)
27
28compute = cloud.compute
29identity = cloud.identity
30image = cloud.image
31network = cloud.network
32orchestration = cloud.orchestration
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020033volume = cloud.volume
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +030034load_balancer = cloud.load_balancer
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020035
Ievgeniia Zadorozhnab02617b2024-01-22 23:59:05 +010036# Check if Object Storage is present on the cloud, else skip
37object_store_present = any(service.type == 'object-store' for service
38 in list(identity.services()))
39if object_store_present:
40 object_store = cloud.object_store
41
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +010042# Check if Manila Shared File System is present on the cloud, else skip
43manila_present = any(service.type == 'sharev2' for service
44 in list(identity.services()))
45if manila_present:
46 shared_file_system = cloud.shared_file_system
47
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +010048mask = "cvp|s_rally|rally_|tempest-|tempest_|spt-test|fio"
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020049full_mask = f"^(?!.*(manual|-static-)).*({mask}).*$"
50mask_pattern = re.compile(full_mask, re.IGNORECASE)
51stack_mask = "api-[0-9]+-[a-z]+"
52stack_pattern = re.compile(stack_mask, re.IGNORECASE)
53
54
55def get_resource_value(resource_key, default):
56 try:
57 return cloud_config.config['custom_vars'][resource_key]
58 except KeyError:
59 return default
60
61
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +030062def items_to_object(items):
63 data = json.dumps(items)
64 return json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
65
66
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020067def _filter_test_resources(resources, attribute, pattern=mask_pattern):
68 filtered_resources = {}
69 for item in resources:
70 # If there is no attribute in object, use just empty string as value
71 value = getattr(item, attribute, '')
72 # If the attribute value is None, use empty string instead, to be
73 # able to run regex search
74 if value is None:
75 value = ''
76 found = pattern.match(value)
77 if found:
78 filtered_resources[item.id] = getattr(item, attribute)
79 return filtered_resources
80
81
82def _log_resources_count(count, resource, pattern=mask):
83 log.info(f"{count} {resource} containing '{pattern}' are found.")
84
85
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +010086def _log_resources_details_at_dry_run(list_to_delete, resource):
87 if len(list_to_delete) > 0:
88 log.info(f"... {len(list_to_delete)} {resource} would be deleted:")
89 for id_ in list_to_delete:
90 log.info(f"... ... {id_} ({list_to_delete[id_]})")
91
92
Dmitriy Kruglovb811e642022-10-06 12:24:33 +020093def _log_resource_delete(id_, name, type_):
94 log.info(f"... deleting {name} (id={id_}) {type_}")
95
96
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +010097def _skip_tempest_fixed_net(nets_to_delete: dict) -> dict:
98 # the "tempest-fixed-net" comes from MOSK itself and should not be deleted
99 keys_to_remove = [
100 net_id for net_id, name in nets_to_delete.items()
101 if name == "tempest-fixed-net"
102 ]
103 for net_id in keys_to_remove:
104 nets_to_delete.pop(net_id, None)
105 return nets_to_delete
106
107
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300108def _get_volume_groups(all_tenants='true'):
109 ep = volume.get_endpoint()
110 uri = f"{ep}/groups/detail"
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +0300111 headers = {'X-Auth-Token': cloud.session.get_token(),
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300112 'Accept': 'application/json',
113 'OpenStack-API-Version': f'volume {volume_api_version}'}
114 params = {'all_tenants': all_tenants}
115 response = cloud.session.request(url=uri, method='GET',
116 headers=headers, params=params).json()
117 for group in response['groups']:
118 yield group
119
120
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100121def _get_shares(all_tenants='true'):
122 ep = shared_file_system.get_endpoint()
123 uri = f"{ep}/shares/detail"
124 headers = {'X-Auth-Token': cloud.session.get_token(),
125 'Accept': 'application/json',
126 'X-Openstack-Manila-Api-Version': f'{manila_api_version}'}
127 params = {'all_tenants': all_tenants}
128 response = cloud.session.request(url=uri, method='GET',
129 headers=headers, params=params).json()
130 for share in response['shares']:
131 yield share
132
133
134def _get_share_types(all_tenants='true'):
135 ep = shared_file_system.get_endpoint()
136 uri = f"{ep}/types"
137 headers = {'X-Auth-Token': cloud.session.get_token(),
138 'Accept': 'application/json',
139 'X-Openstack-Manila-Api-Version': f'{manila_api_version}'}
140 params = {'all_tenants': all_tenants}
141 response = cloud.session.request(url=uri, method='GET',
142 headers=headers, params=params).json()
143 for share_type in response['volume_types']:
144 yield share_type
145
146
147def _get_share_networks(all_tenants='true'):
148 ep = shared_file_system.get_endpoint()
149 uri = f"{ep}/share-networks/detail"
150 headers = {'X-Auth-Token': cloud.session.get_token(),
151 'Accept': 'application/json',
152 'X-Openstack-Manila-Api-Version': f'{manila_api_version}'}
153 params = {'all_tenants': all_tenants}
154 response = cloud.session.request(url=uri, method='GET',
155 headers=headers, params=params).json()
156 for share_network in response['share_networks']:
157 yield share_network
158
159
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300160def _delete_volume_group(uuid, delete_volumes='false'):
161 ep = volume.get_endpoint()
162 uri = f"{ep}/groups/{uuid}/action"
163 headers = {'X-Auth-Token': cloud.session.get_token(),
164 'OpenStack-API-Version': f'volume {volume_api_version}',
165 'Content-Type': 'application/json',
166 'Accept': 'application/json'}
167 body = {"delete": {"delete-volumes": delete_volumes}}
168 cloud.session.request(
169 url=uri, method='POST', headers=headers, json=body)
170
171
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100172def _delete_share_type(uuid):
173 ep = shared_file_system.get_endpoint()
174 uri = f"{ep}/types/{uuid}"
175 headers = {'X-Auth-Token': cloud.session.get_token(),
176 'X-Openstack-Manila-Api-Version': f'{manila_api_version}',
177 'Content-Type': 'application/json',
178 'Accept': 'application/json'}
179 cloud.session.request(
180 url=uri, method='DELETE', headers=headers)
181
182
183def _delete_share(uuid, force_delete=True):
184 ep = shared_file_system.get_endpoint()
185 uri = f"{ep}/shares/{uuid}/action"
186 headers = {'X-Auth-Token': cloud.session.get_token(),
187 'X-Openstack-Manila-Api-Version': f'{manila_api_version}',
188 'Content-Type': 'application/json',
189 'Accept': 'application/json'}
190 body = {"force_delete": force_delete}
191 cloud.session.request(
192 url=uri, method='POST', headers=headers, json=body)
193
194
195def _delete_share_network(uuid):
196 ep = shared_file_system.get_endpoint()
197 uri = f"{ep}/share-networks/{uuid}"
198 headers = {'X-Auth-Token': cloud.session.get_token(),
199 'X-Openstack-Manila-Api-Version': f'{manila_api_version}',
200 'Content-Type': 'application/json',
201 'Accept': 'application/json'}
202 cloud.session.request(
203 url=uri, method='DELETE', headers=headers)
204
205
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300206def _reset_volume_status(uuid, status='available', attach_status='detached',
207 migration_status='None'):
208 ep = volume.get_endpoint()
209 uri = f"{ep}/volumes/{uuid}/action"
210 headers = {'X-Auth-Token': cloud.session.get_token(),
211 'Content-Type': 'application/json',
212 'Accept': 'application/json'}
213 body = {"os-reset_status": {
214 "status": status, "attach_status": attach_status,
215 "migration_status": migration_status}}
216 cloud.session.request(
217 url=uri, method='POST', headers=headers, json=body)
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +0300218
219
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200220def cleanup_users():
221 users = identity.users()
222 users_to_delete = _filter_test_resources(users, 'name')
223 _log_resources_count(len(users_to_delete), 'user(s)')
224 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100225 _log_resources_details_at_dry_run(users_to_delete, 'user(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200226 return
227 for id_ in users_to_delete:
228 _log_resource_delete(id_, users_to_delete[id_], 'user')
229 identity.delete_user(id_)
230
231
232def cleanup_roles():
233 roles = identity.roles()
234 roles_to_delete = _filter_test_resources(roles, 'name')
235 _log_resources_count(len(roles_to_delete), 'role(s)')
236 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100237 _log_resources_details_at_dry_run(roles_to_delete, 'role(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200238 return
239 for id_ in roles_to_delete:
240 _log_resource_delete(id_, roles_to_delete[id_], 'role')
241 identity.delete_role(id_)
242
243
244def cleanup_projects():
245 projects = identity.projects()
246 projects_to_delete = _filter_test_resources(projects, 'name')
247 _log_resources_count(len(projects_to_delete), 'project(s)')
248 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100249 _log_resources_details_at_dry_run(projects_to_delete, 'project(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200250 return
251 for id_ in projects_to_delete:
252 _log_resource_delete(id_, projects_to_delete[id_], 'project')
253 identity.delete_project(id_)
254
255
256def cleanup_regions():
257 regions = identity.regions()
258 regions_to_delete = _filter_test_resources(regions, 'id')
259 _log_resources_count(len(regions_to_delete), 'region(s)')
260 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100261 _log_resources_details_at_dry_run(regions_to_delete, 'region(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200262 return
263 for id_ in regions_to_delete:
264 _log_resource_delete(id_, id_, 'region')
265 identity.delete_region(id_)
266
267
268def cleanup_services():
269 services = identity.services()
270 services_to_delete = _filter_test_resources(services, 'name')
271 _log_resources_count(len(services_to_delete), 'service(s)')
272 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100273 _log_resources_details_at_dry_run(services_to_delete, 'service(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200274 return
275 for id_ in services_to_delete:
276 _log_resource_delete(id_, services_to_delete[id_], 'service')
277 identity.delete_service(id_)
278
279
280def cleanup_stacks(stacks_alt=False):
281 stacks = orchestration.stacks()
282 stacks_to_delete = _filter_test_resources(stacks, 'name')
283 _log_resources_count(len(stacks_to_delete), 'stack(s)')
284
285 # Use additional pattern for searching/deleting test Heat resources,
286 # if enabled
287 if stacks_alt:
288 stacks_alt_to_delete = _filter_test_resources(
289 stacks, 'name', stack_pattern)
290 _log_resources_count(len(stacks_alt_to_delete), 'stack(s)', stack_mask)
291 stacks_to_delete.update(stacks_alt_to_delete)
292
293 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100294 _log_resources_details_at_dry_run(stacks_to_delete, 'stack(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200295 return
296
297 for id_ in stacks_to_delete:
298 _log_resource_delete(id_, stacks_to_delete[id_], 'stack')
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300299 stack_obj = orchestration.get_stack(id_)
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200300 orchestration.delete_stack(id_)
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300301 orchestration.wait_for_delete(stack_obj)
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200302
303
304def cleanup_flavors():
305 flavors = compute.flavors()
306 flavors_to_delete = _filter_test_resources(flavors, 'name')
307 _log_resources_count(len(flavors_to_delete), 'flavor(s)')
308 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100309 _log_resources_details_at_dry_run(flavors_to_delete, 'flavor(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200310 return
311 for id_ in flavors_to_delete:
312 _log_resource_delete(id_, flavors_to_delete[id_], 'flavor')
313 compute.delete_flavor(id_)
314
315
316def cleanup_images():
317 images = image.images()
318 images_to_delete = _filter_test_resources(images, 'name')
319 _log_resources_count(len(images_to_delete), 'image(s)')
320 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100321 _log_resources_details_at_dry_run(images_to_delete, 'image(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200322 return
323 for id_ in images_to_delete:
324 _log_resource_delete(id_, images_to_delete[id_], 'image')
325 image.delete_image(id_)
326
327
328def cleanup_keypairs():
329 keypairs = compute.keypairs()
330 keypairs_to_delete = _filter_test_resources(keypairs, 'name')
331 _log_resources_count(len(keypairs_to_delete), 'keypair(s)')
332 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100333 _log_resources_details_at_dry_run(keypairs_to_delete, 'keypair(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200334 return
335 for id_ in keypairs_to_delete:
336 _log_resource_delete(id_, keypairs_to_delete[id_], 'keypair')
337 compute.delete_keypair(id_)
338
339
340def cleanup_servers():
341 servers = compute.servers(all_projects=True)
342 servers_to_delete = _filter_test_resources(servers, 'name')
343 _log_resources_count(len(servers_to_delete), 'server(s)')
344 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100345 _log_resources_details_at_dry_run(servers_to_delete, 'server(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200346 return
347 for id_ in servers_to_delete:
348 if args.servers_active:
349 log.info(
350 f"... resetting {servers_to_delete[id_]} (id={id_}) server "
351 "state to 'active'")
352 compute.reset_server_state(id_, 'active')
353 _log_resource_delete(id_, servers_to_delete[id_], 'server')
354 compute.delete_server(id_)
355 srv_obj = compute.get_server(id_)
356 compute.wait_for_delete(srv_obj)
357
358
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100359def cleanup_shares():
360 shares_in_response = _get_shares()
361 shares = items_to_object([g for g in shares_in_response])
362 shares_to_delete = _filter_test_resources(shares, 'name')
363 _log_resources_count(len(shares_to_delete), 'share(s)')
364 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100365 _log_resources_details_at_dry_run(shares_to_delete, 'share(s)')
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100366 return
367 for id_ in shares_to_delete:
368 _log_resource_delete(id_, shares_to_delete[id_], 'share')
369 # TODO: uncomment
370 _delete_share(id_)
371 shr_obj = shared_file_system.get_share(id_)
372 shared_file_system.wait_for_delete(shr_obj)
373
374
375def cleanup_share_types():
376 share_types_in_response = _get_share_types()
377 share_types = items_to_object([g for g in share_types_in_response])
378 share_types_to_delete = _filter_test_resources(share_types, 'name')
379 _log_resources_count(len(share_types_to_delete), 'share type(s)')
380 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100381 _log_resources_details_at_dry_run(share_types_to_delete,
382 'share_type(s)')
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100383 return
384 for id_ in share_types_to_delete:
385 _log_resource_delete(id_, share_types_to_delete[id_], 'type')
386 _delete_share_type(id_)
387
388
389def cleanup_share_networks():
390 share_networks_in_response = _get_share_networks()
391 share_networks = items_to_object([g for g in share_networks_in_response])
392 share_networks_to_delete = _filter_test_resources(share_networks, 'name')
393 _log_resources_count(len(share_networks_to_delete), 'share network(s)')
394 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100395 _log_resources_details_at_dry_run(share_networks_to_delete,
396 'share_network(s)')
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100397 return
398 for id_ in share_networks_to_delete:
399 _log_resource_delete(id_, share_networks_to_delete[id_], 'type')
400 _delete_share_network(id_)
401
402
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200403def cleanup_snapshots():
404 snapshots = volume.snapshots(all_projects=True)
405 snapshots_to_delete = _filter_test_resources(snapshots, 'name')
406 _log_resources_count(len(snapshots_to_delete), 'snapshot(s)')
407 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100408 _log_resources_details_at_dry_run(snapshots_to_delete, 'snapshot(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200409 return
410 for id_ in snapshots_to_delete:
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300411 snapshot_obj = volume.get_snapshot(id_)
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200412 volume.reset_snapshot(id_, 'available')
413 _log_resource_delete(id_, snapshots_to_delete[id_], 'snapshot')
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300414 volume.delete_snapshot(id_, force=True)
415 volume.wait_for_delete(snapshot_obj)
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200416
417
418def cleanup_volumes():
419 volumes = volume.volumes(all_projects=True)
420 volumes_to_delete = _filter_test_resources(volumes, 'name')
421 _log_resources_count(len(volumes_to_delete), 'volume(s)')
422 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100423 _log_resources_details_at_dry_run(volumes_to_delete, 'volume(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200424 return
425 for id_ in volumes_to_delete:
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300426 _reset_volume_status(id_, 'available', 'detached', 'None')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200427 _log_resource_delete(id_, volumes_to_delete[id_], 'volume')
428 volume.delete_volume(id_)
429 vol_obj = volume.get_volume(id_)
430 volume.wait_for_delete(vol_obj)
431
432
433def cleanup_volume_groups():
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300434 groups_in_response = _get_volume_groups()
435 groups = items_to_object([g for g in groups_in_response])
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200436 groups_to_delete = _filter_test_resources(groups, 'name')
437 _log_resources_count(len(groups_to_delete), 'volume group(s)')
438 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100439 _log_resources_details_at_dry_run(groups_to_delete, 'volume group(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200440 return
441 for id_ in groups_to_delete:
442 _log_resource_delete(id_, groups_to_delete[id_], 'volume group')
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300443 _delete_volume_group(id_)
444 time.sleep(10) # TODO(izadorozhna): need to add a proper waiter
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200445
446
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300447def cleanup_volume_backups():
448 backups = volume.backups(all_tenants=True)
449 backups_to_delete = _filter_test_resources(backups, 'name')
450 _log_resources_count(len(backups_to_delete), 'volume backup(s)')
451 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100452 _log_resources_details_at_dry_run(backups_to_delete,
453 'volume backup(s)')
Ievgeniia Zadorozhna85020982023-08-03 22:04:12 +0300454 return
455 for id_ in backups_to_delete:
456 backup_obj = volume.get_backup(id_)
457 _log_resource_delete(id_, backups_to_delete[id_], 'volume backup')
458 volume.delete_backup(id_)
459 volume.wait_for_delete(backup_obj)
460
461
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200462def cleanup_volume_group_types():
463 group_types = volume.group_types()
464 group_types_to_delete = _filter_test_resources(group_types, 'name')
465 _log_resources_count(len(group_types_to_delete), 'volume group type(s)')
466 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100467 _log_resources_details_at_dry_run(group_types_to_delete,
468 'volume group type(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200469 return
470 for id_ in group_types_to_delete:
471 _log_resource_delete(
472 id_, group_types_to_delete[id_], 'volume group type')
473 volume.delete_group_type(id_)
474
475
476def cleanup_volume_types():
477 volume_types = volume.types()
478 volume_types_to_delete = _filter_test_resources(volume_types, 'name')
479 _log_resources_count(len(volume_types_to_delete), 'volume type(s)')
480 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100481 _log_resources_details_at_dry_run(volume_types_to_delete,
482 'volume type(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200483 return
484 for id_ in volume_types_to_delete:
485 _log_resource_delete(id_, volume_types_to_delete[id_], 'volume type')
486 volume.delete_type(id_)
487
488
489def cleanup_sec_groups():
490 sec_groups = network.security_groups()
491 sec_groups_to_delete = _filter_test_resources(sec_groups, 'name')
492 _log_resources_count(len(sec_groups_to_delete), 'security group(s)')
493 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100494 _log_resources_details_at_dry_run(sec_groups_to_delete,
495 'security group(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200496 return
497 for id_ in sec_groups_to_delete:
498 _log_resource_delete(id_, sec_groups_to_delete[id_], 'security group')
499 network.delete_security_group(id_)
500
501
502def cleanup_containers():
503 containers = object_store.containers()
504 containers_to_delete = _filter_test_resources(containers, 'name')
505 _log_resources_count(len(containers_to_delete), 'container(s)')
506 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100507 _log_resources_details_at_dry_run(containers_to_delete, 'container(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200508 return
509 for id_ in containers_to_delete:
510 _log_resource_delete(id_, containers_to_delete[id_], 'container')
511 object_store.delete_container(id_)
512
513
514def cleanup_routers():
515 routers = network.routers()
516 routers_to_delete = _filter_test_resources(routers, 'name')
517 _log_resources_count(len(routers_to_delete), 'router(s)')
518 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100519 _log_resources_details_at_dry_run(routers_to_delete, 'router(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200520 return
521 for id_ in routers_to_delete:
522 _log_resource_delete(id_, routers_to_delete[id_], 'router')
523
524 # Unset external gateway and remove ports from router
525 log.info("... ... removing external gateway from the router")
526 network.update_router(id_, external_gateway_info={})
527 ports = network.ports(device_id=id_)
528 for p in ports:
529 if p.device_owner != 'network:router_ha_interface':
530 log.info(f"... ... removing port {p.id} from the router")
531 network.remove_interface_from_router(id_, port_id=p.id)
532
533 network.delete_router(id_)
534
535
536def cleanup_networks():
537 nets = network.networks()
538 nets_to_delete = _filter_test_resources(nets, 'name')
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100539 _skip_tempest_fixed_net(nets_to_delete)
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200540 _log_resources_count(len(nets_to_delete), 'network(s)')
541 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100542 _log_resources_details_at_dry_run(nets_to_delete, 'network(s)')
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200543 return
544 for id_ in nets_to_delete:
545 _log_resource_delete(id_, nets_to_delete[id_], 'network')
546
547 ports = network.ports(network_id=id_)
548 for p in ports:
549 log.info(
550 f"... ... removing port {p.id} from the network")
551 network.delete_port(p.id)
552 subnets = network.subnets(network_id=id_)
553 for s in subnets:
554 log.info(
555 f"... ... removing subnet {s.id} from the network")
556 network.delete_subnet(s.id)
557
558 network.delete_network(id_)
559
560
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +0300561def cleanup_load_balancers():
562 lbs = load_balancer.load_balancers()
563 lbs_to_delete = _filter_test_resources(lbs, 'name')
564 _log_resources_count(len(lbs_to_delete), 'load_balancer(s)')
565 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100566 _log_resources_details_at_dry_run(lbs_to_delete, 'load_balancer(s)')
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +0300567 return
568 for id_ in lbs_to_delete:
569 _log_resource_delete(id_, lbs_to_delete[id_], 'load_balancer')
570 try:
571 load_balancer.delete_load_balancer(id_, cascade=True)
572 except openstack.exceptions.ConflictException:
573 # force delete the LB in case it is in some PENDING_* state
Ievgeniia Zadorozhnaa33b29a2023-08-29 18:19:47 +0300574 log.info(f"... ... force deleting {id_} load balancer")
575 load_balancer.delete_load_balancer(id_, cascade=True, force=True)
Ievgeniia Zadorozhnaab334132023-08-01 23:20:13 +0300576 except Exception as e:
577 log.info(f"... ... could not delete {id_} load balancer: {e}")
578
579
Ievgeniia Zadorozhna9600b182023-08-04 17:56:24 +0300580def cleanup_floating_ips():
581 projects = identity.projects()
582 list_projects_to_delete = list(_filter_test_resources(projects, 'name'))
583 floating_ips = network.ips()
584 fips_to_delete = {}
585 for ip in floating_ips:
586 # filter only non-associated IPs, only inside target projects
587 if (ip.status == 'DOWN') and (ip.fixed_ip_address is None):
588 if ip.project_id in list_projects_to_delete:
589 fips_to_delete[ip.id] = ip.floating_ip_address
590 _log_resources_count(len(fips_to_delete), 'floating ip(s)')
591 if args.dry_run:
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100592 _log_resources_details_at_dry_run(fips_to_delete, 'floating ip(s)')
Ievgeniia Zadorozhna9600b182023-08-04 17:56:24 +0300593 return
594 for id_ in fips_to_delete:
595 _log_resource_delete(id_, fips_to_delete[id_], 'floating ip')
596 network.delete_ip(id_)
597
598
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200599if __name__ == "__main__":
600 parser = argparse.ArgumentParser(
601 description='OpenStack test resources cleanup script')
602 parser.add_argument(
603 '-t', dest='dry_run', action='store_true',
604 help='Dry run mode, no cleanup is done')
605 parser.add_argument(
606 '-P', dest='projects', action='store_true',
607 help='Force cleanup of projects')
608 parser.add_argument(
609 '-S', dest='servers_active', action='store_true',
610 help='Set servers to ACTIVE before deletion (reqiured by bare metal)')
611 parser.add_argument(
612 '-f', dest='stacks_alt', action='store_true',
613 help='Use additional mask for stack cleanup')
614
615 args = parser.parse_args()
616
617 if args.dry_run:
618 log.info("Running in dry-run mode")
619 if args.servers_active:
620 log.info("Servers will be set to ACTIVE before cleanup")
621 if args.projects:
622 log.info("Project cleanup is enabled")
623 if args.stacks_alt:
624 log.info(
625 f"Stacks will be cleaned up using additional '{stack_mask}' mask")
626
627 cleanup_stacks(stacks_alt=args.stacks_alt)
Ievgeniia Zadorozhnad70f21c2023-08-09 20:24:38 +0300628 cleanup_load_balancers()
Ievgeniia Zadorozhnac7713ae2024-12-23 20:55:55 +0100629
630 if manila_present:
631 cleanup_shares()
632 cleanup_share_types()
633 cleanup_share_networks()
634
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200635 cleanup_servers()
636 cleanup_flavors()
Ievgeniia Zadorozhnab02617b2024-01-22 23:59:05 +0100637 try: # Skip if cinder-backup service is not enabled
638 cleanup_volume_backups()
639 except openstack.exceptions.ResourceNotFound:
640 pass
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200641 cleanup_snapshots()
642 cleanup_volumes()
643 cleanup_volume_groups()
644 cleanup_volume_group_types()
645 cleanup_volume_types()
646 cleanup_images()
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200647 cleanup_keypairs()
648 cleanup_users()
649 cleanup_roles()
650 cleanup_services()
651 cleanup_regions()
652 cleanup_routers()
653 cleanup_networks()
Ievgeniia Zadorozhna76d639c2025-03-24 22:47:55 +0100654 cleanup_sec_groups()
Ievgeniia Zadorozhnab02617b2024-01-22 23:59:05 +0100655 if object_store_present:
656 cleanup_containers()
Ievgeniia Zadorozhna9600b182023-08-04 17:56:24 +0300657 cleanup_floating_ips()
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200658
659 if args.projects:
660 cleanup_projects()
661
Ievgeniia Zadorozhnaa4ba3e82025-12-12 16:34:05 +0100662 if args.dry_run:
663 msg = "DRY-RUN mode, no cleanup is done"
664 else:
665 msg = "Cleanup is FINISHED"
Dmitriy Kruglovb811e642022-10-06 12:24:33 +0200666 log.info(f"\n{'=' * len(msg)}\n{msg}")