Skip to content

Commit

Permalink
Implemented PodDisruptionBudget
Browse files Browse the repository at this point in the history
  • Loading branch information
triceras committed Dec 20, 2024
1 parent d225d9c commit e37ae7c
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 0 deletions.
14 changes: 14 additions & 0 deletions api/v1alpha1/humiocluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ type HumioClusterSpec struct {

// NodePools can be used to define additional groups of Humio cluster pods that share a set of configuration.
NodePools []HumioNodePoolSpec `json:"nodePools,omitempty"`

// PodDisruptionBudget defines the configuration for the PodDisruptionBudget
PodDisruptionBudget *PodDisruptionBudgetSpec `json:"podDisruptionBudget,omitempty"`
}

type HumioNodeSpec struct {
Expand Down Expand Up @@ -451,6 +454,17 @@ type HumioClusterList struct {
Items []HumioCluster `json:"items"`
}

// PodDisruptionBudgetSpec defines the configuration for the PodDisruptionBudget
type PodDisruptionBudgetSpec struct {
// MinAvailable specifies the minimum number of pods that must be available
// +optional
MinAvailable *intstr.IntOrString `json:"minAvailable,omitempty"`

// MaxUnavailable specifies the maximum number of pods that can be unavailable
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
}

// Len is the number of elements in the collection
func (l HumioPodStatusList) Len() int {
return len(l)
Expand Down
30 changes: 30 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions charts/humio-operator/crds/core.humio.com_humioclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13154,6 +13154,25 @@ spec:
description: PodAnnotations can be used to specify annotations that
will be added to the Humio pods
type: object
podDisruptionBudget:
description: PodDisruptionBudget defines the configuration for the
PodDisruptionBudget
properties:
maxUnavailable:
anyOf:
- type: integer
- type: string
description: MaxUnavailable specifies the maximum number of pods
that can be unavailable
x-kubernetes-int-or-string: true
minAvailable:
anyOf:
- type: integer
- type: string
description: MinAvailable specifies the minimum number of pods
that must be available
x-kubernetes-int-or-string: true
type: object
podLabels:
additionalProperties:
type: string
Expand Down
19 changes: 19 additions & 0 deletions config/crd/bases/core.humio.com_humioclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13154,6 +13154,25 @@ spec:
description: PodAnnotations can be used to specify annotations that
will be added to the Humio pods
type: object
podDisruptionBudget:
description: PodDisruptionBudget defines the configuration for the
PodDisruptionBudget
properties:
maxUnavailable:
anyOf:
- type: integer
- type: string
description: MaxUnavailable specifies the maximum number of pods
that can be unavailable
x-kubernetes-int-or-string: true
minAvailable:
anyOf:
- type: integer
- type: string
description: MinAvailable specifies the minimum number of pods
that must be available
x-kubernetes-int-or-string: true
type: object
podLabels:
additionalProperties:
type: string
Expand Down
36 changes: 36 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ kind: ClusterRole
metadata:
name: manager-role
rules:
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -436,3 +448,27 @@ rules:
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- policy
resources:
- poddisruptionbudgets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
91 changes: 91 additions & 0 deletions controllers/humiocluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ import (
"github.com/humio/humio-operator/internal/kubernetes"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
policyv1 "k8s.io/api/policy/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/utils/strings/slices"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand Down Expand Up @@ -79,6 +82,9 @@ const (
//+kubebuilder:rbac:groups=core,resources=secrets,verbs=create;delete;get;list;patch;update;watch
//+kubebuilder:rbac:groups=core,resources=serviceaccounts,verbs=create;delete;get;list;patch;update;watch
//+kubebuilder:rbac:groups=networking.k8s.io,resources=ingress,verbs=create;delete;get;list;patch;update;watch
//+kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses,verbs=get;list;watch;create;update;patch;delete

func (r *HumioClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// when running tests, ignore resources that are not in the correct namespace
Expand Down Expand Up @@ -306,6 +312,13 @@ func (r *HumioClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request
return result, err
}

// Set podDisruptionBudget
if err = r.reconcilePodDisruptionBudget(ctx, hc); err != nil {
return r.updateStatus(ctx, r.Client.Status(), hc, statusOptions().
withMessage(r.logErrorAndReturn(err, "unable to set pod disruption budget").Error()),
)
}

r.Log.Info("done reconciling")
return r.updateStatus(ctx, r.Client.Status(), hc, statusOptions().withState(hc.Status.State).withMessage(""))
}
Expand All @@ -321,6 +334,7 @@ func (r *HumioClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
Owns(&corev1.PersistentVolumeClaim{}).
Owns(&corev1.ConfigMap{}).
Owns(&networkingv1.Ingress{}).
Owns(&policyv1.PodDisruptionBudget{}).
Complete(r)
}

Expand Down Expand Up @@ -2349,3 +2363,80 @@ func getHumioNodePoolManagers(hc *humiov1alpha1.HumioCluster) HumioNodePoolList
}
return humioNodePools
}

// podLabelsForHumio returns the labels for selecting the resources
// belonging to the given humioCluster CR name.
func (r *HumioClusterReconciler) podLabelsForHumio(name string) map[string]string {
return map[string]string{"app": "humio", "humio_cr": name}
}

func (r *HumioClusterReconciler) reconcilePodDisruptionBudget(ctx context.Context, humioCluster *humiov1alpha1.HumioCluster) error {
// Define the desired PodDisruptionBudget object
pdb := &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: humioCluster.Name + "-pdb", // Or a more suitable name
Namespace: humioCluster.Namespace,
Labels: r.podLabelsForHumio(humioCluster.Name), // Make sure labels are correct
},
Spec: policyv1.PodDisruptionBudgetSpec{
Selector: &metav1.LabelSelector{
MatchLabels: r.podLabelsForHumio(humioCluster.Name),
},
},
}

// Set the MinAvailable or MaxUnavailable value
if humioCluster.Spec.PodDisruptionBudget != nil {
if humioCluster.Spec.PodDisruptionBudget.MinAvailable != nil {
pdb.Spec.MinAvailable = humioCluster.Spec.PodDisruptionBudget.MinAvailable
} else if humioCluster.Spec.PodDisruptionBudget.MaxUnavailable != nil {
pdb.Spec.MaxUnavailable = humioCluster.Spec.PodDisruptionBudget.MaxUnavailable
}
} else {
// Set default values if not specified in the CR
defaultMinAvailable := intstr.FromInt(2) // Example default: at least 2 pods available
pdb.Spec.MinAvailable = &defaultMinAvailable
}

// Check if the PodDisruptionBudget already exists
foundPdb := &policyv1.PodDisruptionBudget{}
err := r.Client.Get(ctx, types.NamespacedName{Name: pdb.Name, Namespace: pdb.Namespace}, foundPdb)
if err != nil && k8serrors.IsNotFound(err) {
// Create the PodDisruptionBudget
r.Log.Info("Creating a new PodDisruptionBudget", "PDB.Namespace", pdb.Namespace, "PDB.Name", pdb.Name)
err = r.Client.Create(ctx, pdb)
if err != nil {
return err
}
return nil
} else if err != nil {
return err
}

// Update the PodDisruptionBudget if it exists and needs updating
if humioCluster.Spec.PodDisruptionBudget != nil {
if needsPDBUpdate(foundPdb, pdb) {
foundPdb.Spec = pdb.Spec
r.Log.Info("Updating PodDisruptionBudget", "PDB.Namespace", foundPdb.Namespace, "PDB.Name", foundPdb.Name)
err = r.Client.Update(ctx, foundPdb)
if err != nil {
return err
}
}
}
return nil
}

func needsPDBUpdate(current, desired *policyv1.PodDisruptionBudget) bool {
if current.Spec.MinAvailable != nil && desired.Spec.MinAvailable != nil {
if current.Spec.MinAvailable.String() != desired.Spec.MinAvailable.String() {
return true
}
}
if current.Spec.MaxUnavailable != nil && desired.Spec.MaxUnavailable != nil {
if current.Spec.MaxUnavailable.String() != desired.Spec.MaxUnavailable.String() {
return true
}
}
return false
}
Loading

0 comments on commit e37ae7c

Please sign in to comment.