From 8a912baac1e7cd1435f95ba648a5488d357d1a29 Mon Sep 17 00:00:00 2001 From: platex-rehor-bot Date: Tue, 29 Sep 2026 20:05:31 +0000 Subject: [PATCH 1/2] RHCLOUD-51702: prefer V2 dependency endpoint for RBAC service discovery The Clowder V2 endpoint API provides a complete URI including scheme and port, avoiding the manual URL construction from V1 flat endpoint lists. This change tries V2 first via GetV2DependencyEndpoint("rbac", "service") and falls back to V1 iteration when V2 is not available. The RBAC_ADDRESS env var override is preserved as the final layer. Co-Authored-By: Claude Opus 4.6 --- base/utils/config.go | 19 +++++- base/utils/config_clowder_v2_test.go | 96 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 base/utils/config_clowder_v2_test.go diff --git a/base/utils/config.go b/base/utils/config.go index 9077291ad..df28d2d53 100644 --- a/base/utils/config.go +++ b/base/utils/config.go @@ -274,7 +274,21 @@ func initKafkaFromClowder() { type Endpoint clowder.DependencyEndpoint type PrivateEndpoint clowder.PrivateDependencyEndpoint +// resolveRbacV2Address returns the RBAC address from V2 dependency endpoints, +// or empty string if V2 is not available. +func resolveRbacV2Address() string { + if endpoint, ok := clowder.GetV2DependencyEndpoint("rbac", "service"); ok && endpoint.Uri != "" { + return endpoint.Uri + } + return "" +} + func initServicesFromClowder() { + // Try V2 dependency endpoint for RBAC (preferred over V1 flat list). + if addr := resolveRbacV2Address(); addr != "" { + CoreCfg.RbacAddress = addr + } + webappName := "webapp-service" if PodConfig.GetBool("use_vmaas_go", true) { webappName = "webapp-go" @@ -286,7 +300,10 @@ func initServicesFromClowder() { CoreCfg.VmaasAddress = (*Endpoint)(&endpoint).buildURL() } case "rbac": - CoreCfg.RbacAddress = (*Endpoint)(&endpoint).buildURL() + // V1 fallback: set only if V2 did not resolve above. + if CoreCfg.RbacAddress == "" { + CoreCfg.RbacAddress = (*Endpoint)(&endpoint).buildURL() + } case "rbac-service": CoreCfg.RbacURL = (*Endpoint)(&endpoint).buildURL() case "content-sources-backend": diff --git a/base/utils/config_clowder_v2_test.go b/base/utils/config_clowder_v2_test.go new file mode 100644 index 000000000..ab5376484 --- /dev/null +++ b/base/utils/config_clowder_v2_test.go @@ -0,0 +1,96 @@ +package utils + +import ( + "os" + "testing" + + clowder "github.com/redhatinsights/app-common-go/pkg/api/v1" + "github.com/stretchr/testify/assert" +) + +func TestResolveRbacV2Address(t *testing.T) { + origV2 := clowder.DependencyEndpointsV2 + defer func() { clowder.DependencyEndpointsV2 = origV2 }() + + t.Run("V2 available with URI", func(t *testing.T) { + clowder.DependencyEndpointsV2 = map[string]map[string]clowder.DependencyEndpointV2{ + "rbac": { + "service": {Uri: "https://rbac-service.svc:8443", Authenticated: false}, + }, + } + assert.Equal(t, "https://rbac-service.svc:8443", resolveRbacV2Address()) + }) + + t.Run("V2 nil map", func(t *testing.T) { + clowder.DependencyEndpointsV2 = nil + assert.Equal(t, "", resolveRbacV2Address()) + }) + + t.Run("V2 empty URI", func(t *testing.T) { + clowder.DependencyEndpointsV2 = map[string]map[string]clowder.DependencyEndpointV2{ + "rbac": { + "service": {Uri: "", Authenticated: false}, + }, + } + assert.Equal(t, "", resolveRbacV2Address()) + }) + + t.Run("V2 wrong app key", func(t *testing.T) { + clowder.DependencyEndpointsV2 = map[string]map[string]clowder.DependencyEndpointV2{ + "other-app": { + "service": {Uri: "https://other.svc:8443", Authenticated: false}, + }, + } + assert.Equal(t, "", resolveRbacV2Address()) + }) + + t.Run("V2 wrong deployment key", func(t *testing.T) { + clowder.DependencyEndpointsV2 = map[string]map[string]clowder.DependencyEndpointV2{ + "rbac": { + "wrong-deploy": {Uri: "https://rbac.svc:8443", Authenticated: false}, + }, + } + assert.Equal(t, "", resolveRbacV2Address()) + }) + + t.Run("V2 with CA certificate", func(t *testing.T) { + caPath := "/tmp/ca.crt" + clowder.DependencyEndpointsV2 = map[string]map[string]clowder.DependencyEndpointV2{ + "rbac": { + "service": { + Uri: "https://rbac-service.svc:8443", + Authenticated: false, + CaCertificate: &caPath, + }, + }, + } + assert.Equal(t, "https://rbac-service.svc:8443", resolveRbacV2Address()) + }) +} + +func TestRbacAddressEnvOverride(t *testing.T) { + origAddr := CoreCfg.RbacAddress + defer func() { CoreCfg.RbacAddress = origAddr }() + + // Simulate V2-resolved address + CoreCfg.RbacAddress = "https://rbac-service.svc:8443" + + // Env var override takes precedence (initServicesFromEnv behavior) + os.Setenv("RBAC_ADDRESS", "http://localhost:8080") + defer os.Unsetenv("RBAC_ADDRESS") + initServicesFromEnv() + assert.Equal(t, "http://localhost:8080", CoreCfg.RbacAddress) +} + +func TestRbacAddressEnvPreservesV2WhenUnset(t *testing.T) { + origAddr := CoreCfg.RbacAddress + defer func() { CoreCfg.RbacAddress = origAddr }() + + // Simulate V2-resolved address + CoreCfg.RbacAddress = "https://rbac-service.svc:8443" + + // No env override: Getenv returns current value as default + os.Unsetenv("RBAC_ADDRESS") + initServicesFromEnv() + assert.Equal(t, "https://rbac-service.svc:8443", CoreCfg.RbacAddress) +} From aa3b5b5a61fee9fb8dcce49e2182676bb6ef55a0 Mon Sep 17 00:00:00 2001 From: platex-rehor-bot Date: Wed, 30 Sep 2026 14:00:25 +0000 Subject: [PATCH 2/2] fix(rbac): move V2 resolution into rbac section, fix test side effects RHCLOUD-51702 Address review feedback: V2 endpoint resolution now scoped to the rbac case block so it only runs when rbac endpoints exist. Tests use t.Setenv for automatic cleanup, preventing env var side effects across test runs. Co-Authored-By: Claude Opus 4.6 --- base/utils/config.go | 11 ++++------- base/utils/config_clowder_v2_test.go | 8 +++++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/base/utils/config.go b/base/utils/config.go index df28d2d53..d3dad80aa 100644 --- a/base/utils/config.go +++ b/base/utils/config.go @@ -284,11 +284,6 @@ func resolveRbacV2Address() string { } func initServicesFromClowder() { - // Try V2 dependency endpoint for RBAC (preferred over V1 flat list). - if addr := resolveRbacV2Address(); addr != "" { - CoreCfg.RbacAddress = addr - } - webappName := "webapp-service" if PodConfig.GetBool("use_vmaas_go", true) { webappName = "webapp-go" @@ -300,8 +295,10 @@ func initServicesFromClowder() { CoreCfg.VmaasAddress = (*Endpoint)(&endpoint).buildURL() } case "rbac": - // V1 fallback: set only if V2 did not resolve above. - if CoreCfg.RbacAddress == "" { + // Prefer V2 dependency endpoint; fall back to V1 flat list. + if addr := resolveRbacV2Address(); addr != "" { + CoreCfg.RbacAddress = addr + } else { CoreCfg.RbacAddress = (*Endpoint)(&endpoint).buildURL() } case "rbac-service": diff --git a/base/utils/config_clowder_v2_test.go b/base/utils/config_clowder_v2_test.go index ab5376484..0e1a25e71 100644 --- a/base/utils/config_clowder_v2_test.go +++ b/base/utils/config_clowder_v2_test.go @@ -76,8 +76,7 @@ func TestRbacAddressEnvOverride(t *testing.T) { CoreCfg.RbacAddress = "https://rbac-service.svc:8443" // Env var override takes precedence (initServicesFromEnv behavior) - os.Setenv("RBAC_ADDRESS", "http://localhost:8080") - defer os.Unsetenv("RBAC_ADDRESS") + t.Setenv("RBAC_ADDRESS", "http://localhost:8080") initServicesFromEnv() assert.Equal(t, "http://localhost:8080", CoreCfg.RbacAddress) } @@ -89,7 +88,10 @@ func TestRbacAddressEnvPreservesV2WhenUnset(t *testing.T) { // Simulate V2-resolved address CoreCfg.RbacAddress = "https://rbac-service.svc:8443" - // No env override: Getenv returns current value as default + // No env override: Getenv returns current value as default. + // t.Setenv registers cleanup to restore original value after test; + // os.Unsetenv then clears it so LookupEnv returns ok=false. + t.Setenv("RBAC_ADDRESS", "") os.Unsetenv("RBAC_ADDRESS") initServicesFromEnv() assert.Equal(t, "https://rbac-service.svc:8443", CoreCfg.RbacAddress)