-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathreport.py
executable file
·138 lines (116 loc) · 4.79 KB
/
report.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python3
import sys
import os
import argparse
import datetime
import boto3
import zulip
import yaml
BASEDIR = os.path.dirname(sys.argv[0])
CONFIG_FILE = os.path.join(BASEDIR, 'config.yaml')
class AWSUsage(object):
def __init__(self, account_id, use_default_session=False):
self._account_id = account_id
self._use_default_session = use_default_session
self._custom_session = None
self._profile_name = 'default'
def set_profile_name(self, name):
if self._use_default_session:
raise RuntimeError("Cannot set profile name when using default session.")
self._profile_name = name
def get_monthly_cost(self):
client = self._get_client('budgets')
resp = client.describe_budgets(AccountId=self._account_id)
cost = resp['Budgets'][0]['CalculatedSpend']['ActualSpend']['Amount']
forecast = resp['Budgets'][0]['CalculatedSpend']['ForecastedSpend']['Amount']
return (float(cost), float(forecast))
def get_server_stats(self):
client = self._get_client('ec2')
resp = client.describe_instances()
nserver = 0
for resv in resp['Reservations']:
for inst in resv['Instances']:
if inst['State']['Name'] != 'terminated':
nserver += 1
return nserver
def _get_client(self, name):
if self._use_default_session:
return boto3.client(name)
custom_session = self._get_custom_session()
return custom_session.client(name)
def _get_custom_session(self):
if self._custom_session is None:
self._custom_session = boto3.Session(profile_name=self._profile_name)
return self._custom_session
class ConfigLoader(object):
@staticmethod
def load():
config = {
'aws': {},
'zulip': {},
}
if os.path.exists(CONFIG_FILE):
config = ConfigLoader._load_file()
config = ConfigLoader._apply_env(config)
return config
@staticmethod
def _load_file():
with open(CONFIG_FILE) as fp:
return yaml.load(fp, Loader=yaml.Loader)
@staticmethod
def _apply_env(config):
if 'AWS_ACCOUNT_ID' in os.environ:
config['aws']['account_id'] = os.environ['AWS_ACCOUNT_ID']
if 'ZULIP_SITE' in os.environ:
config['zulip']['site'] = os.environ['ZULIP_SITE']
if 'ZULIP_EMAIL' in os.environ:
config['zulip']['email'] = os.environ['ZULIP_EMAIL']
if 'ZULIP_API_KEY' in os.environ:
config['zulip']['api_key'] = os.environ['ZULIP_API_KEY']
if 'ZULIP_TYPE' in os.environ:
config['zulip']['type'] = os.environ['ZULIP_TYPE']
if 'ZULIP_TO' in os.environ:
config['zulip']['to'] = os.environ['ZULIP_TO']
if 'ZULIP_TOPIC' in os.environ:
config['zulip']['topic'] = os.environ['ZULIP_TOPIC']
if 'ZULIP_MESSAGE' in os.environ:
config['zulip']['message'] = os.environ['ZULIP_MESSAGE']
return config
def send_message(config, message):
client = zulip.Client(site=config['zulip']['site'],
email=config['zulip']['email'],
api_key=config['zulip']['api_key'],
insecure=False)
client.send_message({
'type': config['zulip']['type'],
'to': [config['zulip']['to']],
'topic': config['zulip']['topic'],
'content': message
})
def format_message(config, cost, forecast, nserver):
today = datetime.date.today()
template = config['zulip']['message']
return template.format(year=today.year, month=today.month, day=today.day,
cost=cost, forecast=forecast, nserver=nserver)
def main(aws_profile_name='default', use_aws_default_session=False, dryrun=False):
config = ConfigLoader.load()
aws_usage = AWSUsage(config['aws']['account_id'], use_aws_default_session)
if not use_aws_default_session:
aws_usage.set_profile_name(aws_profile_name)
cost, forecast = aws_usage.get_monthly_cost()
nserver = aws_usage.get_server_stats()
message = format_message(config, cost, forecast, nserver)
if dryrun:
print(message)
else:
send_message(config, message)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--aws-profile', type=str, default='default',
help="AWS profile name. Default: 'default'.")
parser.add_argument('--use-aws-default-session', action='store_true',
help="Use default session to connect AWS. --aws-profile is ignored.")
parser.add_argument('--dryrun', action='store_true',
help="For debug. Print the message to stdout.")
args = parser.parse_args()
main(args.aws_profile, args.use_aws_default_session, args.dryrun)