diff --git a/pkg/apiserver/rest/dualwriter_mode1.go b/pkg/apiserver/rest/dualwriter_mode1.go index e153cfb95b4..58dd0e0aede 100644 --- a/pkg/apiserver/rest/dualwriter_mode1.go +++ b/pkg/apiserver/rest/dualwriter_mode1.go @@ -32,3 +32,8 @@ func (d *DualWriterMode1) Create(ctx context.Context, obj runtime.Object, create return legacy.Create(ctx, obj, createValidation, options) } + +// Get overrides the default behavior of the DualWriter and reads only to LegacyStorage. +func (d *DualWriterMode1) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return d.Legacy.Get(ctx, name, options) +} diff --git a/pkg/apiserver/rest/dualwriter_mode2.go b/pkg/apiserver/rest/dualwriter_mode2.go index 151c22a7f3c..ecbce6b7589 100644 --- a/pkg/apiserver/rest/dualwriter_mode2.go +++ b/pkg/apiserver/rest/dualwriter_mode2.go @@ -80,3 +80,8 @@ func enrichObject(orig, copy runtime.Object) (runtime.Object, error) { return copy, nil } + +// Get overrides the default behavior of the Storage and retrieves an object from LegacyStorage +func (d *DualWriterMode2) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return d.Legacy.Get(ctx, name, &metav1.GetOptions{}) +} diff --git a/pkg/apiserver/rest/dualwriter_mode3.go b/pkg/apiserver/rest/dualwriter_mode3.go index a6ea69b85f7..517ea89d09b 100644 --- a/pkg/apiserver/rest/dualwriter_mode3.go +++ b/pkg/apiserver/rest/dualwriter_mode3.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/registry/rest" @@ -38,3 +39,24 @@ func (d *DualWriterMode3) Create(ctx context.Context, obj runtime.Object, create } return created, nil } + +// Get overrides the default behavior of the Storage and retrieves an object from Unified Storage +// the object is still fetched from Legacy Storage if it's not found in Unified Storage +func (d *DualWriterMode3) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + legacy, ok := d.Legacy.(rest.Getter) + if !ok { + return nil, fmt.Errorf("legacy storage rest.Getter is missing") + } + + s, err := d.Storage.Get(ctx, name, &metav1.GetOptions{}) + if err == nil { + return s, err + } + if !apierrors.IsNotFound(err) { + return nil, err + } + + klog.Info("object not found in unified storage. Getting it from legacy", "name", name) + + return legacy.Get(ctx, name, &metav1.GetOptions{}) +} diff --git a/pkg/apiserver/rest/dualwriter_mode4.go b/pkg/apiserver/rest/dualwriter_mode4.go index 3b1beb42aef..6dc4b281192 100644 --- a/pkg/apiserver/rest/dualwriter_mode4.go +++ b/pkg/apiserver/rest/dualwriter_mode4.go @@ -23,3 +23,8 @@ func NewDualWriterMode4(legacy LegacyStorage, storage Storage) *DualWriterMode4 func (d *DualWriterMode4) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { return d.Storage.Create(ctx, obj, createValidation, options) } + +// Get overrides the default behavior of the Storage and retrieves an object from Unified Storage +func (d *DualWriterMode4) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return d.Storage.Get(ctx, name, &metav1.GetOptions{}) +} diff --git a/pkg/apiserver/rest/dualwriter_test.go b/pkg/apiserver/rest/dualwriter_test.go new file mode 100644 index 00000000000..f6d5a264803 --- /dev/null +++ b/pkg/apiserver/rest/dualwriter_test.go @@ -0,0 +1,75 @@ +package rest + +import ( + "context" + "testing" + + "github.com/zeebo/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const kind = "dummy" + +func Test_Mode1(t *testing.T) { + var ls = (LegacyStorage)(nil) + var s = (Storage)(nil) + lsSpy := NewLegacyStorageSpyClient(ls) + sSpy := NewStorageSpyClient(s) + + dw := NewDualWriterMode1(lsSpy, sSpy) + + _, err := dw.Get(context.Background(), kind, &metav1.GetOptions{}) + assert.NoError(t, err) + + // it should use the Legacy Get implementation + assert.Equal(t, 1, lsSpy.Counts("LegacyStorage.Get")) + assert.Equal(t, 0, sSpy.Counts("Storage.Get")) +} + +func Test_Mode2(t *testing.T) { + var ls = (LegacyStorage)(nil) + var s = (Storage)(nil) + lsSpy := NewLegacyStorageSpyClient(ls) + sSpy := NewStorageSpyClient(s) + + dw := NewDualWriterMode2(lsSpy, sSpy) + + _, err := dw.Get(context.Background(), kind, &metav1.GetOptions{}) + assert.NoError(t, err) + + // it should use the Legacy Get implementation + assert.Equal(t, 1, lsSpy.Counts("LegacyStorage.Get")) + assert.Equal(t, 0, sSpy.Counts("Storage.Get")) +} + +func Mode3_Test(t *testing.T) { + var ls = (LegacyStorage)(nil) + var s = (Storage)(nil) + lsSpy := NewLegacyStorageSpyClient(ls) + sSpy := NewStorageSpyClient(s) + + dw := NewDualWriterMode3(lsSpy, sSpy) + + _, err := dw.Get(context.Background(), kind, &metav1.GetOptions{}) + assert.NoError(t, err) + + // it should use the Unified Storage Get implementation + assert.Equal(t, 0, lsSpy.Counts("LegacyStorage.Get")) + assert.Equal(t, 1, sSpy.Counts("Storage.Get")) +} + +func Test_Mode4(t *testing.T) { + var ls = (LegacyStorage)(nil) + var s = (Storage)(nil) + lsSpy := NewLegacyStorageSpyClient(ls) + sSpy := NewStorageSpyClient(s) + + dw := NewDualWriterMode3(lsSpy, sSpy) + + _, err := dw.Get(context.Background(), kind, &metav1.GetOptions{}) + assert.NoError(t, err) + + // it should use the Unified Storage Get implementation + assert.Equal(t, 0, lsSpy.Counts("LegacyStorage.Get")) + assert.Equal(t, 1, sSpy.Counts("Storage.Get")) +}