Python for DevOps Cheat Sheet¶
Remember: Python's
json.toolmodule is a built-in JSON pretty-printer with no dependencies:python3 -m json.tool < file.json. The-mflag runs a module as a script — it works withhttp.server(instant file server),venv(virtual environments),base64,zipfile, and more. Python's stdlib is your Swiss army knife on servers where you cannot install extra tools.
One-Liners¶
# Pretty-print JSON
python3 -m json.tool < file.json
cat file.json | python3 -m json.tool
# Simple HTTP server
python3 -m http.server 8000
# Base64 encode/decode
python3 -c "import base64; print(base64.b64encode(b'secret').decode())"
python3 -c "import base64; print(base64.b64decode('c2VjcmV0').decode())"
# URL encode
python3 -c "import urllib.parse; print(urllib.parse.quote('hello world'))"
# Generate random password
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# Timestamp conversion
python3 -c "from datetime import datetime; print(datetime.fromtimestamp(1700000000))"
File Operations (pathlib)¶
from pathlib import Path
p = Path('/etc/nginx/nginx.conf')
p.exists() # Check existence
p.read_text() # Read file
p.write_text(content) # Write file
p.stem # 'nginx'
p.suffix # '.conf'
p.parent # Path('/etc/nginx')
# Find files
list(Path('.').rglob('*.yaml')) # Recursive glob
list(Path('.').glob('*.py')) # Current dir only
JSON / YAML Processing¶
import json
import yaml # pip install pyyaml
# JSON
data = json.loads('{"key": "val"}')
text = json.dumps(data, indent=2)
with open('f.json') as f:
data = json.load(f)
# YAML
with open('f.yaml') as f:
data = yaml.safe_load(f)
# Multi-doc YAML
with open('f.yaml') as f:
for doc in yaml.safe_load_all(f):
print(doc)
Subprocess (Run Shell Commands)¶
import subprocess
# Simple command
r = subprocess.run(['kubectl', 'get', 'pods'], capture_output=True, text=True, check=True)
print(r.stdout)
# With timeout
r = subprocess.run(['helm', 'list'], capture_output=True, text=True, timeout=30)
# Parse JSON output
import json
r = subprocess.run(['kubectl', 'get', 'pods', '-o', 'json'], capture_output=True, text=True)
pods = json.loads(r.stdout)
Never use shell=True with user input — shell injection risk.
Gotcha:
subprocess.run()withcheck=TrueraisesCalledProcessErroron non-zero exit codes, which is what you want in scripts (fail fast). Withoutcheck=True, a failed command silently returns a result object withreturncode != 0, and your script continues as if nothing went wrong. Always usecheck=Trueunless you explicitly handle non-zero exits.
HTTP Requests¶
# stdlib (no dependencies)
import urllib.request, json
resp = urllib.request.urlopen('http://localhost:8080/health')
data = json.loads(resp.read())
# requests library (pip install requests)
import requests
r = requests.get('https://api.example.com/data', headers={'Authorization': 'Bearer tok'})
r.raise_for_status()
data = r.json()
r = requests.post('https://api.example.com/deploy',
json={'version': 'v2.0', 'env': 'prod'},
timeout=10)
Default trap:
yaml.load()(withoutLoaderargument) is a security vulnerability — it can execute arbitrary Python code embedded in YAML. Always useyaml.safe_load(). Modern PyYAML versions warn about this, but older versions silently allow it. This is a common audit finding in DevOps scripts.
Environment Variables¶
import os
val = os.environ.get('MY_VAR', 'default') # With default
val = os.environ['REQUIRED_VAR'] # Raises KeyError if missing
# Boolean from env
debug = os.environ.get('DEBUG', 'false').lower() == 'true'
Kubernetes Client¶
from kubernetes import client, config # pip install kubernetes
config.load_kube_config() # From ~/.kube/config
# config.load_incluster_config() # Inside a pod
v1 = client.CoreV1Api()
pods = v1.list_namespaced_pod('default')
for p in pods.items:
print(f"{p.metadata.name}: {p.status.phase}")
Jinja2 Templating¶
from jinja2 import Template, Environment, FileSystemLoader
# Inline
tmpl = Template("Hello {{ name }}")
print(tmpl.render(name="world"))
# From files
env = Environment(loader=FileSystemLoader('templates/'))
tmpl = env.get_template('deploy.yaml.j2')
print(tmpl.render(replicas=3, image='myapp:v2'))
Common Patterns¶
# Retry with backoff
import time
def retry(fn, attempts=3, delay=2):
for i in range(attempts):
try:
return fn()
except Exception as e:
if i == attempts - 1:
raise
time.sleep(delay * (2 ** i))
# Parallel execution
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=5) as pool:
results = list(pool.map(check_health, services))
# Temp files
import tempfile
with tempfile.NamedTemporaryFile(suffix='.yaml', mode='w', delete=False) as f:
f.write(yaml_content)
print(f.name) # Use the path
Script Boilerplate¶
#!/usr/bin/env python3
"""Brief description of what this script does."""
import argparse
import sys
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--env', required=True, choices=['dev', 'prod'])
parser.add_argument('--dry-run', action='store_true')
args = parser.parse_args()
# ... your logic here ...
if __name__ == '__main__':
main()