From ed54be40e9b6d2d17c6ee833c27e8348961517b2 Mon Sep 17 00:00:00 2001 From: badra001 Date: Fri, 30 Jan 2026 09:18:30 -0500 Subject: [PATCH] add --profile --- .../python-tools/billing/aws_monthly_cost.py | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/local-app/python-tools/billing/aws_monthly_cost.py b/local-app/python-tools/billing/aws_monthly_cost.py index 6d80a32a..0a344f38 100755 --- a/local-app/python-tools/billing/aws_monthly_cost.py +++ b/local-app/python-tools/billing/aws_monthly_cost.py @@ -3,17 +3,18 @@ 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: @@ -21,13 +22,20 @@ def get_monthly_range(target_date=None): 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', @@ -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']) @@ -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)