Skip to content

Commit

Permalink
add --profile
Browse files Browse the repository at this point in the history
  • Loading branch information
badra001 committed Jan 30, 2026
1 parent eee1435 commit ed54be4
Showing 1 changed file with 33 additions and 19 deletions.
52 changes: 33 additions & 19 deletions local-app/python-tools/billing/aws_monthly_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,39 @@
import boto3
import csv
import datetime
from botocore.exceptions import ClientError
import argparse
import sys
from botocore.exceptions import ClientError, ProfileNotFound

__version__ = "1.0.1"

def get_monthly_range(target_date=None):
"""Calculates the start of the current month and the start of the next month."""
"""Calculates start of current month and start of next month (exclusive)."""
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}...")

def fetch_aws_costs(profile, region):
try:
# Initialize session with user parameters
session = boto3.Session(profile_name=profile, region_name=region)

# Cost Explorer API is globally managed via us-east-1 endpoint
client = session.client('ce', region_name='us-east-1')

start_date, end_date = get_monthly_range()
print(f"--- AWS Monthly Cost Summary v{__version__} ---")
print(f"Profile: {profile or 'default'}")
print(f"Region: {region}")
print(f"Period: {start_date} to {end_date}\n")

response = client.get_cost_and_usage(
TimePeriod={'Start': start_date, 'End': end_date},
Granularity='MONTHLY',
Expand All @@ -42,7 +50,6 @@ def fetch_aws_costs():
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'])
Expand All @@ -51,30 +58,37 @@ def fetch_aws_costs():

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
# Sort by Total Cost 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}")
print(f"✅ Success! Report saved as: {filename}")

except ProfileNotFound:
print(f"❌ Error: The profile '{profile}' was not found in your AWS config.")
except ClientError as e:
print(f"❌ Error: {e}")
print(f"❌ AWS Error: {e}")
except Exception as e:
print(f"❌ Unexpected Error: {e}")

if __name__ == "__main__":
fetch_aws_costs()
parser = argparse.ArgumentParser(description="Generate AWS Monthly Cost CSV")
parser.add_argument('--profile', type=str, help="AWS CLI profile to use", default=None)
parser.add_argument('--region', type=str, help="AWS region (default: us-east-1)", default='us-east-1')
parser.add_argument('--version', action='version', version=f'%(prog)s {__version__}')

args = parser.parse_args()
fetch_aws_costs(args.profile, args.region)

0 comments on commit ed54be4

Please sign in to comment.