Skip to content

Commit 1e0cac1

Browse files
authored
Merge pull request kubernetes-sigs#672 from akutz/feature/context
Refactor context package
2 parents a455906 + 1f6b56d commit 1e0cac1

27 files changed

+1261
-748
lines changed

controllers/suite_test.go

Lines changed: 0 additions & 91 deletions
This file was deleted.

controllers/vspherecluster_controller.go

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -17,106 +17,144 @@ limitations under the License.
1717
package controllers
1818

1919
import (
20-
goctx "context"
2120
"fmt"
21+
"reflect"
2222

23-
"github.com/go-logr/logr"
2423
"github.com/pkg/errors"
2524
apiv1 "k8s.io/api/core/v1"
2625
apierrors "k8s.io/apimachinery/pkg/api/errors"
2726
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"
2929
clusterutilv1 "sigs.k8s.io/cluster-api/util"
30+
"sigs.k8s.io/cluster-api/util/patch"
3031
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"
3234
"sigs.k8s.io/controller-runtime/pkg/reconcile"
35+
"sigs.k8s.io/controller-runtime/pkg/source"
3336

3437
infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/api/v1alpha2"
35-
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/config"
3638
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
39+
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/record"
3740
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/services/cloudprovider"
3841
infrautilv1 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/util"
3942
)
4043

4144
const (
42-
controllerName = "vspherecluster-controller"
43-
apiEndpointPort = 6443
45+
clusterControllerName = "vspherecluster-controller"
46+
apiEndpointPort = 6443
4447
)
4548

46-
// VSphereClusterReconciler reconciles a VSphereCluster object
47-
type VSphereClusterReconciler struct {
48-
client.Client
49-
Recorder record.EventRecorder
50-
Log logr.Logger
51-
}
52-
5349
// +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch;create;patch
5450
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=vsphereclusters,verbs=get;list;watch;create;update;patch;delete
5551
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=vsphereclusters/status,verbs=get;update;patch
5652
// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;clusters/status,verbs=get;list;watch
5753
// +kubebuilder:rbac:groups=bootstrap.cluster.x-k8s.io,resources=kubeadmconfigs;kubeadmconfigs/status,verbs=get;list;watch
5854

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+
}
6271

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()
6674

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.
6897
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 {
7199
if apierrors.IsNotFound(err) {
100+
r.Logger.V(4).Info("VSphereCluster not found, won't reconcile", "key", req.NamespacedName)
72101
return reconcile.Result{}, nil
73102
}
74103
return reconcile.Result{}, err
75104
}
76105

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)
81108
if err != nil {
82109
return reconcile.Result{}, err
83110
}
84111
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
87114
}
88115

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)
99118
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)
101125
}
102126

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.
104138
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+
}
107145
}
108146
}()
109147

110148
// Handle deleted clusters
111149
if !vsphereCluster.DeletionTimestamp.IsZero() {
112-
return r.reconcileDelete(ctx)
150+
return r.reconcileDelete(clusterContext)
113151
}
114152

115153
// Handle non-deleted clusters
116-
return r.reconcileNormal(ctx)
154+
return r.reconcileNormal(clusterContext)
117155
}
118156

119-
func (r *VSphereClusterReconciler) reconcileDelete(ctx *context.ClusterContext) (reconcile.Result, error) {
157+
func (r clusterReconciler) reconcileDelete(ctx *context.ClusterContext) (reconcile.Result, error) {
120158
ctx.Logger.Info("Reconciling VSphereCluster delete")
121159

122160
// Cluster is deleted so remove the finalizer.
@@ -125,7 +163,7 @@ func (r *VSphereClusterReconciler) reconcileDelete(ctx *context.ClusterContext)
125163
return reconcile.Result{}, nil
126164
}
127165

128-
func (r *VSphereClusterReconciler) reconcileNormal(ctx *context.ClusterContext) (reconcile.Result, error) {
166+
func (r clusterReconciler) reconcileNormal(ctx *context.ClusterContext) (reconcile.Result, error) {
129167
ctx.Logger.Info("Reconciling VSphereCluster")
130168

131169
// TODO(akutz) Update this logic to include infrastructure prep such as:
@@ -175,7 +213,7 @@ func (r *VSphereClusterReconciler) reconcileNormal(ctx *context.ClusterContext)
175213
return reconcile.Result{}, nil
176214
}
177215

178-
func (r *VSphereClusterReconciler) reconcileAPIEndpoints(ctx *context.ClusterContext) error {
216+
func (r clusterReconciler) reconcileAPIEndpoints(ctx *context.ClusterContext) error {
179217
// If the cluster already has API endpoints set then there is nothing to do.
180218
if len(ctx.VSphereCluster.Status.APIEndpoints) > 0 {
181219
ctx.Logger.V(6).Info("API endpoints already exist")
@@ -263,7 +301,7 @@ func (r *VSphereClusterReconciler) reconcileAPIEndpoints(ctx *context.ClusterCon
263301
return infrautilv1.ErrNoMachineIPAddr
264302
}
265303

266-
func (r *VSphereClusterReconciler) reconcileCloudProvider(ctx *context.ClusterContext) error {
304+
func (r clusterReconciler) reconcileCloudProvider(ctx *context.ClusterContext) error {
267305
// if the cloud provider image is not specified, then we do nothing
268306
cloudproviderConfig := ctx.VSphereCluster.Spec.CloudProviderConfiguration.ProviderConfig.Cloud
269307
if cloudproviderConfig == nil {
@@ -331,7 +369,7 @@ func (r *VSphereClusterReconciler) reconcileCloudProvider(ctx *context.ClusterCo
331369
return nil
332370
}
333371

334-
func (r *VSphereClusterReconciler) reconcileStorageProvider(ctx *context.ClusterContext) error {
372+
func (r clusterReconciler) reconcileStorageProvider(ctx *context.ClusterContext) error {
335373
// if storage config is not defined, assume we don't want CSI installed
336374
storageConfig := ctx.VSphereCluster.Spec.CloudProviderConfiguration.ProviderConfig.Storage
337375
if storageConfig == nil {
@@ -428,7 +466,7 @@ func (r *VSphereClusterReconciler) reconcileStorageProvider(ctx *context.Cluster
428466

429467
// reconcileCloudConfigSecret ensures the cloud config secret is present in the
430468
// target cluster
431-
func (r *VSphereClusterReconciler) reconcileCloudConfigSecret(ctx *context.ClusterContext) error {
469+
func (r clusterReconciler) reconcileCloudConfigSecret(ctx *context.ClusterContext) error {
432470
if len(ctx.VSphereCluster.Spec.CloudProviderConfiguration.VCenter) == 0 {
433471
return errors.Errorf(
434472
"no vCenters defined for VSphereCluster %s/%s",
@@ -444,8 +482,8 @@ func (r *VSphereClusterReconciler) reconcileCloudConfigSecret(ctx *context.Clust
444482

445483
credentials := map[string]string{}
446484
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
449487
}
450488
// Define the kubeconfig secret for the target cluster.
451489
secret := &apiv1.Secret{
@@ -474,10 +512,3 @@ func (r *VSphereClusterReconciler) reconcileCloudConfigSecret(ctx *context.Clust
474512

475513
return nil
476514
}
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

Comments
 (0)