Skip to content

Subresource status failing to stop infinite loop #2795

@cacois

Description

@cacois

Bug Report

What did you do?
A clear and concise description of the steps you took (or insert a code snippet).

As documented here, in order to avoid CR status changes causing an infinite loop of the reconcile() function, we should make the status block a subresource, following steps outlined here.

However, we have found that even though we successfully set the CRD status attribute as a subresource, we still see infinite looping of reconcile() when status is changed. A simple example to reproduce, using the canonical PodSet operator demo, would have the following types spec:

// +kubebuilder:subresource:status
// +kubebuilder:resource:path=podsets,scope=Namespaced
type PodSet struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   PodSetSpec   `json:"spec,omitempty"`
	Status PodSetStatus `json:"status,omitempty"`
}

which results in a CRD with a subresource, as expected:

...
spec:
  group: app.example.com
  names:
    kind: PodSet
    listKind: PodSetList
    plural: podsets
    singular: podset
  scope: Namespaced
  subresources:
    status: {}
  validation:
...

However, placing the following code in the controller reconcile() function:

// NOTE: the 'Updated' timestamp will change each time reconcile() is called
// If status is not treated correctly as a subresource
instance.Status.Updated = time.Now().String()
err = r.client.Status().Update(context.TODO(), podSet)
if err != nil {
	reqLogger.Error(err, "failed to update the podSet")
	return reconcile.Result{}, err
}

This updates the 'Updated' timestamp on the status object every time reconcile() is called. According to the documentation, this change to the status object should not trigger a call of the reconcile() function because the status object is a subresource, thus avoiding an infinite loop. However, the infinite loop occurs. Is the documentation wrong, is there a bug, or am I missing something?

What did you expect to see?

When setting the 'status' attribute as a subresource of a CRD, I should be able to update status in the reconcile() function without re-invoking the reconcile() loop.

What did you see instead? Under which circumstances?

When updating the status attribute, even though its a subresource, I see an infinite loop of the reconcile() function.

Environment

  • operator-sdk version: v0.15.2
  • go version: 1.13.8
  • Kubernetes version information: 1.16.2
  • Kubernetes cluster kind: openshift

  • Are you writing your operator in ansible, helm, or go? go

Possible Solution

Additional context
I've created a functional reproduction of the issue in this repo

Metadata

Metadata

Assignees

Labels

triage/supportIndicates an issue that is a support question.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions