diff --git a/base/core/gintesting.go b/base/core/gintesting.go index 7108536c2..02be78cd1 100644 --- a/base/core/gintesting.go +++ b/base/core/gintesting.go @@ -17,6 +17,15 @@ type ContextKV struct { var V3APICtx = ContextKV{Key: utils.KeyApiver, Value: 3} +var WorkspacesTestCtx = ContextKV{ + Key: utils.KeyInventoryWorkspaces, + Value: []string{ + "00000000-0000-0000-0000-000000000001", + "00000000-0000-0000-0000-000000000002", + "00000000-0000-0000-0000-999999999999", + }, +} + func InitRouter(handler gin.HandlerFunc, contextKVs ...ContextKV) *gin.Engine { return InitRouterWithPath(handler, "/", contextKVs...) } @@ -32,6 +41,7 @@ func InitRouterWithParams(handler gin.HandlerFunc, account int, method, path str router.Use(func(c *gin.Context) { // set default api version for tests to latest c.Set(utils.KeyApiver, LatestAPIVersion) + c.Set(utils.KeyInventoryWorkspaces, WorkspacesTestCtx.Value) for _, kv := range contextKVs { c.Set(kv.Key, kv.Value) } diff --git a/base/database/testing.go b/base/database/testing.go index 075496cb7..8012571ce 100644 --- a/base/database/testing.go +++ b/base/database/testing.go @@ -26,6 +26,16 @@ func TestWorkspacesGroup1() *inventory.Groups { return &g } +func TestWorkspace1IDPtr() *uuid.UUID { + id := uuid.MustParse(TestWorkspace1ID) + return &id +} + +func TestWorkspace1NamePtr() *string { + name := "group1" + return &name +} + func DebugWithCachesCheck(part string, fun func()) { fun() validAfter, err := CheckCachesValidRet() diff --git a/base/database/utils.go b/base/database/utils.go index 9db75f14d..84bf3490c 100644 --- a/base/database/utils.go +++ b/base/database/utils.go @@ -27,16 +27,16 @@ 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 { +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) tx = (joinsT)(joins).apply(tx) - return ApplyInventoryWorkspaceFilter(tx, groups) + return ApplyInventoryWorkspaceFilter(tx, workspaceIDs) } -func SystemAdvisories(tx *gorm.DB, accountID int, groups map[string]string, joins ...join) *gorm.DB { - tx = Systems(tx, accountID, groups). +func SystemAdvisories(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { + 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) } @@ -47,8 +47,8 @@ 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). +func SystemPackages(tx *gorm.DB, accountID int, workspaceIDs []string, joins ...join) *gorm.DB { + 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") @@ -66,9 +66,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 uuid.UUID, +func SystemAdvisoriesByInventoryID(tx *gorm.DB, accountID int, workspaceIDs []string, inventoryID uuid.UUID, joins ...join) *gorm.DB { - tx = SystemAdvisories(tx, accountID, groups).Where("si.inventory_id = ?", inventoryID) + tx = SystemAdvisories(tx, accountID, workspaceIDs).Where("si.inventory_id = ?", inventoryID) return (joinsT)(joins).apply(tx) } @@ -241,21 +241,12 @@ func ReadReplicaConfigured() bool { return len(utils.CoreCfg.DBReadReplicaHost) > 0 && utils.CoreCfg.DBReadReplicaPort != 0 } -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 +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 } - - 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) + return tx.Where("si.workspace_id IN (?)", workspaceIDs) } // LEFT JOIN templates to spatch (system_patch) diff --git a/base/database/utils_test.go b/base/database/utils_test.go index f28a18c1e..d3a7f5dae 100644 --- a/base/database/utils_test.go +++ b/base/database/utils_test.go @@ -11,26 +11,23 @@ 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 nonExisting = "00000000-0000-0000-3333-000000000000" -var testCases = []map[int64]map[string]string{ - {nGroup1: {utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]"}`}}, - {nGroup2: {utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000002\"}]"}`}}, - {nGroup1 + nGroup2: {utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]","[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000002\"}]"}`}}, //nolint:lll - {nGroup1 + nUngrouped: { - utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]"}`, - utils.KeyUngrouped: "[]", - }}, - {nUngrouped: { - utils.KeyGrouped: `{"[{\"id\":\"non-existing-group\"}]"}`, - utils.KeyUngrouped: "[]", - }}, - {0: {utils.KeyGrouped: `{"[{\"id\":\"non-existing-group\"}]"}`}}, - {nUngrouped: {utils.KeyUngrouped: "[]"}}, - {nAll: {}}, +var testCases = []map[int64][]string{ + {nGroup1: {"00000000-0000-0000-0000-000000000001"}}, + {nGroup2: {"00000000-0000-0000-0000-000000000002"}}, + {nGroup1 + nGroup2: {"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002"}}, + {nGroup1 + nUngrouped: {"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-999999999999"}}, + {nUngrouped: {nonExisting, "00000000-0000-0000-0000-999999999999"}}, + {0: {nonExisting}}, + {nUngrouped: {"00000000-0000-0000-0000-999999999999"}}, + {nAll: {"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002", + "00000000-0000-0000-0000-999999999999"}}, {nAll: nil}, + {nAll: {}}, } func TestApplyInventoryWorkspaceFilter(t *testing.T) { @@ -38,11 +35,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/base/models/models.go b/base/models/models.go index 5d61e0a5e..0c2c0887e 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 *uuid.UUID `gorm:"column:workspace_id"` + WorkspaceName *string `gorm:"column:workspace_name"` StaleTimestamp *time.Time StaleWarningTimestamp *time.Time CulledTimestamp *time.Time diff --git a/base/utils/gin.go b/base/utils/gin.go index 73e622384..58501973e 100644 --- a/base/utils/gin.go +++ b/base/utils/gin.go @@ -13,14 +13,12 @@ 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" + KeyInventoryWorkspaces = "workspaceIDs" // ReadHeaderTimeout same as nginx default ReadHeaderTimeout = 60 * time.Second ) diff --git a/database_admin/migrations/159_create_workspace_columns_indexes.down.sql b/database_admin/migrations/159_create_workspace_columns_indexes.down.sql new file mode 100644 index 000000000..69945e946 --- /dev/null +++ b/database_admin/migrations/159_create_workspace_columns_indexes.down.sql @@ -0,0 +1,26 @@ +DROP INDEX IF EXISTS system_inventory_workspace_id_index; + +CREATE OR REPLACE FUNCTION sync_system_inventory_workspace() + RETURNS TRIGGER AS +$$ +BEGIN + IF NEW.workspaces IS NOT NULL + AND jsonb_typeof(NEW.workspaces) = 'array' + AND jsonb_array_length(NEW.workspaces) > 0 + THEN + NEW.workspace_id := (NEW.workspaces->0->>'id')::UUID; + NEW.workspace_name := NEW.workspaces->0->>'name'; + IF NEW.workspace_name IS NULL OR empty(NEW.workspace_name) THEN + RAISE EXCEPTION 'workspace_name must not be empty'; + END IF; + ELSIF TG_OP = 'INSERT' THEN + RAISE EXCEPTION 'workspaces required'; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +SELECT create_table_partition_triggers('system_inventory_sync_workspace', + $$BEFORE INSERT OR UPDATE OF workspaces$$, + 'system_inventory', + $$FOR EACH ROW EXECUTE PROCEDURE sync_system_inventory_workspace()$$); diff --git a/database_admin/migrations/159_create_workspace_columns_indexes.up.sql b/database_admin/migrations/159_create_workspace_columns_indexes.up.sql new file mode 100644 index 000000000..118a6f8ad --- /dev/null +++ b/database_admin/migrations/159_create_workspace_columns_indexes.up.sql @@ -0,0 +1,8 @@ +SELECT drop_table_partition_triggers('system_inventory_sync_workspace', + $$BEFORE INSERT OR UPDATE OF workspaces$$, + 'system_inventory', + $$FOR EACH ROW EXECUTE PROCEDURE sync_system_inventory_workspace()$$); + +DROP FUNCTION IF EXISTS sync_system_inventory_workspace(); + +CREATE INDEX IF NOT EXISTS system_inventory_workspace_id_index ON system_inventory (workspace_id); diff --git a/database_admin/schema/create_schema.sql b/database_admin/schema/create_schema.sql index dc1772835..1019113c5 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 (158, false); +VALUES (159, false); -- --------------------------------------------------------------------------- -- Functions @@ -65,26 +65,6 @@ END; $check_unchanged$ LANGUAGE 'plpgsql'; -CREATE OR REPLACE FUNCTION sync_system_inventory_workspace() - RETURNS TRIGGER AS -$$ -BEGIN - IF NEW.workspaces IS NOT NULL - AND jsonb_typeof(NEW.workspaces) = 'array' - AND jsonb_array_length(NEW.workspaces) > 0 - THEN - NEW.workspace_id := (NEW.workspaces->0->>'id')::UUID; - NEW.workspace_name := NEW.workspaces->0->>'name'; - IF NEW.workspace_name IS NULL OR empty(NEW.workspace_name) THEN - RAISE EXCEPTION 'workspace_name must not be empty'; - END IF; - ELSIF TG_OP = 'INSERT' THEN - RAISE EXCEPTION 'workspaces required'; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - CREATE OR REPLACE FUNCTION on_system_update() -- this trigger updates advisory_account_data when server changes its stale flag RETURNS TRIGGER @@ -706,15 +686,11 @@ SELECT create_table_partition_triggers('system_inventory_on_update', 'system_inventory', $$FOR EACH ROW EXECUTE PROCEDURE on_system_update()$$); -SELECT create_table_partition_triggers('system_inventory_sync_workspace', - $$BEFORE INSERT OR UPDATE OF workspaces$$, - 'system_inventory', - $$FOR EACH ROW EXECUTE PROCEDURE sync_system_inventory_workspace()$$); - 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 TABLE IF NOT EXISTS deleted_system ( diff --git a/dev/test_data.sql b/dev/test_data.sql index 4c3306116..386e7d17a 100644 --- a/dev/test_data.sql +++ b/dev/test_data.sql @@ -7,7 +7,6 @@ DELETE FROM deleted_system; DELETE FROM repo; DELETE FROM timestamp_kv; DELETE FROM advisory_account_data; -DELETE FROM account_advisory; DELETE FROM package_account_data; DELETE FROM package; DELETE FROM package_name; @@ -25,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": "aaaaaaaa-0000-0000-0000-000000000001", "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": "aaaaaaaa-0000-0000-0000-000000000001", "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": "aaaaaaaa-0000-0000-0000-000000000001", "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": "aaaaaaaa-0000-0000-0000-000000000001", "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": "aaaaaaaa-0000-0000-0000-000000000001", "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": "aaaaaaaa-0000-0000-0000-000000000001", "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, 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', '00000000-0000-0000-0000-000000000001', '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', '00000000-0000-0000-0000-000000000001', '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', '00000000-0000-0000-0000-000000000001', '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', '00000000-0000-0000-0000-000000000001', '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', '00000000-0000-0000-0000-000000000001', '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', '00000000-0000-0000-0000-000000000001', '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), @@ -40,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": "aaaaaaaa-0000-0000-0000-000000000002", "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, 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', '00000000-0000-0000-0000-000000000002', '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": "aaaaaaaa-0000-0000-0000-000000000002", "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', '[{"id": "bbbbbbbb-0000-0000-0000-000000000003", "name": "other"}]', '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', '[{"id": "bbbbbbbb-0000-0000-0000-000000000003", "name": "other"}]', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '00000000-0000-0000-0000-000000000002', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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), @@ -58,29 +57,27 @@ 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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '[{"id": "aaaaaaaa-0000-0000-0000-000000000001", "name": "group1"}]', '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', '00000000-0000-0000-0000-999999999999', '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', '00000000-0000-0000-0000-999999999999', '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": "aaaaaaaa-0000-0000-0000-000000000001", "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, 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', '00000000-0000-0000-0000-000000000001', '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); -UPDATE system_inventory SET workspaces = '[]'::jsonb WHERE id IN (11, 12, 13, 14, 15, 16, 17); - INSERT INTO advisory_metadata (id, name, description, synopsis, summary, solution, advisory_type_id, public_date, modified_date, url, severity_id, cve_list, release_versions) VALUES (1, 'RH-1', 'adv-1-des', 'adv-1-syn', 'adv-1-sum', 'adv-1-sol', 1, '2016-09-22 12:00:00-04', '2017-09-22 12:00:00-04', 'url1', NULL, NULL, '["7.0","7Server"]'), diff --git a/docs/v3/openapi.json b/docs/v3/openapi.json index edf4c0964..d3b82f1fa 100644 --- a/docs/v3/openapi.json +++ b/docs/v3/openapi.json @@ -6833,6 +6833,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -6912,6 +6918,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7219,6 +7231,12 @@ }, "update_status": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7507,6 +7525,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7653,6 +7677,12 @@ }, "template_uuid": { "type": "string" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -7784,6 +7814,12 @@ }, "third_party": { "type": "boolean" + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -8100,6 +8136,12 @@ "items": { "$ref": "#/components/schemas/controllers.SystemTag" } + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, @@ -8172,6 +8214,12 @@ "items": { "$ref": "#/components/schemas/controllers.SystemTag" } + }, + "workspace_id": { + "type": "string" + }, + "workspace_name": { + "type": "string" } } }, diff --git a/evaluator/advisory_update.go b/evaluator/advisory_update.go index 5d411b59f..635b0618d 100644 --- a/evaluator/advisory_update.go +++ b/evaluator/advisory_update.go @@ -32,15 +32,10 @@ func getChangedAdvisoryIDs(advisoriesByName extendedAdvisoryMap) []int64 { func createAdvisoryUpdateEvent(system *models.SystemPlatformV2, advisoryIDs []int64) mqueue.AdvisoryUpdateEvent { var workspaceID uuid.UUID - if system.Inventory.Workspaces != nil && len(*system.Inventory.Workspaces) > 0 { - parsed, err := uuid.Parse((*system.Inventory.Workspaces)[0].ID) - if err != nil { - utils.LogWarn("inventoryID", system.GetInventoryID(), "err", err.Error(), "unable to parse workspace ID") - } else { - workspaceID = parsed - } + if system.Inventory.WorkspaceID != nil { + workspaceID = *system.Inventory.WorkspaceID } else { - utils.LogWarn("inventoryID", system.GetInventoryID(), "no workspaces for system") + utils.LogWarn("inventoryID", system.GetInventoryID(), "no workspace for system") } return mqueue.AdvisoryUpdateEvent{ diff --git a/evaluator/advisory_update_test.go b/evaluator/advisory_update_test.go index 6e77862ff..f3d012709 100644 --- a/evaluator/advisory_update_test.go +++ b/evaluator/advisory_update_test.go @@ -3,7 +3,6 @@ package evaluator import ( "app/base/core" "app/base/database" - "app/base/inventory" "app/base/models" "app/base/mqueue" "app/base/utils" @@ -28,14 +27,15 @@ func TestGetChangedAdvisoryIDs(t *testing.T) { } func TestCreateAdvisoryUpdateEvent(t *testing.T) { - wsID := "d964b282-17f6-47ab-b596-a4a34d711f04" - workspaces := inventory.Groups{{ID: wsID, Name: "test-workspace"}} + wsID := uuid.MustParse("d964b282-17f6-47ab-b596-a4a34d711f04") + wsName := "test-workspace" system := &models.SystemPlatformV2{ Inventory: models.SystemInventory{ - ID: 1, - RhAccountID: rhAccountID, - InventoryID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), - Workspaces: &workspaces, + ID: 1, + RhAccountID: rhAccountID, + InventoryID: uuid.MustParse("00000000-0000-0000-0000-000000000001"), + WorkspaceID: &wsID, + WorkspaceName: &wsName, }, Patch: models.SystemPatch{}, } @@ -44,7 +44,7 @@ func TestCreateAdvisoryUpdateEvent(t *testing.T) { event := createAdvisoryUpdateEvent(system, changedAdvisoryIDs) assert.Equal(t, rhAccountID, event.RhAccountID) - assert.Equal(t, uuid.MustParse(wsID), event.WorkspaceID) + assert.Equal(t, wsID, event.WorkspaceID) assert.ElementsMatch(t, changedAdvisoryIDs, event.AdvisoryIDs) assert.False(t, event.ProducedAt.Time().IsZero()) } diff --git a/go.mod b/go.mod index ea6f7d0db..6bd8510df 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/bytedance/sonic/loader v0.5.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/ezamriy/gorpm v0.0.0-20160905202458-25f7273cbf51 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect @@ -59,16 +60,16 @@ require ( github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.22.5 // indirect - github.com/go-openapi/jsonreference v0.21.5 // indirect - github.com/go-openapi/spec v0.22.4 // indirect - github.com/go-openapi/swag/conv v0.25.5 // indirect - github.com/go-openapi/swag/jsonname v0.25.5 // indirect - github.com/go-openapi/swag/jsonutils v0.25.5 // indirect - github.com/go-openapi/swag/loading v0.25.5 // indirect - github.com/go-openapi/swag/stringutils v0.25.5 // indirect - github.com/go-openapi/swag/typeutils v0.25.5 // indirect - github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/jsonreference v0.21.6 // indirect + github.com/go-openapi/spec v0.22.5 // indirect + github.com/go-openapi/swag/conv v0.26.1 // indirect + github.com/go-openapi/swag/jsonname v0.26.1 // indirect + github.com/go-openapi/swag/jsonutils v0.26.1 // indirect + github.com/go-openapi/swag/loading v0.26.1 // indirect + github.com/go-openapi/swag/stringutils v0.26.1 // indirect + github.com/go-openapi/swag/typeutils v0.26.1 // indirect + github.com/go-openapi/swag/yamlutils v0.26.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect @@ -108,14 +109,18 @@ require ( github.com/prometheus/procfs v0.20.1 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/swaggo/swag v1.16.6 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect + github.com/urfave/cli/v2 v2.27.7 // indirect github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect github.com/zitadel/logging v0.7.0 // indirect github.com/zitadel/oidc/v3 v3.47.5 // indirect github.com/zitadel/schema v1.3.2 // indirect @@ -129,18 +134,20 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.25.0 // indirect golang.org/x/crypto v0.52.0 // indirect - golang.org/x/mod v0.36.0 // indirect + golang.org/x/mod v0.37.0 // indirect golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.20.0 // indirect + golang.org/x/sync v0.21.0 // indirect golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect + golang.org/x/text v0.38.0 // indirect golang.org/x/tools v0.45.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 // indirect google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.5.6 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) replace github.com/segmentio/kafka-go v0.4.49 => github.com/MichaelMraka/kafka-go v0.0.0-20251014134425-230b5408c208 diff --git a/go.sum b/go.sum index 7d867481c..5920e3138 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,8 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -82,31 +84,54 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= +github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= +github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= +github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= +github.com/go-openapi/spec v0.22.5 h1:KhO7RBlKQfonUWX2WzQCoLIXVA6AcNqDGZ3a1Dutdlo= +github.com/go-openapi/spec v0.22.5/go.mod h1:vxpOtMya5TXtENXKE5bKqv5NjocVhyhxHrlZfvKnZ74= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg= +github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A= github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= +github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY= +github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ= github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ= github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w= +github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E= github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU= +github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk= github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU= +github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= +github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -290,10 +315,14 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/segmentio/kafka-go v0.4.51 h1:JgDPPG75tC1rWIS2Me6MwcvXJ6f49UQ4HjAOef71Hno= github.com/segmentio/kafka-go v0.4.51/go.mod h1:Y1gn60kzLEEaW28YshXyk2+VCUKbJ3Qr6DrnT3i4+9E= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= @@ -322,6 +351,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= +github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -330,6 +361,8 @@ github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= +github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zitadel/logging v0.7.0 h1:eugftwMM95Wgqwftsvj81isL0JK/hoScVqp/7iA2adQ= @@ -389,6 +422,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -411,6 +446,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -445,6 +482,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -504,3 +543,5 @@ modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/listener/common_test.go b/listener/common_test.go index 036cd4fd8..df7887df2 100644 --- a/listener/common_test.go +++ b/listener/common_test.go @@ -56,7 +56,6 @@ func createTestSystemInDB(t *testing.T, inventoryID uuid.UUID, rhAccountID int, RhAccountID: rhAccountID, DisplayName: displayName, Tags: []byte("[]"), - Workspaces: database.TestWorkspacesGroup1(), } assert.NoError(t, database.DB.Create(&inv).Error) assert.NoError(t, database.DB.Create(&models.SystemPatch{ @@ -91,7 +90,7 @@ func assertSystemInDB(t *testing.T, inventoryID uuid.UUID, rhAccountID *int, rep // 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, funlen +// nolint: unparam,funlen func assertSystemInventoryProfileMatchesHost(t *testing.T, inventoryID uuid.UUID, host *Host) { t.Helper() var inv models.SystemInventory @@ -99,8 +98,23 @@ func assertSystemInventoryProfileMatchesHost(t *testing.T, inventoryID uuid.UUID 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 len(host.Groups) == 0 { + assert.Nil(t, inv.WorkspaceID) + assert.Nil(t, inv.WorkspaceName) + } else { + if hostWorkspaceID := host.Groups[0].ID; hostWorkspaceID != "" { + require.NotNil(t, inv.WorkspaceID) + assert.Equal(t, hostWorkspaceID, inv.WorkspaceID.String()) + } 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) diff --git a/listener/upload.go b/listener/upload.go index 724f69e68..a610a651a 100644 --- a/listener/upload.go +++ b/listener/upload.go @@ -335,7 +335,8 @@ func updateSystemPlatform(tx *gorm.DB, accountID int, host *Host, "arch", "bootc", "tags", - "workspaces", + "workspace_id", + "workspace_name", "os_name", "os_major", "os_minor", @@ -357,7 +358,26 @@ 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 *uuid.UUID + var workspaceName *string + if l := len(host.Groups); l > 0 { + workspace := host.Groups[0] + uuid, err := uuid.Parse(workspace.ID) + if err != nil { + utils.LogError("workspaceID", workspace.ID, "invalid workspace UUID") + return nil, errors.New("received invalid workspace UUID") + } + workspaceID = &uuid + if workspace.Name != "" { + workspaceName = &workspace.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, @@ -365,7 +385,8 @@ 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), JSONChecksum: utils.EmptyToNil(&jsonChecksum), LastUpload: host.GetLastUpload(), @@ -546,7 +567,8 @@ func fixEpelRepos(sys *inventory.SystemProfile, repos []string) []string { func updateRepos(tx *gorm.DB, profile inventory.SystemProfile, rhAccountID int, systemID int64, repos []string) (addedRepos int64, addedSysRepos int64, deletedSysRepos int64, err error) { - defer utils.ObserveSecondsSince(time.Now(), messagePartDuration.WithLabelValues("update-repos")) + tStart := time.Now() + defer utils.ObserveSecondsSince(tStart, messagePartDuration.WithLabelValues("update-repos")) repos = fixEpelRepos(&profile, repos) repoIDs, addedRepos, err := ensureReposInDB(tx, repos) if err != nil { @@ -741,7 +763,8 @@ func processModules(systemProfile *inventory.SystemProfile) *[]vmaas.UpdatesV3Re // We have received new upload, update stored host data, and re-evaluate the host against VMaaS func processUpload(host *Host, yumUpdates *YumUpdates) (*models.SystemPlatformV2, error) { - defer utils.ObserveSecondsSince(time.Now(), messagePartDuration.WithLabelValues("upload-processing")) + tStart := time.Now() + defer utils.ObserveSecondsSince(tStart, messagePartDuration.WithLabelValues("upload-processing")) // Ensure we have account stored accountID, err := middlewares.GetOrCreateAccount(host.GetOrgID()) if err != nil { diff --git a/listener/upload_test.go b/listener/upload_test.go index 67d513381..918eb5067 100644 --- a/listener/upload_test.go +++ b/listener/upload_test.go @@ -479,7 +479,8 @@ func TestStoreOrUpdateSysPlatform(t *testing.T) { vmaasJSON := "this_is_json" // insert new row hostEvent := createTestUploadEvent("1", testInventoryID, "puptoo", false, true, "created") - hostWorkspaces := inventory.Groups(hostEvent.Host.Groups) + workspaceID := uuid.MustParse(hostEvent.Host.Groups[0].ID) + workspaceName := &hostEvent.Host.Groups[0].Name inStore := &models.SystemPlatformV2{ Inventory: models.SystemInventory{ InventoryID: uuid.MustParse("99990000-0000-0000-0000-000000000001"), @@ -489,7 +490,8 @@ 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), OSMajor: &hostEvent.Host.SystemProfile.OperatingSystem.Major, OSMinor: &hostEvent.Host.SystemProfile.OperatingSystem.Minor, @@ -532,8 +534,10 @@ 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.String()) + 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) @@ -571,7 +575,8 @@ 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), OSMajor: &hostEvent.Host.SystemProfile.OperatingSystem.Major, OSMinor: &hostEvent.Host.SystemProfile.OperatingSystem.Minor, diff --git a/manager/controllers/advisories.go b/manager/controllers/advisories.go index e06c88368..ba8e020ab 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.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`). @@ -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/advisory_systems.go b/manager/controllers/advisory_systems.go index 0b8432876..70cd53504 100644 --- a/manager/controllers/advisory_systems.go +++ b/manager/controllers/advisory_systems.go @@ -42,6 +42,7 @@ type AdvisorySystemItemAttributes struct { SystemTimestamps SystemTags SystemGroups + SystemWorkspace BaselineIDAttr BaselineNameAttr TemplateAttibutes @@ -71,7 +72,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 +94,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 +271,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.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/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 462e530aa..382441346 100644 --- a/manager/controllers/advisory_systems_export_test.go +++ b/manager/controllers/advisory_systems_export_test.go @@ -33,12 +33,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':'aaaaaaaa-0000-0000-0000-000000000001','name':'group1'}]\","+ //nolint:lll - "0,,temp1-1,99900000-0000-0000-0000-000000000001,Installable,false,false,"+ - "00000000-0000-0000-0000-000000000001", + "{'key':'k2','namespace':'ns1','value':'val2'}]\",\"[{'id':'00000000-0000-0000-0000-000000000001',"+ + "'name':'group1'}]\",00000000-0000-0000-0000-000000000001,group1,0,,temp1-1,99900000-0000-0000-0000-000000000001,"+ + "Installable,false,false,00000000-0000-0000-0000-000000000001", lines[1]) } diff --git a/manager/controllers/common_attributes.go b/manager/controllers/common_attributes.go index f591cc4b5..98937a25b 100644 --- a/manager/controllers/common_attributes.go +++ b/manager/controllers/common_attributes.go @@ -29,7 +29,12 @@ type SystemTags struct { } type SystemGroups struct { - Groups SystemGroupsList `json:"groups" csv:"groups" query:"si.workspaces" gorm:"column:groups" order_query:"si.workspaces->0->>'name'"` + Groups SystemGroupsList `json:"groups" csv:"groups" query:"CASE WHEN si.workspace_id IS NOT NULL THEN jsonb_build_array(jsonb_build_object('id', si.workspace_id, 'name', si.workspace_name)) ELSE '[]'::jsonb END" order_query:"si.workspace_name"` +} + +type SystemWorkspace struct { + WorkspaceID *uuid.UUID `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 diff --git a/manager/controllers/package_systems.go b/manager/controllers/package_systems.go index c948e2242..bd7279298 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 { @@ -54,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.SystemPackages(db, acc, workspaceIDs, database.JoinTemplates, database.JoinInstallableApplicablePackages). Select(PackageSystemsSelect). Where("si.stale = false"). @@ -67,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") @@ -87,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 37dee8cca..e34e00533 100644 --- a/manager/controllers/package_systems_export_test.go +++ b/manager/controllers/package_systems_export_test.go @@ -39,14 +39,17 @@ 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,"+ + "\"[{'id':'00000000-0000-0000-0000-999999999999','name':'root-ws'}]\","+ + "00000000-0000-0000-0000-999999999999,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,\"[{'id':'00000000-0000-0000-0000-999999999999','name':'root-ws'}]\","+ + "00000000-0000-0000-0000-999999999999,root-ws", lines[2]) } func TestPackageSystemsExportInvalidName(t *testing.T) { diff --git a/manager/controllers/package_versions.go b/manager/controllers/package_versions.go index 78bf80a8c..07df60435 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.SystemPackages(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/packages.go b/manager/controllers/packages.go index 59b8b8eea..ea4d14de0 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.Systems(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/system_advisories.go b/manager/controllers/system_advisories.go index 4ad30f88e..ac69064a5 100644 --- a/manager/controllers/system_advisories.go +++ b/manager/controllers/system_advisories.go @@ -73,7 +73,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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -101,7 +101,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 @@ -196,8 +196,8 @@ func SystemAdvisoriesIDsHandler(c *gin.Context) { c.JSON(http.StatusOK, &resp) } -func buildSystemAdvisoriesQuery(db *gorm.DB, account int, groups map[string]string, inventoryID uuid.UUID) *gorm.DB { - query := database.SystemAdvisoriesByInventoryID(db, account, groups, inventoryID, +func buildSystemAdvisoriesQuery(db *gorm.DB, account int, workspaceIDs []string, inventoryID uuid.UUID) *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 76b104733..164bf055b 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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -55,7 +55,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_detail.go b/manager/controllers/system_detail.go index 2624c2546..29d8e4c8a 100644 --- a/manager/controllers/system_detail.go +++ b/manager/controllers/system_detail.go @@ -45,7 +45,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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -59,7 +59,7 @@ func SystemDetailHandler(c *gin.Context) { var systemDetail SystemDetailLookup db := middlewares.DBFromContext(c) - query := database.Systems(db, account, groups, database.JoinTemplates). + query := database.Systems(db, account, workspaceIDs, database.JoinTemplates). Select(database.MustGetSelect(&systemDetail)). Where("si.inventory_id = ?", inventoryID) @@ -150,7 +150,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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -164,7 +164,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.Systems(db, account, workspaceIDs). Select(column). Where("si.inventory_id = ?", inventoryID) diff --git a/manager/controllers/system_packages.go b/manager/controllers/system_packages.go index d6baa3d1b..5335248e8 100644 --- a/manager/controllers/system_packages.go +++ b/manager/controllers/system_packages.go @@ -57,8 +57,8 @@ type SystemPackageDBLoad struct { MetaTotalHelper } -func systemPackageQuery(db *gorm.DB, account int, groups map[string]string, inventoryID uuid.UUID) *gorm.DB { - query := database.SystemPackages(db, account, groups, database.JoinInstallableApplicablePackages). +func systemPackageQuery(db *gorm.DB, account int, workspaceIDs []string, inventoryID uuid.UUID) *gorm.DB { + 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). @@ -90,7 +90,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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -104,7 +104,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 90004354e..51d514ac4 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, err := uuid.Parse(c.Param("inventory_id")) if err != nil { @@ -47,7 +47,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/systems.go b/manager/controllers/systems.go index 481a6f910..a5f6ee2d6 100644 --- a/manager/controllers/systems.go +++ b/manager/controllers/systems.go @@ -97,6 +97,7 @@ type SystemItemAttributes struct { BaselineIDAttr TemplateAttibutes SystemGroups + SystemWorkspace SystemArch } @@ -199,9 +200,9 @@ func validateSystemsListIDs(ids []string) error { func systemsCommon(c *gin.Context, ids []string) (*gorm.DB, *ListMeta, []string, 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 @@ -459,6 +460,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.Systems(db, account, workspaceIDs, database.JoinTemplates).Select(SystemsSelect) } diff --git a/manager/controllers/systems_advisories_view.go b/manager/controllers/systems_advisories_view.go index 36422135a..3386aa0d6 100644 --- a/manager/controllers/systems_advisories_view.go +++ b/manager/controllers/systems_advisories_view.go @@ -8,12 +8,11 @@ import ( "net/http" "github.com/gin-gonic/gin" - "github.com/google/uuid" "gorm.io/gorm" ) type AdvisoryName string -type SystemID = uuid.UUID +type SystemID string type SystemsAdvisoriesRequest struct { Systems []SystemID `json:"systems"` @@ -73,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( 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 @@ -123,12 +122,12 @@ func systemsAdvisoriesQuery(c *gin.Context, db *gorm.DB, acc int, groups map[str 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.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 @@ -181,7 +180,7 @@ 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 if req.Limit != nil { @@ -192,9 +191,9 @@ 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) + q, meta, links, err = advisoriesSystemsQuery(c, db, acc, workspaceIDs, req) default: return nil, nil, nil, fmt.Errorf("unknown endpoint '%s'", endpoint) } @@ -291,11 +290,11 @@ func PostAdvisoriesSystems(c *gin.Context) { } for _, i := range data { - if _, has := response.Data[i.AdvisoryID]; has && i.SystemID == uuid.Nil { + if _, has := response.Data[i.AdvisoryID]; has && i.SystemID == "" { // don't append empty values to slices with len > 1 continue } - if _, has := response.Data[i.AdvisoryID]; !has && i.SystemID == uuid.Nil { + if _, has := response.Data[i.AdvisoryID]; !has && i.SystemID == "" { response.Data[i.AdvisoryID] = []SystemID{} continue } diff --git a/manager/controllers/systems_advisories_view_test.go b/manager/controllers/systems_advisories_view_test.go index 9758a6b7f..face8a2ea 100644 --- a/manager/controllers/systems_advisories_view_test.go +++ b/manager/controllers/systems_advisories_view_test.go @@ -13,10 +13,11 @@ import ( "github.com/stretchr/testify/assert" ) -func doTestView(t *testing.T, handler gin.HandlerFunc, q string, limit, offset *int) *httptest.ResponseRecorder { +func doTestView(t *testing.T, handler gin.HandlerFunc, q string, limit, offset *int, +) *httptest.ResponseRecorder { core.SetupTest(t) body := SystemsAdvisoriesRequest{ - Systems: []SystemID{testInventoryID1, testInventoryID2}, + Systems: []SystemID{"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002"}, Advisories: []AdvisoryName{"RH-1", "RH-3"}, Limit: limit, Offset: offset, @@ -34,33 +35,33 @@ func TestSystemsAdvisoriesView(t *testing.T) { w := doTestView(t, PostSystemsAdvisories, "", nil, nil) var output SystemsAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) - assert.Equal(t, output.Data[testInventoryID1][0], AdvisoryName("RH-1")) - assert.Equal(t, output.Data[testInventoryID1][1], AdvisoryName("RH-3")) - assert.Equal(t, 0, len(output.Data[testInventoryID2])) + assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][0], AdvisoryName("RH-1")) + assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][1], AdvisoryName("RH-3")) + assert.Equal(t, 0, len(output.Data["00000000-0000-0000-0000-000000000002"])) } func TestAdvisoriesSystemsView(t *testing.T) { w := doTestView(t, PostAdvisoriesSystems, "", nil, nil) var output AdvisoriesSystemsResponse CheckResponse(t, w, http.StatusOK, &output) - assert.Equal(t, output.Data["RH-1"][0], testInventoryID1) - assert.Equal(t, output.Data["RH-3"][0], testInventoryID1) + assert.Equal(t, output.Data["RH-1"][0], SystemID("00000000-0000-0000-0000-000000000001")) + assert.Equal(t, output.Data["RH-3"][0], SystemID("00000000-0000-0000-0000-000000000001")) } func TestSystemsAdvisoriesViewTags(t *testing.T) { w := doTestView(t, PostSystemsAdvisories, "?filter[system_profile][sap_sids]=DEF", nil, nil) var output SystemsAdvisoriesResponse CheckResponse(t, w, http.StatusOK, &output) - assert.Equal(t, output.Data[testInventoryID1][0], AdvisoryName("RH-1")) - assert.Equal(t, output.Data[testInventoryID1][1], AdvisoryName("RH-3")) + assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][0], AdvisoryName("RH-1")) + assert.Equal(t, output.Data["00000000-0000-0000-0000-000000000001"][1], AdvisoryName("RH-3")) } func TestAdvisoriesSystemsViewTags(t *testing.T) { w := doTestView(t, PostAdvisoriesSystems, "?filter[system_profile][sap_sids]=DEF", nil, nil) var output AdvisoriesSystemsResponse CheckResponse(t, w, http.StatusOK, &output) - assert.Equal(t, output.Data["RH-1"][0], testInventoryID1) - assert.Equal(t, output.Data["RH-3"][0], testInventoryID1) + assert.Equal(t, output.Data["RH-1"][0], SystemID("00000000-0000-0000-0000-000000000001")) + assert.Equal(t, output.Data["RH-3"][0], SystemID("00000000-0000-0000-0000-000000000001")) } func TestSystemAdvisoriesViewOffsetLimit(t *testing.T) { limit := 3 @@ -71,7 +72,7 @@ func TestSystemAdvisoriesViewOffsetLimit(t *testing.T) { assert.Equal(t, 2, len(output.Data)) assert.Equal(t, limit, output.Meta.Limit) assert.Equal(t, offset, output.Meta.Offset) - _, has := output.Data[testInventoryID1] + _, has := output.Data["00000000-0000-0000-0000-000000000001"] assert.True(t, has) } 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 090ae8f8e..3b77d8eb4 100644 --- a/manager/controllers/systems_export_test.go +++ b/manager/controllers/systems_export_test.go @@ -19,7 +19,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) @@ -61,7 +61,8 @@ 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':'aaaaaaaa-0000-0000-0000-000000000001','name':'group1'}]\",x86_64", + "\"[{'id':'00000000-0000-0000-0000-000000000001','name':'group1'}]\","+ + "00000000-0000-0000-0000-000000000001,group1,x86_64", lines[1]) } diff --git a/manager/controllers/systemtags.go b/manager/controllers/systemtags.go index 05fe05c7d..3ef2fdafd 100644 --- a/manager/controllers/systemtags.go +++ b/manager/controllers/systemtags.go @@ -72,11 +72,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.Systems(db, account, workspaceIDs). Select("jsonb_array_elements(si.tags) AS tag") query := db.Table("(?) AS sq", sq). diff --git a/manager/controllers/template_subscribed_systems_update.go b/manager/controllers/template_subscribed_systems_update.go index 90afb2313..7c785bdff 100644 --- a/manager/controllers/template_subscribed_systems_update.go +++ b/manager/controllers/template_subscribed_systems_update.go @@ -27,6 +27,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) @@ -42,12 +43,12 @@ func TemplateSubscribedSystemsUpdateHandler(c *gin.Context) { } systemList := []uuid.UUID{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_systems.go b/manager/controllers/template_systems.go index b1362aa0d..fbfa47e10 100644 --- a/manager/controllers/template_systems.go +++ b/manager/controllers/template_systems.go @@ -37,6 +37,7 @@ type TemplateSystemAttributes struct { ApplicableAdvisories SystemTags SystemGroups + SystemWorkspace SystemLastUpload } @@ -76,7 +77,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 +87,7 @@ func templateSystemsQuery(c *gin.Context, account int, groups map[string]string) return nil, nil, err } - query := database.Systems(db, account, groups). + query := database.Systems(db, account, workspaceIDs). Where("spatch.template_id = ?", template.ID). Select(templateSystemSelect) @@ -98,9 +99,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 +161,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 +210,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_delete.go b/manager/controllers/template_systems_delete.go index ac12ca80d..d28da56fd 100644 --- a/manager/controllers/template_systems_delete.go +++ b/manager/controllers/template_systems_delete.go @@ -25,7 +25,7 @@ import ( func TemplateSystemsDeleteHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) orgID := c.GetString(utils.KeyOrgID) - groups := c.GetStringMapString(utils.KeyInventoryGroups) + workspaceIDs := c.GetStringSlice(utils.KeyInventoryWorkspaces) var req TemplateSystemsUpdateRequest if err := c.ShouldBindJSON(&req); err != nil { @@ -39,12 +39,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_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 0ddc24dd1..78d4f69bf 100644 --- a/manager/controllers/template_systems_export_test.go +++ b/manager/controllers/template_systems_export_test.go @@ -15,7 +15,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) { @@ -69,13 +69,13 @@ 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':'aaaaaaaa-0000-0000-0000-000000000001','name':'group1'}]\",2018-09-22T16:00:00Z", - lines[1]) + "\"[{'id':'00000000-0000-0000-0000-000000000001','name':'group1'}]\","+ + "00000000-0000-0000-0000-000000000001,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':'aaaaaaaa-0000-0000-0000-000000000001','name':'group1'}]\",2020-09-22T16:00:00Z", - lines[2]) + "\"[{'id':'00000000-0000-0000-0000-000000000001','name':'group1'}]\","+ + "00000000-0000-0000-0000-000000000001,group1,2020-09-22T16:00:00Z", lines[2]) } func TestTemplateSystemsExportWrongFormat(t *testing.T) { diff --git a/manager/controllers/template_systems_update.go b/manager/controllers/template_systems_update.go index 4ea2c6bb0..4ccc34d97 100644 --- a/manager/controllers/template_systems_update.go +++ b/manager/controllers/template_systems_update.go @@ -17,10 +17,11 @@ import ( errors2 "errors" - "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/pkg/errors" "gorm.io/gorm" + + "github.com/gin-gonic/gin" ) var candlepinClient = candlepin.CreateCandlepinClient() @@ -56,7 +57,7 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { account := c.GetInt(utils.KeyAccount) orgID := c.GetString(utils.KeyOrgID) 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 { @@ -75,12 +76,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 } @@ -99,14 +100,14 @@ func TemplateSystemsUpdateHandler(c *gin.Context) { } func checkTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template *models.Template, - inventoryIDs []uuid.UUID, groups map[string]string) error { + inventoryIDs []uuid.UUID, 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): @@ -121,7 +122,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 @@ -166,7 +167,7 @@ func assignTemplateSystems(c *gin.Context, db *gorm.DB, accountID int, template } func templateArchVersionMatch( - db *gorm.DB, inventoryIDs []uuid.UUID, template *models.Template, acc int, groups map[string]string, + db *gorm.DB, inventoryIDs []uuid.UUID, template *models.Template, acc int, workspaceIDs []string, ) error { if template == nil { return nil @@ -177,7 +178,7 @@ func templateArchVersionMatch( Version string } var err error - err = database.Systems(db, acc, groups). + 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 { @@ -222,13 +223,13 @@ func callCandlepin(ctx context.Context, owner string, request *candlepin.Consume } func assignCandlepinEnvironment(c *gin.Context, db *gorm.DB, accountID int, env *string, inventoryIDs []uuid.UUID, - groups map[string]string) error { - var hosts []struct { + workspaceIDs []string) error { + var hosts = []struct { InventoryID uuid.UUID Consumer *string - } + }{} - err := database.Systems(db, accountID, groups). + 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 { @@ -272,14 +273,14 @@ func assignCandlepinEnvironment(c *gin.Context, db *gorm.DB, accountID int, env return nil } -func checkInventoryIDs(db *gorm.DB, accountID int, inventoryIDs []uuid.UUID, groups map[string]string) (err error) { +func checkInventoryIDs(db *gorm.DB, accountID int, inventoryIDs []uuid.UUID, workspaceIDs []string) (err error) { var containingSystems []SystemTemplateDBLookup var missingIDs []uuid.UUID var satelliteIDs []uuid.UUID var bootcIDs []uuid.UUID - err = database.Systems(db, accountID, groups). + err = database.Systems(db, accountID, workspaceIDs). Select("si.inventory_id, si.satellite_managed, si.bootc"). - Where("si.inventory_id IN (?)", inventoryIDs). + Where("si.inventory_id IN (?::uuid)", inventoryIDs). Scan(&containingSystems).Error if err != nil { return errors2.Join(base.ErrDatabase, err) diff --git a/manager/controllers/template_systems_update_test.go b/manager/controllers/template_systems_update_test.go index f32cfb918..5b09ff53c 100644 --- a/manager/controllers/template_systems_update_test.go +++ b/manager/controllers/template_systems_update_test.go @@ -179,7 +179,8 @@ func testUpdateTemplateBadRequest(t *testing.T, satelliteManaged, bootc bool) { RhAccountID: templateAccount, DisplayName: "template_bad_request_test", Tags: []byte("[]"), - Workspaces: database.TestWorkspacesGroup1(), + WorkspaceID: database.TestWorkspace1IDPtr(), + WorkspaceName: database.TestWorkspace1NamePtr(), BuiltPkgcache: true, SatelliteManaged: satelliteManaged, Bootc: bootc, diff --git a/manager/controllers/templates.go b/manager/controllers/templates.go index 75d58c20a..d58a92306 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.Systems(db, account, workspaceIDs). Select("spatch.template_id, count(*) as systems"). Group("spatch.template_id") diff --git a/manager/controllers/utils.go b/manager/controllers/utils.go index 12c330365..675a2d8a1 100644 --- a/manager/controllers/utils.go +++ b/manager/controllers/utils.go @@ -223,15 +223,18 @@ func UpdateMetaLinks(c *gin.Context, meta *ListMeta, total int, subTotals map[st func ApplySearch(c *gin.Context, tx *gorm.DB, searchColumns ...string) (*gorm.DB, string) { search := base.RemoveInvalidChars(c.Query("search")) - if search == "" || len(searchColumns) == 0 { + if search == "" { return tx, "" } - or := database.DB - for _, column := range searchColumns { - or = or.Or(column+"::text ILIKE ?", "%"+search+"%") + if len(searchColumns) == 0 { + return tx, "" } - return tx.Where(or), fmt.Sprintf("search=%s", search) + + searchExtended := "%" + search + "%" + concatValue := strings.Join(searchColumns, ",' ',") + txWithSearch := tx.Where("LOWER(CONCAT("+concatValue+")) LIKE LOWER(?)", searchExtended) + return txWithSearch, fmt.Sprintf("search=%s", search) } type Tag struct { @@ -389,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 diff --git a/manager/controllers/utils_test.go b/manager/controllers/utils_test.go index 180eb8778..4cdebf1de 100644 --- a/manager/controllers/utils_test.go +++ b/manager/controllers/utils_test.go @@ -1,7 +1,6 @@ package controllers import ( - "app/base/core" "app/base/database" "app/base/utils" "net/http" @@ -11,7 +10,6 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) func TestGroupNameFilter(t *testing.T) { @@ -25,14 +23,12 @@ func TestGroupNameFilter(t *testing.T) { assert.Nil(t, err) var systems []SystemsID - groups := map[string]string{ - utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]","[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000002\"}]"}`, //nolint:lll - } - tx := database.Systems(database.DB, 1, groups) + workspaceIDs := []string{"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002"} + tx := database.Systems(database.DB, 1, workspaceIDs) 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, 2, len(systems)) assert.Equal(t, uuid.MustParse("00000000-0000-0000-0000-000000000007"), systems[0].ID) assert.Equal(t, uuid.MustParse("00000000-0000-0000-0000-000000000008"), systems[1].ID) } @@ -48,53 +44,10 @@ func TestGroupNameFilter2(t *testing.T) { assert.Nil(t, err) var systems []SystemsID - groups := map[string]string{ - utils.KeyGrouped: `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]","[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000002\"}]"}`, //nolint:lll - } - tx := database.Systems(database.DB, 1, groups) + workspaceIDs := []string{"00000000-0000-0000-0000-000000000001", "00000000-0000-0000-0000-000000000002"} + tx := database.Systems(database.DB, 1, workspaceIDs) 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 -} - -func TestApplySearchEmpty(t *testing.T) { - var baseTx gorm.DB - - var cases = []struct { - url string - columns []string - comment string - }{ - {"/", []string{""}, "no search query returns original tx and empty meta"}, - {"/?search=", []string{"some_col"}, "empty search value returns original tx and empty meta"}, - {"/?search=foo", []string{}, "search present but no columns returns original tx and empty meta"}, - } - for _, c := range cases { - t.Run(c.comment, func(t *testing.T) { - ctx, _ := gin.CreateTestContext(httptest.NewRecorder()) - ctx.Request, _ = http.NewRequest("GET", c.url, nil) - outTx, q := ApplySearch(ctx, &baseTx, c.columns...) - assert.Same(t, &baseTx, outTx) - assert.Equal(t, "", q) - }) - } -} - -func TestApplySearchHello(t *testing.T) { - core.SetupTest(t) - - c, _ := gin.CreateTestContext(httptest.NewRecorder()) - c.Request, _ = http.NewRequest("GET", "/?search=hello", nil) - - tx, searchQ := ApplySearch(c, database.DB, "a", "b") - assert.Equal(t, "search=hello", searchQ) - - tx = tx.Where("1 = 0") - var n string - sql := tx.ToSQL(func(g *gorm.DB) *gorm.DB { - return g.Table("(select 'a' as a, 'b' as b) as t").Select("a").Scan(&n) - }) - - assert.Contains(t, sql, "WHERE (a::text ILIKE '%hello%' OR b::text ILIKE '%hello%')") + assert.Equal(t, 9, len(systems)) } diff --git a/manager/middlewares/kessel.go b/manager/middlewares/kessel.go index 7e682f089..91aea0b65 100644 --- a/manager/middlewares/kessel.go +++ b/manager/middlewares/kessel.go @@ -3,13 +3,11 @@ package middlewares import ( "app/base/utils" "context" - "fmt" "net/http" "strings" "time" "github.com/gin-gonic/gin" - "github.com/google/uuid" "github.com/pkg/errors" "github.com/redhatinsights/platform-go-middlewares/v2/identity" "google.golang.org/grpc" @@ -36,30 +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 { - id, err := uuid.Parse(workspace.Object.ResourceId) - if err != nil { - continue - } - group, err := utils.ParseInventoryGroup(&id, nil) - if err != nil { - 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(), ".") @@ -146,13 +120,17 @@ func hasPermissionKessel(c *gin.Context) { return } - inventoryGroups, err := processWorkspaces(workspaces) - if err != nil { - utils.LogWarn(err.Error()) + 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.KeyInventoryGroups, inventoryGroups) + c.Set(utils.KeyInventoryWorkspaces, workspaceIDs) } func Kessel() gin.HandlerFunc { diff --git a/manager/middlewares/kessel_test.go b/manager/middlewares/kessel_test.go index cb97ff5c5..2648cfedb 100644 --- a/manager/middlewares/kessel_test.go +++ b/manager/middlewares/kessel_test.go @@ -2,9 +2,9 @@ package middlewares import ( "app/base/utils" - "fmt" + "net" "net/http" - "strconv" + "net/http/httptest" "testing" "google.golang.org/grpc" @@ -17,6 +17,62 @@ import ( "github.com/stretchr/testify/require" ) +const testXRHIdentity = "ewogICAgImVudGl0bGVtZW50cyI6IHsKICAgICAgICAiaW5zaWdodHMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJjb3N0X21hbmFnZW1lbnQiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJhbnNpYmxlIjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAib3BlbnNoaWZ0IjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAic21hcnRfbWFuYWdlbWVudCI6IHsKICAgICAgICAgICAgImlzX2VudGl0bGVkIjogdHJ1ZQogICAgICAgIH0sCiAgICAgICAgIm1pZ3JhdGlvbnMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9CiAgICB9LAogICAgImlkZW50aXR5IjogewogICAgICAgICJpbnRlcm5hbCI6IHsKICAgICAgICAgICAgImF1dGhfdGltZSI6IDI5OSwKICAgICAgICAgICAgImF1dGhfdHlwZSI6ICJiYXNpYy1hdXRoIiwKICAgICAgICAgICAgIm9yZ19pZCI6ICIxMTc4OTc3MiIKICAgICAgICB9LAogICAgICAgICJhY2NvdW50X251bWJlciI6ICI2MDg5NzE5IiwKICAgICAgICAidXNlciI6IHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiAiSW5zaWdodHMiLAogICAgICAgICAgICAiaXNfYWN0aXZlIjogdHJ1ZSwKICAgICAgICAgICAgImlzX2ludGVybmFsIjogZmFsc2UsCiAgICAgICAgICAgICJsYXN0X25hbWUiOiAiUUEiLAogICAgICAgICAgICAibG9jYWxlIjogImVuX1VTIiwKICAgICAgICAgICAgImlzX29yZ19hZG1pbiI6IHRydWUsCiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJpbnNpZ2h0cy1xYSIsCiAgICAgICAgICAgICJlbWFpbCI6ICJqbmVlZGxlK3FhQHJlZGhhdC5jb20iLAogICAgICAgICAgICAidXNlcl9pZCI6ICI2MDg5NzE5IgogICAgICAgIH0sCiAgICAgICAgInR5cGUiOiAiVXNlciIKICAgIH0KfQ==" //nolint:lll + +type testKesselServer struct { + kesselv2.UnimplementedKesselInventoryServiceServer + workspaceIDs []string +} + +func (s *testKesselServer) StreamedListObjects(_ *kesselv2.StreamedListObjectsRequest, + stream kesselv2.KesselInventoryService_StreamedListObjectsServer, +) error { + for _, id := range s.workspaceIDs { + if err := stream.Send(&kesselv2.StreamedListObjectsResponse{ + Object: &kesselv2.ResourceReference{ + ResourceType: "workspace", + ResourceId: id, + }, + }); err != nil { + return err + } + } + return nil +} + +func withTestKesselServer(t *testing.T, workspaceIDs []string) func() { + t.Helper() + + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + grpcServer := grpc.NewServer() + kesselv2.RegisterKesselInventoryServiceServer(grpcServer, &testKesselServer{workspaceIDs: workspaceIDs}) + go func() { + _ = grpcServer.Serve(listener) + }() + + originalURL := utils.CoreCfg.KesselURL + originalInsecure := utils.CoreCfg.KesselInsecure + utils.CoreCfg.KesselURL = listener.Addr().String() + utils.CoreCfg.KesselInsecure = true + + return func() { + grpcServer.Stop() + _ = listener.Close() + utils.CoreCfg.KesselURL = originalURL + utils.CoreCfg.KesselInsecure = originalInsecure + } +} + +func newKesselTestContext() (*gin.Context, *httptest.ResponseRecorder) { + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Request = httptest.NewRequest(http.MethodGet, "/", nil) + c.Request.Header.Set("x-rh-identity", testXRHIdentity) + return c, w +} + func TestSetupClient(t *testing.T) { originalKesselInsecure := utils.CoreCfg.KesselInsecure originalKesselAuthEnabled := utils.CoreCfg.KesselAuthEnabled @@ -66,22 +122,6 @@ func TestSetupClient(t *testing.T) { utils.CoreCfg.KesselAuthClientSecret = originalKesselAuthClientSecret } -func TestProcessWorkspaces(t *testing.T) { - id1 := "aaaaaaaa-0000-0000-0000-000000000001" - id2 := "bbbbbbbb-0000-0000-0000-000000000002" - expected := fmt.Sprintf("{%s,%s}", - strconv.Quote(fmt.Sprintf(`[{"id":"%s"}]`, id1)), - strconv.Quote(fmt.Sprintf(`[{"id":"%s"}]`, id2))) - workspaces := []*kesselv2.StreamedListObjectsResponse{ - {Object: &kesselv2.ResourceReference{ResourceId: id1}}, - {Object: &kesselv2.ResourceReference{ResourceId: id2}}, - } - 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,15 +149,48 @@ func TestUseStreamedListObjects(t *testing.T) { } func TestHasPermissionKessel(t *testing.T) { - c := &gin.Context{Request: &http.Request{Header: map[string][]string{}, Method: http.MethodGet}} - c.Request.Header.Set("x-rh-identity", "ewogICAgImVudGl0bGVtZW50cyI6IHsKICAgICAgICAiaW5zaWdodHMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJjb3N0X21hbmFnZW1lbnQiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9LAogICAgICAgICJhbnNpYmxlIjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAib3BlbnNoaWZ0IjogewogICAgICAgICAgICAiaXNfZW50aXRsZWQiOiB0cnVlCiAgICAgICAgfSwKICAgICAgICAic21hcnRfbWFuYWdlbWVudCI6IHsKICAgICAgICAgICAgImlzX2VudGl0bGVkIjogdHJ1ZQogICAgICAgIH0sCiAgICAgICAgIm1pZ3JhdGlvbnMiOiB7CiAgICAgICAgICAgICJpc19lbnRpdGxlZCI6IHRydWUKICAgICAgICB9CiAgICB9LAogICAgImlkZW50aXR5IjogewogICAgICAgICJpbnRlcm5hbCI6IHsKICAgICAgICAgICAgImF1dGhfdGltZSI6IDI5OSwKICAgICAgICAgICAgImF1dGhfdHlwZSI6ICJiYXNpYy1hdXRoIiwKICAgICAgICAgICAgIm9yZ19pZCI6ICIxMTc4OTc3MiIKICAgICAgICB9LAogICAgICAgICJhY2NvdW50X251bWJlciI6ICI2MDg5NzE5IiwKICAgICAgICAidXNlciI6IHsKICAgICAgICAgICAgImZpcnN0X25hbWUiOiAiSW5zaWdodHMiLAogICAgICAgICAgICAiaXNfYWN0aXZlIjogdHJ1ZSwKICAgICAgICAgICAgImlzX2ludGVybmFsIjogZmFsc2UsCiAgICAgICAgICAgICJsYXN0X25hbWUiOiAiUUEiLAogICAgICAgICAgICAibG9jYWxlIjogImVuX1VTIiwKICAgICAgICAgICAgImlzX29yZ19hZG1pbiI6IHRydWUsCiAgICAgICAgICAgICJ1c2VybmFtZSI6ICJpbnNpZ2h0cy1xYSIsCiAgICAgICAgICAgICJlbWFpbCI6ICJqbmVlZGxlK3FhQHJlZGhhdC5jb20iLAogICAgICAgICAgICAidXNlcl9pZCI6ICI2MDg5NzE5IgogICAgICAgIH0sCiAgICAgICAgInR5cGUiOiAiVXNlciIKICAgIH0KfQ==") //nolint:lll + c, _ := newKesselTestContext() + hasPermissionKessel(c) + 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, "aaaaaaaa-0000-0000-0000-000000000001", workspaceIDs[0]) +} +func TestHasPermissionKesselMultipleWorkspacesSetsContext(t *testing.T) { + defer withTestKesselServer(t, []string{ + "aaaaaaaa-0000-0000-0000-000000000001", + "bbbbbbbb-0000-0000-0000-000000000002", + })() + + c, w := newKesselTestContext() hasPermissionKessel(c) - inventoryGroups, found := c.Get(utils.KeyInventoryGroups) + + assert.False(t, c.IsAborted()) + assert.Equal(t, http.StatusOK, w.Code) + + workspaces, found := c.Get(utils.KeyInventoryWorkspaces) require.True(t, found) - inventoryGroupMap, ok := (inventoryGroups).(map[string]string) + workspaceIDs, ok := workspaces.([]string) require.True(t, ok) - assert.Equal(t, `{"[{\"id\":\"aaaaaaaa-0000-0000-0000-000000000001\"}]"}`, inventoryGroupMap[utils.KeyGrouped]) + assert.Equal(t, []string{ + "aaaaaaaa-0000-0000-0000-000000000001", + "bbbbbbbb-0000-0000-0000-000000000002", + }, workspaceIDs) +} + +func TestHasPermissionKesselNoWorkspacesReturnsUnauthorized(t *testing.T) { + defer withTestKesselServer(t, nil)() + + c, w := newKesselTestContext() + hasPermissionKessel(c) + + assert.True(t, c.IsAborted()) + assert.Equal(t, http.StatusUnauthorized, w.Code) + _, found := c.Get(utils.KeyInventoryWorkspaces) + assert.False(t, found) } func mockXRHID(userType string) *identity.XRHID { diff --git a/manager/middlewares/rbac.go b/manager/middlewares/rbac.go index 34f7c111b..6966fa974 100644 --- a/manager/middlewares/rbac.go +++ b/manager/middlewares/rbac.go @@ -17,6 +17,8 @@ import ( "golang.org/x/exp/slices" ) +const rootWorkspaceID = "00000000-0000-0000-0000-999999999999" + var ( rbacURL = "" httpClient = &http.Client{} @@ -124,36 +126,30 @@ func isAccessGranted(c *gin.Context) bool { granted := checkPermissions(&access, handlerName, c.Request.Method) if granted { - // collect inventory groups - groups, err := findInventoryGroups(&access) + workspaces, err := findInventoryWorkspaces(&access) if err != nil { utils.LogError("err", err.Error(), "RBAC") granted = false } - c.Set(utils.KeyInventoryGroups, groups) + c.Set(utils.KeyInventoryWorkspaces, workspaces) } return granted } -// nolint: gocognit -func findInventoryGroups(access *rbac.AccessPagination) (map[string]string, error) { - res := make(map[string]string) - +func findInventoryWorkspaces(access *rbac.AccessPagination) ([]string, error) { if len(access.Data) == 0 { utils.LogDebug("rbac zero access data") - return res, nil + return nil, nil } inventoryHostsReadPerms := expandedPermission(inventoryHostsReadPerm) - groups := []string{} + workspaceIDs := make([]string, 0) 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") + utils.LogDebug("rbac access to all workspaces") return nil, nil } for _, rd := range a.ResourceDefinitions { @@ -170,27 +166,20 @@ func findInventoryGroups(access *rbac.AccessPagination) (map[string]string, erro } for _, v := range rd.AttributeFilter.Value { if v == nil { - res[utils.KeyUngrouped] = "[]" + workspaceIDs = append(workspaceIDs, rootWorkspaceID) continue } id, err := uuid.Parse(*v) if err != nil { continue } - group, err := utils.ParseInventoryGroup(&id, nil) - if err != nil { - continue - } - groups = append(groups, group) + workspaceIDs = append(workspaceIDs, id.String()) } } } - if len(groups) > 0 { - res[utils.KeyGrouped] = fmt.Sprintf("{%s}", strings.Join(groups, ",")) - } - utils.LogDebug("group_count", len(groups), "processed groups") - return res, nil + utils.LogDebug("workspace_count", len(workspaceIDs), "processed workspaces") + return workspaceIDs, nil } func RBAC() gin.HandlerFunc { diff --git a/manager/middlewares/rbac_test.go b/manager/middlewares/rbac_test.go index aa41641dd..39e4dd8ac 100644 --- a/manager/middlewares/rbac_test.go +++ b/manager/middlewares/rbac_test.go @@ -2,7 +2,6 @@ package middlewares import ( "app/base/rbac" - "app/base/utils" "encoding/json" "net/http" "net/http/httptest" @@ -242,7 +241,7 @@ func TestPermissionsRead(t *testing.T) { assert.False(t, checkPermissions(&access, handler, "GET")) } -func TestFindInventoryGroupsGrouped(t *testing.T) { +func TestFindInventoryWorkspacesGrouped(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{{ Permission: "inventory:hosts:read", @@ -255,19 +254,13 @@ func TestFindInventoryGroupsGrouped(t *testing.T) { }}, }}, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(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) + assert.Equal(t, []string{group1}, workspaces) } } -func TestFindInventoryGroupsUnrouped(t *testing.T) { +func TestFindInventoryWorkspacesUngrouped(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{{ Permission: "inventory:hosts:read", @@ -280,16 +273,13 @@ func TestFindInventoryGroupsUnrouped(t *testing.T) { }}, }}, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(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]) + assert.Equal(t, []string{rootWorkspaceID}, workspaces) } } -func TestFindInventoryGroups(t *testing.T) { +func TestFindInventoryWorkspaces(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{{ Permission: "inventory:hosts:read", @@ -302,17 +292,13 @@ func TestFindInventoryGroups(t *testing.T) { }}, }}, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(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]) + assert.Equal(t, []string{group1, group2, rootWorkspaceID}, workspaces) } } -func TestFindInventoryGroupsOverwrite(t *testing.T) { +func TestFindInventoryWorkspacesAllAccess(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{ { @@ -331,14 +317,13 @@ func TestFindInventoryGroupsOverwrite(t *testing.T) { }, }, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(access) if assert.NoError(t, err) { - // we expect access to all groups (empty map) - assert.Equal(t, 0, len(groups)) + assert.Nil(t, workspaces) } } -func TestFindInventoryGroupsOverwrite2(t *testing.T) { +func TestFindInventoryWorkspacesAllAccessFirst(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{ { @@ -357,14 +342,13 @@ func TestFindInventoryGroupsOverwrite2(t *testing.T) { }, }, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(access) if assert.NoError(t, err) { - // we expect access to all groups (empty map) - assert.Equal(t, 0, len(groups)) + assert.Nil(t, workspaces) } } -func TestFindInventoryGroupsInvalidOp(t *testing.T) { +func TestFindInventoryWorkspacesInvalidOp(t *testing.T) { access := &rbac.AccessPagination{ Data: []rbac.Access{ { @@ -379,9 +363,29 @@ func TestFindInventoryGroupsInvalidOp(t *testing.T) { }, }, } - groups, err := findInventoryGroups(access) + workspaces, err := findInventoryWorkspaces(access) assert.Error(t, err) - assert.Nil(t, groups) + assert.Nil(t, workspaces) +} + +func TestFindInventoryWorkspacesSkipsInvalidUUID(t *testing.T) { + invalid := "not-a-uuid" + access := &rbac.AccessPagination{ + Data: []rbac.Access{{ + Permission: "inventory:hosts:read", + ResourceDefinitions: []rbac.ResourceDefinition{{ + AttributeFilter: rbac.AttributeFilter{ + Key: "group.id", + Value: []*string{&invalid, &group1}, + Operation: "in", + }, + }}, + }}, + } + workspaces, err := findInventoryWorkspaces(access) + if assert.NoError(t, err) { + assert.Equal(t, []string{group1}, workspaces) + } } func TestMultiplePermissions(t *testing.T) { @@ -477,11 +481,13 @@ func TestPermissionsAllowedOperations(t *testing.T) { err := json.Unmarshal([]byte(allowedOperations), &access) assert.NoError(t, err) assert.True(t, checkPermissions(&access, handler, "GET")) - groups, err := findInventoryGroups(&access) + workspaces, err := findInventoryWorkspaces(&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"]) + assert.Equal(t, []string{ + "00000000-f688-49d4-a8e2-87394f1ac1b1", + "00000000-f7a6-45a1-b5a8-410f20052fb1", + "00000000-78e0-4cad-bf01-63cf1e4b1dca", + "00000000-f688-49d4-a8e2-ee394f1ac1b1", + rootWorkspaceID, + }, workspaces) } diff --git a/platform/rbac.go b/platform/rbac.go index d97170fee..2db09a5b4 100644 --- a/platform/rbac.go +++ b/platform/rbac.go @@ -10,7 +10,7 @@ import ( var rbacPermissions = utils.PodConfig.GetString("rbac_permissions", "patch:*:read") -var inventoryGroup = "inventory-group-1" +var inventoryGroup = "00000000-0000-0000-0000-000000000001" func rbacHandler(c *gin.Context) { c.JSON(http.StatusOK, rbac.AccessPagination{ diff --git a/tasks/system_culling/system_culling_test.go b/tasks/system_culling/system_culling_test.go index f16e50cee..a8f318af5 100644 --- a/tasks/system_culling/system_culling_test.go +++ b/tasks/system_culling/system_culling_test.go @@ -177,7 +177,8 @@ func TestCullSystems(t *testing.T) { RhAccountID: 1, DisplayName: invID, Tags: []byte("[]"), - Workspaces: database.TestWorkspacesGroup1(), + WorkspaceID: database.TestWorkspace1IDPtr(), + WorkspaceName: database.TestWorkspace1NamePtr(), CulledTimestamp: &staleDate, } assert.NoError(t, database.DB.Create(&inv).Error) diff --git a/turnpike/controllers/admin_test.go b/turnpike/controllers/admin_test.go index c281865d4..5a48ce7cd 100644 --- a/turnpike/controllers/admin_test.go +++ b/turnpike/controllers/admin_test.go @@ -20,11 +20,12 @@ func TestInitDelete(t *testing.T) { core.SetupTest(t) inv := models.SystemInventory{ - InventoryID: uuid.MustParse(del), - RhAccountID: 1, - DisplayName: del, - Tags: []byte("[]"), - Workspaces: database.TestWorkspacesGroup1(), + InventoryID: uuid.MustParse(del), + RhAccountID: 1, + DisplayName: del, + Tags: []byte("[]"), + WorkspaceID: database.TestWorkspace1IDPtr(), + WorkspaceName: database.TestWorkspace1NamePtr(), } assert.NoError(t, database.DB.Create(&inv).Error) assert.NoError(t, database.DB.Create(&models.SystemPatch{