From b82d9ce352528a8343aabfbf3bdc828c0bf057e3 Mon Sep 17 00:00:00 2001 From: Tanvir Tatla Date: Thu, 21 Mar 2024 13:40:24 -0700 Subject: [PATCH] use unstructured --- pkg/clustermanager/eksa_mover.go | 37 +++++-------- pkg/clustermanager/eksa_mover_test.go | 76 +++++++++++++-------------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/pkg/clustermanager/eksa_mover.go b/pkg/clustermanager/eksa_mover.go index 2e9754964ba00..f2a72f66bb944 100644 --- a/pkg/clustermanager/eksa_mover.go +++ b/pkg/clustermanager/eksa_mover.go @@ -8,12 +8,12 @@ import ( "github.com/go-logr/logr" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "github.com/aws/eks-anywhere/pkg/api/v1alpha1" "github.com/aws/eks-anywhere/pkg/clients/kubernetes" "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/retrier" - "github.com/aws/eks-anywhere/pkg/types" ) // MoverOpt allows to customize a Mover on construction. @@ -71,40 +71,29 @@ func WithMoverRetryBackOff(backOff time.Duration) MoverOpt { } // Move applies the cluster's namespace and spec without checking for reconcile conditions. -func (m *Mover) Move(ctx context.Context, spec *cluster.Spec, fromCluster, toCluster *types.Cluster) error { +func (m *Mover) Move(ctx context.Context, spec *cluster.Spec, fromClient, toClient kubernetes.Client) error { m.log.V(3).Info("Moving the cluster object") err := retrier.New( m.moveClusterTimeout, retrier.WithRetryPolicy(retrier.BackOffPolicy(m.retryBackOff)), ).Retry(func() error { - var err error - fromClient, err := m.clientFactory.BuildClientFromKubeconfig(fromCluster.KubeconfigFile) - if err != nil { - return errors.Wrap(err, "building client to read cluster objects") - } - - toClient, err := m.clientFactory.BuildClientFromKubeconfig(toCluster.KubeconfigFile) - if err != nil { - return errors.Wrap(err, "building client to move cluster objects") - } - // read the cluster from bootstrap cluster := &v1alpha1.Cluster{} if err := fromClient.Get(ctx, spec.Cluster.Name, spec.Cluster.Namespace, cluster); err != nil { - return errors.Wrapf(err, "getting cluster from %s", fromCluster.Name) + return errors.Wrapf(err, "reading cluster from source") } // pause cluster on bootstrap cluster.PauseReconcile() if err := fromClient.Update(ctx, cluster); err != nil { - return errors.Wrapf(err, "updating cluster on %s", fromCluster.Name) + return errors.Wrapf(err, "updating cluster on source") } if err := moveClusterResource(ctx, cluster, toClient); err != nil { return err } - if err := moveChildObjects(ctx, *spec, fromClient, toClient); err != nil { + if err := moveChildObjects(ctx, spec, fromClient, toClient); err != nil { return err } @@ -126,19 +115,21 @@ func moveClusterResource(ctx context.Context, cluster *v1alpha1.Cluster, client return nil } -func moveChildObjects(ctx context.Context, spec cluster.Spec, fromClient, toClient kubernetes.Client) error { +func moveChildObjects(ctx context.Context, spec *cluster.Spec, fromClient, toClient kubernetes.Client) error { // read and move child objects for _, child := range spec.ChildObjects() { - if err := fromClient.Get(ctx, child.GetName(), child.GetNamespace(), child); err != nil { + obj := &unstructured.Unstructured{} + obj.SetGroupVersionKind(child.GetObjectKind().GroupVersionKind()) + if err := fromClient.Get(ctx, child.GetName(), child.GetNamespace(), obj); err != nil { return errors.Wrapf(err, "reading child object %s %s", child.GetObjectKind().GroupVersionKind().Kind, child.GetName()) } - child.SetResourceVersion("") - child.SetUID("") - child.SetOwnerReferences(nil) + obj.SetResourceVersion("") + obj.SetUID("") + obj.SetOwnerReferences(nil) - if err := toClient.Create(ctx, child); err != nil && !apierrors.IsAlreadyExists(err) { - return errors.Wrapf(err, "moving child object %s %s", child.GetObjectKind().GroupVersionKind().Kind, child.GetName()) + if err := toClient.Create(ctx, obj); err != nil && !apierrors.IsAlreadyExists(err) { + return errors.Wrapf(err, "moving child object %s %s", obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName()) } } diff --git a/pkg/clustermanager/eksa_mover_test.go b/pkg/clustermanager/eksa_mover_test.go index 3beb8d62185c6..97b7823cfc1a4 100644 --- a/pkg/clustermanager/eksa_mover_test.go +++ b/pkg/clustermanager/eksa_mover_test.go @@ -2,13 +2,14 @@ package clustermanager_test import ( "context" - "fmt" "testing" "time" "github.com/go-logr/logr" "github.com/golang/mock/gomock" "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "github.com/aws/eks-anywhere/internal/test" "github.com/aws/eks-anywhere/pkg/clients/kubernetes" @@ -50,81 +51,76 @@ func newMoverTest(tb testing.TB) *moverTest { } } -func (a *moverTest) buildClient(err1, err2 error, objs ...kubernetes.Object) { - a.fromClient = test.NewFakeKubeClient(clientutil.ObjectsToClientObjects(objs)...) - a.toClient = test.NewFakeKubeClient() - a.clientFactory.EXPECT().BuildClientFromKubeconfig(a.bootstrap.KubeconfigFile).Return(a.fromClient, err1).MaxTimes(1) - a.clientFactory.EXPECT().BuildClientFromKubeconfig(a.mgmtCluster.KubeconfigFile).Return(a.toClient, err2).MaxTimes(1) -} - -func (a *moverTest) expectClientError() { - a.fromClient = test.NewFakeKubeClientAlwaysError() - a.clientFactory.EXPECT().BuildClientFromKubeconfig(a.bootstrap.KubeconfigFile).Return(a.fromClient, nil) - a.toClient = test.NewFakeKubeClientAlwaysError() - a.clientFactory.EXPECT().BuildClientFromKubeconfig(a.mgmtCluster.KubeconfigFile).Return(a.toClient, nil) +func (a *moverTest) buildClients(fromObjs, toObjs []kubernetes.Object) { + a.fromClient = test.NewFakeKubeClient(clientutil.ObjectsToClientObjects(fromObjs)...) + a.toClient = test.NewFakeKubeClient(clientutil.ObjectsToClientObjects(toObjs)...) } func TestMoverSuccess(t *testing.T) { tt := newMoverTest(t) objs := tt.spec.ClusterAndChildren() - tt.buildClient(nil, nil, objs...) + tt.buildClients(objs, nil) m := clustermanager.NewMover(tt.log, tt.clientFactory, clustermanager.WithMoverRetryBackOff(time.Millisecond), clustermanager.WithMoverNoTimeouts(), ) - tt.Expect(m.Move(tt.ctx, tt.spec, tt.bootstrap, tt.mgmtCluster)).To(gomega.Succeed()) + tt.Expect(m.Move(tt.ctx, tt.spec, tt.fromClient, tt.toClient)).To(gomega.Succeed()) for _, obj := range objs { - tt.Expect(tt.toClient.Get(tt.ctx, obj.GetName(), obj.GetNamespace(), obj)).To(gomega.Succeed()) + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) + tt.Expect(tt.toClient.Get(tt.ctx, obj.GetName(), obj.GetNamespace(), u)).To(gomega.Succeed()) + original, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + tt.Expect(err).To(gomega.Succeed()) + tt.Expect(u.Object["spec"]).To(gomega.Equal(original["spec"])) } } -func TestMoverFailBuildFromClient(t *testing.T) { +func TestMoverFailReadCluster(t *testing.T) { tt := newMoverTest(t) - tt.buildClient(fmt.Errorf(""), nil) + tt.buildClients(nil, nil) m := clustermanager.NewMover(tt.log, tt.clientFactory, clustermanager.WithMoverRetryBackOff(time.Millisecond), clustermanager.WithMoverApplyClusterTimeout(time.Millisecond), ) - err := m.Move(tt.ctx, tt.spec, tt.bootstrap, tt.mgmtCluster) + err := m.Move(tt.ctx, tt.spec, tt.fromClient, tt.toClient) - tt.Expect(err).To(gomega.HaveOccurred()) + tt.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("reading cluster from source"))) } -func TestMoverFailBuildToClient(t *testing.T) { +func TestMoverFailGetChildren(t *testing.T) { tt := newMoverTest(t) - tt.buildClient(nil, fmt.Errorf("")) + objs := []kubernetes.Object{tt.spec.Cluster} + tt.buildClients(objs, nil) m := clustermanager.NewMover(tt.log, tt.clientFactory, clustermanager.WithMoverRetryBackOff(time.Millisecond), clustermanager.WithMoverApplyClusterTimeout(time.Millisecond), ) - err := m.Move(tt.ctx, tt.spec, tt.bootstrap, tt.mgmtCluster) - tt.Expect(err).To(gomega.HaveOccurred()) + err := m.Move(tt.ctx, tt.spec, tt.fromClient, tt.toClient) + tt.Expect(err).To(gomega.MatchError(gomega.ContainSubstring("reading child object"))) } -func TestMoverFailCreateNamespace(t *testing.T) { +func TestMoverAlreadyMoved(t *testing.T) { tt := newMoverTest(t) - tt.expectClientError() + objs := tt.spec.ClusterAndChildren() + tt.buildClients(objs, objs) m := clustermanager.NewMover(tt.log, tt.clientFactory, clustermanager.WithMoverRetryBackOff(time.Millisecond), clustermanager.WithMoverApplyClusterTimeout(time.Millisecond), ) - err := m.Move(tt.ctx, tt.spec, tt.bootstrap, tt.mgmtCluster) - - tt.Expect(err).To(gomega.HaveOccurred()) -} -func TestMoverFailGetChildren(t *testing.T) { - tt := newMoverTest(t) - objs := []kubernetes.Object{tt.spec.Cluster} - tt.buildClient(nil, nil, objs...) - m := clustermanager.NewMover(tt.log, tt.clientFactory, - clustermanager.WithMoverRetryBackOff(time.Millisecond), - clustermanager.WithMoverApplyClusterTimeout(time.Millisecond), - ) + err := m.Move(tt.ctx, tt.spec, tt.fromClient, tt.toClient) + tt.Expect(err).To(gomega.Succeed()) - err := m.Move(tt.ctx, tt.spec, tt.bootstrap, tt.mgmtCluster) - tt.Expect(err).To(gomega.HaveOccurred()) + for _, obj := range objs { + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(obj.GetObjectKind().GroupVersionKind()) + tt.Expect(tt.toClient.Get(tt.ctx, obj.GetName(), obj.GetNamespace(), u)).To(gomega.Succeed()) + original, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + tt.Expect(err).To(gomega.Succeed()) + // the entire object including metadata/status should be equal if the object already exists in dst + tt.Expect(u.Object).To(gomega.Equal(original)) + } }