From b38a041f1e0d024b06a30733d6feca79651b04a6 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Sun, 29 Aug 2021 14:03:31 -0700 Subject: [PATCH] Classify costs --- .gitignore | 3 ++- financials/2021-07/breakdown.txt | 23 +++++++++++++++++++++ financials/2021-08/breakdown.txt | 18 ++++++++++++++++ financials/fin.py | 35 ++++++++++++++++++++++---------- 4 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 financials/2021-07/breakdown.txt create mode 100644 financials/2021-08/breakdown.txt diff --git a/.gitignore b/.gitignore index 40f72a3..9bc9590 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ build node_modules out sentinel.h -financials/????-?? +financials/????-??/* +!financials/????-??/breakdown.txt diff --git a/financials/2021-07/breakdown.txt b/financials/2021-07/breakdown.txt new file mode 100644 index 0000000..bffef79 --- /dev/null +++ b/financials/2021-07/breakdown.txt @@ -0,0 +1,23 @@ +Riju :: $175.43 + CloudWatch :: $34.80 + EC2 :: $112.98 + Data Transfer :: $0.68 + EBS Snapshot :: $11.42 + EBS Volume :: $46.40 + EBS Volume :: $46.40 + gp2 :: $11.61 + gp3 :: $34.78 + Instance :: $54.48 + t2.small :: $0.04 + t3 :: $0.08 + t3.2xlarge :: $29.80 + t3.medium :: $14.77 + t3.small :: $9.78 + ECR :: $7.31 + Data Transfer :: $3.29 + Storage :: $4.02 + ELB :: $20.05 + Data Transfer :: $0.31 + LCUs :: $0.06 + Load Balancer :: $19.68 + S3 :: $0.29 diff --git a/financials/2021-08/breakdown.txt b/financials/2021-08/breakdown.txt new file mode 100644 index 0000000..6c62765 --- /dev/null +++ b/financials/2021-08/breakdown.txt @@ -0,0 +1,18 @@ +Riju :: $52.21 + EC2 :: $27.85 + Data Transfer :: $0.03 + EBS Snapshot :: $1.51 + EBS Volume :: $15.87 + EBS Volume :: $15.87 + gp2 :: $0.60 + gp3 :: $15.27 + Instance :: $10.44 + t3.small :: $10.44 + ECR :: $6.00 + Data Transfer :: $1.38 + Storage :: $4.62 + ELB :: $18.25 + Data Transfer :: $0.17 + LCUs :: $0.06 + Load Balancer :: $18.02 + S3 :: $0.12 diff --git a/financials/fin.py b/financials/fin.py index cc368aa..917f58a 100755 --- a/financials/fin.py +++ b/financials/fin.py @@ -184,6 +184,12 @@ def classify_line_item(item, billing_month=None, full=False): category = ["EC2"] if "ElasticIP:IdleAddress" in usage_type: category.append("EIP") + # Apparently tags on EIPs are ignored for billing + # purposes, so we just have to know what we were using + # them for. (Leaving them uncategorized for 2021-07 + # though.) + if billing_month != "2021-07": + project = "Corona" elif "EBS:VolumeUsage" in usage_type: category.append("EBS Volume") category.extend(["EBS Volume", re.sub(r"^.+\.", "", usage_type)]) @@ -252,28 +258,29 @@ def uncategorized_last(key): return (key == "Uncategorized", key) -def print_taxonomy(taxonomy, indent=""): +def print_taxonomy(taxonomy, indent="", file=sys.stdout): cost = taxonomy["cost"] - if not indent: - print(f"(total) :: ${cost:.2f}") categories = taxonomy.get("categories", {}) for category in sorted(categories, key=uncategorized_last): subtaxonomy = categories[category] cost = subtaxonomy["cost"] if cost < 0.01: continue - print(f"{indent}{category} :: ${cost:.2f}") - print_taxonomy(subtaxonomy, indent=indent + " ") + print(f"{indent}{category} :: ${cost:.2f}", file=file) + print_taxonomy(subtaxonomy, indent=indent + " ", file=file) def classify_costs(csv_path, **kwargs): - items = [item for item in read_csv(csv_path) if item["lineItem/UnblendedCost"]] - for item in items: - item["lineItem/UnblendedCost"] = float(item["lineItem/UnblendedCost"]) + all_items = [item for item in read_csv(csv_path)] + items = [] + for item in all_items: + cost = item["lineItem/UnblendedCost"] + if cost and float(cost): + items.append({**item, "lineItem/UnblendedCost": float(cost)}) taxonomy = {} for item in embed_taxes(items): - add_to_taxonomy(taxonomy, classify_line_item(item, **kwargs), item) - print_taxonomy(taxonomy) + add_to_taxonomy(taxonomy, ["AWS", *classify_line_item(item, **kwargs)], item) + return taxonomy def main(): @@ -284,7 +291,13 @@ def main(): year, month = map(int, args.date.split("-")) billing_month = f"{year}-{month:02d}" csv_path = get_csv(year, month, force_download=args.force_download) - classify_costs(csv_path, billing_month=billing_month) + taxonomy = classify_costs(csv_path, billing_month=billing_month) + print_taxonomy(taxonomy) + riju_taxonomy = taxonomy["categories"]["AWS"] + riju_taxonomy["categories"] = {"Riju": riju_taxonomy["categories"]["Riju"]} + target_dir = ROOT / f"{year}-{month:02d}" + with open(target_dir / "breakdown.txt", "w") as f: + print_taxonomy(riju_taxonomy, file=f) if __name__ == "__main__":