summaryrefslogtreecommitdiffstats
path: root/py3status/modules/aws_bill.py
blob: 5452718ee22d3e8485a20657e1695fb0fbbde0b9 (plain)
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
# -*- coding: utf-8 -*-
"""
Display the current AWS bill.

##### WARNING #####
This module generate some costs on the AWS bill.
Take care about the cache_timeout to limit these fees !
##### WARNING #####

Configuration parameters:
    - aws_access_key_id: Your AWS access key
    - aws_account_id: the root ID of the AWS account.
      Can be found here: https://console.aws.amazon.com/billing/home#/account
    - aws_secret_access_key: Your AWS secret key
    - billing_file: csv file location
    - cache_timeout: how often we refresh this module in seconds
    - s3_bucket_name: the bucket where billing files are sent by AWS.
      Follow this article to activate this feature:
      http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/detailed-billing-reports.html

Format of status string placeholders:
    {bill_amount} - AWS bill amount

Requires:
    - boto

@author nawadanp
"""

import boto
import csv
import datetime

from boto.s3.connection import Key
from time import time


class Py3status:
    """
    """
    # available configuration parameters
    aws_access_key_id = ''
    aws_account_id = ''
    aws_secret_access_key = ''
    billing_file = '/tmp/.aws_billing.csv'
    cache_timeout = 3600
    format = '{bill_amount}$'
    s3_bucket_name = ''

    def _get_bill_amount(self):
        # Billing file name, generated by Amazon itself
        # Format : 123456789012-aws-billing-csv-yyyy-mm.csv
        s3_file_key = '{}-aws-billing-csv-{}-{}.csv'.format(
            self.aws_account_id, datetime.datetime.now().strftime('%Y'),
            datetime.datetime.now().strftime('%m'))
        i = 0

        # Connection to s3 service
        try:
            conn = boto.connect_s3(self.aws_access_key_id,
                                   self.aws_secret_access_key)
        except:
            return 'conn_error'

        # Connection to the bucket
        try:
            bucket = conn.get_bucket(self.s3_bucket_name)
        except:
            return 'bucket_error'

        # Fetch the objects keys and get the billing file
        try:
            k = Key(bucket)
            k.key = s3_file_key
            k.get_contents_to_filename(self.billing_file)
            k.close
        except:
            return 'key_error'

        # Parse the file and get the InvoiceTotal amount
        try:
            with open(self.billing_file, 'rb') as f:
                reader = csv.reader(f)
                for row in reader:
                    if ''.join(row).find('InvoiceTotal') == -1:
                        continue
                    i = i + 1
                    return row[-1]
        except:
            return 'csv_error'

        return False

    def aws_bill(self, i3s_output_list, i3s_config):
        response = {
            'cached_until': time() + self.cache_timeout,
            'color': i3s_config['color_bad'],
            'full_text': ''
        }

        bill_amount = self._get_bill_amount()

        if bill_amount == 'csv_error':
            response['full_text'] = 'Bad CSV file'
        elif bill_amount == 'key_error':
            response['full_text'] = 'Key not found in the bucket'
        elif bill_amount == 'bucket_error':
            response['full_text'] = 'Check the bucket name or your AWS keys'
        elif bill_amount == 'conn_error':
            response['full_text'] = 'Check your internet access'
        elif bill_amount is not False:
            response['full_text'] = self.format.format(bill_amount=bill_amount)
            response['color'] = i3s_config['color_good']
        else:
            response['full_text'] = 'Global error - WTF exception'

        return response


if __name__ == "__main__":
    """
    Test this module by calling it directly.
    """
    from time import sleep
    x = Py3status()
    config = {
        'color_bad': '#FF0000',
        'color_degraded': '#FFFF00',
        'color_good': '#00FF00'
    }
    while True:
        print(x.aws_bill([], config))
        sleep(1)