diff --git a/plugins/filter/ocp_compatibility.py b/plugins/filter/ocp_compatibility.py index 9d7c375e3..c84073a54 100644 --- a/plugins/filter/ocp_compatibility.py +++ b/plugins/filter/ocp_compatibility.py @@ -9,6 +9,7 @@ def ocp_compatibility(self, removed_in_release_api, curr_version, junit_ocp_file Parse the deprecated and to-be-deprecated API after the workload installation. ''' from junit_xml import TestCase, TestSuite + from collections import defaultdict def k8s2ocp(k8s_version): ''' @@ -36,10 +37,13 @@ def ocp_to_str(version): # parse the API after the workload installation and write down incompatible OCP versions failed_versions = {k8s2ocp(api['removedInRelease']) for api in removed_in_release_api} - version_to_removed_apis = { - version: {api['name'] for api in removed_in_release_api if k8s2ocp(api['removedInRelease']) == version} - for version in failed_versions - } + version_to_removed_apis = defaultdict(list) + for api in removed_in_release_api: + release = k8s2ocp(api['removedInRelease']) + name = api['name'] + service_accounts = api['serviceAccounts'] + + version_to_removed_apis[release].append((name, service_accounts)) # Find max version in the set of incompatible versions. # If the set is empty, bump the current version. @@ -51,9 +55,14 @@ def ocp_to_str(version): status = 'compatible' while version <= max_version: if version in failed_versions: - deprecated_apis = ", ".join(version_to_removed_apis[version]) - compatibility[version] = status + ", " + deprecated_apis if status != 'compatible' else deprecated_apis - status = deprecated_apis + incompatible_apis = ', '.join( + f"{name} (service accounts: {', '.join(service_accounts)})" + for name, service_accounts in version_to_removed_apis[version] + ) + # making sure to carry the incompatible versions + # from the previous releases + compatibility[version] = status + ", " + incompatible_apis if status != 'compatible' else incompatible_apis + status = incompatible_apis elif status != 'compatible': compatibility[version] = status else: diff --git a/roles/deprecated_api/tasks/get_api_request_counts_per_namespace.yml b/roles/deprecated_api/tasks/get_api_request_counts_per_namespace.yml index d2de0248c..9be0b1c4c 100644 --- a/roles/deprecated_api/tasks/get_api_request_counts_per_namespace.yml +++ b/roles/deprecated_api/tasks/get_api_request_counts_per_namespace.yml @@ -8,13 +8,39 @@ - name: "Extract deprecated and to-be-deprecated API for {{ da_ns }}" vars: - query: "resources[*].{name: metadata.name, removedInRelease: status.removedInRelease}[?removedInRelease != null]" + query: > + resources[?status.removedInRelease != null].{ + name: metadata.name, + removedInRelease: status.removedInRelease, + serviceAccounts: status.last24h[].byNode[].byUser[].username + } ansible.builtin.set_fact: - da_removed_api: "{{ deprecated_api_apirequestcount | json_query(query) | flatten | unique }}" + da_removed_api_dupes: "{{ deprecated_api_apirequestcount | json_query(query) }}" + +- name: "Reset da_removed_api before processing new namespace {{ da_ns }}" + ansible.builtin.set_fact: + da_removed_api: [] + +- name: "Remove duplicates from serviceAccounts for {{ da_ns }}" + ansible.builtin.set_fact: + da_removed_api: >- + {{ + da_removed_api + + [{ + 'name': item.name, + 'removedInRelease': item.removedInRelease, + 'serviceAccounts': item.serviceAccounts | unique + }] | unique(attribute='name') + }} + loop: "{{ da_removed_api_dupes }}" + +- name: "Display cleaned API data for {{ da_ns }}" + ansible.builtin.debug: + var: da_removed_api - name: "Compute OCP compatibility of the workload API for {{ da_ns }}" vars: ocp_filename: "{{ deprecated_api_logs.path }}/apirequestcounts_ocp_compatibility_{{ da_ns }}_junit.xml" - set_fact: + ansible.builtin.set_fact: ocp_compatibility: "{{ da_removed_api | redhatci.ocp.ocp_compatibility(da_ocp_version, ocp_filename) }}" ... diff --git a/tests/unit/data/test_ocp_compatibility_data.json b/tests/unit/data/test_ocp_compatibility_data.json index 11dee42a0..708bad02a 100644 --- a/tests/unit/data/test_ocp_compatibility_data.json +++ b/tests/unit/data/test_ocp_compatibility_data.json @@ -1,10 +1,22 @@ [ - { - "name": "flowschemas.v1beta2.flowcontrol.apiserver.k8s.io", - "removedInRelease": "1.29" - }, - { - "name": "prioritylevelconfigurations.v1beta2.flowcontrol.apiserver.k8s.io", - "removedInRelease": "1.29" - } + { + "name": "events.v1beta1.events.k8s.io", + "removedInRelease": "1.25", + "serviceAccounts": ["system:serviceaccount:default:eventtest-operator-service-account"] + }, + { + "name": "flowschemas.v1beta1.flowcontrol.apiserver.k8s.io", + "removedInRelease": "1.26", + "serviceAccounts": ["system:serviceaccount:openshift-cluster-version:default"] + }, + { + "name": "podsecuritypolicies.v1beta1.policy", + "removedInRelease": "1.25", + "serviceAccounts": ["system:kube-controller-manager"] + }, + { + "name": "prioritylevelconfigurations.v1beta1.flowcontrol.apiserver.k8s.io", + "removedInRelease": "1.26", + "serviceAccounts": ["system:serviceaccount:openshift-cluster-version:default"] + } ] diff --git a/tests/unit/filter/test_ocp_compatibility.py b/tests/unit/filter/test_ocp_compatibility.py index e6fcc2a5a..c5f2a9478 100644 --- a/tests/unit/filter/test_ocp_compatibility.py +++ b/tests/unit/filter/test_ocp_compatibility.py @@ -39,24 +39,34 @@ def test_filter_with_no_deprecated_api_with_empty_array(self): def test_filter_with_deprecated_api_in_non_empty_list(self): filter = ocp_compatibility.FilterModule() - json_file_path = os.path.join(os.path.dirname(__file__), '..', 'data', 'test_ocp_compatibility_data.json') + json_file_path = os.path.join( + os.path.dirname(__file__), '..', 'data', 'test_ocp_compatibility_data.json' + ) with open(json_file_path, 'r') as json_file: json_data = json.load(json_file) with tempfile.TemporaryDirectory() as tmpdirname: actual_result = filter.filters()["ocp_compatibility"]( - json_data, "4.13", os.path.join(tmpdirname, "junit.xml")) - - # The order of elements in a dictionary is not guaranteed in Python. - # Have to sort before comparing to avoid random failures. - actual_result["4.16"] = ", ".join(sorted(actual_result["4.16"].split(", "))) + json_data, "4.11", os.path.join(tmpdirname, "junit.xml") + ) expected_result = { - "4.13": "compatible", - "4.14": "compatible", - "4.15": "compatible", - "4.16": "flowschemas.v1beta2.flowcontrol.apiserver.k8s.io, prioritylevelconfigurations.v1beta2.flowcontrol.apiserver.k8s.io", + "4.11": "compatible", + "4.12": " ".join([ + "events.v1beta1.events.k8s.io (service accounts: system:serviceaccount:default:", + "eventtest-operator-service-account), podsecuritypolicies.v1beta1.policy ", + "(service accounts: system:kube-controller-manager)" + ]), + "4.13": " ".join([ + "events.v1beta1.events.k8s.io (service accounts: system:serviceaccount:default:", + "eventtest-operator-service-account), podsecuritypolicies.v1beta1.policy ", + "(service accounts: system:kube-controller-manager), flowschemas.v1beta1.", + "flowcontrol.apiserver.k8s.io (service accounts: system:serviceaccount:", + "openshift-cluster-version:default), prioritylevelconfigurations.v1beta1.", + "flowcontrol.apiserver.k8s.io (service accounts: system:serviceaccount:", + "openshift-cluster-version:default)" + ]) } self.assertEqual(actual_result, expected_result)