Lab 1 โ Build a cloud cost calculator
Objectiveโ
By the end of this lab you will have a runnable Python module, cloudcost.py,
that takes a workload's object-storage GB, egress GB, and compute-hours together
with per-unit prices, computes its monthly bill after free-tier allowances, and
flags every driver whose usage would leave the free tier. It uses only the Python
standard library and runs entirely on your machine โ no cloud account, no
network, no card on file, and nothing billable to create.
Skills exercised:
- Turning the three cost drivers from Lesson 3 into a reproducible calculation
- Applying free-tier allowances so you bill only for usage above the free line
- Detecting when a configuration spills out of the free tier, per driver
- Assembling the pieces into a report and a self-checking validation
Prerequisites and setupโ
Prerequisites: the three lessons in this module โ Cloud building blocks for data, The managed data-services landscape, and Cost and security fundamentals. The last one introduces the three cost drivers and the free-tier posture this lab makes executable.
Setup: you need Python 3.10 or newer. There are no packages to install โ everything uses the standard library. Verify your version and create a working folder.
- macOS / Linux
- Windows (PowerShell)
python3 --version
mkdir cd101-cost-lab && cd cd101-cost-lab
python --version
mkdir cd101-cost-lab; cd cd101-cost-lab
Expected output from the version command is a line like Python 3.11.6. If the
command is not found, install Python from python.org before continuing. In the
steps below, use python3 on macOS/Linux and python on Windows.
Every step edits the one file cloudcost.py in this folder. If you close your
terminal and come back, re-run cd cd101-cost-lab to return to it; the file is
still there and you can continue from the step you were on.
Step 1 โ Define the prices and free-tier allowancesโ
Goal: capture the per-unit prices and the monthly free-tier allowances as data, so every later calculation reads from one place.
Create cloudcost.py with two dictionaries:
# Per-unit prices (illustrative; real rates vary by provider and region).
PRICES = {
"storage_per_gb": 0.023, # dollars per GB stored per month
"egress_per_gb": 0.09, # dollars per GB leaving a boundary
"compute_per_hour": 0.0116, # dollars per compute-hour
}
# Illustrative monthly free-tier allowances. Usage above these is billed.
FREE_TIER = {
"storage_gb": 5.0,
"egress_gb": 1.0,
"compute_hours": 750.0,
}
Checkpoint: read one price and one allowance back.
python3 -c "import cloudcost as c; print(c.PRICES['storage_per_gb'], c.FREE_TIER['storage_gb'])"
You should see 0.023 5.0. If you get a KeyError, a dictionary key is
misspelled; if you get a ModuleNotFoundError, run the command from inside the
cd101-cost-lab folder where cloudcost.py lives.
Step 2 โ Bill only for usage above the free lineโ
Goal: compute the billable units for any driver โ the usage above its free allowance, and never a negative number.
Add this function to cloudcost.py:
def billable_units(used, free):
"""Units you actually pay for: usage above the free allowance, never below 0."""
return max(0.0, used - free)
Checkpoint: check a driver that exceeds its allowance and one that does not.
python3 -c "import cloudcost as c; print(c.billable_units(60, 5), c.billable_units(3, 5))"
You should see 55 0.0. The 55 is the billable storage above a 5 GB free
allowance; the 0.0 shows that 3 GB of usage under a 5 GB allowance bills
nothing. If the second value is -2, the max(0.0, ...) guard is missing.
Step 3 โ Compute the per-driver cost and the monthly billโ
Goal: apply prices to billable units for each driver, then sum them into a monthly total. A workload is a dictionary with three keys.
Add these two functions:
def cost_breakdown(usage):
"""Return dollar cost per driver after applying free-tier allowances."""
storage = billable_units(usage["storage_gb"], FREE_TIER["storage_gb"])
egress = billable_units(usage["egress_gb"], FREE_TIER["egress_gb"])
compute = billable_units(usage["compute_hours"], FREE_TIER["compute_hours"])
return {
"storage": storage * PRICES["storage_per_gb"],
"egress": egress * PRICES["egress_per_gb"],
"compute": compute * PRICES["compute_per_hour"],
}
def monthly_bill(usage):
"""Total monthly cost across all three drivers."""
return sum(cost_breakdown(usage).values())
Checkpoint: price a workload of 60 GB stored, 12 GB egress, 900 compute-hours.
python3 -c "import cloudcost as c; w={'storage_gb':60.0,'egress_gb':12.0,'compute_hours':900.0}; b=c.cost_breakdown(w); print(round(b['storage'],3), round(b['egress'],3), round(b['compute'],3)); print(round(c.monthly_bill(w),3))"
You should see 1.265 0.99 1.74 on the first line and 3.995 on the second โ
55 billable GB of storage, 11 billable GB of egress, and 150 billable
compute-hours, summing to just under four dollars a month. If storage shows
1.38, the free allowance is not being subtracted; the billable units, not the
raw usage, must be priced.
Step 4 โ Flag when a config leaves the free tierโ
Goal: report which drivers spill past their free allowance, and a single verdict for the whole workload.
Add these two functions:
def free_tier_flags(usage):
"""List the drivers whose usage exceeds the free allowance."""
flags = []
for driver, allowance in FREE_TIER.items():
if usage[driver] > allowance:
flags.append(driver)
return flags
def leaves_free_tier(usage):
"""True when any driver spills past its free allowance."""
return len(free_tier_flags(usage)) > 0
Checkpoint: test a workload that exceeds every allowance against one that stays under all of them.
python3 -c "import cloudcost as c; big={'storage_gb':60.0,'egress_gb':12.0,'compute_hours':900.0}; small={'storage_gb':3.0,'egress_gb':0.5,'compute_hours':100.0}; print(c.free_tier_flags(big), c.leaves_free_tier(big)); print(c.free_tier_flags(small), c.leaves_free_tier(small))"
You should see the big workload flag all three drivers with True, and the small
workload flag none with False:
['storage_gb', 'egress_gb', 'compute_hours'] True
[] False
If the small workload reports flags, the comparison is using >= instead of >
โ usage exactly at the allowance still counts as within the free tier.
Step 5 โ Assemble the report and run itโ
Goal: combine the breakdown, the total, and the free-tier verdict into a readable report, and make the module runnable.
Add this function and the main block to finish cloudcost.py:
def report(usage):
"""Human-readable summary: per-driver cost, total, and free-tier verdict."""
breakdown = cost_breakdown(usage)
lines = []
for driver in ("storage", "egress", "compute"):
lines.append(f"{driver:<8} ${breakdown[driver]:.2f}")
lines.append(f"{'TOTAL':<8} ${monthly_bill(usage):.2f} / month")
if leaves_free_tier(usage):
drivers = ", ".join(free_tier_flags(usage))
lines.append(f"FREE TIER: exceeded on {drivers}")
else:
lines.append("FREE TIER: within allowances")
return "\n".join(lines)
if __name__ == "__main__":
workload = {"storage_gb": 60.0, "egress_gb": 12.0, "compute_hours": 900.0}
print(report(workload))
Checkpoint: run the whole module.
python3 cloudcost.py
You should see the full report, with the total formatted to two decimals and all three drivers flagged:
storage $1.26
egress $0.99
compute $1.74
TOTAL $3.99 / month
FREE TIER: exceeded on storage_gb, egress_gb, compute_hours
The TOTAL line shows $3.99 because the true total of 3.995 rounds to two
decimals for display. If you see FREE TIER: within allowances instead, the
verdict is reading the wrong workload โ confirm the main block passes workload.
Validationโ
Verify the whole build against the objective: a correct monthly bill and correct free-tier flags for the same workload, checked automatically. Run this validation one-liner, which reprices the workload and confirms both the total and the flags:
python3 -c "import cloudcost as c; w={'storage_gb':60.0,'egress_gb':12.0,'compute_hours':900.0}; s={'storage_gb':3.0,'egress_gb':0.5,'compute_hours':100.0}; ok = abs(c.monthly_bill(w)-3.995)<0.01 and c.free_tier_flags(w)==['storage_gb','egress_gb','compute_hours'] and not c.leaves_free_tier(s); print('PASSED โ cost calculator verified' if ok else 'FAILED โ check the bill and free-tier flags')"
Checkpoint: the command prints PASSED โ cost calculator verified. If it
prints FAILED, the bill is off by more than a cent or the flags are wrong:
re-run the Step 3 checkpoint (the total must be 3.995) and the Step 4
checkpoint (the big workload must flag all three drivers, the small workload
none).
Teardownโ
Nothing is billable โ this lab runs entirely on your machine with no cloud
account. Keep the cd101-cost-lab folder if you want cloudcost.py as a
reference for sizing workloads later; otherwise remove it with
rm -rf cd101-cost-lab (macOS/Linux) or Remove-Item -Recurse cd101-cost-lab
(Windows PowerShell).
Troubleshootingโ
| Symptom | Likely cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'cloudcost' | Running from the wrong folder | cd into cd101-cost-lab, where cloudcost.py lives |
KeyError: 'storage_per_gb' | A price or allowance key is misspelled | Match the keys in Step 1 exactly, including underscores |
Step 2 prints -2 for the under-allowance case | Missing the max(0.0, ...) guard | Return max(0.0, used - free) so billable units never go negative |
Storage cost is 1.38 in Step 3 | Pricing raw usage, not billable units | Price billable_units(...), not usage["storage_gb"] directly |
| Small workload reports free-tier flags in Step 4 | Comparison uses >= instead of > | Usage exactly at the allowance is within the tier; compare with > |
Validation prints FAILED | Wrong total or wrong flags | Re-run the Step 3 checkpoint (3.995) and the Step 4 checkpoint |