From 9118869d049cebca59a24ae86c92eb877aca6509 Mon Sep 17 00:00:00 2001 From: Monis Khan Date: Sat, 18 Jul 2020 23:52:18 -0400 Subject: [PATCH 1/3] Use protobuf with built-in Kube REST APIs Signed-off-by: Monis Khan --- cmd/placeholder-name/app/app.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/cmd/placeholder-name/app/app.go b/cmd/placeholder-name/app/app.go index 5b7a5c41..028622df 100644 --- a/cmd/placeholder-name/app/app.go +++ b/cmd/placeholder-name/app/app.go @@ -22,6 +22,7 @@ import ( "golang.org/x/sync/errgroup" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/client-go/kubernetes" @@ -73,19 +74,22 @@ credential from somewhere to an internal credential to be used for authenticating to the Kubernetes API.`, RunE: func(cmd *cobra.Command, args []string) error { // Load the Kubernetes client configuration (kubeconfig), - kubeconfig, err := restclient.InClusterConfig() + kubeConfig, err := restclient.InClusterConfig() if err != nil { return fmt.Errorf("could not load in-cluster configuration: %w", err) } + // explicitly use protobuf when talking to built-in kube APIs + protoKubeConfig := createProtoKubeConfig(kubeConfig) + // Connect to the core Kubernetes API. - k8s, err := kubernetes.NewForConfig(kubeconfig) + k8s, err := kubernetes.NewForConfig(protoKubeConfig) if err != nil { return fmt.Errorf("could not initialize Kubernetes client: %w", err) } // Connect to the Kubernetes aggregation API. - aggregation, err := aggregationv1client.NewForConfig(kubeconfig) + aggregation, err := aggregationv1client.NewForConfig(protoKubeConfig) if err != nil { return fmt.Errorf("could not initialize Kubernetes client: %w", err) } @@ -259,3 +263,13 @@ func runGracefully(ctx context.Context, srv *http.Server, eg *errgroup.Group, f defer cancel() return srv.Shutdown(shutdownCtx) } + +// createProtoKubeConfig returns a copy of the input config with the ContentConfig set to use protobuf. +// do not use this config to communicate with any CRD based APIs. +func createProtoKubeConfig(kubeConfig *restclient.Config) *restclient.Config { + protoKubeConfig := restclient.CopyConfig(kubeConfig) + const protoThenJSON = runtime.ContentTypeProtobuf + "," + runtime.ContentTypeJSON + protoKubeConfig.AcceptContentTypes = protoThenJSON + protoKubeConfig.ContentType = runtime.ContentTypeProtobuf + return protoKubeConfig +} From 5fa5b9a9a99769c15e589cc06589798e38cb3370 Mon Sep 17 00:00:00 2001 From: Monis Khan Date: Sat, 18 Jul 2020 23:57:00 -0400 Subject: [PATCH 2/3] Do not hard code API version Signed-off-by: Monis Khan --- cmd/placeholder-name/app/app.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/placeholder-name/app/app.go b/cmd/placeholder-name/app/app.go index 028622df..cdc45d35 100644 --- a/cmd/placeholder-name/app/app.go +++ b/cmd/placeholder-name/app/app.go @@ -31,7 +31,7 @@ import ( apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" aggregationv1client "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - "github.com/suzerain-io/placeholder-name-api/pkg/apis/placeholder" + placeholderv1alpha1 "github.com/suzerain-io/placeholder-name-api/pkg/apis/placeholder/v1alpha1" "github.com/suzerain-io/placeholder-name/internal/autoregistration" "github.com/suzerain-io/placeholder-name/internal/certauthority" "github.com/suzerain-io/placeholder-name/internal/downward" @@ -182,11 +182,11 @@ func (a *App) serve(ctx context.Context, k8s corev1client.CoreV1Interface, aggre } apiService := apiregistrationv1.APIService{ ObjectMeta: metav1.ObjectMeta{ - Name: "v1alpha1." + placeholder.GroupName, + Name: placeholderv1alpha1.SchemeGroupVersion.Version + "." + placeholderv1alpha1.GroupName, }, Spec: apiregistrationv1.APIServiceSpec{ - Group: placeholder.GroupName, - Version: "v1alpha1", + Group: placeholderv1alpha1.GroupName, + Version: placeholderv1alpha1.SchemeGroupVersion.Version, CABundle: caBundle, GroupPriorityMinimum: 2500, VersionPriority: 10, From b638bd7eeb96d4b0b4e2dc758af7ec846248b812 Mon Sep 17 00:00:00 2001 From: Monis Khan Date: Sun, 19 Jul 2020 01:25:02 -0400 Subject: [PATCH 3/3] Describe why/how we recover type meta using scheme Signed-off-by: Monis Khan --- internal/autoregistration/autoregistration.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/autoregistration/autoregistration.go b/internal/autoregistration/autoregistration.go index 28f2d3e2..63108f7c 100644 --- a/internal/autoregistration/autoregistration.go +++ b/internal/autoregistration/autoregistration.go @@ -41,8 +41,16 @@ func Setup(ctx context.Context, options SetupOptions) error { return fmt.Errorf("could not get namespace: %w", err) } - // Clayton ... 😒 + // runtime.WithoutVersionDecoder clears the GVK set on the namespace because Clayton ... 😒 // https://github.com/kubernetes/kubernetes/pull/26251/files#diff-71b26e1e133ec6d3c4da26366b6502acR360-R361 + // I think this is legacy cruft from the internal rest clients combined with using the same codec + // in places where implicit conversion occurs from some external version to an internal or different external version + // i.e. the type meta we saw on the wire may not match the type meta of the struct in all cases + // however, in our case, we know that we directly called the rest API at a particular version and that no conversion occurred + // thus we know that the type meta we saw on the wire directly matches the struct that we are using + // said in a different way, we know that our GVR to GVK (and vice versa) mapping is 1:1 + // this means we can recover the type meta by asking the Kube client-go scheme for it + // the below code will only error if some generated Kube client-go code is broken gvks, _, err := scheme.Scheme.ObjectKinds(ns) if err != nil || len(gvks) == 0 { return fmt.Errorf("could not get GVK: %w", err)