Commit 9c50513b authored by Afraz Ahmadzadeh's avatar Afraz Ahmadzadeh

Merge branch 'using_costexplorerapi' into 'master'

Using Cost Explorer API in boto3 for billing command

See merge request !10
parents c1af1f2c 449ea231
......@@ -10,7 +10,9 @@ At the moment it only does three things; blue/green deploys for plugging into Gi
- [EBS Volumes](#ebs)
4. [RDS](#rds)
- [Copy](#copy)
5. [Contributing](#contributing)
5. [Reporting](#reporting)
- [Billing](#billing)
6. [Contributing](#contributing)
## Installation
......@@ -123,6 +125,27 @@ Copy encrypted RDS instances between accounts:
`--region` is optional because it will default to the environment variable `AWS_DEFAULT_REGION`.
### Billing
Get a view of your daily AWS estimated bill for the x number of days. Defaults to today's estimated bill.
akinaka.py reporting --region us-east-1 \
--role-arn arn:aws:iam::1234567890:role/billing_assumerole \
bill-estimates --from-days-ago 1
Example output:
Today's estimated bill
+------------+-----------+
| Date | Total |
|------------+-----------|
| 2019-03-14 | USD 13.93 |
+------------+-----------+
You can specify any integer value to the `--days-ago` flag. It's optional. Default value set for today (current day).
You can specify any region to the `--region` flag.
## Contributing
Modules can be added easily by simply dropping them in and adding an entry into `akinaka.py` to include them, and some `click` code in their `__init__` (or elsewhere that's loaded, but this is the cleanest way).
......
......@@ -5,7 +5,7 @@ from time import gmtime, strftime
from akinaka_update.commands import update as update_commands
from akinaka_cleanup.commands import cleanup as cleanup_commands
from akinaka_rds.commands import copy as copy_commands
from akinaka_reporting.commands import billing as billing_commands
from akinaka_reporting.commands import reporting as reporting_commands
@click.group()
def cli():
......@@ -14,6 +14,6 @@ def cli():
cli.add_command(update_commands)
cli.add_command(cleanup_commands)
cli.add_command(copy_commands)
cli.add_command(billing_commands)
cli.add_command(reporting_commands)
cli()
import boto3
from akinaka_client.aws_client import AWS_Client
import akinaka_libs.helpers as helpers
from datetime import datetime, timezone, timedelta
aws_client = AWS_Client()
class CostExplorer():
def __init__(self, region, role_arn):
self.costexplorer_client = aws_client.create_client('ce', region, role_arn)
def get_bill_estimates(self, from_days_ago):
days_ago = 0 or int(from_days_ago)
if days_ago > 0:
end = datetime.now().strftime("%Y-%m-%d")
datetime_days_ago = datetime.now() - timedelta(days=days_ago + 1)
start = datetime_days_ago.strftime("%Y-%m-%d")
else:
start = datetime.now().strftime("%Y-%m-%d")
datetime_days_ago = datetime.now() + timedelta(days=1)
end = datetime_days_ago.strftime("%Y-%m-%d")
return self.costexplorer_client.get_cost_and_usage(
TimePeriod={
'Start': start,
'End': end,
},
Granularity='DAILY',
Metrics=[
'UnblendedCost'
]
)
\ No newline at end of file
import akinaka_libs.cloudwatch
import akinaka_libs.costexplorer
import boto3
import time
import datetime
import sys
import tabulate
class BillingQueries():
def __init__(self, region, assume_role_arn):
self.cloudwatch = akinaka_libs.cloudwatch.CloudWatch(region, assume_role_arn)
self.costexplorer = akinaka_libs.costexplorer.CostExplorer(region, assume_role_arn)
def print_last_two_estimates(self):
def days_estimates(self, from_days_ago):
try:
estimates = self.cloudwatch.get_bill_estimates(from_hours_ago=72)
sorted_estimates = sorted(estimates, key=lambda k: k['Timestamp'])
response = self.costexplorer.get_bill_estimates(from_days_ago)
data = response['ResultsByTime']
except Exception as e:
print("Couldn't get last two estimates: {}".format(e))
print("Billing estimates is not available: {}".format(e))
return e
message = """\
Last estimate ({}): {}
Previous estimate ({}): {}
""".format(sorted_estimates[-1]['Timestamp'], sorted_estimates[-1]['Maximum'], sorted_estimates[-2]['Timestamp'], sorted_estimates[-2]['Maximum'])
results = []
if len(data) == 1:
amount = float(data[0]['Total']['UnblendedCost']['Amount'])
unit = data[0]['Total']['UnblendedCost']['Unit']
date_today = datetime.datetime.now().strftime("%Y-%m-%d")
results.append([date_today, "{} {:.2f}".format(unit, amount)])
message = "\nToday's estimated bill\n"
else:
for d in data:
unit = d['Total']['UnblendedCost']['Unit']
amount = float(d['Total']['UnblendedCost']['Amount'])
results.append([d['TimePeriod']['End'], "{} {:.2f}".format(unit, amount)])
message = "\nEstimated bill for the past {} days\n".format(str(len(data)))
message += tabulate.tabulate(results, headers=["Date", "Total"], tablefmt='psql')
message += "\n"
print(message)
return message
\ No newline at end of file
......@@ -5,17 +5,19 @@ import click
@click.option("--region", required=True, help="Region your resources are located in. N.B. Currently, only us-east-1 supports estimates")
@click.option("--role-arn", required=True, help="Role ARN which contains necessary assume permissions")
@click.pass_context
def billing(ctx, region, role_arn):
def reporting(ctx, region, role_arn):
ctx.obj = {'region': region, 'role_arn': role_arn}
pass
@billing.command()
@reporting.command(name="bill-estimates")
@click.pass_context
def estimate(ctx):
@click.option("--from-days-ago", "from_days_ago", default=0, help="Number of days ago.")
def bill_estimates(ctx, from_days_ago):
region = ctx.obj.get('region')
role_arn = ctx.obj.get('role_arn')
from .billing_summary import billing_queries
billing_queries.BillingQueries(region, role_arn).print_last_two_estimates()
billing_queries.BillingQueries(region, role_arn).days_estimates(from_days_ago)
boto3
datetime
click
\ No newline at end of file
click
tabulate
\ No newline at end of file
......@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
setuptools.setup(
name="akinaka",
python_requires='>3.0.0',
version="0.2.7",
version="0.2.8",
author="Afraz",
author_email="afraz@olindata.com",
description="OlinData's aws cli Extras",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment