Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for the deployment resource #7

Merged
merged 2 commits into from
Jul 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Kor - Kubernetes Orphaned Resources Finder

Kor is a CLI tool to discover unused Kubernetes resources. Currently, Kor can identify and list unused ConfigMaps and Secrets.
Kor is a CLI tool to discover unused Kubernetes resources. Currently, Kor can identify and list unused:
- ConfigMaps
- Secrets.
- Services
- ServiceAccounts
- Deployments

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

Expand Down Expand Up @@ -30,10 +35,21 @@ For more information about each subcommand and its available flags, you can use
kor [subcommand] --help
```

## Supported resources and limitations

| Resource | What it looks for | Known False Positives |
|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|
| Configmaps | - Configmaps used by pods<br/>- Configmaps used by 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 |
| Secrets | - Secrets used by pods<br/>- Secrets used by containers <br/>- Secrets used through volumes <br/>- Secrets used through environment variables<br/>- Secrets used by ingress TLS<br/>-Secrets used by ServiceAccounts | |
| Services | Services with no endpoints | |
| Deployments | Deployments with 0 Replicas | |
| ServiceAccounts | ServiceAccounts used by pods | |

## Contributing

Contributions are welcome! If you encounter any bugs or have suggestions for improvements, please open an issue in the [issue tracker](https://github.com/yonahd/kor/issues).

## License

This project is open-source and available under the [MIT License](LICENSE). Feel free to use, modify, and distribute it as per the terms of the license.
This project is open-source and available under the [MIT License](LICENSE). Feel free to use, modify, and distribute it as per the terms of the license.

22 changes: 22 additions & 0 deletions cmd/kor/deployments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package kor

import (
"github.com/spf13/cobra"
"github.com/yonahd/kor/pkg/kor"
)

var deployCmd = &cobra.Command{
Use: "deployments",
Aliases: []string{"deploy"},
Short: "Gets unused deployments",
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, args []string) {
kor.GetUnusedDeployments(namespace)

},
}

func init() {
deployCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", "", "Namespace to run on")
rootCmd.AddCommand(deployCmd)
}
11 changes: 11 additions & 0 deletions pkg/kor/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ func getUnusedServiceAccounts(kubeClient *kubernetes.Clientset, namespace string
return namespaceSADiff
}

func getUnusedDeployments(kubeClient *kubernetes.Clientset, namespace string) ResourceDiff {
saDiff, err := ProcessNamespaceDeployments(kubeClient, namespace)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to get %s namespace %s: %v\n", "serviceaccounts", namespace, err)
}
namespaceSADiff := ResourceDiff{"Deployment", saDiff}
return namespaceSADiff
}

func GetUnusedAll(namespace string) {
var kubeClient *kubernetes.Clientset
var namespaces []string
Expand All @@ -64,6 +73,8 @@ func GetUnusedAll(namespace string) {
allDiffs = append(allDiffs, namespaceSecretDiff)
namespaceSADiff := getUnusedServiceAccounts(kubeClient, namespace)
allDiffs = append(allDiffs, namespaceSADiff)
namespaceDeploymentDiff := getUnusedDeployments(kubeClient, namespace)
allDiffs = append(allDiffs, namespaceDeploymentDiff)
output := FormatOutputAll(namespace, allDiffs)
fmt.Println(output)
fmt.Println()
Expand Down
56 changes: 56 additions & 0 deletions pkg/kor/deployments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package kor

import (
"context"
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"os"
)

func getDeploymentsWithoutReplicas(kubeClient *kubernetes.Clientset, namespace string) ([]string, error) {
deploymentsList, err := kubeClient.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return nil, err
}

var deploymentsWithoutReplicas []string

for _, deployment := range deploymentsList.Items {
if *deployment.Spec.Replicas == 0 {
deploymentsWithoutReplicas = append(deploymentsWithoutReplicas, deployment.Name)
}
}

return deploymentsWithoutReplicas, nil
}

func ProcessNamespaceDeployments(clientset *kubernetes.Clientset, namespace string) ([]string, error) {
usedServices, err := getDeploymentsWithoutReplicas(clientset, namespace)
if err != nil {
return nil, err
}

return usedServices, nil

}

func GetUnusedDeployments(namespace string) {
var kubeClient *kubernetes.Clientset
var namespaces []string

kubeClient = GetKubeClient()

namespaces = SetNamespaceList(namespace, kubeClient)

for _, namespace := range namespaces {
diff, err := ProcessNamespaceDeployments(kubeClient, namespace)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to process namespace %s: %v\n", namespace, err)
continue
}
output := FormatOutput(namespace, diff, "Deployments")
fmt.Println(output)
fmt.Println()
}
}
Loading