Skip to main content

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.

python3 --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.

note

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โ€‹

SymptomLikely causeFix
ModuleNotFoundError: No module named 'cloudcost'Running from the wrong foldercd into cd101-cost-lab, where cloudcost.py lives
KeyError: 'storage_per_gb'A price or allowance key is misspelledMatch the keys in Step 1 exactly, including underscores
Step 2 prints -2 for the under-allowance caseMissing the max(0.0, ...) guardReturn max(0.0, used - free) so billable units never go negative
Storage cost is 1.38 in Step 3Pricing raw usage, not billable unitsPrice billable_units(...), not usage["storage_gb"] directly
Small workload reports free-tier flags in Step 4Comparison uses >= instead of >Usage exactly at the allowance is within the tier; compare with >
Validation prints FAILEDWrong total or wrong flagsRe-run the Step 3 checkpoint (3.995) and the Step 4 checkpoint