Last active
October 8, 2015 04:48
-
-
Save prehensile/841cb7f0bb822ea902cd to your computer and use it in GitHub Desktop.
Various Kubernetes / Google Container Engine tools
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
#!/usr/bin/env python | |
## | |
# kube-resources.py | |
# Collate and report Kubernetes pod usages vs. node limits. | |
# | |
# Assumes `kubectl` is installed and available. | |
# | |
# Author: Henry Cooke, [email protected] | |
# Version: 20150816 | |
# | |
import json | |
import subprocess | |
import re | |
import math | |
def main(): | |
# get pod & node data | |
pod_dict = get_pods() | |
node_dict = get_nodes() | |
# step through nodes hash | |
for node_name in node_dict: | |
# print node info | |
print "---\nNODE:\t%s\n---" % node_name | |
node = node_dict[node_name] | |
stat = node.get("status") | |
cap = stat.get("capacity") | |
cpu_capacity = 0 | |
mem_capacity = 0 | |
if cap: | |
cpu_capacity = parse_cpu( cap.get("cpu") ) | |
mem_capacity = parse_mem( cap.get("memory") ) | |
# print pods | |
pods = pod_dict.get( node_name ) | |
if (pods is not None) and (len(pods)>0): | |
total_cpu, total_mem, rows = parse_pods( pods ) | |
print_pods( rows ) | |
print "---" | |
print "Memory allocated: %s (%2.2f%% of capacity)" % ( | |
format_mem(total_mem,"Mi"), | |
(float(total_mem)/float(mem_capacity))*100.0 | |
) | |
print "CPU allocated: %s (%2.2f%% of capacity)" % ( | |
format_cpu(total_cpu,"m"), | |
(total_cpu/cpu_capacity)*100.0 | |
) | |
# print node capacity | |
print "---" | |
print "Memory capacity: %s" % format_mem(mem_capacity,"Mi") | |
print "CPU capacity: %s" % format_cpu(cpu_capacity,"m") | |
print "---\n" | |
def get_nodes(): | |
node_dict = {} | |
node_json = json.loads( | |
subprocess.check_output( | |
[ "kubectl", "get", "nodes", "-o", "json" ] | |
) | |
) | |
node_dict = {} | |
for node in node_json["items"]: | |
node_dict[ node["metadata"]["name"] ] = node | |
return node_dict | |
def get_pods(): | |
pod_json = json.loads( | |
subprocess.check_output( | |
[ "kubectl", "get", "pods", "-o", "json", "--all-namespaces" ] | |
) | |
) | |
pod_dict = {} | |
for pod in pod_json["items"]: | |
spec = pod["spec"] | |
if "nodeName" in spec: | |
node_name = spec["nodeName"] | |
if node_name not in pod_dict: | |
pod_dict[node_name] = [] | |
pod_dict[node_name].append(pod) | |
return pod_dict | |
def parse_container( container ): | |
container_name = container["name"] | |
res = container.get("resources") | |
cpu_limit = 0 | |
mem_limit = 0 | |
if res: | |
limits = res.get("limits") | |
if limits: | |
cpu_limit = parse_cpu( limits.get("cpu") ) | |
mem_limit = parse_mem( limits.get("memory") ) | |
return container_name, cpu_limit, mem_limit | |
def print_pods( rows ): | |
headers = [ "CONTAINER NAME", "NAMESPACE", "MEM LIMIT", "CPU LIMIT" ] | |
# calculate inital column widths | |
row_widths = [ len(col)+2 for col in headers ] | |
# step through rows, find max widths for columns | |
rows.insert( 0, headers ) | |
for row in rows: | |
for i in range(len(row_widths)): | |
row_widths[i] = max( row_widths[i], len("%s"%row[i])+2 ) | |
# generate format string, see https://docs.python.org/3/library/string.html#format-examples | |
fmt = '{:<%d}{:<%d}{:<%d}{:<%d}' % tuple(row_widths) | |
for row in rows: | |
print fmt.format(*row) | |
def parse_pods( pods ): | |
total_cpu = 0 | |
total_mem = 0 | |
rows = [] | |
for pod in pods: | |
spec = pod["spec"] | |
m = pod["metadata"] | |
namespace = m["namespace"] | |
for container in spec["containers"]: | |
container_name, cpu_limit, mem_limit = parse_container( container ) | |
total_cpu += cpu_limit | |
total_mem += mem_limit | |
rows.append( (container_name,namespace, format_mem(mem_limit,"Mi"), format_cpu(cpu_limit,"m"))) | |
rows.append( ["","","---","---"] ) | |
rows.append( ["","TOTALS",format_mem(total_mem,"Mi"),format_cpu(total_cpu,"m")] ) | |
return total_cpu, total_mem, rows | |
def parse_cpu( cpu ): | |
""" Return CPU value in whole units """ | |
if cpu is None: | |
return 0 | |
if type(cpu) is int: | |
return cpu | |
g = re.match('(\d*)(\w*)',cpu).groups() | |
amt = int(g[0]) | |
if len(g) > 1: | |
unit = g[1] | |
# TODO: add more possible unit types? | |
if unit == "m": | |
amt = float(amt) / 1000.0 | |
return amt | |
def format_cpu( cpu, unit=None ): | |
if unit.lower() == "m": | |
# return CPU formatted in milliunits | |
return "%0.0fm" % (float(cpu) * 1000.0) | |
return cpu * 1000 | |
def parse_mem( mem ): | |
""" Return mem value in bytes """ | |
if mem is None: | |
return 0 | |
if type(mem) is int: | |
return mem | |
g = re.match('(\d*)(\w*)',mem).groups() | |
amt = int(g[0]) | |
if len(g) > 1: | |
unit = g[1] | |
# TODO: add more possible unit types? | |
if unit.lower() == "ki": | |
amt *= 1024 | |
elif unit.lower() == "mi": | |
amt *= (1024 * 1024) | |
return amt | |
def format_mem( mem, unit=None ): | |
if unit.lower() == "ki": | |
# return mem formatted in kibibytes | |
return "%dKi" % (mem / 1024) | |
elif unit.lower() == "mi": | |
# return mem formatted in mebibytes | |
return "%dMi" % (mem / math.pow(1024,2) ) | |
elif unit.lower() == "gi": | |
# return mem formatted in gibibytes | |
return "%dGi" % (mem / math.pow(1024,3) ) | |
return mem | |
# entrypoint... | |
if __name__ == '__main__': | |
main() |
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
#!/usr/bin/env bash | |
for MODULE in "$@" | |
do | |
kubectl rolling-update $MODULE --image=gcr.io/pastcards-1033/$MODULE | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment