Skip to content

Commit

Permalink
Crd Readme and multi support (#144)
Browse files Browse the repository at this point in the history
* add crd to readme and support multi

* support crds in multi command
  • Loading branch information
yonahd committed Nov 12, 2023
1 parent 205acb0 commit dec8161
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Kor is a tool to discover unused Kubernetes resources. Currently, Kor can identi
- PVCs
- Ingresses
- PDBs
- CRDs

![Kor Screenshot](/images/screenshot.png)

Expand Down Expand Up @@ -83,6 +84,7 @@ Kor provides various subcommands to identify and list unused resources. The avai
- `pvc` - Gets unused PVCs for the specified namespace or all namespaces.
- `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.
- `exporter` - Export Prometheus metrics.

### Supported Flags
Expand Down Expand Up @@ -117,19 +119,20 @@ kor [subcommand] --help

## Supported resources and limitations

| Resource | What it looks for | Known False Positives ⚠️ |
|-----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| ConfigMaps | ConfigMaps not used in the following places:<br/>- Pods<br/>- Containers<br/>- ConfigMaps used through Volumes<br/>- ConfigMaps used through environment variables | ConfigMaps used by resources which don't explicitly state them in the config.<br/> e.g Grafana dashboards loaded dynamically OPA policies fluentd configs |
| Resource | What it looks for | Known False Positives ⚠️ |
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| ConfigMaps | ConfigMaps not used in the following places:<br/>- Pods<br/>- Containers<br/>- ConfigMaps used through Volumes<br/>- ConfigMaps used through environment variables | ConfigMaps used by resources which don't explicitly state them in the config.<br/> e.g Grafana dashboards loaded dynamically OPA policies fluentd configs |
| Secrets | Secrets not used in the following places:<br/>- Pods<br/>- Containers<br/>- Secrets used through volumes<br/>- Secrets used through environment variables<br/>- Secrets used by Ingress TLS<br/>- Secrets used by ServiceAccounts | Secrets used by resources which don't explicitly state them in the config |
| Services | Services with no endpoints | |
| Deployments | Deployments with no Replicas | |
| ServiceAccounts | ServiceAccounts unused by Pods<br/>ServiceAccounts unused by roleBinding or clusterRoleBinding | |
| StatefulSets | Statefulsets with no Replicas | |
| Roles | Roles not used in roleBinding | |
| PVCs | PVCs not used in Pods | |
| Ingresses | Ingresses not pointing at any Service | |
| Hpas | HPAs not used in Deployments<br/> HPAs not used in StatefulSets | |
| Pdbs | PDBs not used in Deployments<br/> PDBs not used in StatefulSets | |
| Services | Services with no endpoints | |
| Deployments | Deployments with no Replicas | |
| ServiceAccounts | ServiceAccounts unused by Pods<br/>ServiceAccounts unused by roleBinding or clusterRoleBinding | |
| StatefulSets | Statefulsets with no Replicas | |
| Roles | Roles not used in roleBinding | |
| PVCs | PVCs not used in Pods | |
| 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 | |
| Pdbs | PDBs not used in Deployments<br/> PDBs not used in StatefulSets | |


## Deleting Unused resources
Expand Down
6 changes: 4 additions & 2 deletions cmd/kor/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ var rootCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
resourceNames := args[0]

// Cheks whether the string contains a comma, indicating that it represents a list of resources
// Checks whether the string contains a comma, indicating that it represents a list of resources
if strings.ContainsRune(resourceNames, 44) {
clientset := kor.GetKubeClient(kubeconfig)
apiExtClient := kor.GetAPIExtensionsClient(kubeconfig)
dynamicClient := kor.GetDynamicClient(kubeconfig)

if response, err := kor.GetUnusedMulti(includeExcludeLists, resourceNames, filterOptions, clientset, outputFormat, opts); err != nil {
if response, err := kor.GetUnusedMulti(includeExcludeLists, resourceNames, filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts); err != nil {
fmt.Println(err)
} else {
fmt.Println(response)
Expand Down
40 changes: 37 additions & 3 deletions pkg/kor/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,27 @@ import (
"os"
"strings"

apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
)

func retrieveNoNamespaceDiff(apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts, resourceList []string) ([]ResourceDiff, []string) {
var noNamespaceDiff []ResourceDiff
for counter, resource := range resourceList {
if resource == "crd" || resource == "customresourcedefinition" || resource == "customresourcedefinitions" {
crdDiff := getUnusedCrds(apiExtClient, dynamicClient)
noNamespaceDiff = append(noNamespaceDiff, crdDiff)
updatedResourceList := append(resourceList[:counter], resourceList[counter+1:]...)
return noNamespaceDiff, updatedResourceList
} else {
resourceList[counter] = resource
}
}
return noNamespaceDiff, resourceList

}

func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, resourceList []string, filterOpts *FilterOptions) []ResourceDiff {
var allDiffs []ResourceDiff
for _, resource := range resourceList {
Expand Down Expand Up @@ -54,15 +72,31 @@ func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, re
return allDiffs
}

func GetUnusedMulti(includeExcludeLists IncludeExcludeLists, resourceNames string, filterOpts *FilterOptions, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
func GetUnusedMulti(includeExcludeLists IncludeExcludeLists, resourceNames string, filterOpts *FilterOptions, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) {
var allDiffs []ResourceDiff
var outputBuffer bytes.Buffer
var unusedMulti string
resourceList := strings.Split(resourceNames, ",")
namespaces := SetNamespaceList(includeExcludeLists, clientset)
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)
outputBuffer.WriteString(output)
outputBuffer.WriteString("\n")

resourceMap := make(map[string][]string)
for _, diff := range crdDiff {
resourceMap[diff.resourceType] = diff.diff
}
response[""] = resourceMap

}

for _, namespace := range namespaces {
allDiffs := retrieveNamespaceDiffs(clientset, namespace, resourceList, filterOpts)
allDiffs = retrieveNamespaceDiffs(clientset, namespace, resourceList, filterOpts)

if opts.DeleteFlag {
for _, diff := range allDiffs {
Expand All @@ -88,7 +122,7 @@ func GetUnusedMulti(includeExcludeLists IncludeExcludeLists, resourceNames strin
return "", err
}

unusedMulti, err := unusedResourceFormatter(outputFormat, outputBuffer, opts, jsonResponse)
unusedMulti, err = unusedResourceFormatter(outputFormat, outputBuffer, opts, jsonResponse)
if err != nil {
fmt.Printf("err: %v\n", err)
}
Expand Down

0 comments on commit dec8161

Please sign in to comment.