Skip to content

Commit

Permalink
Reconcile CNI for Tinkerbell provider (aws#4774)
Browse files Browse the repository at this point in the history
  • Loading branch information
taneyland committed Jan 30, 2023
1 parent 2450b3e commit e29fc2e
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 15 deletions.
4 changes: 4 additions & 0 deletions controllers/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,13 +308,17 @@ func (f *Factory) withSnowClusterReconciler() *Factory {
}

func (f *Factory) withTinkerbellClusterReconciler() *Factory {
f.withCNIReconciler().withTracker()

f.buildSteps = append(f.buildSteps, func(ctx context.Context) error {
if f.tinkerbellClusterReconciler != nil {
return nil
}

f.tinkerbellClusterReconciler = tinkerbellreconciler.New(
f.manager.GetClient(),
f.cniReconciler,
f.tracker,
f.ipValidator,
)
f.registryBuilder.Add(anywherev1.TinkerbellDatacenterKind, f.tinkerbellClusterReconciler)
Expand Down
77 changes: 77 additions & 0 deletions pkg/providers/tinkerbell/reconciler/mocks/reconciler.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 27 additions & 7 deletions pkg/providers/tinkerbell/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,36 @@ import (
"github.com/aws/eks-anywhere/pkg/controller/clientutil"
)

// CNIReconciler is an interface for reconciling CNI in the Tinkerbell cluster reconciler.
type CNIReconciler interface {
Reconcile(ctx context.Context, logger logr.Logger, client client.Client, spec *c.Spec) (controller.Result, error)
}

// RemoteClientRegistry is an interface that defines methods for remote clients.
type RemoteClientRegistry interface {
GetClient(ctx context.Context, cluster client.ObjectKey) (client.Client, error)
}

// IPValidator is an interface that defines methods to validate the control plane IP.
type IPValidator interface {
ValidateControlPlaneIP(ctx context.Context, log logr.Logger, spec *c.Spec) (controller.Result, error)
}

// Reconciler for Tinkerbell.
type Reconciler struct {
client client.Client
ipValidator IPValidator
client client.Client
cniReconciler CNIReconciler
remoteClientRegistry RemoteClientRegistry
ipValidator IPValidator
}

// New defines a new Tinkerbell reconciler.
func New(client client.Client, ipValidator IPValidator) *Reconciler {
func New(client client.Client, cniReconciler CNIReconciler, remoteClientRegistry RemoteClientRegistry, ipValidator IPValidator) *Reconciler {
return &Reconciler{
client: client,
ipValidator: ipValidator,
client: client,
cniReconciler: cniReconciler,
remoteClientRegistry: remoteClientRegistry,
ipValidator: ipValidator,
}
}

Expand All @@ -45,6 +59,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, log logr.Logger, cluster *an

return controller.NewPhaseRunner().Register(
r.ipValidator.ValidateControlPlaneIP,
r.ReconcileCNI,
).Run(ctx, log, clusterSpec)
}

Expand All @@ -65,7 +80,12 @@ func (r *Reconciler) ReconcileWorkerNodes(ctx context.Context, log logr.Logger,

// ReconcileCNI reconciles the CNI to the desired state.
func (r *Reconciler) ReconcileCNI(ctx context.Context, log logr.Logger, clusterSpec *c.Spec) (controller.Result, error) {
// Implement reconcile CNI here
log = log.WithValues("phase", "reconcileCNI")

return controller.Result{}, nil
client, err := r.remoteClientRegistry.GetClient(ctx, controller.CapiClusterObjectKey(clusterSpec.Cluster))
if err != nil {
return controller.Result{}, err
}

return r.cniReconciler.Reconcile(ctx, log, client, clusterSpec)
}
71 changes: 63 additions & 8 deletions pkg/providers/tinkerbell/reconciler/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package reconciler_test

import (
"context"
"errors"
"testing"

"github.com/golang/mock/gomock"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"

"github.com/aws/eks-anywhere/internal/test"
"github.com/aws/eks-anywhere/internal/test/envtest"
Expand Down Expand Up @@ -36,17 +38,65 @@ func TestReconcilerReconcileSuccess(t *testing.T) {
tt.createAllObjs()

logger := test.NewNullLogger()
remoteClient := env.Client()

tt.ipValidator.EXPECT().ValidateControlPlaneIP(tt.ctx, logger, tt.buildSpec()).Return(controller.Result{}, nil)

tt.remoteClientRegistry.EXPECT().GetClient(
tt.ctx, client.ObjectKey{Name: "workload-cluster", Namespace: "eksa-system"},
).Return(remoteClient, nil)
tt.cniReconciler.EXPECT().Reconcile(tt.ctx, logger, remoteClient, tt.buildSpec())

result, err := tt.reconciler().Reconcile(tt.ctx, logger, tt.cluster)

tt.Expect(err).NotTo(HaveOccurred())
tt.Expect(result).To(Equal(controller.Result{}))
}

func TestReconcileCNISuccess(t *testing.T) {
tt := newReconcilerTest(t)
tt.withFakeClient()

logger := test.NewNullLogger()
remoteClient := fake.NewClientBuilder().Build()
spec := tt.buildSpec()

tt.remoteClientRegistry.EXPECT().GetClient(
tt.ctx, client.ObjectKey{Name: "workload-cluster", Namespace: "eksa-system"},
).Return(remoteClient, nil)
tt.cniReconciler.EXPECT().Reconcile(tt.ctx, logger, remoteClient, spec)

result, err := tt.reconciler().ReconcileCNI(tt.ctx, logger, spec)

tt.Expect(err).NotTo(HaveOccurred())
tt.Expect(tt.cluster.Status.FailureMessage).To(BeZero())
tt.Expect(result).To(Equal(controller.Result{}))
}

func TestReconcileCNIErrorClientRegistry(t *testing.T) {
tt := newReconcilerTest(t)
tt.withFakeClient()

logger := test.NewNullLogger()
spec := tt.buildSpec()

tt.remoteClientRegistry.EXPECT().GetClient(
tt.ctx, client.ObjectKey{Name: "workload-cluster", Namespace: "eksa-system"},
).Return(nil, errors.New("building client"))

result, err := tt.reconciler().ReconcileCNI(tt.ctx, logger, spec)

tt.Expect(err).To(MatchError(ContainSubstring("building client")))
tt.Expect(tt.cluster.Status.FailureMessage).To(BeZero())
tt.Expect(result).To(Equal(controller.Result{}))
}

func (tt *reconcilerTest) withFakeClient() {
tt.client = fake.NewClientBuilder().WithObjects(clientutil.ObjectsToClientObjects(tt.allObjs())...).Build()
}

func (tt *reconcilerTest) reconciler() *reconciler.Reconciler {
return reconciler.New(tt.client, tt.ipValidator)
return reconciler.New(tt.client, tt.cniReconciler, tt.remoteClientRegistry, tt.ipValidator)
}

func (tt *reconcilerTest) buildSpec() *clusterspec.Spec {
Expand Down Expand Up @@ -82,12 +132,16 @@ type reconcilerTest struct {
machineConfigControlPlane *anywherev1.TinkerbellMachineConfig
machineConfigWorker *anywherev1.TinkerbellMachineConfig
ipValidator *tinkerbellreconcilermocks.MockIPValidator
cniReconciler *tinkerbellreconcilermocks.MockCNIReconciler
remoteClientRegistry *tinkerbellreconcilermocks.MockRemoteClientRegistry
}

func newReconcilerTest(t testing.TB) *reconcilerTest {
ctrl := gomock.NewController(t)
c := env.Client()

cniReconciler := tinkerbellreconcilermocks.NewMockCNIReconciler(ctrl)
remoteClientRegistry := tinkerbellreconcilermocks.NewMockRemoteClientRegistry(ctrl)
ipValidator := tinkerbellreconcilermocks.NewMockIPValidator(ctrl)

bundle := test.Bundle()
Expand Down Expand Up @@ -152,13 +206,14 @@ func newReconcilerTest(t testing.TB) *reconcilerTest {
})

tt := &reconcilerTest{
t: t,
WithT: NewWithT(t),
APIExpecter: envtest.NewAPIExpecter(t, c),
ctx: context.Background(),
ipValidator: ipValidator,

client: c,
t: t,
WithT: NewWithT(t),
APIExpecter: envtest.NewAPIExpecter(t, c),
ctx: context.Background(),
ipValidator: ipValidator,
cniReconciler: cniReconciler,
remoteClientRegistry: remoteClientRegistry,
client: c,
eksaSupportObjs: []client.Object{
test.Namespace(clusterNamespace),
test.Namespace(constants.EksaSystemNamespace),
Expand Down

0 comments on commit e29fc2e

Please sign in to comment.