Skip to content

Commit

Permalink
Add ephemeral storage capacity metrics to namespace command
Browse files Browse the repository at this point in the history
  • Loading branch information
akrzos committed Feb 14, 2021
1 parent 7d85537 commit 9040117
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 49 deletions.
1 change: 1 addition & 0 deletions .github/workflows/integration-kind.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ jobs:
bin/kubectl-capacity no
bin/kubectl-capacity no -e
bin/kubectl-capacity ns
bin/kubectl-capacity ns -e
83 changes: 55 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ Total Ready Unready Unsch Capacity Allocatable Total Non-Term Avail Capacity
3 3 0 0 330 330 13 13 317 12.0 12.0 1.1 0.3 10.9 5.8 5.8 0.3 0.5 5.5
```

Flags:

- `-e, --ephemeral-storage` flag includes ephemeral storage capacity data in table output view.

### Node-Role

Capacity data aggregated and grouped by node-role can be displayed with the `node-role` sub-command. This is helpful to see the available space to deploy an application on your kubernetes cluster by looking at the worker/compute node-role available metrics (pods, cpu, memory).
Capacity data aggregated and grouped by node-role can be displayed with the `node-role` sub-command. This is helpful to see the available space to deploy an application on your kubernetes cluster by looking at the worker/compute node-role available metrics (pods, cpu, memory, storage).

```console
$ kubectl capacity node-role
Expand All @@ -114,6 +118,7 @@ master 1 1 0 0 110 110 6 6 104 4.0

Flags:

- `-e, --ephemeral-storage` flag includes ephemeral storage capacity data in table output view.
- `-u, --unassigned` flag includes a row of data on non-terminated pods that have not been assigned a node. Total counts could be confusing if looking at cluster level capacity data compared to node-role data if there are unassigned pods.

### Node
Expand All @@ -131,6 +136,7 @@ NAME STATUS ROLES PODS CPU

Flags:

- `-e, --ephemeral-storage` flag includes ephemeral storage capacity data in table output view.
- `-r, --sort-by-role` flag sorts table output by node-role rather than node name.
- `-t, --display-total` flag includes a row of data displaying totals for each column.
- `-u, --unassigned` flag includes a row of data on non-terminated pods that have not been assigned a node. Total counts could be confusing if looking at cluster level capacity data compared to node data if there are unassigned pods.
Expand All @@ -150,12 +156,13 @@ local-path-storage 1 1 0 0.0 0.0 0.0 0.0
Flags:

- `-A, --all-namespaces` flag includes namespaces with 0 pods.
- `-e, --ephemeral-storage` flag includes ephemeral storage capacity data in table output view.
- `-n, --namespace string` flag selects a specific namespace.
- `-t, --display-total` flag includes a row of data displaying totals for each column.

### Output formats

kubeSize supports table, yaml, and json output formats. Table data is the default format and is designed to be read by humans. With table output, CPU metrics default to cores and Memory metrics into [GiB (gibibyte)](https://en.wikipedia.org/wiki/Byte#Multiple-byte_units).
kubeSize supports table, yaml, and json output formats. Table data is the default format and is designed to be read by humans. With table output, CPU metrics default to cores, Memory metrics into [GiB (gibibyte)](https://en.wikipedia.org/wiki/Byte#Multiple-byte_units) and Storage metrics into [GB (gigabyte)](https://en.wikipedia.org/wiki/Byte#Multiple-byte_units)

Flags:

Expand All @@ -168,39 +175,49 @@ Examples:
$ kubectl capacity c
NODES PODS CPU (cores) MEMORY (GiB)
Total Ready Unready Unsch Capacity Allocatable Total Non-Term Avail Capacity Allocatable Requests Limits Avail Capacity Allocatable Requests Limits Avail
1 1 0 0 110 110 9 9 101 4.0 4.0 0.8 0.1 3.1 1.9 1.9 0.2 0.4 1.8
1 1 0 0 110 110 11 11 99 4.0 4.0 11.4 0.1 -7.5 1.9 1.9 0.4 0.4 1.6
$ kubectl capacity c -d
NODES PODS CPU MEMORY
Total Ready Unready Unsch Capacity Allocatable Total Non-Term Avail Capacity Allocatable Requests Limits Avail Capacity Allocatable Requests Limits Avail
1 1 0 0 110 110 9 9 101 4 4 850m 100m 3150m 2036452Ki 2036452Ki 190Mi 390Mi 1841892Ki
NODES PODS CPU MEMORY
Total Ready Unready Unsch Capacity Allocatable Total Non-Term Avail Capacity Allocatable Requests Limits Avail Capacity Allocatable Requests Limits Avail
1 1 0 0 110 110 11 11 99 4 4 11450m 100m -7450m 2036452Ki 2036452Ki 400Mi 390Mi 1626852Ki
$ kubectl capacity c -o yaml
TotalAllocatableCPU: "4"
TotalAllocatableCPUCores: 4
TotalAllocatableEphemeralStorage: 61255492Ki
TotalAllocatableEphemeralStorageGB: 62.725623807999995
TotalAllocatableMemory: 2036452Ki
TotalAllocatableMemoryGiB: 1.9421119689941406
TotalAllocatablePods: "110"
TotalAvailableCPU: 3150m
TotalAvailableCPUCores: 3.15
TotalAvailableMemory: 1841892Ki
TotalAvailableMemoryGiB: 1.7565650939941406
TotalAvailablePods: 101
TotalAvailableCPU: -7450m
TotalAvailableCPUCores: -7.45
TotalAvailableEphemeralStorage: "59620766208"
TotalAvailableEphemeralStorageGB: 59.62076620799999
TotalAvailableMemory: 1626852Ki
TotalAvailableMemoryGiB: 1.5514869689941406
TotalAvailablePods: 99
TotalCapacityCPU: "4"
TotalCapacityCPUCores: 4
TotalCapacityEphemeralStorage: 61255492Ki
TotalCapacityEphemeralStorageGB: 62.725623807999995
TotalCapacityMemory: 2036452Ki
TotalCapacityMemoryGiB: 1.9421119689941406
TotalCapacityPods: "110"
TotalLimitsCPU: 100m
TotalLimitsCPUCores: 0.1
TotalLimitsEphemeralStorage: 3G
TotalLimitsEphemeralStorageGB: 3
TotalLimitsMemory: 390Mi
TotalLimitsMemoryGiB: 0.380859375
TotalNodeCount: 1
TotalNonTermPodCount: 9
TotalPodCount: 9
TotalNonTermPodCount: 11
TotalPodCount: 11
TotalReadyNodeCount: 1
TotalRequestsCPU: 850m
TotalRequestsCPUCores: 0.85
TotalRequestsMemory: 190Mi
TotalRequestsMemoryGiB: 0.185546875
TotalRequestsCPU: 11450m
TotalRequestsCPUCores: 11.45
TotalRequestsEphemeralStorage: "3104857600"
TotalRequestsEphemeralStorageGB: 3.1048576000000003
TotalRequestsMemory: 400Mi
TotalRequestsMemoryGiB: 0.390625
TotalUnreadyNodeCount: 0
TotalUnschedulableNodeCount: 0
$ kubectl capacity c -o json
Expand All @@ -209,31 +226,41 @@ $ kubectl capacity c -o json
"TotalReadyNodeCount": 1,
"TotalUnreadyNodeCount": 0,
"TotalUnschedulableNodeCount": 0,
"TotalPodCount": 9,
"TotalNonTermPodCount": 9,
"TotalPodCount": 11,
"TotalNonTermPodCount": 11,
"TotalCapacityPods": "110",
"TotalCapacityCPU": "4",
"TotalCapacityCPUCores": 4,
"TotalCapacityMemory": "2036452Ki",
"TotalCapacityMemoryGiB": 1.9421119689941406,
"TotalCapacityEphemeralStorage": "61255492Ki",
"TotalCapacityEphemeralStorageGB": 62.725623807999995,
"TotalAllocatablePods": "110",
"TotalAllocatableCPU": "4",
"TotalAllocatableCPUCores": 4,
"TotalAllocatableMemory": "2036452Ki",
"TotalAllocatableMemoryGiB": 1.9421119689941406,
"TotalAvailablePods": 101,
"TotalRequestsCPU": "850m",
"TotalRequestsCPUCores": 0.85,
"TotalAllocatableEphemeralStorage": "61255492Ki",
"TotalAllocatableEphemeralStorageGB": 62.725623807999995,
"TotalAvailablePods": 99,
"TotalRequestsCPU": "11450m",
"TotalRequestsCPUCores": 11.45,
"TotalLimitsCPU": "100m",
"TotalLimitsCPUCores": 0.1,
"TotalAvailableCPU": "3150m",
"TotalAvailableCPUCores": 3.15,
"TotalRequestsMemory": "190Mi",
"TotalRequestsMemoryGiB": 0.185546875,
"TotalAvailableCPU": "-7450m",
"TotalAvailableCPUCores": -7.45,
"TotalRequestsMemory": "400Mi",
"TotalRequestsMemoryGiB": 0.390625,
"TotalLimitsMemory": "390Mi",
"TotalLimitsMemoryGiB": 0.380859375,
"TotalAvailableMemory": "1841892Ki",
"TotalAvailableMemoryGiB": 1.7565650939941406
"TotalAvailableMemory": "1626852Ki",
"TotalAvailableMemoryGiB": 1.5514869689941406,
"TotalRequestsEphemeralStorage": "3104857600",
"TotalRequestsEphemeralStorageGB": 3.1048576000000003,
"TotalLimitsEphemeralStorage": "3G",
"TotalLimitsEphemeralStorageGB": 3,
"TotalAvailableEphemeralStorage": "59620766208",
"TotalAvailableEphemeralStorageGB": 59.62076620799999
}
```

Expand Down
2 changes: 1 addition & 1 deletion cmd/capacity/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,5 @@ var clusterCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(clusterCmd)
clusterCmd.Flags().BoolP("ephemeral-storage", "e", false, "Display ephemeral storage")
clusterCmd.Flags().BoolP("ephemeral-storage", "e", false, "Include ephemeral storage capacity data in table output")
}
13 changes: 12 additions & 1 deletion cmd/capacity/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ var namespaceCmd = &cobra.Command{
namespaceCapacityData[pod.Namespace].TotalLimitsCPU.Add(*container.Resources.Limits.Cpu())
namespaceCapacityData[pod.Namespace].TotalRequestsMemory.Add(*container.Resources.Requests.Memory())
namespaceCapacityData[pod.Namespace].TotalLimitsMemory.Add(*container.Resources.Limits.Memory())
namespaceCapacityData[pod.Namespace].TotalRequestsEphemeralStorage.Add(*container.Resources.Requests.StorageEphemeral())
namespaceCapacityData[pod.Namespace].TotalLimitsEphemeralStorage.Add(*container.Resources.Limits.StorageEphemeral())
}
}
}
Expand All @@ -111,6 +113,8 @@ var namespaceCmd = &cobra.Command{
namespaceCapacityData[namespace].TotalLimitsCPUCores = capacity.ReadableCPU(namespaceCapacityData[namespace].TotalLimitsCPU)
namespaceCapacityData[namespace].TotalRequestsMemoryGiB = capacity.ReadableMem(namespaceCapacityData[namespace].TotalRequestsMemory)
namespaceCapacityData[namespace].TotalLimitsMemoryGiB = capacity.ReadableMem(namespaceCapacityData[namespace].TotalLimitsMemory)
namespaceCapacityData[namespace].TotalRequestsEphemeralStorageGB = capacity.ReadableStorage(namespaceCapacityData[namespace].TotalRequestsEphemeralStorage)
namespaceCapacityData[namespace].TotalLimitsEphemeralStorageGB = capacity.ReadableStorage(namespaceCapacityData[namespace].TotalLimitsEphemeralStorage)
namespaceCapacityData["*total*"].TotalPodCount += namespaceCapacityData[namespace].TotalPodCount
namespaceCapacityData["*total*"].TotalNonTermPodCount += namespaceCapacityData[namespace].TotalNonTermPodCount
namespaceCapacityData["*total*"].TotalUnassignedNodePodCount += namespaceCapacityData[namespace].TotalUnassignedNodePodCount
Expand All @@ -122,12 +126,18 @@ var namespaceCmd = &cobra.Command{
namespaceCapacityData["*total*"].TotalRequestsMemoryGiB += namespaceCapacityData[namespace].TotalRequestsMemoryGiB
namespaceCapacityData["*total*"].TotalLimitsMemory.Add(namespaceCapacityData[namespace].TotalLimitsMemory)
namespaceCapacityData["*total*"].TotalLimitsMemoryGiB += namespaceCapacityData[namespace].TotalLimitsMemoryGiB
namespaceCapacityData["*total*"].TotalRequestsEphemeralStorage.Add(namespaceCapacityData[namespace].TotalRequestsEphemeralStorage)
namespaceCapacityData["*total*"].TotalRequestsEphemeralStorageGB += namespaceCapacityData[namespace].TotalRequestsEphemeralStorageGB
namespaceCapacityData["*total*"].TotalLimitsEphemeralStorage.Add(namespaceCapacityData[namespace].TotalLimitsEphemeralStorage)
namespaceCapacityData["*total*"].TotalLimitsEphemeralStorageGB += namespaceCapacityData[namespace].TotalLimitsEphemeralStorageGB
}

sort.Strings(namespaceNames)

displayDefault, _ := cmd.Flags().GetBool("default-format")

displayEphemeralStorage, _ := cmd.Flags().GetBool("ephemeral-storage")

displayNoHeaders, _ := cmd.Flags().GetBool("no-headers")

displayFormat, _ := cmd.Flags().GetString("output")
Expand All @@ -140,7 +150,7 @@ var namespaceCmd = &cobra.Command{
namespaceNames = append(namespaceNames, "*total*")
}

output.DisplayNamespaceData(namespaceCapacityData, namespaceNames, displayDefault, !displayNoHeaders, displayFormat, displayAllNamespaces)
output.DisplayNamespaceData(namespaceCapacityData, namespaceNames, displayDefault, !displayNoHeaders, displayEphemeralStorage, displayFormat, displayAllNamespaces)

return nil
},
Expand All @@ -149,5 +159,6 @@ var namespaceCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(namespaceCmd)
namespaceCmd.Flags().BoolP("all-namespaces", "A", false, "Include 0 pod namespaces in table output")
namespaceCmd.Flags().BoolP("ephemeral-storage", "e", false, "Include ephemeral storage capacity data in table output")
namespaceCmd.Flags().BoolP("display-total", "t", false, "Display sum of all namespace capacity data in table output")
}
2 changes: 1 addition & 1 deletion cmd/capacity/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ var nodeCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(nodeCmd)
nodeCmd.Flags().BoolP("ephemeral-storage", "e", false, "Display ephemeral storage")
nodeCmd.Flags().BoolP("ephemeral-storage", "e", false, "Include ephemeral storage capacity data in table output")
nodeCmd.Flags().BoolP("sort-by-role", "r", false, "Sort output by node-role")
nodeCmd.Flags().BoolP("display-total", "t", false, "Display sum of all node capacity data in table output")
nodeCmd.Flags().BoolP("unassigned", "u", false, "Include unassigned pod row, pods which do not have a node")
Expand Down
2 changes: 1 addition & 1 deletion cmd/capacity/noderole.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,6 @@ var nodeRoleCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(nodeRoleCmd)
nodeRoleCmd.Flags().BoolP("ephemeral-storage", "e", false, "Display ephemeral storage")
nodeRoleCmd.Flags().BoolP("ephemeral-storage", "e", false, "Include ephemeral storage capacity data in table output")
nodeRoleCmd.Flags().BoolP("unassigned", "u", false, "Include unassigned pod row, pods which do not have a node")
}
58 changes: 41 additions & 17 deletions internal/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,21 @@ type NodeCapacityData struct {
}

type NamespaceCapacityData struct {
TotalPodCount int
TotalNonTermPodCount int
TotalUnassignedNodePodCount int
TotalRequestsCPU resource.Quantity
TotalRequestsCPUCores float64
TotalLimitsCPU resource.Quantity
TotalLimitsCPUCores float64
TotalRequestsMemory resource.Quantity
TotalRequestsMemoryGiB float64
TotalLimitsMemory resource.Quantity
TotalLimitsMemoryGiB float64
TotalPodCount int
TotalNonTermPodCount int
TotalUnassignedNodePodCount int
TotalRequestsCPU resource.Quantity
TotalRequestsCPUCores float64
TotalLimitsCPU resource.Quantity
TotalLimitsCPUCores float64
TotalRequestsMemory resource.Quantity
TotalRequestsMemoryGiB float64
TotalLimitsMemory resource.Quantity
TotalLimitsMemoryGiB float64
TotalRequestsEphemeralStorage resource.Quantity
TotalRequestsEphemeralStorageGB float64
TotalLimitsEphemeralStorage resource.Quantity
TotalLimitsEphemeralStorageGB float64
}

func DisplayClusterData(clusterCapacityData ClusterCapacityData, displayDefault bool, displayHeaders bool, displayEphemeralStorage bool, displayFormat string) {
Expand Down Expand Up @@ -394,7 +398,7 @@ func printNodeData(w *tabwriter.Writer, nodeName string, nodeData *NodeCapacityD
}
}

func DisplayNamespaceData(namespaceCapacityData map[string]*NamespaceCapacityData, sortedNamespaceNames []string, displayDefault bool, displayHeaders bool, displayFormat string, displayAllNamespaces bool) {
func DisplayNamespaceData(namespaceCapacityData map[string]*NamespaceCapacityData, sortedNamespaceNames []string, displayDefault bool, displayHeaders bool, displayEphemeralStorage bool, displayFormat string, displayAllNamespaces bool) {
switch displayFormat {
case jsonDisplay:
jsonNamespaceData, err := json.MarshalIndent(&namespaceCapacityData, "", " ")
Expand All @@ -415,22 +419,42 @@ func DisplayNamespaceData(namespaceCapacityData map[string]*NamespaceCapacityDat
w.Init(os.Stdout, 0, 5, 1, ' ', 0)
if displayHeaders {
if displayDefault {
fmt.Fprintln(w, "NAMESPACE\tPODS\t\t\tCPU\t\tMEMORY\t\t")
fmt.Fprintf(w, "NAMESPACE\tPODS\t\t\tCPU\t\tMEMORY\t\t")
if displayEphemeralStorage {
fmt.Fprintf(w, "EPHEMERAL STORAGE")
}
fmt.Fprintln(w, "")
} else {
fmt.Fprintln(w, "NAMESPACE\tPODS\t\t\tCPU (cores)\t\tMEMORY (GiB)\t\t")
fmt.Fprintf(w, "NAMESPACE\tPODS\t\t\tCPU (cores)\t\tMEMORY (GiB)\t\t")
if displayEphemeralStorage {
fmt.Fprintf(w, "EPHEMERAL STORAGE (GB)")
}
fmt.Fprintln(w, "")
}
fmt.Fprintln(w, "\tTotal\tNon-Term\tUnassigned\tRequests\tLimits\tRequests\tLimits")
fmt.Fprintf(w, "\tTotal\tNon-Term\tUnassigned\tRequests\tLimits\tRequests\tLimits\t")
if displayEphemeralStorage {
fmt.Fprintf(w, "Requests\tLimits")
}
fmt.Fprintln(w, "")
}
for _, k := range sortedNamespaceNames {
if (namespaceCapacityData[k].TotalPodCount != 0) || displayAllNamespaces {
fmt.Fprintf(w, "%s\t", k)
fmt.Fprintf(w, "%d\t%d\t%d\t", namespaceCapacityData[k].TotalPodCount, namespaceCapacityData[k].TotalNonTermPodCount, namespaceCapacityData[k].TotalUnassignedNodePodCount)
if displayDefault {
fmt.Fprintf(w, "%s\t%s\t", &namespaceCapacityData[k].TotalRequestsCPU, &namespaceCapacityData[k].TotalLimitsCPU)
fmt.Fprintf(w, "%s\t%s\t\n", &namespaceCapacityData[k].TotalRequestsMemory, &namespaceCapacityData[k].TotalLimitsMemory)
fmt.Fprintf(w, "%s\t%s\t", &namespaceCapacityData[k].TotalRequestsMemory, &namespaceCapacityData[k].TotalLimitsMemory)
if displayEphemeralStorage {
fmt.Fprintf(w, "%s\t%s\t", &namespaceCapacityData[k].TotalRequestsEphemeralStorage, &namespaceCapacityData[k].TotalLimitsEphemeralStorage)
}
fmt.Fprintln(w, "")
} else {
fmt.Fprintf(w, "%.1f\t%.1f\t", namespaceCapacityData[k].TotalRequestsCPUCores, namespaceCapacityData[k].TotalLimitsCPUCores)
fmt.Fprintf(w, "%.1f\t%.1f\t\n", namespaceCapacityData[k].TotalRequestsMemoryGiB, namespaceCapacityData[k].TotalLimitsMemoryGiB)
fmt.Fprintf(w, "%.1f\t%.1f\t", namespaceCapacityData[k].TotalRequestsMemoryGiB, namespaceCapacityData[k].TotalLimitsMemoryGiB)
if displayEphemeralStorage {
fmt.Fprintf(w, "%.1f\t%.1f\t", namespaceCapacityData[k].TotalRequestsEphemeralStorageGB, namespaceCapacityData[k].TotalLimitsEphemeralStorageGB)
}
fmt.Fprintln(w, "")
}
}
}
Expand Down

0 comments on commit 9040117

Please sign in to comment.