Skip to content

Commit 4a0b026

Browse files
committed
Move manager to use ctrl runtime.
1 parent df09b05 commit 4a0b026

13 files changed

Lines changed: 337 additions & 214 deletions

File tree

cli/pkg/kubectl/base/kubeconfig.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ func ParseRemoteKubeconfig(kubeconfig []byte) (host string, ns string, err error
3535
return "", "", nil
3636
}
3737
if _, found := config.Contexts[config.CurrentContext]; !found {
38-
return "", "", fmt.Errorf("current context %q of remote kubeconfig not found", config.CurrentContext)
38+
return "", "", fmt.Errorf("current context '%q' of remote kubeconfig not found", config.CurrentContext)
3939
}
4040
cluster, found := config.Clusters[config.Contexts[config.CurrentContext].Cluster]
4141
if !found {
42-
return "", "", fmt.Errorf("cluster %q in current context %q of remote kubeconfig not found", config.Contexts[config.CurrentContext].Cluster, config.CurrentContext)
42+
return "", "", fmt.Errorf("cluster '%q' in current context '%q' of remote kubeconfig not found", config.Contexts[config.CurrentContext].Cluster, config.CurrentContext)
4343
}
4444

4545
return cluster.Server, config.Contexts[config.CurrentContext].Namespace, nil

cmd/example-backend/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ func run(ctx context.Context) error {
8484
if err != nil {
8585
return err
8686
}
87-
server.OptionallyStartInformers(ctx)
87+
8888
if err := server.Run(ctx); err != nil {
8989
return err
9090
}
91-
logger.Info("Listening on %s\n", server.Addr())
91+
logger.Info("Listening on", "address", server.Addr())
9292

9393
<-ctx.Done()
9494

contrib/example-backend/config.go

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,21 @@ package backend
1818

1919
import (
2020
"fmt"
21-
"time"
2221

2322
"github.com/kcp-dev/multicluster-provider/apiexport"
24-
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
25-
apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions"
26-
kubeinformers "k8s.io/client-go/informers"
27-
kubernetesclient "k8s.io/client-go/kubernetes"
2823
"k8s.io/client-go/rest"
2924
"k8s.io/client-go/tools/clientcmd"
3025
"sigs.k8s.io/multicluster-runtime/pkg/multicluster"
3126

3227
"github.com/kube-bind/kube-bind/contrib/example-backend/options"
33-
bindclient "github.com/kube-bind/kube-bind/sdk/client/clientset/versioned"
34-
bindinformers "github.com/kube-bind/kube-bind/sdk/client/informers/externalversions"
3528
)
3629

3730
type Config struct {
3831
Options *options.CompletedOptions
3932

4033
Provider multicluster.Provider
4134

42-
ClientConfig *rest.Config
43-
BindClient *bindclient.Clientset
44-
KubeClient *kubernetesclient.Clientset
45-
ApiextensionsClient *apiextensionsclient.Clientset
46-
47-
KubeInformers kubeinformers.SharedInformerFactory
48-
BindInformers bindinformers.SharedInformerFactory
49-
ApiextensionsInformers apiextensionsinformers.SharedInformerFactory
35+
ClientConfig *rest.Config
5036
}
5137

5238
func NewConfig(options *options.CompletedOptions) (*Config, error) {
@@ -63,22 +49,7 @@ func NewConfig(options *options.CompletedOptions) (*Config, error) {
6349
return nil, err
6450
}
6551
config.ClientConfig = rest.CopyConfig(config.ClientConfig)
66-
config.ClientConfig = rest.AddUserAgent(config.ClientConfig, "kube-bind-example-backend")
67-
68-
if config.BindClient, err = bindclient.NewForConfig(config.ClientConfig); err != nil {
69-
return nil, err
70-
}
71-
if config.KubeClient, err = kubernetesclient.NewForConfig(config.ClientConfig); err != nil {
72-
return nil, err
73-
}
74-
if config.ApiextensionsClient, err = apiextensionsclient.NewForConfig(config.ClientConfig); err != nil {
75-
return nil, err
76-
}
77-
78-
// construct informer factories
79-
config.KubeInformers = kubeinformers.NewSharedInformerFactory(config.KubeClient, time.Minute*30)
80-
config.BindInformers = bindinformers.NewSharedInformerFactory(config.BindClient, time.Minute*30)
81-
config.ApiextensionsInformers = apiextensionsinformers.NewSharedInformerFactory(config.ApiextensionsClient, time.Minute*30)
52+
config.ClientConfig = rest.AddUserAgent(config.ClientConfig, "kube-bind-backend")
8253

8354
switch options.Provider {
8455
case "kcp":

contrib/example-backend/http/handler.go

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"github.com/gorilla/mux"
3333
"github.com/gorilla/securecookie"
3434
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
35-
apiextensionslisters "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1"
3635
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3736
"k8s.io/apimachinery/pkg/labels"
3837
"k8s.io/apimachinery/pkg/runtime"
@@ -70,9 +69,8 @@ type handler struct {
7069
cookieEncryptionKey []byte
7170
cookieSigningKey []byte
7271

73-
client *http.Client
74-
apiextensionsLister apiextensionslisters.CustomResourceDefinitionLister
75-
kubeManager *kubernetes.Manager
72+
client *http.Client
73+
kubeManager *kubernetes.Manager
7674
}
7775

7876
func NewHandler(
@@ -81,7 +79,6 @@ func NewHandler(
8179
cookieSigningKey, cookieEncryptionKey []byte,
8280
scope kubebindv1alpha2.InformerScope,
8381
mgr *kubernetes.Manager,
84-
apiextensionsLister apiextensionslisters.CustomResourceDefinitionLister,
8582
) (*handler, error) {
8683
return &handler{
8784
oidc: provider,
@@ -92,26 +89,30 @@ func NewHandler(
9289
scope: scope,
9390
client: http.DefaultClient,
9491
kubeManager: mgr,
95-
apiextensionsLister: apiextensionsLister,
9692
cookieSigningKey: cookieSigningKey,
9793
cookieEncryptionKey: cookieEncryptionKey,
9894
}, nil
9995
}
10096

10197
func (h *handler) AddRoutes(mux *mux.Router) {
102-
mux.HandleFunc("/export", h.handleServiceExport).Methods("GET")
103-
mux.HandleFunc("/resources", h.handleResources).Methods("GET")
104-
mux.HandleFunc("/bind", h.handleBind).Methods("GET")
105-
mux.HandleFunc("/authorize", h.handleAuthorize).Methods("GET")
98+
// Every route is cluster scoped.
99+
mux.HandleFunc("/clusters/{cluster}/exports", h.handleServiceExport).Methods("GET")
100+
mux.HandleFunc("/clusters/{cluster}/resources", h.handleResources).Methods("GET")
101+
mux.HandleFunc("/clusters/{cluster}/bind", h.handleBind).Methods("GET")
102+
mux.HandleFunc("/clusters/{cluster}/authorize", h.handleAuthorize).Methods("GET")
103+
106104
mux.HandleFunc("/callback", h.handleCallback).Methods("GET")
107105
}
108106

109107
func (h *handler) handleServiceExport(w http.ResponseWriter, r *http.Request) {
110108
logger := klog.FromContext(r.Context()).WithValues("method", r.Method, "url", r.URL.String())
109+
logger.Info("handleServiceExport")
110+
111+
cluster := mux.Vars(r)["cluster"] // Not yet replace -.
111112

112113
oidcAuthorizeURL := h.oidcAuthorizeURL
113114
if oidcAuthorizeURL == "" {
114-
oidcAuthorizeURL = fmt.Sprintf("http://%s/authorize", r.Host)
115+
oidcAuthorizeURL = fmt.Sprintf("http://%s/clusters/%s/authorize", r.Host, cluster)
115116
}
116117

117118
ver, err := bindversion.BinaryVersion(componentbaseversion.Get().GitVersion)
@@ -159,11 +160,13 @@ func prepareNoCache(w http.ResponseWriter) {
159160
func (h *handler) handleAuthorize(w http.ResponseWriter, r *http.Request) {
160161
logger := klog.FromContext(r.Context()).WithValues("method", r.Method, "url", r.URL.String())
161162

163+
cluster := mux.Vars(r)["cluster"]
164+
162165
scopes := []string{"openid", "profile", "email", "offline_access"}
163166
code := &AuthCode{
164167
RedirectURL: r.URL.Query().Get("u"),
165168
SessionID: r.URL.Query().Get("s"),
166-
ClusterID: r.URL.Query().Get("c"),
169+
ClusterID: cluster,
167170
}
168171
if p := r.URL.Query().Get("p"); p != "" && code.RedirectURL == "" {
169172
code.RedirectURL = fmt.Sprintf("http://localhost:%s/callback", p)
@@ -277,40 +280,46 @@ func (h *handler) handleCallback(w http.ResponseWriter, r *http.Request) {
277280
}
278281

279282
http.SetCookie(w, cookie.MakeCookie(r, cookieName, encoded, time.Duration(1)*time.Hour))
280-
http.Redirect(w, r, "/resources?s="+authCode.SessionID, http.StatusFound)
283+
http.Redirect(w, r, "/clusters/"+authCode.ClusterID+"/resources?s="+authCode.SessionID, http.StatusFound)
281284
}
282285

283286
func (h *handler) handleResources(w http.ResponseWriter, r *http.Request) {
284287
logger := klog.FromContext(r.Context()).WithValues("method", r.Method, "url", r.URL.String())
285288

286289
prepareNoCache(w)
287290

291+
clusterPath := mux.Vars(r)["cluster"]
292+
var cluster string
293+
if clusterPath == "-" {
294+
cluster = "" // empty strings means - all cluster for for Multicluster-runtime. But this does not work for bind UI.
295+
}
296+
288297
if h.testingAutoSelect != "" {
289298
parts := strings.SplitN(h.testingAutoSelect, ".", 2)
290-
http.Redirect(w, r, "/resources/"+parts[0]+"/"+parts[1], http.StatusFound)
299+
http.Redirect(w, r, "/clusters/"+cluster+"/resources/"+parts[0]+"/"+parts[1], http.StatusFound)
291300
return
292301
}
293302

294303
labelSelector := labels.Set{
295304
resources.ExportedCRDsLabel: "true",
296305
}
297-
crds, err := h.apiextensionsLister.List(labelSelector.AsSelector())
306+
crds, err := h.kubeManager.ListCustomResourceDefinitions(r.Context(), cluster, labelSelector.AsSelector())
298307
if err != nil {
299308
logger.Error(err, "failed to list crds")
300309
http.Error(w, "internal error", http.StatusInternalServerError)
301310
return
302311
}
303-
sort.SliceStable(crds, func(i, j int) bool {
304-
return crds[i].Name < crds[j].Name
312+
sort.SliceStable(crds.Items, func(i, j int) bool {
313+
return crds.Items[i].Name < crds.Items[j].Name
305314
})
306315
rightScopedCRDs := []*apiextensionsv1.CustomResourceDefinition{}
307-
for _, crd := range crds {
316+
for _, crd := range crds.Items {
308317
if h.scope == kubebindv1alpha2.ClusterScope || crd.Spec.Scope == apiextensionsv1.NamespaceScoped {
309-
rightScopedCRDs = append(rightScopedCRDs, crd)
318+
rightScopedCRDs = append(rightScopedCRDs, &crd)
310319
}
311320
}
312321

313-
apiResourceSchemas, err := h.kubeManager.ListAPIResourceSchemas(r.Context())
322+
apiResourceSchemas, err := h.kubeManager.ListAPIResourceSchemas(r.Context(), cluster)
314323
if err != nil {
315324
logger.Error(err, "failed to get api resource schemas")
316325
http.Error(w, "internal error", http.StatusInternalServerError)
@@ -319,10 +328,12 @@ func (h *handler) handleResources(w http.ResponseWriter, r *http.Request) {
319328
bs := bytes.Buffer{}
320329
if err := resourcesTemplate.Execute(&bs, struct {
321330
SessionID string
331+
Cluster string
322332
CRDs []*apiextensionsv1.CustomResourceDefinition
323333
APIResourceSchemas []kubebindv1alpha2.APIResourceSchema
324334
}{
325335
SessionID: r.URL.Query().Get("s"),
336+
Cluster: clusterPath,
326337
CRDs: rightScopedCRDs,
327338
APIResourceSchemas: apiResourceSchemas.Items,
328339
}); err != nil {
@@ -368,7 +379,12 @@ func (h *handler) handleBind(w http.ResponseWriter, r *http.Request) {
368379

369380
group := r.URL.Query().Get("group")
370381
resource := r.URL.Query().Get("resource")
371-
kfg, err := h.kubeManager.HandleResources(r.Context(), idToken.Subject+"#"+state.ClusterID, resource, group)
382+
cluster := mux.Vars(r)["cluster"]
383+
if cluster == "-" {
384+
cluster = ""
385+
}
386+
387+
kfg, err := h.kubeManager.HandleResources(r.Context(), idToken.Subject+"#"+state.ClusterID, cluster, resource, group)
372388
if err != nil {
373389
logger.Error(err, "failed to handle resources")
374390
http.Error(w, "internal error", http.StatusInternalServerError)
@@ -414,6 +430,7 @@ func (h *handler) handleBind(w http.ResponseWriter, r *http.Request) {
414430
Kubeconfig: kfg,
415431
Requests: []runtime.RawExtension{{Raw: requestBytes}},
416432
}
433+
417434
payload, err := json.Marshal(&response)
418435
if err != nil {
419436
logger.Error(err, "failed to marshal auth response")

contrib/example-backend/kubernetes/indexers.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package kubernetes
1818

1919
import (
2020
corev1 "k8s.io/api/core/v1"
21+
"sigs.k8s.io/controller-runtime/pkg/client"
2122

2223
"github.com/kube-bind/kube-bind/contrib/example-backend/kubernetes/resources"
2324
)
@@ -26,15 +27,15 @@ const (
2627
NamespacesByIdentity = "namespacesByIdentity"
2728
)
2829

29-
func IndexNamespacesByIdentity(obj any) ([]string, error) {
30+
func IndexNamespacesByIdentity(obj client.Object) []string {
3031
ns, ok := obj.(*corev1.Namespace)
3132
if !ok {
32-
return nil, nil
33+
return nil
3334
}
3435

3536
if id, found := ns.Annotations[resources.IdentityAnnotationKey]; found {
36-
return []string{id}, nil
37+
return []string{id}
3738
}
3839

39-
return nil, nil
40+
return nil
4041
}

0 commit comments

Comments
 (0)