-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
80 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| #!/bin/env python | ||
|
|
||
| import boto3 | ||
| import csv | ||
| import datetime | ||
| from botocore.exceptions import ClientError | ||
|
|
||
| def get_monthly_range(target_date=None): | ||
| """Calculates the start of the current month and the start of the next month.""" | ||
| if target_date is None: | ||
| target_date = datetime.date.today() | ||
|
|
||
| # Start of target month | ||
| start = target_date.replace(day=1) | ||
|
|
||
| # Start of next month (End date is exclusive in AWS API) | ||
| if start.month == 12: | ||
| end = start.replace(year=start.year + 1, month=1) | ||
| else: | ||
| end = start.replace(month=start.month + 1) | ||
|
|
||
| return start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d') | ||
|
|
||
| def fetch_aws_costs(): | ||
| client = boto3.client('ce', region_name='us-east-1') # CE API is us-east-1 only | ||
| start_date, end_date = get_monthly_range() | ||
|
|
||
| print(f"Fetching costs from {start_date} to {end_date}...") | ||
|
|
||
| try: | ||
| response = client.get_cost_and_usage( | ||
| TimePeriod={'Start': start_date, 'End': end_date}, | ||
| Granularity='MONTHLY', | ||
| Metrics=['BlendedCost', 'UnblendedCost', 'AmortizedCost', 'UsageQuantity'], | ||
| GroupBy=[{'Type': 'DIMENSION', 'Key': 'SERVICE'}] | ||
| ) | ||
|
|
||
| rows = [] | ||
| grand_totals = {'blended': 0.0, 'unblended': 0.0, 'amortized': 0.0} | ||
|
|
||
| for group in response['ResultsByTime'][0]['Groups']: | ||
| service_name = group['Keys'][0] | ||
| metrics = group['Metrics'] | ||
|
|
||
| # Extracting values | ||
| usage_qty = float(metrics['UsageQuantity']['Amount']) | ||
| usage_unit = metrics['UsageQuantity']['Unit'] | ||
| blended = float(metrics['BlendedCost']['Amount']) | ||
| unblended = float(metrics['UnblendedCost']['Amount']) | ||
| amortized = float(metrics['AmortizedCost']['Amount']) | ||
|
|
||
| rows.append([service_name, f"{usage_qty:.2f}", usage_unit, f"{blended:.2f}", f"{unblended:.2f}", f"{amortized:.2f}"]) | ||
|
|
||
| # Update Grand Totals | ||
| grand_totals['blended'] += blended | ||
| grand_totals['unblended'] += unblended | ||
| grand_totals['amortized'] += amortized | ||
|
|
||
| # Sorting by cost (Amortized/Total) descending | ||
| rows.sort(key=lambda x: float(x[5]), reverse=True) | ||
|
|
||
| # Write to CSV | ||
| filename = f"aws_cost_{start_date[:7]}.csv" | ||
| with open(filename, 'w', newline='') as f: | ||
| writer = csv.writer(f) | ||
| writer.writerow(['Service', 'Usage Quantity', 'Unit', 'Blended Cost', 'Unblended Cost', 'Total (Amortized)']) | ||
| writer.writerows(rows) | ||
| # Grand Total Line | ||
| writer.writerow(['GRAND TOTAL', 'NA', 'NA', | ||
| f"{grand_totals['blended']:.2f}", | ||
| f"{grand_totals['unblended']:.2f}", | ||
| f"{grand_totals['amortized']:.2f}"]) | ||
|
|
||
| print(f"✅ Success! Report saved as {filename}") | ||
|
|
||
| except ClientError as e: | ||
| print(f"❌ Error: {e}") | ||
|
|
||
| if __name__ == "__main__": | ||
| fetch_aws_costs() |