@@ -17,106 +17,144 @@ limitations under the License.
17
17
package controllers
18
18
19
19
import (
20
- goctx "context"
21
20
"fmt"
21
+ "reflect"
22
22
23
- "github.com/go-logr/logr"
24
23
"github.com/pkg/errors"
25
24
apiv1 "k8s.io/api/core/v1"
26
25
apierrors "k8s.io/apimachinery/pkg/api/errors"
27
26
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
- "k8s.io/client-go/tools/record"
27
+ "k8s.io/apimachinery/pkg/runtime/schema"
28
+ clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha2"
29
29
clusterutilv1 "sigs.k8s.io/cluster-api/util"
30
+ "sigs.k8s.io/cluster-api/util/patch"
30
31
ctrl "sigs.k8s.io/controller-runtime"
31
- "sigs.k8s.io/controller-runtime/pkg/client"
32
+ "sigs.k8s.io/controller-runtime/pkg/handler"
33
+ "sigs.k8s.io/controller-runtime/pkg/manager"
32
34
"sigs.k8s.io/controller-runtime/pkg/reconcile"
35
+ "sigs.k8s.io/controller-runtime/pkg/source"
33
36
34
37
infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha2"
35
- "sigs.k8s.io/cluster-api-provider-vsphere/pkg/config"
36
38
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
39
+ "sigs.k8s.io/cluster-api-provider-vsphere/pkg/record"
37
40
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/services/cloudprovider"
38
41
infrautilv1 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/util"
39
42
)
40
43
41
44
const (
42
- controllerName = "vspherecluster-controller"
43
- apiEndpointPort = 6443
45
+ clusterControllerName = "vspherecluster-controller"
46
+ apiEndpointPort = 6443
44
47
)
45
48
46
- // VSphereClusterReconciler reconciles a VSphereCluster object
47
- type VSphereClusterReconciler struct {
48
- client.Client
49
- Recorder record.EventRecorder
50
- Log logr.Logger
51
- }
52
-
53
49
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;patch
54
50
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=vsphereclusters,verbs=get;list;watch;create;update;patch;delete
55
51
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=vsphereclusters/status,verbs=get;update;patch
56
52
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch
57
53
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs;kubeadmconfigs/status,verbs=get;list;watch
58
54
59
- // Reconcile ensures the back-end state reflects the Kubernetes resource state intent.
60
- func (r * VSphereClusterReconciler ) Reconcile (req ctrl.Request ) (_ ctrl.Result , reterr error ) {
61
- parentContext := goctx .Background ()
55
+ // AddClusterControllerToManager adds the cluster controller to the provided
56
+ // manager.
57
+ func AddClusterControllerToManager (ctx * context.ControllerManagerContext , mgr manager.Manager ) error {
58
+
59
+ var (
60
+ controllerNameShort = clusterControllerName
61
+ controllerNameLong = fmt .Sprintf ("%s/%s/%s" , ctx .Namespace , ctx .Name , controllerNameShort )
62
+ )
63
+
64
+ // Build the controller context.
65
+ controllerContext := & context.ControllerContext {
66
+ ControllerManagerContext : ctx ,
67
+ Name : controllerNameShort ,
68
+ Recorder : record .New (mgr .GetEventRecorderFor (controllerNameLong )),
69
+ Logger : ctx .Logger .WithName (controllerNameShort ),
70
+ }
62
71
63
- logger := r .Log .WithName (controllerName ).
64
- WithName (fmt .Sprintf ("namespace=%s" , req .Namespace )).
65
- WithName (fmt .Sprintf ("vsphereCluster=%s" , req .Name ))
72
+ controlledType := & infrav1.VSphereCluster {}
73
+ controlledTypeName := reflect .TypeOf (controlledType ).Elem ().Name ()
66
74
67
- // Fetch the VSphereCluster instance
75
+ return ctrl .NewControllerManagedBy (mgr ).
76
+ For (controlledType ).
77
+ Watches (
78
+ & source.Kind {Type : & clusterv1.Cluster {}},
79
+ & handler.EnqueueRequestsFromMapFunc {
80
+ ToRequests : clusterutilv1 .MachineToInfrastructureMapFunc (schema.GroupVersionKind {
81
+ Group : infrav1 .SchemeBuilder .GroupVersion .Group ,
82
+ Version : infrav1 .SchemeBuilder .GroupVersion .Version ,
83
+ Kind : controlledTypeName ,
84
+ }),
85
+ }).
86
+ Complete (clusterReconciler {ControllerContext : controllerContext })
87
+ }
88
+
89
+ type clusterReconciler struct {
90
+ * context.ControllerContext
91
+ }
92
+
93
+ // Reconcile ensures the back-end state reflects the Kubernetes resource state intent.
94
+ func (r clusterReconciler ) Reconcile (req ctrl.Request ) (_ ctrl.Result , reterr error ) {
95
+
96
+ // Get the VSphereCluster resource for this request.
68
97
vsphereCluster := & infrav1.VSphereCluster {}
69
- err := r .Get (parentContext , req .NamespacedName , vsphereCluster )
70
- if err != nil {
98
+ if err := r .Client .Get (r , req .NamespacedName , vsphereCluster ); err != nil {
71
99
if apierrors .IsNotFound (err ) {
100
+ r .Logger .V (4 ).Info ("VSphereCluster not found, won't reconcile" , "key" , req .NamespacedName )
72
101
return reconcile.Result {}, nil
73
102
}
74
103
return reconcile.Result {}, err
75
104
}
76
105
77
- logger = logger .WithName (vsphereCluster .APIVersion )
78
-
79
- // Fetch the Cluster.
80
- cluster , err := clusterutilv1 .GetOwnerCluster (parentContext , r .Client , vsphereCluster .ObjectMeta )
106
+ // Fetch the CAPI Cluster.
107
+ cluster , err := clusterutilv1 .GetOwnerCluster (r , r .Client , vsphereCluster .ObjectMeta )
81
108
if err != nil {
82
109
return reconcile.Result {}, err
83
110
}
84
111
if cluster == nil {
85
- logger .Info ("Waiting for Cluster Controller to set OwnerRef on VSphereCluster" )
86
- return reconcile.Result {RequeueAfter : config . DefaultRequeue }, nil
112
+ r . Logger .Info ("Waiting for Cluster Controller to set OwnerRef on VSphereCluster" )
113
+ return reconcile.Result {}, nil
87
114
}
88
115
89
- logger = logger .WithName (fmt .Sprintf ("cluster=%s" , cluster .Name ))
90
-
91
- // Create the context.
92
- ctx , err := context .NewClusterContext (& context.ClusterContextParams {
93
- Context : parentContext ,
94
- Cluster : cluster ,
95
- VSphereCluster : vsphereCluster ,
96
- Client : r .Client ,
97
- Logger : logger ,
98
- })
116
+ // Create the patch helper.
117
+ patchHelper , err := patch .NewHelper (vsphereCluster , r .Client )
99
118
if err != nil {
100
- return reconcile.Result {}, errors .Errorf ("failed to create cluster context: %+v" , err )
119
+ return reconcile.Result {}, errors .Wrapf (
120
+ err ,
121
+ "failed to init patch helper for %s %s/%s" ,
122
+ vsphereCluster .GroupVersionKind (),
123
+ vsphereCluster .Namespace ,
124
+ vsphereCluster .Name )
101
125
}
102
126
103
- // Always close the context when exiting this function so we can persist any VSphereCluster changes.
127
+ // Create the cluster context for this request.
128
+ clusterContext := & context.ClusterContext {
129
+ ControllerContext : r .ControllerContext ,
130
+ Cluster : cluster ,
131
+ VSphereCluster : vsphereCluster ,
132
+ Logger : r .Logger .WithName (req .Namespace ).WithName (req .Name ),
133
+ PatchHelper : patchHelper ,
134
+ }
135
+
136
+ // Always issue a patch when exiting this function so changes to the
137
+ // resource are patched back to the API server.
104
138
defer func () {
105
- if err := ctx .Patch (); err != nil && reterr == nil {
106
- reterr = err
139
+ if err := clusterContext .Patch (); err != nil {
140
+ if reterr == nil {
141
+ reterr = err
142
+ } else {
143
+ clusterContext .Logger .Error (err , "patch failed" , "cluster" , clusterContext .String ())
144
+ }
107
145
}
108
146
}()
109
147
110
148
// Handle deleted clusters
111
149
if ! vsphereCluster .DeletionTimestamp .IsZero () {
112
- return r .reconcileDelete (ctx )
150
+ return r .reconcileDelete (clusterContext )
113
151
}
114
152
115
153
// Handle non-deleted clusters
116
- return r .reconcileNormal (ctx )
154
+ return r .reconcileNormal (clusterContext )
117
155
}
118
156
119
- func (r * VSphereClusterReconciler ) reconcileDelete (ctx * context.ClusterContext ) (reconcile.Result , error ) {
157
+ func (r clusterReconciler ) reconcileDelete (ctx * context.ClusterContext ) (reconcile.Result , error ) {
120
158
ctx .Logger .Info ("Reconciling VSphereCluster delete" )
121
159
122
160
// Cluster is deleted so remove the finalizer.
@@ -125,7 +163,7 @@ func (r *VSphereClusterReconciler) reconcileDelete(ctx *context.ClusterContext)
125
163
return reconcile.Result {}, nil
126
164
}
127
165
128
- func (r * VSphereClusterReconciler ) reconcileNormal (ctx * context.ClusterContext ) (reconcile.Result , error ) {
166
+ func (r clusterReconciler ) reconcileNormal (ctx * context.ClusterContext ) (reconcile.Result , error ) {
129
167
ctx .Logger .Info ("Reconciling VSphereCluster" )
130
168
131
169
// TODO(akutz) Update this logic to include infrastructure prep such as:
@@ -175,7 +213,7 @@ func (r *VSphereClusterReconciler) reconcileNormal(ctx *context.ClusterContext)
175
213
return reconcile.Result {}, nil
176
214
}
177
215
178
- func (r * VSphereClusterReconciler ) reconcileAPIEndpoints (ctx * context.ClusterContext ) error {
216
+ func (r clusterReconciler ) reconcileAPIEndpoints (ctx * context.ClusterContext ) error {
179
217
// If the cluster already has API endpoints set then there is nothing to do.
180
218
if len (ctx .VSphereCluster .Status .APIEndpoints ) > 0 {
181
219
ctx .Logger .V (6 ).Info ("API endpoints already exist" )
@@ -263,7 +301,7 @@ func (r *VSphereClusterReconciler) reconcileAPIEndpoints(ctx *context.ClusterCon
263
301
return infrautilv1 .ErrNoMachineIPAddr
264
302
}
265
303
266
- func (r * VSphereClusterReconciler ) reconcileCloudProvider (ctx * context.ClusterContext ) error {
304
+ func (r clusterReconciler ) reconcileCloudProvider (ctx * context.ClusterContext ) error {
267
305
// if the cloud provider image is not specified, then we do nothing
268
306
cloudproviderConfig := ctx .VSphereCluster .Spec .CloudProviderConfiguration .ProviderConfig .Cloud
269
307
if cloudproviderConfig == nil {
@@ -331,7 +369,7 @@ func (r *VSphereClusterReconciler) reconcileCloudProvider(ctx *context.ClusterCo
331
369
return nil
332
370
}
333
371
334
- func (r * VSphereClusterReconciler ) reconcileStorageProvider (ctx * context.ClusterContext ) error {
372
+ func (r clusterReconciler ) reconcileStorageProvider (ctx * context.ClusterContext ) error {
335
373
// if storage config is not defined, assume we don't want CSI installed
336
374
storageConfig := ctx .VSphereCluster .Spec .CloudProviderConfiguration .ProviderConfig .Storage
337
375
if storageConfig == nil {
@@ -428,7 +466,7 @@ func (r *VSphereClusterReconciler) reconcileStorageProvider(ctx *context.Cluster
428
466
429
467
// reconcileCloudConfigSecret ensures the cloud config secret is present in the
430
468
// target cluster
431
- func (r * VSphereClusterReconciler ) reconcileCloudConfigSecret (ctx * context.ClusterContext ) error {
469
+ func (r clusterReconciler ) reconcileCloudConfigSecret (ctx * context.ClusterContext ) error {
432
470
if len (ctx .VSphereCluster .Spec .CloudProviderConfiguration .VCenter ) == 0 {
433
471
return errors .Errorf (
434
472
"no vCenters defined for VSphereCluster %s/%s" ,
@@ -444,8 +482,8 @@ func (r *VSphereClusterReconciler) reconcileCloudConfigSecret(ctx *context.Clust
444
482
445
483
credentials := map [string ]string {}
446
484
for server := range ctx .VSphereCluster .Spec .CloudProviderConfiguration .VCenter {
447
- credentials [fmt .Sprintf ("%s.username" , server )] = ctx .User ()
448
- credentials [fmt .Sprintf ("%s.password" , server )] = ctx .Pass ()
485
+ credentials [fmt .Sprintf ("%s.username" , server )] = ctx .Username
486
+ credentials [fmt .Sprintf ("%s.password" , server )] = ctx .Password
449
487
}
450
488
// Define the kubeconfig secret for the target cluster.
451
489
secret := & apiv1.Secret {
@@ -474,10 +512,3 @@ func (r *VSphereClusterReconciler) reconcileCloudConfigSecret(ctx *context.Clust
474
512
475
513
return nil
476
514
}
477
-
478
- // SetupWithManager adds this controller to the provided manager.
479
- func (r * VSphereClusterReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
480
- return ctrl .NewControllerManagedBy (mgr ).
481
- For (& infrav1.VSphereCluster {}).
482
- Complete (r )
483
- }
0 commit comments