Created
November 22, 2023 22:18
-
-
Save rooftopcellist/9a5ab0a4f10c22e7b5472318ddfad5b0 to your computer and use it in GitHub Desktop.
Create a report of resource usage in a given namespace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Purpose: | |
* Generate a report of all pod cpu and memory usage in a namespace | |
Usage: | |
$ python3 resource-utilization-report.py namespace | |
''' | |
import subprocess | |
import argparse | |
import json | |
from tabulate import tabulate | |
def convert_memory_to_megabytes(memory_str): | |
""" | |
Convert memory value to Megabytes. | |
If the value is in Gi, convert it to Mi; otherwise, return the value as is. | |
""" | |
if memory_str.endswith('Gi'): | |
return str(int(float(memory_str.replace('Gi', '')) * 1024)) + 'Mi' | |
elif memory_str.endswith('Mi'): | |
return memory_str | |
else: | |
return 'N/A' # Handle cases where unit is not recognized | |
def get_resource_usage(namespace): | |
try: | |
# Initialize variables to store total metrics for CPU and Memory | |
total_cpu_usage = 0.0 | |
total_cpu_requests = 0.0 | |
total_cpu_limits = 0.0 | |
total_memory_usage = 0.0 | |
total_memory_requests = 0 | |
total_memory_limits = 0 | |
# Get CPU and memory usage for all pods in the namespace | |
top_output = subprocess.check_output(['kubectl', 'top', 'pod', '-n', namespace, '--containers', '--no-headers']).decode('utf-8') | |
# Get resource requests and limits for all pods in the namespace | |
describe_output = subprocess.check_output(['kubectl', 'get', 'pod', '-n', namespace, '-o', 'json']).decode('utf-8') | |
# Parse the describe output as JSON | |
pod_info = json.loads(describe_output) | |
pod_count = len(pod_info['items']) | |
# Initialize dictionaries to store resource data | |
resource_data = {} | |
# Split and process the top output | |
top_lines = top_output.strip().split('\n') | |
for line in top_lines: | |
parts = line.split() | |
pod_name = parts[0] | |
container_name = parts[1] | |
cpu_usage = parts[2] | |
memory_usage = parts[3] | |
# Add CPU usage to total and convert memory usage to Mi if necessary | |
total_cpu_usage += float(cpu_usage.replace('m', '')) | |
total_memory_usage += int(convert_memory_to_megabytes(memory_usage).replace('Mi', '')) | |
# Skip the "POD" container | |
if container_name == "POD": | |
continue | |
# Store resource data | |
if pod_name not in resource_data: | |
resource_data[pod_name] = { | |
'Pod Name': pod_name, | |
'Containers': [] | |
} | |
resource_data[pod_name]['Containers'].append({ | |
'Container Name': container_name, | |
'CPU Usage': cpu_usage, | |
'Memory Usage': memory_usage | |
}) | |
# Iterate over pods to gather requests and limits | |
for pod in pod_info['items']: | |
pod_name = pod['metadata']['name'] | |
# Initialize dictionaries to store requests and limits for containers | |
requests = {} | |
limits = {} | |
for container in pod['spec']['containers']: | |
container_name = container['name'] | |
# Get container-level resource requests and limits | |
container_resources_data = container.get('resources', {}) | |
cpu_requests = container_resources_data.get('requests', {}).get('cpu', 'N/A') | |
memory_requests = convert_memory_to_megabytes(container_resources_data.get('requests', {}).get('memory', 'N/A')) | |
cpu_limits = container_resources_data.get('limits', {}).get('cpu', 'N/A') | |
memory_limits = convert_memory_to_megabytes(container_resources_data.get('limits', {}).get('memory', 'N/A')) | |
# Add CPU and Memory requests and limits to total | |
if cpu_requests != 'N/A': | |
total_cpu_requests += float(cpu_requests.replace('m', '')) | |
if cpu_limits != 'N/A': | |
total_cpu_limits += float(cpu_limits.replace('m', '')) | |
if memory_requests != 'N/A': | |
total_memory_requests += int(memory_requests.replace('Mi', '')) | |
if memory_limits != 'N/A': | |
total_memory_limits += int(memory_limits.replace('Mi', '')) | |
requests[container_name] = f"CPU: {cpu_requests}, Memory: {memory_requests}" | |
limits[container_name] = f"CPU: {cpu_limits}, Memory: {memory_limits}" | |
container_resources = {} | |
container_resources[pod_name] = { | |
'Requests': requests, | |
'Limits': limits | |
} | |
# Return the total metrics along with the existing data | |
return resource_data, container_resources, total_cpu_usage, total_cpu_requests, total_cpu_limits, total_memory_usage, total_memory_requests, total_memory_limits, pod_count | |
except subprocess.CalledProcessError as e: | |
return str(e), None, None, None, None, None, None, None, None | |
def main(): | |
parser = argparse.ArgumentParser(description='Generate a performance report for a Kubernetes namespace.') | |
parser.add_argument('namespace', metavar='NAMESPACE', type=str, help='The Kubernetes namespace to monitor') | |
args = parser.parse_args() | |
namespace = args.namespace | |
resource_data, container_resources, total_cpu_usage, total_cpu_requests, total_cpu_limits, total_memory_usage, total_memory_requests, total_memory_limits, pod_count = get_resource_usage(namespace) | |
if isinstance(resource_data, dict): | |
data = [] | |
headers = ['Pod Name', 'Container Name', 'CPU Usage', 'Memory Usage', 'Requests', 'Limits'] | |
for pod_name, pod_info in resource_data.items(): | |
for container_info in pod_info['Containers']: | |
container_name = container_info['Container Name'] | |
cpu_usage = container_info['CPU Usage'] | |
memory_usage = container_info['Memory Usage'] | |
requests = container_resources.get(pod_name, {}).get('Requests', {}).get(container_name, 'N/A') | |
limits = container_resources.get(pod_name, {}).get('Limits', {}).get(container_name, 'N/A') | |
data.append([pod_name, container_name, cpu_usage, memory_usage, requests, limits]) | |
print(tabulate(data, headers=headers, tablefmt='grid')) | |
# Print the totals | |
print(f"\nTotal CPU Usage for Namespace: {total_cpu_usage}m") | |
print(f"Total CPU Requests for Namespace: {total_cpu_requests}m") | |
print(f"Total CPU Limits for Namespace: {total_cpu_limits}m") | |
print(f"Total Memory Usage for Namespace: {total_memory_usage}Mi") | |
print(f"Total Memory Requests for Namespace: {total_memory_requests}Mi") | |
print(f"Total Memory Limits for Namespace: {total_memory_limits}Mi") | |
print(f"Total Pods for Namespace: {pod_count}") | |
else: | |
print(f"Error: {resource_data}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment