Beautifully crafted timelines that are easy and intuitive to use. http://timeline.knightlab.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

178 lines
6.9 KiB

## Amazon SimpleDB library
## Author: Michal Ludvig <michal@logix.cz>
## http://www.logix.cz/michal
## License: GPL Version 2
"""
Low-level class for working with Amazon SimpleDB
"""
import time
import urllib
import base64
import hmac
import sha
import httplib
from logging import debug, info, warning, error
from Utils import convertTupleListToDict
from SortedDict import SortedDict
from Exceptions import *
class SimpleDB(object):
# API Version
# See http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/
Version = "2007-11-07"
SignatureVersion = 1
def __init__(self, config):
self.config = config
## ------------------------------------------------
## Methods implementing SimpleDB API
## ------------------------------------------------
def ListDomains(self, MaxNumberOfDomains = 100):
'''
Lists all domains associated with our Access Key. Returns
domain names up to the limit set by MaxNumberOfDomains.
'''
parameters = SortedDict()
parameters['MaxNumberOfDomains'] = MaxNumberOfDomains
return self.send_request("ListDomains", DomainName = None, parameters = parameters)
def CreateDomain(self, DomainName):
return self.send_request("CreateDomain", DomainName = DomainName)
def DeleteDomain(self, DomainName):
return self.send_request("DeleteDomain", DomainName = DomainName)
def PutAttributes(self, DomainName, ItemName, Attributes):
parameters = SortedDict()
parameters['ItemName'] = ItemName
seq = 0
for attrib in Attributes:
if type(Attributes[attrib]) == type(list()):
for value in Attributes[attrib]:
parameters['Attribute.%d.Name' % seq] = attrib
parameters['Attribute.%d.Value' % seq] = unicode(value)
seq += 1
else:
parameters['Attribute.%d.Name' % seq] = attrib
parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
seq += 1
## TODO:
## - support for Attribute.N.Replace
## - support for multiple values for one attribute
return self.send_request("PutAttributes", DomainName = DomainName, parameters = parameters)
def GetAttributes(self, DomainName, ItemName, Attributes = []):
parameters = SortedDict()
parameters['ItemName'] = ItemName
seq = 0
for attrib in Attributes:
parameters['AttributeName.%d' % seq] = attrib
seq += 1
return self.send_request("GetAttributes", DomainName = DomainName, parameters = parameters)
def DeleteAttributes(self, DomainName, ItemName, Attributes = {}):
"""
Remove specified Attributes from ItemName.
Attributes parameter can be either:
- not specified, in which case the whole Item is removed
- list, e.g. ['Attr1', 'Attr2'] in which case these parameters are removed
- dict, e.g. {'Attr' : 'One', 'Attr' : 'Two'} in which case the
specified values are removed from multi-value attributes.
"""
parameters = SortedDict()
parameters['ItemName'] = ItemName
seq = 0
for attrib in Attributes:
parameters['Attribute.%d.Name' % seq] = attrib
if type(Attributes) == type(dict()):
parameters['Attribute.%d.Value' % seq] = unicode(Attributes[attrib])
seq += 1
return self.send_request("DeleteAttributes", DomainName = DomainName, parameters = parameters)
def Query(self, DomainName, QueryExpression = None, MaxNumberOfItems = None, NextToken = None):
parameters = SortedDict()
if QueryExpression:
parameters['QueryExpression'] = QueryExpression
if MaxNumberOfItems:
parameters['MaxNumberOfItems'] = MaxNumberOfItems
if NextToken:
parameters['NextToken'] = NextToken
return self.send_request("Query", DomainName = DomainName, parameters = parameters)
## Handle NextToken? Or maybe not - let the upper level do it
## ------------------------------------------------
## Low-level methods for handling SimpleDB requests
## ------------------------------------------------
def send_request(self, *args, **kwargs):
request = self.create_request(*args, **kwargs)
#debug("Request: %s" % repr(request))
conn = self.get_connection()
conn.request("GET", self.format_uri(request['uri_params']))
http_response = conn.getresponse()
response = {}
response["status"] = http_response.status
response["reason"] = http_response.reason
response["headers"] = convertTupleListToDict(http_response.getheaders())
response["data"] = http_response.read()
conn.close()
if response["status"] < 200 or response["status"] > 299:
debug("Response: " + str(response))
raise S3Error(response)
return response
def create_request(self, Action, DomainName, parameters = None):
if not parameters:
parameters = SortedDict()
if len(self.config.access_token) > 0:
self.config.refresh_role()
parameters['Signature']=self.config.access_token
parameters['AWSAccessKeyId'] = self.config.access_key
parameters['Version'] = self.Version
parameters['SignatureVersion'] = self.SignatureVersion
parameters['Action'] = Action
parameters['Timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
if DomainName:
parameters['DomainName'] = DomainName
parameters['Signature'] = self.sign_request(parameters)
parameters.keys_return_lowercase = False
uri_params = urllib.urlencode(parameters)
request = {}
request['uri_params'] = uri_params
request['parameters'] = parameters
return request
def sign_request(self, parameters):
h = ""
parameters.keys_sort_lowercase = True
parameters.keys_return_lowercase = False
for key in parameters:
h += "%s%s" % (key, parameters[key])
#debug("SignRequest: %s" % h)
return base64.encodestring(hmac.new(self.config.secret_key, h, sha).digest()).strip()
def get_connection(self):
if self.config.proxy_host != "":
return httplib.HTTPConnection(self.config.proxy_host, self.config.proxy_port)
else:
if self.config.use_https:
return httplib.HTTPSConnection(self.config.simpledb_host)
else:
return httplib.HTTPConnection(self.config.simpledb_host)
def format_uri(self, uri_params):
if self.config.proxy_host != "":
uri = "http://%s/?%s" % (self.config.simpledb_host, uri_params)
else:
uri = "/?%s" % uri_params
#debug('format_uri(): ' + uri)
return uri
# vim:et:ts=4:sts=4:ai