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 --exclude-node-labels flag #84

Closed
wants to merge 3 commits into from
Closed
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
33 changes: 16 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ kube-capacity --pod-labels app=nginx
kube-capacity --namespace default
kube-capacity --namespace-labels team=api
kube-capacity --node-labels kubernetes.io/role=node
kube-capacity --exclude-node-labels kubernetes.io/os=linux
```

### JSON and YAML Output
Expand All @@ -140,23 +141,21 @@ kube-capacity --pods --containers --util --output yaml

## Flags Supported
```
-c, --containers includes containers in output
--context string context to use for Kubernetes config
-h, --help help for kube-capacity
-n, --namespace string only include pods from this namespace
--namespace-labels string labels to filter namespaces with
--node-labels string labels to filter nodes with
-o, --output string output format for information
(supports: [table json yaml])
(default "table")
-a, --available includes quantity available instead of percentage used
-l, --pod-labels string labels to filter pods with
-p, --pods includes pods in output
--sort string attribute to sort results be (supports:
[cpu.util cpu.request cpu.limit mem.util mem.request mem.limit name])
(default "name")
-u, --util includes resource utilization in output
--pod-count includes pod counts for each of the nodes and the whole cluster
-a, --available includes quantity available instead of percentage used
-c, --containers includes containers in output
--context string context to use for Kubernetes config
--exclude-node-labels string labels to exclude nodes with
-h, --help help for kube-capacity
--kubeconfig string kubeconfig file to use for Kubernetes config
-n, --namespace string only include pods from this namespace
--namespace-labels string labels to filter namespaces with
--node-labels string labels to filter nodes with
-o, --output string output format for information (supports: [table json yaml]) (default "table")
--pod-count includes pod count per node in output
-l, --pod-labels string labels to filter pods with
-p, --pods includes pods in output
--sort string attribute to sort results by (supports: [cpu.util cpu.request cpu.limit mem.util mem.request mem.limit cpu.util.percentage cpu.request.percentage cpu.limit.percentage mem.util.percentage mem.request.percentage mem.limit.percentage name]) (default "name")
-u, --util includes resource utilization in output
```

## Prerequisites
Expand Down
37 changes: 31 additions & 6 deletions pkg/capacity/capacity.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ import (
)

// FetchAndPrint gathers cluster resource data and outputs it
func FetchAndPrint(showContainers, showPods, showUtil, showPodCount, availableFormat bool, podLabels, nodeLabels, namespaceLabels, namespace, kubeContext, kubeConfig, output, sortBy string) {
func FetchAndPrint(showContainers, showPods, showUtil, showPodCount, availableFormat bool, podLabels, nodeLabels, excludeNodeLabels, namespaceLabels, namespace, kubeContext, kubeConfig, output, sortBy string) {
clientset, err := kube.NewClientSet(kubeContext, kubeConfig)
if err != nil {
fmt.Printf("Error connecting to Kubernetes: %v\n", err)
os.Exit(1)
}

podList, nodeList := getPodsAndNodes(clientset, podLabels, nodeLabels, namespaceLabels, namespace)
podList, nodeList := getPodsAndNodes(clientset, podLabels, nodeLabels, excludeNodeLabels, namespaceLabels, namespace)
var pmList *v1beta1.PodMetricsList
var nmList *v1beta1.NodeMetricsList

Expand All @@ -59,7 +59,7 @@ func FetchAndPrint(showContainers, showPods, showUtil, showPodCount, availableFo
printList(&cm, showContainers, showPods, showUtil, showPodCount, showNamespace, output, sortBy, availableFormat)
}

func getPodsAndNodes(clientset kubernetes.Interface, podLabels, nodeLabels, namespaceLabels, namespace string) (*corev1.PodList, *corev1.NodeList) {
func getPodsAndNodes(clientset kubernetes.Interface, podLabels, nodeLabels, excludeNodeLabels, namespaceLabels, namespace string) (*corev1.PodList, *corev1.NodeList) {
nodeList, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{
LabelSelector: nodeLabels,
})
Expand All @@ -76,13 +76,38 @@ func getPodsAndNodes(clientset kubernetes.Interface, podLabels, nodeLabels, name
os.Exit(3)
}

newPodItems := []corev1.Pod{}

nodes := map[string]bool{}
nodeNamesToExclude := map[string]bool{}
if excludeNodeLabels != "" {
excludeNodeList, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{
LabelSelector: excludeNodeLabels,
})
if err != nil {
fmt.Printf("Error listing Nodes: %v\n", err)
os.Exit(2)
}
for _, node := range excludeNodeList.Items {
nodeNamesToExclude[node.GetName()] = true
}
}

for _, node := range nodeList.Items {
nodes[node.GetName()] = true
if !nodeNamesToExclude[node.GetName()] {
nodes[node.GetName()] = true
}
}

newNodeItems := []corev1.Node{}
for _, node := range nodeList.Items {
if nodes[node.GetName()] {
newNodeItems = append(newNodeItems, node)
}
}

nodeList.Items = newNodeItems

newPodItems := []corev1.Pod{}

for _, pod := range podList.Items {
if !nodes[pod.Spec.NodeName] {
continue
Expand Down
12 changes: 6 additions & 6 deletions pkg/capacity/capacity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestGetPodsAndNodes(t *testing.T) {
pod("mynode", "default", "mypod6", map[string]string{"g": "test"}),
)

podList, nodeList := getPodsAndNodes(clientset, "", "", "", "")
podList, nodeList := getPodsAndNodes(clientset, "", "", "", "", "")
assert.Equal(t, []string{"mynode", "mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"another/mypod5",
Expand All @@ -52,7 +52,7 @@ func TestGetPodsAndNodes(t *testing.T) {
"other/mypod3",
}, listPods(podList))

podList, nodeList = getPodsAndNodes(clientset, "", "hello=world", "", "")
podList, nodeList = getPodsAndNodes(clientset, "", "hello=world", "", "", "")
assert.Equal(t, []string{"mynode", "mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"another/mypod5",
Expand All @@ -64,27 +64,27 @@ func TestGetPodsAndNodes(t *testing.T) {
"other/mypod3",
}, listPods(podList))

podList, nodeList = getPodsAndNodes(clientset, "", "moon=lol", "", "")
podList, nodeList = getPodsAndNodes(clientset, "", "moon=lol", "", "", "")
assert.Equal(t, []string{"mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"default/mypod4",
"kube-system/mypod1",
"other/mypod3",
}, listPods(podList))

podList, nodeList = getPodsAndNodes(clientset, "a=test", "", "", "")
podList, nodeList = getPodsAndNodes(clientset, "a=test", "", "", "", "")
assert.Equal(t, []string{"mynode", "mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"default/mypod",
}, listPods(podList))

podList, nodeList = getPodsAndNodes(clientset, "a=test,b!=test", "", "app=true", "")
podList, nodeList = getPodsAndNodes(clientset, "a=test,b!=test", "", "app=true", "", "")
assert.Equal(t, []string{"mynode", "mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"default/mypod",
}, listPods(podList))

podList, nodeList = getPodsAndNodes(clientset, "a=test,b!=test", "", "", "default")
podList, nodeList = getPodsAndNodes(clientset, "a=test,b!=test", "", "", "default", "")
assert.Equal(t, []string{"mynode", "mynode2"}, listNodes(nodeList))
assert.Equal(t, []string{
"default/mypod",
Expand Down
5 changes: 4 additions & 1 deletion pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var showUtil bool
var showPodCount bool
var podLabels string
var nodeLabels string
var excludeNodeLabels string
var namespaceLabels string
var namespace string
var kubeContext string
Expand All @@ -50,7 +51,7 @@ var rootCmd = &cobra.Command{
os.Exit(1)
}

capacity.FetchAndPrint(showContainers, showPods, showUtil, showPodCount, availableFormat, podLabels, nodeLabels,
capacity.FetchAndPrint(showContainers, showPods, showUtil, showPodCount, availableFormat, podLabels, nodeLabels, excludeNodeLabels,
namespaceLabels, namespace, kubeContext, kubeConfig, outputFormat, sortBy)
},
}
Expand All @@ -70,6 +71,8 @@ func init() {
"pod-labels", "l", "", "labels to filter pods with")
rootCmd.PersistentFlags().StringVarP(&nodeLabels,
"node-labels", "", "", "labels to filter nodes with")
rootCmd.PersistentFlags().StringVarP(&excludeNodeLabels,
"exclude-node-labels", "", "", "labels to exclude nodes with")
rootCmd.PersistentFlags().StringVarP(&namespaceLabels,
"namespace-labels", "", "", "labels to filter namespaces with")
rootCmd.PersistentFlags().StringVarP(&namespace,
Expand Down