@@ -27,7 +27,10 @@ import (
2727 "github.com/aws/eks-anywhere/pkg/controller/clientutil"
2828 "github.com/aws/eks-anywhere/pkg/controller/clusters"
2929 "github.com/aws/eks-anywhere/pkg/controller/handlers"
30+ "github.com/aws/eks-anywhere/pkg/controller/serverside"
3031 "github.com/aws/eks-anywhere/pkg/curatedpackages"
32+ "github.com/aws/eks-anywhere/pkg/features"
33+ "github.com/aws/eks-anywhere/pkg/providers/vsphere"
3134 "github.com/aws/eks-anywhere/pkg/registrymirror"
3235 "github.com/aws/eks-anywhere/pkg/utils/ptr"
3336 "github.com/aws/eks-anywhere/pkg/validations"
@@ -49,6 +52,7 @@ type ClusterReconciler struct {
4952 clusterValidator ClusterValidator
5053 packagesClient PackagesClient
5154 machineHealthCheck MachineHealthCheckReconciler
55+ vSpherefailureDomainMover FailureDomainApplier
5256}
5357
5458// PackagesClient handles curated packages operations from within the cluster
@@ -83,15 +87,93 @@ type ClusterValidator interface {
8387// ClusterReconcilerOption allows to configure the ClusterReconciler.
8488type ClusterReconcilerOption func (* ClusterReconciler )
8589
90+ // SpecBuilder builds a cluster specification from an EKS Anywhere Cluster object.
91+ type SpecBuilder interface {
92+ BuildSpec (ctx context.Context , eksaCluster * anywherev1.Cluster ) (* c.Spec , error )
93+ }
94+
95+ // FailureDomainSpecBuilder transforms a cluster specification into VSphere-specific failure domains.
96+ type FailureDomainSpecBuilder interface {
97+ BuildFailureDomainSpec (log logr.Logger , clusterSpec * c.Spec ) (* vsphere.FailureDomains , error )
98+ }
99+
100+ // ObjectReconciler applies failure domain objects to a Kubernetes cluster.
101+ type ObjectReconciler interface {
102+ ReconcileObjects (ctx context.Context , fd * vsphere.FailureDomains ) error
103+ }
104+
105+ // FailureDomainApplier orchestrates the end-to-end process of applying failure domains to a cluster.
106+ type FailureDomainApplier interface {
107+ ApplyFailureDomains (ctx context.Context , log logr.Logger , cluster * anywherev1.Cluster ) error
108+ }
109+
110+ // DefaultSpecBuilder is the standard implementation of SpecBuilder that uses a Kubernetes client.
111+ type DefaultSpecBuilder struct {
112+ client client.Client
113+ }
114+
115+ // BuildSpec is a wrapper method for building and obtaining all neccessary objects from a cluster.
116+ func (b * DefaultSpecBuilder ) BuildSpec (ctx context.Context , cluster * anywherev1.Cluster ) (* c.Spec , error ) {
117+ return c .BuildSpec (ctx , clientutil .NewKubeClient (b .client ), cluster )
118+ }
119+
120+ // DefaultFailureDomainSpecBuilder is the standard implementation of FailureDomainSpecBuilder.
121+ type DefaultFailureDomainSpecBuilder struct {}
122+
123+ // BuildFailureDomainSpec wrapper to the vsphere package's FailureDomainsSpec function.
124+ func (b * DefaultFailureDomainSpecBuilder ) BuildFailureDomainSpec (log logr.Logger , clusterSpec * c.Spec ) (* vsphere.FailureDomains , error ) {
125+ return vsphere .FailureDomainsSpec (log , clusterSpec )
126+ }
127+
128+ // DefaultObjectReconciler is the standard implementation of ObjectReconciler that applies objects using a client.
129+ type DefaultObjectReconciler struct {
130+ client client.Client
131+ }
132+
133+ // ReconcileObjects applies failure domain objects to the cluster using serverside reconciliation.
134+ func (r * DefaultObjectReconciler ) ReconcileObjects (ctx context.Context , fd * vsphere.FailureDomains ) error {
135+ return serverside .ReconcileObjects (ctx , r .client , fd .Objects ())
136+ }
137+
138+ // FailureDomainMover defines config for applying failure domain objects.
139+ type FailureDomainMover struct {
140+ specBuilder SpecBuilder
141+ fdSpecBuilder FailureDomainSpecBuilder
142+ objectReconciler ObjectReconciler
143+ }
144+
145+ // NewFailureDomainMover builds FailureDomainMover with default dependencies.
146+ func NewFailureDomainMover (client client.Client ) * FailureDomainMover {
147+ return & FailureDomainMover {
148+ specBuilder : & DefaultSpecBuilder {client : client },
149+ fdSpecBuilder : & DefaultFailureDomainSpecBuilder {},
150+ objectReconciler : & DefaultObjectReconciler {client : client },
151+ }
152+ }
153+
154+ // NewFailureDomainMoverWithDependencies builds FailureDomainMover with specified dependencies.
155+ func NewFailureDomainMoverWithDependencies (
156+ specBuilder SpecBuilder ,
157+ fdSpecBuilder FailureDomainSpecBuilder ,
158+ objectReconciler ObjectReconciler ,
159+ ) * FailureDomainMover {
160+ return & FailureDomainMover {
161+ specBuilder : specBuilder ,
162+ fdSpecBuilder : fdSpecBuilder ,
163+ objectReconciler : objectReconciler ,
164+ }
165+ }
166+
86167// NewClusterReconciler constructs a new ClusterReconciler.
87- func NewClusterReconciler (client client.Client , registry ProviderClusterReconcilerRegistry , awsIamAuth AWSIamConfigReconciler , clusterValidator ClusterValidator , pkgs PackagesClient , machineHealthCheck MachineHealthCheckReconciler , opts ... ClusterReconcilerOption ) * ClusterReconciler {
168+ func NewClusterReconciler (client client.Client , registry ProviderClusterReconcilerRegistry , awsIamAuth AWSIamConfigReconciler , clusterValidator ClusterValidator , pkgs PackagesClient , machineHealthCheck MachineHealthCheckReconciler , failuredomainmover FailureDomainApplier , opts ... ClusterReconcilerOption ) * ClusterReconciler {
88169 c := & ClusterReconciler {
89170 client : client ,
90171 providerReconcilerRegistry : registry ,
91172 awsIamAuth : awsIamAuth ,
92173 clusterValidator : clusterValidator ,
93174 packagesClient : pkgs ,
94175 machineHealthCheck : machineHealthCheck ,
176+ vSpherefailureDomainMover : failuredomainmover ,
95177 }
96178
97179 for _ , opt := range opts {
@@ -488,6 +570,18 @@ func (r *ClusterReconciler) reconcileDelete(ctx context.Context, log logr.Logger
488570 return ctrl.Result {}, nil
489571 }
490572
573+ // Creates vspheredeploymentzone and vspherefailuredomain CR on bootstrap cluster prior to delete
574+ // These CRs are not migrated over during pivot and must be present to cleanly delete vspheremachines
575+ // This solution isn't ideal, but would require redesign
576+ if cluster .Spec .DatacenterRef .Kind == "VSphereDatacenterConfig" && cluster .IsSelfManaged () {
577+ if features .IsActive (features .VsphereFailureDomainEnabled ()) {
578+ log .Info ("Creating vspheredeploymentzones and vspherefailuredomains on bootstrap" )
579+ if err := r .applyFailureDomains (ctx , log , cluster ); err != nil {
580+ return ctrl.Result {}, err
581+ }
582+ }
583+ }
584+
491585 capiCluster := & clusterv1.Cluster {}
492586 capiClusterName := types.NamespacedName {Namespace : constants .EksaSystemNamespace , Name : cluster .Name }
493587 log .Info ("Deleting" , "name" , cluster .Name )
@@ -541,6 +635,25 @@ func (r *ClusterReconciler) buildClusterConfig(ctx context.Context, clus *anywhe
541635 return config , nil
542636}
543637
638+ func (r * ClusterReconciler ) applyFailureDomains (ctx context.Context , log logr.Logger , cluster * anywherev1.Cluster ) error {
639+ return r .vSpherefailureDomainMover .ApplyFailureDomains (ctx , log , cluster )
640+ }
641+
642+ // ApplyFailureDomains orchestrates the end-to-end process of applying failure domain objects to a cluster.
643+ func (m * FailureDomainMover ) ApplyFailureDomains (ctx context.Context , log logr.Logger , cluster * anywherev1.Cluster ) error {
644+ clusterSpec , err := m .specBuilder .BuildSpec (ctx , cluster )
645+ if err != nil {
646+ return err
647+ }
648+
649+ fd , err := m .fdSpecBuilder .BuildFailureDomainSpec (log , clusterSpec )
650+ if err != nil {
651+ return err
652+ }
653+
654+ return m .objectReconciler .ReconcileObjects (ctx , fd )
655+ }
656+
544657func (r * ClusterReconciler ) ensureClusterOwnerReferences (ctx context.Context , clus * anywherev1.Cluster , config * c.Config ) error {
545658 for _ , obj := range config .ChildObjects () {
546659 numberOfOwnerReferences := len (obj .GetOwnerReferences ())
0 commit comments