From d83e5997325bca0eb409d1ec1247cd2a93e5cc3b Mon Sep 17 00:00:00 2001 From: Joachim Bartosik Date: Mon, 14 Oct 2024 13:53:13 +0100 Subject: [PATCH] Adding PDB NOTE: not adding yaml - all the yaml fields are marked as obsolete and we now have a dedicated pipeline for yamls so I presume there is no need to add the field --- .../collectors/inventory/inventory.go | 1 + .../collectors/k8s/poddisruptionbudget.go | 95 +++++ .../processors/k8s/poddisruptionbudget.go | 90 +++++ .../transformers/k8s/poddisruptionbudget.go | 101 +++++ .../k8s/poddisruptionbudget_test.go | 368 ++++++++++++++++++ pkg/orchestrator/aliases.go | 2 + pkg/orchestrator/model/types.go | 37 +- 7 files changed, 678 insertions(+), 16 deletions(-) create mode 100644 pkg/collector/corechecks/cluster/orchestrator/collectors/k8s/poddisruptionbudget.go create mode 100644 pkg/collector/corechecks/cluster/orchestrator/processors/k8s/poddisruptionbudget.go create mode 100644 pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget.go create mode 100644 pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget_test.go diff --git a/pkg/collector/corechecks/cluster/orchestrator/collectors/inventory/inventory.go b/pkg/collector/corechecks/cluster/orchestrator/collectors/inventory/inventory.go index 7afb23461e5b27..5f6d0a849441fe 100644 --- a/pkg/collector/corechecks/cluster/orchestrator/collectors/inventory/inventory.go +++ b/pkg/collector/corechecks/cluster/orchestrator/collectors/inventory/inventory.go @@ -43,6 +43,7 @@ func NewCollectorInventory(cfg config.Component, store workloadmeta.Component) * k8sCollectors.NewNodeCollectorVersions(), k8sCollectors.NewPersistentVolumeClaimCollectorVersions(), k8sCollectors.NewPersistentVolumeCollectorVersions(), + k8sCollectors.NewPodDisruptionBudgetCollectorVersions(), k8sCollectors.NewReplicaSetCollectorVersions(), k8sCollectors.NewRoleBindingCollectorVersions(), k8sCollectors.NewRoleCollectorVersions(), diff --git a/pkg/collector/corechecks/cluster/orchestrator/collectors/k8s/poddisruptionbudget.go b/pkg/collector/corechecks/cluster/orchestrator/collectors/k8s/poddisruptionbudget.go new file mode 100644 index 00000000000000..5f410f1e9c0b8c --- /dev/null +++ b/pkg/collector/corechecks/cluster/orchestrator/collectors/k8s/poddisruptionbudget.go @@ -0,0 +1,95 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +//go:build kubeapiserver && orchestrator + +package k8s + +import ( + "k8s.io/apimachinery/pkg/labels" + v1policyinformer "k8s.io/client-go/informers/policy/v1" + v1policylister "k8s.io/client-go/listers/policy/v1" + "k8s.io/client-go/tools/cache" + + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/collectors" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/processors" + k8sProcessors "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/processors/k8s" + "github.com/DataDog/datadog-agent/pkg/orchestrator" +) + +// NewPodDisruptionBudgetCollectorVersions builds the group of collector versions. +func NewPodDisruptionBudgetCollectorVersions() collectors.CollectorVersions { + return collectors.NewCollectorVersions( + NewPodDisruptionBudgetCollectorVersion(), + ) +} + +// PodDisruptionBudgetCollector is a collector for Kubernetes Pod Disruption Budgets. +type PodDisruptionBudgetCollector struct { + informer v1policyinformer.PodDisruptionBudgetInformer + lister v1policylister.PodDisruptionBudgetLister + metadata *collectors.CollectorMetadata + processor *processors.Processor +} + +// NewPodDisruptionBudgetCollectorVersion creates a new collector for the Kubernetes Pod Disruption Budget +// resource. +func NewPodDisruptionBudgetCollectorVersion() *PodDisruptionBudgetCollector { + return &PodDisruptionBudgetCollector{ + informer: nil, + lister: nil, + metadata: &collectors.CollectorMetadata{ + IsDefaultVersion: true, + IsStable: true, + IsMetadataProducer: true, + IsManifestProducer: true, + SupportsManifestBuffering: true, + Name: "poddisruptionbudgets", + NodeType: orchestrator.K8sPodDisruptionBudget, + Version: "policy/v1", + }, + processor: processors.NewProcessor(new(k8sProcessors.PodDisruptionBudgetHandlers)), + } +} + +// Informer returns the shared informer. +func (c *PodDisruptionBudgetCollector) Informer() cache.SharedInformer { + return c.informer.Informer() +} + +// Init is used to initialize the collector. +func (c *PodDisruptionBudgetCollector) Init(rcfg *collectors.CollectorRunConfig) { + c.informer = rcfg.OrchestratorInformerFactory.InformerFactory.Policy().V1().PodDisruptionBudgets() + c.lister = c.informer.Lister() +} + +// Metadata is used to access information about the collector. +func (c *PodDisruptionBudgetCollector) Metadata() *collectors.CollectorMetadata { + return c.metadata +} + +// Run triggers the collection process. +func (c *PodDisruptionBudgetCollector) Run(rcfg *collectors.CollectorRunConfig) (*collectors.CollectorRunResult, error) { + list, err := c.lister.List(labels.Everything()) + if err != nil { + return nil, collectors.NewListingError(err) + } + + ctx := collectors.NewK8sProcessorContext(rcfg, c.metadata) + + processResult, processed := c.processor.Process(ctx, list) + + if processed == -1 { + return nil, collectors.ErrProcessingPanic + } + + result := &collectors.CollectorRunResult{ + Result: processResult, + ResourcesListed: len(list), + ResourcesProcessed: processed, + } + + return result, nil +} diff --git a/pkg/collector/corechecks/cluster/orchestrator/processors/k8s/poddisruptionbudget.go b/pkg/collector/corechecks/cluster/orchestrator/processors/k8s/poddisruptionbudget.go new file mode 100644 index 00000000000000..3dc6fdb8373581 --- /dev/null +++ b/pkg/collector/corechecks/cluster/orchestrator/processors/k8s/poddisruptionbudget.go @@ -0,0 +1,90 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +//go:build orchestrator + +package k8s + +import ( + model "github.com/DataDog/agent-payload/v5/process" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/processors" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/processors/common" + k8sTransformers "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s" + "github.com/DataDog/datadog-agent/pkg/orchestrator/redact" + + policyv1 "k8s.io/api/policy/v1" + "k8s.io/apimachinery/pkg/types" +) + +// PodDisruptionBudgetHandlers implements the Handlers interface for Kubernetes NetworkPolicy. +type PodDisruptionBudgetHandlers struct { + common.BaseHandlers +} + +// AfterMarshalling is a handler called after resource marshalling. +func (h *PodDisruptionBudgetHandlers) AfterMarshalling(_ processors.ProcessorContext, _, _ interface{}, _ []byte) (skip bool) { + return +} + +// BuildMessageBody is a handler called to build a message body out of a list of +// extracted resources. +func (h *PodDisruptionBudgetHandlers) BuildMessageBody(ctx processors.ProcessorContext, resourceModels []interface{}, groupSize int) model.MessageBody { + pctx := ctx.(*processors.K8sProcessorContext) + models := make([]*model.PodDisruptionBudget, 0, len(resourceModels)) + + for _, m := range resourceModels { + models = append(models, m.(*model.PodDisruptionBudget)) + } + + return &model.CollectorPodDisruptionBudget{ + ClusterName: pctx.Cfg.KubeClusterName, + ClusterId: pctx.ClusterID, + GroupId: pctx.MsgGroupID, + GroupSize: int32(groupSize), + PodDisruptionBudgets: models, + Tags: append(pctx.Cfg.ExtraTags, pctx.ApiGroupVersionTag), + } +} + +// ExtractResource is a handler called to extract the resource model out of a raw resource. +func (h *PodDisruptionBudgetHandlers) ExtractResource(_ processors.ProcessorContext, resource interface{}) (resourceModel interface{}) { + r := resource.(*policyv1.PodDisruptionBudget) + return k8sTransformers.ExtractPodDisruptionBudget(r) +} + +// ResourceList is a handler called to convert a list passed as a generic +// interface to a list of generic interfaces. +func (h *PodDisruptionBudgetHandlers) ResourceList(_ processors.ProcessorContext, list interface{}) (resources []interface{}) { + resourceList := list.([]*policyv1.PodDisruptionBudget) + resources = make([]interface{}, 0, len(resourceList)) + + for _, resource := range resourceList { + resources = append(resources, resource) + } + + return resources +} + +// ResourceUID is a handler called to retrieve the resource UID. +func (h *PodDisruptionBudgetHandlers) ResourceUID(_ processors.ProcessorContext, resource interface{}) types.UID { + return resource.(*policyv1.PodDisruptionBudget).UID +} + +// ResourceVersion is a handler called to retrieve the resource version. +func (h *PodDisruptionBudgetHandlers) ResourceVersion(_ processors.ProcessorContext, resource, _ interface{}) string { + return resource.(*policyv1.PodDisruptionBudget).ResourceVersion +} + +// ScrubBeforeExtraction is a handler called to redact the raw resource before +// it is extracted as an internal resource model. +func (h *PodDisruptionBudgetHandlers) ScrubBeforeExtraction(_ processors.ProcessorContext, resource interface{}) { + r := resource.(*policyv1.PodDisruptionBudget) + redact.RemoveSensitiveAnnotationsAndLabels(r.Annotations, r.Labels) +} + +// ScrubBeforeMarshalling is a handler called to redact the raw resource before +// it is marshalled to generate a manifest. +func (h *PodDisruptionBudgetHandlers) ScrubBeforeMarshalling(_ processors.ProcessorContext, _ interface{}) { +} diff --git a/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget.go b/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget.go new file mode 100644 index 00000000000000..3838c30ef0f7fa --- /dev/null +++ b/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget.go @@ -0,0 +1,101 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +//go:build orchestrator + +package k8s + +import ( + model "github.com/DataDog/agent-payload/v5/process" + "github.com/DataDog/datadog-agent/pkg/collector/corechecks/cluster/orchestrator/transformers" + + policyv1 "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// ExtractPodDisruptionBudget returns the protobuf model corresponding to a Kubernetes +func ExtractPodDisruptionBudget(pdb *policyv1.PodDisruptionBudget) *model.PodDisruptionBudget { + if pdb == nil { + return nil + } + result := model.PodDisruptionBudget{ + Metadata: extractMetadata(&pdb.ObjectMeta), + Spec: extractPodDisruptionBudgetSpec(&pdb.Spec), + Status: extractPodDisruptionBudgetStatus(&pdb.Status), + } + result.Tags = append(result.Tags, transformers.RetrieveUnifiedServiceTags(pdb.ObjectMeta.Labels)...) + return &result +} + +func extractPodDisruptionBudgetSpec(spec *policyv1.PodDisruptionBudgetSpec) *model.PodDisruptionBudgetSpec { + if spec == nil { + return nil + } + result := model.PodDisruptionBudgetSpec{} + result.MinAvailable = extractIntOrString(spec.MinAvailable) + if spec.Selector != nil { + result.Selector = extractLabelSelector(spec.Selector) + } + result.MaxUnavailable = extractIntOrString(spec.MaxUnavailable) + if spec.UnhealthyPodEvictionPolicy != nil { + result.UnhealthyPodEvictionPolicy = string(*spec.UnhealthyPodEvictionPolicy) + } + return &result +} + +func extractIntOrString(source *intstr.IntOrString) *model.IntOrString { + if source == nil { + return nil + } + switch source.Type { + case intstr.Int: + return &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: source.IntVal, + } + case intstr.String: + return &model.IntOrString{ + Type: model.IntOrString_String, + StrVal: source.StrVal, + } + } + return nil +} + +func extractPodDisruptionBudgetStatus(status *policyv1.PodDisruptionBudgetStatus) *model.PodDisruptionBudgetStatus { + if status == nil { + return nil + } + return &model.PodDisruptionBudgetStatus{ + DisruptedPods: extractDisruptedPods(status.DisruptedPods), + DisruptionsAllowed: status.DisruptionsAllowed, + CurrentHealthy: status.CurrentHealthy, + DesiredHealthy: status.DesiredHealthy, + ExpectedPods: status.ExpectedPods, + Conditions: extractPodDisruptionBudgetConditions(status.Conditions), + } +} + +func extractDisruptedPods(disruptedPodsmap map[string]metav1.Time) map[string]int64 { + result := make(map[string]int64) + for pod, t := range disruptedPodsmap { + result[pod] = t.Time.Unix() + } + return result +} +func extractPodDisruptionBudgetConditions(conditions []metav1.Condition) []*model.Condition { + result := make([]*model.Condition, 0) + for _, condition := range conditions { + result = append(result, &model.Condition{ + Type: condition.Type, + Status: string(condition.Status), + LastTransitionTime: condition.LastTransitionTime.Time.Unix(), + Reason: condition.Reason, + Message: condition.Message, + }) + } + return result +} diff --git a/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget_test.go b/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget_test.go new file mode 100644 index 00000000000000..79bdbb8516c8f5 --- /dev/null +++ b/pkg/collector/corechecks/cluster/orchestrator/transformers/k8s/poddisruptionbudget_test.go @@ -0,0 +1,368 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024-present Datadog, Inc. + +//go:build orchestrator + +package k8s + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + model "github.com/DataDog/agent-payload/v5/process" + "github.com/DataDog/datadog-agent/pkg/util/kubernetes" + + policyv1 "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +func TestExtractIntOrString(t *testing.T) { + iVal := int32(95) + sVal := "reshape" + iOS95 := intstr.FromInt32(iVal) + iOSStr := intstr.FromString(sVal) + for name, tc := range map[string]struct { + in *intstr.IntOrString + expect *model.IntOrString + }{ + "nil": { + in: nil, + expect: nil, + }, + "int": { + in: &iOS95, + expect: &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: iVal, + }, + }, + "str": { + in: &iOSStr, + expect: &model.IntOrString{ + Type: model.IntOrString_String, + StrVal: sVal, + }, + }, + "empty": { + in: &intstr.IntOrString{}, + expect: &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: 0, + }, + }, + "unknown": { + in: &intstr.IntOrString{ + Type: intstr.Type(95), + }, + expect: nil, + }, + } { + t.Run(name, func(t *testing.T) { + got := extractIntOrString(tc.in) + if tc.expect == nil { + assert.Nil(t, got) + } else { + assert.Equal(t, tc.expect, got) + } + }) + } +} + +func TestExtractPodDisruptionBudgetSpec(t *testing.T) { + iVal1 := int32(95) + iVal2 := int32(99) + iOS1 := intstr.FromInt32(iVal1) + iOS2 := intstr.FromInt32(iVal2) + var labels = map[string]string{"reshape": "all"} + + sVal1 := "110%" + sVal2 := "111%" + iOS3 := intstr.FromString(sVal1) + iOS4 := intstr.FromString(sVal2) + + ePolicy := policyv1.AlwaysAllow + + for name, tc := range map[string]struct { + in *policyv1.PodDisruptionBudgetSpec + expect *model.PodDisruptionBudgetSpec + }{ + "nil": { + in: nil, + expect: nil, + }, + "allInts": { + in: &policyv1.PodDisruptionBudgetSpec{ + MinAvailable: &iOS1, + MaxUnavailable: &iOS2, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + }, + expect: &model.PodDisruptionBudgetSpec{ + MinAvailable: &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: iVal1, + }, + MaxUnavailable: &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: iVal2, + }, + Selector: []*model.LabelSelectorRequirement{ + { + Key: "reshape", + Operator: "In", + Values: []string{"all"}, + }, + }, + }, + }, + "allStrings": { + in: &policyv1.PodDisruptionBudgetSpec{ + MinAvailable: &iOS3, + MaxUnavailable: &iOS4, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + UnhealthyPodEvictionPolicy: &ePolicy, + }, + expect: &model.PodDisruptionBudgetSpec{ + MinAvailable: &model.IntOrString{ + Type: model.IntOrString_String, + StrVal: sVal1, + }, + MaxUnavailable: &model.IntOrString{ + Type: model.IntOrString_String, + StrVal: sVal2, + }, + Selector: []*model.LabelSelectorRequirement{ + { + Key: "reshape", + Operator: "In", + Values: []string{"all"}, + }, + }, + UnhealthyPodEvictionPolicy: string(policyv1.AlwaysAllow), + }, + }, + } { + t.Run(name, func(t *testing.T) { + got := extractPodDisruptionBudgetSpec(tc.in) + if tc.expect == nil { + assert.Nil(t, got) + } else { + assert.Equal(t, tc.expect, got) + } + }) + } +} + +func TestExtractPodDisruptionBudget(t *testing.T) { + iVal := int32(95) + sVal := "reshape" + iOSI := intstr.FromInt32(iVal) + iOSS := intstr.FromString(sVal) + var labels = map[string]string{"reshape": "all"} + ePolicy := policyv1.AlwaysAllow + + t0 := time.Now() + t1 := t0.Add(time.Minute) + + for name, tc := range map[string]struct { + in *policyv1.PodDisruptionBudget + expect *model.PodDisruptionBudget + }{ + "nil": { + in: nil, + expect: nil, + }, + "empty": { + in: &policyv1.PodDisruptionBudget{}, + expect: &model.PodDisruptionBudget{ + Metadata: &model.Metadata{ + Name: "", + Namespace: "", + Uid: "", + CreationTimestamp: 0, + DeletionTimestamp: 0, + }, + Spec: &model.PodDisruptionBudgetSpec{ + UnhealthyPodEvictionPolicy: "", + }, + Status: &model.PodDisruptionBudgetStatus{ + DisruptedPods: map[string]int64{}, + Conditions: []*model.Condition{}, + }, + }, + }, + "full": { + in: &policyv1.PodDisruptionBudget{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gwern", + Namespace: "kog", + UID: "513", + ResourceVersion: "platinum", + Labels: map[string]string{ + kubernetes.VersionTagLabelKey: "ultimate", + kubernetes.ServiceTagLabelKey: "honorable", + }, + }, + Spec: policyv1.PodDisruptionBudgetSpec{ + MinAvailable: &iOSI, + MaxUnavailable: &iOSS, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + UnhealthyPodEvictionPolicy: &ePolicy, + }, + Status: policyv1.PodDisruptionBudgetStatus{ + ObservedGeneration: 3, + DisruptedPods: map[string]metav1.Time{"liborio": metav1.NewTime(t0)}, + DisruptionsAllowed: 4, + CurrentHealthy: 5, + DesiredHealthy: 6, + ExpectedPods: 7, + Conditions: []metav1.Condition{ + { + Type: "regular", + Status: metav1.ConditionUnknown, + ObservedGeneration: 2, + LastTransitionTime: metav1.NewTime(t1), + Reason: "why not", + Message: "instant", + }, + }, + }, + }, + expect: &model.PodDisruptionBudget{ + Metadata: &model.Metadata{ + Name: "gwern", + Namespace: "kog", + Uid: "513", + ResourceVersion: "platinum", + CreationTimestamp: 0, + DeletionTimestamp: 0, + Labels: []string{ + fmt.Sprintf("%s:ultimate", kubernetes.VersionTagLabelKey), + fmt.Sprintf("%s:honorable", kubernetes.ServiceTagLabelKey), + }, + }, + Spec: &model.PodDisruptionBudgetSpec{ + MinAvailable: &model.IntOrString{ + Type: model.IntOrString_Int, + IntVal: iVal, + }, + MaxUnavailable: &model.IntOrString{ + Type: model.IntOrString_String, + StrVal: sVal, + }, + Selector: []*model.LabelSelectorRequirement{ + { + Key: sVal, + Operator: "In", + Values: []string{"all"}, + }, + }, + UnhealthyPodEvictionPolicy: string(ePolicy), + }, + Status: &model.PodDisruptionBudgetStatus{ + DisruptedPods: map[string]int64{"liborio": t0.Unix()}, + DisruptionsAllowed: 4, + CurrentHealthy: 5, + DesiredHealthy: 6, + ExpectedPods: 7, + Conditions: []*model.Condition{ + { + Type: "regular", + Status: string(metav1.ConditionUnknown), + LastTransitionTime: t1.Unix(), + Reason: "why not", + Message: "instant", + }, + }, + }, + Tags: []string{ + "version:ultimate", + "service:honorable", + }, + }, + }, + } { + t.Run(name, func(t *testing.T) { + got := ExtractPodDisruptionBudget(tc.in) + if tc.expect == nil { + assert.Nil(t, got) + } else { + assert.Equal(t, tc.expect, got) + } + }) + } +} + +func TestExtractExtractPodDisruptionBudgetStatus(t *testing.T) { + for name, tc := range map[string]struct { + in *policyv1.PodDisruptionBudgetStatus + expect *model.PodDisruptionBudgetStatus + }{ + "nil": { + in: nil, + expect: nil, + }, + "empty": { + in: &policyv1.PodDisruptionBudgetStatus{}, + expect: &model.PodDisruptionBudgetStatus{ + Conditions: []*model.Condition{}, + DisruptedPods: map[string]int64{}, + }, + }, + "full": { + in: &policyv1.PodDisruptionBudgetStatus{ + DisruptedPods: map[string]metav1.Time{"liborio": metav1.NewTime(time.Now())}, + DisruptionsAllowed: 4, + CurrentHealthy: 5, + DesiredHealthy: 6, + ExpectedPods: 7, + Conditions: []metav1.Condition{ + { + Type: "regular", + Status: metav1.ConditionUnknown, + ObservedGeneration: 2, + LastTransitionTime: metav1.NewTime(time.Now()), + Reason: "why not", + Message: "instant", + }, + }, + }, + expect: &model.PodDisruptionBudgetStatus{ + DisruptedPods: map[string]int64{"liborio": time.Now().Unix()}, + DisruptionsAllowed: 4, + CurrentHealthy: 5, + DesiredHealthy: 6, + ExpectedPods: 7, + Conditions: []*model.Condition{ + { + Type: "regular", + Status: string(metav1.ConditionUnknown), + LastTransitionTime: time.Now().Unix(), + Reason: "why not", + Message: "instant", + }, + }, + }, + }, + } { + t.Run(name, func(t *testing.T) { + got := extractPodDisruptionBudgetStatus(tc.in) + if tc.expect == nil { + assert.Nil(t, got) + } else { + assert.Equal(t, tc.expect, got) + } + }) + } +} diff --git a/pkg/orchestrator/aliases.go b/pkg/orchestrator/aliases.go index e7113276ab834f..efc5574aa3e1cd 100644 --- a/pkg/orchestrator/aliases.go +++ b/pkg/orchestrator/aliases.go @@ -83,6 +83,8 @@ const ( K8sLimitRange = pkgorchestratormodel.K8sLimitRange // K8sStorageClass alias for pkgorchestratormodel.K8sStorageClass K8sStorageClass = pkgorchestratormodel.K8sStorageClass + // K8sPodDisruptionBudget alias for pkgorchestratormodel.K8sPodDisruptionBudget + K8sPodDisruptionBudget = pkgorchestratormodel.K8sPodDisruptionBudget // ECSTask alias for pkgorchestratormodel.ECSTask ECSTask = pkgorchestratormodel.ECSTask ) diff --git a/pkg/orchestrator/model/types.go b/pkg/orchestrator/model/types.go index b06aca75840038..b8046b5ab73afa 100644 --- a/pkg/orchestrator/model/types.go +++ b/pkg/orchestrator/model/types.go @@ -83,6 +83,8 @@ const ( K8sLimitRange = 25 // K8sStorageClass represents a Kubernetes StorageClass K8sStorageClass = 26 + // K8sPodDisruptionBudget represents a Kubernetes PodDisruptionBudget + K8sPodDisruptionBudget = 27 // ECSTask represents an ECS Task ECSTask = 150 ) @@ -90,33 +92,34 @@ const ( // NodeTypes returns the current existing NodesTypes as a slice to iterate over. func NodeTypes() []NodeType { return []NodeType{ + ECSTask, + K8sCR, + K8sCRD, K8sCluster, + K8sClusterRole, + K8sClusterRoleBinding, K8sCronJob, - K8sDeployment, K8sDaemonSet, + K8sDeployment, + K8sHorizontalPodAutoscaler, + K8sIngress, K8sJob, + K8sLimitRange, + K8sNamespace, + K8sNetworkPolicy, K8sNode, + K8sPersistentVolume, + K8sPersistentVolumeClaim, K8sPod, + K8sPodDisruptionBudget, K8sReplicaSet, - K8sService, - K8sStatefulSet, - K8sPersistentVolumeClaim, - K8sPersistentVolume, K8sRole, K8sRoleBinding, - K8sClusterRole, - K8sClusterRoleBinding, + K8sService, K8sServiceAccount, - K8sIngress, - K8sNamespace, - K8sCR, - K8sCRD, - K8sVerticalPodAutoscaler, - K8sHorizontalPodAutoscaler, - K8sNetworkPolicy, - K8sLimitRange, + K8sStatefulSet, K8sStorageClass, - ECSTask, + K8sVerticalPodAutoscaler, } } @@ -178,6 +181,8 @@ func (n NodeType) String() string { return "UnsetType" case ECSTask: return "ECSTask" + case K8sPodDisruptionBudget: + return "PodDisruptionBudget" default: _ = log.Errorf("Trying to convert unknown NodeType iota: %d", n) return "Unknown"