Calligraphy

Background

Calligraphy came about due to the challenges that came about with writing a management script for an Artifactory instance. The instance was deployed to an EKS cluster via Helm with an S3 bucket backing the actual artifacts themselves and an RDS database for the metadata. These various AWS resources were all backed as Infrastructure As Code (IAC) and managed via Terraform. This led to some pain when writing the management script as we could go two directions:

  1. Use Bash and get the ability to run the necessary shell commands very easily however lose all the advantages of a modern programming language
  2. Use Python and get the advantages of a modern programming language but lose the ability to easily run shell commands

After considering the two options I figured, why not get the best of both worlds and set out to create Calligraphy.

How it Works

Calligraphy works by doing a shallow parse of the script that is passed into it. It breaks it apart into tokens and determines what is inside of strings (will not be checked for Bash commands) and what is outside of them. For those outside of strings, we then go through each line of code and check if it matches the following conditions:

  • Does it start with a Python keyword
  • Is it a function call to a previously detected function
  • Does it start with a previously detected Python variable name
  • Does it start with a package name (i.e. is it a call to a package’s function)

If any of those are true then the line of code is a Python line, otherwise if it starts with """ or # then it’s a comment. Any remaining lines are marked as Bash lines. Finally, we check each Python line to see if it contains something wrapped in $(...). If yes, that is then inline Bash code and the line is considered mixed, otherwise it’s pure Python.

Once the language has been determined for each line, we can then wrap the bash code in calls to functions defined the header which gets pre-pended to the transpiled code. This code is then either output or run (depending on what the user has asked to do).

Example Script

#! /usr/bin/env calligraphy
# type: ignore

# This file will get the resources for all containers and initContainers present in pods
# in your currently active Kubernetes cluster/namespace
# It will then print them out neatly so you can verify what is set on each pod/container

import json

pods = ?(kubectl get pods | tail -n +2 | awk '{{print $1}}').split('\n')[:-1]

for pod in pods:
    print(pod)
    pod_data = json.loads(?(kubectl get pod {pod} -o json))
    print('  containers')
    for container in pod_data['spec']['containers']:
        if 'limits' in container["resources"].keys():
            print(f'    limits   : {container["resources"]["limits"]}')
        if 'requests' in container["resources"].keys():
            print(f'    requests : {container["resources"]["requests"]}')
    if 'initContainers' in pod_data['spec'].keys():
        print('  init containers')
        for init_container in pod_data['spec']['containers']:
            if 'limits' in init_container["resources"].keys():
                print(f'    limits   : {init_container["resources"]["limits"]}')
            if 'requests' in init_container["resources"].keys():
                print(f'    requests : {init_container["resources"]["requests"]}')

Links

Home
Education
Laboratory Experience
Projects
Publications and Presentations
Work Experience
Journal