Various reconciliation fixes

- Reduce log noise by logging errors instead of successes
- Use context logger provided by controller-runtime
- Patch status instead of update to avoid "the object has been modified; please apply your changes to the latest version and try again"
- Add finalizer even if object is already under deletion, in case we never got a chance yet
- Don't set RequeueAfter on errors since it is ignored anyway [0]

[0]: https://github.com/kubernetes-sigs/controller-runtime/issues/617
Change-Id: Ic06aa74f9e1465d3f7e32137559231e940c8a74d
This commit is contained in:
Sean Eagan 2021-01-08 13:43:45 -06:00
parent 234c2320f4
commit e663f81ff2
2 changed files with 28 additions and 24 deletions

View File

@ -76,7 +76,6 @@ func main() {
if err = (&controllers.VinoReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Vino"),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Vino")

View File

@ -50,7 +50,6 @@ const (
// VinoReconciler reconciles a Vino object
type VinoReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
}
@ -58,9 +57,7 @@ type VinoReconciler struct {
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=vinoes/status,verbs=get;update;patch
func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
logger := r.Log.WithValues("vino", req.NamespacedName)
ctx = context.TODO()
logger := logr.FromContext(ctx)
vino := &vinov1.Vino{}
if err := r.Get(ctx, req.NamespacedName, vino); err != nil {
if apierror.IsNotFound(err) {
@ -71,24 +68,23 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
}
var err error
if vino.ObjectMeta.DeletionTimestamp.IsZero() && !controllerutil.ContainsFinalizer(vino, vinov1.VinoFinalizer) {
if !controllerutil.ContainsFinalizer(vino, vinov1.VinoFinalizer) {
logger.Info("adding finalizer to new vino object")
controllerutil.AddFinalizer(vino, vinov1.VinoFinalizer)
err = r.Update(ctx, vino)
if err != nil {
if err = r.Update(ctx, vino); err != nil {
logger.Error(err, "unable to register finalizer")
return ctrl.Result{}, err
}
return ctrl.Result{Requeue: true}, nil
}
defer func() {
if dErr := r.Status().Update(ctx, vino); dErr != nil {
if dErr := r.patchStatus(ctx, vino); dErr != nil {
if err != nil {
err = kerror.NewAggregate([]error{err, dErr})
}
err = dErr
logger.Error(err, "unable to patch status after reconciliation")
}
logger.Info("updated vino CR status")
}()
if !vino.ObjectMeta.DeletionTimestamp.IsZero() {
@ -107,7 +103,7 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
}
apimeta.SetStatusCondition(&vino.Status.Conditions, readyCondition)
vino.Status.ConfigMapReady = false
return ctrl.Result{Requeue: true, RequeueAfter: time.Second * 60}, err
return ctrl.Result{Requeue: true}, err
}
vino.Status.ConfigMapReady = true
@ -123,7 +119,7 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
}
apimeta.SetStatusCondition(&vino.Status.Conditions, readyCondition)
vino.Status.DaemonSetReady = false
return ctrl.Result{Requeue: true, RequeueAfter: time.Second * 60}, err
return ctrl.Result{Requeue: true}, err
}
vino.Status.DaemonSetReady = true
@ -133,9 +129,9 @@ func (r *VinoReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.
}
func (r *VinoReconciler) ensureConfigMap(ctx context.Context, name types.NamespacedName, vino *vinov1.Vino) error {
logger := r.Log.WithValues("vino", name)
logger := logr.FromContext(ctx)
generatedCM, err := r.buildConfigMap(name, vino)
generatedCM, err := r.buildConfigMap(ctx, name, vino)
if err != nil {
return err
}
@ -164,8 +160,9 @@ func (r *VinoReconciler) ensureConfigMap(ctx context.Context, name types.Namespa
return nil
}
func (r *VinoReconciler) buildConfigMap(name types.NamespacedName, vino *vinov1.Vino) (*corev1.ConfigMap, error) {
r.Log.Info("Generating new config map for vino object")
func (r *VinoReconciler) buildConfigMap(ctx context.Context, name types.NamespacedName, vino *vinov1.Vino) (
*corev1.ConfigMap, error) {
logr.FromContext(ctx).Info("Generating new config map for vino object")
data, err := yaml.Marshal(vino.Spec)
if err != nil {
@ -184,7 +181,7 @@ func (r *VinoReconciler) buildConfigMap(name types.NamespacedName, vino *vinov1.
}
func (r *VinoReconciler) getCurrentConfigMap(ctx context.Context, vino *vinov1.Vino) (*corev1.ConfigMap, error) {
r.Log.Info("Getting current config map for vino object")
logr.FromContext(ctx).Info("Getting current config map for vino object")
cm := &corev1.ConfigMap{}
err := r.Get(ctx, types.NamespacedName{
Name: vino.Name,
@ -202,7 +199,6 @@ func (r *VinoReconciler) getCurrentConfigMap(ctx context.Context, vino *vinov1.V
func (r *VinoReconciler) setReadyStatus(vino *vinov1.Vino) {
if vino.Status.ConfigMapReady && vino.Status.DaemonSetReady {
r.Log.Info("All VINO components are in ready state, setting VINO CR to ready state")
readyCondition := metav1.Condition{
Status: metav1.ConditionTrue,
Reason: vinov1.ReconciliationSucceededReason,
@ -214,6 +210,15 @@ func (r *VinoReconciler) setReadyStatus(vino *vinov1.Vino) {
}
}
func (r *VinoReconciler) patchStatus(ctx context.Context, vino *vinov1.Vino) error {
key := client.ObjectKeyFromObject(vino)
latest := &vinov1.Vino{}
if err := r.Client.Get(ctx, key, latest); err != nil {
return err
}
return r.Client.Status().Patch(ctx, vino, client.MergeFrom(latest))
}
func needsUpdate(generated, current *corev1.ConfigMap) bool {
for key, value := range generated.Data {
if current.Data[key] != value {
@ -229,7 +234,7 @@ func (r *VinoReconciler) ensureDaemonSet(ctx context.Context, vino *vinov1.Vino)
return err
}
r.decorateDaemonSet(ds, vino)
r.decorateDaemonSet(ctx, ds, vino)
existDS := &appsv1.DaemonSet{}
err = r.Get(ctx, types.NamespacedName{Name: ds.Name, Namespace: ds.Namespace}, existDS)
@ -253,7 +258,7 @@ func (r *VinoReconciler) ensureDaemonSet(ctx context.Context, vino *vinov1.Vino)
return r.waitDaemonSet(ctx, ds)
}
func (r *VinoReconciler) decorateDaemonSet(ds *appsv1.DaemonSet, vino *vinov1.Vino) {
func (r *VinoReconciler) decorateDaemonSet(ctx context.Context, ds *appsv1.DaemonSet, vino *vinov1.Vino) {
volume := "vino-spec"
ds.Spec.Template.Spec.NodeSelector = vino.Spec.NodeSelector.MatchLabels
@ -287,7 +292,7 @@ func (r *VinoReconciler) decorateDaemonSet(ds *appsv1.DaemonSet, vino *vinov1.Vi
}
}
if !found {
r.Log.Info("volume mount with vino spec is not found",
logr.FromContext(ctx).Info("volume mount with vino spec is not found",
"vino instance", vino.Namespace+"/"+vino.Name,
"container name", c.Name,
)
@ -310,7 +315,7 @@ func (r *VinoReconciler) decorateDaemonSet(ds *appsv1.DaemonSet, vino *vinov1.Vi
}
func (r *VinoReconciler) waitDaemonSet(ctx context.Context, ds *appsv1.DaemonSet) error {
logger := r.Log.WithValues(
logger := logr.FromContext(ctx).WithValues(
"daemonset", ds.Namespace+"/"+ds.Name)
for {
select {
@ -342,7 +347,7 @@ func (r *VinoReconciler) waitDaemonSet(ctx context.Context, ds *appsv1.DaemonSet
func (r *VinoReconciler) daemonSet(ctx context.Context, vino *vinov1.Vino) (*appsv1.DaemonSet, error) {
dsTemplate := vino.Spec.DaemonSetOptions.Template
logger := r.Log.WithValues("DaemonSetTemplate", &dsTemplate)
logger := logr.FromContext(ctx).WithValues("DaemonSetTemplate", dsTemplate)
cm := &corev1.ConfigMap{}
if dsTemplate == (vinov1.NamespacedName{}) {