Skip to content

Commit 5edbdbb

Browse files
committed
Add object count sub-command (size)
1 parent 0864d8b commit 5edbdbb

File tree

2 files changed

+329
-0
lines changed

2 files changed

+329
-0
lines changed

cmd/capacity/size.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
Copyright © 2021 Alex Krzos [email protected]
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package capacity
17+
18+
import (
19+
"fmt"
20+
"os"
21+
22+
"github.com/akrzos/kubeSize/internal/kube"
23+
"github.com/akrzos/kubeSize/internal/output"
24+
"github.com/pkg/errors"
25+
"github.com/spf13/cobra"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
)
28+
29+
var sizeCmd = &cobra.Command{
30+
Use: "size",
31+
Aliases: []string{"s"},
32+
Short: "Get cluster size data",
33+
Long: `Get counts of many Kubernetes objects in a cluster`,
34+
PreRun: func(cmd *cobra.Command, args []string) {
35+
if err := output.ValidateOutput(*cmd); err != nil {
36+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
37+
os.Exit(1)
38+
}
39+
},
40+
RunE: func(cmd *cobra.Command, args []string) error {
41+
42+
clientset, err := kube.CreateClientSet(KubernetesConfigFlags)
43+
if err != nil {
44+
return errors.Wrap(err, "failed to create clientset")
45+
}
46+
47+
clusterSizeData := new(output.ClusterSizeData)
48+
49+
// Cluster APIs
50+
namespaces, err := clientset.CoreV1().Namespaces().List(metav1.ListOptions{})
51+
if err != nil {
52+
return errors.Wrap(err, "failed to list namespaces")
53+
}
54+
nodes, err := clientset.CoreV1().Nodes().List(metav1.ListOptions{})
55+
if err != nil {
56+
return errors.Wrap(err, "failed to list nodes")
57+
}
58+
persistentVolumes, err := clientset.CoreV1().PersistentVolumes().List(metav1.ListOptions{})
59+
if err != nil {
60+
return errors.Wrap(err, "failed to list persistent volumes")
61+
}
62+
serviceAccounts, err := clientset.CoreV1().ServiceAccounts("").List(metav1.ListOptions{})
63+
if err != nil {
64+
return errors.Wrap(err, "failed to list service accounts")
65+
}
66+
clusterRoles, err := clientset.RbacV1().ClusterRoles().List(metav1.ListOptions{})
67+
if err != nil {
68+
return errors.Wrap(err, "failed to list cluster roles")
69+
}
70+
clusterRoleBindings, err := clientset.RbacV1().ClusterRoleBindings().List(metav1.ListOptions{})
71+
if err != nil {
72+
return errors.Wrap(err, "failed to list cluster role bindings")
73+
}
74+
roles, err := clientset.RbacV1().Roles("").List(metav1.ListOptions{})
75+
if err != nil {
76+
return errors.Wrap(err, "failed to list roles")
77+
}
78+
roleBindings, err := clientset.RbacV1().RoleBindings("").List(metav1.ListOptions{})
79+
if err != nil {
80+
return errors.Wrap(err, "failed to list role bindings")
81+
}
82+
resourceQuotas, err := clientset.CoreV1().ResourceQuotas("").List(metav1.ListOptions{})
83+
if err != nil {
84+
return errors.Wrap(err, "failed to list resourcequotas")
85+
}
86+
networkPolicy, err := clientset.NetworkingV1().NetworkPolicies("").List(metav1.ListOptions{})
87+
if err != nil {
88+
return errors.Wrap(err, "failed to list networkpolicy")
89+
}
90+
91+
// Workloads APIs
92+
pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
93+
if err != nil {
94+
return errors.Wrap(err, "failed to list pods")
95+
}
96+
replicaSets, err := clientset.AppsV1().ReplicaSets("").List(metav1.ListOptions{})
97+
if err != nil {
98+
return errors.Wrap(err, "failed to list replicasets")
99+
}
100+
replicationControllers, err := clientset.CoreV1().ReplicationControllers("").List(metav1.ListOptions{})
101+
if err != nil {
102+
return errors.Wrap(err, "failed to list replication controllers")
103+
}
104+
deployments, err := clientset.AppsV1().Deployments("").List(metav1.ListOptions{})
105+
if err != nil {
106+
return errors.Wrap(err, "failed to list deployments")
107+
}
108+
daemonsets, err := clientset.AppsV1().DaemonSets("").List(metav1.ListOptions{})
109+
if err != nil {
110+
return errors.Wrap(err, "failed to list daemonsets")
111+
}
112+
statefulSets, err := clientset.AppsV1().StatefulSets("").List(metav1.ListOptions{})
113+
if err != nil {
114+
return errors.Wrap(err, "failed to list statefulsets")
115+
}
116+
cronJobs, err := clientset.BatchV1beta1().CronJobs("").List(metav1.ListOptions{})
117+
if err != nil {
118+
return errors.Wrap(err, "failed to list jobs")
119+
}
120+
jobs, err := clientset.BatchV1().Jobs("").List(metav1.ListOptions{})
121+
if err != nil {
122+
return errors.Wrap(err, "failed to list jobs")
123+
}
124+
125+
// Service APIs
126+
endPoints, err := clientset.CoreV1().Endpoints("").List(metav1.ListOptions{})
127+
if err != nil {
128+
return errors.Wrap(err, "failed to list end points")
129+
}
130+
services, err := clientset.CoreV1().Services("").List(metav1.ListOptions{})
131+
if err != nil {
132+
return errors.Wrap(err, "failed to list services")
133+
}
134+
ingresses, err := clientset.NetworkingV1beta1().Ingresses("").List(metav1.ListOptions{})
135+
if err != nil {
136+
return errors.Wrap(err, "failed to list ingresses")
137+
}
138+
139+
// Config And Storage APIs
140+
configmaps, err := clientset.CoreV1().ConfigMaps("").List(metav1.ListOptions{})
141+
if err != nil {
142+
return errors.Wrap(err, "failed to list configmaps")
143+
}
144+
secrets, err := clientset.CoreV1().Secrets("").List(metav1.ListOptions{})
145+
if err != nil {
146+
return errors.Wrap(err, "failed to list secrets")
147+
}
148+
persistentVolumeClaims, err := clientset.CoreV1().PersistentVolumeClaims("").List(metav1.ListOptions{})
149+
if err != nil {
150+
return errors.Wrap(err, "failed to list persistentvolumesclaims")
151+
}
152+
storageClasses, err := clientset.StorageV1().StorageClasses().List(metav1.ListOptions{})
153+
if err != nil {
154+
return errors.Wrap(err, "failed to list storageclasses")
155+
}
156+
volumeAttachments, err := clientset.StorageV1().VolumeAttachments().List(metav1.ListOptions{})
157+
if err != nil {
158+
return errors.Wrap(err, "failed to list storageclasses")
159+
}
160+
161+
// Metadata APIs
162+
events, err := clientset.CoreV1().Events("").List(metav1.ListOptions{})
163+
if err != nil {
164+
return errors.Wrap(err, "failed to list events")
165+
}
166+
limitRanges, err := clientset.CoreV1().LimitRanges("").List(metav1.ListOptions{})
167+
if err != nil {
168+
return errors.Wrap(err, "failed to list limitrange")
169+
}
170+
podDisruptionBudget, err := clientset.PolicyV1beta1().PodDisruptionBudgets("").List(metav1.ListOptions{})
171+
if err != nil {
172+
return errors.Wrap(err, "failed to list poddisruptionbudget")
173+
}
174+
podSecurityPolicy, err := clientset.PolicyV1beta1().PodSecurityPolicies().List(metav1.ListOptions{})
175+
if err != nil {
176+
return errors.Wrap(err, "failed to list podsecuritypolicy")
177+
}
178+
179+
// Cluster APIs
180+
clusterSizeData.Namespace = len(namespaces.Items)
181+
clusterSizeData.Node = len(nodes.Items)
182+
clusterSizeData.PersistentVolume = len(persistentVolumes.Items)
183+
clusterSizeData.ServiceAccount = len(serviceAccounts.Items)
184+
clusterSizeData.ClusterRole = len(clusterRoles.Items)
185+
clusterSizeData.ClusterRoleBinding = len(clusterRoleBindings.Items)
186+
clusterSizeData.Role = len(roles.Items)
187+
clusterSizeData.RoleBinding = len(roleBindings.Items)
188+
clusterSizeData.ResourceQuota = len(resourceQuotas.Items)
189+
clusterSizeData.NetworkPolicy = len(networkPolicy.Items)
190+
191+
// Workloads APIs
192+
for _, pod := range pods.Items {
193+
for range pod.Spec.Containers {
194+
clusterSizeData.Container++
195+
}
196+
}
197+
clusterSizeData.Pod = len(pods.Items)
198+
clusterSizeData.ReplicaSet = len(replicaSets.Items)
199+
clusterSizeData.ReplicaController = len(replicationControllers.Items)
200+
clusterSizeData.Deployment = len(deployments.Items)
201+
clusterSizeData.Daemonset = len(daemonsets.Items)
202+
clusterSizeData.StatefulSet = len(statefulSets.Items)
203+
clusterSizeData.CronJob = len(cronJobs.Items)
204+
clusterSizeData.Job = len(jobs.Items)
205+
206+
// Service APIs
207+
clusterSizeData.EndPoints = len(endPoints.Items)
208+
clusterSizeData.Service = len(services.Items)
209+
clusterSizeData.Ingress = len(ingresses.Items)
210+
211+
// Config And Storage APIs
212+
clusterSizeData.Configmap = len(configmaps.Items)
213+
clusterSizeData.Secret = len(secrets.Items)
214+
clusterSizeData.PersistentVolumeClaim = len(persistentVolumeClaims.Items)
215+
clusterSizeData.StorageClass = len(storageClasses.Items)
216+
clusterSizeData.VolumeAttachment = len(volumeAttachments.Items)
217+
218+
// Metadata APIs
219+
clusterSizeData.Event = len(events.Items)
220+
clusterSizeData.LimitRange = len(limitRanges.Items)
221+
clusterSizeData.PodDisruptionBudget = len(podDisruptionBudget.Items)
222+
clusterSizeData.PodSecurityPolicy = len(podSecurityPolicy.Items)
223+
224+
displayNoHeaders, _ := cmd.Flags().GetBool("no-headers")
225+
226+
displayFormat, _ := cmd.Flags().GetString("output")
227+
228+
output.DisplayClusterSizeData(*clusterSizeData, !displayNoHeaders, displayFormat)
229+
230+
return nil
231+
},
232+
}
233+
234+
func init() {
235+
rootCmd.AddCommand(sizeCmd)
236+
}

internal/output/output.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,45 @@ type ClusterCapacityData struct {
7878
TotalAvailableEphemeralStorageGB float64
7979
}
8080

81+
type ClusterSizeData struct {
82+
// Cluster APIs
83+
Namespace int
84+
Node int
85+
PersistentVolume int
86+
ServiceAccount int
87+
ClusterRole int
88+
ClusterRoleBinding int
89+
Role int
90+
RoleBinding int
91+
ResourceQuota int
92+
NetworkPolicy int
93+
// Workloads APIs
94+
Container int
95+
Pod int
96+
ReplicaSet int
97+
ReplicaController int
98+
Deployment int
99+
Daemonset int
100+
StatefulSet int
101+
CronJob int
102+
Job int
103+
// Service APIs
104+
EndPoints int
105+
Service int
106+
Ingress int
107+
// Config And Storage APIs
108+
Configmap int
109+
Secret int
110+
PersistentVolumeClaim int
111+
StorageClass int
112+
VolumeAttachment int
113+
// Metadata APIs
114+
Event int
115+
LimitRange int
116+
PodDisruptionBudget int
117+
PodSecurityPolicy int
118+
}
119+
81120
type NodeCapacityData struct {
82121
TotalPodCount int
83122
TotalNonTermPodCount int
@@ -211,6 +250,60 @@ func DisplayClusterData(clusterCapacityData ClusterCapacityData, displayDefault
211250
}
212251
}
213252

253+
func DisplayClusterSizeData(clusterSizeData ClusterSizeData, displayHeaders bool, displayFormat string) {
254+
switch displayFormat {
255+
case jsonDisplay:
256+
jsonClusterData, err := json.MarshalIndent(&clusterSizeData, "", " ")
257+
if err != nil {
258+
fmt.Println(err)
259+
return
260+
}
261+
fmt.Println(string(jsonClusterData))
262+
case yamlDisplay:
263+
yamlClusterData, err := yaml.Marshal(clusterSizeData)
264+
if err != nil {
265+
fmt.Println(err)
266+
return
267+
}
268+
fmt.Print(string(yamlClusterData))
269+
default:
270+
w := new(tabwriter.Writer)
271+
w.Init(os.Stdout, 0, 5, 1, ' ', 0)
272+
if displayHeaders {
273+
fmt.Fprintln(w, "CLUSTER APIs")
274+
fmt.Fprintln(w, "Namespaces\tNodes\tPersistentVolumes\tServiceAccounts\tClusterRoles\tClusterRoleBindings\tRoles\tRoleBindings\tResourceQuotas\tNetworkPolicies")
275+
}
276+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t", clusterSizeData.Namespace, clusterSizeData.Node, clusterSizeData.PersistentVolume, clusterSizeData.ServiceAccount)
277+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t", clusterSizeData.ClusterRole, clusterSizeData.ClusterRoleBinding, clusterSizeData.Role, clusterSizeData.RoleBinding)
278+
fmt.Fprintf(w, "%d\t%d\n", clusterSizeData.ResourceQuota, clusterSizeData.NetworkPolicy)
279+
if displayHeaders {
280+
fmt.Fprintln(w, "WORKLOAD APIs")
281+
fmt.Fprintln(w, "Containers\tPods\tReplicaSets\tReplicationControllers\tDeployments\tDaemonSets\tStatefulSets\tCronJobs\tJobs")
282+
}
283+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t", clusterSizeData.Container, clusterSizeData.Pod, clusterSizeData.ReplicaSet, clusterSizeData.ReplicaController)
284+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t", clusterSizeData.Deployment, clusterSizeData.Daemonset, clusterSizeData.StatefulSet, clusterSizeData.CronJob)
285+
fmt.Fprintf(w, "%d\n", clusterSizeData.Job)
286+
if displayHeaders {
287+
fmt.Fprintln(w, "SERVICE APIs")
288+
fmt.Fprintln(w, "Endpoints\tIngresses\tServices")
289+
}
290+
fmt.Fprintf(w, "%d\t%d\t%d\n", clusterSizeData.EndPoints, clusterSizeData.Ingress, clusterSizeData.Service)
291+
if displayHeaders {
292+
fmt.Fprintln(w, "CONFIG And STORAGE APIs")
293+
fmt.Fprintln(w, "ConfigMaps\tSecrets\tPersistentVolumeClaims\tStorageClasses\tVolumes\tVolumeAttachments")
294+
}
295+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t", clusterSizeData.Configmap, clusterSizeData.Secret, clusterSizeData.PersistentVolumeClaim, clusterSizeData.StorageClass)
296+
fmt.Fprintf(w, "%d\t\n", clusterSizeData.VolumeAttachment)
297+
if displayHeaders {
298+
fmt.Fprintln(w, "METADATA APIs")
299+
fmt.Fprintln(w, "Events\tLimitRanges\tPodDisruptionBudgets\tPodSecurityPolicies")
300+
}
301+
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t\n", clusterSizeData.Event, clusterSizeData.LimitRange, clusterSizeData.PodDisruptionBudget, clusterSizeData.PodSecurityPolicy)
302+
303+
w.Flush()
304+
}
305+
}
306+
214307
func DisplayNodeRoleData(nodeRoleCapacityData map[string]*ClusterCapacityData, sortedRoleNames []string, displayDefault bool, displayHeaders bool, displayEphemeralStorage bool, displayFormat string) {
215308
switch displayFormat {
216309
case jsonDisplay:

0 commit comments

Comments
 (0)