-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🏃 Update status.controlPlaneInitialized from cluster controller #1356
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ package controllers | |
|
||
import ( | ||
"context" | ||
"fmt" | ||
"path" | ||
"sync" | ||
"time" | ||
|
@@ -27,6 +28,7 @@ import ( | |
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
kerrors "k8s.io/apimachinery/pkg/util/errors" | ||
"k8s.io/client-go/tools/record" | ||
"k8s.io/klog" | ||
|
@@ -38,7 +40,9 @@ import ( | |
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller" | ||
"sigs.k8s.io/controller-runtime/pkg/handler" | ||
"sigs.k8s.io/controller-runtime/pkg/reconcile" | ||
"sigs.k8s.io/controller-runtime/pkg/source" | ||
) | ||
|
||
const ( | ||
|
@@ -66,6 +70,10 @@ type ClusterReconciler struct { | |
func (r *ClusterReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { | ||
c, err := ctrl.NewControllerManagedBy(mgr). | ||
For(&clusterv1.Cluster{}). | ||
Watches( | ||
&source.Kind{Type: &clusterv1.Machine{}}, | ||
&handler.EnqueueRequestsFromMapFunc{ToRequests: handler.ToRequestsFunc(r.controlPlaneMachineToCluster)}, | ||
). | ||
WithOptions(options). | ||
Build(r) | ||
|
||
|
@@ -129,6 +137,7 @@ func (r *ClusterReconciler) reconcile(ctx context.Context, cluster *clusterv1.Cl | |
reconciliationErrors := []error{ | ||
r.reconcileInfrastructure(ctx, cluster), | ||
r.reconcileKubeconfig(ctx, cluster), | ||
r.reconcileControlPlaneInitialized(ctx, cluster), | ||
} | ||
|
||
// Parse the errors, making sure we record if there is a RequeueAfterError. | ||
|
@@ -287,3 +296,80 @@ func splitMachineList(list *clusterv1.MachineList) (*clusterv1.MachineList, *clu | |
} | ||
return controlplanes, nodes | ||
} | ||
|
||
func (r *ClusterReconciler) reconcileControlPlaneInitialized(ctx context.Context, cluster *clusterv1.Cluster) error { | ||
if cluster.Status.ControlPlaneInitialized { | ||
return nil | ||
} | ||
|
||
machines, err := r.getMachinesInCluster(ctx, cluster.Namespace, cluster.Name) | ||
if err != nil { | ||
r.Log.Error(err, "error getting machines in cluster", "cluster", cluster.Name, "namespace", cluster.Namespace) | ||
return err | ||
} | ||
|
||
for _, m := range machines { | ||
if util.IsControlPlaneMachine(m) && m.Status.NodeRef != nil { | ||
cluster.Status.ControlPlaneInitialized = true | ||
return nil | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// getMachinesInCluster returns all of the Machine objects that belong to the cluster | ||
func (r *ClusterReconciler) getMachinesInCluster(ctx context.Context, namespace, name string) ([]*clusterv1.Machine, error) { | ||
if name == "" { | ||
return nil, nil | ||
} | ||
|
||
machineList := &clusterv1.MachineList{} | ||
labels := map[string]string{clusterv1.MachineClusterLabelName: name} | ||
|
||
if err := r.Client.List(ctx, machineList, client.InNamespace(namespace), client.MatchingLabels(labels)); err != nil { | ||
return nil, errors.Wrap(err, "failed to list machines") | ||
} | ||
|
||
machines := []*clusterv1.Machine{} | ||
for i := range machineList.Items { | ||
m := &machineList.Items[i] | ||
if m.DeletionTimestamp.IsZero() { | ||
machines = append(machines, m) | ||
} | ||
} | ||
return machines, nil | ||
} | ||
|
||
// controlPlaneMachineToCluster is a handler.ToRequestsFunc to be used to enqueue requests for reconciliation | ||
// for Cluster to update its status.controlPlaneInitialized field | ||
func (r *ClusterReconciler) controlPlaneMachineToCluster(o handler.MapObject) []ctrl.Request { | ||
m, ok := o.Object.(*clusterv1.Machine) | ||
if !ok { | ||
r.Log.Error(errors.New("did not get machine"), "got", fmt.Sprintf("%T", o.Object)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm almost hesitant to suggest this, but I wonder if we should consider a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't disagree, I'm +1 to use Fatal or panic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is what we are doing in other places, so we'd need to update all the existing use cases as well if we wanted to go down that path. (Not saying we shouldn't, just outside the scope of this PR). |
||
return nil | ||
} | ||
if !util.IsControlPlaneMachine(m) { | ||
return nil | ||
} | ||
if m.Status.NodeRef == nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can do an OR and merge the two ifs above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to leave it like this |
||
return nil | ||
} | ||
|
||
cluster, err := util.GetClusterFromMetadata(context.TODO(), r.Client, m.ObjectMeta) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we remove this query and just enqueue the request from the label name, and assume the same namespace? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a code copy from the machine controller. The get is here so we can check control plane initialized below on line 365 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method name threw me off a little There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It pulls from the cache, so it's not a network hit. I guess it comes down to whether or not you want to avoid enqueuing if you know up front it's not relevant (non control plane machine). |
||
if err != nil { | ||
r.Log.Error(err, "failed to get cluster", "machine", m.Name, "cluster", m.ClusterName, "namespace", m.Namespace) | ||
return nil | ||
} | ||
|
||
if cluster.Status.ControlPlaneInitialized { | ||
return nil | ||
} | ||
|
||
return []ctrl.Request{{ | ||
NamespacedName: types.NamespacedName{ | ||
Namespace: cluster.Namespace, | ||
Name: cluster.Name, | ||
}, | ||
}} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vincepri @ncdc I created this function similar to this in machine controller. should move this as a common function elsewhere?
cluster-api/controllers/machine_controller.go
Lines 264 to 284 in 2a55573
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes please! You can change the signature so it takes in the
Client
. As for where to put it... I'm trying to avoid generic files/packages likeutil
orhelpers
. Even though I just said let's avoid "helpers", maybe we put it incontrollers/machine_helpers.go
? @vincepri wdyt?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either way should be fine, I'm also ok adding it in
util/util.go
for now and remove it later, there are a bunch of other similar functions that take a Controller Runtime Client and return something, so this wouldn't be anything new.If we want to make it private,
controllers/helpers.go
orcontrollers/machine_helpers.go
as you suggested sounds good.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets address it in a separate pr after it is merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#1414