@@ -21,19 +21,7 @@ import (
2121 metav1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
2222)
2323
24- // GetPods returns a list of Pod objects in a given Kubernetes namespace.
25- //
26- // It accepts:
27- // - ctx: The context for the request
28- // - k8sClient: A Kubernetes clientset for making API requests
29- // - namespace: The Kubernetes namespace to list Pods from
30- //
31- // It returns:
32- // - A slice of Pod objects from the given namespace
33- // - An error if there was an issue listing Pods
34- //
35- // If no Pods exist in the given namespace, a warning message is printed and the
36- // program exits with a non-zero status code.
24+ // GetPods fetches all pods in a given namespace.
3725func GetPods (ctx context.Context , cfg * scout.Config ) ([]corev1.Pod , error ) {
3826 podInterface := cfg .K8sClient .CoreV1 ().Pods (cfg .Namespace )
3927 podList , err := podInterface .List (ctx , metav1.ListOptions {})
@@ -58,10 +46,7 @@ func GetPods(ctx context.Context, cfg *scout.Config) ([]corev1.Pod, error) {
5846 return podList .Items , nil
5947}
6048
61- // getPod returns a Pod object with the given name.
62- //
63- // If a Pod with the given name exists in pods, it is returned.
64- // Otherwise, an error is returned indicating no Pod with that name exists.
49+ // GetPod returns a pod object with the given name from a list of pods.
6550func GetPod (podName string , pods []corev1.Pod ) (corev1.Pod , error ) {
6651 for _ , p := range pods {
6752 if p .Name == podName {
@@ -71,11 +56,16 @@ func GetPod(podName string, pods []corev1.Pod) (corev1.Pod, error) {
7156 return corev1.Pod {}, errors .New ("no pod with this name exists in this namespace" )
7257}
7358
74- // getPodMetrics retrieves metrics for a given pod.
59+ // GetPodMetrics fetches metrics for a given pod from the Kubernetes Metrics API.
60+ //
61+ // It accepts:
62+ // - ctx: The context for the request
63+ // - cfg: The scout config containing Kubernetes clientsets
64+ // - pod: The pod specification
7565//
76- // It returns:
66+ // It returns:
7767// - podMetrics: The PodMetrics object containing metrics for the pod
78- // - err: Any error that occurred while getting the pod metrics
68+ // - Any error that occurred while fetching the metrics
7969func GetPodMetrics (ctx context.Context , cfg * scout.Config , pod corev1.Pod ) (* metav1beta1.PodMetrics , error ) {
8070 podMetrics , err := cfg .MetricsClient .
8171 MetricsV1beta1 ().
@@ -88,15 +78,117 @@ func GetPodMetrics(ctx context.Context, cfg *scout.Config, pod corev1.Pod) (*met
8878 return podMetrics , nil
8979}
9080
91- // GetRawUsage retrieves the raw usage value for a given resource type from a Kubernetes ResourceList.
81+ // GetLimits generates resource limits for containers in a pod.
82+ //
83+ // It accepts:
84+ // - ctx: The context for the request
85+ // - cfg: The scout config containing Kubernetes clientsets
86+ // - pod: The pod specification
87+ // - containerMetrics: A pointer to a ContainerMetrics struct to populate
88+ //
89+ // It populates the containerMetrics.Limits field with a map of container names
90+ // to resource limits (CPU, memory, storage) for each container in the pod.
9291//
92+ // It returns:
93+ // - Any error that occurred while fetching resource limits
94+ func GetLimits (ctx context.Context , cfg * scout.Config , pod * corev1.Pod , containerMetrics * scout.ContainerMetrics ) error {
95+ for _ , container := range pod .Spec .Containers {
96+ containerName := container .Name
97+ capacity , err := GetPvcCapacity (ctx , cfg , container , pod )
98+ if err != nil {
99+ return errors .Wrap (err , "while getting storage capacity of PV" )
100+ }
101+
102+ rsrcs := scout.Resources {
103+ Cpu : container .Resources .Limits .Cpu ().ToDec (),
104+ Memory : container .Resources .Limits .Memory ().ToDec (),
105+ Storage : capacity ,
106+ }
107+ containerMetrics .Limits [containerName ] = rsrcs
108+ }
109+
110+ return nil
111+ }
112+
113+ // GetUsage generates resource usage statistics for a Kubernetes container.
114+ //
93115// It accepts:
94- // - usages: A Kubernetes ResourceList containing usage values for multiple resource types
95- // - targetKey: The key for the resource type to retrieve usage for (e.g. "cpu" or "memory")
116+ // - ctx: The context for the request
117+ // - cfg: The scout config containing Kubernetes clientsets
118+ // - metrics: Container resource limits
119+ // - pod: The pod specification
120+ // - container: Container metrics from the Metrics API
96121//
97122// It returns:
98- // - The raw usage value for the target resource type as a float64
99- // - An error if there was an issue retrieving or parsing the usage value
123+ // - usageStats: A UsageStats struct containing the resource usage info
124+ // - Any error that occurred while generating the usage stats
125+ func GetUsage (
126+ ctx context.Context ,
127+ cfg * scout.Config ,
128+ metrics scout.ContainerMetrics ,
129+ pod corev1.Pod ,
130+ container metav1beta1.ContainerMetrics ,
131+ ) (scout.UsageStats , error ) {
132+ var usageStats scout.UsageStats
133+ usageStats .ContainerName = container .Name
134+
135+ cpuUsage , err := GetRawUsage (container .Usage , "cpu" )
136+ if err != nil {
137+ return usageStats , errors .Wrap (err , "failed to get raw CPU usage" )
138+ }
139+
140+ memUsage , err := GetRawUsage (container .Usage , "memory" )
141+ if err != nil {
142+ return usageStats , errors .Wrap (err , "failed to get raw memory usage" )
143+ }
144+
145+ storageCapacity , storageUsage , err := GetStorageUsage (ctx , cfg , pod .Name , container .Name )
146+ if err != nil {
147+ return usageStats , errors .Wrap (err , "failed to get storage usage" )
148+ }
149+
150+ limits := metrics .Limits [container .Name ]
151+
152+ usageStats .CpuCores = limits .Cpu
153+ usageStats .CpuUsage = scout .GetPercentage (
154+ cpuUsage ,
155+ limits .Cpu .AsApproximateFloat64 ()* scout .ABillion ,
156+ )
157+
158+ usageStats .Memory = limits .Memory
159+ usageStats .MemoryUsage = scout .GetPercentage (
160+ memUsage ,
161+ limits .Memory .AsApproximateFloat64 (),
162+ )
163+
164+ if limits .Storage == nil {
165+ storageDec := * inf .NewDec (0 , 0 )
166+ usageStats .Storage = resource .NewDecimalQuantity (storageDec , resource .Format ("DecimalSI" ))
167+ } else {
168+ usageStats .Storage = limits .Storage
169+ }
170+
171+ usageStats .StorageUsage = scout .GetPercentage (
172+ storageUsage ,
173+ storageCapacity ,
174+ )
175+
176+ if metrics .Limits [container .Name ].Storage == nil {
177+ usageStats .Storage = nil
178+ }
179+
180+ return usageStats , nil
181+ }
182+
183+ // GetRawUsage returns the raw usage value for a given resource type from a Kubernetes ResourceList.
184+ //
185+ // It accepts:
186+ // - usages: A Kubernetes ResourceList containing usage values
187+ // - targetKey: The resource type to get the usage for (e.g. "cpu" or "memory")
188+ //
189+ // It returns:
190+ // - The raw usage value for the target resource type
191+ // - Any error that occurred while parsing the usage value
100192func GetRawUsage (usages corev1.ResourceList , targetKey string ) (float64 , error ) {
101193 var usage * inf.Dec
102194
@@ -114,13 +206,19 @@ func GetRawUsage(usages corev1.ResourceList, targetKey string) (float64, error)
114206 return toFloat , nil
115207}
116208
117- // getPvcCapacity retrieves the storage capacity of a PersistentVolumeClaim
118- // mounted as a volume by a container.
209+ // GetPvcCapacity returns the storage capacity of a PersistentVolumeClaim mounted to a container.
210+ //
211+ // It accepts:
212+ // - ctx: The context for the request
213+ // - cfg: The scout config containing Kubernetes clientsets
214+ // - container: The container specification
215+ // - pod: The pod specification
119216//
120217// It returns:
121- // - The capacity Quantity of the PVC if a matching PVC mount is found
122- // - nil if no PVC mount is found
123- // - Any error that occurred while getting the PVC
218+ // - The storage capacity of the PVC in bytes
219+ // - Any error that occurred while fetching the PVC
220+ //
221+ // If no PVC is mounted to the container, nil is returned for the capacity and no error.
124222func GetPvcCapacity (ctx context.Context , cfg * scout.Config , container corev1.Container , pod * corev1.Pod ) (* resource.Quantity , error ) {
125223 for _ , vm := range container .VolumeMounts {
126224 for _ , v := range pod .Spec .Volumes {
@@ -147,18 +245,49 @@ func GetPvcCapacity(ctx context.Context, cfg *scout.Config, container corev1.Con
147245 return nil , nil
148246}
149247
150- // getStorageUsage executes the df -h command in a container and parses the
151- // output to get the storage usage percentage for ephemeral storage volumes.
248+ // GetStorageUsage returns the storage capacity and usage for a given pod and container.
249+ //
250+ // It accepts:
251+ // - ctx: The context for the request
252+ // - cfg: The scout config containing Kubernetes clientsets
253+ // - podName: The name of the pod
254+ // - containerName: The name of the container
152255//
153256// It returns:
154- // - The storage usage percentage for storage volumes
155- // - "-" if no storage volumes are found
156- // - Any error that occurred while executing the df -h command or parsing the output
257+ // - storageCapacity: The total storage capacity for the container in bytes
258+ // - storageUsage: The used storage for the container in bytes
259+ // - Any error that occurred while fetching the storage usage
157260func GetStorageUsage (
158261 ctx context.Context ,
159262 cfg * scout.Config ,
160- podName , containerName string ,
263+ podName string ,
264+ containerName string ,
161265) (float64 , float64 , error ) {
266+ var storageCapacity float64
267+ var storageUsage float64
268+
269+ stateless := []string {
270+ "cadvisor" ,
271+ "pgsql-exporter" ,
272+ "executor" ,
273+ "dind" ,
274+ "github-proxy" ,
275+ "jaeger" ,
276+ "node-exporter" ,
277+ "otel-agent" ,
278+ "otel-collector" ,
279+ "precise-code-intel-worker" ,
280+ "redis-exporter" ,
281+ "repo-updater" ,
282+ "frontend" ,
283+ "syntect-server" ,
284+ "worker" ,
285+ }
286+
287+ if scout .Contains (stateless , containerName ) {
288+ return storageCapacity , storageUsage , nil
289+ }
290+
162291 req := cfg .K8sClient .CoreV1 ().RESTClient ().Post ().
163292 Resource ("pods" ).
164293 Name (podName ).
0 commit comments