diff --git a/README.md b/README.md
index 9024b1a1..bd317012 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,9 @@ Kor is a tool to discover unused Kubernetes resources. Currently, Kor can identi
- StorageClasses
- NetworkPolicies
- RoleBindings
+- Argo Rollouts
+- Argo Rollouts Analysis template
+- Argo Rollouts Cluster Analysis template
![Kor Screenshot](/images/show_reason_screenshot.png)
@@ -125,6 +128,7 @@ Kor provides various subcommands to identify and list unused resources. The avai
- `daemonset`- Gets unused DaemonSets for the specified namespace or all namespaces.
- `finalizer` - Gets unused pending deletion resources for the specified namespace or all namespaces.
- `networkpolicy` - Gets unused NetworkPolicies for the specified namespace or all namespaces.
+- `argo-rollouts, argo-rollouts-analysis-templates, argo-rollouts-cluster-analysis-templates` - Gets unsed argo-rollouts, analysis-templates and cluster-analysis-templates
- `exporter` - Export Prometheus metrics.
- `version` - Print kor version information.
@@ -147,7 +151,9 @@ Kor provides various subcommands to identify and list unused resources. The avai
--slack-auth-token string Slack auth token to send notifications to. --slack-auth-token requires --slack-channel to be set.
--slack-channel string Slack channel to send notifications to. --slack-channel requires --slack-auth-token to be set.
--slack-webhook-url string Slack webhook URL to send notifications to
+ --include-third-party-crds To get unused argo-rollouts, analysis-templates and cluster-analysis-templates
-v, --verbose Verbose output (print empty namespaces)
+
```
To use a specific subcommand, run `kor [subcommand] [flags]`.
@@ -156,6 +162,13 @@ To use a specific subcommand, run `kor [subcommand] [flags]`.
kor all --include-namespaces my-namespace
```
+To get all with Argo Rollouts
+
+```sh
+kor all --include-namespaces my-namespace --include-third-party-crds argo-rollouts,argo-rollouts-analysis-templates,argo-rollouts-cluster-analysis-templates
+```
+
+
For more information about each subcommand and its available flags, you can use the `--help` flag.
```sh
@@ -179,13 +192,16 @@ kor [subcommand] --help
| Ingresses | Ingresses not pointing at any Service | |
| Hpas | HPAs not used in Deployments
HPAs not used in StatefulSets | |
| CRDs | CRDs not used the cluster | |
-| Pvs | PVs not bound to a PVC | |
-| Pdbs | PDBs not used in Deployments / StatefulSets (templates) or in arbitrary Pods
PDBs with empty selectors (match every pod) but no running pods in namespace | |
+| Pvs | PVs not bound to a PVC
+| Pdbs | PDBs not used in Deployments / StatefulSets (templates) or in arbitrary Pods
PDBs with empty selectors (match every pod) but no running pods in namespace | |
| Jobs | Jobs status is completed
Jobs status is suspended
Jobs failed with backoff limit exceeded (including indexed jobs)
Jobs failed with dedaline exceeded | |
| ReplicaSets | replicaSets that specify replicas to 0 and has already completed it's work |
| DaemonSets | DaemonSets not scheduled on any nodes |
-| StorageClasses | StorageClasses not used by any PVs/PVCs |
+| StorageClasses | StorageClasses not used by any PVs/PVCs
| NetworkPolicies | NetworkPolicies with no Pods selected by podSelector or Ingress/Egress rules |
+| ArgoRollouts | ArgoRollouts not used by any deployment |
+| ArgoRollouts-AnalysisTemplate | Analysys template not used by any Argo Rollout |
+| ArgoRollouts-ClusterAnalysisTemplate | Cluster analysys template not used by any Argo Rollout |
### Deleting Unused resources
@@ -253,6 +269,45 @@ Unused resources in namespace: "test"
+---+----------------+----------------------------------------------+--------------------------------------------------------+
```
+```sh
+kor all --include-third-party-crds argo-rollouts,argo-rollouts-analysis-templates,argo-rollouts-cluster-analysis-templates --show-reason --show-reason
+```
+```
+Unused resources in namespace: "default"
++---+-------------------------------+------------------------------------+------------------------------------------------+
+| # | RESOURCE TYPE | RESOURCE NAME | REASON |
++---+-------------------------------+------------------------------------+------------------------------------------------+
+| 1 | ServiceAccount | bookinfo-gateway-istio | ServiceAccount is not in use |
+| 2 | ConfigMap | istio-ca-root-cert | ConfigMap is not used in any pod or container |
+| 3 | Pvc | devlake-mysql-data-devlake-mysql-0 | PVC is not in use |
+| 4 | ReplicaSet | rollout-canary-679b8b5b4c | ReplicaSet is not in use |
+| 5 | ArgoRollout | rollout-canary | Rollout has 0 replicas |
+| 6 | ArgoRollouts-AnalysisTemplate | pass | Argo Rollouts Analysis Templates is not in use |
++---+-------------------------------+------------------------------------+------------------------------------------------+
+
+Unused resources in namespace: ""
++----+--------------------------------------+----------------------------------+--------------------------------------------------------------+
+| # | RESOURCE TYPE | RESOURCE NAME | REASON |
++----+--------------------------------------+----------------------------------+--------------------------------------------------------------+
+| 1 | ArgoRollouts-ClusterAnalysisTemplate | always-pass | Argo Rollouts Cluster Analysis Templates is not in use |
+| 2 | ArgoRollouts-ClusterAnalysisTemplate | alert-template | Argo Rollouts Cluster Analysis Templates is not in use |
+| 3 | Pv | mongo-data-pv | Persistent Volume is not in use |
+| 4 | Pv | config | Persistent Volume is not in use |
+| 5 | ClusterRole | cert-manager-cluster-view | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
+| 6 | ClusterRole | cert-manager-view | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
+| 7 | ClusterRole | cert-manager-edit | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
+| 8 | ClusterRole | argo-rollouts-aggregate-to-admin | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
+| 9 | ClusterRole | argo-rollouts-aggregate-to-edit | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
+| 10 | ClusterRole | argo-rollouts-aggregate-to-view | ClusterRole is not used by any RoleBinding or |
+| | | | ClusterRoleBinding |
++----+--------------------------------------+----------------------------------+--------------------------------------------------------------+
+```
+
#### Group by resource
```sh
@@ -283,6 +338,33 @@ Unused ReplicaSets:
+---+-----------+--------------------+
```
+```sh
+kor all --include-third-party-crds argo-rollouts,argo-rollouts-analysis-templates,argo-rollouts-cluster-analysis-templates --group-by=resource --output=table
+```
+```**
+Unused ArgoRollouts:
++---+-----------+----------------+
+| # | NAMESPACE | RESOURCE NAME |
++---+-----------+----------------+
+| 1 | default | rollout-canary |
++---+-----------+----------------+
+
+Unused ArgoRollouts-AnalysisTemplates:
++---+-----------+---------------+
+| # | NAMESPACE | RESOURCE NAME |
++---+-----------+---------------+
+| 1 | default | pass |
++---+-----------+---------------+
+
+Unused ArgoRollouts-ClusterAnalysisTemplates:
++---+-----------+----------------+
+| # | NAMESPACE | RESOURCE NAME |
++---+-----------+----------------+
+| 1 | | always-pass |
+| 2 | | alert-template |
++---+-----------+----------------+
+```
+
#### Group by namespace
```sh
diff --git a/charts/kor/Chart.yaml b/charts/kor/Chart.yaml
index 76415413..f24c5d31 100644
--- a/charts/kor/Chart.yaml
+++ b/charts/kor/Chart.yaml
@@ -15,4 +15,4 @@ annotations:
- name: Chart Source
url: https://github.com/yonahd/kor/tree/main/charts/kor
- name: Grafana Dashboard
- url: https://grafana.com/grafana/dashboards/19863-kor-dashboard/
+ url: https://grafana.com/grafana/dashboards/19863-kor-dashboard/
\ No newline at end of file
diff --git a/charts/kor/values.yaml b/charts/kor/values.yaml
index 4a251c0b..515dbb8d 100644
--- a/charts/kor/values.yaml
+++ b/charts/kor/values.yaml
@@ -85,4 +85,4 @@ serviceAccount:
annotations: {}
# -- The name of the service account to use.
# -- If not set and create is true, a name is generated using the fullname template
- name: ""
+ name: ""
\ No newline at end of file
diff --git a/cmd/kor/all.go b/cmd/kor/all.go
index 3478c9be..50c887fe 100644
--- a/cmd/kor/all.go
+++ b/cmd/kor/all.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -14,11 +15,11 @@ var allCmd = &cobra.Command{
Short: "Gets unused resources",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
- apiExtClient := kor.GetAPIExtensionsClient(kubeconfig)
- dynamicClient := kor.GetDynamicClient(kubeconfig)
-
- if response, err := kor.GetUnusedAll(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts); err != nil {
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
+ apiExtClient := clusterconfig.GetAPIExtensionsClient(kubeconfig)
+ dynamicClient := clusterconfig.GetDynamicClient(kubeconfig)
+ clientsetinterface, _ := clusterconfig.GetKubeClientForCrds(kubeconfig, clientset)
+ if response, err := kor.GetUnusedAll(filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
utils.PrintLogo(outputFormat)
diff --git a/cmd/kor/clusterroles.go b/cmd/kor/clusterroles.go
index 3eca16fb..f5963267 100644
--- a/cmd/kor/clusterroles.go
+++ b/cmd/kor/clusterroles.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var clusterRoleCmd = &cobra.Command{
Short: "Gets unused cluster roles",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedClusterRoles(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/configmaps.go b/cmd/kor/configmaps.go
index 161b2a61..8e8b062f 100644
--- a/cmd/kor/configmaps.go
+++ b/cmd/kor/configmaps.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var configmapCmd = &cobra.Command{
Short: "Gets unused configmaps",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedConfigmaps(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
diff --git a/cmd/kor/crds.go b/cmd/kor/crds.go
index eebd98f3..89f8294a 100644
--- a/cmd/kor/crds.go
+++ b/cmd/kor/crds.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,8 +16,8 @@ var crdCmd = &cobra.Command{
Short: "Gets unused crds",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- apiExtClient := kor.GetAPIExtensionsClient(kubeconfig)
- dynamicClient := kor.GetDynamicClient(kubeconfig)
+ apiExtClient := clusterconfig.GetAPIExtensionsClient(kubeconfig)
+ dynamicClient := clusterconfig.GetDynamicClient(kubeconfig)
if response, err := kor.GetUnusedCrds(filterOptions, apiExtClient, dynamicClient, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
diff --git a/cmd/kor/daemonsets.go b/cmd/kor/daemonsets.go
index 374934e9..5a0f5ef5 100644
--- a/cmd/kor/daemonsets.go
+++ b/cmd/kor/daemonsets.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var dsCmd = &cobra.Command{
Short: "Gets unused daemonSets",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedDaemonSets(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/deployments.go b/cmd/kor/deployments.go
index 4eb16d6d..bc23f5f9 100644
--- a/cmd/kor/deployments.go
+++ b/cmd/kor/deployments.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var deployCmd = &cobra.Command{
Short: "Gets unused deployments",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedDeployments(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
diff --git a/cmd/kor/exporter.go b/cmd/kor/exporter.go
index bb245124..50f06308 100644
--- a/cmd/kor/exporter.go
+++ b/cmd/kor/exporter.go
@@ -3,6 +3,7 @@ package kor
import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
)
@@ -13,11 +14,12 @@ var exporterCmd = &cobra.Command{
Short: "start prometheus exporter",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
- apiExtClient := kor.GetAPIExtensionsClient(kubeconfig)
- dynamicClient := kor.GetDynamicClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
+ clientsetinterface, _ := clusterconfig.GetKubeClientForCrds(kubeconfig, clientset)
+ apiExtClient := clusterconfig.GetAPIExtensionsClient(kubeconfig)
+ dynamicClient := clusterconfig.GetDynamicClient(kubeconfig)
- kor.Exporter(filterOptions, clientset, apiExtClient, dynamicClient, "json", opts, resourceList)
+ kor.Exporter(filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, "json", opts, resourceList)
},
}
diff --git a/cmd/kor/finalizers.go b/cmd/kor/finalizers.go
index 08a8acd8..80d97e6f 100644
--- a/cmd/kor/finalizers.go
+++ b/cmd/kor/finalizers.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
)
@@ -14,8 +15,8 @@ var finalizerCmd = &cobra.Command{
Short: "Gets resources waiting for finalizers to delete",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
- dynamicClient := kor.GetDynamicClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
+ dynamicClient := clusterconfig.GetDynamicClient(kubeconfig)
if response, err := kor.GetUnusedfinalizers(filterOptions, clientset, dynamicClient, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/hpas.go b/cmd/kor/hpas.go
index 2679637e..859ee56e 100644
--- a/cmd/kor/hpas.go
+++ b/cmd/kor/hpas.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var hpaCmd = &cobra.Command{
Short: "Gets unused hpas",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedHpas(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/ingresses.go b/cmd/kor/ingresses.go
index 9ec5c91b..06f06ff7 100644
--- a/cmd/kor/ingresses.go
+++ b/cmd/kor/ingresses.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var ingressCmd = &cobra.Command{
Short: "Gets unused ingresses",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedIngresses(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/jobs.go b/cmd/kor/jobs.go
index 16034eb8..3792cf79 100644
--- a/cmd/kor/jobs.go
+++ b/cmd/kor/jobs.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var jobCmd = &cobra.Command{
Short: "Gets unused jobs",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedJobs(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/networkpolicies.go b/cmd/kor/networkpolicies.go
index cb0efea4..21758435 100644
--- a/cmd/kor/networkpolicies.go
+++ b/cmd/kor/networkpolicies.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var netpolCmd = &cobra.Command{
Short: "Gets unused networkpolicies",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedNetworkPolicies(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
diff --git a/cmd/kor/pdbs.go b/cmd/kor/pdbs.go
index 6fecadee..84be68f9 100644
--- a/cmd/kor/pdbs.go
+++ b/cmd/kor/pdbs.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var pdbCmd = &cobra.Command{
Short: "Gets unused pdbs",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedPdbs(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/pods.go b/cmd/kor/pods.go
index 9c13c036..df67ebcb 100644
--- a/cmd/kor/pods.go
+++ b/cmd/kor/pods.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var podCmd = &cobra.Command{
Short: "Gets unused pods",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedPods(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/pv.go b/cmd/kor/pv.go
index dcfc6692..ff73478e 100644
--- a/cmd/kor/pv.go
+++ b/cmd/kor/pv.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var pvCmd = &cobra.Command{
Short: "Gets unused pvs",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedPvs(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/pvc.go b/cmd/kor/pvc.go
index e29f9c61..fdb03515 100644
--- a/cmd/kor/pvc.go
+++ b/cmd/kor/pvc.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var pvcCmd = &cobra.Command{
Short: "Gets unused pvcs",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedPvcs(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/replicasets.go b/cmd/kor/replicasets.go
index f12e8dff..6483b48f 100644
--- a/cmd/kor/replicasets.go
+++ b/cmd/kor/replicasets.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var replicaSetCmd = &cobra.Command{
Short: "Gets unused replicaSets",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedReplicaSets(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/rolebindings.go b/cmd/kor/rolebindings.go
index 5b471450..0fe20e77 100644
--- a/cmd/kor/rolebindings.go
+++ b/cmd/kor/rolebindings.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var roleBindingCmd = &cobra.Command{
Short: "Gets unused role bindings",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedRoleBindings(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/roles.go b/cmd/kor/roles.go
index 2f71739b..7471c64e 100644
--- a/cmd/kor/roles.go
+++ b/cmd/kor/roles.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var roleCmd = &cobra.Command{
Short: "Gets unused roles",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedRoles(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/root.go b/cmd/kor/root.go
index 17c818e9..b3cad3e0 100644
--- a/cmd/kor/root.go
+++ b/cmd/kor/root.go
@@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/common"
"github.com/yonahd/kor/pkg/filters"
"github.com/yonahd/kor/pkg/kor"
@@ -31,11 +32,12 @@ var rootCmd = &cobra.Command{
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
resourceNames := args[0]
- clientset := kor.GetKubeClient(kubeconfig)
- apiExtClient := kor.GetAPIExtensionsClient(kubeconfig)
- dynamicClient := kor.GetDynamicClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
+ clientsetinterface, _ := clusterconfig.GetKubeClientForCrds(kubeconfig, clientset)
+ apiExtClient := clusterconfig.GetAPIExtensionsClient(kubeconfig)
+ dynamicClient := clusterconfig.GetDynamicClient(kubeconfig)
- if response, err := kor.GetUnusedMulti(resourceNames, filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts); err != nil {
+ if response, err := kor.GetUnusedMulti(resourceNames, filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
utils.PrintLogo(outputFormat)
@@ -85,4 +87,5 @@ func addFilterOptionsFlag(cmd *cobra.Command, opts *filters.Options) {
cmd.PersistentFlags().StringVar(&opts.IncludeLabels, "include-labels", opts.IncludeLabels, "Selector to filter in, Example: --include-labels key1=value1.(currently supports one label)")
cmd.PersistentFlags().StringSliceVarP(&opts.ExcludeNamespaces, "exclude-namespaces", "e", opts.ExcludeNamespaces, "Namespaces to be excluded, split by commas. Example: --exclude-namespaces ns1,ns2,ns3. If --include-namespaces is set, --exclude-namespaces will be ignored.")
cmd.PersistentFlags().StringSliceVarP(&opts.IncludeNamespaces, "include-namespaces", "n", opts.IncludeNamespaces, "Namespaces to run on, split by commas. Example: --include-namespaces ns1,ns2,ns3. If set, non-namespaced resources will be ignored.")
+ rootCmd.PersistentFlags().StringSliceVar(&opts.IncludeThirdPartyCrds, "include-third-party-crds", opts.IncludeThirdPartyCrds, "Custom resources defintions to search, split by commas. Example: --include-crds argo-rollouts. If set, the chosen crd will be returned (in addition to the other resources, of course)")
}
diff --git a/cmd/kor/secrets.go b/cmd/kor/secrets.go
index b484d4af..0a79aaf1 100644
--- a/cmd/kor/secrets.go
+++ b/cmd/kor/secrets.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var secretCmd = &cobra.Command{
Short: "Gets unused secrets",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedSecrets(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/serviceaccounts.go b/cmd/kor/serviceaccounts.go
index ba73b462..faae3e15 100644
--- a/cmd/kor/serviceaccounts.go
+++ b/cmd/kor/serviceaccounts.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var serviceAccountCmd = &cobra.Command{
Short: "Gets unused service accounts",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedServiceAccounts(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/services.go b/cmd/kor/services.go
index 996ca611..2ce5aaad 100644
--- a/cmd/kor/services.go
+++ b/cmd/kor/services.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var serviceCmd = &cobra.Command{
Short: "Gets unused services",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedServices(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/statefulsets.go b/cmd/kor/statefulsets.go
index dd53e17e..98cee91d 100644
--- a/cmd/kor/statefulsets.go
+++ b/cmd/kor/statefulsets.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var stsCmd = &cobra.Command{
Short: "Gets unused statefulSets",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedStatefulSets(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/cmd/kor/storageclasses.go b/cmd/kor/storageclasses.go
index eade9e03..a7f2f074 100644
--- a/cmd/kor/storageclasses.go
+++ b/cmd/kor/storageclasses.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/kor"
"github.com/yonahd/kor/pkg/utils"
)
@@ -15,7 +16,7 @@ var scCmd = &cobra.Command{
Short: "Gets unused storageClasses",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
- clientset := kor.GetKubeClient(kubeconfig)
+ clientset := clusterconfig.GetKubeClient(kubeconfig)
if response, err := kor.GetUnusedStorageClasses(filterOptions, clientset, outputFormat, opts); err != nil {
fmt.Println(err)
diff --git a/go.mod b/go.mod
index 82a4ca30..adfd1b44 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/yonahd/kor
go 1.23.2
require (
+ github.com/argoproj/argo-rollouts v1.7.2
github.com/fatih/color v1.18.0
github.com/olekukonko/tablewriter v0.0.5
github.com/prometheus/client_golang v1.20.5
diff --git a/go.sum b/go.sum
index 1f576778..4c9fc847 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+github.com/argoproj/argo-rollouts v1.7.2 h1:faDUH/qePerYRwsrHfVzNQkhjGBgXIiVYdVK8824kMo=
+github.com/argoproj/argo-rollouts v1.7.2/go.mod h1:Te4HrUELxKiBpK8lgk77o4gTa3mv8pXCd8xdPprKrbs=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
@@ -190,8 +192,6 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
-k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
diff --git a/pkg/clusterconfig/connection.go b/pkg/clusterconfig/connection.go
new file mode 100644
index 00000000..3f7ccfe4
--- /dev/null
+++ b/pkg/clusterconfig/connection.go
@@ -0,0 +1,129 @@
+package clusterconfig
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned"
+ apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
+ "k8s.io/client-go/dynamic"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ "k8s.io/client-go/util/homedir"
+)
+
+type ClientInterface interface {
+ GetKubernetesClient() kubernetes.Interface
+ GetArgoRolloutsClient() versioned.Interface
+}
+
+type ClientSet struct {
+ coreClient *kubernetes.Clientset
+ coreClientArgoRollouts *versioned.Clientset
+}
+
+func GetKubeConfigPath() string {
+ home := homedir.HomeDir()
+ return filepath.Join(home, ".kube", "config")
+}
+
+func GetConfig(kubeconfig string) (*rest.Config, error) {
+ if _, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token"); err == nil {
+ return rest.InClusterConfig()
+ }
+
+ if kubeconfig == "" {
+ if configEnv := os.Getenv("KUBECONFIG"); configEnv != "" {
+ kubeconfig = configEnv
+ } else {
+ kubeconfig = GetKubeConfigPath()
+ }
+ }
+
+ return clientcmd.BuildConfigFromFlags("", kubeconfig)
+}
+
+func GetKubeClient(kubeconfig string) *kubernetes.Clientset {
+ config, err := GetConfig(kubeconfig)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
+ os.Exit(1)
+ }
+
+ clientset, err := kubernetes.NewForConfig(config)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
+ os.Exit(1)
+ }
+ return clientset
+}
+
+func GetAPIExtensionsClient(kubeconfig string) *apiextensionsclientset.Clientset {
+ config, err := GetConfig(kubeconfig)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
+ os.Exit(1)
+ }
+
+ clientset, err := apiextensionsclientset.NewForConfig(config)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
+ os.Exit(1)
+ }
+ return clientset
+}
+
+func GetDynamicClient(kubeconfig string) *dynamic.DynamicClient {
+ config, err := GetConfig(kubeconfig)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
+ os.Exit(1)
+ }
+
+ clientset, err := dynamic.NewForConfig(config)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
+ os.Exit(1)
+ }
+ return clientset
+}
+
+func (c ClientSet) GetArgoRolloutsClient() versioned.Interface {
+ return c.coreClientArgoRollouts
+}
+
+// GetKubernetesClient returns the Kubernetes core client.
+func (c ClientSet) GetKubernetesClient() kubernetes.Interface {
+ return c.coreClient
+}
+
+func GetKubeClientForCrds(kubeconfig string, clientset *kubernetes.Clientset) (ClientInterface, error) {
+ config, err := GetConfig(kubeconfig)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
+ os.Exit(1)
+ }
+ clientsetall, err := NewClientSetForCrd(config, clientset)
+
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
+ os.Exit(1)
+ }
+ return clientsetall, nil
+}
+
+func NewClientSetForCrd(config *rest.Config, clientset *kubernetes.Clientset) (ClientInterface, error) {
+ // Create the custom v1 client
+ coreClientArgoRolloutsV1Client, err := versioned.NewForConfig(config)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create Argo Rollouts client: %v", err)
+ }
+
+ // Return the ClientSet struct
+ return &ClientSet{
+ coreClient: clientset,
+ coreClientArgoRollouts: coreClientArgoRolloutsV1Client,
+ }, nil
+}
diff --git a/pkg/filters/options.go b/pkg/filters/options.go
index 0244b0f1..db98afa7 100644
--- a/pkg/filters/options.go
+++ b/pkg/filters/options.go
@@ -39,8 +39,9 @@ type Options struct {
// IncludeNamespaces is a namespace selector to include resources in matching namespaces
IncludeNamespaces []string
- namespace []string
- once sync.Once
+ namespace []string
+ once sync.Once
+ IncludeThirdPartyCrds []string
}
// NewFilterOptions returns a new FilterOptions instance with default values
@@ -160,6 +161,22 @@ func (o *Options) Namespaces(clientset kubernetes.Interface) []string {
return o.namespace
}
+func (o *Options) CleanRepeatedCrds() []string {
+ if len(o.IncludeThirdPartyCrds) > 0 {
+ keys := make(map[string]bool)
+ includecrdsNew := make([]string, 0)
+
+ for _, entry := range o.IncludeThirdPartyCrds {
+ if _, value := keys[entry]; !value {
+ keys[entry] = true
+ includecrdsNew = append(includecrdsNew, entry)
+ }
+ o.IncludeThirdPartyCrds = includecrdsNew
+ }
+ }
+ return o.IncludeThirdPartyCrds
+}
+
func (o *Options) modifyLabels() {
if o.IncludeLabels != "" {
if len(o.ExcludeLabels) > 0 {
diff --git a/pkg/kor/all.go b/pkg/kor/all.go
index ffaad22b..bf320e50 100644
--- a/pkg/kor/all.go
+++ b/pkg/kor/all.go
@@ -10,6 +10,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/common"
"github.com/yonahd/kor/pkg/filters"
)
@@ -277,7 +278,7 @@ func getUnusedRoleBindings(clientset kubernetes.Interface, namespace string, fil
return namespaceRoleBindingDiff
}
-func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
+func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts) (string, error) {
resources := make(map[string]map[string][]ResourceInfo)
for _, namespace := range filterOpts.Namespaces(clientset) {
switch opts.GroupBy {
@@ -300,6 +301,8 @@ func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.In
resources[namespace]["DaemonSet"] = getUnusedDaemonSets(clientset, namespace, filterOpts).diff
resources[namespace]["NetworkPolicy"] = getUnusedNetworkPolicies(clientset, namespace, filterOpts).diff
resources[namespace]["RoleBinding"] = getUnusedRoleBindings(clientset, namespace, filterOpts).diff
+ GetUnusedCrdsThirdParty(opts.GroupBy, clientsetinterface, namespace, filterOpts, resources, true)
+
case "resource":
appendResources(resources, "ConfigMap", namespace, getUnusedCMs(clientset, namespace, filterOpts).diff)
appendResources(resources, "Service", namespace, getUnusedSVCs(clientset, namespace, filterOpts).diff)
@@ -318,6 +321,7 @@ func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.In
appendResources(resources, "DaemonSet", namespace, getUnusedDaemonSets(clientset, namespace, filterOpts).diff)
appendResources(resources, "NetworkPolicy", namespace, getUnusedNetworkPolicies(clientset, namespace, filterOpts).diff)
appendResources(resources, "RoleBinding", namespace, getUnusedRoleBindings(clientset, namespace, filterOpts).diff)
+ GetUnusedCrdsThirdParty(opts.GroupBy, clientsetinterface, namespace, filterOpts, resources, true)
}
}
@@ -341,7 +345,7 @@ func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.In
return unusedAllNamespaced, nil
}
-func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
+func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, clientsetinterface clusterconfig.ClientInterface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
resources := make(map[string]map[string][]ResourceInfo)
switch opts.GroupBy {
case "namespace":
@@ -350,11 +354,13 @@ func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes
resources[""]["Pv"] = getUnusedPvs(clientset, filterOpts).diff
resources[""]["ClusterRole"] = getUnusedClusterRoles(clientset, filterOpts).diff
resources[""]["StorageClass"] = getUnusedStorageClasses(clientset, filterOpts).diff
+ GetUnusedCrdsThirdParty(opts.GroupBy, clientsetinterface, "", filterOpts, resources, false)
case "resource":
appendResources(resources, "Crd", "", getUnusedCrds(apiExtClient, dynamicClient, filterOpts).diff)
appendResources(resources, "Pv", "", getUnusedPvs(clientset, filterOpts).diff)
appendResources(resources, "ClusterRole", "", getUnusedClusterRoles(clientset, filterOpts).diff)
appendResources(resources, "StorageClass", "", getUnusedStorageClasses(clientset, filterOpts).diff)
+ GetUnusedCrdsThirdParty(opts.GroupBy, clientsetinterface, "", filterOpts, resources, false)
}
var outputBuffer bytes.Buffer
@@ -377,8 +383,8 @@ func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes
return unusedAllNonNamespaced, nil
}
-func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
- unusedAllNamespaced, err := GetUnusedAllNamespaced(filterOpts, clientset, outputFormat, opts)
+func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts) (string, error) {
+ unusedAllNamespaced, err := GetUnusedAllNamespaced(filterOpts, clientset, clientsetinterface, outputFormat, opts)
if err != nil {
fmt.Printf("err: %v\n", err)
}
@@ -388,7 +394,7 @@ func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, a
return unusedAllNamespaced, nil
}
- unusedAllNonNamespaced, err := GetUnusedAllNonNamespaced(filterOpts, clientset, apiExtClient, dynamicClient, outputFormat, opts)
+ unusedAllNonNamespaced, err := GetUnusedAllNonNamespaced(filterOpts, clientset, clientsetinterface, apiExtClient, dynamicClient, outputFormat, opts)
if err != nil {
fmt.Printf("err: %v\n", err)
}
@@ -424,3 +430,37 @@ func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, a
return string(jsonResponse), nil
}
}
+
+func GetUnusedCrdsThirdParty(groupBy string, clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options, resources map[string]map[string][]ResourceInfo, namespaced bool) map[string]map[string][]ResourceInfo {
+ for _, crd := range filterOpts.CleanRepeatedCrds() {
+ if namespaced {
+ switch crd {
+ case "argo-rollouts":
+ unusedArgoRollouts := GetUnusedArgoRollouts(clientsetinterface, namespace, filterOpts)
+ separateItemsThirdParty(resources, namespace, groupBy, "ArgoRollout", unusedArgoRollouts.diff)
+ case "argo-rollouts-analysis-templates":
+ unusedArgoRolloutsAnalysisTemplates := GetUnusedArgoRolloutsAnalysisTemplates(clientsetinterface, namespace, filterOpts)
+ separateItemsThirdParty(resources, namespace, groupBy, "ArgoRollouts-AnalysisTemplate", unusedArgoRolloutsAnalysisTemplates.diff)
+ }
+ }
+ if !namespaced {
+ switch crd {
+ case "argo-rollouts-cluster-analysis-templates":
+ unusedArgoRolloutsClusterAnalysisTemplates := GetUnusedArgoRolloutsClusterAnalysisTemplates(clientsetinterface, "", filterOpts)
+ separateItemsThirdParty(resources, "", groupBy, "ArgoRollouts-ClusterAnalysisTemplate", unusedArgoRolloutsClusterAnalysisTemplates.diff)
+ }
+ }
+ }
+ return resources
+}
+
+func separateItemsThirdParty(resources map[string]map[string][]ResourceInfo, namespace string, groupBy string, name string, diff []ResourceInfo) map[string]map[string][]ResourceInfo {
+ switch groupBy {
+ case "namespace":
+ resources[namespace][name] = diff
+ case "resource":
+ appendResources(resources, name, namespace, diff)
+ }
+
+ return resources
+}
diff --git a/pkg/kor/argorollouts.go b/pkg/kor/argorollouts.go
new file mode 100644
index 00000000..ef4b25d8
--- /dev/null
+++ b/pkg/kor/argorollouts.go
@@ -0,0 +1,214 @@
+package kor
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/yonahd/kor/pkg/clusterconfig"
+ "github.com/yonahd/kor/pkg/filters"
+)
+
+func GetUnusedArgoRollouts(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ResourceDiff {
+ argoRolloutsDiff, err := processNamespaceArgoRollouts(clientsetinterface, namespace, filterOpts)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "argorollouts", namespace, err)
+ }
+ namespaceSADiff := ResourceDiff{
+ "ArgoRollouts",
+ argoRolloutsDiff,
+ }
+
+ return namespaceSADiff
+}
+
+func GetUnusedArgoRolloutsAnalysisTemplates(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ResourceDiff {
+ argoRolloutsDiff, err := processNamespaceArgoAnalysisTemplate(clientsetinterface, namespace, filterOpts)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "analysis templates from Argo rollouts", namespace, err)
+ }
+
+ namespaceSADiff := ResourceDiff{
+ "Analysis Templates",
+ argoRolloutsDiff,
+ }
+
+ return namespaceSADiff
+}
+
+func GetUnusedArgoRolloutsClusterAnalysisTemplates(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ResourceDiff {
+ argoRolloutsDiff, err := processNamespaceArgoClusterAnalysisTemplate(clientsetinterface, namespace, filterOpts)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "analysis templates from Argo rollouts", namespace, err)
+ }
+
+ namespaceSADiff := ResourceDiff{
+ "Cluster Analysis Templates",
+ argoRolloutsDiff,
+ }
+
+ return namespaceSADiff
+}
+
+func processNamespaceArgoRollouts(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ([]ResourceInfo, error) {
+ clientset := clientsetinterface.GetKubernetesClient()
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+ argoRolloutList, err := clientsetargorollouts.ArgoprojV1alpha1().Rollouts(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
+
+ if err != nil {
+ return nil, err
+ }
+
+ var argoRolloutWithoutReplicas []ResourceInfo
+
+ for _, argoRollout := range argoRolloutList.Items {
+ if pass, _ := filter.SetObject(&argoRollout).Run(filterOpts); pass {
+ continue
+ }
+ if argoRollout.Labels["kor/used"] == "false" {
+ reason := "Marked with unused label"
+ argoRolloutWithoutReplicas = append(argoRolloutWithoutReplicas, ResourceInfo{Name: argoRollout.Name, Reason: reason})
+ continue
+ }
+ deploymentWorkLoadRef := argoRollout.Spec.WorkloadRef
+
+ if deploymentWorkLoadRef == nil {
+ if *argoRollout.Spec.Replicas == 0 {
+ reason := "Rollout has 0 replicas"
+ argoRolloutWithoutReplicas = append(argoRolloutWithoutReplicas, ResourceInfo{Name: argoRollout.Name, Reason: reason})
+ }
+ }
+
+ if deploymentWorkLoadRef != nil && deploymentWorkLoadRef.Kind == "Deployment" {
+ deploymentItem, _ := clientset.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentWorkLoadRef.Name, metav1.GetOptions{})
+
+ if deploymentItem.GetName() == "" {
+ reason := "Rollout has no deployments"
+ argoRolloutWithoutReplicas = append(argoRolloutWithoutReplicas, ResourceInfo{Name: argoRollout.Name, Reason: reason})
+ }
+ }
+ }
+
+ return argoRolloutWithoutReplicas, nil
+}
+
+func processNamespaceArgoAnalysisTemplate(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ([]ResourceInfo, error) {
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+ argoRolloutList, err := clientsetargorollouts.ArgoprojV1alpha1().Rollouts(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
+ argoRolloutAnalysisTemplateList, _ := clientsetargorollouts.ArgoprojV1alpha1().AnalysisTemplates(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
+ if err != nil {
+ return nil, err
+ }
+
+ var analysisTemplateList []ResourceInfo
+
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ if argoRolloutAnalysisTemplate.Labels["kor/used"] == "false" {
+ reason := "Marked with unused label"
+ analysisTemplateList = append(analysisTemplateList, ResourceInfo{Name: argoRolloutAnalysisTemplate.Name, Reason: reason})
+ continue
+ }
+ }
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ templateNameInUse := false
+ for _, argoRollout := range argoRolloutList.Items {
+ if pass, _ := filter.SetObject(&argoRollout).Run(filterOpts); pass {
+ continue
+ }
+
+ skip := argoRollout.Spec.Strategy.Canary == nil || argoRollout.Spec.Strategy.Canary.Analysis == nil || len(argoRollout.Spec.Strategy.Canary.Analysis.Templates) < 1
+ if !skip {
+ rolloutCanaryAnalysis := argoRollout.Spec.Strategy.Canary.Analysis.Templates
+ for _, canaryAnalysisItem := range rolloutCanaryAnalysis {
+ templateNameInUse = canaryAnalysisItem.TemplateName == argoRolloutAnalysisTemplate.Name
+ if templateNameInUse {
+ continue
+ }
+ }
+ }
+
+ skip = argoRollout.Spec.Strategy.BlueGreen == nil || argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis == nil || len(argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis.Templates) < 1
+ if !skip {
+ rolloutBlueGreenAnalysis := argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis.Templates
+ for _, blueGreenAnalysisAnalysisItem := range rolloutBlueGreenAnalysis {
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ templateNameInUse = blueGreenAnalysisAnalysisItem.TemplateName == argoRolloutAnalysisTemplate.Name
+ if templateNameInUse {
+ continue
+ }
+ }
+ }
+ }
+ }
+ if !templateNameInUse {
+ reason := "Argo Rollouts Analysis Templates is not in use"
+ analysisTemplateList = append(analysisTemplateList, ResourceInfo{Name: argoRolloutAnalysisTemplate.Name, Reason: reason})
+ }
+ }
+ return analysisTemplateList, nil
+}
+
+func processNamespaceArgoClusterAnalysisTemplate(clientsetinterface clusterconfig.ClientInterface, namespace string, filterOpts *filters.Options) ([]ResourceInfo, error) {
+ clientset := clientsetinterface.GetKubernetesClient()
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+
+ var clusterAnalysisTemplateList []ResourceInfo
+
+ argoRolloutAnalysisTemplateList, _ := clientsetargorollouts.ArgoprojV1alpha1().ClusterAnalysisTemplates().List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ if argoRolloutAnalysisTemplate.Labels["kor/used"] == "false" {
+ reason := "Marked with unused label"
+ clusterAnalysisTemplateList = append(clusterAnalysisTemplateList, ResourceInfo{Name: argoRolloutAnalysisTemplate.Name, Reason: reason})
+ continue
+ }
+ }
+
+ for _, namespace := range filterOpts.Namespaces(clientset) {
+ argoRolloutList, _ := clientsetargorollouts.ArgoprojV1alpha1().Rollouts(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
+
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ templateNameInUse := false
+ for _, argoRollout := range argoRolloutList.Items {
+ if pass, _ := filter.SetObject(&argoRollout).Run(filterOpts); pass {
+ continue
+ }
+
+ templateNameInUse = false
+ skip := argoRollout.Spec.Strategy.Canary == nil || argoRollout.Spec.Strategy.Canary.Analysis == nil || len(argoRollout.Spec.Strategy.Canary.Analysis.Templates) < 1
+ if !skip {
+ rolloutCanaryAnalysis := argoRollout.Spec.Strategy.Canary.Analysis.Templates
+ for _, canaryAnalysisItem := range rolloutCanaryAnalysis {
+ if canaryAnalysisItem.TemplateName == argoRolloutAnalysisTemplate.Name {
+ templateNameInUse = true
+ continue
+ }
+
+ }
+ }
+
+ skip = argoRollout.Spec.Strategy.BlueGreen == nil || argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis == nil || len(argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis.Templates) < 1
+ if !skip {
+ rolloutBlueGreenAnalysis := argoRollout.Spec.Strategy.BlueGreen.PrePromotionAnalysis.Templates
+ for _, blueGreenAnalysisAnalysisItem := range rolloutBlueGreenAnalysis {
+ for _, argoRolloutAnalysisTemplate := range argoRolloutAnalysisTemplateList.Items {
+ if blueGreenAnalysisAnalysisItem.TemplateName == argoRolloutAnalysisTemplate.Name {
+ templateNameInUse = true
+ continue
+ }
+ }
+ }
+ }
+ }
+ if !templateNameInUse {
+ reason := "Argo Rollouts Cluster Analysis Templates is not in use"
+ if !SkipIfContainsValue(clusterAnalysisTemplateList, "Name", argoRolloutAnalysisTemplate.Name) {
+ clusterAnalysisTemplateList = append(clusterAnalysisTemplateList, ResourceInfo{Name: argoRolloutAnalysisTemplate.Name, Reason: reason})
+ }
+ }
+ }
+ }
+
+ return clusterAnalysisTemplateList, nil
+}
diff --git a/pkg/kor/argorollouts_test.go b/pkg/kor/argorollouts_test.go
new file mode 100644
index 00000000..3e67b57c
--- /dev/null
+++ b/pkg/kor/argorollouts_test.go
@@ -0,0 +1,434 @@
+package kor
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "reflect"
+ "testing"
+
+ "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
+ appsv1 "k8s.io/api/apps/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"
+ "k8s.io/client-go/kubernetes/scheme"
+
+ "github.com/yonahd/kor/pkg/clusterconfig"
+ "github.com/yonahd/kor/pkg/common"
+ "github.com/yonahd/kor/pkg/filters"
+)
+
+func createTestArgoRolloutMultiResources(t *testing.T, rolloutName string, implementationType string) (kubernetes.Interface, clusterconfig.ClientInterface, *appsv1.Deployment) {
+ clientsetinterface, _ := NewFakeClientSet(t)
+ clientset := clientsetinterface.GetKubernetesClient()
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+
+ _, 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)
+ }
+
+ deploymentName := "test-deployment1"
+
+ deployment := CreateTestDeployment(testNamespace, deploymentName, 0, AppLabels)
+ _, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake deployment: %v", err)
+ }
+
+ rollout := CreateTestArgoRolloutWithDeployment(testNamespace, rolloutName, deployment, AppLabels, implementationType)
+
+ _, err = clientsetargorollouts.ArgoprojV1alpha1().Rollouts(testNamespace).Create(context.TODO(), rollout, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake argo rollout: %v", err)
+ }
+
+ return clientset, clientsetinterface, deployment
+
+}
+
+func createTestArgoRolloutMultiResourcesWithAnalysis(t *testing.T, rolloutName string, analysisName string, implementationType string) (kubernetes.Interface, clusterconfig.ClientInterface, *appsv1.Deployment) {
+ clientsetinterface, _ := NewFakeClientSet(t)
+ clientset := clientsetinterface.GetKubernetesClient()
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+
+ _, 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)
+ }
+
+ deploymentName := "test-deployment2"
+
+ deployment := CreateTestDeployment(testNamespace, deploymentName, 0, AppLabels)
+ _, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake deployment: %v", err)
+ }
+ var rollout *v1alpha1.Rollout
+ if implementationType == "bluegreen" {
+ rollout = CreateTestArgoRolloutWithDeployment(testNamespace, rolloutName, deployment, AppLabels, implementationType)
+ } else {
+ rollout = CreateTestArgoRolloutWithDeployment(testNamespace, rolloutName, deployment, AppLabels, implementationType)
+ }
+
+ _, err = clientsetargorollouts.ArgoprojV1alpha1().Rollouts(testNamespace).Create(context.TODO(), rollout, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake argo rollout: %v", err)
+ }
+
+ analysisTemplate := CreateTestArgoRolloutAnalysis(testNamespace, analysisName, AppLabels)
+ _, err = clientsetargorollouts.ArgoprojV1alpha1().AnalysisTemplates(testNamespace).Create(context.TODO(), analysisTemplate, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake analysis template for argo rollout: %v", err)
+ }
+
+ return clientset, clientsetinterface, deployment
+
+}
+
+func createTestArgoRolloutMultiResourcesWithClusterAnalysis(t *testing.T, rolloutName string, analysisName string, implementationType string) (kubernetes.Interface, clusterconfig.ClientInterface, *appsv1.Deployment) {
+ clientsetinterface, _ := NewFakeClientSet(t)
+ clientset := clientsetinterface.GetKubernetesClient()
+ clientsetargorollouts := clientsetinterface.GetArgoRolloutsClient()
+
+ _, 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)
+ }
+
+ deploymentName := "test-deployment2"
+
+ deployment := CreateTestDeployment(testNamespace, deploymentName, 0, AppLabels)
+ _, err = clientset.AppsV1().Deployments(testNamespace).Create(context.TODO(), deployment, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake deployment: %v", err)
+ }
+ var rollout *v1alpha1.Rollout
+ if implementationType == "bluegreen" {
+ rollout = CreateTestArgoRolloutWithDeployment(testNamespace, rolloutName, deployment, AppLabels, implementationType)
+ } else {
+ rollout = CreateTestArgoRolloutWithDeployment(testNamespace, rolloutName, deployment, AppLabels, implementationType)
+ }
+
+ _, err = clientsetargorollouts.ArgoprojV1alpha1().Rollouts(testNamespace).Create(context.TODO(), rollout, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake argo rollout: %v", err)
+ }
+
+ analysisTemplate := CreateTestArgoRolloutClusterAnalysis(analysisName, AppLabels)
+ _, err = clientsetargorollouts.ArgoprojV1alpha1().ClusterAnalysisTemplates().Create(context.TODO(), analysisTemplate, v1.CreateOptions{})
+ if err != nil {
+ t.Fatalf("Error creating fake analysis template for argo rollout: %v", err)
+ }
+
+ return clientset, clientsetinterface, deployment
+
+}
+
+func TestGetUnusedArgoRolloutsStructuredByNamespace(t *testing.T) {
+ rolloutName := "test-rollout-1"
+ implementationType := "canary"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResources(t, rolloutName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.Name, v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ parseOpts := common.Opts{}
+ parseOpts.GroupBy = "namespace"
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, "testNamespace")
+
+ resources := make(map[string]map[string][]ResourceInfo)
+ resources[testNamespace] = make(map[string][]ResourceInfo)
+
+ var outputBuffer bytes.Buffer
+ var jsonResponse []byte
+
+ GetUnusedCrdsThirdParty("namespace", clientsetinterface, testNamespace, opts, resources, true)
+ jsonResponse, err = json.MarshalIndent(resources, "", " ")
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ unused, err := unusedResourceFormatter("json", outputBuffer, parseOpts, jsonResponse)
+ if err != nil {
+ t.Fatalf("Error on get argorollout unused: %v", err)
+ }
+
+ expectedOutput := map[string]map[string][]string{
+ testNamespace: {
+ "ArgoRollout": {
+ rolloutName,
+ },
+ },
+ }
+ var actualOutput map[string]map[string][]string
+ if err := json.Unmarshal([]byte(unused), &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 TestGetUnusedArgoRolloutsStructuredByResources(t *testing.T) {
+ rolloutName := "test-rollout-1"
+ implementationType := "canary"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResources(t, rolloutName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.Name, v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ parseOpts := common.Opts{}
+ parseOpts.GroupBy = "resource"
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, "testNamespace")
+
+ resources := make(map[string]map[string][]ResourceInfo)
+ resources[testNamespace] = make(map[string][]ResourceInfo)
+
+ var outputBuffer bytes.Buffer
+ var jsonResponse []byte
+
+ GetUnusedCrdsThirdParty("resource", clientsetinterface, testNamespace, opts, resources, true)
+
+ jsonResponse, err = json.MarshalIndent(resources, "", " ")
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ unused, err := unusedResourceFormatter("json", outputBuffer, parseOpts, jsonResponse)
+ if err != nil {
+ t.Fatalf("Error on get argorollout unused: %v", err)
+ }
+
+ expectedOutput := map[string]map[string][]string{
+ "ArgoRollout": {
+ testNamespace: {
+ rolloutName,
+ },
+ },
+ }
+
+ var actualOutput map[string]map[string][]string
+ if err := json.Unmarshal([]byte(unused), &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 TestGetUnusedArgoRolloutsCanary(t *testing.T) {
+ rolloutName := "test-rollout-2"
+ implementationType := "canary"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResources(t, rolloutName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRollouts(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: rolloutName, Reason: "Rollout has no deployments"})
+ expectedOutput := ResourceDiff{
+ "ArgoRollouts",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func TestGetUnusedArgoRolloutsBlueGreen(t *testing.T) {
+ rolloutName := "test-rollout-3"
+ implementationType := "bluegreen"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResources(t, rolloutName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRollouts(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: rolloutName, Reason: "Rollout has no deployments"})
+ expectedOutput := ResourceDiff{
+ "ArgoRollouts",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func TestGetUnusedArgoRolloutsAnalysisTemplatesCanary(t *testing.T) {
+ analysisName := "test-analysys-template-1"
+ rolloutName := "test-rollout-4"
+ implementationType := "canary"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResourcesWithAnalysis(t, rolloutName, analysisName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRolloutsAnalysisTemplates(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: analysisName, Reason: "Argo Rollouts Analysis Templates is not in use"})
+ expectedOutput := ResourceDiff{
+ "Analysis Templates",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func TestGetUnusedArgoRolloutsAnalysisTemplatesBlueGreen(t *testing.T) {
+ analysisName := "test-analysys-template-2"
+ rolloutName := "test-rollout-5"
+ implementationType := "bluegreen"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResourcesWithAnalysis(t, rolloutName, analysisName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRolloutsAnalysisTemplates(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: analysisName, Reason: "Argo Rollouts Analysis Templates is not in use"})
+ expectedOutput := ResourceDiff{
+ "Analysis Templates",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func TestGetUnusedArgoRolloutsClusterAnalysisTemplatesCanary(t *testing.T) {
+ analysisName := "test-analysys-template-3"
+ rolloutName := "test-rollout-6"
+ implementationType := "canary"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResourcesWithClusterAnalysis(t, rolloutName, analysisName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRolloutsClusterAnalysisTemplates(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: analysisName, Reason: "Argo Rollouts Cluster Analysis Templates is not in use"})
+ expectedOutput := ResourceDiff{
+ "Cluster Analysis Templates",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func TestGetUnusedArgoRolloutsClusterAnalysisTemplatesBlueGreen(t *testing.T) {
+ analysisName := "test-analysys-template-4"
+ rolloutName := "test-rollout-7"
+ implementationType := "bluegreen"
+ clientset, clientsetinterface, deployment := createTestArgoRolloutMultiResourcesWithClusterAnalysis(t, rolloutName, analysisName, implementationType)
+
+ err := clientset.AppsV1().Deployments(testNamespace).Delete(context.TODO(), deployment.GetName(), v1.DeleteOptions{})
+ if err != nil {
+ t.Fatalf("Error on delete test deployment %s for argorollout testing: %v", deployment.GetName(), err)
+ }
+
+ opts := &filters.Options{}
+ opts.IncludeThirdPartyCrds = append(opts.IncludeThirdPartyCrds, "argo-rollouts")
+ opts.IncludeNamespaces = append(opts.IncludeNamespaces, testNamespace)
+
+ resources := GetUnusedArgoRolloutsClusterAnalysisTemplates(clientsetinterface, testNamespace, opts)
+ if err != nil {
+ t.Fatalf("Error marshaling jsonResponse: %v", err)
+ }
+
+ var argoRolloutsDiffTest []ResourceInfo
+ argoRolloutsDiffTest = append(argoRolloutsDiffTest, ResourceInfo{Name: analysisName, Reason: "Argo Rollouts Cluster Analysis Templates is not in use"})
+ expectedOutput := ResourceDiff{
+ "Cluster Analysis Templates",
+ argoRolloutsDiffTest,
+ }
+
+ if !reflect.DeepEqual(expectedOutput, resources) {
+ t.Errorf("Expected output does not match actual output")
+ }
+}
+
+func init() {
+ scheme.Scheme = runtime.NewScheme()
+ _ = appsv1.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/kor/config_test.go b/pkg/kor/config_test.go
new file mode 100644
index 00000000..e997d7d1
--- /dev/null
+++ b/pkg/kor/config_test.go
@@ -0,0 +1,57 @@
+package kor
+
+import (
+ "testing"
+
+ "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned"
+ fakeargorollouts "github.com/argoproj/argo-rollouts/pkg/client/clientset/versioned/fake"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/kubernetes/fake"
+
+ "github.com/yonahd/kor/pkg/clusterconfig"
+)
+
+type FakeClientSet struct {
+ coreClient *fake.Clientset
+ coreClientArgoRollouts *fakeargorollouts.Clientset
+}
+
+// GetArgoRolloutsClient implements ClientInterface.
+func (c *FakeClientSet) GetArgoRolloutsClient() versioned.Interface {
+ return c.coreClientArgoRollouts
+}
+
+// GetKubernetesClient implements ClientInterface.
+func (c *FakeClientSet) GetKubernetesClient() kubernetes.Interface {
+ return c.coreClient
+}
+
+func NewFakeClientSet(t *testing.T) (clusterconfig.ClientInterface, error) {
+ coreClient := fake.NewSimpleClientset()
+ coreClientArgoRollouts := fakeargorollouts.NewSimpleClientset()
+
+ // Return the ClientSet struct
+ return &FakeClientSet{
+ coreClient: coreClient,
+ coreClientArgoRollouts: coreClientArgoRollouts,
+ }, nil
+}
+
+func GetFakeKubeClient(t *testing.T) (clusterconfig.ClientInterface, error) {
+ clientsetinterface, err := NewFakeClientSet(t)
+
+ if err != nil {
+ t.Fatalf("Error creating fake clientset. Error: %v", err)
+ }
+
+ return clientsetinterface, nil
+}
+
+func SetConfigsForTests(t *testing.T) clusterconfig.ClientInterface {
+ clientsetinterface, err := GetFakeKubeClient(t)
+ if err != nil {
+ t.Fatalf("Error on setting config: %v", err)
+ }
+
+ return clientsetinterface
+}
diff --git a/pkg/kor/create_test_resources.go b/pkg/kor/create_test_resources.go
index 8e2c2ce6..3d9ab4f5 100644
--- a/pkg/kor/create_test_resources.go
+++ b/pkg/kor/create_test_resources.go
@@ -1,6 +1,7 @@
package kor
import (
+ argorollouts "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
batchv1 "k8s.io/api/batch/v1"
@@ -431,3 +432,59 @@ func CreateTestNetworkPolicy(name, namespace string, labels map[string]string, p
},
}
}
+
+func CreateTestArgoRolloutWithDeployment(namespace, name string, deplomentWorkLoadRef *appsv1.Deployment, labels map[string]string, implementationType string) *argorollouts.Rollout {
+ rollout := &argorollouts.Rollout{
+ ObjectMeta: v1.ObjectMeta{
+ Namespace: namespace,
+ Name: name,
+ Labels: labels,
+ },
+ }
+ if implementationType == "canary" {
+ rollout.Spec = argorollouts.RolloutSpec{
+ WorkloadRef: &argorollouts.ObjectRef{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ Name: deplomentWorkLoadRef.GetName(),
+ },
+ Strategy: argorollouts.RolloutStrategy{
+ Canary: &argorollouts.CanaryStrategy{},
+ },
+ }
+ }
+ if implementationType == "bluegreen" {
+ rollout.Spec = argorollouts.RolloutSpec{
+ WorkloadRef: &argorollouts.ObjectRef{
+ APIVersion: "apps/v1",
+ Kind: "Deployment",
+ Name: deplomentWorkLoadRef.GetName(),
+ },
+ Strategy: argorollouts.RolloutStrategy{
+ BlueGreen: &argorollouts.BlueGreenStrategy{},
+ },
+ }
+ }
+ return rollout
+}
+
+func CreateTestArgoRolloutAnalysis(namespace, analysisName string, labels map[string]string) *argorollouts.AnalysisTemplate {
+
+ return &argorollouts.AnalysisTemplate{
+ ObjectMeta: v1.ObjectMeta{
+ Namespace: namespace,
+ Name: analysisName,
+ Labels: labels,
+ },
+ }
+}
+
+func CreateTestArgoRolloutClusterAnalysis(analysisName string, labels map[string]string) *argorollouts.ClusterAnalysisTemplate {
+ return &argorollouts.ClusterAnalysisTemplate{
+ ObjectMeta: v1.ObjectMeta{
+
+ Name: analysisName,
+ Labels: labels,
+ },
+ }
+}
diff --git a/pkg/kor/exporter.go b/pkg/kor/exporter.go
index 39b66c3b..45891df8 100644
--- a/pkg/kor/exporter.go
+++ b/pkg/kor/exporter.go
@@ -15,6 +15,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/common"
"github.com/yonahd/kor/pkg/filters"
)
@@ -34,16 +35,16 @@ func init() {
}
// TODO: add option to change port / url !?
-func Exporter(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) {
+func Exporter(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts, resourceList []string) {
http.Handle("/metrics", promhttp.Handler())
fmt.Println("Server listening on :8080")
- go exportMetrics(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts, resourceList) // Start exporting metrics in the background
+ go exportMetrics(filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts, resourceList) // Start exporting metrics in the background
if err := http.ListenAndServe(":8080", nil); err != nil {
fmt.Println(err)
}
}
-func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) {
+func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts, resourceList []string) {
exporterInterval := os.Getenv("EXPORTER_INTERVAL")
if exporterInterval == "" {
exporterInterval = "10"
@@ -56,7 +57,7 @@ func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interfac
for {
fmt.Println("collecting unused resources")
- if korOutput, err := getUnusedResources(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts, resourceList); err != nil {
+ if korOutput, err := getUnusedResources(filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts, resourceList); err != nil {
fmt.Println(err)
os.Exit(1)
} else {
@@ -80,10 +81,10 @@ func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interfac
}
}
-func getUnusedResources(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) (string, error) {
+func getUnusedResources(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts, resourceList []string) (string, error) {
if len(resourceList) == 0 || (len(resourceList) == 1 && resourceList[0] == "all") {
- return GetUnusedAll(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts)
+ return GetUnusedAll(filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts)
}
- return GetUnusedMulti(strings.Join(resourceList, ","), filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts)
+ return GetUnusedMulti(strings.Join(resourceList, ","), filterOptions, clientset, apiExtClient, dynamicClient, clientsetinterface, outputFormat, opts)
}
diff --git a/pkg/kor/formatter.go b/pkg/kor/formatter.go
index cec7a0c5..932f04d0 100644
--- a/pkg/kor/formatter.go
+++ b/pkg/kor/formatter.go
@@ -235,3 +235,12 @@ func FormatOutputAll(namespace string, allDiffs []ResourceDiff, opts common.Opts
table.Render()
return fmt.Sprintf("Unused resources in namespace: %q\n%s\n", namespace, buf.String())
}
+
+func SkipIfContainsValue(data []ResourceInfo, key string, value interface{}) bool {
+ for _, item := range data {
+ if item.Name == value {
+ return true
+ }
+ }
+ return false
+}
diff --git a/pkg/kor/kor.go b/pkg/kor/kor.go
index be6968c0..2f5b135d 100644
--- a/pkg/kor/kor.go
+++ b/pkg/kor/kor.go
@@ -2,18 +2,8 @@ package kor
import (
"encoding/json"
- "fmt"
- "os"
- "path/filepath"
"regexp"
"sort"
-
- apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
- "k8s.io/client-go/dynamic"
- "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/clientcmd"
- "k8s.io/client-go/util/homedir"
)
type ExceptionResource struct {
@@ -55,72 +45,6 @@ func RemoveDuplicatesAndSort(slice []string) []string {
return uniqueSlice
}
-func GetKubeConfigPath() string {
- home := homedir.HomeDir()
- return filepath.Join(home, ".kube", "config")
-}
-
-func GetConfig(kubeconfig string) (*rest.Config, error) {
- if _, err := os.Stat("/var/run/secrets/kubernetes.io/serviceaccount/token"); err == nil {
- return rest.InClusterConfig()
- }
-
- if kubeconfig == "" {
- if configEnv := os.Getenv("KUBECONFIG"); configEnv != "" {
- kubeconfig = configEnv
- } else {
- kubeconfig = GetKubeConfigPath()
- }
- }
-
- return clientcmd.BuildConfigFromFlags("", kubeconfig)
-}
-
-func GetKubeClient(kubeconfig string) *kubernetes.Clientset {
- config, err := GetConfig(kubeconfig)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
- os.Exit(1)
- }
-
- clientset, err := kubernetes.NewForConfig(config)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
- os.Exit(1)
- }
- return clientset
-}
-
-func GetAPIExtensionsClient(kubeconfig string) *apiextensionsclientset.Clientset {
- config, err := GetConfig(kubeconfig)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
- os.Exit(1)
- }
-
- clientset, err := apiextensionsclientset.NewForConfig(config)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
- os.Exit(1)
- }
- return clientset
-}
-
-func GetDynamicClient(kubeconfig string) *dynamic.DynamicClient {
- config, err := GetConfig(kubeconfig)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to load kubeconfig: %v\n", err)
- os.Exit(1)
- }
-
- clientset, err := dynamic.NewForConfig(config)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Failed to create Kubernetes client: %v\n", err)
- os.Exit(1)
- }
- return clientset
-}
-
// TODO create formatter by resource "#", "Resource Name", "Namespace"
// TODO Functions that use this object are accompanied by repeated data acquisition operations and can be optimized.
func CalculateResourceDifference(usedResourceNames []string, allResourceNames []string) []string {
diff --git a/pkg/kor/kor_test.go b/pkg/kor/kor_test.go
index eafddb17..03622283 100644
--- a/pkg/kor/kor_test.go
+++ b/pkg/kor/kor_test.go
@@ -4,6 +4,8 @@ import (
"os"
"sort"
"testing"
+
+ "github.com/yonahd/kor/pkg/clusterconfig"
)
func stringSlicesEqual(a, b []string) bool {
@@ -99,7 +101,7 @@ func TestGetKubeClientFromEnvVar(t *testing.T) {
defer os.Setenv("KUBECONFIG", originalKCEnv)
os.Setenv("KUBECONFIG", configFile.Name())
- kcs := GetKubeClient("")
+ kcs := clusterconfig.GetKubeClient("")
if kcs == nil {
t.Errorf("Expected valid clientSet")
}
@@ -125,7 +127,7 @@ func TestGetKubeClientFromInput(t *testing.T) {
os.Setenv("KUBERNETES_SERVICE_PORT", oldKubeServicePort)
}()
- kcs := GetKubeClient(configFile.Name())
+ kcs := clusterconfig.GetKubeClient(configFile.Name())
if kcs == nil {
t.Errorf("Expected valid clientSet")
}
diff --git a/pkg/kor/multi.go b/pkg/kor/multi.go
index ef2dfd94..323f2c41 100644
--- a/pkg/kor/multi.go
+++ b/pkg/kor/multi.go
@@ -11,6 +11,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/common"
"github.com/yonahd/kor/pkg/filters"
)
@@ -99,7 +100,7 @@ func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, re
return allDiffs
}
-func GetUnusedMulti(resourceNames string, filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
+func GetUnusedMulti(resourceNames string, filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, clientsetinterface clusterconfig.ClientInterface, outputFormat string, opts common.Opts) (string, error) {
resourceList := strings.Split(resourceNames, ",")
namespaces := filterOpts.Namespaces(clientset)
resources := make(map[string]map[string][]ResourceInfo)
diff --git a/pkg/kor/multi_test.go b/pkg/kor/multi_test.go
index 3c4828f2..d617cf11 100644
--- a/pkg/kor/multi_test.go
+++ b/pkg/kor/multi_test.go
@@ -8,14 +8,16 @@ import (
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes/fake"
+ "k8s.io/client-go/kubernetes"
+ "github.com/yonahd/kor/pkg/clusterconfig"
"github.com/yonahd/kor/pkg/common"
"github.com/yonahd/kor/pkg/filters"
)
-func createTestMultiResources(t *testing.T) *fake.Clientset {
- clientset := fake.NewClientset()
+func createTestMultiResources(t *testing.T) (kubernetes.Interface, clusterconfig.ClientInterface) {
+ clientsetinterface, _ := NewFakeClientSet(t)
+ clientset := clientsetinterface.GetKubernetesClient()
_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
ObjectMeta: v1.ObjectMeta{Name: testNamespace},
@@ -37,12 +39,12 @@ func createTestMultiResources(t *testing.T) *fake.Clientset {
t.Fatalf("Error creating fake configmap: %v", err)
}
- return clientset
+ return clientset, clientsetinterface
}
func TestRetrieveNamespaceDiff(t *testing.T) {
- clientset := createTestMultiResources(t)
+ clientset, _ := createTestMultiResources(t)
resourceList := []string{"cm", "pdb", "deployment"}
filterOpts := &filters.Options{}
@@ -67,7 +69,7 @@ func TestRetrieveNamespaceDiff(t *testing.T) {
}
func TestGetUnusedMulti(t *testing.T) {
- clientset := createTestMultiResources(t)
+ clientset, clientsetinterface := createTestMultiResources(t)
resourceList := "cm,pdb,deployment"
opts := common.Opts{
@@ -79,7 +81,7 @@ func TestGetUnusedMulti(t *testing.T) {
GroupBy: "namespace",
}
- output, err := GetUnusedMulti(resourceList, &filters.Options{}, clientset, nil, nil, "json", opts)
+ output, err := GetUnusedMulti(resourceList, &filters.Options{}, clientset, nil, nil, clientsetinterface, "json", opts)
if err != nil {
t.Fatalf("Error calling GetUnusedMulti: %v", err)