Skip to content

Feat: virtual workspace #282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6aa4dac
feat: virtual ws support
vertex451 Jul 15, 2025
22fe7a4
Merge branch 'main' of github.com:openmfp/kubernetes-graphql-gateway …
vertex451 Jul 16, 2025
e386bf1
/{virtual-ws-name}/clusters/{cluster-name}/api/v1
vertex451 Jul 17, 2025
4f370c6
virtual ws works in the gateway
vertex451 Jul 18, 2025
d964753
normal ws works
vertex451 Jul 18, 2025
5c33b08
pass kubeconfig via metadata
vertex451 Jul 18, 2025
fba3b4e
first iteration of improvements
vertex451 Jul 21, 2025
57d3b7c
tests for extractClusterName
vertex451 Jul 21, 2025
9f12a03
added pattern matching
vertex451 Jul 21, 2025
0d2e5cc
removed overlaped tests cases
vertex451 Jul 21, 2025
7f20b65
imporved kcp/apibinding_controller.go
vertex451 Jul 21, 2025
e711fd7
moved metadata injector to common package
vertex451 Jul 21, 2025
8d3644b
improved virtual worksapce code
vertex451 Jul 22, 2025
51fe783
moved url params to the config
vertex451 Jul 22, 2025
164a3e6
fix test
vertex451 Jul 22, 2025
861a3e0
pass context to watcher from the very top
vertex451 Jul 22, 2025
0b4d447
removed Close() method
vertex451 Jul 22, 2025
8936333
fixed tests
vertex451 Jul 22, 2025
28a19c5
more coverage
vertex451 Jul 22, 2025
fe6fdff
watcher test
vertex451 Jul 22, 2025
baa7339
listener/reconciler/kcp/virtual_workspace_test.go
vertex451 Jul 22, 2025
513d338
fix tests
vertex451 Jul 22, 2025
969a712
linter
vertex451 Jul 22, 2025
8bf176f
adjusted sleep time
vertex451 Jul 22, 2025
acf4135
one more fix
vertex451 Jul 22, 2025
97ac6b8
fixed tests
vertex451 Jul 22, 2025
e5ee282
removed redundnat test
vertex451 Jul 22, 2025
675663a
increse coverage
vertex451 Jul 22, 2025
d123a8d
linter
vertex451 Jul 22, 2025
bc4a0c4
more tests
vertex451 Jul 23, 2025
9001fa7
tests for listener/reconciler/clusteraccess/metadata_injector_test.go
vertex451 Jul 23, 2025
cd170fe
fixed unnecessary extract auth data call in inject metadata
vertex451 Jul 23, 2025
2a02c2f
pass ctx from top
vertex451 Jul 23, 2025
4f3cd2c
extractAuthDataForMetadata test
vertex451 Jul 23, 2025
55ca379
reduced complexity at metadata_injector
vertex451 Jul 23, 2025
141ce82
return error if no watching path
vertex451 Jul 23, 2025
a2815de
adjust tests
vertex451 Jul 23, 2025
7cc1136
WalkDir
vertex451 Jul 23, 2025
2c4f965
used constants for timeout
vertex451 Jul 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var gatewayCmd = &cobra.Command{

ctrl.SetLogger(log.Logr())

gatewayInstance, err := manager.NewGateway(log, appCfg)
gatewayInstance, err := manager.NewGateway(ctx, log, appCfg)
if err != nil {
log.Error().Err(err).Msg("Error creating gateway")
return fmt.Errorf("failed to create gateway: %w", err)
Expand Down
26 changes: 21 additions & 5 deletions cmd/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,29 @@ var listenCmd = &cobra.Command{
// Create the appropriate reconciler based on configuration
var reconcilerInstance reconciler.CustomReconciler
if appCfg.EnableKcp {
reconcilerInstance, err = kcp.NewKCPReconciler(appCfg, reconcilerOpts, log)
kcpReconciler, err := kcp.NewKCPReconciler(appCfg, reconcilerOpts, log)
if err != nil {
log.Error().Err(err).Msg("unable to create KCP reconciler")
os.Exit(1)
}

// Start virtual workspace watching if path is configured
if appCfg.Listener.VirtualWorkspacesConfigPath != "" {
go func() {
if err := kcpReconciler.StartVirtualWorkspaceWatching(ctx, appCfg.Listener.VirtualWorkspacesConfigPath); err != nil {
log.Error().Err(err).Msg("failed to start virtual workspace watching")
os.Exit(1)
}
}()
}

reconcilerInstance = kcpReconciler
} else {
reconcilerInstance, err = clusteraccess.CreateMultiClusterReconciler(appCfg, reconcilerOpts, log)
}
if err != nil {
log.Error().Err(err).Msg("unable to create reconciler")
os.Exit(1)
if err != nil {
log.Error().Err(err).Msg("unable to create cluster access reconciler")
os.Exit(1)
}
}

// Setup reconciler with its own manager and start everything
Expand Down
4 changes: 4 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ func initConfig() {
v.SetDefault("gateway-cors-enabled", false)
v.SetDefault("gateway-cors-allowed-origins", "*")
v.SetDefault("gateway-cors-allowed-headers", "*")
// Gateway URL
v.SetDefault("gateway-url-virtual-workspace-prefix", "virtual-workspace")
v.SetDefault("gateway-url-default-kcp-workspace", "root")
v.SetDefault("gateway-url-graphql-suffix", "graphql")
}

func Execute() {
Expand Down
14 changes: 5 additions & 9 deletions common/auth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

// BuildConfig creates a rest.Config from cluster connection parameters
// This function unifies the authentication logic used by both listener and gateway
func BuildConfig(host string, auth *gatewayv1alpha1.AuthConfig, ca *gatewayv1alpha1.CAConfig, k8sClient client.Client) (*rest.Config, error) {
func BuildConfig(ctx context.Context, host string, auth *gatewayv1alpha1.AuthConfig, ca *gatewayv1alpha1.CAConfig, k8sClient client.Client) (*rest.Config, error) {
if host == "" {
return nil, errors.New("host is required")
}
Expand All @@ -34,7 +34,7 @@ func BuildConfig(host string, auth *gatewayv1alpha1.AuthConfig, ca *gatewayv1alp

// Handle CA configuration first
if ca != nil {
caData, err := ExtractCAData(ca, k8sClient)
caData, err := ExtractCAData(ctx, ca, k8sClient)
if err != nil {
return nil, errors.Join(errors.New("failed to extract CA data"), err)
}
Expand All @@ -46,7 +46,7 @@ func BuildConfig(host string, auth *gatewayv1alpha1.AuthConfig, ca *gatewayv1alp

// Handle Auth configuration
if auth != nil {
err := ConfigureAuthentication(config, auth, k8sClient)
err := ConfigureAuthentication(ctx, config, auth, k8sClient)
if err != nil {
return nil, errors.Join(errors.New("failed to configure authentication"), err)
}
Expand Down Expand Up @@ -118,13 +118,11 @@ func BuildConfigFromMetadata(host string, authType, token, kubeconfig, certData,
}

// ExtractCAData extracts CA certificate data from secret or configmap references
func ExtractCAData(ca *gatewayv1alpha1.CAConfig, k8sClient client.Client) ([]byte, error) {
func ExtractCAData(ctx context.Context, ca *gatewayv1alpha1.CAConfig, k8sClient client.Client) ([]byte, error) {
if ca == nil {
return nil, nil
}

ctx := context.Background()

if ca.SecretRef != nil {
secret := &corev1.Secret{}
namespace := ca.SecretRef.Namespace
Expand Down Expand Up @@ -175,13 +173,11 @@ func ExtractCAData(ca *gatewayv1alpha1.CAConfig, k8sClient client.Client) ([]byt
}

// ConfigureAuthentication configures authentication for rest.Config from AuthConfig
func ConfigureAuthentication(config *rest.Config, auth *gatewayv1alpha1.AuthConfig, k8sClient client.Client) error {
func ConfigureAuthentication(ctx context.Context, config *rest.Config, auth *gatewayv1alpha1.AuthConfig, k8sClient client.Client) error {
if auth == nil {
return nil
}

ctx := context.Background()

if auth.SecretRef != nil {
secret := &corev1.Secret{}
namespace := auth.SecretRef.Namespace
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package clusteraccess_test
package auth

import (
"context"
Expand All @@ -15,7 +15,6 @@ import (

gatewayv1alpha1 "github.com/openmfp/kubernetes-graphql-gateway/common/apis/v1alpha1"
"github.com/openmfp/kubernetes-graphql-gateway/common/mocks"
"github.com/openmfp/kubernetes-graphql-gateway/listener/reconciler/clusteraccess"
)

func TestConfigureAuthentication(t *testing.T) {
Expand Down Expand Up @@ -257,7 +256,7 @@ clusters:
},
}

err := clusteraccess.ConfigureAuthentication(config, tt.auth, mockClient)
err := ConfigureAuthentication(t.Context(), config, tt.auth, mockClient)

if tt.wantErr {
assert.Error(t, err)
Expand Down Expand Up @@ -366,7 +365,7 @@ func TestExtractAuthFromKubeconfig(t *testing.T) {
},
}

err := clusteraccess.ExtractAuthFromKubeconfig(config, tt.authInfo)
err := ExtractAuthFromKubeconfig(config, tt.authInfo)

if tt.wantErr {
assert.Error(t, err)
Expand Down
Loading