Skip to content

Commit

Permalink
Fix ApiVersion overwrite during conversion
Browse files Browse the repository at this point in the history
During conversion webhook handler controller-runtime sets desire meta api version of the
destination resource from the Kubernetes API server request. Round trip marshall and unmarshall
is overwriting metadata.

Reference

https://github.com/kubernetes-sigs/controller-runtime/blob/f4ca78ebc00a4717ecd1c2daea1874d69ddd0137/pkg/webhook/conversion/conversion.go#L101
  • Loading branch information
RafalKorepta committed May 17, 2024
1 parent b4809a1 commit 20ffaec
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/go/k8s/api/redpanda/v1alpha1/redpanda_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package v1alpha1
import (
"encoding/json"
"fmt"
"k8s.io/apimachinery/pkg/api/meta"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/conversion"
Expand All @@ -32,6 +33,15 @@ func (r *Redpanda) SetupWebhookWithManager(mgr ctrl.Manager) error {
func (src *Redpanda) ConvertTo(dstRaw conversion.Hub) error { // nolint:stylecheck // `src` as a received helps with readability
dst := dstRaw.(*v1alpha2.Redpanda)

// controller-runtime respects desired api version and kind from the
// Kubernetes API server and set it in destination resource
// https://github.com/kubernetes-sigs/controller-runtime/blob/f4ca78ebc00a4717ecd1c2daea1874d69ddd0137/pkg/webhook/conversion/conversion.go#L101
//
// By using round trip json marshall/unmarshall the TypeMeta is being
// overwritten. The desiredAPIVersion is saved for later rollback.
t, err := meta.TypeAccessor(dst)
desiredAPIVersion := t.GetAPIVersion()

b, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("marshaling %T: %w", Redpanda{}, err)
Expand All @@ -41,13 +51,24 @@ func (src *Redpanda) ConvertTo(dstRaw conversion.Hub) error { // nolint:styleche
return fmt.Errorf("unmarshaling %T: %w", v1alpha2.Redpanda{}, err)
}

t.SetAPIVersion(desiredAPIVersion)

return nil
}

// ConvertFrom converts from the Hub version (v1) to this version.
func (dst *Redpanda) ConvertFrom(srcRaw conversion.Hub) error { // nolint:stylecheck // `dst` as a received helps with readability
src := srcRaw.(*v1alpha2.Redpanda)

// controller-runtime respects desired api version and kind from the
// Kubernetes API server and set it in destination resource
// https://github.com/kubernetes-sigs/controller-runtime/blob/f4ca78ebc00a4717ecd1c2daea1874d69ddd0137/pkg/webhook/conversion/conversion.go#L101
//
// By using round trip json marshall/unmarshall the TypeMeta is being
// overwritten. The desiredAPIVersion is saved for later rollback.
t, err := meta.TypeAccessor(dst)
desiredAPIVersion := t.GetAPIVersion()

b, err := json.Marshal(src)
if err != nil {
return fmt.Errorf("marshaling %T: %w", v1alpha2.Redpanda{}, err)
Expand All @@ -56,5 +77,8 @@ func (dst *Redpanda) ConvertFrom(srcRaw conversion.Hub) error { // nolint:stylec
if err = json.Unmarshal(b, dst); err != nil {
return fmt.Errorf("unmarshaling %T: %w", Redpanda{}, err)
}

t.SetAPIVersion(desiredAPIVersion)

return nil
}
8 changes: 8 additions & 0 deletions src/go/k8s/api/redpanda/v1alpha1/redpanda_conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package v1alpha1_test
import (
"encoding/json"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"regexp"
"strings"
"testing"
Expand Down Expand Up @@ -219,5 +220,12 @@ func CRDFuzzer() *fuzz.Fuzzer {
func(q *resource.Quantity, c fuzz.Continue) { // nolint:ineffassign,staticcheck // Fuzzing is weird, we're assigning to a pointer to pass the value out.
q = resource.NewQuantity(c.Int63(), resource.DecimalSI)
},
// TypeMeta is special case where ApiVersion needs to be empty. In the real webhook handler the apiVersion will be set
// by controller runtime.
func(typeMeta *metav1.TypeMeta, c fuzz.Continue) {
typeMeta = &metav1.TypeMeta{
Kind: c.RandString(),
}
},
).SkipFieldsWithPattern(regexp.MustCompile("Console|Config|Connectors|FieldsV1"))
}

0 comments on commit 20ffaec

Please sign in to comment.