forked from yonahd/kor
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add jobs cleaner * chore: go vet thing * fix: rename variable name --------- Co-authored-by: liumengna <[email protected]>
- Loading branch information
1 parent
95fda98
commit 6ee6450
Showing
8 changed files
with
272 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package kor | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/yonahd/kor/pkg/kor" | ||
"github.com/yonahd/kor/pkg/utils" | ||
) | ||
|
||
var jobCmd = &cobra.Command{ | ||
Use: "job", | ||
Aliases: []string{"job", "jobs"}, | ||
Short: "Gets unused jobs", | ||
Args: cobra.ExactArgs(0), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
clientset := kor.GetKubeClient(kubeconfig) | ||
if response, err := kor.GetUnusedJobs(includeExcludeLists, filterOptions, clientset, outputFormat, opts); err != nil { | ||
fmt.Println(err) | ||
} else { | ||
utils.PrintLogo(outputFormat) | ||
fmt.Println(response) | ||
} | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(jobCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package kor | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes" | ||
"os" | ||
) | ||
|
||
func ProcessNamespaceJobs(clientset kubernetes.Interface, namespace string, filterOpts *FilterOptions) ([]string, error) { | ||
jobsList, err := clientset.BatchV1().Jobs(namespace).List(context.TODO(), metav1.ListOptions{}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var unusedJobNames []string | ||
|
||
for _, job := range jobsList.Items { | ||
if job.Labels["kor/used"] == "true" { | ||
continue | ||
} | ||
|
||
// checks if the resource has any labels that match the excluded selector specified in opts.ExcludeLabels. | ||
// If it does, the resource is skipped. | ||
if excluded, _ := HasExcludedLabel(job.Labels, filterOpts.ExcludeLabels); excluded { | ||
continue | ||
} | ||
// checks if the resource's age (measured from its last modified time) matches the included criteria | ||
// specified by the filter options. | ||
if included, _ := HasIncludedAge(job.CreationTimestamp, filterOpts); !included { | ||
continue | ||
} | ||
|
||
// if the job has completionTime and succeeded count greater than zero, think the job is completed | ||
if job.Status.CompletionTime != nil && job.Status.Succeeded > 0 { | ||
unusedJobNames = append(unusedJobNames, job.Name) | ||
} | ||
} | ||
|
||
return unusedJobNames, nil | ||
} | ||
|
||
func GetUnusedJobs(includeExcludeLists IncludeExcludeLists, filterOpts *FilterOptions, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) { | ||
var outputBuffer bytes.Buffer | ||
namespaces := SetNamespaceList(includeExcludeLists, clientset) | ||
response := make(map[string]map[string][]string) | ||
|
||
for _, namespace := range namespaces { | ||
diff, err := ProcessNamespaceJobs(clientset, namespace, filterOpts) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to process namespace %s: %v\n", namespace, err) | ||
continue | ||
} | ||
|
||
if opts.DeleteFlag { | ||
if diff, err = DeleteResource(diff, clientset, namespace, "Job", opts.NoInteractive); err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to delete Job %s in namespace %s: %v\n", diff, namespace, err) | ||
} | ||
} | ||
output := FormatOutput(namespace, diff, "Job", opts) | ||
if output != "" { | ||
outputBuffer.WriteString(output) | ||
outputBuffer.WriteString("\n") | ||
|
||
resourceMap := make(map[string][]string) | ||
resourceMap["Jobs"] = diff | ||
response[namespace] = resourceMap | ||
} | ||
} | ||
|
||
jsonResponse, err := json.MarshalIndent(response, "", " ") | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
unusedJobs, err := unusedResourceFormatter(outputFormat, outputBuffer, opts, jsonResponse) | ||
if err != nil { | ||
fmt.Printf("err: %v\n", err) | ||
} | ||
|
||
return unusedJobs, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package kor | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
appsv1 "k8s.io/api/apps/v1" | ||
batchv1 "k8s.io/api/batch/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/client-go/kubernetes/fake" | ||
"k8s.io/client-go/kubernetes/scheme" | ||
"reflect" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func createTestJobs(t *testing.T) *fake.Clientset { | ||
clientset := fake.NewSimpleClientset() | ||
|
||
_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ | ||
ObjectMeta: v1.ObjectMeta{Name: testNamespace}, | ||
}, v1.CreateOptions{}) | ||
|
||
if err != nil { | ||
t.Fatalf("Error creating namespace %s: %v", testNamespace, err) | ||
} | ||
|
||
job1 := CreateTestJob(testNamespace, "test-job1", &batchv1.JobStatus{ | ||
Succeeded: 0, | ||
Failed: 1, | ||
}) | ||
job2 := CreateTestJob(testNamespace, "test-job2", &batchv1.JobStatus{ | ||
Succeeded: 1, | ||
Failed: 0, | ||
CompletionTime: &v1.Time{Time: time.Now()}, | ||
}) | ||
|
||
_, err = clientset.BatchV1().Jobs(testNamespace).Create(context.TODO(), job1, v1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating fake job: %v", err) | ||
} | ||
|
||
_, err = clientset.BatchV1().Jobs(testNamespace).Create(context.TODO(), job2, v1.CreateOptions{}) | ||
if err != nil { | ||
t.Fatalf("Error creating fake job: %v", err) | ||
} | ||
return clientset | ||
} | ||
|
||
func TestProcessNamespaceJobs(t *testing.T) { | ||
clientset := createTestJobs(t) | ||
|
||
completedJobs, err := ProcessNamespaceJobs(clientset, testNamespace, &FilterOptions{}) | ||
if err != nil { | ||
t.Errorf("Expected no error, got %v", err) | ||
} | ||
|
||
if len(completedJobs) != 1 { | ||
t.Errorf("Expected 1 job been completed, got %d", len(completedJobs)) | ||
} | ||
|
||
if completedJobs[0] != "test-job2" { | ||
t.Errorf("job2', got %s", completedJobs[0]) | ||
} | ||
} | ||
|
||
func TestGetUnusedJobsStructured(t *testing.T) { | ||
clientset := createTestJobs(t) | ||
|
||
includeExcludeLists := IncludeExcludeLists{ | ||
IncludeListStr: "", | ||
ExcludeListStr: "", | ||
} | ||
|
||
opts := Opts{ | ||
WebhookURL: "", | ||
Channel: "", | ||
Token: "", | ||
DeleteFlag: false, | ||
NoInteractive: true, | ||
} | ||
|
||
output, err := GetUnusedJobs(includeExcludeLists, &FilterOptions{}, clientset, "json", opts) | ||
if err != nil { | ||
t.Fatalf("Error calling GetUnusedJobsStructured: %v", err) | ||
} | ||
|
||
expectedOutput := map[string]map[string][]string{ | ||
testNamespace: { | ||
"Jobs": {"test-job2"}, | ||
}, | ||
} | ||
|
||
var actualOutput map[string]map[string][]string | ||
if err := json.Unmarshal([]byte(output), &actualOutput); err != nil { | ||
t.Fatalf("Error unmarshaling actual output: %v", err) | ||
} | ||
|
||
if !reflect.DeepEqual(expectedOutput, actualOutput) { | ||
t.Errorf("Expected output does not match actual output") | ||
} | ||
} | ||
|
||
func init() { | ||
scheme.Scheme = runtime.NewScheme() | ||
_ = appsv1.AddToScheme(scheme.Scheme) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters