Skip to content

Commit eff3b10

Browse files
committed
add PDB trackability and unit test
1 parent cb0c5f7 commit eff3b10

File tree

4 files changed

+131
-1
lines changed

4 files changed

+131
-1
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ require (
2828
k8s.io/apimachinery v0.30.3
2929
k8s.io/client-go v0.30.3
3030
k8s.io/component-base v0.30.2
31+
k8s.io/component-helpers v0.28.3
3132
k8s.io/klog/v2 v2.130.1
3233
k8s.io/metrics v0.25.2
3334
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8

pkg/controllers/work/apply_controller.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"go.uber.org/atomic"
3030
appv1 "k8s.io/api/apps/v1"
3131
v1 "k8s.io/api/core/v1"
32+
policyv1 "k8s.io/api/policy/v1"
3233
apiextensionshelpers "k8s.io/apiextensions-apiserver/pkg/apihelpers"
3334
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3435
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -41,6 +42,7 @@ import (
4142
utilerrors "k8s.io/apimachinery/pkg/util/errors"
4243
"k8s.io/client-go/dynamic"
4344
"k8s.io/client-go/tools/record"
45+
"k8s.io/component-helpers/apps/poddisruptionbudget"
4446
"k8s.io/klog/v2"
4547
"k8s.io/utils/ptr"
4648
ctrl "sigs.k8s.io/controller-runtime"
@@ -453,6 +455,9 @@ func trackResourceAvailability(gvr schema.GroupVersionResource, curObj *unstruct
453455
case utils.CustomResourceDefinitionGVR:
454456
return trackCRDAvailability(curObj)
455457

458+
case utils.PodDisruptionBudgetGVR:
459+
return trackPDBAvailability(curObj)
460+
456461
default:
457462
if isDataResource(gvr) {
458463
klog.V(2).InfoS("Data resources are available immediately", "gvr", gvr, "resource", klog.KObj(curObj))
@@ -463,6 +468,24 @@ func trackResourceAvailability(gvr schema.GroupVersionResource, curObj *unstruct
463468
}
464469
}
465470

471+
func trackPDBAvailability(curObj *unstructured.Unstructured) (ApplyAction, error) {
472+
var pdb policyv1.PodDisruptionBudget
473+
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(curObj.Object, &pdb); err != nil {
474+
return errorApplyAction, controller.NewUnexpectedBehaviorError(err)
475+
}
476+
// Check if conditions are up-to-date
477+
if poddisruptionbudget.ConditionsAreUpToDate(&pdb) {
478+
if cond := meta.FindStatusCondition(pdb.Status.Conditions, policyv1.DisruptionAllowedCondition); cond != nil {
479+
if cond.Status == metav1.ConditionTrue && cond.Reason == policyv1.SufficientPodsReason {
480+
klog.V(2).InfoS("PodDisruptionBudget is available", "pdb", klog.KObj(curObj))
481+
return manifestAvailableAction, nil
482+
}
483+
}
484+
}
485+
klog.V(2).InfoS("Still need to wait for PodDisruptionBudget to be available", "pdb", klog.KObj(curObj))
486+
return manifestNotAvailableYetAction, nil
487+
}
488+
466489
func trackCRDAvailability(curObj *unstructured.Unstructured) (ApplyAction, error) {
467490
var crd apiextensionsv1.CustomResourceDefinition
468491
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(curObj.Object, &crd); err != nil {

pkg/controllers/work/apply_controller_test.go

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,8 +1420,107 @@ func TestTrackResourceAvailability(t *testing.T) {
14201420
expected: manifestNotAvailableYetAction,
14211421
err: nil,
14221422
},
1423+
"Test PodDisruptionBudget available": {
1424+
gvr: utils.PodDisruptionBudgetGVR,
1425+
obj: &unstructured.Unstructured{
1426+
Object: map[string]interface{}{
1427+
"apiVersion": "policy/v1",
1428+
"kind": "PodDisruptionBudget",
1429+
"metadata": map[string]interface{}{
1430+
"name": "test-pdb",
1431+
"namespace": "default",
1432+
"generation": 2,
1433+
},
1434+
"spec": map[string]interface{}{
1435+
"minAvailable": 1,
1436+
},
1437+
"status": map[string]interface{}{
1438+
"currentHealthy": 2,
1439+
"desiredHealthy": 1,
1440+
"observedGeneration": 2,
1441+
"disruptionsAllowed": 1,
1442+
"expectedPods": 1,
1443+
"conditions": []interface{}{
1444+
map[string]interface{}{
1445+
"type": "DisruptionAllowed",
1446+
"status": "True",
1447+
"reason": "SufficientPods",
1448+
"observedGeneration": 2,
1449+
},
1450+
},
1451+
},
1452+
},
1453+
},
1454+
expected: manifestAvailableAction,
1455+
err: nil,
1456+
},
1457+
"Test PodDisruptionBudget unavailable (condition not up-to-date)": {
1458+
gvr: utils.PodDisruptionBudgetGVR,
1459+
obj: &unstructured.Unstructured{
1460+
Object: map[string]interface{}{
1461+
"apiVersion": "policy/v1",
1462+
"kind": "PodDisruptionBudget",
1463+
"metadata": map[string]interface{}{
1464+
"name": "test-pdb",
1465+
"namespace": "default",
1466+
"generation": 2,
1467+
},
1468+
"spec": map[string]interface{}{
1469+
"minAvailable": 1,
1470+
},
1471+
"status": map[string]interface{}{
1472+
"currentHealthy": 2,
1473+
"desiredHealthy": 1,
1474+
"observedGeneration": 1,
1475+
"disruptionsAllowed": 1,
1476+
"expectedPods": 1,
1477+
"conditions": []interface{}{
1478+
map[string]interface{}{
1479+
"type": "DisruptionAllowed",
1480+
"status": "True",
1481+
"reason": "SufficientPods",
1482+
},
1483+
},
1484+
},
1485+
},
1486+
},
1487+
expected: manifestNotAvailableYetAction,
1488+
err: nil,
1489+
},
1490+
"Test PodDisruptionBudget unavailable": {
1491+
gvr: utils.PodDisruptionBudgetGVR,
1492+
obj: &unstructured.Unstructured{
1493+
Object: map[string]interface{}{
1494+
"apiVersion": "policy/v1",
1495+
"kind": "PodDisruptionBudget",
1496+
"metadata": map[string]interface{}{
1497+
"name": "test-pdb",
1498+
"namespace": "default",
1499+
"generation": 2,
1500+
},
1501+
"spec": map[string]interface{}{
1502+
"minAvailable": 1,
1503+
},
1504+
"status": map[string]interface{}{
1505+
"currentHealthy": 1,
1506+
"desiredHealthy": 1,
1507+
"observedGeneration": 2,
1508+
"disruptionsAllowed": 1,
1509+
"expectedPods": 1,
1510+
"conditions": []interface{}{
1511+
map[string]interface{}{
1512+
"type": "DisruptionAllowed",
1513+
"status": "False",
1514+
"reason": "InsufficientPods",
1515+
},
1516+
},
1517+
},
1518+
},
1519+
},
1520+
expected: manifestNotAvailableYetAction,
1521+
err: nil,
1522+
},
14231523
}
1424-
14251524
for name, tt := range tests {
14261525
t.Run(name, func(t *testing.T) {
14271526
action, err := trackResourceAvailability(tt.gvr, tt.obj)

pkg/utils/common.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
batchv1 "k8s.io/api/batch/v1"
1818
corev1 "k8s.io/api/core/v1"
1919
discoveryv1 "k8s.io/api/discovery/v1"
20+
policyv1 "k8s.io/api/policy/v1"
2021
rbacv1 "k8s.io/api/rbac/v1"
2122
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2223
"k8s.io/apimachinery/pkg/api/equality"
@@ -263,6 +264,12 @@ var (
263264
Kind: "Pod",
264265
}
265266

267+
PodDisruptionBudgetGVR = schema.GroupVersionResource{
268+
Group: policyv1.GroupName,
269+
Version: policyv1.SchemeGroupVersion.Version,
270+
Resource: "poddisruptionbudgets",
271+
}
272+
266273
RoleMetaGVK = metav1.GroupVersionKind{
267274
Group: rbacv1.SchemeGroupVersion.Group,
268275
Version: rbacv1.SchemeGroupVersion.Version,

0 commit comments

Comments
 (0)