Skip to content

Commit bf78b8e

Browse files
authored
Improve PVC phase handling (#70)
Now: - ignore PVC that are pending - raise a specific error if the phase is not expected Since Status is a subresource, it has to be updated directly in the tests
1 parent 1376a1d commit bf78b8e

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

internal/controller/applicationdisruptionbudget_controller_test.go

+48-6
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ var _ = Describe("ApplicationDisruptionBudget controller", func() {
118118
return createdADB.Status.WatchedNodes
119119
}, timeout, interval).Should(Equal([]string{"node1"}))
120120

121-
By("Adding Pods")
121+
By("Adding more Pods")
122122
pod2 := newPod("podadb2", ADBNamespace, "node2", podLabels)
123123
Expect(k8sClient.Create(ctx, &pod2)).Should(Succeed())
124124

@@ -129,9 +129,10 @@ var _ = Describe("ApplicationDisruptionBudget controller", func() {
129129
return createdADB.Status.WatchedNodes
130130
}, timeout, interval).Should(Equal([]string{"node1", "node2"}))
131131

132-
By("Adding PVCs")
132+
By("Adding a new PVC")
133133
pvc3 := newPVC("pvc3", ADBNamespace, "node3-pv-local", podLabels)
134-
Expect(k8sClient.Create(ctx, &pvc3)).Should(Succeed())
134+
Expect(k8sClient.Create(ctx, pvc3.DeepCopy())).Should(Succeed())
135+
Expect(k8sClient.Status().Update(ctx, pvc3.DeepCopy())).Should(Succeed())
135136

136137
By("checking the ApplicationDisruptionBudget updated the status")
137138
Eventually(func() []string {
@@ -153,7 +154,8 @@ var _ = Describe("ApplicationDisruptionBudget controller", func() {
153154
pod3 := newPod("podadb3", ADBNamespace, "", podLabels)
154155
Expect(k8sClient.Create(ctx, &pod3)).Should(Succeed())
155156
pvc3 := newPVC("pvc3", ADBNamespace, "node3-pv-local", podLabels)
156-
Expect(k8sClient.Create(ctx, &pvc3)).Should(Succeed())
157+
Expect(k8sClient.Create(ctx, pvc3.DeepCopy())).Should(Succeed())
158+
Expect(k8sClient.Status().Update(ctx, pvc3.DeepCopy())).Should(Succeed())
157159

158160
By("creating a budget that accepts one disruption")
159161
ndb := &nodedisruptionv1alpha1.ApplicationDisruptionBudget{
@@ -232,7 +234,8 @@ var _ = Describe("ApplicationDisruptionBudget controller", func() {
232234

233235
By("Adding PVC")
234236
pvc := newPVC("pvc", ADBNamespace, "remote-pv", podLabels)
235-
Expect(k8sClient.Create(ctx, &pvc)).Should(Succeed())
237+
Expect(k8sClient.Create(ctx, pvc.DeepCopy())).Should(Succeed())
238+
Expect(k8sClient.Status().Update(ctx, pvc.DeepCopy())).Should(Succeed())
236239

237240
By("creating a budget that accepts one disruption")
238241
adb := &nodedisruptionv1alpha1.ApplicationDisruptionBudget{
@@ -265,6 +268,45 @@ var _ = Describe("ApplicationDisruptionBudget controller", func() {
265268
Expect(adb.Status.WatchedNodes).Should(BeEmpty())
266269
})
267270
})
268-
})
269271

272+
When("PVC is pending", func() {
273+
It("is ignored by ADB", func() {
274+
By("Adding PVC")
275+
pvc := newPVC("pvc", ADBNamespace, "remote-pv", podLabels)
276+
pvc.Status.Phase = corev1.ClaimPending
277+
Expect(k8sClient.Create(ctx, pvc.DeepCopy())).Should(Succeed())
278+
Expect(k8sClient.Status().Update(ctx, pvc.DeepCopy())).Should(Succeed())
279+
280+
By("creating a budget that accepts one disruption")
281+
adb := &nodedisruptionv1alpha1.ApplicationDisruptionBudget{
282+
TypeMeta: metav1.TypeMeta{
283+
APIVersion: "nodedisruption.criteo.com/v1alpha1",
284+
Kind: "ApplicationDisruptionBudget",
285+
},
286+
ObjectMeta: metav1.ObjectMeta{
287+
Name: ADBname,
288+
Namespace: ADBNamespace,
289+
},
290+
Spec: nodedisruptionv1alpha1.ApplicationDisruptionBudgetSpec{
291+
PodSelector: metav1.LabelSelector{MatchLabels: podLabels},
292+
PVCSelector: metav1.LabelSelector{MatchLabels: podLabels},
293+
MaxDisruptions: 1,
294+
},
295+
}
296+
Expect(k8sClient.Create(ctx, adb)).Should(Succeed())
297+
298+
By("checking the ApplicationDisruptionBudget updated the status and has seen no nodes")
299+
Eventually(func() int {
300+
err := k8sClient.Get(ctx, types.NamespacedName{
301+
Namespace: ADBNamespace,
302+
Name: ADBname,
303+
}, adb)
304+
Expect(err).Should(Succeed())
305+
return adb.Status.DisruptionsAllowed
306+
}, timeout, interval).Should(Equal(1))
307+
308+
Expect(adb.Status.WatchedNodes).Should(BeEmpty())
309+
})
310+
})
311+
})
270312
})

internal/controller/suite_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ func newPVC(name, namespace, pvName string, labels map[string]string) corev1.Per
8787
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce},
8888
Resources: corev1.ResourceRequirements{Requests: resources},
8989
},
90-
Status: corev1.PersistentVolumeClaimStatus{},
90+
Status: corev1.PersistentVolumeClaimStatus{
91+
Phase: corev1.ClaimBound,
92+
},
9193
}
9294
}
9395

pkg/resolver/resolver.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,19 @@ func (r *Resolver) GetNodesFromNamespacedPVCSelector(ctx context.Context, pvcSel
165165
PVsToFetch := []string{}
166166

167167
for _, pvc := range PVCs.Items {
168-
PVsToFetch = append(PVsToFetch, pvc.Spec.VolumeName)
168+
169+
logger.Info("PVC status", "pvc_name", pvc.Name, "pvc_phase", pvc.Status.Phase)
170+
if pvc.Status.Phase == corev1.ClaimBound {
171+
PVsToFetch = append(PVsToFetch, pvc.Spec.VolumeName)
172+
} else if pvc.Status.Phase == corev1.ClaimLost {
173+
return nodeSet, fmt.Errorf("PVC %s is marked lost. It is unsafe to grant disruption in this state", pvc.Name)
174+
} else if pvc.Status.Phase == corev1.ClaimPending {
175+
// Pending means that no nodes around bound yet so no need to fetch a non existing pv
176+
logger.Info("Skipping PVC because it is pending", "pvc_name", pvc.Name, "pvc_phase", pvc.Status.Phase)
177+
continue
178+
} else {
179+
return nodeSet, fmt.Errorf("PVC %s is unexpected phase (%s). It is unsafe to grant disruption in this state", pvc.Name, pvc.Status.Phase)
180+
}
169181
}
170182

171183
getOptions := []client.GetOption{}

0 commit comments

Comments
 (0)