Kubernetes/k8s2d2.py - Diagram with python and D2

From Federal Burro of Information
Jump to navigationJump to search

This python script will read your kubernetes and write a D2 file from which you can make a diagram.

So far: service -> deployment -> hpa

Missing: sts, cron, ingress, gateway, configmaps, secrets, mounts, pvc.

#!/usr/bin/env python3
# connects to you k8s cluster create d2 source file.
# https://kubernetes.io/
# https://d2lang.com/
# https://github.com/MrBlenny/py-d2

from kubernetes import client, config
import argparse
import pprint
from py_d2.connection import D2Connection
from py_d2.diagram    import D2Diagram
from py_d2.shape      import D2Shape 

pp = pprint.PrettyPrinter(indent=4)
config.load_kube_config() 
parser = argparse.ArgumentParser()
parser.add_argument('--namespace', type=str, help='kubernetes namespace', default="default");
args = parser.parse_args()

# k8s apis clients, why three?
core = client.CoreV1Api()
v1 = client.AppsV1Api()
autoscaleapi = client.AutoscalingV1Api()
network_api = client.NetworkingV1Api()

# diagram setup containers
diagram = D2Diagram()
cluster = D2Shape(name="kubernetes_cluster", label="cluster name: staging-gcp-env-gke")
namespace = D2Shape(name="namespace", label="namespace:"+args.namespace)
cluster.add_shape(namespace)
diagram.add_shape(cluster)

try:
  deployments = v1.list_namespaced_deployment(args.namespace)
  for i in deployments.items:
    # pp.pprint(i)
    print("deployment {}\t{}".format(i.metadata.name, i.metadata.namespace))
    namespace.add_shape(D2Shape(name="deploy."+i.metadata.name,label="deploy: " + i.metadata.name))
except Exception as e:
  print("Exception when calling v1.list_namespaced_horizontal_pod_autoscaler: %s\n" % e)

try:
  hpas = autoscaleapi.list_namespaced_horizontal_pod_autoscaler(args.namespace)
  for i in hpas.items:
    print("hpa {}\t{}".format(i.metadata.name, i.metadata.namespace))
    namespace.add_shape(D2Shape(name="hpa."+i.metadata.name,label="hpa: "+i.metadata.name))
    namespace.add_connection(D2Connection(shape_2="hpa."+i.metadata.name, shape_1="deploy."+i.spec.scale_target_ref.name))
except Exception as e:
  print("Exception when calling v1.list_namespaced_horizontal_pod_autoscaler: %s\n" % e)

try:
  services = core.list_namespaced_service(args.namespace)
  for i in services.items:
    # print("service {}\t{}".format(i.metadata.name, i.metadata.namespace))
    namespace.add_shape(D2Shape(name="service."+i.metadata.name,label="service: "+i.metadata.name))
    # find the deploy this service points at.
    for deploy in deployments.items:
      if deploy.spec.selector.match_labels == i.spec.selector:
        #print("selectors match")
        #pp.pprint(deploy.spec.selector.match_labels)
        #print("---")
        #pp.pprint(i.spec.selector)
        #print("---")
        namespace.add_connection(D2Connection(shape_1="service."+i.metadata.name, shape_2="deploy."+deploy.metadata.name))
except Exception as e:
  print("Exception when calling core.list_namespaced_service: %s\n" % e)

try:
  # ingress = v1.list_namespaced_deployment(args.namespace)
  ingress = network_api.list_namespaced_ingress(args.namespace)

  for i in ingress.items:
    # pp.pprint(i)
    print("ingress {}\t{}".format(i.metadata.name, i.metadata.namespace))
    namespace.add_shape(D2Shape(name="ingress."+i.metadata.name,label="ingress: " + i.metadata.name))
    if i.spec.default_backend.service.name:
      print ( "{}".format(i.spec.default_backend.service.name))
      namespace.add_connection(D2Connection(shape_1="ingress."+i.metadata.name, shape_2="service."+i.spec.default_backend.service.name))
except Exception as e:
  print("Exception when calling network_api.list_namespaced_ingress(args.namespace) : {}".format(e))

with open("namespace.d2", "w", encoding="utf-8") as f:
    f.write(str(diagram))