From 2ee4d019e02d76d11b60cc1388c6f67452f72f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Wed, 8 Apr 2026 14:12:17 +0200 Subject: [PATCH 01/34] RHINENG-25147: refactor workspaces in DB --- .../migrations/153_simplify_workspaces.up.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 database_admin/migrations/153_simplify_workspaces.up.sql diff --git a/database_admin/migrations/153_simplify_workspaces.up.sql b/database_admin/migrations/153_simplify_workspaces.up.sql new file mode 100644 index 000000000..b8b60ff61 --- /dev/null +++ b/database_admin/migrations/153_simplify_workspaces.up.sql @@ -0,0 +1,10 @@ +ALTER TABLE system_inventory + ADD COLUMN workspace_id TEXT CHECK (NOT empty(workspace_id)), + ADD COLUMN workspace_name TEXT CHECK (NOT empty(workspace_name)); + +UPDATE system_inventory + SET workspace_id = workspaces->0->>'id', + workspace_name = workspaces->0->>'name'; + +CREATE INDEX IF NOT EXISTS system_inventory_workspace_id_index ON system_inventory (workspace_id); +CREATE INDEX IF NOT EXISTS system_inventory_workspace_name_index ON system_inventory (workspace_name); From 7632358baef60e67740c130cfbe4e1e2c39f53b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Wed, 8 Apr 2026 14:12:17 +0200 Subject: [PATCH 02/34] RHINENG-25147: update create_schema after the refactor --- database_admin/schema/create_schema.sql | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/database_admin/schema/create_schema.sql b/database_admin/schema/create_schema.sql index 28a57e442..960bbe3c0 100644 --- a/database_admin/schema/create_schema.sql +++ b/database_admin/schema/create_schema.sql @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations INSERT INTO schema_migrations -VALUES (152, false); +VALUES (153, false); -- --------------------------------------------------------------------------- -- Functions @@ -593,6 +593,8 @@ CREATE TABLE IF NOT EXISTS system_inventory mssql_workload BOOLEAN NOT NULL DEFAULT false, mssql_workload_version TEXT CHECK (NOT empty(mssql_workload_version)), workspaces JSONB, + workspace_id TEXT CHECK (NOT empty(workspace_id)), + workspace_name TEXT CHECK (NOT empty(workspace_name)), PRIMARY KEY (rh_account_id, id), UNIQUE (rh_account_id, inventory_id) ) PARTITION BY HASH (rh_account_id); @@ -625,6 +627,8 @@ CREATE INDEX IF NOT EXISTS system_inventory_inventory_id_idx ON system_inventory CREATE INDEX IF NOT EXISTS system_inventory_tags_index ON system_inventory USING GIN (tags JSONB_PATH_OPS); CREATE INDEX IF NOT EXISTS system_inventory_stale_timestamp_index ON system_inventory (stale_timestamp); CREATE INDEX IF NOT EXISTS system_inventory_workspaces_index ON system_inventory USING GIN (workspaces); +CREATE INDEX IF NOT EXISTS system_inventory_workspace_id_index ON system_inventory (workspace_id); +CREATE INDEX IF NOT EXISTS system_inventory_workspace_name_index ON system_inventory (workspace_name); CREATE TABLE IF NOT EXISTS deleted_system ( From efc195a33dfff7904a652e87994f17263ab5fcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 9 Apr 2026 17:10:06 +0200 Subject: [PATCH 03/34] RHINENG-25147: update test_data after migration --- dev/test_data.sql | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/dev/test_data.sql b/dev/test_data.sql index c4fb5f544..ea481056f 100644 --- a/dev/test_data.sql +++ b/dev/test_data.sql @@ -24,13 +24,13 @@ INSERT INTO template (id, rh_account_id, uuid, environment_id, name, description (3, 1, '99900000-0000-0000-0000-000000000003', '99900000000000000000000000000003', 'temp3-1', NULL, '{"to_time": "2000-01-01T00:00:00+00:00"}', 'x86_64', '8', 'user3'), (4, 3, '99900000-0000-0000-0000-000000000004', '99900000000000000000000000000004', 'temp4-3', 'desc4', '{"to_time": "2000-01-01T00:00:00+00:00"}', 'x86_64', '8', 'user4'); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload, sap_workload_sids, mssql_workload, mssql_workload_version) VALUES -(1, '00000000-0000-0000-0000-000000000001', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000001', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 10, '8.10', NULL, true, ARRAY['ABC', 'DEF', 'GHI'], false, NULL), -(2, '00000000-0000-0000-0000-000000000002', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000002', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"},{"key": "k3", "value": "val3", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 1, '8.1', NULL, true, ARRAY['ABC'], false, NULL), -(3, '00000000-0000-0000-0000-000000000003', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000003', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}, {"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 1, '8.0', NULL, true, NULL, false, NULL), -(4, '00000000-0000-0000-0000-000000000004', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000004', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 2, '8.3', 'cccccccc-0000-0000-0001-000000000004', true, NULL, false, NULL), -(5, '00000000-0000-0000-0000-000000000005', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000005', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000005', true, NULL, false, NULL), -(6, '00000000-0000-0000-0000-000000000006', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000006', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 7, 3, '7.3', NULL, true, NULL, true, '15.3.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload, sap_workload_sids, mssql_workload, mssql_workload_version) VALUES +(1, '00000000-0000-0000-0000-000000000001', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000001', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 10, '8.10', NULL, true, ARRAY['ABC', 'DEF', 'GHI'], false, NULL), +(2, '00000000-0000-0000-0000-000000000002', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000002', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"},{"key": "k3", "value": "val3", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.1', NULL, true, ARRAY['ABC'], false, NULL), +(3, '00000000-0000-0000-0000-000000000003', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000003', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}, {"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.0', NULL, true, NULL, false, NULL), +(4, '00000000-0000-0000-0000-000000000004', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000004', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', 'cccccccc-0000-0000-0001-000000000004', true, NULL, false, NULL), +(5, '00000000-0000-0000-0000-000000000005', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000005', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000005', true, NULL, false, NULL), +(6, '00000000-0000-0000-0000-000000000006', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000006', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 7, 3, '7.3', NULL, true, NULL, true, '15.3.0'); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party, template_id) VALUES (1, 1, '2018-09-22 12:00:00-04', true , 1), (2, 1, '2018-09-22 12:00:00-04', false, 1), @@ -39,17 +39,17 @@ INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party (5, 1, '2018-09-22 12:00:00-04', false, NULL), (6, 1, '2018-09-22 12:00:00-04', false, NULL); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_updated, unchanged_since, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, rhsm_version, subscription_manager_id, sap_workload, ansible_workload, ansible_workload_controller_version) VALUES -(7, '00000000-0000-0000-0000-000000000007', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-10-04 14:13:12-04', '2018-09-22 12:00:00-04', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000007', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'RHEL', 8, '8.x', 'cccccccc-0000-0000-0001-000000000007', true, true, '1.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_updated, unchanged_since, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, rhsm_version, subscription_manager_id, sap_workload, ansible_workload, ansible_workload_controller_version) VALUES +(7, '00000000-0000-0000-0000-000000000007', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-10-04 14:13:12-04', '2018-09-22 12:00:00-04', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000007', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'inventory-group-2', 'group2', 'RHEL', 8, '8.x', 'cccccccc-0000-0000-0001-000000000007', true, true, '1.0'); INSERT INTO system_patch (system_id, rh_account_id) VALUES (7, 1); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES -( 8, '00000000-0000-0000-0000-000000000008', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000008', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000008', true), -( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'RHEL', 8, 1, '8.1', NULL, true), -(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'RHEL', 8, 2, '8.2', NULL, true), -(11, '00000000-0000-0000-0000-000000000011', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000011', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 3, '8.3', NULL, true), -(12, '00000000-0000-0000-0000-000000000012', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000012', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 1, '8.1', NULL, true); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES +( 8, '00000000-0000-0000-0000-000000000008', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000008', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'inventory-group-2', 'group2', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000008', true), +( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, NULL, NULL, 'RHEL', 8, 1, '8.1', NULL, true), +(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, NULL, NULL, 'RHEL', 8, 2, '8.2', NULL, true), +(11, '00000000-0000-0000-0000-000000000011', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000011', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 3, '8.3', NULL, true), +(12, '00000000-0000-0000-0000-000000000012', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000012', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed, packages_installable, packages_applicable) VALUES ( 8, 1, '2018-09-22 12:00:00-04', 0, 0, 0), ( 9, 2, '2018-09-22 12:00:00-04', 0, 0, 0), @@ -57,24 +57,24 @@ INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_in (11, 2, '2018-09-22 12:00:00-04', 0, 0, 0), (12, 3, '2018-09-22 12:00:00-04', 2, 2, 2); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, yum_updates, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, os_minor, rhsm_version, sap_workload) VALUES -(13, '00000000-0000-0000-0000-000000000013', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000013', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 2, '8.2', true), -(14, '00000000-0000-0000-0000-000000000014', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000014', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 3, NULL, true), -(15, '00000000-0000-0000-0000-000000000015', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000015', '{"update_list": {"suricata-0:6.0.3-2.fc35.i686": {"available_updates": [{"erratum": "RHSA-2021:3801", "basearch": "i686", "releasever": "ser1", "repository": "group_oisf:suricata-6.0", "package": "suricata-0:6.0.4-2.fc35.i686"}]}}, "basearch": "i686", "releasever": "ser1"}', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 1, '8.1', false); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, yum_updates, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, sap_workload) VALUES +(13, '00000000-0000-0000-0000-000000000013', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000013', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', true), +(14, '00000000-0000-0000-0000-000000000014', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000014', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 3, NULL, true), +(15, '00000000-0000-0000-0000-000000000015', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000015', '{"update_list": {"suricata-0:6.0.3-2.fc35.i686": {"available_updates": [{"erratum": "RHSA-2021:3801", "basearch": "i686", "releasever": "ser1", "repository": "group_oisf:suricata-6.0", "package": "suricata-0:6.0.4-2.fc35.i686"}]}}, "basearch": "i686", "releasever": "ser1"}', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', false); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed) VALUES (13, 3, '2018-09-22 12:00:00-04', 1), (14, 3, '2018-09-22 12:00:00-04', 0), (15, 3, '2018-09-22 12:00:00-04', 0); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, os_minor, rhsm_version, ansible_workload, ansible_workload_controller_version, mssql_workload, mssql_workload_version) VALUES -(16, '00000000-0000-0000-0000-000000000016', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000016', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 2, '8.2', false, NULL, false, NULL), -(17, '00000000-0000-0000-0000-000000000017', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000017', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'RHEL', 8, 1, '8.1', true, '1.0', true, '15.3.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, ansible_workload, ansible_workload_controller_version, mssql_workload, mssql_workload_version) VALUES +(16, '00000000-0000-0000-0000-000000000016', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000016', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', false, NULL, false, NULL), +(17, '00000000-0000-0000-0000-000000000017', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000017', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', true, '1.0', true, '15.3.0'); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed, packages_installable, packages_applicable, template_id) VALUES (16, 3, '2018-09-22 12:00:00-04', 1, 1, 1, 4), (17, 1, '2018-09-22 12:00:00-04', 2, 2, 2, NULL); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES -(18, '00000000-0000-0000-0000-000000000018', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000018', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'RHEL', 8, 2, '8.3', '99999999-9999-9999-9999-999999999404', true); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES +(18, '00000000-0000-0000-0000-000000000018', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000018', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', '99999999-9999-9999-9999-999999999404', true); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party) VALUES (18, 1, '2018-09-22 12:00:00-04', true); From ac28fbb6bbd1ef5e2177ba36443fb462fa69cc51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 21 Apr 2026 13:16:54 +0200 Subject: [PATCH 04/34] RHINENG-25147: add SystemWorkspaces --- manager/controllers/advisory_systems.go | 1 + manager/controllers/common_attributes.go | 5 +++++ manager/controllers/package_systems.go | 1 + manager/controllers/systems.go | 1 + manager/controllers/template_systems.go | 1 + 5 files changed, 9 insertions(+) diff --git a/manager/controllers/advisory_systems.go b/manager/controllers/advisory_systems.go index d85a2f5c5..d2f58944d 100644 --- a/manager/controllers/advisory_systems.go +++ b/manager/controllers/advisory_systems.go @@ -41,6 +41,7 @@ type AdvisorySystemItemAttributes struct { SystemTimestamps SystemTags SystemGroups + SystemWorkspace BaselineIDAttr BaselineNameAttr TemplateAttibutes diff --git a/manager/controllers/common_attributes.go b/manager/controllers/common_attributes.go index 964ead642..ad5302e01 100644 --- a/manager/controllers/common_attributes.go +++ b/manager/controllers/common_attributes.go @@ -28,6 +28,11 @@ type SystemGroups struct { Groups SystemGroupsList `json:"groups" csv:"groups" query:"si.workspaces" gorm:"column:groups" order_query:"si.workspaces->0->>'name'"` } +type SystemWorkspace struct { + WorkspaceID *string `json:"workspace_id" csv:"workspace_id" query:"si.workspace_id" gorm:"column:workspace_id"` + WorkspaceName *string `json:"workspace_name" csv:"workspace_name" query:"si.workspace_name" gorm:"column:workspace_name"` +} + // baseline attributes are obsoleted and we keep them only for backward API compatibility // now they always return default value type BaselineAttributes struct { diff --git a/manager/controllers/package_systems.go b/manager/controllers/package_systems.go index c948e2242..e6171c08b 100644 --- a/manager/controllers/package_systems.go +++ b/manager/controllers/package_systems.go @@ -40,6 +40,7 @@ type PackageSystemItem struct { OSAttributes UpdateStatus string `json:"update_status" csv:"update_status" query:"CASE WHEN spkg.installable_id is not null THEN 'Installable' WHEN spkg.applicable_id is not null THEN 'Applicable' ELSE 'None' END" gorm:"column:update_status"` SystemGroups + SystemWorkspace } type PackageSystemDBLookup struct { diff --git a/manager/controllers/systems.go b/manager/controllers/systems.go index 097541022..6bc85713a 100644 --- a/manager/controllers/systems.go +++ b/manager/controllers/systems.go @@ -95,6 +95,7 @@ type SystemItemAttributes struct { BaselineIDAttr TemplateAttibutes SystemGroups + SystemWorkspace SystemArch } diff --git a/manager/controllers/template_systems.go b/manager/controllers/template_systems.go index 83d243275..bd076fac7 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -36,6 +36,7 @@ type TemplateSystemAttributes struct { ApplicableAdvisories SystemTags SystemGroups + SystemWorkspace SystemLastUpload } From 10b75d8199108603ef1784c4ae0f88bfce633ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 21 Apr 2026 13:21:06 +0200 Subject: [PATCH 05/34] RHINENG-25147: update columns in export tests --- manager/controllers/advisory_systems_export_test.go | 5 +++-- manager/controllers/package_systems_export_test.go | 7 ++++--- manager/controllers/systems_export_test.go | 4 ++-- manager/controllers/template_systems_export_test.go | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/manager/controllers/advisory_systems_export_test.go b/manager/controllers/advisory_systems_export_test.go index 8804e8b9e..6ec2934be 100644 --- a/manager/controllers/advisory_systems_export_test.go +++ b/manager/controllers/advisory_systems_export_test.go @@ -32,12 +32,13 @@ func TestAdvisorySystemsExportCSV(t *testing.T) { assert.Equal(t, 8, len(lines)) assert.Equal(t, "display_name,last_upload,stale,os,rhsm,stale_timestamp,stale_warning_timestamp,culled_timestamp,created,tags,"+ - "groups,baseline_id,baseline_name,template_name,template_uuid,status,satellite_managed,built_pkgcache,id", lines[0]) + "groups,workspace_id,workspace_name,baseline_id,baseline_name,template_name,template_uuid,status,"+ + "satellite_managed,built_pkgcache,id", lines[0]) assert.Equal(t, "00000000-0000-0000-0000-000000000001,2020-09-22T16:00:00Z,false,RHEL 8.10,8.10,2018-08-26T16:00:00Z,"+ "2018-09-02T16:00:00Z,,2018-08-26T16:00:00Z,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ "{'key':'k2','namespace':'ns1','value':'val2'}]\",\"[{'id':'inventory-group-1','name':'group1'}]\","+ - "0,,temp1-1,99900000-0000-0000-0000-000000000001,Installable,false,false,"+ + "inventory-group-1,group1,0,,temp1-1,99900000-0000-0000-0000-000000000001,Installable,false,false,"+ "00000000-0000-0000-0000-000000000001", lines[1]) } diff --git a/manager/controllers/package_systems_export_test.go b/manager/controllers/package_systems_export_test.go index acfc52af1..d588f91b8 100644 --- a/manager/controllers/package_systems_export_test.go +++ b/manager/controllers/package_systems_export_test.go @@ -38,14 +38,15 @@ func TestPackageSystemsExportHandlerCSV(t *testing.T) { assert.Equal(t, 5, len(lines)) assert.Equal(t, "id,display_name,installed_evra,available_evra,updatable,tags,"+ "baseline_name,baseline_uptodate,template_name,template_uuid,satellite_managed,baseline_id,os,rhsm,"+ - "update_status,groups", lines[0]) + "update_status,groups,workspace_id,workspace_name", lines[0]) assert.Equal(t, "00000000-0000-0000-0000-000000000012,00000000-0000-0000-0000-000000000012,"+ "5.6.13-200.fc31.x86_64,5.6.13-201.fc31.x86_64,true,"+ - "\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,false,0,RHEL 8.1,8.1,Installable,[]", + "\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,false,0,RHEL 8.1,8.1,Installable,[],"+ + "root-workspace,root-ws", lines[1]) assert.Equal(t, "00000000-0000-0000-0000-000000000013,00000000-0000-0000-0000-000000000013,"+ "5.6.13-200.fc31.x86_64,,false,\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,"+ - "false,0,RHEL 8.2,8.2,None,[]", lines[2]) + "false,0,RHEL 8.2,8.2,None,[],root-workspace,root-ws", lines[2]) } func TestPackageSystemsExportInvalidName(t *testing.T) { diff --git a/manager/controllers/systems_export_test.go b/manager/controllers/systems_export_test.go index ae99a7cc6..5e3080eb7 100644 --- a/manager/controllers/systems_export_test.go +++ b/manager/controllers/systems_export_test.go @@ -18,7 +18,7 @@ var SystemCsvHeader = "id,display_name,os,rhsm,tags,last_evaluation," + "satellite_managed,built_pkgcache,packages_installable,packages_applicable," + "installable_rhsa_count,installable_rhba_count,installable_rhea_count,installable_other_count," + "applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count,applicable_other_count," + - "baseline_id,template_name,template_uuid,groups,arch" + "baseline_id,template_name,template_uuid,groups,workspace_id,workspace_name,arch" func makeRequest(t *testing.T, path string, contentType string) *httptest.ResponseRecorder { core.SetupTest(t) @@ -60,7 +60,7 @@ func TestSystemsExportCSV(t *testing.T) { "2018-09-22T16:00:00Z,2,2,1,0,0,,"+ "2020-09-22T16:00:00Z,2018-08-26T16:00:00Z,2018-09-02T16:00:00Z,,2018-08-26T16:00:00Z,"+ "false,false,false,0,0,2,2,1,0,2,3,3,3,0,temp1-1,99900000-0000-0000-0000-000000000001,"+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",x86_64", + "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,x86_64", lines[1]) } diff --git a/manager/controllers/template_systems_export_test.go b/manager/controllers/template_systems_export_test.go index 0d3a312f3..51bd83f12 100644 --- a/manager/controllers/template_systems_export_test.go +++ b/manager/controllers/template_systems_export_test.go @@ -14,7 +14,7 @@ import ( var TemplateCsvHeader = "id,display_name,os,rhsm," + "installable_rhsa_count,installable_rhba_count,installable_rhea_count,installable_other_count," + "applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count,applicable_other_count," + - "tags,groups,last_upload" + "tags,groups,workspace_id,workspace_name,last_upload" // nolint: dupl func TestTemplateSystemsExportJSON(t *testing.T) { @@ -68,12 +68,12 @@ func TestTemplateSystemsExportCSV(t *testing.T) { assert.Equal(t, "00000000-0000-0000-0000-000000000002,00000000-0000-0000-0000-000000000002,RHEL 8.1,"+ "8.1,0,0,0,0,0,0,1,0,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ "{'key':'k2','namespace':'ns1','value':'val2'},{'key':'k3','namespace':'ns1','value':'val3'}]\","+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",2018-09-22T16:00:00Z", + "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,2018-09-22T16:00:00Z", lines[1]) assert.Equal(t, "00000000-0000-0000-0000-000000000001,00000000-0000-0000-0000-000000000001,RHEL 8.10,"+ "8.10,2,2,1,0,2,3,3,0,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ "{'key':'k2','namespace':'ns1','value':'val2'}]\","+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",2020-09-22T16:00:00Z", + "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,2020-09-22T16:00:00Z", lines[2]) } From 5a06feaa24a5ca9b1739ec66aaae14d5aa01539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 21 Apr 2026 16:38:19 +0200 Subject: [PATCH 06/34] RHINENG-25147: set invenotry workspaces in context --- base/utils/gin.go | 17 +++++++++-------- manager/middlewares/kessel.go | 12 ++++++++++++ manager/middlewares/kessel_test.go | 7 +++++++ manager/middlewares/rbac.go | 30 +++++++++++++++++++++++------- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/base/utils/gin.go b/base/utils/gin.go index 73e622384..cdb1686cd 100644 --- a/base/utils/gin.go +++ b/base/utils/gin.go @@ -13,14 +13,15 @@ import ( ) const ( - KeyApiver = "apiver" - KeyAccount = "account" - KeyOrgID = "org_id" - KeyUser = "user" - KeySystem = "system_cn" - KeyInventoryGroups = "inventoryGroups" - KeyGrouped = "grouped" - KeyUngrouped = "ungrouped" + KeyApiver = "apiver" + KeyAccount = "account" + KeyOrgID = "org_id" + KeyUser = "user" + KeySystem = "system_cn" + KeyInventoryGroups = "inventoryGroups" + KeyGrouped = "grouped" + KeyUngrouped = "ungrouped" + KeyInventoryWorkspaces = "workspaceIDs" // ReadHeaderTimeout same as nginx default ReadHeaderTimeout = 60 * time.Second ) diff --git a/manager/middlewares/kessel.go b/manager/middlewares/kessel.go index 6c71ec00b..08fa4e96e 100644 --- a/manager/middlewares/kessel.go +++ b/manager/middlewares/kessel.go @@ -142,6 +142,18 @@ func hasPermissionKessel(c *gin.Context) { return } + workspaceIDs := make([]string, 0, len(workspaces)) + for _, workspace := range workspaces { + workspaceIDs = append(workspaceIDs, workspace.Object.ResourceId) + } + + if len(workspaceIDs) == 0 { + utils.LogWarn(errors.New("no workspaces found")) + c.AbortWithStatusJSON(http.StatusUnauthorized, utils.ErrorResponse{Error: "Missing permission"}) + return + } + c.Set(utils.KeyInventoryWorkspaces, workspaceIDs) + inventoryGroups, err := processWorkspaces(workspaces) if err != nil { utils.LogWarn(err.Error()) diff --git a/manager/middlewares/kessel_test.go b/manager/middlewares/kessel_test.go index b70da7a9e..fd7c58931 100644 --- a/manager/middlewares/kessel_test.go +++ b/manager/middlewares/kessel_test.go @@ -114,6 +114,13 @@ func TestHasPermissionKessel(t *testing.T) { inventoryGroupMap, ok := (inventoryGroups).(map[string]string) require.True(t, ok) assert.Equal(t, `{"[{\"id\":\"inventory-group-1\"}]"}`, inventoryGroupMap[utils.KeyGrouped]) + + workspaces, found := c.Get(utils.KeyInventoryWorkspaces) + require.True(t, found) + workspaceIDs, ok := (workspaces).([]string) + require.True(t, ok) + require.Greater(t, len(workspaceIDs), 0) + assert.Equal(t, "inventory-group-1", workspaceIDs[0]) } func mockXRHID(userType string) *identity.XRHID { diff --git a/manager/middlewares/rbac.go b/manager/middlewares/rbac.go index 7232aff9d..25d9ff3b0 100644 --- a/manager/middlewares/rbac.go +++ b/manager/middlewares/rbac.go @@ -122,15 +122,31 @@ func isAccessGranted(c *gin.Context) bool { handlerName := nameSplitted[len(nameSplitted)-1] granted := checkPermissions(&access, handlerName, c.Request.Method) - if granted { - // collect inventory groups - groups, err := findInventoryGroups(&access) - if err != nil { - utils.LogError("err", err.Error(), "RBAC") - granted = false + if !granted { + return granted + } + // collect inventory groups + groups, err := findInventoryGroups(&access) + if err != nil { + utils.LogError("err", err.Error(), "RBAC") + granted = false + } + c.Set(utils.KeyInventoryGroups, groups) + + workspaceIDs := make([]string, 0) + for _, a := range access.Data { + for _, rd := range a.ResourceDefinitions { + for _, v := range rd.AttributeFilter.Value { + if v == nil { + // TODO: use root ws + } else { + workspaceIDs = append(workspaceIDs, *v) + } + } } - c.Set(utils.KeyInventoryGroups, groups) } + c.Set(utils.KeyInventoryWorkspaces, workspaceIDs) + return granted } From e41cfdf1e4e0bab3b152768a1fd04127e5cdeef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Wed, 22 Apr 2026 13:25:19 +0200 Subject: [PATCH 07/34] RHINENG-25147: replace groups with workspaces: PostSystemsAdvisories --- base/database/utils.go | 7 +++++++ manager/controllers/systems_advisories_view.go | 9 +++++---- .../systems_advisories_view_test.go | 18 ++++++++++++------ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index 044d6b676..67673963d 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -240,6 +240,13 @@ func ReadReplicaConfigured() bool { return len(utils.CoreCfg.DBReadReplicaHost) > 0 && utils.CoreCfg.DBReadReplicaPort != 0 } +func ApplyInventoryWorkspaceFilter2(tx *gorm.DB, workspaceIDs []string) *gorm.DB { + if len(workspaceIDs) == 0 { + utils.LogWarn("there should always be some workspaces, at least root workspace") + } + return tx.Where("si.workspace_id IN (?)", workspaceIDs) +} + func ApplyInventoryWorkspaceFilter(tx *gorm.DB, groups map[string]string) *gorm.DB { if _, ok := groups[utils.KeyGrouped]; !ok { if _, ok := groups[utils.KeyUngrouped]; ok { diff --git a/manager/controllers/systems_advisories_view.go b/manager/controllers/systems_advisories_view.go index 7c4b4f885..9024d7847 100644 --- a/manager/controllers/systems_advisories_view.go +++ b/manager/controllers/systems_advisories_view.go @@ -72,14 +72,14 @@ func totalItems(tx *gorm.DB, cols string) (int, error) { return int(count), err } -func systemsAdvisoriesQuery(c *gin.Context, db *gorm.DB, acc int, groups map[string]string, +func systemsAdvisoriesQuery(c *gin.Context, db *gorm.DB, acc int, workspaceIDs []string, req SystemsAdvisoriesRequest) (*gorm.DB, *ListMeta, *Links, error) { systems := req.Systems advisories := req.Advisories - sysq := database.ApplyInventoryWorkspaceFilter( + sysq := database.ApplyInventoryWorkspaceFilter2( db.Table("system_inventory si"). Where("si.rh_account_id = ?", acc), - groups). + workspaceIDs). Distinct("si.rh_account_id, si.id, si.inventory_id"). // we need to join system_advisories to make `limit` work properly // without this join it can happen that we display less items on some pages @@ -181,6 +181,7 @@ func queryDB(c *gin.Context, endpoint string) ([]systemsAdvisoriesDBLoad, *ListM } acc := c.GetInt(utils.KeyAccount) groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) // backward compatibility, put limit/offset from json into querystring if req.Limit != nil { @@ -191,7 +192,7 @@ func queryDB(c *gin.Context, endpoint string) ([]systemsAdvisoriesDBLoad, *ListM } switch endpoint { case "SystemsAdvisories": - q, meta, links, err = systemsAdvisoriesQuery(c, db, acc, groups, req) + q, meta, links, err = systemsAdvisoriesQuery(c, db, acc, workspaceIDs, req) case "AdvisoriesSystems": q, meta, links, err = advisoriesSystemsQuery(c, db, acc, groups, req) default: diff --git a/manager/controllers/systems_advisories_view_test.go b/manager/controllers/systems_advisories_view_test.go index 6ac238d04..89223b7b6 100644 --- a/manager/controllers/systems_advisories_view_test.go +++ b/manager/controllers/systems_advisories_view_test.go @@ -13,7 +13,13 @@ import ( "github.com/stretchr/testify/assert" ) -func doTestView(t *testing.T, handler gin.HandlerFunc, q string, limit, offset *int) *httptest.ResponseRecorder { +var c = core.ContextKV{ + Key: utils.KeyInventoryWorkspaces, + Value: []string{"root-workspace", "inventory-group-1", "inventory-group-2"}, +} + +func doTestView(t *testing.T, handler gin.HandlerFunc, q string, limit, offset *int, contextKVs ...core.ContextKV, +) *httptest.ResponseRecorder { core.SetupTest(t) body := SystemsAdvisoriesRequest{ Systems: []SystemID{"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002"}, @@ -26,12 +32,12 @@ func doTestView(t *testing.T, handler gin.HandlerFunc, q string, limit, offset * panic(err) } - w := CreateRequestRouterWithParams("POST", "/", "", q, bytes.NewBuffer(bodyJSON), "", handler, 1) + w := CreateRequestRouterWithParams("POST", "/", "", q, bytes.NewBuffer(bodyJSON), "", handler, 1, contextKVs...) return w } func TestSystemsAdvisoriesView(t *testing.T) { - w := doTestView(t, PostSystemsAdvisories, "", nil, nil) + w := doTestView(t, PostSystemsAdvisories, "", nil, nil, c) var output SystemsAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][0], AdvisoryName("RH-1")) @@ -48,7 +54,7 @@ func TestAdvisoriesSystemsView(t *testing.T) { } func TestSystemsAdvisoriesViewTags(t *testing.T) { - w := doTestView(t, PostSystemsAdvisories, "?filter[system_profile][sap_sids]=DEF", nil, nil) + w := doTestView(t, PostSystemsAdvisories, "?filter[system_profile][sap_sids]=DEF", nil, nil, c) var output SystemsAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][0], AdvisoryName("RH-1")) @@ -65,7 +71,7 @@ func TestAdvisoriesSystemsViewTags(t *testing.T) { func TestSystemAdvisoriesViewOffsetLimit(t *testing.T) { limit := 3 offset := 0 - w := doTestView(t, PostSystemsAdvisories, "", &limit, &offset) + w := doTestView(t, PostSystemsAdvisories, "", &limit, &offset, c) var output SystemsAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, 2, len(output.Data)) @@ -78,7 +84,7 @@ func TestSystemAdvisoriesViewOffsetLimit(t *testing.T) { func TestSystemAdvisoriesViewOffsetOverflow(t *testing.T) { limit := 1 offset := 100 - w := doTestView(t, PostSystemsAdvisories, "", &limit, &offset) + w := doTestView(t, PostSystemsAdvisories, "", &limit, &offset, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) assert.Equal(t, InvalidOffsetMsg, errResp.Error) From e9a3c76871f40ae342a93eab65fbd9fa6d8fb42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Wed, 22 Apr 2026 17:53:20 +0200 Subject: [PATCH 08/34] RHINENG-25147: replace groups with workspaces: database.Systems() --- base/database/utils.go | 8 ++++++++ manager/controllers/utils_test.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/base/database/utils.go b/base/database/utils.go index 67673963d..9ec0340e7 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -34,6 +34,14 @@ func Systems(tx *gorm.DB, accountID int, groups map[string]string, joins ...join return ApplyInventoryWorkspaceFilter(tx, groups) } +func Systems2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { + tx = tx.Table("system_inventory si"). + Joins("JOIN system_patch spatch ON si.id = spatch.system_id AND si.rh_account_id = spatch.rh_account_id"). + Where("si.rh_account_id = ?", accountID) + tx = (joinsT)(joins).apply(tx) + return ApplyInventoryWorkspaceFilter2(tx, workspaceIDs) +} + func SystemAdvisories(tx *gorm.DB, accountID int, groups map[string]string, joins ...join) *gorm.DB { tx = Systems(tx, accountID, groups). Joins("JOIN system_advisories sa on sa.system_id = si.id AND sa.rh_account_id = ?", accountID) diff --git a/manager/controllers/utils_test.go b/manager/controllers/utils_test.go index 8be6e427d..39dadc955 100644 --- a/manager/controllers/utils_test.go +++ b/manager/controllers/utils_test.go @@ -32,6 +32,17 @@ func TestGroupNameFilter(t *testing.T) { assert.Equal(t, 2, len(systems)) // 2 systems with `group2` in test_data assert.Equal(t, "00000000-0000-0000-0000-000000000007", systems[0].ID) assert.Equal(t, "00000000-0000-0000-0000-000000000008", systems[1].ID) + + // ensure the workspaces work the same as groups + var systems2 []SystemsID + workspaceIDs := []string{"inventory-group-1", "inventory-group-2"} + ty := database.Systems2(database.DB, 1, workspaceIDs) + ty, _ = ApplyInventoryFilter(filters, ty, "si.inventory_id") + ty.Scan(&systems2) + + assert.Equal(t, 2, len(systems2)) + assert.Equal(t, "00000000-0000-0000-0000-000000000007", systems2[0].ID) + assert.Equal(t, "00000000-0000-0000-0000-000000000008", systems2[1].ID) } func TestGroupNameFilter2(t *testing.T) { @@ -53,4 +64,13 @@ func TestGroupNameFilter2(t *testing.T) { tx.Scan(&systems) assert.Equal(t, 9, len(systems)) // 2 systems with `group2`, 6 with `group1` in test_data + + // ensure the workspaces work the same as groups + var systems2 []SystemsID + workspaceIDs := []string{"inventory-group-1", "inventory-group-2"} + ty := database.Systems2(database.DB, 1, workspaceIDs) + ty, _ = ApplyInventoryFilter(filters, ty, "si.inventory_id") + ty.Scan(&systems2) + + assert.Equal(t, 9, len(systems2)) } From ed5f74d99ef0a6c107981777223d93f0de55135a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 11:58:40 +0200 Subject: [PATCH 09/34] RHINENG-25146: replace groups with workspaces: PackagesExportHandler, PackagesListHandler --- manager/controllers/advisories_test.go | 6 +++--- manager/controllers/packages.go | 17 ++++++++++------- manager/controllers/packages_export.go | 6 +++--- manager/controllers/packages_export_test.go | 4 ++-- manager/controllers/packages_test.go | 6 +++--- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/manager/controllers/advisories_test.go b/manager/controllers/advisories_test.go index 4c10882b0..2ccc43f09 100644 --- a/manager/controllers/advisories_test.go +++ b/manager/controllers/advisories_test.go @@ -335,16 +335,16 @@ func TestListAdvisoriesTagsInvalid(t *testing.T) { assert.Equal(t, fmt.Sprintf(InvalidTagMsg, "invalidTag"), errResp.Error) } -func doTestWrongOffset(t *testing.T, path, param, q string, handler gin.HandlerFunc) { +func doTestWrongOffset(t *testing.T, path, param, q string, handler gin.HandlerFunc, contextKVs ...core.ContextKV) { core.SetupTest(t) - w := CreateRequestRouterWithParams("GET", path, param, q, nil, "", handler, 3) + w := CreateRequestRouterWithParams("GET", path, param, q, nil, "", handler, 3, contextKVs...) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) assert.Equal(t, InvalidOffsetMsg, errResp.Error) } func TestAdvisoriesWrongOffset(t *testing.T) { - doTestWrongOffset(t, "/", "", "?offset=1000", AdvisoriesListHandler) + doTestWrongOffset(t, "/", "", "?offset=1000", AdvisoriesListHandler, c) } func TestAdvisoryTagsInMetadata(t *testing.T) { diff --git a/manager/controllers/packages.go b/manager/controllers/packages.go index 59b8b8eea..d05457cf9 100644 --- a/manager/controllers/packages.go +++ b/manager/controllers/packages.go @@ -54,7 +54,7 @@ type queryItem struct { var queryItemSelect = database.MustGetSelect(&queryItem{}) -func packagesQuery(db *gorm.DB, filters map[string]FilterData, acc int, groups map[string]string, +func packagesQuery(db *gorm.DB, filters map[string]FilterData, acc int, workspaceIDs []string, useCache bool) *gorm.DB { if useCache { middlewares.PackageAccountDataCnt.WithLabelValues("hit").Inc() @@ -65,7 +65,7 @@ func packagesQuery(db *gorm.DB, filters map[string]FilterData, acc int, groups m return q } middlewares.PackageAccountDataCnt.WithLabelValues("miss").Inc() - systemsWithPkgsInstalledQ := database.Systems(db, acc, groups). + systemsWithPkgsInstalledQ := database.Systems2(db, acc, workspaceIDs). Select("si.id"). Where("si.stale = false AND spatch.packages_installed > 0") @@ -114,7 +114,7 @@ func packagesQuery(db *gorm.DB, filters map[string]FilterData, acc int, groups m func PackagesListHandler(c *gin.Context) { var filters map[string]FilterData account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) filters, err := ParseAllFilters(c, PackagesOpts) if err != nil { @@ -122,13 +122,13 @@ func PackagesListHandler(c *gin.Context) { } db := middlewares.DBFromContext(c) - useCache := shouldUseCache(db, account, filters, groups) + useCache := shouldUseCache(db, account, filters, workspaceIDs) if !useCache { db.Exec("SET work_mem TO '?'", utils.CoreCfg.DBWorkMem) defer db.Exec("RESET work_mem") } - query := packagesQuery(db, filters, account, groups, useCache) + query := packagesQuery(db, filters, account, workspaceIDs, useCache) query, meta, params, err := ListCommon(query, c, filters, PackagesOpts) if err != nil { return @@ -167,11 +167,14 @@ func PackageDBLookup2Item(packages []PackageDBLookup) ([]PackageItem, int) { } // use cache only when tag filter is not used, there are no inventory groups and cache is valid -func shouldUseCache(db *gorm.DB, acc int, filters map[string]FilterData, groups map[string]string) bool { +func shouldUseCache(db *gorm.DB, acc int, filters map[string]FilterData, workspaceIDs []string) bool { + // TODO: remove this function, it does not make sense since replacing groups with workspaces, + // because there is always at least the root workspace + if !config.EnabledPackageCache { return false } - if HasInventoryFilter(filters) || len(groups) != 0 { + if HasInventoryFilter(filters) || len(workspaceIDs) != 0 { return false } diff --git a/manager/controllers/packages_export.go b/manager/controllers/packages_export.go index 43c6f607b..e027af7b0 100644 --- a/manager/controllers/packages_export.go +++ b/manager/controllers/packages_export.go @@ -27,19 +27,19 @@ import ( // @Router /export/packages [get] func PackagesExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) filters, err := ParseAllFilters(c, PackagesOpts) if err != nil { return } db := middlewares.DBFromContext(c) - useCache := shouldUseCache(db, account, filters, groups) + useCache := shouldUseCache(db, account, filters, workspaceIDs) if !useCache { db.Exec("SET work_mem TO '?'", utils.CoreCfg.DBWorkMem) defer db.Exec("RESET work_mem") } - query := packagesQuery(db, filters, account, groups, useCache) + query := packagesQuery(db, filters, account, workspaceIDs, useCache) query, err = ExportListCommon(query, c, PackagesOpts) var data []PackageDBLookup diff --git a/manager/controllers/packages_export_test.go b/manager/controllers/packages_export_test.go index 5b559ef2f..fb121a084 100644 --- a/manager/controllers/packages_export_test.go +++ b/manager/controllers/packages_export_test.go @@ -12,7 +12,7 @@ import ( func TestPackageExportJSON(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithParams("GET", "/", "", "", nil, "application/json", PackagesExportHandler, 3) + w := CreateRequestRouterWithParams("GET", "/", "", "", nil, "application/json", PackagesExportHandler, 3, c) var output []PackageItem CheckResponse(t, w, http.StatusOK, &output) @@ -30,7 +30,7 @@ func TestPackageExportJSON(t *testing.T) { func TestPackageExportCSV(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithParams("GET", "/", "", "", nil, "text/csv", PackagesExportHandler, 3) + w := CreateRequestRouterWithParams("GET", "/", "", "", nil, "text/csv", PackagesExportHandler, 3, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() diff --git a/manager/controllers/packages_test.go b/manager/controllers/packages_test.go index cec81cf3d..ae2b80f3d 100644 --- a/manager/controllers/packages_test.go +++ b/manager/controllers/packages_test.go @@ -12,7 +12,7 @@ import ( func doTestPackagesBytes(t *testing.T, q string) (resp []byte, status int) { core.SetupTest(t) - w := CreateRequestRouterWithParams("GET", "/", "", q, nil, "", PackagesListHandler, 3) + w := CreateRequestRouterWithParams("GET", "/", "", q, nil, "", PackagesListHandler, 3, c) return w.Body.Bytes(), w.Code } @@ -75,7 +75,7 @@ func TestSearchPackages(t *testing.T) { func TestPackageTagsInvalid(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/", "", "?tags=ns1/k3=val4&tags=invalidTag", nil, "", - PackagesListHandler, 3) + PackagesListHandler, 3, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -89,7 +89,7 @@ func TestPackagesWrongOffset(t *testing.T) { func TestPackageTagsInMetadata(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/", "", "?tags=ns1/k3=val4&tags=ns1/k1=val1", nil, "", - PackagesListHandler, 3) + PackagesListHandler, 3, c) var output PackagesResponse CheckResponse(t, w, http.StatusOK, &output) From 4f4771a17ca6ccc2b97633e11c4956ae4595ded5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 12:19:30 +0200 Subject: [PATCH 10/34] RHINENG-25147: replace groups with workspaces: SystemDetailHandler, SystemVmaasJSONHandler, SystemYumUpdatesHandler --- manager/controllers/system_detail.go | 8 ++++---- manager/controllers/system_detail_test.go | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/manager/controllers/system_detail.go b/manager/controllers/system_detail.go index faa78bfb8..5cf3a10fe 100644 --- a/manager/controllers/system_detail.go +++ b/manager/controllers/system_detail.go @@ -44,7 +44,7 @@ type SystemYumUpdatesResponse struct { // @Router /systems/{inventory_id} [get] func SystemDetailHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -63,7 +63,7 @@ func SystemDetailHandler(c *gin.Context) { var systemDetail SystemDetailLookup db := middlewares.DBFromContext(c) - query := database.Systems(db, account, groups, database.JoinTemplates). + query := database.Systems2(db, account, workspaceIDs, database.JoinTemplates). Select(database.MustGetSelect(&systemDetail)). Where("si.inventory_id = ?::uuid", inventoryID) @@ -154,7 +154,7 @@ func SystemYumUpdatesHandler(c *gin.Context) { func systemJSONsCommon(c *gin.Context, column string) *models.SystemInventory { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -173,7 +173,7 @@ func systemJSONsCommon(c *gin.Context, column string) *models.SystemInventory { var system models.SystemInventory db := middlewares.DBFromContext(c) - query := database.Systems(db, account, groups). + query := database.Systems2(db, account, workspaceIDs). Select(column). Where("si.inventory_id = ?::uuid", inventoryID) diff --git a/manager/controllers/system_detail_test.go b/manager/controllers/system_detail_test.go index a886a0166..de1db9514 100644 --- a/manager/controllers/system_detail_test.go +++ b/manager/controllers/system_detail_test.go @@ -12,7 +12,7 @@ import ( func TestSystemDetailDefault1(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", "", nil, "", - SystemDetailHandler) + SystemDetailHandler, c) var output SystemDetailResponse CheckResponse(t, w, http.StatusOK, &output) @@ -40,7 +40,7 @@ func TestSystemDetailDefault2(t *testing.T) { core.SetupTest(t) // get system with some installable/updatable packages w := CreateRequestRouterWithAccount("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000012", "", nil, "", - SystemDetailHandler, 3) + SystemDetailHandler, 3, c) var output SystemDetailResponse CheckResponse(t, w, http.StatusOK, &output) @@ -50,7 +50,7 @@ func TestSystemDetailDefault2(t *testing.T) { func TestSystemDetailNoIdProvided(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/", nil, "", SystemDetailHandler) + w := CreateRequest("GET", "/", nil, "", SystemDetailHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -60,7 +60,7 @@ func TestSystemDetailNoIdProvided(t *testing.T) { func TestSystemDetailNotFound(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "ffffffff-ffff-ffff-ffff-ffffffffffff", "", nil, "", - SystemDetailHandler) + SystemDetailHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusNotFound, &errResp) @@ -70,7 +70,7 @@ func TestSystemDetailNotFound(t *testing.T) { func TestSystemsNoRHSM(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithAccount("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000014", "", nil, "", - SystemDetailHandler, 3) + SystemDetailHandler, 3, c) var output SystemDetailResponse CheckResponse(t, w, http.StatusOK, &output) @@ -82,7 +82,7 @@ func TestSystemsNoRHSM(t *testing.T) { func TestRHSMLessThanOS(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithAccount("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000003", "", nil, "", - SystemDetailHandler, 1) + SystemDetailHandler, 1, c) var output SystemDetailResponse CheckResponse(t, w, http.StatusOK, &output) @@ -95,7 +95,7 @@ func TestRHSMLessThanOS(t *testing.T) { func TestRHSMGreaterThanOS(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithAccount("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000004", "", nil, "", - SystemDetailHandler, 1) + SystemDetailHandler, 1, c) var output SystemDetailResponse CheckResponse(t, w, http.StatusOK, &output) @@ -114,7 +114,7 @@ func TestSystemUnknown(t *testing.T) { func TestSystemDetailFiltering(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithAccount("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?filter[filter]=abcd", nil, "", SystemDetailHandler, 1) + "?filter[filter]=abcd", nil, "", SystemDetailHandler, 1, c) var errResp utils.ErrorResponse ParseResponseBody(t, w.Body.Bytes(), &errResp) From ea0178fe71c88816f12a238f9066e5153191ffd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 12:29:03 +0200 Subject: [PATCH 11/34] RHINENG-25147: replace groups with workspaces: SystemsListHandler, SystemsListIDsHandler, SystemsExportHandler --- dev/test_data.sql | 4 ++-- manager/controllers/systems.go | 8 ++++---- manager/controllers/systems_auth_test.go | 2 +- manager/controllers/systems_export.go | 4 ++-- manager/controllers/systems_export_test.go | 2 +- manager/controllers/systems_ids_test.go | 6 +++--- manager/controllers/systems_test.go | 8 ++++---- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dev/test_data.sql b/dev/test_data.sql index ea481056f..30122ae8e 100644 --- a/dev/test_data.sql +++ b/dev/test_data.sql @@ -46,8 +46,8 @@ INSERT INTO system_patch (system_id, rh_account_id) VALUES INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES ( 8, '00000000-0000-0000-0000-000000000008', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000008', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'inventory-group-2', 'group2', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000008', true), -( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, NULL, NULL, 'RHEL', 8, 1, '8.1', NULL, true), -(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, NULL, NULL, 'RHEL', 8, 2, '8.2', NULL, true), +( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true), +(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', NULL, true), (11, '00000000-0000-0000-0000-000000000011', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000011', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 3, '8.3', NULL, true), (12, '00000000-0000-0000-0000-000000000012', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000012', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed, packages_installable, packages_applicable) VALUES diff --git a/manager/controllers/systems.go b/manager/controllers/systems.go index 6bc85713a..87b9a1406 100644 --- a/manager/controllers/systems.go +++ b/manager/controllers/systems.go @@ -185,9 +185,9 @@ type SystemsResponse struct { func systemsCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, error) { var err error account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) - query := querySystems(db, account, groups) + query := querySystems(db, account, workspaceIDs) filters, err := ParseAllFilters(c, SystemOpts) if err != nil { return nil, nil, nil, err @@ -358,6 +358,6 @@ func SystemsListIDsHandler(c *gin.Context) { c.JSON(http.StatusOK, &resp) } -func querySystems(db *gorm.DB, account int, groups map[string]string) *gorm.DB { - return database.Systems(db, account, groups, database.JoinTemplates).Select(SystemsSelect) +func querySystems(db *gorm.DB, account int, workspaceIDs []string) *gorm.DB { + return database.Systems2(db, account, workspaceIDs, database.JoinTemplates).Select(SystemsSelect) } diff --git a/manager/controllers/systems_auth_test.go b/manager/controllers/systems_auth_test.go index 560510ae2..e5658d028 100644 --- a/manager/controllers/systems_auth_test.go +++ b/manager/controllers/systems_auth_test.go @@ -11,7 +11,7 @@ import ( func testAccountSystemCounts(t *testing.T, acc int, count int) { core.SetupTest(t) var output SystemsResponse - w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemsListHandler, acc) + w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemsListHandler, acc, c) CheckResponse(t, w, http.StatusOK, &output) // data assert.Equal(t, count, len(output.Data)) diff --git a/manager/controllers/systems_export.go b/manager/controllers/systems_export.go index d3ef42314..ce1d41328 100644 --- a/manager/controllers/systems_export.go +++ b/manager/controllers/systems_export.go @@ -56,9 +56,9 @@ import ( // @Router /export/systems [get] func SystemsExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) - query := querySystems(db, account, groups) + query := querySystems(db, account, workspaceIDs) filters, err := ParseAllFilters(c, SystemOpts) if err != nil { return diff --git a/manager/controllers/systems_export_test.go b/manager/controllers/systems_export_test.go index 5e3080eb7..029684225 100644 --- a/manager/controllers/systems_export_test.go +++ b/manager/controllers/systems_export_test.go @@ -22,7 +22,7 @@ var SystemCsvHeader = "id,display_name,os,rhsm,tags,last_evaluation," + func makeRequest(t *testing.T, path string, contentType string) *httptest.ResponseRecorder { core.SetupTest(t) - return CreateRequest("GET", path, nil, contentType, SystemsExportHandler) + return CreateRequest("GET", path, nil, contentType, SystemsExportHandler, c) } func TestSystemsExportJSON(t *testing.T) { diff --git a/manager/controllers/systems_ids_test.go b/manager/controllers/systems_ids_test.go index 0ad521c42..f6bf552dd 100644 --- a/manager/controllers/systems_ids_test.go +++ b/manager/controllers/systems_ids_test.go @@ -29,7 +29,7 @@ func TestSystemsIDsOffsetLimit(t *testing.T) { } func TestSystemsIDsWrongOffset(t *testing.T) { - doTestWrongOffset(t, "/", "", "?offset=13&limit=4", SystemsListIDsHandler) + doTestWrongOffset(t, "/", "", "?offset=13&limit=4", SystemsListIDsHandler, c) } func TestSystemsIDsWrongSort(t *testing.T) { @@ -192,7 +192,7 @@ func TestSystemsIDsFilterTemplateUUID(t *testing.T) { func testSystemsIDs(t *testing.T, queryString string, account int) IDsSatelliteManagedResponse { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", queryString, nil, "", SystemsListIDsHandler, account) + w := CreateRequestRouterWithAccount("GET", "/", "", queryString, nil, "", SystemsListIDsHandler, account, c) var output IDsSatelliteManagedResponse CheckResponse(t, w, http.StatusOK, &output) @@ -201,7 +201,7 @@ func testSystemsIDs(t *testing.T, queryString string, account int) IDsSatelliteM func testSystemsIDsError(t *testing.T, queryString string) (int, utils.ErrorResponse) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/", "", queryString, nil, "", SystemsListIDsHandler) + w := CreateRequestRouterWithPath("GET", "/", "", queryString, nil, "", SystemsListIDsHandler, c) var errResp utils.ErrorResponse ParseResponseBody(t, w.Body.Bytes(), &errResp) diff --git a/manager/controllers/systems_test.go b/manager/controllers/systems_test.go index 4520c1826..081f04240 100644 --- a/manager/controllers/systems_test.go +++ b/manager/controllers/systems_test.go @@ -70,7 +70,7 @@ func TestSystemsOffsetLimit(t *testing.T) { } func TestSystemsWrongOffset(t *testing.T) { - doTestWrongOffset(t, "/", "", "?offset=13&limit=4", SystemsListHandler) + doTestWrongOffset(t, "/", "", "?offset=13&limit=4", SystemsListHandler, c) } func TestSystemsWrongSort(t *testing.T) { @@ -257,7 +257,7 @@ func TestSystemsFilterTemplateUUID(t *testing.T) { func testSystems(t *testing.T, queryString string, account int) SystemsResponse { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", queryString, nil, "", SystemsListHandler, account) + w := CreateRequestRouterWithAccount("GET", "/", "", queryString, nil, "", SystemsListHandler, account, c) var output SystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -266,7 +266,7 @@ func testSystems(t *testing.T, queryString string, account int) SystemsResponse func testSystemsError(t *testing.T, queryString string) (int, utils.ErrorResponse) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/", "", queryString, nil, "", SystemsListHandler) + w := CreateRequestRouterWithPath("GET", "/", "", queryString, nil, "", SystemsListHandler, c) var errResp utils.ErrorResponse ParseResponseBody(t, w.Body.Bytes(), &errResp) @@ -276,7 +276,7 @@ func testSystemsError(t *testing.T, queryString string) (int, utils.ErrorRespons func TestSystemsTagsInMetadata(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithAccount("GET", "/", "", "?tags=ns1/k3=val4&tags=ns1/k1=val1", nil, "", - SystemsListHandler, 3) + SystemsListHandler, 3, c) var output SystemsResponse ParseResponseBody(t, w.Body.Bytes(), &output) From 00cca6bf8ccd9904d3b2dd0277dccb0992fcb9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 13:05:32 +0200 Subject: [PATCH 12/34] RHINENG-25147: replace groups with workspaces: SystemTagListHandler --- manager/controllers/systemtags.go | 4 ++-- manager/controllers/systemtags_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/manager/controllers/systemtags.go b/manager/controllers/systemtags.go index 5f02993d9..0153f1b52 100644 --- a/manager/controllers/systemtags.go +++ b/manager/controllers/systemtags.go @@ -65,11 +65,11 @@ var SystemTagsOpts = ListOpts{ func SystemTagListHandler(c *gin.Context) { var err error account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) // https://stackoverflow.com/questions/33474778/how-to-group-result-by-array-column-in-postgres - sq := database.Systems(db, account, groups). + sq := database.Systems2(db, account, workspaceIDs). Select("jsonb_array_elements(si.tags) AS tag") query := db.Table("(?) AS sq", sq). diff --git a/manager/controllers/systemtags_test.go b/manager/controllers/systemtags_test.go index ec12e5b05..14bb6ef82 100644 --- a/manager/controllers/systemtags_test.go +++ b/manager/controllers/systemtags_test.go @@ -12,7 +12,7 @@ import ( func TestSystemTagsListDefault(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemTagListHandler, 1) + w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemTagListHandler, 1, c) var output SystemTagsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -29,7 +29,7 @@ func TestSystemTagsListDefault(t *testing.T) { func TestSystemTagsListPagination(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", "?offset=1&limit=1", nil, "", SystemTagListHandler, 1) + w := CreateRequestRouterWithAccount("GET", "/", "", "?offset=1&limit=1", nil, "", SystemTagListHandler, 1, c) var output SystemTagsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -46,7 +46,7 @@ func TestSystemTagsListPagination(t *testing.T) { func TestSystemTagsTotalItems(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemTagListHandler, 1) + w := CreateRequestRouterWithAccount("GET", "/", "", "", nil, "", SystemTagListHandler, 1, c) var output SystemTagsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -56,7 +56,7 @@ func TestSystemTagsTotalItems(t *testing.T) { func TestSystemTagsListSort(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithAccount("GET", "/", "", "?sort=count", nil, "", SystemTagListHandler, 1) + w := CreateRequestRouterWithAccount("GET", "/", "", "?sort=count", nil, "", SystemTagListHandler, 1, c) var output SystemTagsResponse CheckResponse(t, w, http.StatusOK, &output) From 538139fdeafbef3adf63633f1923fd29cb1805ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 13:57:23 +0200 Subject: [PATCH 13/34] RHINENG-25147: replace groups with workspaces: TemplateSystemsListHandler, TemplateSystemsListIDsHandler, TemplateSystemsExportHandler --- manager/controllers/template_systems.go | 16 ++++++++-------- manager/controllers/template_systems_export.go | 4 ++-- .../controllers/template_systems_export_test.go | 14 +++++++------- manager/controllers/template_systems_test.go | 8 ++++---- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/manager/controllers/template_systems.go b/manager/controllers/template_systems.go index bd076fac7..686d090f8 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -76,7 +76,7 @@ func getTemplate(c *gin.Context, tx *gorm.DB, account int, uuid string) (*models return &template, nil } -func templateSystemsQuery(c *gin.Context, account int, groups map[string]string) (*gorm.DB, Filters, error) { +func templateSystemsQuery(c *gin.Context, account int, workspaceIDs []string) (*gorm.DB, Filters, error) { templateUUID := c.Param("template_id") db := middlewares.DBFromContext(c) @@ -86,7 +86,7 @@ func templateSystemsQuery(c *gin.Context, account int, groups map[string]string) return nil, nil, err } - query := database.Systems(db, account, groups). + query := database.Systems2(db, account, workspaceIDs). Where("spatch.template_id = ?", template.ID). Select(templateSystemSelect) @@ -98,9 +98,9 @@ func templateSystemsQuery(c *gin.Context, account int, groups map[string]string) return query, filters, nil } -func templateSystemsCommon(c *gin.Context, account int, groups map[string]string, +func templateSystemsCommon(c *gin.Context, account int, workspaceIDs []string, ) (*gorm.DB, *ListMeta, []string, error) { - query, filters, err := templateSystemsQuery(c, account, groups) + query, filters, err := templateSystemsQuery(c, account, workspaceIDs) if err != nil { return nil, nil, nil, err } // Error handled in method itself @@ -160,9 +160,9 @@ func templateSystemData(templateSystems []TemplateSystemsDBLookup) ([]TemplateSy // @Router /templates/{template_id}/systems [get] func TemplateSystemsListHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) - query, meta, params, err := templateSystemsCommon(c, account, groups) + query, meta, params, err := templateSystemsCommon(c, account, workspaceIDs) if err != nil { return } // Error handled in method itself @@ -209,9 +209,9 @@ func TemplateSystemsListHandler(c *gin.Context) { // @Router /ids/templates/{template_id}/systems [get] func TemplateSystemsListIDsHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) - query, meta, _, err := templateSystemsCommon(c, account, groups) + query, meta, _, err := templateSystemsCommon(c, account, workspaceIDs) if err != nil { return } // Error handled in method itself diff --git a/manager/controllers/template_systems_export.go b/manager/controllers/template_systems_export.go index 944b9468d..caf3681c7 100644 --- a/manager/controllers/template_systems_export.go +++ b/manager/controllers/template_systems_export.go @@ -33,9 +33,9 @@ import ( // @Router /export/templates/{template_id}/systems [get] func TemplateSystemsExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) - query, _, err := templateSystemsQuery(c, account, groups) + query, _, err := templateSystemsQuery(c, account, workspaceIDs) if err != nil { return } // Error handled in method itself diff --git a/manager/controllers/template_systems_export_test.go b/manager/controllers/template_systems_export_test.go index 51bd83f12..909589fe7 100644 --- a/manager/controllers/template_systems_export_test.go +++ b/manager/controllers/template_systems_export_test.go @@ -20,7 +20,7 @@ var TemplateCsvHeader = "id,display_name,os,rhsm," + func TestTemplateSystemsExportJSON(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", "", - nil, "application/json", TemplateSystemsExportHandler) + nil, "application/json", TemplateSystemsExportHandler, c) var output []TemplateSystemsDBLookup CheckResponse(t, w, http.StatusOK, &output) @@ -56,7 +56,7 @@ func TestTemplateSystemsExportJSON(t *testing.T) { func TestTemplateSystemsExportCSV(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", "", - nil, "text/csv", TemplateSystemsExportHandler) + nil, "text/csv", TemplateSystemsExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -80,7 +80,7 @@ func TestTemplateSystemsExportCSV(t *testing.T) { func TestTemplateSystemsExportWrongFormat(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", "", - nil, "test-format", TemplateSystemsExportHandler) + nil, "test-format", TemplateSystemsExportHandler, c) assert.Equal(t, http.StatusUnsupportedMediaType, w.Code) body := w.Body.String() @@ -90,7 +90,7 @@ func TestTemplateSystemsExportWrongFormat(t *testing.T) { func TestTemplateSystemsExportCSVFilter(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", - "?filter[display_name]=nonexistent", nil, "text/csv", TemplateSystemsExportHandler) + "?filter[display_name]=nonexistent", nil, "text/csv", TemplateSystemsExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -103,7 +103,7 @@ func TestTemplateSystemsExportCSVFilter(t *testing.T) { func TestExportTemplateSystemsTags(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", - "?tags=ns1/k2=val2", nil, "application/json", TemplateSystemsExportHandler) + "?tags=ns1/k2=val2", nil, "application/json", TemplateSystemsExportHandler, c) var output []TemplateSystemsDBLookup CheckResponse(t, w, http.StatusOK, &output) @@ -115,7 +115,7 @@ func TestExportTemplateSystemsTags(t *testing.T) { func TestExportTemplateSystemsTagsInvalid(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", - "?tags=ns1/k3=val4&tags=invalidTag", nil, "application/json", TemplateSystemsExportHandler) + "?tags=ns1/k3=val4&tags=invalidTag", nil, "application/json", TemplateSystemsExportHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -126,7 +126,7 @@ func TestTemplateSystemsExportWorkloads(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", "?filter[system_profile][sap_system]=true&filter[system_profile][sap_sids]=ABC", nil, "application/json", - TemplateSystemsExportHandler) + TemplateSystemsExportHandler, c) var output []TemplateSystemsDBLookup CheckResponse(t, w, http.StatusOK, &output) diff --git a/manager/controllers/template_systems_test.go b/manager/controllers/template_systems_test.go index 5c2e52a61..44f5a744b 100644 --- a/manager/controllers/template_systems_test.go +++ b/manager/controllers/template_systems_test.go @@ -12,7 +12,7 @@ import ( func testTemplateSystems(t *testing.T, param, queryString string) TemplateSystemsResponse { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", param, queryString, nil, "", - TemplateSystemsListHandler) + TemplateSystemsListHandler, c) var output TemplateSystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -78,7 +78,7 @@ func TestTemplateSystemsUnlimited(t *testing.T) { func TestTemplateSystemOffsetOverflow(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", - "?offset=10&limit=4", nil, "", TemplateSystemsListHandler) + "?offset=10&limit=4", nil, "", TemplateSystemsListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -101,7 +101,7 @@ func TestTemplatesFilterTag(t *testing.T) { func TestTemplateSystemsWrongSort(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "99900000-0000-0000-0000-000000000001", - "?sort=unknown_key", nil, "", TemplateSystemsListHandler) + "?sort=unknown_key", nil, "", TemplateSystemsListHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } @@ -131,7 +131,7 @@ func TestTemplateSystemsSearch(t *testing.T) { func TestTemplateSystemsInvalidUUID(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:template_id/systems", "InvalidTemplateUUID", - "?sort=unknown_key", nil, "", TemplateSystemsListHandler) + "?sort=unknown_key", nil, "", TemplateSystemsListHandler, c) assert.Equal(t, http.StatusNotFound, w.Code) assert.Equal(t, `{"error":"Invalid template uuid: InvalidTemplateUUID"}`, w.Body.String()) From a8f97e8e067c6cdb86b030644323d09eae45eda2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 14:07:43 +0200 Subject: [PATCH 14/34] RHINENG-25147: replace groups with workspaces: TemplatesListHandler --- manager/controllers/templates.go | 8 ++++---- manager/controllers/templates_test.go | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manager/controllers/templates.go b/manager/controllers/templates.go index 75d58c20a..ec766443b 100644 --- a/manager/controllers/templates.go +++ b/manager/controllers/templates.go @@ -77,14 +77,14 @@ type TemplatesResponse struct { // @Router /templates [get] func TemplatesListHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) filters, err := ParseAllFilters(c, TemplateOpts) if err != nil { return } db := middlewares.DBFromContext(c) - query := templatesQuery(db, filters, account, groups) + query := templatesQuery(db, filters, account, workspaceIDs) query, meta, params, err := ListCommon(query, c, filters, TemplateOpts) if err != nil { @@ -123,8 +123,8 @@ func TemplatesListHandler(c *gin.Context) { c.JSON(http.StatusOK, &resp) } -func templatesQuery(db *gorm.DB, filters map[string]FilterData, account int, groups map[string]string) *gorm.DB { - subq := database.Systems(db, account, groups). +func templatesQuery(db *gorm.DB, filters map[string]FilterData, account int, workspaceIDs []string) *gorm.DB { + subq := database.Systems2(db, account, workspaceIDs). Select("spatch.template_id, count(*) as systems"). Group("spatch.template_id") diff --git a/manager/controllers/templates_test.go b/manager/controllers/templates_test.go index 7e036e480..29b7fa64f 100644 --- a/manager/controllers/templates_test.go +++ b/manager/controllers/templates_test.go @@ -12,7 +12,7 @@ import ( func testTemplates(t *testing.T, url string) TemplatesResponse { core.SetupTest(t) - w := CreateRequest("GET", url, nil, "", TemplatesListHandler) + w := CreateRequest("GET", url, nil, "", TemplatesListHandler, c) var output TemplatesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -21,7 +21,7 @@ func testTemplates(t *testing.T, url string) TemplatesResponse { func testTemplatesError(t *testing.T, url string, expectedStatus int) utils.ErrorResponse { core.SetupTest(t) - w := CreateRequest("GET", url, nil, "", TemplatesListHandler) + w := CreateRequest("GET", url, nil, "", TemplatesListHandler, c) var output utils.ErrorResponse CheckResponse(t, w, expectedStatus, &output) @@ -64,7 +64,7 @@ func TestTemplatesOffsetLimit(t *testing.T) { func TestTemplatesOffsetOverflow(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/?offset=10&limit=4", nil, "", TemplatesListHandler) + w := CreateRequest("GET", "/?offset=10&limit=4", nil, "", TemplatesListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -115,7 +115,7 @@ func TestTemplatesSort(t *testing.T) { func TestTemplatesWrongSort(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/?sort=unknown_key", nil, "", TemplatesListHandler) + w := CreateRequest("GET", "/?sort=unknown_key", nil, "", TemplatesListHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } From ece5729260bf3f2f02498032ae81a9e761e7a266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 14:16:20 +0200 Subject: [PATCH 15/34] RHINENG-25147: replace groups with workspaces: TemplateSystemsUpdateHandler, TemplateSystemsDeleteHandler, TemplateSubscribedSystemsUpdateHandler --- .../template_subscribed_systems_update.go | 5 ++-- ...template_subscribed_systems_update_test.go | 4 ++-- .../controllers/template_systems_delete.go | 6 ++--- .../template_systems_delete_test.go | 4 ++-- .../controllers/template_systems_update.go | 24 +++++++++---------- .../template_systems_update_test.go | 22 ++++++++--------- 6 files changed, 33 insertions(+), 32 deletions(-) diff --git a/manager/controllers/template_subscribed_systems_update.go b/manager/controllers/template_subscribed_systems_update.go index 5657ed8da..bcf2d2af0 100644 --- a/manager/controllers/template_subscribed_systems_update.go +++ b/manager/controllers/template_subscribed_systems_update.go @@ -26,6 +26,7 @@ import ( // @Router /templates/{template_id}/subscribed-systems [PATCH] func TemplateSubscribedSystemsUpdateHandler(c *gin.Context) { templateUUID := c.Param("template_id") + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) @@ -41,12 +42,12 @@ func TemplateSubscribedSystemsUpdateHandler(c *gin.Context) { } systemList := []string{systemUUID} - err = checkTemplateSystems(c, db, account, template, systemList, nil) + err = checkTemplateSystems(c, db, account, template, systemList, workspaceIDs) if err != nil { return } - err = assignCandlepinEnvironment(c, db, account, &template.EnvironmentID, systemList, nil) + err = assignCandlepinEnvironment(c, db, account, &template.EnvironmentID, systemList, workspaceIDs) if err != nil { return } diff --git a/manager/controllers/template_subscribed_systems_update_test.go b/manager/controllers/template_subscribed_systems_update_test.go index 14a207df3..d5062d9bd 100644 --- a/manager/controllers/template_subscribed_systems_update_test.go +++ b/manager/controllers/template_subscribed_systems_update_test.go @@ -49,7 +49,7 @@ func TestUpdateTemplateSubscribedSystems(t *testing.T) { database.CreateTemplate(t, templateAccount, templateUUID, nil) w := CreateRequestRouterWithParams("PATCH", "/:template_id/subscribed-systems", templateUUID, "", nil, "", - TemplateSubscribedSystemsUpdateHandler, templateAccount, + TemplateSubscribedSystemsUpdateHandler, templateAccount, c, core.ContextKV{Key: utils.KeySystem, Value: subscriptionUUID}, core.ContextKV{Key: utils.KeyOrgID, Value: orgID}) @@ -64,7 +64,7 @@ func TestUpdateTemplateSubscribedSystemsInvalid(t *testing.T) { database.CreateTemplate(t, templateAccount, templateUUID, nil) w := CreateRequestRouterWithParams("PATCH", "/:template_id/subscribed-systems", templateUUID, "", nil, "", - TemplateSubscribedSystemsUpdateHandler, templateAccount, + TemplateSubscribedSystemsUpdateHandler, templateAccount, c, core.ContextKV{Key: utils.KeySystem, Value: subscriptionInvalidUUID}) assert.Equal(t, http.StatusNotFound, w.Code) diff --git a/manager/controllers/template_systems_delete.go b/manager/controllers/template_systems_delete.go index bf84c7834..284a38a26 100644 --- a/manager/controllers/template_systems_delete.go +++ b/manager/controllers/template_systems_delete.go @@ -24,7 +24,7 @@ import ( // @Router /templates/systems [DELETE] func TemplateSystemsDeleteHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) var req TemplateSystemsUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { @@ -38,12 +38,12 @@ func TemplateSystemsDeleteHandler(c *gin.Context) { db := middlewares.DBFromContext(c) - err := checkTemplateSystems(c, db, account, nil, req.Systems, groups) + err := checkTemplateSystems(c, db, account, nil, req.Systems, workspaceIDs) if err != nil { return } - err = assignCandlepinEnvironment(c, db, account, nil, req.Systems, groups) + err = assignCandlepinEnvironment(c, db, account, nil, req.Systems, workspaceIDs) if err != nil { return } diff --git a/manager/controllers/template_systems_delete_test.go b/manager/controllers/template_systems_delete_test.go index a0541b985..3d56c0f43 100644 --- a/manager/controllers/template_systems_delete_test.go +++ b/manager/controllers/template_systems_delete_test.go @@ -22,7 +22,7 @@ func testTemplateSystemsDelete(t *testing.T, body TemplateSystemsUpdateRequest, } w := CreateRequestRouterWithParams("POST", "/systems", "", "", bytes.NewBuffer(bodyJSON), "", - TemplateSystemsDeleteHandler, templateAccount) + TemplateSystemsDeleteHandler, templateAccount, c) assert.Equal(t, status, w.Code) return w @@ -89,7 +89,7 @@ func TestTemplateSystemsDeleteTooManySystems(t *testing.T) { } w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBuffer(putBodyJSON), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) assert.Equal(t, http.StatusOK, w.Code) systems = append(systems, additionalSystem) diff --git a/manager/controllers/template_systems_update.go b/manager/controllers/template_systems_update.go index 9ba90f0ee..fa0c1d7e1 100644 --- a/manager/controllers/template_systems_update.go +++ b/manager/controllers/template_systems_update.go @@ -54,7 +54,7 @@ type SystemTemplateDBLookup struct { func TemplateSystemsUpdateHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) templateUUID := c.Param("template_id") - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) var req TemplateSystemsUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { @@ -73,12 +73,12 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { return } - err = checkTemplateSystems(c, db, account, template, req.Systems, groups) + err = checkTemplateSystems(c, db, account, template, req.Systems, workspaceIDs) if err != nil { return } - err = assignCandlepinEnvironment(c, db, account, &template.EnvironmentID, req.Systems, groups) + err = assignCandlepinEnvironment(c, db, account, &template.EnvironmentID, req.Systems, workspaceIDs) if err != nil { return } @@ -97,14 +97,14 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { } func checkTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template *models.Template, - inventoryIDs []string, groups map[string]string) error { + inventoryIDs []string, workspaceIDs []string) error { if len(inventoryIDs) == 0 { err := errors.New(InvalidInventoryIDsErr) utils.LogAndRespBadRequest(c, err, InvalidInventoryIDsErr) return err } - err := checkInventoryIDs(db, accountID, inventoryIDs, groups) + err := checkInventoryIDs(db, accountID, inventoryIDs, workspaceIDs) if err != nil { switch { case errors.Is(err, base.ErrBadRequest): @@ -119,7 +119,7 @@ func checkTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template * } } - if err := templateArchVersionMatch(db, inventoryIDs, template, accountID, groups); err != nil { + if err := templateArchVersionMatch(db, inventoryIDs, template, accountID, workspaceIDs); err != nil { msg := fmt.Sprintf("Incompatible template and system version or architecture: %s", err.Error()) utils.LogAndRespBadRequest(c, err, msg) return err @@ -164,7 +164,7 @@ func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template } func templateArchVersionMatch( - db *gorm.DB, inventoryIDs []string, template *models.Template, acc int, groups map[string]string, + db *gorm.DB, inventoryIDs []string, template *models.Template, acc int, workspaceIDs []string, ) error { if template == nil { return nil @@ -175,7 +175,7 @@ func templateArchVersionMatch( Version string }{} var err error - err = database.Systems(db, acc, groups). + err = database.Systems2(db, acc, workspaceIDs). Select("si.inventory_id as inventory_id, si.os_major as version, si.arch as arch"). Where("si.inventory_id in (?)", inventoryIDs).Find(&sysArchVersions).Error if err != nil { @@ -220,13 +220,13 @@ func callCandlepin(ctx context.Context, owner string, request *candlepin.Consume } func assignCandlepinEnvironment(c *gin.Context, db *gorm.DB, accountID int, env *string, inventoryIDs []string, - groups map[string]string) error { + workspaceIDs []string) error { var hosts = []struct { InventoryID string Consumer *string }{} - err := database.Systems(db, accountID, groups). + err := database.Systems2(db, accountID, workspaceIDs). Select("si.inventory_id as inventory_id, si.subscription_manager_id as consumer"). Where("si.inventory_id in (?)", inventoryIDs).Find(&hosts).Error if err != nil { @@ -270,12 +270,12 @@ func assignCandlepinEnvironment(c *gin.Context, db *gorm.DB, accountID int, env return nil } -func checkInventoryIDs(db *gorm.DB, accountID int, inventoryIDs []string, groups map[string]string) (err error) { +func checkInventoryIDs(db *gorm.DB, accountID int, inventoryIDs []string, workspaceIDs []string) (err error) { var containingSystems []SystemTemplateDBLookup var missingIDs []string var satelliteIDs []string var bootcIDs []string - err = database.Systems(db, accountID, groups). + err = database.Systems2(db, accountID, workspaceIDs). Select("si.inventory_id, si.satellite_managed, si.bootc"). Where("si.inventory_id IN (?::uuid)", inventoryIDs). Scan(&containingSystems).Error diff --git a/manager/controllers/template_systems_update_test.go b/manager/controllers/template_systems_update_test.go index afec85543..ad1a2edcf 100644 --- a/manager/controllers/template_systems_update_test.go +++ b/manager/controllers/template_systems_update_test.go @@ -37,7 +37,7 @@ func TestUpdateTemplateSystems(t *testing.T) { "00000000-0000-0000-0000-000000000007", }) w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) assert.Equal(t, http.StatusOK, w.Code) database.CheckTemplateSystems(t, templateAccount, templateUUID, templateSystems) @@ -56,7 +56,7 @@ func TestUpdateTemplateInvalidVersion(t *testing.T) { "00000000-0000-0000-0000-000000000007", }) w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -79,7 +79,7 @@ func TestUpdateTemplateInvalidSystem(t *testing.T) { }` database.CreateTemplate(t, templateAccount, templateUUID, []string{}) w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusNotFound, &errResp) @@ -102,7 +102,7 @@ func TestUpdateTemplateSystemNotInCandlepin(t *testing.T) { }` database.CreateTemplate(t, templateAccount, templateUUID, []string{}) w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -118,7 +118,7 @@ func TestUpdateTemplateNullValues(t *testing.T) { database.CreateTemplate(t, templateAccount, templateUUID, templateSystems) data := "{}" w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var resp interface{} CheckResponse(t, w, http.StatusBadRequest, &resp) @@ -130,7 +130,7 @@ func TestUpdateTemplateNullValues(t *testing.T) { func TestUpdateTemplateInvalidTemplateID(t *testing.T) { core.SetupTestEnvironment() w := CreateRequestRouterWithParams("PUT", templatePath, "invalidTemplate", "", bytes.NewBufferString("{}"), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusNotFound, &errResp) @@ -152,7 +152,7 @@ func TestReassignTemplateSystems2(t *testing.T) { ] }` w := CreateRequestRouterWithParams("PUT", templatePath, template2, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) assert.Equal(t, http.StatusOK, w.Code) @@ -202,7 +202,7 @@ func testUpdateTemplateBadRequest(t *testing.T, satelliteManaged, bootc bool) { }` w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var err utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &err) } @@ -238,7 +238,7 @@ func TestUpdateTemplateSystemsCandlepin404(t *testing.T) { }) defer database.DeleteTemplate(t, templateAccount, templateUUID) w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount, core.ContextKV{Key: utils.KeyOrgID, Value: orgID}) + TemplateSystemsUpdateHandler, templateAccount, c, core.ContextKV{Key: utils.KeyOrgID, Value: orgID}) assert.Equal(t, http.StatusBadRequest, w.Code) database.CheckTemplateSystems(t, templateAccount, templateUUID, []string{"00000000-0000-0000-0000-000000000007"}) @@ -251,7 +251,7 @@ func TestUpdateTemplateSystemsCandlepin404(t *testing.T) { ] }` w = CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBufferString(data), "", - TemplateSystemsUpdateHandler, templateAccount, core.ContextKV{Key: utils.KeyOrgID, Value: orgID}) + TemplateSystemsUpdateHandler, templateAccount, c, core.ContextKV{Key: utils.KeyOrgID, Value: orgID}) assert.Equal(t, http.StatusBadRequest, w.Code) database.CheckTemplateSystems(t, templateAccount, templateUUID, @@ -278,7 +278,7 @@ func TestUpdateTemplateTooManySystems(t *testing.T) { } w := CreateRequestRouterWithParams("PUT", templatePath, templateUUID, "", bytes.NewBuffer(bodyJSON), "", - TemplateSystemsUpdateHandler, templateAccount) + TemplateSystemsUpdateHandler, templateAccount, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) From 62323b0610cb57d9a6a177b189351d75130398c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 14:53:05 +0200 Subject: [PATCH 16/34] RHINENG-25147: replace groups with workspaces: AdvisoriesListHandler, AdvisoriesListIDsHandler, AdvisoriesExportHandler --- base/database/utils.go | 6 ++++++ manager/controllers/advisories.go | 16 +++++++++------- manager/controllers/advisories_export.go | 8 +++++--- manager/controllers/advisories_export_test.go | 12 ++++++------ manager/controllers/advisories_test.go | 14 +++++++------- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index 9ec0340e7..6c25a8202 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -48,6 +48,12 @@ func SystemAdvisories(tx *gorm.DB, accountID int, groups map[string]string, join return (joinsT)(joins).apply(tx) } +func SystemAdvisories2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { + tx = Systems2(tx, accountID, workspaceIDs). + Joins("JOIN system_advisories sa on sa.system_id = si.id AND sa.rh_account_id = ?", accountID) + return (joinsT)(joins).apply(tx) +} + func SystemPackagesShort(tx *gorm.DB, accountID int, joins ...join) *gorm.DB { tx = tx.Table("system_package2 spkg"). Where("spkg.rh_account_id = ?", accountID) diff --git a/manager/controllers/advisories.go b/manager/controllers/advisories.go index e06c88368..d02f0513c 100644 --- a/manager/controllers/advisories.go +++ b/manager/controllers/advisories.go @@ -82,16 +82,18 @@ type AdvisoriesResponse struct { func advisoriesCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, error) { db := middlewares.DBFromContext(c) account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) var query *gorm.DB filters, err := ParseAllFilters(c, AdvisoriesOpts) if err != nil { return nil, nil, nil, err } - if config.DisableCachedCounts || HasInventoryFilter(filters) || len(groups) != 0 { + // TODO: fix below; the condition is always true since moving from groups to workspaces, + // there will always be at least root workspace + if config.DisableCachedCounts || HasInventoryFilter(filters) || len(workspaceIDs) != 0 { middlewares.AdvisoryAccountDataCnt.WithLabelValues("miss").Inc() - query = buildQueryAdvisoriesTagged(db, filters, account, groups) + query = buildQueryAdvisoriesTagged(db, filters, account, workspaceIDs) } else { middlewares.AdvisoryAccountDataCnt.WithLabelValues("hit").Inc() query = buildQueryAdvisories(db, account) @@ -216,8 +218,8 @@ func buildQueryAdvisories(db *gorm.DB, account int) *gorm.DB { return query } -func buildAdvisoryAccountDataQuery(db *gorm.DB, account int, groups map[string]string) *gorm.DB { - query := database.SystemAdvisories(db, account, groups). +func buildAdvisoryAccountDataQuery(db *gorm.DB, account int, workspaceIDs []string) *gorm.DB { + query := database.SystemAdvisories2(db, account, workspaceIDs). Select(`sa.advisory_id, si.rh_account_id as rh_account_id, count(si.*) filter (where sa.status_id = 0) as systems_installable, count(si.*) as systems_applicable`). @@ -227,9 +229,9 @@ func buildAdvisoryAccountDataQuery(db *gorm.DB, account int, groups map[string]s return query } -func buildQueryAdvisoriesTagged(db *gorm.DB, filters map[string]FilterData, account int, groups map[string]string, +func buildQueryAdvisoriesTagged(db *gorm.DB, filters map[string]FilterData, account int, workspaceIDs []string, ) *gorm.DB { - subq := buildAdvisoryAccountDataQuery(db, account, groups) + subq := buildAdvisoryAccountDataQuery(db, account, workspaceIDs) subq, _ = ApplyInventoryFilter(filters, subq, "si.inventory_id") query := database.AdvisoryMetadata(db). diff --git a/manager/controllers/advisories_export.go b/manager/controllers/advisories_export.go index 90e34e933..a9a7af66a 100644 --- a/manager/controllers/advisories_export.go +++ b/manager/controllers/advisories_export.go @@ -31,7 +31,7 @@ import ( // @Router /export/advisories [get] func AdvisoriesExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) filters, err := ParseAllFilters(c, AdvisoriesOpts) if err != nil { return @@ -39,8 +39,10 @@ func AdvisoriesExportHandler(c *gin.Context) { db := middlewares.DBFromContext(c) var query *gorm.DB - if config.DisableCachedCounts || HasInventoryFilter(filters) || len(groups) != 0 { - query = buildQueryAdvisoriesTagged(db, filters, account, groups) + // TODO: fix below; the condition is always true since moving from groups to workspaces, + // there will always be at least root workspace + if config.DisableCachedCounts || HasInventoryFilter(filters) || len(workspaceIDs) != 0 { + query = buildQueryAdvisoriesTagged(db, filters, account, workspaceIDs) } else { query = buildQueryAdvisories(db, account) } diff --git a/manager/controllers/advisories_export_test.go b/manager/controllers/advisories_export_test.go index 6e2328ba2..2d0b4d377 100644 --- a/manager/controllers/advisories_export_test.go +++ b/manager/controllers/advisories_export_test.go @@ -13,7 +13,7 @@ import ( func TestAdvisoriesExportJSON(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/", nil, "application/json", AdvisoriesExportHandler) + w := CreateRequest("GET", "/", nil, "application/json", AdvisoriesExportHandler, c) var output []AdvisoriesDBLookup CheckResponse(t, w, http.StatusOK, &output) @@ -32,7 +32,7 @@ func TestAdvisoriesExportJSON(t *testing.T) { func TestAdvisoriesExportCSV(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/", nil, "text/csv", AdvisoriesExportHandler) + w := CreateRequest("GET", "/", nil, "text/csv", AdvisoriesExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -44,7 +44,7 @@ func TestAdvisoriesExportCSV(t *testing.T) { func TestAdvisoriesExportWrongFormat(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/", nil, "test-format", AdvisoriesExportHandler) + w := CreateRequest("GET", "/", nil, "test-format", AdvisoriesExportHandler, c) assert.Equal(t, http.StatusUnsupportedMediaType, w.Code) body := w.Body.String() @@ -55,7 +55,7 @@ func TestAdvisoriesExportCSVFilter(t *testing.T) { core.SetupTest(t) for _, URL := range []string{"/?filter[id]=RH-1", "/?filter[synopsis]=adv-1-syn"} { - w := CreateRequest("GET", URL, nil, "text/csv", AdvisoriesExportHandler) + w := CreateRequest("GET", URL, nil, "text/csv", AdvisoriesExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -70,7 +70,7 @@ func TestAdvisoriesExportCSVFilter(t *testing.T) { func TestAdvisoriesExportTagsInvalid(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/", "", "?tags=ns1/k3=val4&tags=invalidTag", nil, "", - AdvisoriesExportHandler) + AdvisoriesExportHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -80,7 +80,7 @@ func TestAdvisoriesExportTagsInvalid(t *testing.T) { func TestAdvisoriesExportIncorrectFilter(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/", "", "?filter[filteriamnotexitst]=abcd", nil, "text/csv", - AdvisoriesExportHandler) + AdvisoriesExportHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } diff --git a/manager/controllers/advisories_test.go b/manager/controllers/advisories_test.go index 2ccc43f09..9e517f17d 100644 --- a/manager/controllers/advisories_test.go +++ b/manager/controllers/advisories_test.go @@ -22,7 +22,7 @@ func TestInit(_ *testing.T) { func testAdvisories(t *testing.T, url string) AdvisoriesResponse { core.SetupTest(t) - w := CreateRequest("GET", url, nil, "", AdvisoriesListHandler) + w := CreateRequest("GET", url, nil, "", AdvisoriesListHandler, c) var output AdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -31,7 +31,7 @@ func testAdvisories(t *testing.T, url string) AdvisoriesResponse { func testAdvisoriesIDs(t *testing.T, url string) IDsPlainResponse { core.SetupTest(t) - w := CreateRequest("GET", url, nil, "", AdvisoriesListIDsHandler) + w := CreateRequest("GET", url, nil, "", AdvisoriesListIDsHandler, c) var output IDsPlainResponse CheckResponse(t, w, http.StatusOK, &output) @@ -101,7 +101,7 @@ func TestAdvisoriesOffset(t *testing.T) { func TestAdvisoriesOffsetOverflow(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/?offset=13&limit=4", nil, "", AdvisoriesListHandler) + w := CreateRequest("GET", "/?offset=13&limit=4", nil, "", AdvisoriesListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -261,7 +261,7 @@ func TestAdvisoriesPossibleSorts(t *testing.T) { continue } - w := CreateRequest("GET", fmt.Sprintf("/?sort=%v", sort), nil, "", AdvisoriesListHandler) + w := CreateRequest("GET", fmt.Sprintf("/?sort=%v", sort), nil, "", AdvisoriesListHandler, c) var output AdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -272,7 +272,7 @@ func TestAdvisoriesPossibleSorts(t *testing.T) { func TestAdvisoriesWrongSort(t *testing.T) { core.SetupTest(t) - w := CreateRequest("GET", "/?sort=unknown_key", nil, "", AdvisoriesListHandler) + w := CreateRequest("GET", "/?sort=unknown_key", nil, "", AdvisoriesListHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } @@ -328,7 +328,7 @@ func TestAdvisoriesTags(t *testing.T) { func TestListAdvisoriesTagsInvalid(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/", "", "?tags=ns1/k3=val4&tags=invalidTag", nil, "", - AdvisoriesListHandler) + AdvisoriesListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -350,7 +350,7 @@ func TestAdvisoriesWrongOffset(t *testing.T) { func TestAdvisoryTagsInMetadata(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k3=val4&tags=ns1/k1=val1", nil, "", - AdvisoriesListHandler) + AdvisoriesListHandler, c) var output AdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) From 3e69fed6c3c3dfe76fd9c282a7b25b5eed67db4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:05:14 +0200 Subject: [PATCH 17/34] RHINENG-25147: replace groups with workspaces: AdvisorySystemsListHandler, AdvisorySystemsListIDsHandler, AdvisorySystemsExportHandler --- manager/controllers/advisory_systems.go | 8 +++--- .../controllers/advisory_systems_export.go | 4 +-- .../advisory_systems_export_test.go | 5 ++-- manager/controllers/advisory_systems_test.go | 26 +++++++++---------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/manager/controllers/advisory_systems.go b/manager/controllers/advisory_systems.go index d2f58944d..e71eda455 100644 --- a/manager/controllers/advisory_systems.go +++ b/manager/controllers/advisory_systems.go @@ -71,7 +71,7 @@ var AdvisorySystemOpts = ListOpts{ func advisorySystemsCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, error) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) advisoryName := c.Param("advisory_id") if advisoryName == "" { @@ -93,7 +93,7 @@ func advisorySystemsCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, error return nil, nil, nil, err } - query := buildAdvisorySystemsQuery(db, account, groups, advisoryName) + query := buildAdvisorySystemsQuery(db, account, workspaceIDs, advisoryName) opts := AdvisorySystemOpts filters, err := ParseAllFilters(c, opts) if err != nil { @@ -270,9 +270,9 @@ func AdvisorySystemsListIDsHandler(c *gin.Context) { c.JSON(http.StatusOK, &resp) } -func buildAdvisorySystemsQuery(db *gorm.DB, account int, groups map[string]string, advisoryName string) *gorm.DB { +func buildAdvisorySystemsQuery(db *gorm.DB, account int, workspaceIDs []string, advisoryName string) *gorm.DB { selectQuery := AdvisorySystemsSelect - query := database.SystemAdvisories(db, account, groups, database.JoinTemplates, database.JoinAdvisoryMetadata). + query := database.SystemAdvisories2(db, account, workspaceIDs, database.JoinTemplates, database.JoinAdvisoryMetadata). Select(selectQuery). Joins("LEFT JOIN status st ON sa.status_id = st.id"). Where("am.name = ?", advisoryName). diff --git a/manager/controllers/advisory_systems_export.go b/manager/controllers/advisory_systems_export.go index c63592dfb..30b1c1f74 100644 --- a/manager/controllers/advisory_systems_export.go +++ b/manager/controllers/advisory_systems_export.go @@ -53,7 +53,7 @@ var AdvisorySystemExportOpts = ListOpts{ // @Router /export/advisories/{advisory_id}/systems [get] func AdvisorySystemsExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) advisoryName := c.Param("advisory_id") if advisoryName == "" { @@ -73,7 +73,7 @@ func AdvisorySystemsExportHandler(c *gin.Context) { return } - query := buildAdvisorySystemsQuery(db, account, groups, advisoryName) + query := buildAdvisorySystemsQuery(db, account, workspaceIDs, advisoryName) filters, err := ParseAllFilters(c, AdvisorySystemExportOpts) if err != nil { return diff --git a/manager/controllers/advisory_systems_export_test.go b/manager/controllers/advisory_systems_export_test.go index 6ec2934be..443491f46 100644 --- a/manager/controllers/advisory_systems_export_test.go +++ b/manager/controllers/advisory_systems_export_test.go @@ -12,7 +12,7 @@ import ( func TestAdvisorySystemsExportJSON(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "application/json", - AdvisorySystemsExportHandler) + AdvisorySystemsExportHandler, c) var output []SystemDBLookupExtended CheckResponse(t, w, http.StatusOK, &output) @@ -23,7 +23,8 @@ func TestAdvisorySystemsExportJSON(t *testing.T) { func TestAdvisorySystemsExportCSV(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "text/csv", AdvisorySystemsExportHandler) + w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "text/csv", + AdvisorySystemsExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() diff --git a/manager/controllers/advisory_systems_test.go b/manager/controllers/advisory_systems_test.go index 1599ebd99..77e5bcd47 100644 --- a/manager/controllers/advisory_systems_test.go +++ b/manager/controllers/advisory_systems_test.go @@ -13,7 +13,7 @@ import ( func TestAdvisorySystemsDefault(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "", AdvisorySystemsListHandler) + w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "", AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -36,7 +36,7 @@ func TestAdvisorySystemsDefault(t *testing.T) { func TestAdvisorySystemsIDsDefault(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "", AdvisorySystemsListIDsHandler) + w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "", nil, "", AdvisorySystemsListIDsHandler, c) var output IDsStatusResponse CheckResponse(t, w, http.StatusOK, &output) @@ -50,7 +50,7 @@ func TestAdvisorySystemsIDsDefault(t *testing.T) { func TestAdvisorySystemsNotFound(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "nonexistant/systems", "", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) assert.Equal(t, http.StatusNotFound, w.Code) } @@ -58,7 +58,7 @@ func TestAdvisorySystemsNotFound(t *testing.T) { func TestAdvisorySystemsOffsetLimit(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?offset=5&limit=3", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -71,7 +71,7 @@ func TestAdvisorySystemsOffsetLimit(t *testing.T) { func TestAdvisorySystemsOffsetOverflow(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?offset=100&limit=3", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -86,7 +86,7 @@ func TestAdvisorySystemsSorts(t *testing.T) { continue // ignore obsoleted baseline attributes } w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", fmt.Sprintf("?sort=%v", sort), nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -98,7 +98,7 @@ func TestAdvisorySystemsSorts(t *testing.T) { func TestAdvisorySystemsWrongSort(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?sort=unknown_key", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } @@ -106,7 +106,7 @@ func TestAdvisorySystemsWrongSort(t *testing.T) { func TestAdvisorySystemsTags(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k1=val1", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -116,7 +116,7 @@ func TestAdvisorySystemsTags(t *testing.T) { func TestAdvisorySystemsTagsMultiple(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k3=val4&tags=ns1/k1=val1", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -127,7 +127,7 @@ func TestAdvisorySystemsTagsMultiple(t *testing.T) { func TestAdvisorySystemsTagsInvalid(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k3=val4&tags=invalidTag", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -137,7 +137,7 @@ func TestAdvisorySystemsTagsInvalid(t *testing.T) { func TestAdvisorySystemsTagsUnknown(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k3=val4&tags=ns1/k1=unk", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -145,13 +145,13 @@ func TestAdvisorySystemsTagsUnknown(t *testing.T) { } func TestAdvisorySystemsWrongOffset(t *testing.T) { - doTestWrongOffset(t, "/:advisory_id", "RH-1", "?offset=1000", AdvisorySystemsListHandler) + doTestWrongOffset(t, "/:advisory_id", "RH-1", "?offset=1000", AdvisorySystemsListHandler, c) } func TestAdvisorySystemsTagsInMetadata(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:advisory_id", "RH-1", "?tags=ns1/k3=val4&tags=ns1/k1=val1", nil, "", - AdvisorySystemsListHandler) + AdvisorySystemsListHandler, c) var output AdvisorySystemsResponse CheckResponse(t, w, http.StatusOK, &output) From 27c3b037db0114b8aa32291ca7037c2d9a94dbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:16:09 +0200 Subject: [PATCH 18/34] RHINENG-25147: replace groups with workspaces: PostAdvisoriesSystems --- manager/controllers/systems_advisories_view.go | 7 +++---- manager/controllers/systems_advisories_view_test.go | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manager/controllers/systems_advisories_view.go b/manager/controllers/systems_advisories_view.go index 9024d7847..96ff03161 100644 --- a/manager/controllers/systems_advisories_view.go +++ b/manager/controllers/systems_advisories_view.go @@ -122,12 +122,12 @@ func systemsAdvisoriesQuery(c *gin.Context, db *gorm.DB, acc int, workspaceIDs [ return query, meta, links, err } -func advisoriesSystemsQuery(c *gin.Context, db *gorm.DB, acc int, groups map[string]string, +func advisoriesSystemsQuery(c *gin.Context, db *gorm.DB, acc int, workspaceIDs []string, req SystemsAdvisoriesRequest) (*gorm.DB, *ListMeta, *Links, error) { systems := req.Systems advisories := req.Advisories // get all advisories for all systems in the account - advq := database.SystemAdvisories(db, acc, groups, database.JoinAdvisoryMetadata). + advq := database.SystemAdvisories2(db, acc, workspaceIDs, database.JoinAdvisoryMetadata). Distinct("am.id, am.name") // we need to join system_advisories to make `limit` work properly // without this join it can happen that we display less items on some pages @@ -180,7 +180,6 @@ func queryDB(c *gin.Context, endpoint string) ([]systemsAdvisoriesDBLoad, *ListM return nil, nil, nil, err } acc := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) db := middlewares.DBFromContext(c) // backward compatibility, put limit/offset from json into querystring @@ -194,7 +193,7 @@ func queryDB(c *gin.Context, endpoint string) ([]systemsAdvisoriesDBLoad, *ListM case "SystemsAdvisories": q, meta, links, err = systemsAdvisoriesQuery(c, db, acc, workspaceIDs, req) case "AdvisoriesSystems": - q, meta, links, err = advisoriesSystemsQuery(c, db, acc, groups, req) + q, meta, links, err = advisoriesSystemsQuery(c, db, acc, workspaceIDs, req) default: return nil, nil, nil, fmt.Errorf("unknown endpoint '%s'", endpoint) } diff --git a/manager/controllers/systems_advisories_view_test.go b/manager/controllers/systems_advisories_view_test.go index 89223b7b6..51b314952 100644 --- a/manager/controllers/systems_advisories_view_test.go +++ b/manager/controllers/systems_advisories_view_test.go @@ -46,7 +46,7 @@ func TestSystemsAdvisoriesView(t *testing.T) { } func TestAdvisoriesSystemsView(t *testing.T) { - w := doTestView(t, PostAdvisoriesSystems, "", nil, nil) + w := doTestView(t, PostAdvisoriesSystems, "", nil, nil, c) var output AdvisoriesSystemsResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, output.Data["RH-1"][0], SystemID("00000000-0000-0000-0000-000000000001")) @@ -62,7 +62,7 @@ func TestSystemsAdvisoriesViewTags(t *testing.T) { } func TestAdvisoriesSystemsViewTags(t *testing.T) { - w := doTestView(t, PostAdvisoriesSystems, "?filter[system_profile][sap_sids]=DEF", nil, nil) + w := doTestView(t, PostAdvisoriesSystems, "?filter[system_profile][sap_sids]=DEF", nil, nil, c) var output AdvisoriesSystemsResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, output.Data["RH-1"][0], SystemID("00000000-0000-0000-0000-000000000001")) @@ -101,7 +101,7 @@ func TestSystemAdvisoriesViewWrongOffset(t *testing.T) { func TestAvisorySystemsViewOffsetLimit(t *testing.T) { limit := 3 offset := 0 - w := doTestView(t, PostAdvisoriesSystems, "", &limit, &offset) + w := doTestView(t, PostAdvisoriesSystems, "", &limit, &offset, c) var output AdvisoriesSystemsResponse CheckResponse(t, w, http.StatusOK, &output) assert.Equal(t, 2, len(output.Data)) @@ -114,7 +114,7 @@ func TestAvisorySystemsViewOffsetLimit(t *testing.T) { func TestAvisorySystemsViewOffsetOverflow(t *testing.T) { limit := 1 offset := 100 - w := doTestView(t, PostAdvisoriesSystems, "", &limit, &offset) + w := doTestView(t, PostAdvisoriesSystems, "", &limit, &offset, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) assert.Equal(t, InvalidOffsetMsg, errResp.Error) @@ -122,7 +122,7 @@ func TestAvisorySystemsViewOffsetOverflow(t *testing.T) { func TestAvisorySystemsViewWrongOffset(t *testing.T) { offset := 1000 - w := doTestView(t, PostAdvisoriesSystems, "", nil, &offset) + w := doTestView(t, PostAdvisoriesSystems, "", nil, &offset, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) assert.Equal(t, InvalidOffsetMsg, errResp.Error) From 5d32fcdfc49196ec3eaccf6cf7d5fc4053a3e91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:17:58 +0200 Subject: [PATCH 19/34] RHINENG-25147: replace groups with workspaces: SystemAdvisoriesHandler, SystemAdvisoriesIDsHandler, SystemAdvisoriesExportHandler --- base/database/utils.go | 4 ++-- manager/controllers/system_advisories.go | 8 +++---- .../controllers/system_advisories_export.go | 4 ++-- .../system_advisories_export_test.go | 6 ++--- manager/controllers/system_advisories_test.go | 24 +++++++++---------- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index 6c25a8202..a29f8cd43 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -79,9 +79,9 @@ func PackageByName(tx *gorm.DB, pkgName string, joins ...join) *gorm.DB { return (joinsT)(joins).apply(tx) } -func SystemAdvisoriesByInventoryID(tx *gorm.DB, accountID int, groups map[string]string, inventoryID string, +func SystemAdvisoriesByInventoryID(tx *gorm.DB, accountID int, workspaceIDs []string, inventoryID string, joins ...join) *gorm.DB { - tx = SystemAdvisories(tx, accountID, groups).Where("si.inventory_id = ?::uuid", inventoryID) + tx = SystemAdvisories2(tx, accountID, workspaceIDs).Where("si.inventory_id = ?::uuid", inventoryID) return (joinsT)(joins).apply(tx) } diff --git a/manager/controllers/system_advisories.go b/manager/controllers/system_advisories.go index 2a4e85bf0..34ae6b3bc 100644 --- a/manager/controllers/system_advisories.go +++ b/manager/controllers/system_advisories.go @@ -72,7 +72,7 @@ func (v *RelList) Scan(value interface{}) error { func systemAdvisoriesCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, error) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -105,7 +105,7 @@ func systemAdvisoriesCommon(c *gin.Context) (*gorm.DB, *ListMeta, []string, erro return nil, nil, nil, err } - query := buildSystemAdvisoriesQuery(db, account, groups, inventoryID) + query := buildSystemAdvisoriesQuery(db, account, workspaceIDs, inventoryID) query, meta, params, err := ListCommon(query, c, filters, SystemAdvisoriesOpts) // Error handling and setting of result code & content is done in ListCommon return query, meta, params, err @@ -200,8 +200,8 @@ func SystemAdvisoriesIDsHandler(c *gin.Context) { c.JSON(http.StatusOK, &resp) } -func buildSystemAdvisoriesQuery(db *gorm.DB, account int, groups map[string]string, inventoryID string) *gorm.DB { - query := database.SystemAdvisoriesByInventoryID(db, account, groups, inventoryID, +func buildSystemAdvisoriesQuery(db *gorm.DB, account int, workspaceIDs []string, inventoryID string) *gorm.DB { + query := database.SystemAdvisoriesByInventoryID(db, account, workspaceIDs, inventoryID, database.JoinAdvisoryMetadata, database.JoinAdvisoryType). Joins("JOIN status ON sa.status_id = status.id"). Joins("LEFT JOIN advisory_severity sev ON am.severity_id = sev.id"). diff --git a/manager/controllers/system_advisories_export.go b/manager/controllers/system_advisories_export.go index c094841b6..62814cdfd 100644 --- a/manager/controllers/system_advisories_export.go +++ b/manager/controllers/system_advisories_export.go @@ -34,7 +34,7 @@ import ( // @Router /export/systems/{inventory_id}/advisories [get] func SystemAdvisoriesExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -60,7 +60,7 @@ func SystemAdvisoriesExportHandler(c *gin.Context) { return } - query := buildSystemAdvisoriesQuery(db, account, groups, inventoryID) + query := buildSystemAdvisoriesQuery(db, account, workspaceIDs, inventoryID) query = query.Order("id") query, err = ExportListCommon(query, c, SystemAdvisoriesOpts) if err != nil { diff --git a/manager/controllers/system_advisories_export_test.go b/manager/controllers/system_advisories_export_test.go index 8ee3f29d6..c9f4d19d8 100644 --- a/manager/controllers/system_advisories_export_test.go +++ b/manager/controllers/system_advisories_export_test.go @@ -12,7 +12,7 @@ import ( func TestSystemAdvisoriesExportJSON(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", "", nil, - "application/json", SystemAdvisoriesExportHandler) + "application/json", SystemAdvisoriesExportHandler, c) var output []AdvisoriesDBLookup CheckResponse(t, w, http.StatusOK, &output) @@ -23,7 +23,7 @@ func TestSystemAdvisoriesExportJSON(t *testing.T) { func TestSystemAdvisoriesExportCSV(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", "", nil, - "text/csv", SystemAdvisoriesExportHandler) + "text/csv", SystemAdvisoriesExportHandler, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -39,7 +39,7 @@ func TestSystemAdvisoriesExportCSV(t *testing.T) { func TestUnknownSystemAdvisoriesExport(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "unknownsystem", "", nil, "text/csv", - SystemAdvisoriesExportHandler) + SystemAdvisoriesExportHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } diff --git a/manager/controllers/system_advisories_test.go b/manager/controllers/system_advisories_test.go index 34068131f..7859492a9 100644 --- a/manager/controllers/system_advisories_test.go +++ b/manager/controllers/system_advisories_test.go @@ -13,7 +13,7 @@ import ( func TestSystemAdvisoriesDefault(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", "", nil, "", - SystemAdvisoriesHandler) + SystemAdvisoriesHandler, c) var output SystemAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -34,7 +34,7 @@ func TestSystemAdvisoriesDefault(t *testing.T) { func TestSystemAdvisoriesIDsDefault(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", "", nil, "", - SystemAdvisoriesIDsHandler) + SystemAdvisoriesIDsHandler, c) var output IDsStatusResponse CheckResponse(t, w, http.StatusOK, &output) @@ -48,7 +48,7 @@ func TestSystemAdvisoriesIDsDefault(t *testing.T) { func TestSystemAdvisoriesNotFound(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "nonexistant/advisories", "", nil, "", - SystemAdvisoriesHandler) + SystemAdvisoriesHandler, c) assert.Equal(t, http.StatusNotFound, w.Code) } @@ -56,7 +56,7 @@ func TestSystemAdvisoriesNotFound(t *testing.T) { func TestSystemAdvisoriesIDsNotFound(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "nonexistant/advisories", "", nil, "", - SystemAdvisoriesIDsHandler) + SystemAdvisoriesIDsHandler, c) assert.Equal(t, http.StatusNotFound, w.Code) } @@ -64,7 +64,7 @@ func TestSystemAdvisoriesIDsNotFound(t *testing.T) { func TestSystemAdvisoriesOffsetLimit(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?offset=4&limit=3", nil, "", SystemAdvisoriesHandler) + "?offset=4&limit=3", nil, "", SystemAdvisoriesHandler, c) var output SystemAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -75,7 +75,7 @@ func TestSystemAdvisoriesOffsetLimit(t *testing.T) { func TestSystemAdvisoriesIDsOffsetLimit(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?offset=4&limit=3", nil, "", SystemAdvisoriesIDsHandler) + "?offset=4&limit=3", nil, "", SystemAdvisoriesIDsHandler, c) var output IDsStatusResponse CheckResponse(t, w, http.StatusOK, &output) @@ -89,7 +89,7 @@ func TestSystemAdvisoriesIDsOffsetLimit(t *testing.T) { func TestSystemAdvisoriesOffsetOverflow(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?offset=100&limit=3", nil, "", SystemAdvisoriesHandler) + "?offset=100&limit=3", nil, "", SystemAdvisoriesHandler, c) var errResp utils.ErrorResponse CheckResponse(t, w, http.StatusBadRequest, &errResp) @@ -105,7 +105,7 @@ func TestSystemAdvisoriesPossibleSorts(t *testing.T) { continue } w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - fmt.Sprintf("?sort=%v", sort), nil, "", SystemAdvisoriesHandler) + fmt.Sprintf("?sort=%v", sort), nil, "", SystemAdvisoriesHandler, c) var output SystemAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -116,7 +116,7 @@ func TestSystemAdvisoriesPossibleSorts(t *testing.T) { func TestSystemAdvisoriesWrongSort(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?sort=unknown_key", nil, "", SystemAdvisoriesHandler) + "?sort=unknown_key", nil, "", SystemAdvisoriesHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } @@ -124,7 +124,7 @@ func TestSystemAdvisoriesWrongSort(t *testing.T) { func TestSystemAdvisoriesSearch(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithPath("GET", "/:inventory_id", "00000000-0000-0000-0000-000000000001", - "?search=h-3", nil, "", SystemAdvisoriesHandler) + "?search=h-3", nil, "", SystemAdvisoriesHandler, c) var output SystemAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) @@ -141,12 +141,12 @@ func TestSystemAdvisoriesSearch(t *testing.T) { func TestSystemAdvisoriesWrongOffset(t *testing.T) { doTestWrongOffset(t, "/:inventory_id", "00000000-0000-0000-0000-000000000001", "?offset=1000", - SystemAdvisoriesHandler) + SystemAdvisoriesHandler, c) } func TestSystemAdvisoriesExportUnknown(t *testing.T) { core.SetupTest(t) - w := CreateRequestRouterWithPath("GET", "/:inventory_id", "unknownsystem", "", nil, "", SystemAdvisoriesHandler) + w := CreateRequestRouterWithPath("GET", "/:inventory_id", "unknownsystem", "", nil, "", SystemAdvisoriesHandler, c) assert.Equal(t, http.StatusBadRequest, w.Code) } From 2017a324a0155995e32fd0277e17305142160c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:28:01 +0200 Subject: [PATCH 20/34] RHINENG-25147: remove old database.SystemAdvisories() --- base/database/utils.go | 10 ++-------- manager/controllers/advisories.go | 2 +- manager/controllers/advisory_systems.go | 2 +- manager/controllers/systems_advisories_view.go | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index a29f8cd43..88ff58334 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -42,13 +42,7 @@ func Systems2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) return ApplyInventoryWorkspaceFilter2(tx, workspaceIDs) } -func SystemAdvisories(tx *gorm.DB, accountID int, groups map[string]string, joins ...join) *gorm.DB { - tx = Systems(tx, accountID, groups). - Joins("JOIN system_advisories sa on sa.system_id = si.id AND sa.rh_account_id = ?", accountID) - return (joinsT)(joins).apply(tx) -} - -func SystemAdvisories2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { +func SystemAdvisories(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { tx = Systems2(tx, accountID, workspaceIDs). Joins("JOIN system_advisories sa on sa.system_id = si.id AND sa.rh_account_id = ?", accountID) return (joinsT)(joins).apply(tx) @@ -81,7 +75,7 @@ func PackageByName(tx *gorm.DB, pkgName string, joins ...join) *gorm.DB { func SystemAdvisoriesByInventoryID(tx *gorm.DB, accountID int, workspaceIDs []string, inventoryID string, joins ...join) *gorm.DB { - tx = SystemAdvisories2(tx, accountID, workspaceIDs).Where("si.inventory_id = ?::uuid", inventoryID) + tx = SystemAdvisories(tx, accountID, workspaceIDs).Where("si.inventory_id = ?::uuid", inventoryID) return (joinsT)(joins).apply(tx) } diff --git a/manager/controllers/advisories.go b/manager/controllers/advisories.go index d02f0513c..ba8e020ab 100644 --- a/manager/controllers/advisories.go +++ b/manager/controllers/advisories.go @@ -219,7 +219,7 @@ func buildQueryAdvisories(db *gorm.DB, account int) *gorm.DB { } func buildAdvisoryAccountDataQuery(db *gorm.DB, account int, workspaceIDs []string) *gorm.DB { - query := database.SystemAdvisories2(db, account, workspaceIDs). + query := database.SystemAdvisories(db, account, workspaceIDs). Select(`sa.advisory_id, si.rh_account_id as rh_account_id, count(si.*) filter (where sa.status_id = 0) as systems_installable, count(si.*) as systems_applicable`). diff --git a/manager/controllers/advisory_systems.go b/manager/controllers/advisory_systems.go index e71eda455..f1d8ee2a4 100644 --- a/manager/controllers/advisory_systems.go +++ b/manager/controllers/advisory_systems.go @@ -272,7 +272,7 @@ func AdvisorySystemsListIDsHandler(c *gin.Context) { func buildAdvisorySystemsQuery(db *gorm.DB, account int, workspaceIDs []string, advisoryName string) *gorm.DB { selectQuery := AdvisorySystemsSelect - query := database.SystemAdvisories2(db, account, workspaceIDs, database.JoinTemplates, database.JoinAdvisoryMetadata). + query := database.SystemAdvisories(db, account, workspaceIDs, database.JoinTemplates, database.JoinAdvisoryMetadata). Select(selectQuery). Joins("LEFT JOIN status st ON sa.status_id = st.id"). Where("am.name = ?", advisoryName). diff --git a/manager/controllers/systems_advisories_view.go b/manager/controllers/systems_advisories_view.go index 96ff03161..e7577b46e 100644 --- a/manager/controllers/systems_advisories_view.go +++ b/manager/controllers/systems_advisories_view.go @@ -127,7 +127,7 @@ func advisoriesSystemsQuery(c *gin.Context, db *gorm.DB, acc int, workspaceIDs [ systems := req.Systems advisories := req.Advisories // get all advisories for all systems in the account - advq := database.SystemAdvisories2(db, acc, workspaceIDs, database.JoinAdvisoryMetadata). + advq := database.SystemAdvisories(db, acc, workspaceIDs, database.JoinAdvisoryMetadata). Distinct("am.id, am.name") // we need to join system_advisories to make `limit` work properly // without this join it can happen that we display less items on some pages From 3b148f6baa15519182b2e8c761347d3274019e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:30:31 +0200 Subject: [PATCH 21/34] RHINENG-25147: replace groups with workspaces: PackageSystemsListHandler, PackageSystemsListIDsHandler, PackageSystemsExportHandler --- base/database/utils.go | 8 ++++++++ manager/controllers/package_systems.go | 8 ++++---- manager/controllers/package_systems_export.go | 4 ++-- manager/controllers/package_systems_export_test.go | 6 +++--- manager/controllers/package_systems_test.go | 10 +++++----- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index 88ff58334..fbe75800b 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -62,6 +62,14 @@ func SystemPackages(tx *gorm.DB, accountID int, groups map[string]string, joins return (joinsT)(joins).apply(tx) } +func SystemPackages2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { + tx = Systems2(tx, accountID, workspaceIDs). + Joins("JOIN system_package2 spkg on spkg.system_id = si.id AND spkg.rh_account_id = ?", accountID). + Joins("JOIN package p on p.id = spkg.package_id"). + Joins("JOIN package_name pn on pn.id = spkg.name_id") + return (joinsT)(joins).apply(tx) +} + func Packages(tx *gorm.DB, joins ...join) *gorm.DB { tx = tx.Table("package p"). Joins("JOIN package_name pn on p.name_id = pn.id") diff --git a/manager/controllers/package_systems.go b/manager/controllers/package_systems.go index e6171c08b..77e7d094a 100644 --- a/manager/controllers/package_systems.go +++ b/manager/controllers/package_systems.go @@ -55,9 +55,9 @@ type PackageSystemsResponse struct { Meta ListMeta `json:"meta"` } -func packageSystemsQuery(db *gorm.DB, acc int, groups map[string]string, packageName string, packageIDs []int, +func packageSystemsQuery(db *gorm.DB, acc int, workspaceIDs []string, packageName string, packageIDs []int, ) *gorm.DB { - query := database.SystemPackages(db, acc, groups, + query := database.SystemPackages2(db, acc, workspaceIDs, database.JoinTemplates, database.JoinInstallableApplicablePackages). Select(PackageSystemsSelect). Where("si.stale = false"). @@ -68,7 +68,7 @@ func packageSystemsQuery(db *gorm.DB, acc int, groups map[string]string, package func packageSystemsCommon(db *gorm.DB, c *gin.Context) (*gorm.DB, *ListMeta, []string, error) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) var filters map[string]FilterData packageName := c.Param("package_name") @@ -88,7 +88,7 @@ func packageSystemsCommon(db *gorm.DB, c *gin.Context) (*gorm.DB, *ListMeta, []s return nil, nil, nil, errors.New("package not found") } - query := packageSystemsQuery(db, account, groups, packageName, packageIDs) + query := packageSystemsQuery(db, account, workspaceIDs, packageName, packageIDs) filters, err := ParseAllFilters(c, PackageSystemsOpts) if err != nil { return nil, nil, nil, err diff --git a/manager/controllers/package_systems_export.go b/manager/controllers/package_systems_export.go index 65acc3744..5bac813c4 100644 --- a/manager/controllers/package_systems_export.go +++ b/manager/controllers/package_systems_export.go @@ -33,7 +33,7 @@ import ( // @Router /export/packages/{package_name}/systems [get] func PackageSystemsExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) packageName := c.Param("package_name") if packageName == "" { @@ -53,7 +53,7 @@ func PackageSystemsExportHandler(c *gin.Context) { return } - query := packageSystemsQuery(db, account, groups, packageName, packageIDs) + query := packageSystemsQuery(db, account, workspaceIDs, packageName, packageIDs) filters, err := ParseAllFilters(c, PackageSystemsOpts) if err != nil { return diff --git a/manager/controllers/package_systems_export_test.go b/manager/controllers/package_systems_export_test.go index d588f91b8..062b3d9a8 100644 --- a/manager/controllers/package_systems_export_test.go +++ b/manager/controllers/package_systems_export_test.go @@ -13,7 +13,7 @@ import ( func TestPackageSystemsExportHandlerJSON(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", "kernel", "?sort=id", nil, "application/json", - PackageSystemsExportHandler, 3) + PackageSystemsExportHandler, 3, c) var output []PackageSystemItem CheckResponse(t, w, http.StatusOK, &output) @@ -29,7 +29,7 @@ func TestPackageSystemsExportHandlerJSON(t *testing.T) { func TestPackageSystemsExportHandlerCSV(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", "kernel", "?sort=id", nil, "text/csv", - PackageSystemsExportHandler, 3) + PackageSystemsExportHandler, 3, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -52,7 +52,7 @@ func TestPackageSystemsExportHandlerCSV(t *testing.T) { func TestPackageSystemsExportInvalidName(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", "unknown_package", "", nil, "text/csv", - PackageSystemsExportHandler, 3) + PackageSystemsExportHandler, 3, c) assert.Equal(t, http.StatusNotFound, w.Code) } diff --git a/manager/controllers/package_systems_test.go b/manager/controllers/package_systems_test.go index 056b73cb1..60681b64b 100644 --- a/manager/controllers/package_systems_test.go +++ b/manager/controllers/package_systems_test.go @@ -29,7 +29,7 @@ func TestPackageIDsSystems(t *testing.T) { } func TestPackageSystemsWrongOffset(t *testing.T) { - doTestWrongOffset(t, "/:package_name/systems", "kernel", "?offset=1000", PackageSystemsListHandler) + doTestWrongOffset(t, "/:package_name/systems", "kernel", "?offset=1000", PackageSystemsListHandler, c) } func TestPackageSystemsTagsInvalid(t *testing.T) { @@ -47,7 +47,7 @@ func TestPackageSystemsInvalidName(t *testing.T) { func testPackageSystems(t *testing.T, param, queryString string, account int) PackageSystemsResponse { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", param, queryString, nil, "", - PackageSystemsListHandler, account) + PackageSystemsListHandler, account, c) var output PackageSystemsResponse CheckResponse(t, w, http.StatusOK, &output) @@ -57,7 +57,7 @@ func testPackageSystems(t *testing.T, param, queryString string, account int) Pa func testPackageIDsSystems(t *testing.T, param, queryString string, account int) IDsStatusResponse { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", param, queryString, nil, "", - PackageSystemsListIDsHandler, account) + PackageSystemsListIDsHandler, account, c) var output IDsStatusResponse CheckResponse(t, w, http.StatusOK, &output) @@ -67,7 +67,7 @@ func testPackageIDsSystems(t *testing.T, param, queryString string, account int) func testPackageSystemsError(t *testing.T, param, queryString string, account int) (int, utils.ErrorResponse) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", param, queryString, nil, "", - PackageSystemsListHandler, account) + PackageSystemsListHandler, account, c) var errResp utils.ErrorResponse ParseResponseBody(t, w.Body.Bytes(), &errResp) @@ -77,7 +77,7 @@ func testPackageSystemsError(t *testing.T, param, queryString string, account in func TestPackageSystemsTagsInMetadata(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/systems", "kernel", "?tags=ns1/k3=val4&tags=ns1/k1=val1", - nil, "", PackageSystemsListHandler, 3) + nil, "", PackageSystemsListHandler, 3, c) var output PackageSystemsResponse ParseResponseBody(t, w.Body.Bytes(), &output) From 89acf355e000b58237881b68251e8c04b7c3d702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:33:52 +0200 Subject: [PATCH 22/34] RHINENG-25147: replace groups with workspaces: PackageVersionsListHandler --- manager/controllers/package_versions.go | 8 ++++---- manager/controllers/package_versions_test.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/manager/controllers/package_versions.go b/manager/controllers/package_versions.go index 78bf80a8c..2dc4b6ede 100644 --- a/manager/controllers/package_versions.go +++ b/manager/controllers/package_versions.go @@ -45,8 +45,8 @@ func packagesNameID(db *gorm.DB, pkgName string) *gorm.DB { Where("pn.name = ?", pkgName) } -func packageVersionsQuery(db *gorm.DB, acc int, groups map[string]string, packageNameIDs []int) *gorm.DB { - query := database.SystemPackages(db, acc, groups). +func packageVersionsQuery(db *gorm.DB, acc int, workspaceIDs []string, packageNameIDs []int) *gorm.DB { + query := database.SystemPackages2(db, acc, workspaceIDs). Distinct(PackageVersionSelect). Where("si.stale = false"). Where("spkg.name_id in (?)", packageNameIDs) @@ -69,7 +69,7 @@ func packageVersionsQuery(db *gorm.DB, acc int, groups map[string]string, packag // @Router /packages/{package_name}/versions [get] func PackageVersionsListHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) packageName := c.Param("package_name") if packageName == "" { @@ -89,7 +89,7 @@ func PackageVersionsListHandler(c *gin.Context) { return } - query := packageVersionsQuery(db, account, groups, packageNameIDs) + query := packageVersionsQuery(db, account, workspaceIDs, packageNameIDs) // we don't support tags and filters for this endpoint query, meta, params, err := ListCommon(query, c, nil, PackageVersionsOpts) if err != nil { diff --git a/manager/controllers/package_versions_test.go b/manager/controllers/package_versions_test.go index 231874411..868ed5e81 100644 --- a/manager/controllers/package_versions_test.go +++ b/manager/controllers/package_versions_test.go @@ -11,7 +11,7 @@ import ( func TestPackageVersions(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/versions", "firefox", "", nil, "", - PackageVersionsListHandler, 3) + PackageVersionsListHandler, 3, c) var output PackageVersionsResponse assert.Greater(t, len(w.Body.Bytes()), 0) @@ -23,7 +23,7 @@ func TestPackageVersions(t *testing.T) { func TestPackageVersionsInvalidName(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:package_name/versions", "not-existing", "", nil, "", - PackageVersionsListHandler, 3) + PackageVersionsListHandler, 3, c) assert.Equal(t, http.StatusNotFound, w.Code) } From d980a15fa7d92bb784b2157917c699493f6a40af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:34:39 +0200 Subject: [PATCH 23/34] RHINENG-25147: replace groups with workspaces: SystemPackagesHandler, SystemPackagesExportHandler --- manager/controllers/system_packages.go | 8 ++++---- manager/controllers/system_packages_export.go | 4 ++-- .../controllers/system_packages_export_test.go | 6 +++--- manager/controllers/system_packages_test.go | 16 ++++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/manager/controllers/system_packages.go b/manager/controllers/system_packages.go index fecf585c4..6a4e2617c 100644 --- a/manager/controllers/system_packages.go +++ b/manager/controllers/system_packages.go @@ -56,8 +56,8 @@ type SystemPackageDBLoad struct { MetaTotalHelper } -func systemPackageQuery(db *gorm.DB, account int, groups map[string]string, inventoryID string) *gorm.DB { - query := database.SystemPackages(db, account, groups, database.JoinInstallableApplicablePackages). +func systemPackageQuery(db *gorm.DB, account int, workspaceIDs []string, inventoryID string) *gorm.DB { + query := database.SystemPackages2(db, account, workspaceIDs, database.JoinInstallableApplicablePackages). Joins("LEFT JOIN strings AS descr ON p.description_hash = descr.id"). Joins("LEFT JOIN strings AS sum ON p.summary_hash = sum.id"). Select(SystemPackagesSelect). @@ -89,7 +89,7 @@ func systemPackageQuery(db *gorm.DB, account int, groups map[string]string, inve // @Router /systems/{inventory_id}/packages [get] func SystemPackagesHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -108,7 +108,7 @@ func SystemPackagesHandler(c *gin.Context) { } var loaded []SystemPackageDBLoad db := middlewares.DBFromContext(c) - q := systemPackageQuery(db, account, groups, inventoryID) + q := systemPackageQuery(db, account, workspaceIDs, inventoryID) q, meta, params, err := ListCommon(q, c, filters, SystemPackagesOpts) if err != nil { return diff --git a/manager/controllers/system_packages_export.go b/manager/controllers/system_packages_export.go index d585307b8..64ba60526 100644 --- a/manager/controllers/system_packages_export.go +++ b/manager/controllers/system_packages_export.go @@ -37,7 +37,7 @@ type SystemPackageInline struct { // @Router /export/systems/{inventory_id}/packages [get] func SystemPackagesExportHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) inventoryID := c.Param("inventory_id") if inventoryID == "" { @@ -52,7 +52,7 @@ func SystemPackagesExportHandler(c *gin.Context) { var loaded []SystemPackageDBLoad db := middlewares.DBFromContext(c) - q := systemPackageQuery(db, account, groups, inventoryID) + q := systemPackageQuery(db, account, workspaceIDs, inventoryID) q, err := ExportListCommon(q, c, SystemPackagesOpts) if err != nil { // Error handling and setting of result code & content is done in ListCommon diff --git a/manager/controllers/system_packages_export_test.go b/manager/controllers/system_packages_export_test.go index cd9add4e8..c79a68ef4 100644 --- a/manager/controllers/system_packages_export_test.go +++ b/manager/controllers/system_packages_export_test.go @@ -12,7 +12,7 @@ import ( func TestSystemPackagesExportHandlerJSON(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", "", - nil, "application/json", SystemPackagesExportHandler, 3) + nil, "application/json", SystemPackagesExportHandler, 3, c) var output []SystemPackageInline CheckResponse(t, w, http.StatusOK, &output) @@ -31,7 +31,7 @@ func TestSystemPackagesExportHandlerJSON(t *testing.T) { func TestSystemPackagesExportHandlerCSV(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", "", - nil, "text/csv", SystemPackagesExportHandler, 3) + nil, "text/csv", SystemPackagesExportHandler, 3, c) assert.Equal(t, http.StatusOK, w.Code) body := w.Body.String() @@ -56,7 +56,7 @@ func TestSystemPackagesExportHandlerCSV(t *testing.T) { func TestSystemPackagesExportUnknown(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "unknownsystem", "", nil, "text/csv", - SystemPackagesExportHandler, 3) + SystemPackagesExportHandler, 3, c) assert.Equal(t, http.StatusBadRequest, w.Code) } diff --git a/manager/controllers/system_packages_test.go b/manager/controllers/system_packages_test.go index 816af29e8..d0fcaa820 100644 --- a/manager/controllers/system_packages_test.go +++ b/manager/controllers/system_packages_test.go @@ -11,7 +11,7 @@ import ( func TestSystemPackages(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", "", - nil, "", SystemPackagesHandler, 3) + nil, "", SystemPackagesHandler, 3, c) var output SystemPackageResponse CheckResponse(t, w, http.StatusOK, &output) @@ -30,7 +30,7 @@ func TestSystemPackages(t *testing.T) { func TestPackagesSearch(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000012", - "?search=kernel", nil, "", SystemPackagesHandler, 3) + "?search=kernel", nil, "", SystemPackagesHandler, 3, c) var output SystemPackageResponse CheckResponse(t, w, http.StatusOK, &output) @@ -41,7 +41,7 @@ func TestPackagesSearch(t *testing.T) { func TestNoPackages(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000001", "", - nil, "", SystemPackagesHandler, 1) + nil, "", SystemPackagesHandler, 1, c) assert.Equal(t, http.StatusOK, w.Code) } @@ -49,7 +49,7 @@ func TestNoPackages(t *testing.T) { func TestSystemPackagesUpdatableOnly(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", - "?filter[updatable]=true", nil, "", SystemPackagesHandler, 3) + "?filter[updatable]=true", nil, "", SystemPackagesHandler, 3, c) var output SystemPackageResponse CheckResponse(t, w, http.StatusOK, &output) @@ -60,7 +60,7 @@ func TestSystemPackagesUpdatableOnly(t *testing.T) { func TestSystemPackagesName(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", - "?filter[name]=firefox", nil, "", SystemPackagesHandler, 3) + "?filter[name]=firefox", nil, "", SystemPackagesHandler, 3, c) var output SystemPackageResponse CheckResponse(t, w, http.StatusOK, &output) @@ -71,7 +71,7 @@ func TestSystemPackagesName(t *testing.T) { func TestSystemPackagesNonUpdatableOnly(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "00000000-0000-0000-0000-000000000013", - "?filter[updatable]=false", nil, "", SystemPackagesHandler, 3) + "?filter[updatable]=false", nil, "", SystemPackagesHandler, 3, c) var output SystemPackageResponse CheckResponse(t, w, http.StatusOK, &output) @@ -83,13 +83,13 @@ func TestSystemPackagesNonUpdatableOnly(t *testing.T) { func TestSystemPackagesWrongOffset(t *testing.T) { doTestWrongOffset(t, "/:inventory_id/packages", - "00000000-0000-0000-0000-000000000001", "?offset=1000", SystemPackagesHandler) + "00000000-0000-0000-0000-000000000001", "?offset=1000", SystemPackagesHandler, c) } func TestSystemPackagesUnknown(t *testing.T) { core.SetupTest(t) w := CreateRequestRouterWithParams("GET", "/:inventory_id/packages", "unknownsystem", "", nil, "", - SystemPackagesHandler, 3) + SystemPackagesHandler, 3, c) assert.Equal(t, http.StatusBadRequest, w.Code) } From ac6ea05c2c415923cf39c2fd0468919f10949b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:36:09 +0200 Subject: [PATCH 24/34] RHINENG-25147: remove old database.SystemPackages() --- base/database/utils.go | 10 +--------- manager/controllers/package_systems.go | 2 +- manager/controllers/package_versions.go | 2 +- manager/controllers/system_packages.go | 2 +- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index fbe75800b..cae4ed97b 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -54,15 +54,7 @@ func SystemPackagesShort(tx *gorm.DB, accountID int, joins ...join) *gorm.DB { return (joinsT)(joins).apply(tx) } -func SystemPackages(tx *gorm.DB, accountID int, groups map[string]string, joins ...join) *gorm.DB { - tx = Systems(tx, accountID, groups). - Joins("JOIN system_package2 spkg on spkg.system_id = si.id AND spkg.rh_account_id = ?", accountID). - Joins("JOIN package p on p.id = spkg.package_id"). - Joins("JOIN package_name pn on pn.id = spkg.name_id") - return (joinsT)(joins).apply(tx) -} - -func SystemPackages2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { +func SystemPackages(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { tx = Systems2(tx, accountID, workspaceIDs). Joins("JOIN system_package2 spkg on spkg.system_id = si.id AND spkg.rh_account_id = ?", accountID). Joins("JOIN package p on p.id = spkg.package_id"). diff --git a/manager/controllers/package_systems.go b/manager/controllers/package_systems.go index 77e7d094a..bd7279298 100644 --- a/manager/controllers/package_systems.go +++ b/manager/controllers/package_systems.go @@ -57,7 +57,7 @@ type PackageSystemsResponse struct { func packageSystemsQuery(db *gorm.DB, acc int, workspaceIDs []string, packageName string, packageIDs []int, ) *gorm.DB { - query := database.SystemPackages2(db, acc, workspaceIDs, + query := database.SystemPackages(db, acc, workspaceIDs, database.JoinTemplates, database.JoinInstallableApplicablePackages). Select(PackageSystemsSelect). Where("si.stale = false"). diff --git a/manager/controllers/package_versions.go b/manager/controllers/package_versions.go index 2dc4b6ede..07df60435 100644 --- a/manager/controllers/package_versions.go +++ b/manager/controllers/package_versions.go @@ -46,7 +46,7 @@ func packagesNameID(db *gorm.DB, pkgName string) *gorm.DB { } func packageVersionsQuery(db *gorm.DB, acc int, workspaceIDs []string, packageNameIDs []int) *gorm.DB { - query := database.SystemPackages2(db, acc, workspaceIDs). + query := database.SystemPackages(db, acc, workspaceIDs). Distinct(PackageVersionSelect). Where("si.stale = false"). Where("spkg.name_id in (?)", packageNameIDs) diff --git a/manager/controllers/system_packages.go b/manager/controllers/system_packages.go index 6a4e2617c..337298a52 100644 --- a/manager/controllers/system_packages.go +++ b/manager/controllers/system_packages.go @@ -57,7 +57,7 @@ type SystemPackageDBLoad struct { } func systemPackageQuery(db *gorm.DB, account int, workspaceIDs []string, inventoryID string) *gorm.DB { - query := database.SystemPackages2(db, account, workspaceIDs, database.JoinInstallableApplicablePackages). + query := database.SystemPackages(db, account, workspaceIDs, database.JoinInstallableApplicablePackages). Joins("LEFT JOIN strings AS descr ON p.description_hash = descr.id"). Joins("LEFT JOIN strings AS sum ON p.summary_hash = sum.id"). Select(SystemPackagesSelect). From e6c1a774aef8250cad39f2e1053639275bb5d908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:42:53 +0200 Subject: [PATCH 25/34] RHINENG-25147: remove old database.Systems() --- base/database/utils.go | 14 ++-------- manager/controllers/packages.go | 2 +- manager/controllers/system_detail.go | 4 +-- manager/controllers/systems.go | 2 +- manager/controllers/systemtags.go | 2 +- manager/controllers/template_systems.go | 2 +- .../controllers/template_systems_update.go | 6 ++-- manager/controllers/templates.go | 2 +- manager/controllers/utils_test.go | 28 ++----------------- 9 files changed, 15 insertions(+), 47 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index cae4ed97b..d4b5bfd84 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -26,15 +26,7 @@ func (j joinsT) apply(tx *gorm.DB) *gorm.DB { return tx } -func Systems(tx *gorm.DB, accountID int, groups map[string]string, joins ...join) *gorm.DB { - tx = tx.Table("system_inventory si"). - Joins("JOIN system_patch spatch ON si.id = spatch.system_id AND si.rh_account_id = spatch.rh_account_id"). - Where("si.rh_account_id = ?", accountID) - tx = (joinsT)(joins).apply(tx) - return ApplyInventoryWorkspaceFilter(tx, groups) -} - -func Systems2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { +func Systems(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { tx = tx.Table("system_inventory si"). Joins("JOIN system_patch spatch ON si.id = spatch.system_id AND si.rh_account_id = spatch.rh_account_id"). Where("si.rh_account_id = ?", accountID) @@ -43,7 +35,7 @@ func Systems2(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) } func SystemAdvisories(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { - tx = Systems2(tx, accountID, workspaceIDs). + tx = Systems(tx, accountID, workspaceIDs). Joins("JOIN system_advisories sa on sa.system_id = si.id AND sa.rh_account_id = ?", accountID) return (joinsT)(joins).apply(tx) } @@ -55,7 +47,7 @@ func SystemPackagesShort(tx *gorm.DB, accountID int, joins ...join) *gorm.DB { } func SystemPackages(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { - tx = Systems2(tx, accountID, workspaceIDs). + tx = Systems(tx, accountID, workspaceIDs). Joins("JOIN system_package2 spkg on spkg.system_id = si.id AND spkg.rh_account_id = ?", accountID). Joins("JOIN package p on p.id = spkg.package_id"). Joins("JOIN package_name pn on pn.id = spkg.name_id") diff --git a/manager/controllers/packages.go b/manager/controllers/packages.go index d05457cf9..ea4d14de0 100644 --- a/manager/controllers/packages.go +++ b/manager/controllers/packages.go @@ -65,7 +65,7 @@ func packagesQuery(db *gorm.DB, filters map[string]FilterData, acc int, workspac return q } middlewares.PackageAccountDataCnt.WithLabelValues("miss").Inc() - systemsWithPkgsInstalledQ := database.Systems2(db, acc, workspaceIDs). + systemsWithPkgsInstalledQ := database.Systems(db, acc, workspaceIDs). Select("si.id"). Where("si.stale = false AND spatch.packages_installed > 0") diff --git a/manager/controllers/system_detail.go b/manager/controllers/system_detail.go index 5cf3a10fe..02d6c93a3 100644 --- a/manager/controllers/system_detail.go +++ b/manager/controllers/system_detail.go @@ -63,7 +63,7 @@ func SystemDetailHandler(c *gin.Context) { var systemDetail SystemDetailLookup db := middlewares.DBFromContext(c) - query := database.Systems2(db, account, workspaceIDs, database.JoinTemplates). + query := database.Systems(db, account, workspaceIDs, database.JoinTemplates). Select(database.MustGetSelect(&systemDetail)). Where("si.inventory_id = ?::uuid", inventoryID) @@ -173,7 +173,7 @@ func systemJSONsCommon(c *gin.Context, column string) *models.SystemInventory { var system models.SystemInventory db := middlewares.DBFromContext(c) - query := database.Systems2(db, account, workspaceIDs). + query := database.Systems(db, account, workspaceIDs). Select(column). Where("si.inventory_id = ?::uuid", inventoryID) diff --git a/manager/controllers/systems.go b/manager/controllers/systems.go index 87b9a1406..7c9c993f1 100644 --- a/manager/controllers/systems.go +++ b/manager/controllers/systems.go @@ -359,5 +359,5 @@ func SystemsListIDsHandler(c *gin.Context) { } func querySystems(db *gorm.DB, account int, workspaceIDs []string) *gorm.DB { - return database.Systems2(db, account, workspaceIDs, database.JoinTemplates).Select(SystemsSelect) + return database.Systems(db, account, workspaceIDs, database.JoinTemplates).Select(SystemsSelect) } diff --git a/manager/controllers/systemtags.go b/manager/controllers/systemtags.go index 0153f1b52..adec630bb 100644 --- a/manager/controllers/systemtags.go +++ b/manager/controllers/systemtags.go @@ -69,7 +69,7 @@ func SystemTagListHandler(c *gin.Context) { db := middlewares.DBFromContext(c) // https://stackoverflow.com/questions/33474778/how-to-group-result-by-array-column-in-postgres - sq := database.Systems2(db, account, workspaceIDs). + sq := database.Systems(db, account, workspaceIDs). Select("jsonb_array_elements(si.tags) AS tag") query := db.Table("(?) AS sq", sq). diff --git a/manager/controllers/template_systems.go b/manager/controllers/template_systems.go index 686d090f8..fd2e4ccee 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -86,7 +86,7 @@ func templateSystemsQuery(c *gin.Context, account int, workspaceIDs []string) (* return nil, nil, err } - query := database.Systems2(db, account, workspaceIDs). + query := database.Systems(db, account, workspaceIDs). Where("spatch.template_id = ?", template.ID). Select(templateSystemSelect) diff --git a/manager/controllers/template_systems_update.go b/manager/controllers/template_systems_update.go index fa0c1d7e1..2d4591eab 100644 --- a/manager/controllers/template_systems_update.go +++ b/manager/controllers/template_systems_update.go @@ -175,7 +175,7 @@ func templateArchVersionMatch( Version string }{} var err error - err = database.Systems2(db, acc, workspaceIDs). + err = database.Systems(db, acc, workspaceIDs). Select("si.inventory_id as inventory_id, si.os_major as version, si.arch as arch"). Where("si.inventory_id in (?)", inventoryIDs).Find(&sysArchVersions).Error if err != nil { @@ -226,7 +226,7 @@ func assignCandlepinEnvironment(c *gin.Context, db *gorm.DB, accountID int, env Consumer *string }{} - err := database.Systems2(db, accountID, workspaceIDs). + err := database.Systems(db, accountID, workspaceIDs). Select("si.inventory_id as inventory_id, si.subscription_manager_id as consumer"). Where("si.inventory_id in (?)", inventoryIDs).Find(&hosts).Error if err != nil { @@ -275,7 +275,7 @@ func checkInventoryIDs(db *gorm.DB, accountID int, inventoryIDs []string, worksp var missingIDs []string var satelliteIDs []string var bootcIDs []string - err = database.Systems2(db, accountID, workspaceIDs). + err = database.Systems(db, accountID, workspaceIDs). Select("si.inventory_id, si.satellite_managed, si.bootc"). Where("si.inventory_id IN (?::uuid)", inventoryIDs). Scan(&containingSystems).Error diff --git a/manager/controllers/templates.go b/manager/controllers/templates.go index ec766443b..d58a92306 100644 --- a/manager/controllers/templates.go +++ b/manager/controllers/templates.go @@ -124,7 +124,7 @@ func TemplatesListHandler(c *gin.Context) { } func templatesQuery(db *gorm.DB, filters map[string]FilterData, account int, workspaceIDs []string) *gorm.DB { - subq := database.Systems2(db, account, workspaceIDs). + subq := database.Systems(db, account, workspaceIDs). Select("spatch.template_id, count(*) as systems"). Group("spatch.template_id") diff --git a/manager/controllers/utils_test.go b/manager/controllers/utils_test.go index 39dadc955..7216b380d 100644 --- a/manager/controllers/utils_test.go +++ b/manager/controllers/utils_test.go @@ -21,22 +21,9 @@ func TestGroupNameFilter(t *testing.T) { filters, err := ParseAllFilters(c, ListOpts{}) assert.Nil(t, err) - var systems []SystemsID - groups := map[string]string{ - utils.KeyGrouped: `{"[{\"id\":\"inventory-group-1\"}]","[{\"id\":\"inventory-group-2\"}]"}`, - } - tx := database.Systems(database.DB, 1, groups) - tx, _ = ApplyInventoryFilter(filters, tx, "si.inventory_id") - tx.Scan(&systems) - - assert.Equal(t, 2, len(systems)) // 2 systems with `group2` in test_data - assert.Equal(t, "00000000-0000-0000-0000-000000000007", systems[0].ID) - assert.Equal(t, "00000000-0000-0000-0000-000000000008", systems[1].ID) - - // ensure the workspaces work the same as groups var systems2 []SystemsID workspaceIDs := []string{"inventory-group-1", "inventory-group-2"} - ty := database.Systems2(database.DB, 1, workspaceIDs) + ty := database.Systems(database.DB, 1, workspaceIDs) ty, _ = ApplyInventoryFilter(filters, ty, "si.inventory_id") ty.Scan(&systems2) @@ -55,20 +42,9 @@ func TestGroupNameFilter2(t *testing.T) { filters, err := ParseAllFilters(c, ListOpts{}) assert.Nil(t, err) - var systems []SystemsID - groups := map[string]string{ - utils.KeyGrouped: `{"[{\"id\":\"inventory-group-1\"}]","[{\"id\":\"inventory-group-2\"}]"}`, - } - tx := database.Systems(database.DB, 1, groups) - tx, _ = ApplyInventoryFilter(filters, tx, "si.inventory_id") - tx.Scan(&systems) - - assert.Equal(t, 9, len(systems)) // 2 systems with `group2`, 6 with `group1` in test_data - - // ensure the workspaces work the same as groups var systems2 []SystemsID workspaceIDs := []string{"inventory-group-1", "inventory-group-2"} - ty := database.Systems2(database.DB, 1, workspaceIDs) + ty := database.Systems(database.DB, 1, workspaceIDs) ty, _ = ApplyInventoryFilter(filters, ty, "si.inventory_id") ty.Scan(&systems2) From 9efc7ca18ad726ff16ffa52c1940b0adfce17a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:52:14 +0200 Subject: [PATCH 26/34] RHINENG-25147: remove old database.ApplyInventoryWorkspaceFilter() --- base/database/utils.go | 21 ++----------- base/database/utils_test.go | 31 +++++++------------ .../controllers/systems_advisories_view.go | 2 +- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/base/database/utils.go b/base/database/utils.go index d4b5bfd84..cb7675051 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -31,7 +31,7 @@ func Systems(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) * Joins("JOIN system_patch spatch ON si.id = spatch.system_id AND si.rh_account_id = spatch.rh_account_id"). Where("si.rh_account_id = ?", accountID) tx = (joinsT)(joins).apply(tx) - return ApplyInventoryWorkspaceFilter2(tx, workspaceIDs) + return ApplyInventoryWorkspaceFilter(tx, workspaceIDs) } func SystemAdvisories(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { @@ -240,30 +240,13 @@ func ReadReplicaConfigured() bool { return len(utils.CoreCfg.DBReadReplicaHost) > 0 && utils.CoreCfg.DBReadReplicaPort != 0 } -func ApplyInventoryWorkspaceFilter2(tx *gorm.DB, workspaceIDs []string) *gorm.DB { +func ApplyInventoryWorkspaceFilter(tx *gorm.DB, workspaceIDs []string) *gorm.DB { if len(workspaceIDs) == 0 { utils.LogWarn("there should always be some workspaces, at least root workspace") } return tx.Where("si.workspace_id IN (?)", workspaceIDs) } -func ApplyInventoryWorkspaceFilter(tx *gorm.DB, groups map[string]string) *gorm.DB { - if _, ok := groups[utils.KeyGrouped]; !ok { - if _, ok := groups[utils.KeyUngrouped]; ok { - // show only systems with '[]' group - return tx.Where("si.workspaces = '[]'") - } - // return query without WHERE if there are no groups - return tx - } - - db := DB.Where("si.workspaces @> ANY (?::jsonb[])", groups[utils.KeyGrouped]) - if _, ok := groups[utils.KeyUngrouped]; ok { - db = db.Or("si.workspaces = '[]'") - } - return tx.Where(db) -} - // LEFT JOIN templates to spatch (system_patch) func JoinTemplates(tx *gorm.DB) *gorm.DB { return tx.Joins("LEFT JOIN template t ON spatch.template_id = t.id AND spatch.rh_account_id = t.rh_account_id") diff --git a/base/database/utils_test.go b/base/database/utils_test.go index 358b3e6c1..9348fce56 100644 --- a/base/database/utils_test.go +++ b/base/database/utils_test.go @@ -11,26 +11,19 @@ var ( // counts of systems from system_inventory (+ system_patch join in Systems()) nGroup1 int64 = 7 nGroup2 int64 = 2 - nUngrouped int64 = 7 + nUngrouped int64 = 9 nAll int64 = 18 ) -var testCases = []map[int64]map[string]string{ - {nGroup1: {utils.KeyGrouped: `{"[{\"id\":\"inventory-group-1\"}]"}`}}, - {nGroup2: {utils.KeyGrouped: `{"[{\"id\":\"inventory-group-2\"}]"}`}}, - {nGroup1 + nGroup2: {utils.KeyGrouped: `{"[{\"id\":\"inventory-group-1\"}]","[{\"id\":\"inventory-group-2\"}]"}`}}, - {nGroup1 + nUngrouped: { - utils.KeyGrouped: `{"[{\"id\":\"inventory-group-1\"}]"}`, - utils.KeyUngrouped: "[]", - }}, - {nUngrouped: { - utils.KeyGrouped: `{"[{\"id\":\"non-existing-group\"}]"}`, - utils.KeyUngrouped: "[]", - }}, - {0: {utils.KeyGrouped: `{"[{\"id\":\"non-existing-group\"}]"}`}}, - {nUngrouped: {utils.KeyUngrouped: "[]"}}, - {nAll: {}}, - {nAll: nil}, +var testCases = []map[int64][]string{ + {nGroup1: {"inventory-group-1"}}, + {nGroup2: {"inventory-group-2"}}, + {nGroup1 + nGroup2: {"inventory-group-1", "inventory-group-2"}}, + {nGroup1 + nUngrouped: {"inventory-group-1", "root-workspace"}}, + {nUngrouped: {"non-existing-group", "root-workspace"}}, + {0: {"non-existing-group"}}, + {nUngrouped: {"root-workspace"}}, + {nAll: {"inventory-group-1", "inventory-group-2", "root-workspace"}}, } func TestApplyInventoryWorkspaceFilter(t *testing.T) { @@ -38,11 +31,11 @@ func TestApplyInventoryWorkspaceFilter(t *testing.T) { Configure() for _, tc := range testCases { - for expectedCount, groups := range tc { + for expectedCount, workspaceIDs := range tc { var count int64 ApplyInventoryWorkspaceFilter(DB.Table("system_inventory si"). Joins("JOIN system_patch spatch ON si.id = spatch.system_id AND si.rh_account_id = spatch.rh_account_id"), - groups).Count(&count) + workspaceIDs).Count(&count) assert.Equal(t, expectedCount, count) } } diff --git a/manager/controllers/systems_advisories_view.go b/manager/controllers/systems_advisories_view.go index e7577b46e..f6166cc6f 100644 --- a/manager/controllers/systems_advisories_view.go +++ b/manager/controllers/systems_advisories_view.go @@ -76,7 +76,7 @@ func systemsAdvisoriesQuery(c *gin.Context, db *gorm.DB, acc int, workspaceIDs [ req SystemsAdvisoriesRequest) (*gorm.DB, *ListMeta, *Links, error) { systems := req.Systems advisories := req.Advisories - sysq := database.ApplyInventoryWorkspaceFilter2( + sysq := database.ApplyInventoryWorkspaceFilter( db.Table("system_inventory si"). Where("si.rh_account_id = ?", acc), workspaceIDs). From 97577f9431b645e796b2c85b89de5d9b8b971f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 15:59:37 +0200 Subject: [PATCH 27/34] RHINENG-25147: refactor filtering by group_name --- manager/controllers/utils.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/manager/controllers/utils.go b/manager/controllers/utils.go index 416564a9e..a2ab02d5c 100644 --- a/manager/controllers/utils.go +++ b/manager/controllers/utils.go @@ -392,18 +392,7 @@ func ApplyInventoryWhere(filters map[string]FilterData, tx *gorm.DB) (*gorm.DB, // returns "(si.mssql_workload_version) = 1.0" func buildInventoryQuery(tx *gorm.DB, key string, values []string) *gorm.DB { if strings.Contains(key, "group_name") { - groups := []string{} - for _, v := range values { - name := v - group, err := utils.ParseInventoryGroup(nil, &name) - if err != nil { - // couldn't marshal inventory group to json - continue - } - groups = append(groups, group) - } - jsonq := fmt.Sprintf("{%s}", strings.Join(groups, ",")) - return tx.Where("si.workspaces @> ANY (?::jsonb[])", jsonq) + return tx.Where("si.workspace_name IN (?)", values) } var cmp string From 3b8ad95a22fe682cbf37433163e6e62fac664e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Thu, 23 Apr 2026 16:37:49 +0200 Subject: [PATCH 28/34] RHINENG-25147: refactor workspaces in system_inventory model --- base/models/models.go | 2 ++ listener/common_test.go | 16 ++++++++++++++-- listener/upload.go | 19 +++++++++++++++++++ listener/upload_test.go | 12 +++++++++++- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/base/models/models.go b/base/models/models.go index 25771cc6d..100c8c1b9 100644 --- a/base/models/models.go +++ b/base/models/models.go @@ -74,6 +74,8 @@ type SystemInventory struct { Tags []byte `gorm:"column:tags"` Created time.Time // set by trigger system_platform_insert_trigger Workspaces *inventory.Groups `gorm:"column:workspaces"` + WorkspaceID *string `gorm:"column:workspace_id"` + WorkspaceName *string `gorm:"column:workspace_name"` StaleTimestamp *time.Time StaleWarningTimestamp *time.Time CulledTimestamp *time.Time diff --git a/listener/common_test.go b/listener/common_test.go index 3df43e157..19883dbb3 100644 --- a/listener/common_test.go +++ b/listener/common_test.go @@ -86,7 +86,7 @@ func assertSystemInDB(t *testing.T, inventoryID string, rhAccountID *int, report // assertSystemInventoryProfileMatchesHost checks host-derived system_inventory columns written by // storeOrUpdateSysPlatform (must stay in sync on ON CONFLICT DO UPDATE, not only on first insert). -// nolint: unparam +// nolint: unparam,funlen func assertSystemInventoryProfileMatchesHost(t *testing.T, inventoryID string, host *Host) { t.Helper() var inv models.SystemInventory @@ -96,6 +96,18 @@ func assertSystemInventoryProfileMatchesHost(t *testing.T, inventoryID string, h require.NotNil(t, inv.Workspaces) assert.Equal(t, host.Groups, []inventory.Group(*inv.Workspaces)) + if hostWorkspaceID := host.Groups[0].ID; hostWorkspaceID != "" { + require.NotNil(t, inv.WorkspaceID) + assert.Equal(t, hostWorkspaceID, *inv.WorkspaceID) + } else { + require.Nil(t, inv.WorkspaceID) + } + if hostWorkspaceName := host.Groups[0].Name; hostWorkspaceName != "" { + require.NotNil(t, inv.WorkspaceName) + assert.Equal(t, hostWorkspaceName, *inv.WorkspaceName) + } else { + require.Nil(t, inv.WorkspaceName) + } if host.SystemProfile.OperatingSystem.Name != "" { require.NotNil(t, inv.OSName) @@ -184,7 +196,7 @@ func createTestUploadEvent(orgID, inventoryID, reporter string, packages, yum bo reporter: {LastCheckIn: types.Rfc3339TimestampWithZ(now)}, }, Tags: []byte(`{"namespace": "insights-client","key": "env","value": "prod"}`), - Groups: []inventory.Group{{ID: "group1"}}, + Groups: []inventory.Group{{ID: "group1", Name: "group1"}}, SystemProfile: inventory.SystemProfile{ OperatingSystem: inventory.OperatingSystem{ Name: "RHEL", diff --git a/listener/upload.go b/listener/upload.go index 27189e364..eb49dc4dc 100644 --- a/listener/upload.go +++ b/listener/upload.go @@ -337,6 +337,8 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, "bootc", "tags", "workspaces", + "workspace_id", + "workspace_name", "os_name", "os_major", "os_minor", @@ -359,6 +361,21 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, updatesReqJSONString := string(updatesReqJSON) hostWorkspaces := inventory.Groups(host.Groups) + var workspaceID, workspaceName *string + if l := len(host.Groups); l >= 1 { + if host.Groups[0].ID != "" { + workspaceID = &host.Groups[0].ID + } + if host.Groups[0].Name != "" { + workspaceName = &host.Groups[0].Name + } + if l != 1 { + utils.LogWarn( + "host_id", host.ID, "org_id", host.OrgID, "workspaces", host.Groups, + "received a host with multiple workspaces", + ) + } + } systemPlatform := &models.SystemPlatformV2{ Inventory: models.SystemInventory{ InventoryID: inventoryID, @@ -367,6 +384,8 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, Created: host.Created, Tags: utils.MarshalNilToJSONB(host.Tags), Workspaces: &hostWorkspaces, + WorkspaceID: workspaceID, + WorkspaceName: workspaceName, VmaasJSON: utils.EmptyToNil(&updatesReqJSONString), JSONChecksum: utils.EmptyToNil(&jsonChecksum), LastUpload: host.GetLastUpload(), diff --git a/listener/upload_test.go b/listener/upload_test.go index 8b75e6d43..696b59ee0 100644 --- a/listener/upload_test.go +++ b/listener/upload_test.go @@ -478,6 +478,8 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { // insert new row hostEvent := createTestUploadEvent("1", id, "puptoo", false, true, "created") hostWorkspaces := inventory.Groups(hostEvent.Host.Groups) + workspaceID := &hostEvent.Host.Groups[0].ID + workspaceName := &hostEvent.Host.Groups[0].Name inStore := &models.SystemPlatformV2{ Inventory: models.SystemInventory{ InventoryID: "99990000-0000-0000-0000-000000000001", @@ -488,6 +490,8 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { Created: hostEvent.Host.Created, Tags: utils.MarshalNilToJSONB(hostEvent.Host.Tags), Workspaces: &hostWorkspaces, + WorkspaceID: workspaceID, + WorkspaceName: workspaceName, OSName: utils.EmptyToNil(&hostEvent.Host.SystemProfile.OperatingSystem.Name), OSMajor: &hostEvent.Host.SystemProfile.OperatingSystem.Major, OSMinor: &hostEvent.Host.SystemProfile.OperatingSystem.Minor, @@ -504,7 +508,7 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { } err := storeOrUpdateSysPlatform(database.DB, inStore, colsToUpdate) - assert.Nil(t, err) + require.Nil(t, err) var outStore models.SystemInventory assert.NoError(t, database.DB.Where("id = ? AND rh_account_id = ?", inStore.Inventory.ID, inStore.Inventory.RhAccountID). // nolint:lll @@ -532,6 +536,10 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { require.NotNil(t, inventoryAfterInsert.Workspaces) assert.Equal(t, hostEvent.Host.Groups, []inventory.Group(*inventoryAfterInsert.Workspaces)) + require.NotNil(t, inventoryAfterInsert.WorkspaceID) + assert.Equal(t, hostEvent.Host.Groups[0].ID, *inventoryAfterInsert.WorkspaceID) + require.NotNil(t, inventoryAfterInsert.WorkspaceName) + assert.Equal(t, hostEvent.Host.Groups[0].Name, *inventoryAfterInsert.WorkspaceName) assert.Equal(t, hostEvent.Host.SystemProfile.OperatingSystem.Name, *inventoryAfterInsert.OSName) assert.Equal(t, hostEvent.Host.SystemProfile.OperatingSystem.Major, *inventoryAfterInsert.OSMajor) @@ -570,6 +578,8 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { Created: hostEvent.Host.Created, Tags: utils.MarshalNilToJSONB(hostEvent.Host.Tags), Workspaces: &hostWorkspaces, + WorkspaceID: workspaceID, + WorkspaceName: workspaceName, OSName: utils.EmptyToNil(&hostEvent.Host.SystemProfile.OperatingSystem.Name), OSMajor: &hostEvent.Host.SystemProfile.OperatingSystem.Major, OSMinor: &hostEvent.Host.SystemProfile.OperatingSystem.Minor, From 517a06642fa6a1a955f36ea24580a1d07ade444c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 28 Apr 2026 15:08:12 +0200 Subject: [PATCH 29/34] RHINENG-25147: drop workspaces column --- .../migrations/153_simplify_workspaces.up.sql | 3 ++ database_admin/schema/create_schema.sql | 2 - dev/test_data.sql | 48 +++++++++---------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/database_admin/migrations/153_simplify_workspaces.up.sql b/database_admin/migrations/153_simplify_workspaces.up.sql index b8b60ff61..fdd0ce7d3 100644 --- a/database_admin/migrations/153_simplify_workspaces.up.sql +++ b/database_admin/migrations/153_simplify_workspaces.up.sql @@ -8,3 +8,6 @@ UPDATE system_inventory CREATE INDEX IF NOT EXISTS system_inventory_workspace_id_index ON system_inventory (workspace_id); CREATE INDEX IF NOT EXISTS system_inventory_workspace_name_index ON system_inventory (workspace_name); + +ALTER TABLE system_inventory + DROP COLUMN workspaces; diff --git a/database_admin/schema/create_schema.sql b/database_admin/schema/create_schema.sql index 960bbe3c0..e14be6288 100644 --- a/database_admin/schema/create_schema.sql +++ b/database_admin/schema/create_schema.sql @@ -592,7 +592,6 @@ CREATE TABLE IF NOT EXISTS system_inventory ansible_workload_controller_version TEXT CHECK (NOT empty(ansible_workload_controller_version)), mssql_workload BOOLEAN NOT NULL DEFAULT false, mssql_workload_version TEXT CHECK (NOT empty(mssql_workload_version)), - workspaces JSONB, workspace_id TEXT CHECK (NOT empty(workspace_id)), workspace_name TEXT CHECK (NOT empty(workspace_name)), PRIMARY KEY (rh_account_id, id), @@ -626,7 +625,6 @@ SELECT create_table_partition_triggers('system_inventory_on_update', CREATE INDEX IF NOT EXISTS system_inventory_inventory_id_idx ON system_inventory (inventory_id); CREATE INDEX IF NOT EXISTS system_inventory_tags_index ON system_inventory USING GIN (tags JSONB_PATH_OPS); CREATE INDEX IF NOT EXISTS system_inventory_stale_timestamp_index ON system_inventory (stale_timestamp); -CREATE INDEX IF NOT EXISTS system_inventory_workspaces_index ON system_inventory USING GIN (workspaces); CREATE INDEX IF NOT EXISTS system_inventory_workspace_id_index ON system_inventory (workspace_id); CREATE INDEX IF NOT EXISTS system_inventory_workspace_name_index ON system_inventory (workspace_name); diff --git a/dev/test_data.sql b/dev/test_data.sql index 30122ae8e..3d8c39ddb 100644 --- a/dev/test_data.sql +++ b/dev/test_data.sql @@ -24,13 +24,13 @@ INSERT INTO template (id, rh_account_id, uuid, environment_id, name, description (3, 1, '99900000-0000-0000-0000-000000000003', '99900000000000000000000000000003', 'temp3-1', NULL, '{"to_time": "2000-01-01T00:00:00+00:00"}', 'x86_64', '8', 'user3'), (4, 3, '99900000-0000-0000-0000-000000000004', '99900000000000000000000000000004', 'temp4-3', 'desc4', '{"to_time": "2000-01-01T00:00:00+00:00"}', 'x86_64', '8', 'user4'); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload, sap_workload_sids, mssql_workload, mssql_workload_version) VALUES -(1, '00000000-0000-0000-0000-000000000001', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000001', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 10, '8.10', NULL, true, ARRAY['ABC', 'DEF', 'GHI'], false, NULL), -(2, '00000000-0000-0000-0000-000000000002', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000002', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"},{"key": "k3", "value": "val3", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.1', NULL, true, ARRAY['ABC'], false, NULL), -(3, '00000000-0000-0000-0000-000000000003', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000003', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}, {"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.0', NULL, true, NULL, false, NULL), -(4, '00000000-0000-0000-0000-000000000004', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000004', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', 'cccccccc-0000-0000-0001-000000000004', true, NULL, false, NULL), -(5, '00000000-0000-0000-0000-000000000005', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000005', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000005', true, NULL, false, NULL), -(6, '00000000-0000-0000-0000-000000000006', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000006', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 7, 3, '7.3', NULL, true, NULL, true, '15.3.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload, sap_workload_sids, mssql_workload, mssql_workload_version) VALUES +(1, '00000000-0000-0000-0000-000000000001', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000001', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 10, '8.10', NULL, true, ARRAY['ABC', 'DEF', 'GHI'], false, NULL), +(2, '00000000-0000-0000-0000-000000000002', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000002', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"},{"key": "k2", "value": "val2", "namespace": "ns1"},{"key": "k3", "value": "val3", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.1', NULL, true, ARRAY['ABC'], false, NULL), +(3, '00000000-0000-0000-0000-000000000003', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000003', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}, {"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 1, '8.0', NULL, true, NULL, false, NULL), +(4, '00000000-0000-0000-0000-000000000004', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000004', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', 'cccccccc-0000-0000-0001-000000000004', true, NULL, false, NULL), +(5, '00000000-0000-0000-0000-000000000005', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-09-18 12:00:00-04', '00000000-0000-0000-0000-000000000005', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000005', true, NULL, false, NULL), +(6, '00000000-0000-0000-0000-000000000006', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000006', 1, 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 7, 3, '7.3', NULL, true, NULL, true, '15.3.0'); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party, template_id) VALUES (1, 1, '2018-09-22 12:00:00-04', true , 1), (2, 1, '2018-09-22 12:00:00-04', false, 1), @@ -39,17 +39,17 @@ INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party (5, 1, '2018-09-22 12:00:00-04', false, NULL), (6, 1, '2018-09-22 12:00:00-04', false, NULL); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_updated, unchanged_since, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, rhsm_version, subscription_manager_id, sap_workload, ansible_workload, ansible_workload_controller_version) VALUES -(7, '00000000-0000-0000-0000-000000000007', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-10-04 14:13:12-04', '2018-09-22 12:00:00-04', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000007', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'inventory-group-2', 'group2', 'RHEL', 8, '8.x', 'cccccccc-0000-0000-0001-000000000007', true, true, '1.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_updated, unchanged_since, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, rhsm_version, subscription_manager_id, sap_workload, ansible_workload, ansible_workload_controller_version) VALUES +(7, '00000000-0000-0000-0000-000000000007', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-10-04 14:13:12-04', '2018-09-22 12:00:00-04', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000007', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-2', 'group2', 'RHEL', 8, '8.x', 'cccccccc-0000-0000-0001-000000000007', true, true, '1.0'); INSERT INTO system_patch (system_id, rh_account_id) VALUES (7, 1); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES -( 8, '00000000-0000-0000-0000-000000000008', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000008', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-2", "name": "group2"}]', 'inventory-group-2', 'group2', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000008', true), -( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true), -(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', NULL, 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', NULL, true), -(11, '00000000-0000-0000-0000-000000000011', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000011', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 3, '8.3', NULL, true), -(12, '00000000-0000-0000-0000-000000000012', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000012', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES +( 8, '00000000-0000-0000-0000-000000000008', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-08-26 12:00:00-04', '00000000-0000-0000-0000-000000000008', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-2', 'group2', 'RHEL', 8, 3, '8.3', 'cccccccc-0000-0000-0001-000000000008', true), +( 9, '00000000-0000-0000-0000-000000000009', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000009', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true), +(10, '00000000-0000-0000-0000-000000000010', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000010', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', NULL, true), +(11, '00000000-0000-0000-0000-000000000011', 2, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000011', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 3, '8.3', NULL, true), +(12, '00000000-0000-0000-0000-000000000012', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000012', 'x86_64', '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', NULL, true); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed, packages_installable, packages_applicable) VALUES ( 8, 1, '2018-09-22 12:00:00-04', 0, 0, 0), ( 9, 2, '2018-09-22 12:00:00-04', 0, 0, 0), @@ -57,24 +57,24 @@ INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_in (11, 2, '2018-09-22 12:00:00-04', 0, 0, 0), (12, 3, '2018-09-22 12:00:00-04', 2, 2, 2); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, yum_updates, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, sap_workload) VALUES -(13, '00000000-0000-0000-0000-000000000013', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000013', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', true), -(14, '00000000-0000-0000-0000-000000000014', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000014', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 3, NULL, true), -(15, '00000000-0000-0000-0000-000000000015', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000015', '{"update_list": {"suricata-0:6.0.3-2.fc35.i686": {"available_updates": [{"erratum": "RHSA-2021:3801", "basearch": "i686", "releasever": "ser1", "repository": "group_oisf:suricata-6.0", "package": "suricata-0:6.0.4-2.fc35.i686"}]}}, "basearch": "i686", "releasever": "ser1"}', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', false); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, yum_updates, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, sap_workload) VALUES +(13, '00000000-0000-0000-0000-000000000013', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000013', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', true), +(14, '00000000-0000-0000-0000-000000000014', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000014', NULL, '[{"key": "k1", "value": "val1", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 3, NULL, true), +(15, '00000000-0000-0000-0000-000000000015', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000015', '{"update_list": {"suricata-0:6.0.3-2.fc35.i686": {"available_updates": [{"erratum": "RHSA-2021:3801", "basearch": "i686", "releasever": "ser1", "repository": "group_oisf:suricata-6.0", "package": "suricata-0:6.0.4-2.fc35.i686"}]}}, "basearch": "i686", "releasever": "ser1"}', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', false); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed) VALUES (13, 3, '2018-09-22 12:00:00-04', 1), (14, 3, '2018-09-22 12:00:00-04', 0), (15, 3, '2018-09-22 12:00:00-04', 0); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, ansible_workload, ansible_workload_controller_version, mssql_workload, mssql_workload_version) VALUES -(16, '00000000-0000-0000-0000-000000000016', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000016', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', false, NULL, false, NULL), -(17, '00000000-0000-0000-0000-000000000017', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000017', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[]', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', true, '1.0', true, '15.3.0'); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, ansible_workload, ansible_workload_controller_version, mssql_workload, mssql_workload_version) VALUES +(16, '00000000-0000-0000-0000-000000000016', 3, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000016', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 2, '8.2', false, NULL, false, NULL), +(17, '00000000-0000-0000-0000-000000000017', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2018-01-22 12:00:00-04', '00000000-0000-0000-0000-000000000017', '[]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'root-workspace', 'root-ws', 'RHEL', 8, 1, '8.1', true, '1.0', true, '15.3.0'); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, packages_installed, packages_installable, packages_applicable, template_id) VALUES (16, 3, '2018-09-22 12:00:00-04', 1, 1, 1, 4), (17, 1, '2018-09-22 12:00:00-04', 2, 2, 2, NULL); -INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspaces, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES -(18, '00000000-0000-0000-0000-000000000018', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000018', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', '[{"id": "inventory-group-1", "name": "group1"}]', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', '99999999-9999-9999-9999-999999999404', true); +INSERT INTO system_inventory (id, inventory_id, rh_account_id, vmaas_json, json_checksum, last_upload, display_name, reporter_id, arch, tags, created, stale_timestamp, stale_warning_timestamp, workspace_id, workspace_name, os_name, os_major, os_minor, rhsm_version, subscription_manager_id, sap_workload) VALUES +(18, '00000000-0000-0000-0000-000000000018', 1, '{ "package_list": [ "kernel-2.6.32-696.20.1.el6.x86_64" ], "repository_list": [ "rhel-6-server-rpms" ] }', '1', '2020-09-22 12:00:00-04', '00000000-0000-0000-0000-000000000018', 1, 'x86_64', '[{"key": "k3", "value": "val4", "namespace": "ns1"}]', '2018-08-26 12:00:00-04', '2018-08-26 12:00:00-04', '2018-09-02 12:00:00-04', 'inventory-group-1', 'group1', 'RHEL', 8, 2, '8.3', '99999999-9999-9999-9999-999999999404', true); INSERT INTO system_patch (system_id, rh_account_id, last_evaluation, third_party) VALUES (18, 1, '2018-09-22 12:00:00-04', true); From 0154432a3778b513ac927d042032c88b90cce08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 28 Apr 2026 15:17:00 +0200 Subject: [PATCH 30/34] RHINENG-25147: remove SystemGroups --- manager/controllers/advisory_systems.go | 1 - manager/controllers/common_attributes.go | 4 ---- manager/controllers/package_systems.go | 1 - manager/controllers/structures.go | 5 ----- manager/controllers/systems.go | 16 +--------------- manager/controllers/template_systems.go | 1 - 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/manager/controllers/advisory_systems.go b/manager/controllers/advisory_systems.go index f1d8ee2a4..55868d7e9 100644 --- a/manager/controllers/advisory_systems.go +++ b/manager/controllers/advisory_systems.go @@ -40,7 +40,6 @@ type AdvisorySystemItemAttributes struct { OSAttributes SystemTimestamps SystemTags - SystemGroups SystemWorkspace BaselineIDAttr BaselineNameAttr diff --git a/manager/controllers/common_attributes.go b/manager/controllers/common_attributes.go index ad5302e01..ff2c95ead 100644 --- a/manager/controllers/common_attributes.go +++ b/manager/controllers/common_attributes.go @@ -24,10 +24,6 @@ type SystemTags struct { Tags SystemTagsList `json:"tags" csv:"tags" query:"si.tags" gorm:"column:tags"` } -type SystemGroups struct { - Groups SystemGroupsList `json:"groups" csv:"groups" query:"si.workspaces" gorm:"column:groups" order_query:"si.workspaces->0->>'name'"` -} - type SystemWorkspace struct { WorkspaceID *string `json:"workspace_id" csv:"workspace_id" query:"si.workspace_id" gorm:"column:workspace_id"` WorkspaceName *string `json:"workspace_name" csv:"workspace_name" query:"si.workspace_name" gorm:"column:workspace_name"` diff --git a/manager/controllers/package_systems.go b/manager/controllers/package_systems.go index bd7279298..7b0a68257 100644 --- a/manager/controllers/package_systems.go +++ b/manager/controllers/package_systems.go @@ -39,7 +39,6 @@ type PackageSystemItem struct { BaselineIDAttr OSAttributes UpdateStatus string `json:"update_status" csv:"update_status" query:"CASE WHEN spkg.installable_id is not null THEN 'Installable' WHEN spkg.applicable_id is not null THEN 'Applicable' ELSE 'None' END" gorm:"column:update_status"` - SystemGroups SystemWorkspace } diff --git a/manager/controllers/structures.go b/manager/controllers/structures.go index 5634e704f..6b70ce050 100644 --- a/manager/controllers/structures.go +++ b/manager/controllers/structures.go @@ -69,8 +69,3 @@ type IDsSatelliteManagedResponse struct { // TODO: delete later once UI is using only the new `data` field IDsResponseCommon } - -type SystemGroup struct { - ID string `json:"id"` - Name string `json:"name"` -} diff --git a/manager/controllers/systems.go b/manager/controllers/systems.go index 7c9c993f1..6087919e4 100644 --- a/manager/controllers/systems.go +++ b/manager/controllers/systems.go @@ -94,7 +94,6 @@ type SystemItemAttributes struct { ApplicableOtherCount int `json:"applicable_other_count" csv:"applicable_other_count" query:"(spatch.applicable_advisory_count_cache - spatch.installable_advisory_sec_count_cache - spatch.installable_advisory_bug_count_cache - spatch.installable_advisory_enh_count_cache)" gorm:"column:applicable_other_count"` BaselineIDAttr TemplateAttibutes - SystemGroups SystemWorkspace SystemArch } @@ -112,10 +111,9 @@ type SystemItemAttributesExtended struct { } type SystemTagsList []SystemTag -type SystemGroupsList []SystemGroup type SystemJSONBItemType interface { - SystemTagsList | SystemGroupsList + SystemTagsList } func (v SystemTagsList) String() string { @@ -130,18 +128,6 @@ func (v *SystemTagsList) Scan(value interface{}) error { return SystemJSONBItemScan(v, value) } -func (v SystemGroupsList) String() string { - return SystemJSONBItemString(v) -} - -func (v SystemGroupsList) Value() (driver.Value, error) { - return SystemJSONBItemValue(v) -} - -func (v *SystemGroupsList) Scan(value interface{}) error { - return SystemJSONBItemScan(v, value) -} - func SystemJSONBItemString[T SystemJSONBItemType](v T) string { b, err := sonic.Marshal(v) if err != nil { diff --git a/manager/controllers/template_systems.go b/manager/controllers/template_systems.go index fd2e4ccee..d42b7de29 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -35,7 +35,6 @@ type TemplateSystemAttributes struct { InstallableAdvisories ApplicableAdvisories SystemTags - SystemGroups SystemWorkspace SystemLastUpload } From 86d7306cbdbc2ca1b219a6c6f930e4a2c5880fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 28 Apr 2026 15:19:43 +0200 Subject: [PATCH 31/34] RHINENG-25147: update columns in export tests --- manager/controllers/advisory_systems_export_test.go | 7 +++---- manager/controllers/package_systems_export_test.go | 6 +++--- manager/controllers/systems_export_test.go | 4 ++-- manager/controllers/template_systems_export_test.go | 7 +++---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/manager/controllers/advisory_systems_export_test.go b/manager/controllers/advisory_systems_export_test.go index 443491f46..da8ba4320 100644 --- a/manager/controllers/advisory_systems_export_test.go +++ b/manager/controllers/advisory_systems_export_test.go @@ -33,13 +33,12 @@ func TestAdvisorySystemsExportCSV(t *testing.T) { assert.Equal(t, 8, len(lines)) assert.Equal(t, "display_name,last_upload,stale,os,rhsm,stale_timestamp,stale_warning_timestamp,culled_timestamp,created,tags,"+ - "groups,workspace_id,workspace_name,baseline_id,baseline_name,template_name,template_uuid,status,"+ + "workspace_id,workspace_name,baseline_id,baseline_name,template_name,template_uuid,status,"+ "satellite_managed,built_pkgcache,id", lines[0]) assert.Equal(t, "00000000-0000-0000-0000-000000000001,2020-09-22T16:00:00Z,false,RHEL 8.10,8.10,2018-08-26T16:00:00Z,"+ "2018-09-02T16:00:00Z,,2018-08-26T16:00:00Z,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ - "{'key':'k2','namespace':'ns1','value':'val2'}]\",\"[{'id':'inventory-group-1','name':'group1'}]\","+ - "inventory-group-1,group1,0,,temp1-1,99900000-0000-0000-0000-000000000001,Installable,false,false,"+ - "00000000-0000-0000-0000-000000000001", + "{'key':'k2','namespace':'ns1','value':'val2'}]\",inventory-group-1,group1,"+ + "0,,temp1-1,99900000-0000-0000-0000-000000000001,Installable,false,false,00000000-0000-0000-0000-000000000001", lines[1]) } diff --git a/manager/controllers/package_systems_export_test.go b/manager/controllers/package_systems_export_test.go index 062b3d9a8..84c57066a 100644 --- a/manager/controllers/package_systems_export_test.go +++ b/manager/controllers/package_systems_export_test.go @@ -38,15 +38,15 @@ func TestPackageSystemsExportHandlerCSV(t *testing.T) { assert.Equal(t, 5, len(lines)) assert.Equal(t, "id,display_name,installed_evra,available_evra,updatable,tags,"+ "baseline_name,baseline_uptodate,template_name,template_uuid,satellite_managed,baseline_id,os,rhsm,"+ - "update_status,groups,workspace_id,workspace_name", lines[0]) + "update_status,workspace_id,workspace_name", lines[0]) assert.Equal(t, "00000000-0000-0000-0000-000000000012,00000000-0000-0000-0000-000000000012,"+ "5.6.13-200.fc31.x86_64,5.6.13-201.fc31.x86_64,true,"+ - "\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,false,0,RHEL 8.1,8.1,Installable,[],"+ + "\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,false,0,RHEL 8.1,8.1,Installable,"+ "root-workspace,root-ws", lines[1]) assert.Equal(t, "00000000-0000-0000-0000-000000000013,00000000-0000-0000-0000-000000000013,"+ "5.6.13-200.fc31.x86_64,,false,\"[{'key':'k1','namespace':'ns1','value':'val1'}]\",,,,,"+ - "false,0,RHEL 8.2,8.2,None,[],root-workspace,root-ws", lines[2]) + "false,0,RHEL 8.2,8.2,None,root-workspace,root-ws", lines[2]) } func TestPackageSystemsExportInvalidName(t *testing.T) { diff --git a/manager/controllers/systems_export_test.go b/manager/controllers/systems_export_test.go index 029684225..77a3c3aa7 100644 --- a/manager/controllers/systems_export_test.go +++ b/manager/controllers/systems_export_test.go @@ -18,7 +18,7 @@ var SystemCsvHeader = "id,display_name,os,rhsm,tags,last_evaluation," + "satellite_managed,built_pkgcache,packages_installable,packages_applicable," + "installable_rhsa_count,installable_rhba_count,installable_rhea_count,installable_other_count," + "applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count,applicable_other_count," + - "baseline_id,template_name,template_uuid,groups,workspace_id,workspace_name,arch" + "baseline_id,template_name,template_uuid,workspace_id,workspace_name,arch" func makeRequest(t *testing.T, path string, contentType string) *httptest.ResponseRecorder { core.SetupTest(t) @@ -60,7 +60,7 @@ func TestSystemsExportCSV(t *testing.T) { "2018-09-22T16:00:00Z,2,2,1,0,0,,"+ "2020-09-22T16:00:00Z,2018-08-26T16:00:00Z,2018-09-02T16:00:00Z,,2018-08-26T16:00:00Z,"+ "false,false,false,0,0,2,2,1,0,2,3,3,3,0,temp1-1,99900000-0000-0000-0000-000000000001,"+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,x86_64", + "inventory-group-1,group1,x86_64", lines[1]) } diff --git a/manager/controllers/template_systems_export_test.go b/manager/controllers/template_systems_export_test.go index 909589fe7..cd24ca199 100644 --- a/manager/controllers/template_systems_export_test.go +++ b/manager/controllers/template_systems_export_test.go @@ -14,7 +14,7 @@ import ( var TemplateCsvHeader = "id,display_name,os,rhsm," + "installable_rhsa_count,installable_rhba_count,installable_rhea_count,installable_other_count," + "applicable_rhsa_count,applicable_rhba_count,applicable_rhea_count,applicable_other_count," + - "tags,groups,workspace_id,workspace_name,last_upload" + "tags,workspace_id,workspace_name,last_upload" // nolint: dupl func TestTemplateSystemsExportJSON(t *testing.T) { @@ -68,12 +68,11 @@ func TestTemplateSystemsExportCSV(t *testing.T) { assert.Equal(t, "00000000-0000-0000-0000-000000000002,00000000-0000-0000-0000-000000000002,RHEL 8.1,"+ "8.1,0,0,0,0,0,0,1,0,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ "{'key':'k2','namespace':'ns1','value':'val2'},{'key':'k3','namespace':'ns1','value':'val3'}]\","+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,2018-09-22T16:00:00Z", + "inventory-group-1,group1,2018-09-22T16:00:00Z", lines[1]) assert.Equal(t, "00000000-0000-0000-0000-000000000001,00000000-0000-0000-0000-000000000001,RHEL 8.10,"+ "8.10,2,2,1,0,2,3,3,0,\"[{'key':'k1','namespace':'ns1','value':'val1'},"+ - "{'key':'k2','namespace':'ns1','value':'val2'}]\","+ - "\"[{'id':'inventory-group-1','name':'group1'}]\",inventory-group-1,group1,2020-09-22T16:00:00Z", + "{'key':'k2','namespace':'ns1','value':'val2'}]\",inventory-group-1,group1,2020-09-22T16:00:00Z", lines[2]) } From 9e80e2d8016a22abf072583a0045389f2618a85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 28 Apr 2026 15:22:08 +0200 Subject: [PATCH 32/34] RHINENG-25147: remove inventory groups from context --- base/utils/gin.go | 3 - manager/middlewares/kessel.go | 30 ---- manager/middlewares/kessel_test.go | 20 --- manager/middlewares/rbac.go | 62 --------- manager/middlewares/rbac_test.go | 216 ----------------------------- 5 files changed, 331 deletions(-) diff --git a/base/utils/gin.go b/base/utils/gin.go index cdb1686cd..58501973e 100644 --- a/base/utils/gin.go +++ b/base/utils/gin.go @@ -18,9 +18,6 @@ const ( KeyOrgID = "org_id" KeyUser = "user" KeySystem = "system_cn" - KeyInventoryGroups = "inventoryGroups" - KeyGrouped = "grouped" - KeyUngrouped = "ungrouped" KeyInventoryWorkspaces = "workspaceIDs" // ReadHeaderTimeout same as nginx default ReadHeaderTimeout = 60 * time.Second diff --git a/manager/middlewares/kessel.go b/manager/middlewares/kessel.go index 08fa4e96e..91aea0b65 100644 --- a/manager/middlewares/kessel.go +++ b/manager/middlewares/kessel.go @@ -3,7 +3,6 @@ package middlewares import ( "app/base/utils" "context" - "fmt" "net/http" "strings" "time" @@ -35,27 +34,6 @@ func setupClient() (kesselv2.KesselInventoryServiceClient, *grpc.ClientConn, err return clientBuilder.Build() } -func processWorkspaces(workspaces []*kesselv2.StreamedListObjectsResponse) (map[string]string, error) { - defer func(start time.Time) { - utils.LogDebug("durationMs", time.Since(start).Milliseconds(), "processed workspaces") - }(time.Now()) - - groups := make([]string, 0, len(workspaces)) - for _, workspace := range workspaces { - group, err := utils.ParseInventoryGroup(&workspace.Object.ResourceId, nil) - if err != nil { - // couldn't marshal inventory group to json - continue - } - groups = append(groups, group) - } - - if len(groups) == 0 { - return nil, errors.New("no workspaces found") - } - return map[string]string{utils.KeyGrouped: fmt.Sprintf("{%s}", strings.Join(groups, ","))}, nil -} - func buildPermission(c *gin.Context) string { permission := "patch_system_" nameSplit := strings.Split(c.HandlerName(), ".") @@ -153,14 +131,6 @@ func hasPermissionKessel(c *gin.Context) { return } c.Set(utils.KeyInventoryWorkspaces, workspaceIDs) - - inventoryGroups, err := processWorkspaces(workspaces) - if err != nil { - utils.LogWarn(err.Error()) - c.AbortWithStatusJSON(http.StatusUnauthorized, utils.ErrorResponse{Error: "Missing permission"}) - return - } - c.Set(utils.KeyInventoryGroups, inventoryGroups) } func Kessel() gin.HandlerFunc { diff --git a/manager/middlewares/kessel_test.go b/manager/middlewares/kessel_test.go index fd7c58931..3813c315d 100644 --- a/manager/middlewares/kessel_test.go +++ b/manager/middlewares/kessel_test.go @@ -2,9 +2,7 @@ package middlewares import ( "app/base/utils" - "fmt" "net/http" - "strconv" "testing" "google.golang.org/grpc" @@ -66,18 +64,6 @@ func TestSetupClient(t *testing.T) { utils.CoreCfg.KesselAuthClientSecret = originalKesselAuthClientSecret } -func TestProcessWorkspaces(t *testing.T) { - expected := fmt.Sprintf("{%s,%s}", strconv.Quote(`[{"id":"test-1"}]`), strconv.Quote(`[{"id":"test-2"}]`)) - workspaces := []*kesselv2.StreamedListObjectsResponse{ - {Object: &kesselv2.ResourceReference{ResourceId: "test-1"}}, - {Object: &kesselv2.ResourceReference{ResourceId: "test-2"}}, - } - processed, err := processWorkspaces(workspaces) - if assert.NoError(t, err) { - assert.Equal(t, expected, processed[utils.KeyGrouped]) - } -} - func TestBuildPermission(t *testing.T) { c := &gin.Context{Request: &http.Request{Method: http.MethodGet}} permission := buildPermission(c) @@ -109,12 +95,6 @@ func TestHasPermissionKessel(t *testing.T) { c.Request.Header.Set("x-rh-identity", "ewogICAgImVudGl0bGVtZW50cyI6IHsKICAgICAgICAiaW5zaWdodHMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJjb3N0X21hbmFnZW1lbnQiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJhbnNpYmxlIjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAib3BlbnNoaWZ0IjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAic21hcnRfbWFuYWdlbWVudCI6IHsKICAgICAgICAgICAgImlzX2VudGl0bGVkIjogdHJ1ZQogICAgICAgIH0sCiAgICAgICAgIm1pZ3JhdGlvbnMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9CiAgICB9LAogICAgImlkZW50aXR5IjogewogICAgICAgICJpbnRlcm5hbCI6IHsKICAgICAgICAgICAgImF1dGhfdGltZSI6IDI5OSwKICAgICAgICAgICAgImF1dGhfdHlwZSI6ICJiYXNpYy1hdXRoIiwKICAgICAgICAgICAgIm9yZ19pZCI6ICIxMTc4OTc3MiIKICAgICAgICB9LAogICAgICAgICJhY2NvdW50X251bWJlciI6ICI2MDg5NzE5IiwKICAgICAgICAidXNlciI6IHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiAiSW5zaWdodHMiLAogICAgICAgICAgICAiaXNfYWN0aXZlIjogdHJ1ZSwKICAgICAgICAgICAgImlzX2ludGVybmFsIjogZmFsc2UsCiAgICAgICAgICAgICJsYXN0X25hbWUiOiAiUUEiLAogICAgICAgICAgICAibG9jYWxlIjogImVuX1VTIiwKICAgICAgICAgICAgImlzX29yZ19hZG1pbiI6IHRydWUsCiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJpbnNpZ2h0cy1xYSIsCiAgICAgICAgICAgICJlbWFpbCI6ICJqbmVlZGxlK3FhQHJlZGhhdC5jb20iLAogICAgICAgICAgICAidXNlcl9pZCI6ICI2MDg5NzE5IgogICAgICAgIH0sCiAgICAgICAgInR5cGUiOiAiVXNlciIKICAgIH0KfQ==") //nolint:lll hasPermissionKessel(c) - inventoryGroups, found := c.Get(utils.KeyInventoryGroups) - require.True(t, found) - inventoryGroupMap, ok := (inventoryGroups).(map[string]string) - require.True(t, ok) - assert.Equal(t, `{"[{\"id\":\"inventory-group-1\"}]"}`, inventoryGroupMap[utils.KeyGrouped]) - workspaces, found := c.Get(utils.KeyInventoryWorkspaces) require.True(t, found) workspaceIDs, ok := (workspaces).([]string) diff --git a/manager/middlewares/rbac.go b/manager/middlewares/rbac.go index 25d9ff3b0..9ddf258c6 100644 --- a/manager/middlewares/rbac.go +++ b/manager/middlewares/rbac.go @@ -6,7 +6,6 @@ import ( "app/base/rbac" "app/base/utils" "app/manager/config" - "fmt" "net/http" "strconv" "strings" @@ -125,13 +124,6 @@ func isAccessGranted(c *gin.Context) bool { if !granted { return granted } - // collect inventory groups - groups, err := findInventoryGroups(&access) - if err != nil { - utils.LogError("err", err.Error(), "RBAC") - granted = false - } - c.Set(utils.KeyInventoryGroups, groups) workspaceIDs := make([]string, 0) for _, a := range access.Data { @@ -150,60 +142,6 @@ func isAccessGranted(c *gin.Context) bool { return granted } -func findInventoryGroups(access *rbac.AccessPagination) (map[string]string, error) { - res := make(map[string]string) - - if len(access.Data) == 0 { - utils.LogDebug("rbac zero access data") - return res, nil - } - inventoryHostsReadPerms := expandedPermission(inventoryHostsReadPerm) - groups := []string{} - for _, a := range access.Data { - // look for groups only on inventory:hosts:read permissions - if !slices.Contains(inventoryHostsReadPerms, a.Permission) { - continue - } - - if len(a.ResourceDefinitions) == 0 { - // access to all groups - utils.LogDebug("rbac access to all groups") - return nil, nil - } - for _, rd := range a.ResourceDefinitions { - if rd.AttributeFilter.Key != "group.id" { - continue - } - - if rd.AttributeFilter.Operation != "in" && rd.AttributeFilter.Operation != "equal" { - err := fmt.Errorf( - "invalid value '%s' for attributeFilter.Operation", - rd.AttributeFilter.Operation, - ) - return nil, err - } - for _, v := range rd.AttributeFilter.Value { - if v == nil { - res[utils.KeyUngrouped] = "[]" - continue - } - group, err := utils.ParseInventoryGroup(v, nil) - if err != nil { - // couldn't marshal inventory group to json - continue - } - groups = append(groups, group) - } - } - } - - if len(groups) > 0 { - res[utils.KeyGrouped] = fmt.Sprintf("{%s}", strings.Join(groups, ",")) - } - utils.LogDebug("group_count", len(groups), "processed groups") - return res, nil -} - func RBAC() gin.HandlerFunc { if !config.EnableRBACCHeck { return func(_ *gin.Context) {} diff --git a/manager/middlewares/rbac_test.go b/manager/middlewares/rbac_test.go index aa41641dd..f54e22a7b 100644 --- a/manager/middlewares/rbac_test.go +++ b/manager/middlewares/rbac_test.go @@ -2,8 +2,6 @@ package middlewares import ( "app/base/rbac" - "app/base/utils" - "encoding/json" "net/http" "net/http/httptest" "testing" @@ -242,148 +240,6 @@ func TestPermissionsRead(t *testing.T) { assert.False(t, checkPermissions(&access, handler, "GET")) } -func TestFindInventoryGroupsGrouped(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{{ - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{&group1}, - Operation: "in", - }, - }}, - }}, - } - groups, err := findInventoryGroups(access) - if assert.NoError(t, err) { - assert.Equal(t, - `{"[{\"id\":\"df57820e-965c-49a6-b0bc-797b7dd60581\"}]"}`, - groups[utils.KeyGrouped], - ) - val, ok := groups[utils.KeyUngrouped] - assert.Equal(t, "", val) - assert.Equal(t, false, ok) - } -} - -func TestFindInventoryGroupsUnrouped(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{{ - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{nil}, - Operation: "in", - }, - }}, - }}, - } - groups, err := findInventoryGroups(access) - if assert.NoError(t, err) { - val, ok := groups[utils.KeyGrouped] - assert.Equal(t, "", val) - assert.Equal(t, false, ok) - assert.Equal(t, "[]", groups[utils.KeyUngrouped]) - } -} - -func TestFindInventoryGroups(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{{ - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{&group1, &group2, nil}, - Operation: "in", - }, - }}, - }}, - } - groups, err := findInventoryGroups(access) - if assert.NoError(t, err) { - assert.Equal(t, - `{"[{\"id\":\"df57820e-965c-49a6-b0bc-797b7dd60581\"}]","[{\"id\":\"df3f0efd-c853-41b5-80a1-86881d5343d1\"}]"}`, - groups[utils.KeyGrouped], - ) - assert.Equal(t, "[]", groups[utils.KeyUngrouped]) - } -} - -func TestFindInventoryGroupsOverwrite(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{ - { - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{&group1, nil}, - Operation: "in", - }, - }}, - }, - { - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{}, - }, - }, - } - groups, err := findInventoryGroups(access) - if assert.NoError(t, err) { - // we expect access to all groups (empty map) - assert.Equal(t, 0, len(groups)) - } -} - -func TestFindInventoryGroupsOverwrite2(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{ - { - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{}, - }, - { - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{&group1, nil}, - Operation: "in", - }, - }}, - }, - }, - } - groups, err := findInventoryGroups(access) - if assert.NoError(t, err) { - // we expect access to all groups (empty map) - assert.Equal(t, 0, len(groups)) - } -} - -func TestFindInventoryGroupsInvalidOp(t *testing.T) { - access := &rbac.AccessPagination{ - Data: []rbac.Access{ - { - Permission: "inventory:hosts:read", - ResourceDefinitions: []rbac.ResourceDefinition{{ - AttributeFilter: rbac.AttributeFilter{ - Key: "group.id", - Value: []*string{}, - Operation: "unsupported", - }, - }}, - }, - }, - } - groups, err := findInventoryGroups(access) - assert.Error(t, err) - assert.Nil(t, groups) -} - func TestMultiplePermissions(t *testing.T) { handler := "MultiplePermissions" access := rbac.AccessPagination{ @@ -413,75 +269,3 @@ func TestMultiplePermissions(t *testing.T) { assert.True(t, checkPermissions(&access, handler, "GET")) assert.False(t, checkPermissions(&access, handler, "DELETE")) } - -var allowedOperations = `{"data": [ - { - "resourceDefinitions": [], - "permission": "patch:*:read" - }, - { - "resourceDefinitions": [ - { - "attributeFilter": { - "key": "group.id", - "value": "00000000-f688-49d4-a8e2-87394f1ac1b1", - "operation": "equal" - } - } - ], - "permission": "inventory:hosts:read" - }, - { - "resourceDefinitions": [ - { - "attributeFilter": { - "key": "group.id", - "value": [ "00000000-f7a6-45a1-b5a8-410f20052fb1", "00000000-78e0-4cad-bf01-63cf1e4b1dca" ], - "operation": "in" - } - } - ], - "permission": "inventory:hosts:read" - }, - { - "resourceDefinitions": [ - { - "attributeFilter": { - "key": "group.id", - "value": [ "00000000-f688-49d4-a8e2-ee394f1ac1b1" ], - "operation": "in" - } - } - ], - "permission": "inventory:hosts:read" - }, - { - "resourceDefinitions": [ - { - "attributeFilter": { - "key": "group.id", - "value": null, - "operation": "equal" - } - } - ], - "permission": "inventory:hosts:read" - } - ] -} -` - -func TestPermissionsAllowedOperations(t *testing.T) { - handler := "SystemsListHandler" - access := rbac.AccessPagination{} - err := json.Unmarshal([]byte(allowedOperations), &access) - assert.NoError(t, err) - assert.True(t, checkPermissions(&access, handler, "GET")) - groups, err := findInventoryGroups(&access) - assert.NoError(t, err) - assert.Equal(t, "[]", groups["ungrouped"]) - assert.Equal(t, `{"[{\"id\":\"00000000-f688-49d4-a8e2-87394f1ac1b1\"}]",`+ - `"[{\"id\":\"00000000-f7a6-45a1-b5a8-410f20052fb1\"}]",`+ - `"[{\"id\":\"00000000-78e0-4cad-bf01-63cf1e4b1dca\"}]",`+ - `"[{\"id\":\"00000000-f688-49d4-a8e2-ee394f1ac1b1\"}]"}`, groups["grouped"]) -} From f987ecda2fd95c16a99fd1b55ca6b474f64772a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 28 Apr 2026 15:36:56 +0200 Subject: [PATCH 33/34] RHINENG-25147: remove workspaces from model --- base/inventory/inventory.go | 32 -------------------------------- base/models/models.go | 10 ++++------ listener/common_test.go | 2 -- listener/upload.go | 3 --- listener/upload_test.go | 5 ----- 5 files changed, 4 insertions(+), 48 deletions(-) diff --git a/base/inventory/inventory.go b/base/inventory/inventory.go index db615358f..e2cfcdc31 100644 --- a/base/inventory/inventory.go +++ b/base/inventory/inventory.go @@ -2,9 +2,6 @@ package inventory import ( "app/base/types" - "database/sql/driver" - "encoding/json" - "errors" "github.com/google/uuid" ) @@ -86,35 +83,6 @@ type Group struct { Name string `json:"name"` } -// Groups is a slice of Group that implements driver.Valuer and sql.Scanner -// for storing/loading as JSONB in the database (e.g. system_inventory.workspaces). -type Groups []Group - -// Value implements driver.Valuer for GORM: marshal to JSON for DB write. -func (g *Groups) Value() (driver.Value, error) { - if g == nil { - return nil, nil - } - return json.Marshal(g) -} - -// Scan implements sql.Scanner for GORM: unmarshal from JSON on DB read. -func (g *Groups) Scan(value interface{}) error { - if value == nil { - *g = nil - return nil - } - b, ok := value.([]byte) - if !ok { - return errors.New("inventory.Groups: type assertion to []byte failed") - } - if len(b) == 0 { - *g = nil - return nil - } - return json.Unmarshal(b, g) -} - type Workloads struct { Sap SapWorkload `json:"sap,omitempty"` Ansible AnsibleWorkload `json:"ansible,omitempty"` diff --git a/base/models/models.go b/base/models/models.go index 100c8c1b9..666a2ef4f 100644 --- a/base/models/models.go +++ b/base/models/models.go @@ -1,7 +1,6 @@ package models import ( - "app/base/inventory" "time" "github.com/google/uuid" @@ -71,11 +70,10 @@ type SystemInventory struct { BuiltPkgcache bool `gorm:"column:built_pkgcache"` Arch *string Bootc bool - Tags []byte `gorm:"column:tags"` - Created time.Time // set by trigger system_platform_insert_trigger - Workspaces *inventory.Groups `gorm:"column:workspaces"` - WorkspaceID *string `gorm:"column:workspace_id"` - WorkspaceName *string `gorm:"column:workspace_name"` + Tags []byte `gorm:"column:tags"` + Created time.Time // set by trigger system_platform_insert_trigger + WorkspaceID *string `gorm:"column:workspace_id"` + WorkspaceName *string `gorm:"column:workspace_name"` StaleTimestamp *time.Time StaleWarningTimestamp *time.Time CulledTimestamp *time.Time diff --git a/listener/common_test.go b/listener/common_test.go index 19883dbb3..2441040b1 100644 --- a/listener/common_test.go +++ b/listener/common_test.go @@ -94,8 +94,6 @@ func assertSystemInventoryProfileMatchesHost(t *testing.T, inventoryID string, h assert.JSONEq(t, string(utils.MarshalNilToJSONB(host.Tags)), string(inv.Tags)) - require.NotNil(t, inv.Workspaces) - assert.Equal(t, host.Groups, []inventory.Group(*inv.Workspaces)) if hostWorkspaceID := host.Groups[0].ID; hostWorkspaceID != "" { require.NotNil(t, inv.WorkspaceID) assert.Equal(t, hostWorkspaceID, *inv.WorkspaceID) diff --git a/listener/upload.go b/listener/upload.go index eb49dc4dc..30d0cce03 100644 --- a/listener/upload.go +++ b/listener/upload.go @@ -336,7 +336,6 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, "arch", "bootc", "tags", - "workspaces", "workspace_id", "workspace_name", "os_name", @@ -360,7 +359,6 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, isBootc := len(host.SystemProfile.BootcStatus.Booted.Image) > 0 updatesReqJSONString := string(updatesReqJSON) - hostWorkspaces := inventory.Groups(host.Groups) var workspaceID, workspaceName *string if l := len(host.Groups); l >= 1 { if host.Groups[0].ID != "" { @@ -383,7 +381,6 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, DisplayName: displayName, Created: host.Created, Tags: utils.MarshalNilToJSONB(host.Tags), - Workspaces: &hostWorkspaces, WorkspaceID: workspaceID, WorkspaceName: workspaceName, VmaasJSON: utils.EmptyToNil(&updatesReqJSONString), diff --git a/listener/upload_test.go b/listener/upload_test.go index 696b59ee0..8e7019e14 100644 --- a/listener/upload_test.go +++ b/listener/upload_test.go @@ -477,7 +477,6 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { vmaasJSON := "this_is_json" // insert new row hostEvent := createTestUploadEvent("1", id, "puptoo", false, true, "created") - hostWorkspaces := inventory.Groups(hostEvent.Host.Groups) workspaceID := &hostEvent.Host.Groups[0].ID workspaceName := &hostEvent.Host.Groups[0].Name inStore := &models.SystemPlatformV2{ @@ -489,7 +488,6 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { SatelliteManaged: false, Created: hostEvent.Host.Created, Tags: utils.MarshalNilToJSONB(hostEvent.Host.Tags), - Workspaces: &hostWorkspaces, WorkspaceID: workspaceID, WorkspaceName: workspaceName, OSName: utils.EmptyToNil(&hostEvent.Host.SystemProfile.OperatingSystem.Name), @@ -534,8 +532,6 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { assert.Contains(t, string(inventoryAfterInsert.Tags), `"key": "env"`) assert.Contains(t, string(inventoryAfterInsert.Tags), `"value": "prod"`) - require.NotNil(t, inventoryAfterInsert.Workspaces) - assert.Equal(t, hostEvent.Host.Groups, []inventory.Group(*inventoryAfterInsert.Workspaces)) require.NotNil(t, inventoryAfterInsert.WorkspaceID) assert.Equal(t, hostEvent.Host.Groups[0].ID, *inventoryAfterInsert.WorkspaceID) require.NotNil(t, inventoryAfterInsert.WorkspaceName) @@ -577,7 +573,6 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { SatelliteManaged: true, Created: hostEvent.Host.Created, Tags: utils.MarshalNilToJSONB(hostEvent.Host.Tags), - Workspaces: &hostWorkspaces, WorkspaceID: workspaceID, WorkspaceName: workspaceName, OSName: utils.EmptyToNil(&hostEvent.Host.SystemProfile.OperatingSystem.Name), From d19ec59a5a2892fceec73c4f9b82c4101627e37c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Dugovi=C4=8D?= Date: Tue, 21 Apr 2026 15:18:38 +0200 Subject: [PATCH 34/34] RHINENG-25147: update openapi --- docs/v3/openapi.json | 107 +++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/docs/v3/openapi.json b/docs/v3/openapi.json index 0c4149f8a..0015754b8 100644 --- a/docs/v3/openapi.json +++ b/docs/v3/openapi.json @@ -6333,12 +6333,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "id": { "type": "string" }, @@ -6377,6 +6371,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -6415,12 +6415,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "last_upload": { "type": "string" }, @@ -6456,6 +6450,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -6725,12 +6725,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "id": { "type": "string" }, @@ -6763,6 +6757,12 @@ }, "update_status": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -6974,12 +6974,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "id": { "type": "string" }, @@ -7051,6 +7045,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7062,17 +7062,6 @@ } } }, - "controllers.SystemGroup": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - }, "controllers.SystemItem": { "type": "object", "properties": { @@ -7123,12 +7112,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "installable_other_count": { "type": "integer" }, @@ -7197,6 +7180,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7239,12 +7228,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "installable_other_count": { "type": "integer" }, @@ -7328,6 +7311,12 @@ }, "third_party": { "type": "boolean" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7601,12 +7590,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "installable_other_count": { "type": "integer" }, @@ -7633,6 +7616,12 @@ "items": { "$ref": "#/components/schemas/controllers.SystemTag" } + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7670,12 +7659,6 @@ "display_name": { "type": "string" }, - "groups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/controllers.SystemGroup" - } - }, "id": { "type": "string" }, @@ -7705,6 +7688,12 @@ "items": { "$ref": "#/components/schemas/controllers.SystemTag" } + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } },