From a14ea427dc469b5ae63f08d93b138f1863960ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Ma=C5=82ek?= Date: Tue, 12 Nov 2024 15:02:41 +0100 Subject: [PATCH] konnect: use sdk-konnect-go for roles (#6648) --- hack/cleanup/konnect_control_planes.go | 90 +++++++--- internal/konnect/roles/client.go | 167 ------------------ internal/konnect/roles/client_test.go | 107 ----------- test/consts.go | 5 + test/internal/helpers/konnect/access.go | 19 +- .../internal/helpers/konnect/control_plane.go | 42 +++-- test/konnect.go | 14 ++ 7 files changed, 120 insertions(+), 324 deletions(-) delete mode 100644 internal/konnect/roles/client.go delete mode 100644 internal/konnect/roles/client_test.go create mode 100644 test/konnect.go diff --git a/hack/cleanup/konnect_control_planes.go b/hack/cleanup/konnect_control_planes.go index fa05b12cbe..ce2f38d232 100644 --- a/hack/cleanup/konnect_control_planes.go +++ b/hack/cleanup/konnect_control_planes.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "net/http" "time" "github.com/go-logr/logr" @@ -14,30 +13,44 @@ import ( sdkkonnectgo "github.com/Kong/sdk-konnect-go" sdkkonnectops "github.com/Kong/sdk-konnect-go/models/operations" - "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/roles" "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/sdk" + "github.com/kong/kubernetes-ingress-controller/v3/test" ) const ( - konnectControlPlanesBaseURL = "https://us.kic.api.konghq.tech" konnectControlPlanesLimit = int64(100) - konnectRolesBaseURL = "https://global.api.konghq.tech/v2" createdInTestsControlPlaneLabel = "created_in_tests" timeUntilControlPlaneOrphaned = time.Hour ) // cleanupKonnectControlPlanes deletes orphaned control planes created by the tests and their roles. func cleanupKonnectControlPlanes(ctx context.Context, log logr.Logger) error { - sdk := sdk.New(konnectAccessToken, sdkkonnectgo.WithServerURL(konnectControlPlanesBaseURL)) + sdk := sdk.New(konnectAccessToken, + sdkkonnectgo.WithServerURL(test.KonnectServerURL()), + ) + + me, err := sdk.Me.GetUsersMe(ctx, + // NOTE: Otherwise we use prod server by default. + // Related issue: https://github.com/Kong/sdk-konnect-go/issues/20 + sdkkonnectops.WithServerURL(test.KonnectServerURL()), + ) + if err != nil { + return fmt.Errorf("failed to get user info: %w", err) + } + if me.User == nil || me.User.ID == nil { + return errors.New("failed to get user info, user is nil") + } orphanedCPs, err := findOrphanedControlPlanes(ctx, log, sdk.ControlPlanes) if err != nil { return fmt.Errorf("failed to find orphaned control planes: %w", err) } - if err := deleteControlPlanes(ctx, log, orphanedCPs, sdk.ControlPlanes); err != nil { + if err := deleteControlPlanes(ctx, log, sdk.ControlPlanes, orphanedCPs); err != nil { return fmt.Errorf("failed to delete control planes: %w", err) } + userID := *me.User.ID + // We have to manually delete roles created for the control plane because Konnect doesn't do it automatically. // If we don't do it, we will eventually hit a problem with Konnect APIs answering our requests with 504s // because of a performance issue when there's too many roles for the account @@ -45,12 +58,11 @@ func cleanupKonnectControlPlanes(ctx context.Context, log logr.Logger) error { // // We can drop this once the automated cleanup is implemented on Konnect side: // https://konghq.atlassian.net/browse/TPS-1453. - rolesClient := roles.NewClient(&http.Client{}, konnectRolesBaseURL, konnectAccessToken) - rolesToDelete, err := findOrphanedRolesToDelete(ctx, log, orphanedCPs, rolesClient) + rolesToDelete, err := findOrphanedRolesToDelete(ctx, log, sdk.Roles, orphanedCPs, userID) if err != nil { return fmt.Errorf("failed to list control plane roles to delete: %w", err) } - if err := deleteRoles(ctx, log, rolesToDelete, rolesClient); err != nil { + if err := deleteRoles(ctx, log, sdk.Roles, *me.User.ID, rolesToDelete); err != nil { return fmt.Errorf("failed to delete control plane roles: %w", err) } @@ -58,7 +70,11 @@ func cleanupKonnectControlPlanes(ctx context.Context, log logr.Logger) error { } // findOrphanedControlPlanes finds control planes that were created by the tests and are older than timeUntilControlPlaneOrphaned. -func findOrphanedControlPlanes(ctx context.Context, log logr.Logger, c *sdkkonnectgo.ControlPlanes) ([]string, error) { +func findOrphanedControlPlanes( + ctx context.Context, + log logr.Logger, + c *sdkkonnectgo.ControlPlanes, +) ([]string, error) { response, err := c.ListControlPlanes(ctx, sdkkonnectops.ListControlPlanesRequest{ PageSize: lo.ToPtr(konnectControlPlanesLimit), }) @@ -96,7 +112,12 @@ func findOrphanedControlPlanes(ctx context.Context, log logr.Logger, c *sdkkonne } // deleteControlPlanes deletes control planes by their IDs. -func deleteControlPlanes(ctx context.Context, log logr.Logger, cpsIDs []string, c *sdkkonnectgo.ControlPlanes) error { +func deleteControlPlanes( + ctx context.Context, + log logr.Logger, + sdk *sdkkonnectgo.ControlPlanes, + cpsIDs []string, +) error { if len(cpsIDs) < 1 { log.Info("No control planes to clean up") return nil @@ -105,7 +126,7 @@ func deleteControlPlanes(ctx context.Context, log logr.Logger, cpsIDs []string, var errs []error for _, cpID := range cpsIDs { log.Info("Deleting control plane", "name", cpID) - if _, err := c.DeleteControlPlane(ctx, cpID); err != nil { + if _, err := sdk.DeleteControlPlane(ctx, cpID); err != nil { errs = append(errs, fmt.Errorf("failed to delete control plane %s: %w", cpID, err)) } } @@ -113,33 +134,60 @@ func deleteControlPlanes(ctx context.Context, log logr.Logger, cpsIDs []string, } // findOrphanedRolesToDelete gets a list of roles that belong to the orphaned control planes. -func findOrphanedRolesToDelete(ctx context.Context, log logr.Logger, orphanedCPsIDs []string, rolesClient *roles.Client) ([]string, error) { +func findOrphanedRolesToDelete( + ctx context.Context, + log logr.Logger, + sdk *sdkkonnectgo.Roles, + orphanedCPsIDs []string, + userID string, +) ([]string, error) { if len(orphanedCPsIDs) < 1 { log.Info("No control planes to clean up, skipping listing roles") return nil, nil } - existingRoles, err := rolesClient.ListControlPlanesRoles(ctx) + resp, err := sdk.ListUserRoles(ctx, userID, + // NOTE: Sadly we can't do filtering here (yet?) because ListUserRolesQueryParamFilter + // can only match by exact name and we match against a list of orphaned control plane IDs. + &sdkkonnectops.ListUserRolesQueryParamFilter{}, + // NOTE: Otherwise we use prod server by default. + // Related issue: https://github.com/Kong/sdk-konnect-go/issues/20 + sdkkonnectops.WithServerURL(test.KonnectServerURL()), + ) if err != nil { - return nil, fmt.Errorf("failed to list control plane roles: %w", err) + return nil, fmt.Errorf("failed to list user roles: %w", err) + } + + if resp == nil || resp.AssignedRoleCollection == nil { + return nil, errors.New("failed to list user roles, response is nil") } var rolesIDsToDelete []string - for _, role := range existingRoles { + for _, role := range resp.AssignedRoleCollection.GetData() { + log.Info("User role", "id", role.ID, "entity_id", role.EntityID) belongsToOrphanedControlPlane := lo.ContainsBy(orphanedCPsIDs, func(cpID string) bool { - return cpID == role.EntityID + if role.EntityID == nil { + return false + } + return cpID == *role.EntityID }) if !belongsToOrphanedControlPlane { - log.Info("Role is not assigned to an orphaned control plane, skipping", "id", role.ID) continue } - rolesIDsToDelete = append(rolesIDsToDelete, role.ID) + rolesIDsToDelete = append(rolesIDsToDelete, *role.ID) } + return rolesIDsToDelete, nil } // deleteRoles deletes roles by their IDs. -func deleteRoles(ctx context.Context, log logr.Logger, rolesIDsToDelete []string, rolesClient *roles.Client) error { +func deleteRoles( + ctx context.Context, + log logr.Logger, + sdk *sdkkonnectgo.Roles, + userID string, + rolesIDsToDelete []string, +) error { if len(rolesIDsToDelete) == 0 { log.Info("No roles to delete") return nil @@ -148,7 +196,7 @@ func deleteRoles(ctx context.Context, log logr.Logger, rolesIDsToDelete []string var errs []error for _, roleID := range rolesIDsToDelete { log.Info("Deleting role", "id", roleID) - if err := rolesClient.DeleteRole(ctx, roleID); err != nil { + if _, err := sdk.UsersRemoveRole(ctx, userID, roleID); err != nil { errs = append(errs, fmt.Errorf("failed to delete role %s: %w", roleID, err)) } } diff --git a/internal/konnect/roles/client.go b/internal/konnect/roles/client.go deleted file mode 100644 index 277b35f713..0000000000 --- a/internal/konnect/roles/client.go +++ /dev/null @@ -1,167 +0,0 @@ -package roles - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - - "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/useragent" -) - -const ( - konnectUsersMeURL = "/users/me" - konnectUsersAssignedRolesURL = "/users/%s/assigned-roles?filter%%5Bentity_type_name%%5D=Runtime+Groups" - konnectAssignedRoleURL = "/users/%s/assigned-roles/%s" -) - -type Client struct { - httpClient *http.Client - personalAccessToken string - currentUserID string - baseURL string -} - -type Role struct { - // ID is the role ID. - ID string - - // EntityID is the ID of the entity the role is assigned to (e.g. Control Plane). - EntityID string -} - -func NewRole(id, entityID string) (Role, error) { - if id == "" { - return Role{}, fmt.Errorf("role ID is required") - } - if entityID == "" { - return Role{}, fmt.Errorf("entity ID is required") - } - return Role{ - ID: id, - EntityID: entityID, - }, nil -} - -func NewClient(httpClient *http.Client, baseURL string, personalAccessToken string) *Client { - httpClient.Transport = useragent.NewTransport(httpClient.Transport) - return &Client{ - baseURL: baseURL, - httpClient: httpClient, - personalAccessToken: personalAccessToken, - } -} - -// ListControlPlanesRoles lists all roles assigned to the current user for Control Planes. -func (c *Client) ListControlPlanesRoles(ctx context.Context) ([]Role, error) { - currentUserID, err := c.getCurrentUserID(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get current user ID: %w", err) - } - - listRolesURL := fmt.Sprintf(konnectUsersAssignedRolesURL, currentUserID) - req, err := c.newRequestWithAuth(ctx, http.MethodGet, listRolesURL, nil) - if err != nil { - return nil, fmt.Errorf("failed to create request: %w", err) - } - - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, fmt.Errorf("failed to list roles: %w", err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("failed to list roles, status: %s", resp.Status) - } - - var rolesResponse struct { - Data []struct { - ID string `json:"id"` - EntityID string `json:"entity_id"` - } `json:"data"` - } - if err := json.NewDecoder(resp.Body).Decode(&rolesResponse); err != nil { - return nil, fmt.Errorf("failed to decode roles response: %w", err) - } - - roles := make([]Role, 0, len(rolesResponse.Data)) - for _, role := range rolesResponse.Data { - r, err := NewRole(role.ID, role.EntityID) - if err != nil { - return nil, fmt.Errorf("failed to create role: %w", err) - } - roles = append(roles, r) - } - - return roles, nil -} - -// DeleteRole deletes a role assigned to the current user. -func (c *Client) DeleteRole(ctx context.Context, roleID string) error { - currentUserID, err := c.getCurrentUserID(ctx) - if err != nil { - return fmt.Errorf("failed to get current user ID: %w", err) - } - - deleteRoleURL := fmt.Sprintf(konnectAssignedRoleURL, currentUserID, roleID) - req, err := c.newRequestWithAuth(ctx, http.MethodDelete, deleteRoleURL, nil) - if err != nil { - return fmt.Errorf("failed to create request: %w", err) - } - resp, err := c.httpClient.Do(req) - if err != nil { - return fmt.Errorf("failed to delete role %s: %w", roleID, err) - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusNoContent { - return fmt.Errorf("failed to delete role %s, status: %s", roleID, resp.Status) - } - - return nil -} - -func (c *Client) getCurrentUserID(ctx context.Context) (string, error) { - // It's already cached, no need to make a request. - if c.currentUserID != "" { - return c.currentUserID, nil - } - - meRequest, err := c.newRequestWithAuth(ctx, http.MethodGet, konnectUsersMeURL, nil) - if err != nil { - return "", fmt.Errorf("failed to create request: %w", err) - } - meResponse, err := c.httpClient.Do(meRequest) - if err != nil { - return "", fmt.Errorf("failed to get current user: %w", err) - } - defer meResponse.Body.Close() - if meResponse.StatusCode != http.StatusOK { - return "", fmt.Errorf("failed to get current user, status: %s", meResponse.Status) - } - - var meResponseData struct { - ID string `json:"id"` - } - if err := json.NewDecoder(meResponse.Body).Decode(&meResponseData); err != nil { - return "", fmt.Errorf("failed to decode current user response: %w", err) - } - - if meResponseData.ID == "" { - return "", fmt.Errorf("failed to get current user, empty id") - } - - c.currentUserID = meResponseData.ID - return meResponseData.ID, nil -} - -func (c *Client) newRequestWithAuth(ctx context.Context, method, url string, body io.Reader) (*http.Request, error) { - req, err := http.NewRequestWithContext(ctx, method, c.baseURL+url, body) - if err != nil { - return nil, fmt.Errorf("failed to create request: %w", err) - } - req.Header.Set("Authorization", "Bearer "+c.personalAccessToken) - return req, nil -} diff --git a/internal/konnect/roles/client_test.go b/internal/konnect/roles/client_test.go deleted file mode 100644 index 105c457749..0000000000 --- a/internal/konnect/roles/client_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package roles_test - -import ( - "context" - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/roles" - "github.com/kong/kubernetes-ingress-controller/v3/internal/manager/metadata" -) - -const ( - currentUserID = "515d12f2-aab2-42b3-a093-6ad793c0c7ab" - testToken = "test-token" -) - -func newMockRolesServer(t *testing.T) *httptest.Server { - mux := http.NewServeMux() - - requireToken := func(r *http.Request) { - token := r.Header.Get("Authorization") - require.Equal(t, "Bearer "+testToken, token) - } - requireUserAgent := func(r *http.Request) { - userAgent := r.Header.Get("User-Agent") - require.Equal(t, metadata.UserAgent(), userAgent) - } - - mux.HandleFunc("/users/me", func(w http.ResponseWriter, r *http.Request) { - requireUserAgent(r) - requireToken(r) - - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(` - { - "id": "515d12f2-aab2-42b3-a093-6ad793c0c7ab", - "email": "team-k8s+konnect-testing-2@konghq.com", - "full_name": "Kubernetes Team", - "preferred_name": "", - "active": true, - "created_at": "2023-06-26T12:16:08Z", - "updated_at": "2023-06-26T12:16:28Z" - }`)) - }) - - mux.HandleFunc("/users/"+currentUserID+"/assigned-roles/", func(w http.ResponseWriter, r *http.Request) { - requireUserAgent(r) - requireToken(r) - - switch r.Method { - case http.MethodGet: - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(` - { - "meta": { - "page": { - "number": 1, - "size": 10, - "total": 2 - } - }, - "data": [ - { - "id": "24ac168d-4ffb-46ec-8dd6-5a26b5ec6f0b", - "role_name": "Admin", - "entity_region": "us", - "entity_type_name": "Control Planes", - "entity_id": "e3f155ec-1786-4017-98d0-b0a0f5e179c3" - }, - { - "id": "7edaf68b-8f07-4827-b540-fce06e45429e", - "role_name": "Admin", - "entity_region": "us", - "entity_type_name": "Control Planes", - "entity_id": "c486f518-9fc8-461f-af0a-2bc85b70e492" - } - ] - }`)) - case http.MethodDelete: - requireUserAgent(r) - w.WriteHeader(http.StatusNoContent) - default: - t.Errorf("unexpected method %s", r.Method) - } - }) - - return httptest.NewServer(mux) -} - -func TestRolesClient(t *testing.T) { - ctx := context.Background() - server := newMockRolesServer(t) - c := roles.NewClient(&http.Client{}, server.URL, testToken) - - rgRoles, err := c.ListControlPlanesRoles(ctx) - require.NoError(t, err) - require.Equal(t, 2, len(rgRoles)) - role := rgRoles[0] - require.Equal(t, "24ac168d-4ffb-46ec-8dd6-5a26b5ec6f0b", role.ID) - require.Equal(t, "e3f155ec-1786-4017-98d0-b0a0f5e179c3", role.EntityID) - - err = c.DeleteRole(ctx, "24ac168d-4ffb-46ec-8dd6-5a26b5ec6f0b") - require.NoError(t, err) -} diff --git a/test/consts.go b/test/consts.go index 65d47d268e..a006c4c343 100644 --- a/test/consts.go +++ b/test/consts.go @@ -35,3 +35,8 @@ const ( // RequestTimeout is the amount of time that will be given to any request to complete. RequestTimeout = 10 * time.Second ) + +const ( + // konnectDefaultDevServerURL is the default Konnect API server URL used for development. + konnectDefaultDevServerURL = "https://us.api.konghq.tech" +) diff --git a/test/internal/helpers/konnect/access.go b/test/internal/helpers/konnect/access.go index 8ce9fb020e..f5d696d04c 100644 --- a/test/internal/helpers/konnect/access.go +++ b/test/internal/helpers/konnect/access.go @@ -5,6 +5,8 @@ import ( "testing" sdkkonnectgo "github.com/Kong/sdk-konnect-go" + + "github.com/kong/kubernetes-ingress-controller/v3/test" ) // SkipIfMissingRequiredKonnectEnvVariables skips the test if the required Konnect environment variables are missing. @@ -19,19 +21,12 @@ func accessToken() string { return os.Getenv("TEST_KONG_KONNECT_ACCESS_TOKEN") } -// konnectRolesBaseURL returns the base URL for Konnect Roles API. -// NOTE: This is a temporary solution until we migrate all the Konnect API calls to the new SDK. -func konnectRolesBaseURL() string { - const konnectDefaultRolesBaseURL = "https://global.api.konghq.tech/v2" - return konnectDefaultRolesBaseURL -} - // konnectControlPlaneAdminAPIBaseURL returns the base URL for Konnect Control Plane Admin API. // NOTE: This is a temporary solution until we migrate all the Konnect API calls to the new SDK. func konnectControlPlaneAdminAPIBaseURL() string { const konnectDefaultControlPlaneAdminAPIBaseURL = "https://us.kic.api.konghq.tech" - serverURL := os.Getenv("TEST_KONG_KONNECT_SERVER_URL") + serverURL := test.KonnectServerURL() switch serverURL { case "https://eu.api.konghq.tech": return "https://eu.kic.api.konghq.tech" @@ -45,11 +40,5 @@ func konnectControlPlaneAdminAPIBaseURL() string { } func serverURLOpt() sdkkonnectgo.SDKOption { - const konnectDefaultSDKServerURL = "https://us.api.konghq.tech" - - serverURL := os.Getenv("TEST_KONG_KONNECT_SERVER_URL") - if serverURL != "" { - return sdkkonnectgo.WithServerURL(serverURL) - } - return sdkkonnectgo.WithServerURL(konnectDefaultSDKServerURL) + return sdkkonnectgo.WithServerURL(test.KonnectServerURL()) } diff --git a/test/internal/helpers/konnect/control_plane.go b/test/internal/helpers/konnect/control_plane.go index 776de11a96..d6f5215333 100644 --- a/test/internal/helpers/konnect/control_plane.go +++ b/test/internal/helpers/konnect/control_plane.go @@ -16,11 +16,11 @@ import ( "github.com/stretchr/testify/require" sdkkonnectcomp "github.com/Kong/sdk-konnect-go/models/components" + sdkkonnectops "github.com/Kong/sdk-konnect-go/models/operations" "github.com/kong/kubernetes-ingress-controller/v3/internal/adminapi" - "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/roles" "github.com/kong/kubernetes-ingress-controller/v3/internal/konnect/sdk" - "github.com/kong/kubernetes-ingress-controller/v3/test/internal/helpers" + "github.com/kong/kubernetes-ingress-controller/v3/test" "github.com/kong/kubernetes-ingress-controller/v3/test/internal/testenv" ) @@ -31,12 +31,6 @@ func CreateTestControlPlane(ctx context.Context, t *testing.T) string { sdk := sdk.New(accessToken(), serverURLOpt()) - rolesClient := roles.NewClient( - helpers.RetryableHTTPClient(helpers.DefaultHTTPClient()), - konnectRolesBaseURL(), - accessToken(), - ) - var rgID string createRgErr := retry.Do(func() error { createResp, err := sdk.ControlPlanes.CreateControlPlane(ctx, @@ -84,6 +78,15 @@ func CreateTestControlPlane(ctx context.Context, t *testing.T) string { ) assert.NoErrorf(t, err, "failed to cleanup a control plane: %q", rgID) + me, err := sdk.Me.GetUsersMe(ctx, + // NOTE: Otherwise we use prod server by default. + // Related issue: https://github.com/Kong/sdk-konnect-go/issues/20 + sdkkonnectops.WithServerURL(test.KonnectServerURL()), + ) + if !assert.NoError(t, err) { + return + } + // We have to manually delete roles created for the control plane because Konnect doesn't do it automatically. // If we don't do it, we will eventually hit a problem with Konnect APIs answering our requests with 504s // because of a performance issue when there's too many roles for the account @@ -91,13 +94,24 @@ func CreateTestControlPlane(ctx context.Context, t *testing.T) string { // // We can drop this once the automated cleanup is implemented on Konnect side: // https://konghq.atlassian.net/browse/TPS-1453. - rgRoles, err := rolesClient.ListControlPlanesRoles(ctx) + resp, err := sdk.Roles.ListUserRoles(ctx, *me.User.ID, + &sdkkonnectops.ListUserRolesQueryParamFilter{}, + // Related issue: https://github.com/Kong/sdk-konnect-go/issues/20 + sdkkonnectops.WithServerURL(test.KonnectServerURL()), + ) require.NoErrorf(t, err, "failed to list control plane roles for cleanup: %q", rgID) - for _, role := range rgRoles { - if role.EntityID == rgID { // Delete only roles created for the control plane. - t.Logf("deleting test Konnect Control Plane role: %q", role.ID) - err := rolesClient.DeleteRole(ctx, role.ID) - assert.NoErrorf(t, err, "failed to cleanup a control plane role: %q", role.ID) + + for _, role := range resp.AssignedRoleCollection.Data { + if role.EntityID == nil || role.ID == nil { + continue + } + if *role.EntityID == rgID { // Delete only roles created for the control plane. + t.Logf("deleting test Konnect Control Plane role: %q", *role.ID) + _, err := sdk.Roles.UsersRemoveRole(ctx, *me.User.ID, *role.ID, + // Related issue: https://github.com/Kong/sdk-konnect-go/issues/20 + sdkkonnectops.WithServerURL(test.KonnectServerURL()), + ) + assert.NoErrorf(t, err, "failed to cleanup a control plane role: %q", *role.ID) } } }) diff --git a/test/konnect.go b/test/konnect.go new file mode 100644 index 0000000000..a13067c0e6 --- /dev/null +++ b/test/konnect.go @@ -0,0 +1,14 @@ +package test + +import "os" + +// KonnectServerURL returns the Konnect server URL to be used for Konnect API +// requests in tests and CI. +// It is driven by the TEST_KONG_KONNECT_SERVER_URL environment variable. +func KonnectServerURL() string { + serverURL := os.Getenv("TEST_KONG_KONNECT_SERVER_URL") + if serverURL != "" { + return serverURL + } + return konnectDefaultDevServerURL +}