Skip to content
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

🐛 Ensure status updates succeed #1261

Merged
merged 1 commit into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions controllers/cluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,7 @@ func (r *ClusterReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, reterr e

// Always issue a Patch for the Cluster object and its status after each reconciliation.
defer func() {
if err := r.Client.Patch(ctx, cluster, patchCluster); err != nil {
klog.Errorf("Error Patching Cluster %q in namespace %q: %v", cluster.Name, cluster.Namespace, err)
if reterr == nil {
reterr = err
}
return
}
if err := r.Client.Status().Patch(ctx, cluster, patchCluster); err != nil {
klog.Errorf("Error Patching Cluster status %q in namespace %q: %v", cluster.Name, cluster.Namespace, err)
if err := r.patchCluster(ctx, cluster, patchCluster); err != nil {
if reterr == nil {
reterr = err
}
Expand Down Expand Up @@ -241,3 +233,17 @@ func (r *ClusterReconciler) listChildren(ctx context.Context, cluster *clusterv1

return children, nil
}

func (r *ClusterReconciler) patchCluster(ctx context.Context, cluster *clusterv1.Cluster, patch client.Patch) error {
log := r.Log.WithValues("cluster-namespace", cluster.Namespace, "cluster-name", cluster.Name)
// Always patch the status before the spec
if err := r.Client.Status().Patch(ctx, cluster, patch); err != nil {
chuckha marked this conversation as resolved.
Show resolved Hide resolved
chuckha marked this conversation as resolved.
Show resolved Hide resolved
log.Error(err, "Error patching cluster status")
return err
}
if err := r.Client.Patch(ctx, cluster, patch); err != nil {
log.Error(err, "Error patching cluster")
return err
}
return nil
}
89 changes: 89 additions & 0 deletions controllers/cluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package controllers
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha2"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -49,4 +50,92 @@ var _ = Describe("Cluster Reconciler", func() {
}, timeout).Should(BeTrue())
})

It("Should successfully patch a cluster object if the status diff is empty but the spec diff is not", func() {
// Setup
cluster := &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
Namespace: "default",
},
}
key := client.ObjectKey{Name: "test-cluster", Namespace: "default"}
Expect(k8sClient.Create(ctx, cluster)).To(BeNil())
defer k8sClient.Delete(ctx, cluster)

// Reconcile
Eventually(func() bool {
patch := client.MergeFrom(cluster.DeepCopy())
cluster.Spec.InfrastructureRef = &v1.ObjectReference{Name: "test"}
Expect(clusterReconciler.patchCluster(ctx, cluster, patch)).To(BeNil())
return true
}, timeout).Should(BeTrue())

// Assertions
Eventually(func() bool {
instance := &clusterv1.Cluster{}
Expect(k8sClient.Get(ctx, key, instance)).To(BeNil())
Expect(instance.Spec.InfrastructureRef.Name).To(BeEquivalentTo("test"))
return true
}, timeout).Should(BeTrue())
})

It("Should successfully patch a cluster object if the spec diff is empty but the status diff is not", func() {
// Setup
cluster := &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
Namespace: "default",
},
}
key := client.ObjectKey{Name: "test-cluster", Namespace: "default"}
Expect(k8sClient.Create(ctx, cluster)).To(BeNil())
defer k8sClient.Delete(ctx, cluster)

// Reconcile
Eventually(func() bool {
patch := client.MergeFrom(cluster.DeepCopy())
cluster.Status.InfrastructureReady = true
Expect(clusterReconciler.patchCluster(ctx, cluster, patch)).To(BeNil())
return true
}, timeout).Should(BeTrue())

// Assertions
Eventually(func() bool {
instance := &clusterv1.Cluster{}
Expect(k8sClient.Get(ctx, key, instance)).To(BeNil())
Expect(instance.Status.InfrastructureReady).To(BeTrue())
return true
}, timeout).Should(BeTrue())
})

It("Should successfully patch a cluster object if both the spec diff and status diff are non empty", func() {
// Setup
cluster := &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster",
Namespace: "default",
},
}
key := client.ObjectKey{Name: "test-cluster", Namespace: "default"}
Expect(k8sClient.Create(ctx, cluster)).To(BeNil())
defer k8sClient.Delete(ctx, cluster)

// Reconcile
Eventually(func() bool {
patch := client.MergeFrom(cluster.DeepCopy())
cluster.Status.InfrastructureReady = true
cluster.Spec.InfrastructureRef = &v1.ObjectReference{Name: "test"}
Expect(clusterReconciler.patchCluster(ctx, cluster, patch)).To(BeNil())
return true
}, timeout).Should(BeTrue())

// Assertions
Eventually(func() bool {
instance := &clusterv1.Cluster{}
Expect(k8sClient.Get(ctx, key, instance)).To(BeNil())
Expect(instance.Status.InfrastructureReady).To(BeTrue())
Expect(instance.Spec.InfrastructureRef.Name).To(BeEquivalentTo("test"))
return true
}, timeout).Should(BeTrue())
})
})
22 changes: 10 additions & 12 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ const (
)

var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
mgr manager.Manager
doneMgr = make(chan struct{})
ctx = context.Background()
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
mgr manager.Manager
clusterReconciler *ClusterReconciler
doneMgr = make(chan struct{})
ctx = context.Background()
)

func TestAPIs(t *testing.T) {
Expand Down Expand Up @@ -90,14 +91,11 @@ var _ = BeforeSuite(func(done Done) {
By("setting up a new manager")
mgr, err = manager.New(cfg, manager.Options{Scheme: scheme.Scheme, MetricsBindAddress: "0"})
Expect(err).NotTo(HaveOccurred())
Expect((&ClusterReconciler{
clusterReconciler = &ClusterReconciler{
Client: mgr.GetClient(),
Log: log.Log,
}).SetupWithManager(mgr)).NotTo(HaveOccurred())
Expect((&MachineReconciler{
Client: mgr.GetClient(),
Log: log.Log,
}).SetupWithManager(mgr)).NotTo(HaveOccurred())
}
Expect(clusterReconciler.SetupWithManager(mgr)).NotTo(HaveOccurred())

By("starting the manager")
go func() {
Expand Down