Daily biling notification to slack
Tags: #aws #cloud #storage #S3bucket #slack
Author: Maxime Jublou

Input

Install packages

1
!pip install boto3
Copied!

Setup secret keys

Uncomment to setup.
1
#naas.secret.add(name="AWS_ACCESS_KEY_ID", secret="***")
2
#naas.secret.add(name="AWS_SECRET_ACCESS_KEY", secret="***")
3
#naas.secret.add(name="SLACK_TOKEN", secret="***")
Copied!

Import libraries

1
import datetime
2
import boto3
3
import naas
4
import dateutil.relativedelta
5
import pandas as pd
6
import naas_drivers
Copied!

Setup variables

1
# AWS account
2
AWS_ACCESS_KEY_ID = naas.secret.get(name="AWS_ACCESS_KEY_ID")
3
AWS_SECRET_ACCESS_KEY = naas.secret.get(name="AWS_SECRET_ACCESS_KEY")
4
5
# Slack
6
SLACK_TOKEN = naas.secret.get(name="SLACK_TOKEN")
7
SLACK_CHANNEL = "-aws-billing"
Copied!

Constants

1
# Compute dates
2
def last_day_of_month(any_day):
3
# this will never fail
4
# get close to the end of the month for any day, and add 4 days 'over'
5
next_month = any_day.replace(day=28) + datetime.timedelta(days=4)
6
# subtract the number of remaining 'overage' days to get last day of current month, or said programattically said, the previous day of the first of next month
7
return next_month - datetime.timedelta(days=next_month.day)
8
9
today = datetime.date.today()
10
lastDay = last_day_of_month(today)
11
start_month_date = (today - dateutil.relativedelta.relativedelta(months=12))
12
13
start_date = "{}-{:02d}-{:02d}".format(today.year, today.month, 1)
14
end_date = "{}-{:02d}-{:02d}".format(today.year, today.month, today.day)
15
last_day = "{}-{:02d}-{:02d}".format(lastDay.year, lastDay.month, lastDay.day)
Copied!

Connect to AWS

1
client = boto3.client('ce',
2
aws_access_key_id=AWS_ACCESS_KEY_ID,
3
aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
Copied!

Model

Get current cost from AWS billing

1
result = client.get_cost_and_usage(
2
TimePeriod = {
3
'Start': start_date,
4
'End': end_date
5
},
6
Granularity = 'MONTHLY',
7
Filter = {
8
"Dimensions": {
9
"Key": "RECORD_TYPE",
10
"Values": ["Credit", "Refund"]
11
}
12
},
13
Metrics = ["BlendedCost"],
14
GroupBy = [
15
{
16
'Type': 'DIMENSION',
17
'Key': 'SERVICE'
18
},
19
{
20
'Type': 'DIMENSION',
21
'Key': 'USAGE_TYPE'
22
}
23
]
24
)
Copied!

Transform current billing to dataframe

1
df_billing = pd.DataFrame()
2
3
for t in result["ResultsByTime"]:
4
for r in t["Groups"]:
5
dimension = r["Keys"][0]
6
usage_type = r["Keys"][1]
7
amount = r["Metrics"]["BlendedCost"]["Amount"]
8
period_start = t["TimePeriod"]["Start"]
9
period_end = t["TimePeriod"]["End"]
10
df_billing = df_billing.append({
11
"Dimension": dimension,
12
"UsageType": usage_type,
13
"Amount": amount,
14
"PeriodStart": period_start,
15
"PeriodEnd": period_end
16
}, ignore_index=True)
17
df_billing = df_billing.astype({'Amount': 'float'})
18
19
# Display result
20
df_billing.tail(5)
Copied!

Get forecast from AWS

1
ce_forecast = client.get_cost_forecast(
2
TimePeriod={
3
'Start': end_date,
4
'End': last_day
5
},
6
Metric='BLENDED_COST',
7
Granularity='MONTHLY'
8
)
Copied!

Output

Save current billing to csv

1
df_billing.to_csv('current_month_data.csv')
2
naas.asset.add(path='current_month_data.csv')
Copied!

Data from AWS billing

1
current_amount = df_billing["Amount"].sum()
2
forecast = float(ce_forecast["Total"]["Amount"])
3
asset_link = "Copy URL from generate asset above"
Copied!

Create message for slack

1
message = """
2
Hey there,
3
4
This is your daily AWS billing notification.
5
6
- Current spending: [*{:.2f}$*]
7
- Forecast left to spent: [*{:.2f}$*]
8
- End of month estimate: [*{:.2f}$*]
9
10
Download the detailed csv file {}
11
""".format(float(current_amount), float(forecast), float(current_amount - forecast), asset_link)
12
image_url = None # Set to None if you don't need it
13
print(message)
Copied!

Send data to slack

1
naas_drivers.slack.connect(SLACK_TOKEN).send(SLACK_CHANNEL, message)
Copied!

Scheduler

1
naas.scheduler.add(cron="0 9 * * *")
Copied!
Copy link
Edit on GitHub