Python for Automation
While Bash is the king of moving files and running local terminal commands, it struggles when you need to automate interactions with modern Web APIs. As systems grow more complex, you will frequently need to automate tasks that require sending HTTP requests, parsing JSON, and handling authentication.
This is where Python becomes an essential DevOps skill.
The Problem with Bash
Imagine you need to move 50 torrents from one folder to another inside a complex application like qBittorrent.
If you try to do this with Bash, you might use mv /downloads/* /media/downloads/. But this breaks the application because the software's internal SQLite database still thinks the files are in the old location!
To do this safely, you must tell the application to move the files itself via its REST API.
Doing this in Bash with curl requires handling cookies, session tokens, formatting complex JSON payloads, and parsing the responses with jq. It is brittle and difficult to read.
The Python Solution
Python's requests library makes API automation trivial. It handles sessions, cookies, and JSON parsing automatically.
Here is an example of an automation script we wrote to securely connect to a local API, change a global setting, and migrate data:
import requests
import getpass
import sys
URL = "http://qbittorrent.homelab.local"
# 1. Start a persistent session (handles cookies automatically)
session = requests.Session()
# 2. Authenticate
password = getpass.getpass("Password: ")
login = session.post(f"{URL}/api/v2/auth/login", data={"username": "admin", "password": password})
if login.text != "Ok.":
sys.exit("Authentication failed!")
# 3. Retrieve Data (Automatically parses JSON into Python dictionaries)
torrents = session.get(f"{URL}/api/v2/torrents/info").json()
# 4. Perform Complex Logic and Send Actions
hashes = "|".join([t['hash'] for t in torrents])
session.post(f"{URL}/api/v2/torrents/setLocation", data={
"hashes": hashes,
"location": "/data/media/downloads/"
})
print(f"Successfully migrated {len(torrents)} torrents!")
Running Python Scripts with uv
Historically, running Python scripts required setting up a virtualenv and installing dependencies with pip install requests, which cluttered your global system.
Using the modern uv package manager, you can write standalone scripts with inline dependencies. You simply add a special comment block to the top of your script:
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests",
# ]
# ///
import requests
# ...
Now, anyone can download your script, make it executable (chmod +x script.py), and run it directly (./script.py). uv will automatically detect the required dependencies, instantly download them into a hidden, isolated cache, and run the script flawlessly without touching your global environment.
This pattern is the gold standard for DevOps automation scripts!
Kubernetes Automation: Reaching into Pods
Python isn't just for interacting with REST APIs. As a DevOps engineer, you will often need to bridge the gap between CLI tools and web APIs.
For example, when deploying a complex media stack, you might need to extract automatically generated API keys from a newly deployed pod and pass them into another application's API.
Instead of opening a terminal, entering the pod, reading the file, copying the key, opening a browser, and pasting it into a UI, you can write a Python script that uses subprocess to execute kubectl exec commands against the cluster, parses the output, and feeds it directly into a REST API payload!
import subprocess
import xml.etree.ElementTree as ET
import requests
# 1. Execute a CLI command against a remote Kubernetes Pod
cmd = "kubectl exec -n media deploy/radarr -- cat /config/config.xml"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
# 2. Parse the internal XML configuration file of the container
root = ET.fromstring(result.stdout)
api_key = root.find('ApiKey').text
# 3. Inject the stolen secret directly into another service's REST API!
session = requests.Session()
payload = {
"hostname": "radarr.media.svc.cluster.local",
"apiKey": api_key,
}
session.post("http://jellyseerr.homelab.local/api/v1/settings/radarr", json=payload)
This effectively turns your script into a hacker that reaches into your own infrastructure to orchestrate zero-touch deployments!