Skip to content
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

Kcp hacking #1

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open

Kcp hacking #1

wants to merge 38 commits into from

Conversation

fabianvf
Copy link
Owner

@fabianvf fabianvf commented Feb 2, 2022

No description provided.

@@ -112,6 +112,9 @@ type Options struct {
// Default watches all namespaces
Namespace string

// ClusterName restricts cache's ListeWatch to the desired clusterscope
ClusterName string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove


import "k8s.io/client-go/rest"

func MultiClusterMinCache() NewCacheFunc {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can either remove and require user to pass in a rest config that is * scoped, or move to kcp-dev/apimachinery

@@ -60,6 +60,9 @@ type Options struct {
// Opts is used to configure the warning handler responsible for
// surfacing and handling warnings messages sent by the API server.
Opts WarningHandlerOptions

// Cluster refers to the name of the cluster this request is scoped to
Cluster string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably remove this

@@ -330,6 +330,9 @@ type ListOptions struct {
// non-namespaced objects, or to list across all namespaces.
Namespace string

// ClusterName refers to cluster from which to list objects
ClusterName string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

createOpts := &CreateOptions{}
createOpts.ApplyOptions(opts)
return o.Post().
Cluster(clusterName).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing all of this to inject the cluster name here, see if instead we can supply a custom *http.Client to some Options struct, and in pkg/client/apiutil/apimachinery.go near RESTClientForGVK, add a new method that is RESTClientForGVKAndClient. That way we can plumb through the kcp custom round tripper.

createOpts := &CreateOptions{}
createOpts.ApplyOptions(opts)
result := o.Post().
Cluster(clusterName).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as typed_client

@@ -33,10 +33,14 @@ func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
if err != nil {
return nil, err
}
dynamicClient, err := dynamic.NewForConfig(config)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undo?

if err != nil {
return nil, err
}

return &watchingClient{client: client, dynamic: dynamicClient}, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to see what, if any, adjustments need to be made to work with * or cluster-specific watches.

@@ -41,25 +42,16 @@ func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.Rate
enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
return
}
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe write our own cluster-aware handlers in a separate kcp repo

@ncdc
Copy link
Collaborator

ncdc commented May 19, 2022

Additional ideas from our chat:

  • Create a separate kcp-controller-runtime repo (not a fork) that has a ClusterManager, ClusterClient, ClusterCacheReader, and copies of all the enqueuing handlers
  • Need to modify client.ObjectKey and/or types.NamespacedName (in kube apimachinery) to add ClusterName (maybe logicalcluster.Name, maybe string)

@ncdc
Copy link
Collaborator

ncdc commented May 19, 2022

Long term, if we want controller-runtime to work with kcp w/o any go.mod replace directives, controller-runtime will need

  • to account for clusterName in client.ObjectKey in some way. Could be by changing it to an extensible interface, or switching away from NamespacedName to a controller-runtime struct/interface.
  • to modify all code that uses an indexer directly to make sure it supports customization. Although if we write our own ClusterCacheReader, this could be kept outside (but it does mean we need to keep the impls in sync).
  • informer_cache.go does some indexing by field. Need to make sure that supports clusters, or raise it up to our separate kcp-controller-runtime repo maybe

@fabianvf
Copy link
Owner Author

fabianvf commented May 23, 2022

Edit: Ignore literally everything I say here

Extending ObjectKey in a non-breaking way is proving to be pretty difficult due to the way embedded structs work, currently the usage/behavior is:

type ObjectKey = types.NamespaceName

ObjectKey{NamespacedName: types.NamespacedName{Name: "name", Namespace: "namespace"}

ObjectKey.Name  == "name"
ObjectKey.Namespace == "namespace"

If I try to extend it in any way, I don't think it's possible to replicate that behavior. Ex:

type Object struct {
  types.NamespaceName
  AdditionalIdentifer string
}

ObjectKey{NamespacedName: types.NamespacedName{Name: "name", Namespace: "namespace"}

ObjectKey.Name  == "name" // cannot use promoted field Name
ObjectKey.Namespace == "namespace" // cannot use promoted field Namespace
type Object struct {
  Name string
  Namespace string

  AdditionalIdentifer string
}

// Invalid construction, no NamespacedName field
ObjectKey{NamespacedName: types.NamespacedName{Name: "name", Namespace: "namespace"}
type Object struct {
  NamespacedName: types.NamespacedName

  AdditionalIdentifer string
}

ObjectKey{NamespacedName: types.NamespacedName{Name: "name", Namespace: "namespace"}

ObjectKey.Name  // doesn't exist
ObjectKey.Namespace // doesn't exist
type Object struct {
  NamespacedName: types.NamespacedName
  Name string
  Namespace string

  AdditionalIdentifer string
}

ObjectKey{NamespacedName: types.NamespacedName{Name: "name", Namespace: "namespace"}

ObjectKey.Name  // empty
ObjectKey.Namespace // empty

Obviously incredibly easy to work around if we don't care about breaking changes but might make it hard to move this upstream as that's a pretty far-reaching change

ctrl.SetLogger(zap.New())

cfg := ctrl.GetConfigOrDie()
httpClient, err := rest.HTTPClientFor(cfg)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably make a helper for this, like kcpclient.NewClientForConfig(cfg) that gives you an http.Client with the transport set.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

ctrl.SetLogger(zap.New())

cfg := ctrl.GetConfigOrDie()
httpClient, err := rest.HTTPClientFor(cfg)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

httpclient, err := rest.HTTPClientFor(config)
if err != nil {
log.WithName("setup").Error(err, "Failed to create HTTP client")
return opts, fmt.Errorf("Could not create HTTPClient from config")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return opts, fmt.Errorf("Could not create HTTPClient from config")
return opts, fmt.Errorf("could not create HTTPClient from config: %w", err)

if opts.HTTPClient == nil {
httpclient, err := rest.HTTPClientFor(config)
if err != nil {
log.WithName("setup").Error(err, "Failed to create HTTP client")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we need to both log and return an error?

@@ -26,7 +26,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undo

@@ -54,7 +54,7 @@ type CacheReader struct {
}

// Get checks the indexer for the object and writes a copy of it if found.
func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object) error {
func (c *CacheReader) Get(ctx context.Context, key client.ObjectKey, out client.Object) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undo?

@@ -54,9 +55,12 @@ func newSpecificInformersMap(config *rest.Config,
namespace string,
selectors SelectorsByGVK,
disableDeepCopy DisableDeepCopyByGVK,
createListWatcher createListWatcherFunc) *specificInformersMap {
createListWatcher createListWatcherFunc,
httpclient *http.Client) *specificInformersMap {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
httpclient *http.Client) *specificInformersMap {
httpClient *http.Client) *specificInformersMap {

@@ -1,5 +1,5 @@
/*
Copyright 2018 The Kubernetes Authors.
opyright 2018 The Kubernetes Authors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undo

@@ -35,6 +36,9 @@ type clientCache struct {
// config is the rest.Config to talk to an apiserver
config *rest.Config

// httpclient is the httpClient to talk to an apiserver
httpclient *http.Client
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
httpclient *http.Client
httpClient *http.Client

@@ -35,6 +36,9 @@ type clientCache struct {
// config is the rest.Config to talk to an apiserver
config *rest.Config

// httpclient is the httpClient to talk to an apiserver
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// httpclient is the httpClient to talk to an apiserver
// httpClient is the http.Client to talk to an apiserver

@@ -0,0 +1,85 @@
/*
Copyright 2018 The Kubernetes Authors.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change copyright to kcp. Do you want to keep this in controller-runtime for now, or move to a kcp-owned repo?

fabianvf and others added 3 commits May 25, 2022 13:18
Signed-off-by: Andy Goldstein <andy.goldstein@redhat.com>
fabianvf pushed a commit that referenced this pull request May 25, 2022
Controller-runtime allows building kcp-aware controllers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants