@@ -26,24 +26,8 @@ class InputSchema(BaseModel):
2626 title = "Threshold (in %)" ,
2727 )
2828
29-
30- def k8s_check_service_pvc_utilization_printer (output ):
31- status , pvc_info = output
32-
33- if status :
34- print ("Disk sizes for all checked services are within the threshold." )
35- else :
36- print ("ALERT: One or more PVC disk sizes are above threshold:" )
37- print ("-" * 40 )
38- for pvc in pvc_info :
39- print (
40- f"PVC: { pvc ['pvc_name' ]} - Utilized: { pvc ['used' ]} of { pvc ['capacity' ]} "
41- )
42- print ("-" * 40 )
43-
44-
4529def k8s_check_service_pvc_utilization (
46- handle , core_services : list , namespace : str , threshold : int = 80
30+ handle , core_services : list , namespace : str , threshold : int = 60
4731) -> Tuple :
4832 """
4933 k8s_check_service_pvc_utilization checks the utilized disk size of a service's PVC against a given threshold.
@@ -70,6 +54,9 @@ def k8s_check_service_pvc_utilization(
7054
7155 alert_pvcs_all_services = []
7256 services_without_pvcs = []
57+
58+ # Keep track of processed PVCs to avoid duplicates
59+ processed_pvcs = set ()
7360
7461 for svc in core_services :
7562 # Get label associated with the service
@@ -110,9 +97,7 @@ def k8s_check_service_pvc_utilization(
11097 else :
11198 json_path_cmd = "{.metadata.name}:{range .spec.volumes[*].persistentVolumeClaim}{.claimName}{end}"
11299
113- get_pvc_names_command = (
114- f"kubectl get pod { pod_names } -n { namespace } -o=jsonpath='{ json_path_cmd } '"
115- )
100+ get_pvc_names_command = f"kubectl get pod { pod_names } -n { namespace } -o=jsonpath='{ json_path_cmd } '"
116101
117102 response = handle .run_native_cmd (get_pvc_names_command )
118103 if not response or response .stderr :
@@ -129,7 +114,6 @@ def k8s_check_service_pvc_utilization(
129114
130115 pvc_mounts = []
131116 alert_pvcs = []
132- all_pvcs = []
133117
134118 for element in pod_and_pvc_names :
135119 pod_name , claim_name = element .split (":" )
@@ -146,7 +130,9 @@ def k8s_check_service_pvc_utilization(
146130 # df -kh is the command used to get the disk utilization. This is accurate as we get
147131 # the disk utilization from the POD directly, rather than checking the resource limit
148132 # and resource request from the deployment / stateful YAML file.
149- get_pod_json_command = f"kubectl get pod { pod_name } -n { namespace } -o json"
133+ get_pod_json_command = (
134+ f"kubectl get pod { pod_name } -n { namespace } -o json"
135+ )
150136 pod_json_output = handle .run_native_cmd (get_pod_json_command )
151137 if not pod_json_output or pod_json_output .stderr :
152138 raise ApiException (
@@ -165,36 +151,44 @@ def k8s_check_service_pvc_utilization(
165151 claim_name = volume ["persistentVolumeClaim" ][
166152 "claimName"
167153 ]
168- pvc_mounts .append (
169- {
170- "container_name" : container ["name" ],
171- "mount_path" : mount ["mountPath" ],
172- "pvc_name" : claim_name if claim_name else None ,
173- }
174- )
154+ print (f"ClaimName: { claim_name } : MountName: { mount ['name' ]} ContainerName: { container ['name' ]} " )
155+
156+ # Add mount info if not already added
157+ mount_info = {
158+ "container_name" : container ["name" ],
159+ "mount_path" : mount ["mountPath" ],
160+ "pvc_name" : claim_name if claim_name else None ,
161+ "pod_name" : pod_name
162+ }
163+
164+ # Only add if this specific mount combination hasn't been processed yet
165+ mount_key = f"{ pod_name } :{ container ['name' ]} :{ mount ['mountPath' ]} :{ claim_name } "
166+ if mount_key not in processed_pvcs :
167+ pvc_mounts .append (mount_info )
168+ processed_pvcs .add (mount_key )
169+
175170 except KeyError as e :
176171 # Handle the KeyError (e.g., log the error, skip this iteration, etc.)
177172 print (f"KeyError: { e } . Skipping this entry." )
178173 except IndexError as e :
179174 # Handle the IndexError (e.g., log the error, skip this iteration, etc.)
180175 print (f"IndexError: { e } . Skipping this entry." )
181176
182- all_mounts = [mount .get ("mount_path" ) for mount in pvc_mounts ]
183- all_mounts = " " .join (all_mounts ).strip ()
177+ # Create a dictionary to store processed PVC info
178+ pvc_info_dict = {}
179+
180+ # Process each mount separately with a single df command
184181 for mount in pvc_mounts :
185182 container_name = mount ["container_name" ]
186183 mount_path = mount ["mount_path" ]
187184 pvc_name = mount ["pvc_name" ]
188- all_pvcs .append (
189- {
190- "pvc_name" : pvc_name ,
191- "mount_path" : mount_path ,
192- "used" : None ,
193- "capacity" : None ,
194- }
195- )
196-
197- du_command = f"kubectl exec -n { namespace } { pod_name } -c { container_name } -- df -kh { all_mounts } | grep -v Filesystem"
185+ pod_name = mount ["pod_name" ]
186+
187+ # Skip if we've already processed this PVC
188+ if pvc_name in pvc_info_dict :
189+ continue
190+
191+ du_command = f"kubectl exec -n { namespace } { pod_name } -c { container_name } -- df -kh { mount_path } | grep -v Filesystem"
198192 du_output = handle .run_native_cmd (du_command )
199193
200194 if du_output and not du_output .stderr :
@@ -228,16 +222,25 @@ def k8s_check_service_pvc_utilization(
228222 "used" : used_percentage ,
229223 "capacity" : total_capacity ,
230224 }
225+
226+ # Store in dictionary to prevent duplicates
227+ pvc_info_dict [pvc_name ] = pvc_info
231228
232229 # Check if usage exceeds threshold
233230 if used_percentage > threshold :
234231 alert_pvcs .append (pvc_info )
235232
236- alert_pvcs_all_services .extend (alert_pvcs )
233+ # Add unique alert PVCs to the main list
234+ for pvc_info in alert_pvcs :
235+ if pvc_info not in alert_pvcs_all_services :
236+ alert_pvcs_all_services .append (pvc_info )
237237
238238 if services_without_pvcs :
239239 print ("Following services do not have any PVCs attached:" )
240240 for service in services_without_pvcs :
241241 print (f"- { service } " )
242242
243+ if alert_pvcs_all_services :
244+ print (json .dumps (alert_pvcs_all_services , indent = 4 ))
245+
243246 return (not bool (alert_pvcs_all_services ), alert_pvcs_all_services )
0 commit comments