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

table_kubernetes_pod_disruption_budget #76

Merged
merged 3 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
40 changes: 40 additions & 0 deletions docs/tables/kubernetes_pod_disruption_budget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Table: kubernetes_pod_disruption_budget

A Pod Disruption Budget (PDB) limits the number of Pods of a replicated application that are down simultaneously from voluntary disruptions.

## Examples

### Basic info

```sql
select
name,
namespace,
min_available,
max_unavailable,
selector
from
kubernetes_pod_disruption_budget
order by
namespace,
name;
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some more example queries around minAvailable/maxUnavailable, for reference you can check this document.

### List deployments and their matching PDB

```sql
select
d.namespace,
d.name,
min_available,
replicas
from
kubernetes_pod_disruption_budget pdb
inner join
kubernetes_deployment d
on d.selector = pdb.selector
and d.namespace = pdb.namespace
order by
d.namespace,
d.name
```
1 change: 1 addition & 0 deletions kubernetes/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"kubernetes_persistent_volume": tableKubernetesPersistentVolume(ctx),
"kubernetes_persistent_volume_claim": tableKubernetesPersistentVolumeClaim(ctx),
"kubernetes_pod": tableKubernetesPod(ctx),
"kubernetes_pod_disruption_budget": tableKubernetesPDB(ctx),
"kubernetes_pod_security_policy": tableKubernetesPodSecurityPolicy(ctx),
"kubernetes_replicaset": tableKubernetesReplicaSet(ctx),
"kubernetes_replication_controller": tableKubernetesReplicaController(ctx),
Expand Down
158 changes: 158 additions & 0 deletions kubernetes/table_kubernetes_pod_disruption_budget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package kubernetes

import (
"context"
"strings"

v1beta1 "k8s.io/api/policy/v1beta1"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/turbot/steampipe-plugin-sdk/v3/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v3/plugin"
"github.com/turbot/steampipe-plugin-sdk/v3/plugin/transform"
)

func tableKubernetesPDB(ctx context.Context) *plugin.Table {
return &plugin.Table{
Name: "kubernetes_pod_disruption_budget",
Description: "A Pod Disruption Budget limits the number of Pods of a replicated application that are down simultaneously from voluntary disruptions.",
Get: &plugin.GetConfig{
KeyColumns: plugin.AllColumns([]string{"name", "namespace"}),
Hydrate: getPDB,
},
List: &plugin.ListConfig{
Hydrate: listPDBs,
KeyColumns: getCommonOptionalKeyQuals(),
bigdatasourav marked this conversation as resolved.
Show resolved Hide resolved
},
Columns: k8sCommonColumns([]*plugin.Column{

// PodDisruptionBudgetSpec
{
Name: "min_available",
Type: proto.ColumnType_STRING,
Description: "An eviction is allowed if at least 'minAvailable' pods selected by 'selector' will still be available after the eviction.",
Transform: transform.FromField("Spec.MinAvailable"),
},
{
Name: "selector",
Type: proto.ColumnType_JSON,
Description: "Label query over pods whose evictions are managed by the disruption budget.",
Transform: transform.FromField("Spec.Selector"),
},
{
Name: "max_unavailable",
Type: proto.ColumnType_STRING,
Description: "An eviction is allowed if at most 'maxAvailable' pods selected by 'selector' will still be unavailable after the eviction.",
Transform: transform.FromField("Spec.MaxUnavailable"),
},

// Steampipe Standard Columns
{
Name: "title",
Type: proto.ColumnType_STRING,
Description: ColumnDescriptionTitle,
Transform: transform.FromField("Name"),
},
{
Name: "tags",
Type: proto.ColumnType_JSON,
Description: ColumnDescriptionTags,
Transform: transform.From(transformPDBTags),
},
}),
}
}

//// HYDRATE FUNCTIONS

func listPDBs(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
logger := plugin.Logger(ctx)
logger.Trace("listPDBs")

clientset, err := GetNewClientset(ctx, d)
if err != nil {
return nil, err
}

input := metav1.ListOptions{
Limit: 500,
}

// Limiting the results
limit := d.QueryContext.Limit
if d.QueryContext.Limit != nil {
if *limit < input.Limit {
if *limit < 1 {
input.Limit = 1
} else {
input.Limit = *limit
}
}
}

commonFieldSelectorValue := getCommonOptionalKeyQualsValueForFieldSelector(d)

if len(commonFieldSelectorValue) > 0 {
input.FieldSelector = strings.Join(commonFieldSelectorValue, ",")
}

var response *v1beta1.PodDisruptionBudgetList
pageLeft := true

for pageLeft {
response, err = clientset.PolicyV1beta1().PodDisruptionBudgets("").List(ctx, input)
if err != nil {
return nil, err
}

if response.GetContinue() != "" {
input.Continue = response.Continue
} else {
pageLeft = false
}

for _, item := range response.Items {
d.StreamListItem(ctx, item)

// Context can be cancelled due to manual cancellation or the limit has been hit
if d.QueryStatus.RowsRemaining(ctx) == 0 {
return nil, nil
}
}
}

return nil, nil
}

func getPDB(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
logger := plugin.Logger(ctx)
logger.Trace("getPDB")

clientset, err := GetNewClientset(ctx, d)
if err != nil {
return nil, err
}

name := d.KeyColumnQuals["name"].GetStringValue()
namespace := d.KeyColumnQuals["namespace"].GetStringValue()

// return if namespace or name is empty
if namespace == "" || name == "" {
return nil, nil
}

pdb, err := clientset.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil && !isNotFoundError(err) {
return nil, err
}

return *pdb, nil
}

//// TRANSFORM FUNCTIONS

func transformPDBTags(_ context.Context, d *transform.TransformData) (interface{}, error) {
obj := d.HydrateItem.(v1beta1.PodDisruptionBudget)
return mergeTags(obj.Labels, obj.Annotations), nil
}
2 changes: 1 addition & 1 deletion kubernetes/table_kubernetes_pod_security_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func listPodSecurityPolicy(ctx context.Context, d *plugin.QueryData, _ *plugin.H

func getPodSecurityPolicy(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
logger := plugin.Logger(ctx)
logger.Trace("getK8sSecret")
logger.Trace("getPodSecurityPolicy")

clientset, err := GetNewClientset(ctx, d)
if err != nil {
Expand Down