Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kor for openSUSE:Factory checked in at 2023-11-30 22:01:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kor (Old) and /work/SRC/openSUSE:Factory/.kor.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "kor" Thu Nov 30 22:01:46 2023 rev:7 rq:1129949 version:0.3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/kor/kor.changes 2023-11-16 20:29:31.382496265 +0100 +++ /work/SRC/openSUSE:Factory/.kor.new.25432/kor.changes 2023-11-30 22:02:35.667891075 +0100 @@ -1,0 +2,11 @@ +Thu Nov 30 09:08:31 UTC 2023 - kastl@b1-systems.de + +- Update to version 0.3.1: + * fix ingress flag as used (#169) + * Feat: Find unused pv (#163) + * feat:add version flag to ldflags and print version in banner + (#158) + * Bump k8s.io/apiextensions-apiserver from 0.28.3 to 0.28.4 + (#162) + +------------------------------------------------------------------- Old: ---- kor-0.3.0.obscpio New: ---- kor-0.3.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kor.spec ++++++ --- /var/tmp/diff_new_pack.bl0bKQ/_old 2023-11-30 22:02:42.612155229 +0100 +++ /var/tmp/diff_new_pack.bl0bKQ/_new 2023-11-30 22:02:42.612155229 +0100 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: kor -Version: 0.3.0 +Version: 0.3.1 Release: 0 Summary: Tool to discover unused Kubernetes Resources License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.bl0bKQ/_old 2023-11-30 22:02:42.640156294 +0100 +++ /var/tmp/diff_new_pack.bl0bKQ/_new 2023-11-30 22:02:42.644156446 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/yonahd/kor</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.3.0</param> + <param name="revision">v0.3.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.bl0bKQ/_old 2023-11-30 22:02:42.660157055 +0100 +++ /var/tmp/diff_new_pack.bl0bKQ/_new 2023-11-30 22:02:42.660157055 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/yonahd/kor</param> - <param name="changesrevision">062aec60fe8a9a4fcab4711ca8217f8051582d16</param></service></servicedata> + <param name="changesrevision">a459be1a0dfcf5d96ab0ed8c86ec8dc2d675de39</param></service></servicedata> (No newline at EOF) ++++++ kor-0.3.0.obscpio -> kor-0.3.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/.goreleaser.yml new/kor-0.3.1/.goreleaser.yml --- old/kor-0.3.0/.goreleaser.yml 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/.goreleaser.yml 2023-11-29 19:52:39.000000000 +0100 @@ -6,6 +6,8 @@ main: ./main.go env: - CGO_ENABLED=0 + ldflags: + - -X github.com/yonahd/kor/pkg/utils.Version={{.Version}} goos: - linux goarch: @@ -17,6 +19,8 @@ main: ./main.go env: - CGO_ENABLED=0 + ldflags: + - -X github.com/yonahd/kor/pkg/utils.Version={{.Version}} goos: - darwin goarch: @@ -32,7 +36,7 @@ - amd64 ldflags: - -buildmode=exe - + - -X github.com/yonahd/kor/pkg/utils.Version={{.Version}} archives: - format: tar.gz name_template: >- @@ -57,3 +61,5 @@ - 'README' - Merge pull request - Merge branch +snapshot: + name_template: "{{ .Version }}" \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/README.md new/kor-0.3.1/README.md --- old/kor-0.3.0/README.md 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/README.md 2023-11-29 19:52:39.000000000 +0100 @@ -21,6 +21,7 @@ - Ingresses - PDBs - CRDs +- PVs ![Kor Screenshot](/images/screenshot.png) @@ -82,9 +83,10 @@ - `role` - Gets unused Roles for the specified namespace or all namespaces. - `hpa` - Gets unused HPAs for the specified namespace or all namespaces. - `pvc` - Gets unused PVCs for the specified namespace or all namespaces. +- `pv` - Gets unused PVs in the cluster(non namespaced resource). - `ingress` - Gets unused Ingresses for the specified namespace or all namespaces. - `pdb` - Gets unused PDBs for the specified namespace or all namespaces. -- `crd` - Gets unused CRDs in the cluster. +- `crd` - Gets unused CRDs in the cluster(non namespaced resource). - `exporter` - Export Prometheus metrics. ### Supported Flags @@ -133,6 +135,7 @@ | Ingresses | Ingresses not pointing at any Service | | | Hpas | HPAs not used in Deployments<br/> HPAs not used in StatefulSets | | | CRDs | CRDs not used the cluster | | +| Pvs | PVs not bound to a PVC | | | Pdbs | PDBs not used in Deployments<br/> PDBs not used in StatefulSets | | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/cmd/kor/pv.go new/kor-0.3.1/cmd/kor/pv.go --- old/kor-0.3.0/cmd/kor/pv.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kor-0.3.1/cmd/kor/pv.go 2023-11-29 19:52:39.000000000 +0100 @@ -0,0 +1,31 @@ +package kor + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/yonahd/kor/pkg/kor" + "github.com/yonahd/kor/pkg/utils" +) + +var pvCmd = &cobra.Command{ + Use: "persistentvolume", + Aliases: []string{"pv", "persistentvolumes"}, + Short: "Gets unused pvs", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + clientset := kor.GetKubeClient(kubeconfig) + + if response, err := kor.GetUnusedPvs(filterOptions, clientset, outputFormat, opts); err != nil { + fmt.Println(err) + } else { + utils.PrintLogo(outputFormat) + fmt.Println(response) + } + + }, +} + +func init() { + rootCmd.AddCommand(pvCmd) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/go.mod new/kor-0.3.1/go.mod --- old/kor-0.3.0/go.mod 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/go.mod 2023-11-29 19:52:39.000000000 +0100 @@ -8,10 +8,10 @@ github.com/prometheus/client_golang v1.17.0 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 - k8s.io/api v0.28.3 - k8s.io/apiextensions-apiserver v0.28.3 - k8s.io/apimachinery v0.28.3 - k8s.io/client-go v0.28.3 + k8s.io/api v0.28.4 + k8s.io/apiextensions-apiserver v0.28.4 + k8s.io/apimachinery v0.28.4 + k8s.io/client-go v0.28.4 k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 sigs.k8s.io/yaml v1.4.0 ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/go.sum new/kor-0.3.1/go.sum --- old/kor-0.3.0/go.sum 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/go.sum 2023-11-29 19:52:39.000000000 +0100 @@ -181,14 +181,14 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= -k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= -k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= -k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= -k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= -k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= -k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= -k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= +k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= +k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= +k8s.io/apiextensions-apiserver v0.28.4 h1:AZpKY/7wQ8n+ZYDtNHbAJBb+N4AXXJvyZx6ww6yAJvU= +k8s.io/apiextensions-apiserver v0.28.4/go.mod h1:pgQIZ1U8eJSMQcENew/0ShUTlePcSGFq6dxSxf2mwPM= +k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= +k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= +k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= +k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/all.go new/kor-0.3.1/pkg/kor/all.go --- old/kor-0.3.0/pkg/kor/all.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/all.go 2023-11-29 19:52:39.000000000 +0100 @@ -121,12 +121,21 @@ } func getUnusedCrds(apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface) ResourceDiff { - pdbDiff, err := processCrds(apiExtClient, dynamicClient) + crdDiff, err := processCrds(apiExtClient, dynamicClient) if err != nil { fmt.Fprintf(os.Stderr, "Failed to get %s: %v\n", "Crds", err) } - namespacePdbDiff := ResourceDiff{"Crd", pdbDiff} - return namespacePdbDiff + allCrdDiff := ResourceDiff{"Crd", crdDiff} + return allCrdDiff +} + +func getUnusedPvs(clientset kubernetes.Interface, filterOpts *FilterOptions) ResourceDiff { + pvDiff, err := processPvs(clientset, filterOpts) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to get %s: %v\n", "Pvs", err) + } + allPvDiff := ResourceDiff{"Pv", pvDiff} + return allPvDiff } func GetUnusedAll(includeExcludeLists IncludeExcludeLists, filterOpts *FilterOptions, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) { @@ -173,13 +182,24 @@ } var allDiffs []ResourceDiff + noNamespaceResourceMap := make(map[string][]string) crdDiff := getUnusedCrds(apiExtClient, dynamicClient) - allDiffs = append(allDiffs, crdDiff) + crdOutput := FormatOutputAll("", []ResourceDiff{crdDiff}, opts) + outputBuffer.WriteString(crdOutput) + outputBuffer.WriteString("\n") + noNamespaceResourceMap[crdDiff.resourceType] = crdDiff.diff + + pvDiff := getUnusedPvs(clientset, filterOpts) + pvOutput := FormatOutputAll("", []ResourceDiff{pvDiff}, opts) + outputBuffer.WriteString(pvOutput) + outputBuffer.WriteString("\n") + noNamespaceResourceMap[pvDiff.resourceType] = pvDiff.diff output := FormatOutputAll("", allDiffs, opts) outputBuffer.WriteString(output) outputBuffer.WriteString("\n") + response[""] = noNamespaceResourceMap jsonResponse, err := json.MarshalIndent(response, "", " ") if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/create_test_resources.go new/kor-0.3.1/pkg/kor/create_test_resources.go --- old/kor-0.3.0/pkg/kor/create_test_resources.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/create_test_resources.go 2023-11-29 19:52:39.000000000 +0100 @@ -216,6 +216,17 @@ } } +func CreateTestPv(name, phase string) *corev1.PersistentVolume { + return &corev1.PersistentVolume{ + ObjectMeta: v1.ObjectMeta{ + Name: name, + }, + Status: corev1.PersistentVolumeStatus{ + Phase: corev1.PersistentVolumePhase(phase), + }, + } +} + func CreateTestPdb(namespace, name string, matchLabels map[string]string) *policyv1.PodDisruptionBudget { return &policyv1.PodDisruptionBudget{ ObjectMeta: v1.ObjectMeta{ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/delete.go new/kor-0.3.1/pkg/kor/delete.go --- old/kor-0.3.0/pkg/kor/delete.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/delete.go 2023-11-29 19:52:39.000000000 +0100 @@ -10,7 +10,7 @@ appsv1 "k8s.io/api/apps/v1" autoscalingv1 "k8s.io/api/autoscaling/v1" corev1 "k8s.io/api/core/v1" - networkingv1beta1 "k8s.io/api/networking/v1beta1" + networkingv1 "k8s.io/api/networking/v1" policyv1beta1 "k8s.io/api/policy/v1beta1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,7 +35,7 @@ return clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) }, "Ingress": func(clientset kubernetes.Interface, namespace, name string) error { - return clientset.NetworkingV1beta1().Ingresses(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) + return clientset.NetworkingV1().Ingresses(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) }, "PDB": func(clientset kubernetes.Interface, namespace, name string) error { return clientset.PolicyV1beta1().PodDisruptionBudgets(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) @@ -52,6 +52,9 @@ "ServiceAccount": func(clientset kubernetes.Interface, namespace, name string) error { return clientset.CoreV1().ServiceAccounts(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{}) }, + "PV": func(clientset kubernetes.Interface, namespace, name string) error { + return clientset.CoreV1().PersistentVolumes().Delete(context.TODO(), name, metav1.DeleteOptions{}) + }, } return deleteResourceApiMap @@ -92,7 +95,7 @@ case "HPA": return clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).Update(context.TODO(), resource.(*autoscalingv1.HorizontalPodAutoscaler), metav1.UpdateOptions{}) case "Ingress": - return clientset.NetworkingV1beta1().Ingresses(namespace).Update(context.TODO(), resource.(*networkingv1beta1.Ingress), metav1.UpdateOptions{}) + return clientset.NetworkingV1().Ingresses(namespace).Update(context.TODO(), resource.(*networkingv1.Ingress), metav1.UpdateOptions{}) case "PDB": return clientset.PolicyV1beta1().PodDisruptionBudgets(namespace).Update(context.TODO(), resource.(*policyv1beta1.PodDisruptionBudget), metav1.UpdateOptions{}) case "Roles": @@ -103,6 +106,8 @@ return clientset.AppsV1().StatefulSets(namespace).Update(context.TODO(), resource.(*appsv1.StatefulSet), metav1.UpdateOptions{}) case "ServiceAccount": return clientset.CoreV1().ServiceAccounts(namespace).Update(context.TODO(), resource.(*corev1.ServiceAccount), metav1.UpdateOptions{}) + case "PV": + return clientset.CoreV1().PersistentVolumes().Update(context.TODO(), resource.(*corev1.PersistentVolume), metav1.UpdateOptions{}) } return nil, fmt.Errorf("resource type '%s' is not supported", resourceType) } @@ -120,7 +125,7 @@ case "HPA": return clientset.AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) case "Ingress": - return clientset.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) + return clientset.NetworkingV1().Ingresses(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) case "PDB": return clientset.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) case "Roles": @@ -131,6 +136,8 @@ return clientset.AppsV1().StatefulSets(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) case "ServiceAccount": return clientset.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), resourceName, metav1.GetOptions{}) + case "PV": + return clientset.CoreV1().PersistentVolumes().Get(context.TODO(), resourceName, metav1.GetOptions{}) } return nil, fmt.Errorf("resource type '%s' is not supported", resourceType) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/ingresses.go new/kor-0.3.1/pkg/kor/ingresses.go --- old/kor-0.3.0/pkg/kor/ingresses.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/ingresses.go 2023-11-29 19:52:39.000000000 +0100 @@ -34,10 +34,6 @@ usedIngresses := []string{} for _, ingress := range ingresses.Items { - if ingress.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(ingress.Labels, filterOpts.ExcludeLabels); excluded { @@ -83,6 +79,9 @@ } names := make([]string, 0, len(ingresses.Items)) for _, ingress := range ingresses.Items { + if ingress.Labels["kor/used"] == "true" { + continue + } names = append(names, ingress.Name) } return names, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/kor.go new/kor-0.3.1/pkg/kor/kor.go --- old/kor-0.3.0/pkg/kor/kor.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/kor.go 2023-11-29 19:52:39.000000000 +0100 @@ -210,7 +210,7 @@ table.Render() if namespace == "" { - return fmt.Sprintf("Unused CRDs: \n%s", buf.String()) + return fmt.Sprintf("Unused %ss: \n%s", allDiffs[0].resourceType, buf.String()) } return fmt.Sprintf("Unused Resources in Namespace: %s\n%s", namespace, buf.String()) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/multi.go new/kor-0.3.1/pkg/kor/multi.go --- old/kor-0.3.0/pkg/kor/multi.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/multi.go 2023-11-29 19:52:39.000000000 +0100 @@ -12,20 +12,33 @@ "k8s.io/client-go/kubernetes" ) -func retrieveNoNamespaceDiff(apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts, resourceList []string) ([]ResourceDiff, []string) { +func retrieveNoNamespaceDiff(clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, resourceList []string, filterOpts *FilterOptions) ([]ResourceDiff, []string) { var noNamespaceDiff []ResourceDiff + markedForRemoval := make([]bool, len(resourceList)) + updatedResourceList := resourceList + for counter, resource := range resourceList { - if resource == "crd" || resource == "customresourcedefinition" || resource == "customresourcedefinitions" { + switch resource { + case "crd", "customresourcedefinition", "customresourcedefinitions": crdDiff := getUnusedCrds(apiExtClient, dynamicClient) noNamespaceDiff = append(noNamespaceDiff, crdDiff) - updatedResourceList := append(resourceList[:counter], resourceList[counter+1:]...) - return noNamespaceDiff, updatedResourceList - } else { - resourceList[counter] = resource + markedForRemoval[counter] = true + case "pv", "persistentvolume", "persistentvolumes": + pvDiff := getUnusedPvs(clientset, filterOpts) + noNamespaceDiff = append(noNamespaceDiff, pvDiff) + markedForRemoval[counter] = true + } + } + + // Remove elements marked for removal + var clearedResourceList []string + for i, marked := range markedForRemoval { + if !marked { + clearedResourceList = append(clearedResourceList, updatedResourceList[i]) } } - return noNamespaceDiff, resourceList + return noNamespaceDiff, clearedResourceList } func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, resourceList []string, filterOpts *FilterOptions) []ResourceDiff { @@ -72,14 +85,22 @@ response := make(map[string]map[string][]string) var err error - crdDiff, resourceList := retrieveNoNamespaceDiff(apiExtClient, dynamicClient, outputFormat, opts, resourceList) - if len(crdDiff) != 0 { - output := FormatOutputAll("", crdDiff, opts) - outputBuffer.WriteString(output) - outputBuffer.WriteString("\n") + noNamespaceDiff, resourceList := retrieveNoNamespaceDiff(clientset, apiExtClient, dynamicClient, resourceList, filterOpts) + if len(noNamespaceDiff) != 0 { + for _, diff := range noNamespaceDiff { + if len(diff.diff) != 0 { + output := FormatOutputAll("", []ResourceDiff{diff}, opts) + outputBuffer.WriteString(output) + outputBuffer.WriteString("\n") + + resourceMap := make(map[string][]string) + resourceMap[diff.resourceType] = diff.diff + response[""] = resourceMap + } + } resourceMap := make(map[string][]string) - for _, diff := range crdDiff { + for _, diff := range noNamespaceDiff { resourceMap[diff.resourceType] = diff.diff } response[""] = resourceMap diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/pv.go new/kor-0.3.1/pkg/kor/pv.go --- old/kor-0.3.0/pkg/kor/pv.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/pv.go 2023-11-29 19:52:39.000000000 +0100 @@ -0,0 +1,89 @@ +package kor + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" +) + +func processPvs(clientset kubernetes.Interface, filterOpts *FilterOptions) ([]string, error) { + pvs, err := clientset.CoreV1().PersistentVolumes().List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + + var unusedPvs []string + + for _, pv := range pvs.Items { + if pv.Labels["kor/used"] == "true" { + continue + } + + if excluded, _ := HasExcludedLabel(pv.Labels, filterOpts.ExcludeLabels); excluded { + continue + } + + if included, _ := HasIncludedAge(pv.CreationTimestamp, filterOpts); !included { + continue + } + + if pv.Status.Phase != "Bound" { + unusedPvs = append(unusedPvs, pv.Name) + } + + } + + return unusedPvs, nil + +} + +func GetUnusedPvs(filterOpts *FilterOptions, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) { + var outputBuffer bytes.Buffer + response := make(map[string]map[string][]string) + + diff, err := processPvs(clientset, filterOpts) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to process pvs: %v\n", err) + } + + if len(diff) > 0 { + // We consider cluster scope resources in "" (empty string) namespace, as it is common in k8s + if response[""] == nil { + response[""] = make(map[string][]string) + } + response[""]["Pv"] = diff + } + + if opts.DeleteFlag { + if diff, err = DeleteResource(diff, clientset, "", "PV", opts.NoInteractive); err != nil { + fmt.Fprintf(os.Stderr, "Failed to delete PV %s: %v\n", diff, err) + } + } + + output := FormatOutput("", diff, "PVs", opts) + if output != "" { + outputBuffer.WriteString(output) + outputBuffer.WriteString("\n") + + response[""]["Pv"] = diff + + } + + jsonResponse, err := json.MarshalIndent(response, "", " ") + if err != nil { + return "", err + } + + unusedPvs, err := unusedResourceFormatter(outputFormat, outputBuffer, opts, jsonResponse) + if err != nil { + fmt.Printf("err: %v\n", err) + } + + return unusedPvs, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/kor/pv_test.go new/kor-0.3.1/pkg/kor/pv_test.go --- old/kor-0.3.0/pkg/kor/pv_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kor-0.3.1/pkg/kor/pv_test.go 2023-11-29 19:52:39.000000000 +0100 @@ -0,0 +1,79 @@ +package kor + +import ( + "context" + "encoding/json" + "reflect" + "testing" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func createTestPvs(t *testing.T) *fake.Clientset { + clientset := fake.NewSimpleClientset() + + pv1 := CreateTestPv("test-pv1", "Bound") + pv2 := CreateTestPv("test-pv2", "Available") + _, err := clientset.CoreV1().PersistentVolumes().Create(context.TODO(), pv1, v1.CreateOptions{}) + if err != nil { + t.Fatalf("Error creating fake %s: %v", "PV", err) + } + + _, err = clientset.CoreV1().PersistentVolumes().Create(context.TODO(), pv2, v1.CreateOptions{}) + if err != nil { + t.Fatalf("Error creating fake %s: %v", "PV", err) + } + + return clientset +} + +func TestProcessPvs(t *testing.T) { + clientset := createTestPvs(t) + usedPvs, err := processPvs(clientset, &FilterOptions{}) + if err != nil { + t.Errorf("Expected no error, got %v", err) + } + + if len(usedPvs) != 1 { + t.Errorf("Expected 1 used pv, got %d", len(usedPvs)) + } + + if usedPvs[0] != "test-pv2" { + t.Errorf("Expected 'test-pv2', got %s", usedPvs[0]) + } +} + +func TestGetUnusedPvs(t *testing.T) { + clientset := createTestPvs(t) + + opts := Opts{ + WebhookURL: "", + Channel: "", + Token: "", + DeleteFlag: false, + NoInteractive: true, + } + + output, err := GetUnusedPvs(&FilterOptions{}, clientset, "json", opts) + if err != nil { + t.Fatalf("Error calling GetUnusedPvs: %v", err) + } + + expectedOutput := map[string]map[string][]string{ + "": { + "Pv": {"test-pv2"}, + }, + } + + 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") + } +} + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kor-0.3.0/pkg/utils/banner.go new/kor-0.3.1/pkg/utils/banner.go --- old/kor-0.3.0/pkg/utils/banner.go 2023-11-15 16:26:18.000000000 +0100 +++ new/kor-0.3.1/pkg/utils/banner.go 2023-11-29 19:52:39.000000000 +0100 @@ -1,9 +1,13 @@ package utils import ( + "fmt" + "github.com/fatih/color" ) +var Version = "dev" + func PrintLogo(outputFormat string) { boldBlue := color.New(color.FgHiBlue, color.Bold) asciiLogo := ` @@ -15,7 +19,7 @@ ` // processing of the `outputFormat` happens inside of the rootCmd so this requires a pretty large change // to keep the banner. Instead just loop through os args and find if the format was set and handle it there - + fmt.Printf("version: v%s\n", Version) if outputFormat != "yaml" && outputFormat != "json" { boldBlue.Println(asciiLogo) } ++++++ kor.obsinfo ++++++ --- /var/tmp/diff_new_pack.bl0bKQ/_old 2023-11-30 22:02:42.784161772 +0100 +++ /var/tmp/diff_new_pack.bl0bKQ/_new 2023-11-30 22:02:42.784161772 +0100 @@ -1,5 +1,5 @@ name: kor -version: 0.3.0 -mtime: 1700061978 -commit: 062aec60fe8a9a4fcab4711ca8217f8051582d16 +version: 0.3.1 +mtime: 1701283959 +commit: a459be1a0dfcf5d96ab0ed8c86ec8dc2d675de39 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/kor/vendor.tar.gz /work/SRC/openSUSE:Factory/.kor.new.25432/vendor.tar.gz differ: char 5, line 1
participants (1)
-
Source-Sync