* s3db, S3/SimpleDB.py: Initial support for Amazon SimpleDB.
For now implements ListDomains() call and most of the
infrastructure required for request creation.
git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@178 830e0280-6d2a-0410-9c65-932aecc39d9d
... | ... |
@@ -1,5 +1,11 @@ |
1 | 1 |
2008-04-29 Michal Ludvig <michal@logix.cz> |
2 | 2 |
|
3 |
+ * s3db, S3/SimpleDB.py: Initial support for Amazon SimpleDB. |
|
4 |
+ For now implements ListDomains() call and most of the |
|
5 |
+ infrastructure required for request creation. |
|
6 |
+ |
|
7 |
+2008-04-29 Michal Ludvig <michal@logix.cz> |
|
8 |
+ |
|
3 | 9 |
* S3/Exceptions.py: Exceptions moved out of S3.S3 |
4 | 10 |
* S3/SortedDict.py: rewritten from scratch to preserve |
5 | 11 |
case of keys while still sorting in case-ignore mode. |
21 | 22 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,102 @@ |
0 |
+## Amazon SimpleDB library |
|
1 |
+## Author: Michal Ludvig <michal@logix.cz> |
|
2 |
+## http://www.logix.cz/michal |
|
3 |
+## License: GPL Version 2 |
|
4 |
+ |
|
5 |
+""" |
|
6 |
+Low-level class for working with Amazon SimpleDB |
|
7 |
+""" |
|
8 |
+ |
|
9 |
+import time |
|
10 |
+import urllib |
|
11 |
+import base64 |
|
12 |
+import hmac |
|
13 |
+import sha |
|
14 |
+import httplib |
|
15 |
+from logging import debug, info, warning, error |
|
16 |
+ |
|
17 |
+from Utils import convertTupleListToDict |
|
18 |
+from SortedDict import SortedDict |
|
19 |
+from Exceptions import * |
|
20 |
+ |
|
21 |
+class SimpleDB(object): |
|
22 |
+ # API Version |
|
23 |
+ # See http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/ |
|
24 |
+ Version = "2007-11-07" |
|
25 |
+ SignatureVersion = 1 |
|
26 |
+ |
|
27 |
+ def __init__(self, config): |
|
28 |
+ self.config = config |
|
29 |
+ |
|
30 |
+ def ListDomains(self, MaxNumberOfDomains = 100): |
|
31 |
+ ''' |
|
32 |
+ Lists all domains associated with our Access Key. Returns |
|
33 |
+ domain names up to the limit set by MaxNumberOfDomains. |
|
34 |
+ ''' |
|
35 |
+ parameters = SortedDict() |
|
36 |
+ parameters['MaxNumberOfDomains'] = MaxNumberOfDomains |
|
37 |
+ response = self.send_request("ListDomains", domain = None, parameters = parameters) |
|
38 |
+ return response |
|
39 |
+ |
|
40 |
+ def send_request(self, *args, **kwargs): |
|
41 |
+ request = self.create_request(*args, **kwargs) |
|
42 |
+ debug("Request: %s" % repr(request)) |
|
43 |
+ conn = self.get_connection() |
|
44 |
+ conn.request("GET", self.format_uri(request['uri_params'])) |
|
45 |
+ http_response = conn.getresponse() |
|
46 |
+ response = {} |
|
47 |
+ response["status"] = http_response.status |
|
48 |
+ response["reason"] = http_response.reason |
|
49 |
+ response["headers"] = convertTupleListToDict(http_response.getheaders()) |
|
50 |
+ response["data"] = http_response.read() |
|
51 |
+ debug("Response: " + str(response)) |
|
52 |
+ conn.close() |
|
53 |
+ |
|
54 |
+ if response["status"] < 200 or response["status"] > 299: |
|
55 |
+ raise S3Error(response) |
|
56 |
+ |
|
57 |
+ return response |
|
58 |
+ |
|
59 |
+ def create_request(self, action, domain, parameters = None): |
|
60 |
+ if not parameters: |
|
61 |
+ parameters = SortedDict() |
|
62 |
+ parameters['AWSAccessKeyId'] = self.config.access_key |
|
63 |
+ parameters['Version'] = self.Version |
|
64 |
+ parameters['SignatureVersion'] = self.SignatureVersion |
|
65 |
+ parameters['Action'] = action |
|
66 |
+ parameters['Timestamp'] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) |
|
67 |
+ if domain: |
|
68 |
+ parameters['DomainName'] = domain |
|
69 |
+ parameters['Signature'] = self.sign_request(parameters) |
|
70 |
+ parameters.keys_return_lowercase = False |
|
71 |
+ uri_params = urllib.urlencode(parameters) |
|
72 |
+ request = {} |
|
73 |
+ request['uri_params'] = uri_params |
|
74 |
+ request['parameters'] = parameters |
|
75 |
+ return request |
|
76 |
+ |
|
77 |
+ def sign_request(self, parameters): |
|
78 |
+ h = "" |
|
79 |
+ parameters.keys_sort_lowercase = True |
|
80 |
+ parameters.keys_return_lowercase = False |
|
81 |
+ for key in parameters: |
|
82 |
+ h += "%s%s" % (key, parameters[key]) |
|
83 |
+ debug("SignRequest: %s" % h) |
|
84 |
+ return base64.encodestring(hmac.new(self.config.secret_key, h, sha).digest()).strip() |
|
85 |
+ |
|
86 |
+ def get_connection(self): |
|
87 |
+ if self.config.proxy_host != "": |
|
88 |
+ return httplib.HTTPConnection(self.config.proxy_host, self.config.proxy_port) |
|
89 |
+ else: |
|
90 |
+ if self.config.use_https: |
|
91 |
+ return httplib.HTTPSConnection(self.config.simpledb_host) |
|
92 |
+ else: |
|
93 |
+ return httplib.HTTPConnection(self.config.simpledb_host) |
|
94 |
+ |
|
95 |
+ def format_uri(self, uri_params): |
|
96 |
+ if self.config.proxy_host != "": |
|
97 |
+ uri = "http://%s/?%s" % (self.config.simpledb_host, uri_params) |
|
98 |
+ else: |
|
99 |
+ uri = "/?%s" % uri_params |
|
100 |
+ debug('format_uri(): ' + uri) |
|
101 |
+ return uri |
0 | 102 |
new file mode 100755 |
... | ... |
@@ -0,0 +1,29 @@ |
0 |
+#!/usr/bin/env python |
|
1 |
+ |
|
2 |
+## Amazon S3 manager |
|
3 |
+## Author: Michal Ludvig <michal@logix.cz> |
|
4 |
+## http://www.logix.cz/michal |
|
5 |
+## License: GPL Version 2 |
|
6 |
+ |
|
7 |
+import sys |
|
8 |
+import os |
|
9 |
+import logging |
|
10 |
+ |
|
11 |
+from optparse import OptionParser, Option, OptionValueError, IndentedHelpFormatter |
|
12 |
+from logging import debug, info, warning, error |
|
13 |
+ |
|
14 |
+## Our modules |
|
15 |
+from S3 import PkgInfo |
|
16 |
+from S3.SimpleDB import SimpleDB |
|
17 |
+from S3.Config import Config |
|
18 |
+from S3.Exceptions import * |
|
19 |
+ |
|
20 |
+ |
|
21 |
+if __name__ == '__main__': |
|
22 |
+ if float("%d.%d" %(sys.version_info[0], sys.version_info[1])) < 2.4: |
|
23 |
+ sys.stderr.write("ERROR: Python 2.4 or higher required, sorry.\n") |
|
24 |
+ sys.exit(1) |
|
25 |
+ logging.root.setLevel(logging.DEBUG) |
|
26 |
+ cfg = Config(os.getenv("HOME")+"/.s3cfg") |
|
27 |
+ sdb = SimpleDB(cfg) |
|
28 |
+ print sdb.ListDomains() |