Python for SRE - Interview Preparation
Goal: Prepare for live coding interviews for SRE positions Time Required: ~15-18 hours (2-3 weeks, 1 hour/day) Level: Beginner → Interview-ready Focus: Operational scripting, NOT general programming
Why This Learning Plan?
What this guide will NOT do:
- Deep algorithm and data structure theory
- "Become a Python developer" approach
- General programming concepts
- LeetCode-style puzzles (though practice exercises are included)
What THIS guide WILL do:
- SRE-specific Python scripting - operational automation
- Live coding confidence - syntax fluency, speed
- Interview patterns - working script in 30 minutes
- Thinking out loud - communication practice
- Real-world SRE tasks - health checks, log parsing, Kubernetes
What this prepares you for:
- Shopify-style live pair programming (if you choose this path)
- Technical screening coding exercises (general SRE interviews)
- Operational scripting questions (real-world scenarios)
- Mock interview practice (Claude as interviewer)
Learning Methodology
Progressive Approach (3 phases):
Week 1: Claude-Assisted Learning - Claude writes the solution (full solution) - YOU read, understand, study it - Rewrite it YOURSELF (without Claude, but you can look at the solution) - Goal: Syntax familiarity, pattern recognition
Week 2: Guided Practice - Task description - YOU write it (Claude does NOT help initially!) - If stuck → Claude hint (NOT full solution!) - Testing, debugging - Goal: Independent problem-solving
Week 3: Timed Mock Interviews - Timer: 30 minutes / task - Think out loud (as if in interview) - No help (realistic interview conditions) - Goal: Interview simulation, pressure handling
Daily Routine (1 hour):
- Reading (10 min) - module theory
- Example study (10 min) - code comprehension
- Practice (30 min) - task solving
- Review (10 min) - what you learned, what was difficult
Module 1: Python Basics for SRE
Time Required: ~1 hour Goal: Variables, types, control flow (if/for/while) - minimal theory, maximum practice
1.1 Variables and Basic Types
What you need to know (minimal theory):
# String (text)
pod_name = "nginx-deployment-7d5c8f9b6d-abc12"
namespace = "production"
# Integer (number)
replica_count = 3
timeout_seconds = 30
# Float (decimal number)
cpu_usage = 0.75
memory_gb = 2.5
# Boolean (true/false)
is_healthy = True
has_errors = False
# List
namespaces = ["default", "kube-system", "production"]
pod_ips = ["10.0.1.5", "10.0.1.6", "10.0.1.7"]
# Dictionary (key-value pairs)
pod_status = {
"name": "nginx-abc12",
"status": "Running",
"restarts": 0
}
Print and string formatting:
# Simple print
print("Pod name:", pod_name)
# f-string (MODERN, use this!)
print(f"Pod {pod_name} is in {namespace} namespace")
print(f"Replica count: {replica_count}")
# String concatenation (avoid, but works)
print("Namespace: " + namespace)
1.2 Control Flow (If/Else)
# Simple if
if is_healthy:
print("Pod is healthy")
# If-else
if replica_count < 3:
print("WARNING: Low replica count")
else:
print("Replica count OK")
# If-elif-else
if cpu_usage > 0.9:
print("CRITICAL: High CPU usage")
elif cpu_usage > 0.7:
print("WARNING: Elevated CPU usage")
else:
print("CPU usage normal")
# Comparison operators
if timeout_seconds >= 30:
print("Timeout is sufficient")
if namespace == "production":
print("Production environment detected")
if namespace != "default":
print("Not using default namespace")
SRE example - pod health check logic:
pod_status = "Running"
restart_count = 5
if pod_status != "Running":
health = "Unhealthy"
elif restart_count > 3:
health = "Degraded"
else:
health = "Healthy"
print(f"Pod health: {health}")
1.3 Loops (For and While)
For loop - iterating lists:
# Simple list iteration
namespaces = ["default", "kube-system", "production"]
for ns in namespaces:
print(f"Namespace: {ns}")
# Dictionary iteration
pod_status = {
"name": "nginx-abc12",
"status": "Running",
"restarts": 0
}
for key, value in pod_status.items():
print(f"{key}: {value}")
# Range usage (counting)
for i in range(5): # 0, 1, 2, 3, 4
print(f"Replica {i}")
for i in range(1, 4): # 1, 2, 3
print(f"Attempt {i}")
While loop (less common in SRE work):
# Retry logic example
attempts = 0
max_attempts = 3
while attempts < max_attempts:
print(f"Attempt {attempts + 1}")
attempts += 1
SRE example - pod health summary:
pods = [
{"name": "nginx-1", "status": "Running"},
{"name": "nginx-2", "status": "Pending"},
{"name": "nginx-3", "status": "Running"},
]
healthy_count = 0
unhealthy_count = 0
for pod in pods:
if pod["status"] == "Running":
healthy_count += 1
else:
unhealthy_count += 1
print(f"Healthy: {healthy_count}, Unhealthy: {unhealthy_count}")
1.4 Practice Exercises (30 minutes)
Exercise 1: Namespace Filter (EASY)
Input: List of namespaces: ["default", "kube-system", "production", "staging"]
Task:
- Iterate through the list
- Print only those that are NOT "default"
Output: kube-system, production, staging
Solution (Week 1 - with Claude's help):
Click for solution
Exercise 2: Pod Health Summary (EASY)
Input:
pods = [
{"name": "nginx-1", "status": "Running", "restarts": 0},
{"name": "nginx-2", "status": "Running", "restarts": 5},
{"name": "nginx-3", "status": "CrashLoopBackOff", "restarts": 10},
]
Task:
- Count how many pods have "Running" status
- Count how many pods have more than 3 restarts
- Print: "Running pods: X, High restart count: Y"
Solution:
Click for solution
pods = [
{"name": "nginx-1", "status": "Running", "restarts": 0},
{"name": "nginx-2", "status": "Running", "restarts": 5},
{"name": "nginx-3", "status": "CrashLoopBackOff", "restarts": 10},
]
running_count = 0
high_restart_count = 0
for pod in pods:
if pod["status"] == "Running":
running_count += 1
if pod["restarts"] > 3:
high_restart_count += 1
print(f"Running pods: {running_count}, High restart count: {high_restart_count}")
Exercise 3: CPU Alert Logic (MEDIUM)
Input: cpu_usage = 0.85 (float, 0-1 range)
Task:
- If cpu_usage > 0.9 → print "CRITICAL: CPU usage X%"
- If cpu_usage > 0.7 → print "WARNING: CPU usage X%"
- Otherwise → print "OK: CPU usage X%"
Example output: "WARNING: CPU usage 85%"
Solution:
Click for solution
Module 2: Functions and Error Handling
Time Required: ~1 hour Goal: Code reusability, try/except (CRITICAL interview skill!)
2.1 Function Basics
Syntax:
# Simple function (no parameters)
def print_header():
print("=" * 50)
print("Pod Health Check Report")
print("=" * 50)
print_header()
# Function with parameter
def greet_namespace(namespace):
print(f"Checking namespace: {namespace}")
greet_namespace("production")
# Function with return value
def calculate_percentage(value, total):
percentage = (value / total) * 100
return percentage
result = calculate_percentage(75, 100)
print(f"Result: {result}%")
# Multiple return values
def get_pod_counts(pods):
running = 0
pending = 0
for pod in pods:
if pod["status"] == "Running":
running += 1
else:
pending += 1
return running, pending
running_count, pending_count = get_pod_counts(pods)
SRE example - health check function:
def check_pod_health(pod):
"""
Check if a pod is healthy based on status and restart count.
Args:
pod: Dictionary with 'status' and 'restarts' keys
Returns:
String: "Healthy", "Degraded", or "Unhealthy"
"""
if pod["status"] != "Running":
return "Unhealthy"
elif pod["restarts"] > 3:
return "Degraded"
else:
return "Healthy"
# Usage
pod = {"name": "nginx-1", "status": "Running", "restarts": 5}
health = check_pod_health(pod)
print(f"Pod {pod['name']} is {health}")
2.2 Error Handling (try/except) - CRITICAL!
Why it's important: Live interviews ALWAYS ask about error handling!
Basic try/except:
# Division by zero example
try:
result = 10 / 0
except ZeroDivisionError:
print("ERROR: Cannot divide by zero")
# File not found example
try:
with open("config.yaml", "r") as f:
content = f.read()
except FileNotFoundError:
print("ERROR: Config file not found")
# Generic exception (catch all)
try:
# Risky operation
result = some_operation()
except Exception as e:
print(f"ERROR: {str(e)}")
SRE example - HTTP request with error handling:
import requests
def check_url_health(url, timeout=5):
"""
Check if URL is reachable and healthy.
Args:
url: URL to check
timeout: Request timeout in seconds
Returns:
Dictionary with status and message
"""
try:
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
return {"status": "healthy", "message": "OK"}
else:
return {"status": "unhealthy", "message": f"HTTP {response.status_code}"}
except requests.exceptions.Timeout:
return {"status": "unhealthy", "message": "Timeout"}
except requests.exceptions.ConnectionError:
return {"status": "unhealthy", "message": "Connection failed"}
except Exception as e:
return {"status": "error", "message": str(e)}
# Usage
result = check_url_health("https://example.com")
print(f"Status: {result['status']}, Message: {result['message']}")
Try/except/else/finally (complete structure):
try:
# Risky operation
with open("log.txt", "r") as f:
lines = f.readlines()
except FileNotFoundError:
print("ERROR: Log file not found")
lines = []
else:
# Only runs if NO exception occurred
print(f"Successfully read {len(lines)} lines")
finally:
# ALWAYS runs (cleanup)
print("Log read attempt completed")
2.3 Practice Exercises (30 minutes)
Exercise 1: Temperature Converter (EASY)
Write a function that converts Celsius to Fahrenheit.
Formula: F = (C * 9/5) + 32
def celsius_to_fahrenheit(celsius):
# Your code here
pass
# Test
print(celsius_to_fahrenheit(0)) # Should print 32.0
print(celsius_to_fahrenheit(100)) # Should print 212.0
Solution:
Click for solution
Exercise 2: Safe Division (MEDIUM)
Write a function that divides safely (with error handling!).
If division by zero → return None and print error message.
def safe_divide(a, b):
# Your code here
pass
# Test
print(safe_divide(10, 2)) # Should print 5.0
print(safe_divide(10, 0)) # Should print error and return None
Solution:
Click for solution
Exercise 3: Pod Status Filter (MEDIUM)
Write a function that filters pods by status from a list.
def filter_pods_by_status(pods, target_status):
# Your code here
pass
# Test
pods = [
{"name": "nginx-1", "status": "Running"},
{"name": "nginx-2", "status": "Pending"},
{"name": "nginx-3", "status": "Running"},
]
running_pods = filter_pods_by_status(pods, "Running")
print(running_pods) # Should print list with nginx-1 and nginx-3
Solution:
Click for solution
def filter_pods_by_status(pods, target_status):
filtered = []
for pod in pods:
if pod["status"] == target_status:
filtered.append(pod)
return filtered
# Or list comprehension (advanced):
def filter_pods_by_status(pods, target_status):
return [pod for pod in pods if pod["status"] == target_status]
pods = [
{"name": "nginx-1", "status": "Running"},
{"name": "nginx-2", "status": "Pending"},
{"name": "nginx-3", "status": "Running"},
]
running_pods = filter_pods_by_status(pods, "Running")
print(running_pods)
Module 3: Lists, Dictionaries, Sets
Time Required: ~1 hour Goal: SRE data structures - pod lists, config dicts, unique values
3.1 List Operations
# List creation
pods = ["nginx-1", "nginx-2", "nginx-3"]
empty_list = []
# Adding
pods.append("nginx-4") # Add to end
pods.insert(0, "nginx-0") # Insert at index
# Removing
pods.remove("nginx-2") # Remove by value
last_pod = pods.pop() # Remove and return last
first_pod = pods.pop(0) # Remove by index
# Length and membership
count = len(pods) # Number of elements
if "nginx-1" in pods: # Check membership
print("Found nginx-1")
# Slicing (sub-list)
first_three = pods[0:3] # Index 0, 1, 2
last_two = pods[-2:] # Last two elements
# Sorting
pods.sort() # In-place sort
sorted_pods = sorted(pods) # New list (original unchanged)
SRE example - pod name extraction:
# Pod names list (typically from Kubernetes API)
pod_names = [
"nginx-deployment-7d5c8f9b6d-abc12",
"redis-statefulset-0",
"nginx-deployment-7d5c8f9b6d-xyz34",
]
# Filter only nginx pods
nginx_pods = []
for name in pod_names:
if "nginx" in name:
nginx_pods.append(name)
print(f"Nginx pods: {nginx_pods}")
# List comprehension (advanced, but common in interviews!)
nginx_pods = [name for name in pod_names if "nginx" in name]
3.2 Dictionary Operations
# Dictionary creation
pod = {
"name": "nginx-abc12",
"namespace": "production",
"status": "Running",
"restarts": 0
}
# Getting values
name = pod["name"] # If key missing → ERROR!
namespace = pod.get("namespace") # If key missing → None (safe)
namespace = pod.get("namespace", "default") # Default value
# Adding/modifying
pod["ip"] = "10.0.1.5" # New key-value
pod["restarts"] = 1 # Modification
# Deleting
del pod["ip"] # Delete key
removed_value = pod.pop("restarts", 0) # Pop with default
# Iteration
for key in pod: # Keys iteration
print(key)
for value in pod.values(): # Values iteration
print(value)
for key, value in pod.items(): # Key-value pairs
print(f"{key}: {value}")
# Membership
if "status" in pod:
print(f"Status: {pod['status']}")
SRE example - config parsing:
# Kubernetes-style config
config = {
"metadata": {
"name": "nginx-deployment",
"namespace": "production"
},
"spec": {
"replicas": 3,
"template": {
"spec": {
"containers": [
{"name": "nginx", "image": "nginx:1.21"}
]
}
}
}
}
# Nested access
namespace = config["metadata"]["namespace"]
replicas = config["spec"]["replicas"]
image = config["spec"]["template"]["spec"]["containers"][0]["image"]
print(f"Namespace: {namespace}, Replicas: {replicas}, Image: {image}")
# Safe nested access
replicas = config.get("spec", {}).get("replicas", 1)
3.3 Sets (Unique Values)
# Set creation
namespaces = {"production", "staging", "development"}
namespaces = set(["production", "staging", "production"]) # Duplicates removed
# Adding
namespaces.add("testing")
# Removing
namespaces.remove("staging") # If missing → ERROR!
namespaces.discard("staging") # If missing → OK (no error)
# Set operations
set1 = {"production", "staging", "development"}
set2 = {"production", "testing"}
union = set1 | set2 # Union: {'production', 'staging', 'development', 'testing'}
intersection = set1 & set2 # Intersection: {'production'}
difference = set1 - set2 # Difference: {'staging', 'development'}
SRE example - unique namespace extraction:
pods = [
{"name": "nginx-1", "namespace": "production"},
{"name": "redis-1", "namespace": "production"},
{"name": "mysql-1", "namespace": "staging"},
{"name": "nginx-2", "namespace": "production"},
]
# Extract unique namespaces
namespaces = set()
for pod in pods:
namespaces.add(pod["namespace"])
print(f"Unique namespaces: {namespaces}")
# List comprehension + set
namespaces = {pod["namespace"] for pod in pods}
3.4 Practice Exercises (30 minutes)
Exercise 1: Pod IP Collection (EASY)
Input:
pods = [
{"name": "nginx-1", "ip": "10.0.1.5"},
{"name": "nginx-2", "ip": "10.0.1.6"},
{"name": "nginx-3", "ip": "10.0.1.7"},
]
Task: Collect all IPs into a list.
Output: ["10.0.1.5", "10.0.1.6", "10.0.1.7"]
Solution:
Click for solution
Exercise 2: Namespace Summary (MEDIUM)
Input:
pods = [
{"name": "nginx-1", "namespace": "production"},
{"name": "redis-1", "namespace": "production"},
{"name": "mysql-1", "namespace": "staging"},
{"name": "nginx-2", "namespace": "production"},
{"name": "redis-2", "namespace": "staging"},
]
Task: Count how many pods per namespace.
Output (dictionary): {"production": 3, "staging": 2}
Solution:
Click for solution
pods = [
{"name": "nginx-1", "namespace": "production"},
{"name": "redis-1", "namespace": "production"},
{"name": "mysql-1", "namespace": "staging"},
{"name": "nginx-2", "namespace": "production"},
{"name": "redis-2", "namespace": "staging"},
]
namespace_counts = {}
for pod in pods:
ns = pod["namespace"]
if ns in namespace_counts:
namespace_counts[ns] += 1
else:
namespace_counts[ns] = 1
print(namespace_counts)
# Or using .get() (more elegant):
namespace_counts = {}
for pod in pods:
ns = pod["namespace"]
namespace_counts[ns] = namespace_counts.get(ns, 0) + 1
Exercise 3: Merge Pod Lists (HARD)
Input: Two pod lists, merge them but keep ONLY unique pod names!
list1 = [
{"name": "nginx-1", "status": "Running"},
{"name": "nginx-2", "status": "Running"},
]
list2 = [
{"name": "nginx-2", "status": "Running"},
{"name": "nginx-3", "status": "Pending"},
]
Output: 3 unique pods (nginx-1, nginx-2, nginx-3)
Solution:
Click for solution
list1 = [
{"name": "nginx-1", "status": "Running"},
{"name": "nginx-2", "status": "Running"},
]
list2 = [
{"name": "nginx-2", "status": "Running"},
{"name": "nginx-3", "status": "Pending"},
]
# Track seen names with set
seen_names = set()
merged = []
for pod in list1 + list2: # Concatenate lists
if pod["name"] not in seen_names:
merged.append(pod)
seen_names.add(pod["name"])
print(merged)
print(f"Total unique pods: {len(merged)}")
Module 4: File Handling (Log Parsing, Config Files)
Time Required: ~1 hour Goal: File reading/writing, log parsing (CRITICAL SRE skill!)
4.1 Reading Files
Basic file reading:
# Method 1: with statement (RECOMMENDED - auto close!)
with open("app.log", "r") as f:
content = f.read() # Entire file as string
print(content)
# Method 2: Read lines (list)
with open("app.log", "r") as f:
lines = f.readlines() # List, each line is an element
for line in lines:
print(line.strip()) # strip() removes newline
# Method 3: Iterate line by line (memory-efficient!)
with open("app.log", "r") as f:
for line in f:
print(line.strip())
Error handling (ALWAYS!):
try:
with open("app.log", "r") as f:
content = f.read()
except FileNotFoundError:
print("ERROR: Log file not found")
content = ""
except PermissionError:
print("ERROR: Permission denied")
content = ""
SRE example - error log parsing:
# Parse log file, count errors
def count_errors_in_log(log_file):
"""
Count lines containing 'ERROR' in log file.
Args:
log_file: Path to log file
Returns:
Integer count of error lines
"""
try:
error_count = 0
with open(log_file, "r") as f:
for line in f:
if "ERROR" in line:
error_count += 1
return error_count
except FileNotFoundError:
print(f"ERROR: {log_file} not found")
return 0
# Usage
count = count_errors_in_log("app.log")
print(f"Total errors: {count}")
4.2 Writing Files
# Write to file (OVERWRITE!)
with open("output.txt", "w") as f:
f.write("First line\n")
f.write("Second line\n")
# Append to file
with open("output.txt", "a") as f:
f.write("Third line\n")
# Write list of lines
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as f:
f.writelines(lines)
SRE example - error report generation:
def generate_error_report(log_file, output_file):
"""
Extract ERROR lines from log and write to report file.
Args:
log_file: Input log file path
output_file: Output report file path
"""
try:
errors = []
with open(log_file, "r") as f:
for line in f:
if "ERROR" in line:
errors.append(line)
with open(output_file, "w") as f:
f.write(f"Error Report - Total Errors: {len(errors)}\n")
f.write("=" * 50 + "\n")
for error in errors:
f.write(error)
print(f"Report generated: {output_file}")
except FileNotFoundError:
print(f"ERROR: {log_file} not found")
except Exception as e:
print(f"ERROR: {str(e)}")
# Usage
generate_error_report("app.log", "error_report.txt")
4.3 Advanced - Log Pattern Extraction
# Extract specific patterns (e.g., timestamps, error codes)
import re
def extract_error_codes(log_file):
"""
Extract error codes like [E001], [E002] from log.
Args:
log_file: Path to log file
Returns:
List of unique error codes
"""
error_codes = set()
pattern = r'\[E\d+\]' # Matches [E001], [E123], etc.
try:
with open(log_file, "r") as f:
for line in f:
matches = re.findall(pattern, line)
for match in matches:
error_codes.add(match)
return list(error_codes)
except FileNotFoundError:
print(f"ERROR: {log_file} not found")
return []
# Usage
codes = extract_error_codes("app.log")
print(f"Found error codes: {codes}")
4.4 Practice Exercises (30 minutes)
Exercise 1: Line Counter (EASY)
Write a function that counts the number of lines in a file.
def count_lines(file_path):
# Your code here
pass
# Test (create test file first!)
with open("test.txt", "w") as f:
f.write("Line 1\nLine 2\nLine 3\n")
print(count_lines("test.txt")) # Should print 3
Solution:
Click for solution
Exercise 2: Warning Filter (MEDIUM)
Write a function that filters lines containing "WARNING" from a log file
and returns them in a list.
def extract_warnings(log_file):
# Your code here
pass
# Test file:
with open("app.log", "w") as f:
f.write("INFO: Application started\n")
f.write("WARNING: Low disk space\n")
f.write("ERROR: Connection failed\n")
f.write("WARNING: High CPU usage\n")
warnings = extract_warnings("app.log")
print(warnings) # Should print 2 warning lines
Solution:
Click for solution
def extract_warnings(log_file):
warnings = []
try:
with open(log_file, "r") as f:
for line in f:
if "WARNING" in line:
warnings.append(line.strip())
return warnings
except FileNotFoundError:
print(f"ERROR: {log_file} not found")
return []
# Test
with open("app.log", "w") as f:
f.write("INFO: Application started\n")
f.write("WARNING: Low disk space\n")
f.write("ERROR: Connection failed\n")
f.write("WARNING: High CPU usage\n")
warnings = extract_warnings("app.log")
print(warnings)
Exercise 3: Log Summary Report (HARD)
Write a function that analyzes a log file and creates a summary:
- How many INFO lines
- How many WARNING lines
- How many ERROR lines
- Write the result to a "summary.txt" file
def generate_log_summary(log_file, output_file):
# Your code here
pass
# Test
with open("app.log", "w") as f:
f.write("INFO: Application started\n")
f.write("WARNING: Low disk space\n")
f.write("ERROR: Connection failed\n")
f.write("INFO: Request processed\n")
f.write("WARNING: High CPU usage\n")
f.write("ERROR: Database timeout\n")
generate_log_summary("app.log", "summary.txt")
# Check summary.txt for output
Solution:
Click for solution
def generate_log_summary(log_file, output_file):
counts = {"INFO": 0, "WARNING": 0, "ERROR": 0}
try:
# Count log levels
with open(log_file, "r") as f:
for line in f:
if "INFO" in line:
counts["INFO"] += 1
elif "WARNING" in line:
counts["WARNING"] += 1
elif "ERROR" in line:
counts["ERROR"] += 1
# Write summary
with open(output_file, "w") as f:
f.write("Log Summary Report\n")
f.write("=" * 30 + "\n")
for level, count in counts.items():
f.write(f"{level}: {count}\n")
print(f"Summary generated: {output_file}")
except FileNotFoundError:
print(f"ERROR: {log_file} not found")
except Exception as e:
print(f"ERROR: {str(e)}")
# Test
with open("app.log", "w") as f:
f.write("INFO: Application started\n")
f.write("WARNING: Low disk space\n")
f.write("ERROR: Connection failed\n")
f.write("INFO: Request processed\n")
f.write("WARNING: High CPU usage\n")
f.write("ERROR: Database timeout\n")
generate_log_summary("app.log", "summary.txt")
# Read result
with open("summary.txt", "r") as f:
print(f.read())
Module 5: HTTP Requests (Health Checks, API Calls)
Time Required: ~1 hour Goal: Using requests library (CRITICAL SRE interview skill!)
5.1 Requests Library Basics
Installation:
Basic GET request:
import requests
# Simple GET
response = requests.get("https://api.github.com")
print(response.status_code) # 200, 404, 500, etc.
print(response.text) # Response body (string)
# GET with timeout (ALWAYS use timeout!)
response = requests.get("https://api.github.com", timeout=5)
# JSON response parsing
response = requests.get("https://api.github.com/users/octocat")
data = response.json() # Parse JSON to dict
print(data["login"]) # octocat
Error handling (CRITICAL!):
import requests
def safe_http_get(url, timeout=5):
"""
Safely perform HTTP GET with error handling.
Args:
url: URL to fetch
timeout: Request timeout in seconds
Returns:
Dictionary with status_code and content
"""
try:
response = requests.get(url, timeout=timeout)
return {
"success": True,
"status_code": response.status_code,
"content": response.text
}
except requests.exceptions.Timeout:
return {
"success": False,
"error": "Request timeout"
}
except requests.exceptions.ConnectionError:
return {
"success": False,
"error": "Connection failed"
}
except Exception as e:
return {
"success": False,
"error": str(e)
}
# Usage
result = safe_http_get("https://example.com")
if result["success"]:
print(f"Status: {result['status_code']}")
else:
print(f"Error: {result['error']}")
5.2 SRE Health Check Function
Classic interview question: Check health of multiple URLs
import requests
def check_urls_health(urls, timeout=5):
"""
Check health status of multiple URLs.
Args:
urls: List of URLs to check
timeout: Request timeout in seconds
Returns:
Dictionary: {url: {"status": "healthy/unhealthy", "code": 200}}
"""
results = {}
for url in urls:
try:
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
status = "healthy"
else:
status = "unhealthy"
results[url] = {
"status": status,
"code": response.status_code
}
except requests.exceptions.Timeout:
results[url] = {
"status": "unhealthy",
"error": "timeout"
}
except requests.exceptions.ConnectionError:
results[url] = {
"status": "unhealthy",
"error": "connection_failed"
}
except Exception as e:
results[url] = {
"status": "error",
"error": str(e)
}
return results
# Usage
urls = [
"https://google.com",
"https://github.com",
"https://invalid-domain-12345.com"
]
health_results = check_urls_health(urls)
for url, result in health_results.items():
print(f"{url}: {result['status']}")
5.3 POST Requests and Headers
import requests
# POST with JSON body
data = {
"username": "admin",
"password": "secret"
}
response = requests.post(
"https://api.example.com/login",
json=data,
timeout=5
)
# Custom headers
headers = {
"Authorization": "Bearer token123",
"Content-Type": "application/json"
}
response = requests.get(
"https://api.example.com/users",
headers=headers,
timeout=5
)
5.4 Practice Exercises (30 minutes)
Exercise 1: URL Checker (EASY)
Write a function that checks if a URL is reachable (status code 200).
Return True if reachable, False if not.
def is_url_reachable(url, timeout=5):
# Your code here
pass
# Test
print(is_url_reachable("https://google.com")) # Should be True
print(is_url_reachable("https://invalid-url-12345.com")) # Should be False
Solution:
Click for solution
Exercise 2: Health Check Summary (MEDIUM)
Write a function that checks a list of URLs and provides a summary:
- How many healthy (200 status)
- How many unhealthy (not 200, or error)
def summarize_health_check(urls, timeout=5):
# Your code here
# Return: {"healthy": count, "unhealthy": count}
pass
# Test
urls = [
"https://google.com",
"https://github.com",
"https://invalid-domain.com"
]
print(summarize_health_check(urls))
Solution:
Click for solution
import requests
def summarize_health_check(urls, timeout=5):
healthy = 0
unhealthy = 0
for url in urls:
try:
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
healthy += 1
else:
unhealthy += 1
except:
unhealthy += 1
return {"healthy": healthy, "unhealthy": unhealthy}
# Test
urls = [
"https://google.com",
"https://github.com",
"https://invalid-domain.com"
]
print(summarize_health_check(urls))
Exercise 3: Service Monitor (HARD)
Write a function that:
1. Checks a list of URLs
2. Prints the result to console ("URL: status")
3. Writes a full report to "health_report.txt" file
def monitor_services(urls, output_file, timeout=5):
# Your code here
pass
# Test
urls = [
"https://google.com",
"https://github.com",
"https://stackoverflow.com"
]
monitor_services(urls, "health_report.txt")
# Check console output and health_report.txt file
Solution:
Click for solution
import requests
def monitor_services(urls, output_file, timeout=5):
results = []
# Check all URLs
for url in urls:
try:
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
status = "healthy"
else:
status = f"unhealthy (HTTP {response.status_code})"
except requests.exceptions.Timeout:
status = "unhealthy (timeout)"
except requests.exceptions.ConnectionError:
status = "unhealthy (connection failed)"
except Exception as e:
status = f"error ({str(e)})"
# Print to console
print(f"{url}: {status}")
# Store for file output
results.append(f"{url}: {status}\n")
# Write to file
try:
with open(output_file, "w") as f:
f.write("Service Health Report\n")
f.write("=" * 50 + "\n")
for line in results:
f.write(line)
print(f"\nReport saved to {output_file}")
except Exception as e:
print(f"ERROR writing report: {str(e)}")
# Test
urls = [
"https://google.com",
"https://github.com",
"https://stackoverflow.com"
]
monitor_services(urls, "health_report.txt")
Modules 6-12: Additional Modules (Continued)
IMPORTANT: This learning plan is LARGE (~35-40K words in full form)!
Next modules (brief summary):
Module 6: Kubernetes Python Client
- Installing
kuberneteslibrary - Listing pods, querying status
- Namespace enumeration
- Error handling for K8s API calls
Module 7: JSON/YAML Parsing
jsonmodule (built-in)yamllibrary (PyYAML)- Config file parsing
- Kubernetes manifest parsing
Module 8: Command Line Arguments
argparsemodule- Script parameterization
- Environment variables (
os.environ)
Module 9: Regular Expressions
remodule- Pattern matching
- Log parsing patterns
- Error code extraction
Module 10: String Manipulation
.split(),.join(),.strip().replace(),.format()- String slicing
- Case conversion
Module 11: Timed Practice Exercises (30 min challenges)
- 10 interview-style tasks
- Timer: 30 min / task
- Progressive difficulty
- Realistic scenarios
Module 12: Mock Interview Preparation
- Full interview simulation (90 min)
- Claude as interviewer
- Live coding setup (VSCode screen share)
- Feedback and improvements
Quick Win: 1 Week Practice Tasks
If you only have 1 week (5-7 hours total):
Day 1-2: Modules 1-3 (basics, functions, data structures) Day 3-4: Modules 4-5 (file ops, HTTP requests) Day 5-7: Practice exercises (timed challenges)
This is MINIMAL preparation, but provides a baseline!
Next Steps
WHAT DO YOU WANT NOW?
Option 1: Continue the full learning plan (Modules 6-12 in detail) - ~25-30K words remaining - Complete interview prep (2-3 weeks) - All SRE Python skills covered
Option 2: Quick Reference cheat sheet first - 1-2 pages, quick lookup - Syntax patterns - Interview pitfalls - Then full learning plan later
Option 3: Start practice NOW (based on Modules 1-5) - Complete all exercises - Come back with questions - Continue Modules 6-12 later
Tell me which direction!