diff --git a/ci/olib.py b/ci/olib.py index 8b68f1d127ec6cf2ca07f7ef0dcc63a2d13a58da..e7040c0d693cadcbe4991453e77b4fd0d3b350f1 100644 --- a/ci/olib.py +++ b/ci/olib.py @@ -748,3 +748,92 @@ def get_server_floating_ip_properties(server): return {} +def compare_and_log_projects_quotas(args, log_prefix, src_connection, src_project_id, dst_connection, dst_project_id): + """ Log quotas comparison for 2 projects. """ + src_quotas = get_project_quotas(src_connection, src_project_id) + dst_quotas = get_project_quotas(dst_connection, dst_project_id) + quota_comparison_dict = { + 0: {"logger": args.logger.info, "comment": "Source and destination project quota equal"}, + 1: {"logger": args.logger.error, "comment": "Source project quota higher"}, + -1: {"logger": args.logger.warn, "comment": "Destination project quota higher"}, + } + for i_quota_resource, i_src_quota in src_quotas.items(): + dst_quota = dst_quotas[i_quota_resource] + comparison_result = compare_quota_values(i_src_quota, dst_quota) + logger_function = quota_comparison_dict[comparison_result]["logger"] + comment = quota_comparison_dict[comparison_result]["comment"] + logger_function(f"{log_prefix} {comment}: {i_quota_resource}, src: {i_src_quota}, dst: {dst_quota}") + + +# Define sets of names of quotas which we want to check explicitly, +# in order to avoid dealing with irrelevant QuotaSet / Quota properties. +quota_resources_compute = [ + "cores", + "fixed_ips", + "injected_file_content_bytes", + "injected_file_path_bytes", + "injected_files", + "instances", + "key_pairs", + "metadata_items", + "ram", + "server_group_members", + "server_groups", +] +quota_resources_volume = [ + "backup_gigabytes", + "backups", + "gigabytes", + "groups", + "per_volume_gigabytes", + "snapshots", + "volumes", +] +quota_resources_network = [ + "floating_ips", + "networks", + "ports", + "rbac_policies", + "routers", + "security_group_rules", + "security_groups", + "subnet_pools", + "subnets", +] + + +def get_project_quotas(ostack_connection: openstack.connection.Connection, project_id): + """ Return all quotas (compute, volume, network) for given project. """ + compute_quotas = ostack_connection.get_compute_quotas(project_id) + volume_quotas = ostack_connection.get_volume_quotas(project_id) + network_quotas = ostack_connection.get_network_quotas(project_id) + project_quotas = {} + project_quotas |= filter_quota_set(quota_resources_compute, compute_quotas) + project_quotas |= filter_quota_set(quota_resources_volume, volume_quotas) + project_quotas |= filter_quota_set(quota_resources_network, network_quotas) + return project_quotas + + +def filter_quota_set(quota_resources, quotas): + """ Return a dictionary of quotas filtered by keys in quota_resources """ + return {i_quota_resource: quotas[i_quota_resource] for i_quota_resource in quota_resources} + + +def compare_quota_values(value_1, value_2): + """ + Return integer representation of comparison of parameters: + value_1 == value_2: return 0 + value_1 > value_2: return 1 + value_1 < value_2: return -1 + + Treats `None` and `-1` values as unlimited, i.e. always bigger than any other limited value. + """ + # treat None as unlimited quota, i.e. -1 + val_1 = -1 if value_1 is None else value_1 + val_2 = -1 if value_2 is None else value_2 + if val_1 == val_2: + return 0 + if val_1 > val_2 or val_1 == -1: + return 1 + if val_1 < val_2 or val_2 == -1: + return -1 diff --git a/ci/project-migrator.py b/ci/project-migrator.py index ccc4d7266d425c216d99b275ac048cd51e9caa26..41a18eb6960fb43a25d0c5845399b1b4160863e5 100755 --- a/ci/project-migrator.py +++ b/ci/project-migrator.py @@ -72,17 +72,11 @@ def main(args): "B.14 Cloud group project migration is executed by authorized person (cloud/openstack team member).", lib.executed_as_admin_user_in_ci()) - - # check user context switching & quotas source_project_conn = lib.get_ostack_connection(source_migrator_openrc | {'OS_PROJECT_NAME': source_project.name}) - #source_project_quotas = source_project_conn.get_compute_quotas(source_project.id) - #lib.log_or_assert(args, f"C.1 Context switching to source OpenStack cloud project succeeded (id:{source_project.id})", - # source_project_quotas and source_project_quotas.id == source_project.id) - destination_project_conn = lib.get_ostack_connection(destination_migrator_openrc | {'OS_PROJECT_NAME': destination_project.name}) - #destination_project_quotas = destination_project_conn.get_compute_quotas(destination_project.id) - #lib.log_or_assert(args, f"C.2 Context switching to destination OpenStack cloud project succeeded (id:{destination_project.id})", - # destination_project_quotas and destination_project_quotas.id == destination_project.id) + + args.logger.info(f"C.01 Source and destination project quotas comparison:") + olib.compare_and_log_projects_quotas(args, "C.01", source_project_conn, source_project.id, destination_project_conn, destination_project.id) # connect to migrator node reply_stdout, reply_stderr, reply_ecode = lib.remote_cmd_exec(args.ceph_migrator_host, args.ceph_migrator_user,