Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 9th, 2012  |  syntax: None  |  size: 7.29 KB  |  hits: 16  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python
  2.  
  3. """
  4. A script to query the Amazon Web Services usage reports programmatically.
  5.  
  6. Ideally this wouldn't exist, and Amazon would provide an API we can use
  7. instead, but hey - that's life.
  8.  
  9. Basically takes your AWS account username and password, logs into the
  10. website as you, and grabs the data out. Always gets the 'All Usage Types'
  11. report for the specified service.
  12.  
  13. Requirements:
  14.  
  15. * Mechanize: http://wwwsearch.sourceforge.net/mechanize/
  16.   You can install this via pip/easy_install
  17.  
  18. Run with -h to see the available options.
  19. """
  20.  
  21. import re
  22. import os
  23. import sys
  24. from datetime import date
  25. import time
  26.  
  27. import mechanize
  28.  
  29. FORMATS = ('xml', 'csv')
  30. PERIODS = ('hours', 'days', 'months')
  31. SERVICES = ('AmazonS3', 'AmazonEC2', 'AmazonCloudFront', 'AmazonSimpleDB', 'AWSQueueService', 'IngestionService', 'AmazonVPC',)
  32.  
  33. ACCOUNT_SUMMARY_URL = "https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=activity-summary"
  34. FORM_URL = "https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=usage-report"
  35.  
  36. def get_current(username, password, debug=False):
  37.     br = mechanize.Browser()
  38.     br.set_handle_robots(False)
  39.  
  40.     if debug:
  41.         # Log information about HTTP redirects and Refreshes.
  42.         br.set_debug_redirects(True)
  43.         # Log HTTP response bodies (ie. the HTML, most of the time).
  44.         br.set_debug_responses(True)
  45.         # Print HTTP headers.
  46.         br.set_debug_http(True)
  47.    
  48.     br.addheaders = [
  49.         # the login process 404s if you leave Python's UA string
  50.         ('User-Agent', 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4'),
  51.         ('Accept', 'text/html, application/xml, */*'),
  52.     ]
  53.    
  54.     # login
  55.     print >>sys.stderr, "Logging in..."
  56.     try:
  57.         resp = br.open(ACCOUNT_SUMMARY_URL)
  58.         #Some funkiness in DOCTYPE string. mechanize doesn't like
  59.         #results in: mechanize._form.ParseError: unexpected '\\' char in declaration
  60.         #if we don't strip out
  61.         resp.set_data(re.sub('<!DOCTYPE(.*)>', '', resp.get_data()))      
  62.         br.set_response(resp)
  63.         br.select_form(name="signIn")
  64.         br["email"] = username
  65.         br["password"] = password
  66.         resp = br.submit()  # submit current form
  67.     except Exception, e:
  68.         print >>sys.stderr, "Error logging in to AWS"
  69.         raise
  70.  
  71.     cost = re.findall('Total Charges due on.*\$([0-9\,]+\.[0-9][0-9])', resp.get_data(), re.DOTALL)
  72.     if len(cost) > 0:
  73.         print "Total Charges due: %s" % cost[0]
  74.     else:
  75.         print "Current Charges Unknown"
  76.  
  77.  
  78. def get_report(service, date_from, date_to, username, password, format='csv', period='days', debug=False):
  79.     br = mechanize.Browser()
  80.     br.set_handle_robots(False)
  81.  
  82.     if debug:
  83.         # Log information about HTTP redirects and Refreshes.
  84.         br.set_debug_redirects(True)
  85.         # Log HTTP response bodies (ie. the HTML, most of the time).
  86.         br.set_debug_responses(True)
  87.         # Print HTTP headers.
  88.         br.set_debug_http(True)
  89.    
  90.     br.addheaders = [
  91.         # the login process 404s if you leave Python's UA string
  92.         ('User-Agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1) Gecko/20090701 Ubuntu/9.04 (jaunty) Firefox/3.5'),
  93.         ('Accept', 'text/html, application/xml, */*'),
  94.     ]
  95.    
  96.     # login
  97.     print >>sys.stderr, "Logging in..."
  98.     try:
  99.         resp = br.open(FORM_URL)
  100.         #Some funkiness in DOCTYPE string. mechanize doesn't like
  101.         #results in: mechanize._form.ParseError: unexpected '\\' char in declaration
  102.         #if we don't strip out
  103.         resp.set_data(re.sub('<!DOCTYPE(.*)>', '', resp.get_data()))      
  104.         br.set_response(resp)
  105.         br.select_form(name="signIn")
  106.         br["email"] = username
  107.         br["password"] = password
  108.         resp = br.submit()  # submit current form
  109.     except Exception, e:
  110.         print >>sys.stderr, "Error logging in to AWS"
  111.         raise
  112.    
  113.     # service selector
  114.     print >>sys.stderr, "Selecting service %s..." % service
  115.     br.select_form(name="usageReportForm")
  116.     br["productCode"] = [service]
  117.     resp = br.submit()
  118.    
  119.     # report selector
  120.     print >>sys.stderr, "Building report..."
  121.     br.select_form(name="usageReportForm")
  122.     # update timePeriod to fix: mechanize._form.ItemNotFoundError: insufficient items with name 'Custom date range'
  123.     br["timePeriod"] = ["aws-portal-custom-date-range"]
  124.     br["startYear"] = [str(date_from.year)]
  125.     br["startMonth"] = [str(date_from.month)]
  126.     br["startDay"] = [str(date_from.day)]
  127.     br["endYear"] = [str(date_to.year)]
  128.     br["endMonth"] = [str(date_to.month)]
  129.     br["endDay"] = [str(date_to.day)]
  130.     br["periodType"] = [period]
  131.    
  132.     resp = br.submit("download-usage-report-%s" % format)
  133.     return resp.read()
  134.    
  135. if __name__ == "__main__":
  136.     from optparse import OptionParser
  137.    
  138.     USAGE = (
  139.         "Usage: %prog [options] -s SERVICE DATE_FROM DATE_TO\n\n"
  140.         "DATE_FROM and DATE_TO should be in YYYY-MM-DD format (eg. 2009-01-31)\n"
  141.         "Username and Password can also be specified via AWS_USERNAME and AWS_PASSWORD environment variables.\n"
  142.         "\n"
  143.         "Available Services: " + ', '.join(SERVICES)
  144.     )
  145.     parser = OptionParser(usage=USAGE)
  146.     parser.add_option('-s', '--service', dest="service", type="choice", choices=SERVICES, help="The AWS service to query")
  147.     parser.add_option('-p', '--period', dest="period", type="choice", choices=PERIODS, default='days', metavar="PERIOD", help="Period of report entries")
  148.     parser.add_option('-f', '--format', dest="format", type="choice", choices=FORMATS, default='csv', metavar="FORMAT", help="Format of report")
  149.     parser.add_option('-U', '--username', dest="username", metavar="USERNAME", help="Email address for your AWS account")
  150.     parser.add_option('-P', '--password', dest="password", metavar="PASSWORD")
  151.     parser.add_option('-d', '--debug', action="store_true", dest="debug", default=False)
  152.     parser.add_option('-c', '--current', action="store_true", dest="current", default=False)    
  153.    
  154.     opts, args = parser.parse_args()
  155.    
  156.     if not opts.username and not os.environ.get('AWS_USERNAME'):
  157.         parser.error("Must specify username option or set AWS_USERNAME")
  158.     if not opts.password and not os.environ.get('AWS_PASSWORD'):
  159.         parser.error("Must specify password option or set AWS_PASSWORD")
  160.        
  161.     if opts.current:
  162.         kwopts = {
  163.           'username': opts.username or os.environ.get('AWS_USERNAME'),
  164.           'password': opts.password or os.environ.get('AWS_PASSWORD'),
  165.           'debug': opts.debug,
  166.         }    
  167.         get_current(**kwopts)
  168.    
  169.     else:
  170.    
  171.       if len(args) < 2:
  172.           parser.error("Missing date range")
  173.       date_range = [date(*time.strptime(args[i], '%Y-%m-%d')[0:3]) for i in range(2)]
  174.       if date_range[1] < date_range[0]:
  175.           parser.error("End date < start date")
  176.      
  177.       if not opts.service:
  178.           parser.error("Specify a service to query!")
  179.            
  180.       kwopts = {
  181.           'service': opts.service,
  182.           'date_from': date_range[0],
  183.           'date_to': date_range[1],
  184.           'format': opts.format,
  185.           'period': opts.period,
  186.           'username': opts.username or os.environ.get('AWS_USERNAME'),
  187.           'password': opts.password or os.environ.get('AWS_PASSWORD'),
  188.           'debug': opts.debug,
  189.       }
  190.      
  191.       print get_report(**kwopts)