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

Implemented PodDisruptionBudget #896

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
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
triceras marked this conversation as resolved.
Show resolved Hide resolved
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) {
bsocaciu marked this conversation as resolved.
Show resolved Hide resolved
// 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
Loading