Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 7 additions & 7 deletions backend/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import (
"net/url"
"strings"

apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
"github.com/kcp-dev/multicluster-provider/apiexport"
apisv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1"
apisv1alpha2 "github.com/kcp-dev/sdk/apis/apis/v1alpha2"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
Expand All @@ -39,6 +39,7 @@ import (

kuberesources "github.com/kube-bind/kube-bind/backend/kubernetes/resources"
"github.com/kube-bind/kube-bind/backend/options"
kcpprovider "github.com/kube-bind/kube-bind/backend/provider/kcp"
kubebindv1alpha1 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha1"
kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
)
Expand Down Expand Up @@ -70,10 +71,6 @@ func NewConfig(options *options.CompletedOptions) (*Config, error) {
config.ClientConfig = rest.CopyConfig(config.ClientConfig)
config.ClientConfig = rest.AddUserAgent(config.ClientConfig, "kube-bind-backend")

if options.ServerURL != "" {
config.ClientConfig.Host = options.ServerURL
}

// Set up controller-runtime manager
scheme := runtime.NewScheme()
if err := clientgoscheme.AddToScheme(scheme); err != nil {
Expand All @@ -93,13 +90,16 @@ func NewConfig(options *options.CompletedOptions) (*Config, error) {

switch options.Provider {
case "kcp":
if options.ProviderKcp == nil {
return nil, fmt.Errorf("kcp provider options must be provided when provider is kcp")
}
if err := apisv1alpha1.AddToScheme(scheme); err != nil {
return nil, fmt.Errorf("error adding apis scheme: %w", err)
}
if err := apisv1alpha2.AddToScheme(scheme); err != nil {
return nil, fmt.Errorf("error adding apis scheme: %w", err)
}
provider, err := apiexport.New(config.ClientConfig, apiexport.Options{
provider, err := kcpprovider.New(config.ClientConfig, options.ProviderKcp.APIExportEndpointSliceName, apiexport.Options{
Scheme: scheme,
})
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion backend/oidc/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"strings"
"testing"

"github.com/kcp-dev/kcp/sdk/testing/third_party/library-go/crypto"
"github.com/kcp-dev/sdk/testing/third_party/library-go/crypto"
"github.com/xrstf/mockoidc"
)

Expand Down
38 changes: 26 additions & 12 deletions backend/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/component-base/logs"
logsv1 "k8s.io/component-base/logs/api/v1"

providerkcp "github.com/kube-bind/kube-bind/backend/provider/kcp/options"
kubebindv1alpha2 "github.com/kube-bind/kube-bind/sdk/apis/kubebind/v1alpha2"
)

Expand All @@ -36,14 +37,15 @@ type Options struct {
Cookie *Cookie
Serve *Serve

ProviderKcp *providerkcp.Options

ExtraOptions
}

type ExtraOptions struct {
KubeConfig string

Provider string
ServerURL string
Provider string

NamespacePrefix string
PrettyName string
Expand Down Expand Up @@ -73,6 +75,9 @@ type completedOptions struct {
Cookie *Cookie
Serve *Serve

// Provider specific options
ProviderKcp *providerkcp.CompletedOptions

ExtraOptions
}

Expand All @@ -85,23 +90,24 @@ func NewOptions() *Options {
logs := logs.NewOptions()
logs.Verbosity = logsv1.VerbosityLevel(2)

return &Options{
Logs: logs,
OIDC: NewOIDC(),
Cookie: NewCookie(),
Serve: NewServe(),
opts := &Options{
Logs: logs,
OIDC: NewOIDC(),
Cookie: NewCookie(),
Serve: NewServe(),
ProviderKcp: providerkcp.NewOptions(),

ExtraOptions: ExtraOptions{
Provider: "kubernetes",
NamespacePrefix: "cluster",
PrettyName: "Backend",
ConsumerScope: string(kubebindv1alpha2.NamespacedScope),
ClusterScopedIsolation: string(kubebindv1alpha2.IsolationPrefixed),
ServerURL: "",
SchemaSource: CustomResourceDefinitionSource.String(),
Frontend: "embedded", // Not used, but indicates to use embedded frontend using SPA.
},
}
return opts
}

var providerAliases = map[string]string{
Expand Down Expand Up @@ -135,6 +141,7 @@ func (options *Options) AddFlags(fs *pflag.FlagSet) {
options.OIDC.AddFlags(fs)
options.Cookie.AddFlags(fs)
options.Serve.AddFlags(fs)
options.ProviderKcp.AddFlags(fs)

fs.StringVar(&options.KubeConfig, "kubeconfig", options.KubeConfig, "path to a kubeconfig. Only required if out-of-cluster")
fs.StringVar(&options.NamespacePrefix, "namespace-prefix", options.NamespacePrefix, "The prefix to use for cluster namespaces")
Expand All @@ -160,8 +167,6 @@ func (options *Options) AddFlags(fs *pflag.FlagSet) {
values),
)

fs.StringVar(&options.ServerURL, "server-url", options.ServerURL, "The URL of the backend server. If not specified, it will be derived from the kubeconfig or service account's hosts.")

fs.StringVar(&options.TestingAutoSelect, "testing-auto-select", options.TestingAutoSelect, "<resource>.<group> that is automatically selected on th bind screen for testing")
fs.MarkHidden("testing-auto-select") //nolint:errcheck
}
Expand Down Expand Up @@ -209,15 +214,24 @@ func (options *Options) Complete() (*CompletedOptions, error) {
}
options.ExternalCA = ca
}
return &CompletedOptions{
co := &CompletedOptions{
completedOptions: &completedOptions{
Logs: options.Logs,
OIDC: options.OIDC,
Cookie: options.Cookie,
Serve: options.Serve,
ExtraOptions: options.ExtraOptions,
},
}, nil
}

if options.Provider == "kcp" {
opts, err := options.ProviderKcp.Complete()
if err != nil {
return nil, err
}
co.completedOptions.ProviderKcp = opts
}
return co, nil
}

func (options *CompletedOptions) Validate() error {
Expand Down
61 changes: 61 additions & 0 deletions backend/provider/kcp/options/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2025 The Kube Bind Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package options

import (
"github.com/spf13/pflag"
)

type Options struct {
ExtraOptions
}

type ExtraOptions struct {
APIExportEndpointSliceName string
}

type completedOptions struct {
ExtraOptions
}

type CompletedOptions struct {
*completedOptions
}

func NewOptions() *Options {
return &Options{
ExtraOptions: ExtraOptions{
APIExportEndpointSliceName: "kube-bind.io",
},
}
}

func (options *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&options.ExtraOptions.APIExportEndpointSliceName, "apiexport-endpoint-slice-name", options.ExtraOptions.APIExportEndpointSliceName, "name of the APIExport EndpointSlice to watch")
}

func (options *Options) Complete() (*CompletedOptions, error) {
return &CompletedOptions{
completedOptions: &completedOptions{
ExtraOptions: options.ExtraOptions,
},
}, nil
}

func (options *CompletedOptions) Validate() error {
return nil
}
78 changes: 78 additions & 0 deletions backend/provider/kcp/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Copyright 2025 The Kube Bind Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kcp

import (
"context"

provider "github.com/kcp-dev/multicluster-provider/apiexport"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/cluster"
"sigs.k8s.io/multicluster-runtime/pkg/multicluster"
)

var _ multicluster.Provider = &Provider{}
var _ multicluster.ProviderRunnable = &Provider{}

// Provider is a [sigs.k8s.io/multicluster-runtime/pkg/multicluster.Provider] that represents each [logical cluster]
// (in the kcp sense) exposed via a APIExport virtual workspace as a cluster in the [sigs.k8s.io/multicluster-runtime] sense.
//
// Core functionality is delegated to the apiexport.Provider, this wrapper just adds best effort path-awareness index to it via hooks.
//
// [logical cluster]: https://docs.kcp.io/kcp/latest/concepts/terminology/#logical-cluster
type Provider struct {
*provider.Provider
}

// New is simple provider wrapper for kcp.
func New(cfg *rest.Config, endpointSliceName string, options provider.Options) (*Provider, error) {
p, err := provider.New(cfg, endpointSliceName, options)
if err != nil {
return nil, err
}

return &Provider{
Provider: p,
}, nil
}

// Get returns the cluster with the given name as a cluster.Cluster.
func (p *Provider) Get(ctx context.Context, clusterName string) (cluster.Cluster, error) {
return p.Provider.Get(ctx, clusterName)
}

// IndexField adds an indexer to the clusters managed by this provider.
func (p *Provider) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
return p.Provider.IndexField(ctx, obj, field, extractValue)
}

// Start starts the provider and blocks.
func (p *Provider) Start(ctx context.Context, aware multicluster.Aware) error {
return p.Provider.Start(ctx, &awareWrapper{Aware: aware})
}

// awareWrapper wraps a multicluster.Aware to create kube-bind Cluster objects
// so we could bootstrap RBAC for them.
type awareWrapper struct {
multicluster.Aware
}

func (a *awareWrapper) Engage(ctx context.Context, name string, cluster cluster.Cluster) error {
// TODO: Add cluster seeding here in the follow-up PRS.
return a.Aware.Engage(ctx, name, cluster)
}
17 changes: 0 additions & 17 deletions backend/provider/provider.go

This file was deleted.

12 changes: 6 additions & 6 deletions cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ require (
github.com/spf13/pflag v1.0.9
github.com/stretchr/testify v1.11.1
helm.sh/helm/v3 v3.19.0
k8s.io/api v0.34.0
k8s.io/apiextensions-apiserver v0.34.0
k8s.io/apimachinery v0.34.0
k8s.io/api v0.34.2
k8s.io/apiextensions-apiserver v0.34.2
k8s.io/apimachinery v0.34.2
k8s.io/cli-runtime v0.34.0
k8s.io/client-go v0.34.0
k8s.io/component-base v0.34.0
k8s.io/client-go v0.34.2
k8s.io/component-base v0.34.2
k8s.io/klog/v2 v2.130.1
sigs.k8s.io/kind v0.30.0
sigs.k8s.io/yaml v1.6.0
Expand Down Expand Up @@ -148,7 +148,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.2 // indirect
k8s.io/apiserver v0.34.0 // indirect
k8s.io/apiserver v0.34.2 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/kubectl v0.34.0 // indirect
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
Expand Down
24 changes: 12 additions & 12 deletions cli/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -444,20 +444,20 @@ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
helm.sh/helm/v3 v3.19.0 h1:krVyCGa8fa/wzTZgqw0DUiXuRT5BPdeqE/sQXujQ22k=
helm.sh/helm/v3 v3.19.0/go.mod h1:Lk/SfzN0w3a3C3o+TdAKrLwJ0wcZ//t1/SDXAvfgDdc=
k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE=
k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug=
k8s.io/apiextensions-apiserver v0.34.0 h1:B3hiB32jV7BcyKcMU5fDaDxk882YrJ1KU+ZSkA9Qxoc=
k8s.io/apiextensions-apiserver v0.34.0/go.mod h1:hLI4GxE1BDBy9adJKxUxCEHBGZtGfIg98Q+JmTD7+g0=
k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0=
k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/apiserver v0.34.0 h1:Z51fw1iGMqN7uJ1kEaynf2Aec1Y774PqU+FVWCFV3Jg=
k8s.io/apiserver v0.34.0/go.mod h1:52ti5YhxAvewmmpVRqlASvaqxt0gKJxvCeW7ZrwgazQ=
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo=
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE=
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
k8s.io/cli-runtime v0.34.0 h1:N2/rUlJg6TMEBgtQ3SDRJwa8XyKUizwjlOknT1mB2Cw=
k8s.io/cli-runtime v0.34.0/go.mod h1:t/skRecS73Piv+J+FmWIQA2N2/rDjdYSQzEE67LUUs8=
k8s.io/client-go v0.34.0 h1:YoWv5r7bsBfb0Hs2jh8SOvFbKzzxyNo0nSb0zC19KZo=
k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY=
k8s.io/component-base v0.34.0 h1:bS8Ua3zlJzapklsB1dZgjEJuJEeHjj8yTu1gxE2zQX8=
k8s.io/component-base v0.34.0/go.mod h1:RSCqUdvIjjrEm81epPcjQ/DS+49fADvGSCkIP3IC6vg=
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ=
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
Expand Down
Loading