Skip to content

Commit

Permalink
Add Job support (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
micnncim authored Sep 21, 2020
1 parent 24bd63b commit 8cc52fb
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 42 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

Supported resources:

- [x] Pods (whose status is not `Running`)
- [x] ConfigMaps (not used in any Pods)
- [x] Secrets (not used in any Pods or ServiceAccounts)
- [x] Pods (whose status is not `Running`)
- [x] PersistentVolumes (not satisfying any PersistentVolumeClaims)
- [x] PersistentVolumeClaims (not used in any Pods)
- [x] Jobs (completed)
- [x] PodDisruptionBudgets (not targeting any Pods)
- [x] HorizontalPodAutoscalers (not targeting any resources)

Expand Down Expand Up @@ -123,11 +124,12 @@ $ kubectl prune --help

Delete unused resources. Supported resources:

- Pods (whose status is not Running)
- ConfigMaps (not used in any Pods)
- Secrets (not used in any Pods or ServiceAccounts)
- Pods (whose status is not Running)
- PersistentVolumes (not satisfying any PersistentVolumeClaims)
- PersistentVolumeClaims (not used in any Pods)
- Jobs (completed)
- PodDisruptionBudgets (not targeting any Pods)
- HorizontalPodAutoscalers (not targeting any resources)

Expand Down
25 changes: 13 additions & 12 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ import (
)

const (
pruneShortDescription = `
Delete unused resources. Supported resources:
- Pods (whose status is not Running)
- ConfigMaps (not used in any Pods)
- Secrets (not used in any Pods or ServiceAccounts)
- PersistentVolumes (not satisfying any PersistentVolumeClaims)
- PersistentVolumeClaims (not used in any Pods)
- Jobs (completed)
- PodDisruptionBudgets (not targeting any Pods)
- HorizontalPodAutoscalers (not targeting any resources)
`

pruneExample = `
# Delete ConfigMaps not mounted on any Pods and in the current namespace and context
$ kubectl prune configmaps
Expand All @@ -41,18 +54,6 @@ const (
# Delete Pods whose status is not Running as client-side dry-run
$ kubectl prune po --dry-run=client`

pruneShortDescription = `
Delete unused resources. Supported resources:
- ConfigMaps (not used in any Pods)
- Secrets (not used in any Pods or ServiceAccounts)
- Pods (whose status is not Running)
- PersistentVolumes (not satisfying any PersistentVolumeClaims)
- PersistentVolumeClaims (not used in any Pods)
- PodDisruptionBudgets (not targeting any Pods)
- HorizontalPodAutoscalers (not targeting any resources)
`

// printedOperationTypeDeleted is used when printer outputs the result of operations.
printedOperationTypeDeleted = "deleted"
)
Expand Down
12 changes: 12 additions & 0 deletions pkg/determiner/determiner.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ func (d *determiner) DetermineDeletion(ctx context.Context, info *cliresource.In
case resource.KindPersistentVolumeClaim:
return d.determineDeletionPersistentVolumeClaim(info)

case resource.KindJob:
return d.determineDeletionJob(info)

case resource.KindPodDisruptionBudget:
return d.determineDeletionPodDisruptionBudget(info)

Expand Down Expand Up @@ -169,6 +172,15 @@ func (d *determiner) determineDeletionPersistentVolumeClaim(info *cliresource.In
return !ok, nil
}

func (d *determiner) determineDeletionJob(info *cliresource.Info) (bool, error) {
job, err := resource.ObjectToJob(info.Object)
if err != nil {
return false, err
}

return job.Status.CompletionTime != nil, nil
}

func (d *determiner) determineDeletionPodDisruptionBudget(info *cliresource.Info) (bool, error) {
pdb, err := resource.ObjectToPodDisruptionBudget(info.Object)
if err != nil {
Expand Down
97 changes: 69 additions & 28 deletions pkg/determiner/determiner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package determiner
import (
"context"
"testing"
"time"

"github.com/google/go-cmp/cmp"
appsv1 "k8s.io/api/apps/v1"
autoscalingv1 "k8s.io/api/autoscaling/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -18,17 +20,20 @@ import (

func Test_determiner_DetermineDeletion(t *testing.T) {
const (
fakePod = "fake-pod"
fakeConfigMap = "fake-cm"
fakeSecret = "fake-secret"
fakePod = "fake-pod"
fakePersistentVolumeClaim = "fake-pvc"
fakeJob = "fake-job"
fakePodDisruptionBudget = "fake-pdb"
fakeLabelKey1 = "fake-label1-key"
fakeLabelValue1 = "fake-label1-value"
fakeLabelKey2 = "fake-label2-key"
fakeLabelValue2 = "fake-label2-value"
)

fakeTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)

type fields struct {
usedConfigMaps map[string]struct{}
usedSecrets map[string]struct{}
Expand All @@ -46,6 +51,42 @@ func Test_determiner_DetermineDeletion(t *testing.T) {
want bool
wantErr bool
}{
{
name: "Pod should be deleted when it is not running",
args: args{
info: &cliresource.Info{
Name: fakePod,
Object: &corev1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPod,
},
Status: corev1.PodStatus{
Phase: corev1.PodFailed,
},
},
},
},
want: true,
wantErr: false,
},
{
name: "Pod should not be deleted when it is running",
args: args{
info: &cliresource.Info{
Name: fakePod,
Object: &corev1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPod,
},
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
},
},
},
},
want: false,
wantErr: false,
},
{
name: "ConfigMap should be deleted when it is not used",
args: args{
Expand Down Expand Up @@ -117,16 +158,13 @@ func Test_determiner_DetermineDeletion(t *testing.T) {
wantErr: false,
},
{
name: "Pod should be deleted when it is not running",
name: "PersistentVolumeClaim should be deleted when it is not used",
args: args{
info: &cliresource.Info{
Name: fakePod,
Object: &corev1.Pod{
Name: fakePersistentVolumeClaim,
Object: &corev1.PersistentVolumeClaim{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPod,
},
Status: corev1.PodStatus{
Phase: corev1.PodFailed,
Kind: resource.KindPersistentVolumeClaim,
},
},
},
Expand All @@ -135,16 +173,18 @@ func Test_determiner_DetermineDeletion(t *testing.T) {
wantErr: false,
},
{
name: "Pod should not be deleted when it is running",
name: "PersistentVolumeClaim should not be deleted when it is used",
fields: fields{
usedPersistentVolumes: map[string]struct{}{
fakePersistentVolumeClaim: {},
},
},
args: args{
info: &cliresource.Info{
Name: fakePod,
Object: &corev1.Pod{
Name: fakePersistentVolumeClaim,
Object: &corev1.PersistentVolumeClaim{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPod,
},
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
Kind: resource.KindPersistentVolumeClaim,
},
},
},
Expand All @@ -153,13 +193,18 @@ func Test_determiner_DetermineDeletion(t *testing.T) {
wantErr: false,
},
{
name: "PersistentVolumeClaim should be deleted when it is not used",
name: "Job should be deleted when it is completed",
args: args{
info: &cliresource.Info{
Name: fakePersistentVolumeClaim,
Object: &corev1.PersistentVolumeClaim{
Name: fakeJob,
Object: &batchv1.Job{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPersistentVolumeClaim,
Kind: resource.KindJob,
},
Status: batchv1.JobStatus{
CompletionTime: &metav1.Time{
Time: fakeTime,
},
},
},
},
Expand All @@ -168,19 +213,15 @@ func Test_determiner_DetermineDeletion(t *testing.T) {
wantErr: false,
},
{
name: "PersistentVolumeClaim should not be deleted when it is used",
fields: fields{
usedPersistentVolumes: map[string]struct{}{
fakePersistentVolumeClaim: {},
},
},
name: "Job should not be deleted when it is not completed",
args: args{
info: &cliresource.Info{
Name: fakePersistentVolumeClaim,
Object: &corev1.PersistentVolumeClaim{
Name: fakeJob,
Object: &batchv1.Job{
TypeMeta: metav1.TypeMeta{
Kind: resource.KindPersistentVolumeClaim,
Kind: resource.KindJob,
},
Status: batchv1.JobStatus{},
},
},
},
Expand Down
16 changes: 16 additions & 0 deletions pkg/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package resource

import (
autoscalingv1 "k8s.io/api/autoscaling/v1"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -14,6 +15,7 @@ const (
KindServiceAccount = "ServiceAccount"
KindPersistentVolume = "PersistentVolume"
KindPersistentVolumeClaim = "PersistentVolumeClaim"
KindJob = "Job"
KindPodDisruptionBudget = "PodDisruptionBudget"
KindHorizontalPodAutoscaler = "HorizontalPodAutoscaler"
)
Expand Down Expand Up @@ -48,6 +50,20 @@ func ObjectToPersistentVolume(obj runtime.Object) (*corev1.PersistentVolume, err
return &volume, nil
}

func ObjectToJob(obj runtime.Object) (*batchv1.Job, error) {
u, err := toUnstructured(obj)
if err != nil {
return nil, err
}

var job batchv1.Job
if err := fromUnstructured(u, &job); err != nil {
return nil, err
}

return &job, nil
}

func ObjectToPodDisruptionBudget(obj runtime.Object) (*policyv1beta1.PodDisruptionBudget, error) {
u, err := toUnstructured(obj)
if err != nil {
Expand Down

0 comments on commit 8cc52fb

Please sign in to comment.