0d19ed4c1c7abb1d1e953c9825014573f4ba8975
[bluesky.git] / cloudbench / azure.py
1 #!/usr/bin/python2.6
2
3 """A simple test API for accessing Windows Azure blob storage.
4
5 Parts of the code are modeled after boto (a library for accessing Amazon Web
6 Services), but this code is far less general and is meant only as a
7 proof-of-concept."""
8
9 import base64, hashlib, hmac, httplib, os, time
10
11 # The version of the Azure API we implement; sent in the x-ms-version header.
12 API_VERSION = '2009-09-19'
13
14 def uri_decode(s):
15     # TODO
16     return s
17
18 def add_auth_headers(headers, method, path):
19     header_order = ['Content-Encoding', 'Content-Language', 'Content-Length',
20                     'Content-MD5', 'Content-Type', 'Date', 'If-Modified-Since',
21                     'If-Match', 'If-None-Match', 'If-Unmodified-Since',
22                     'Range']
23
24     if not headers.has_key('Date'):
25         headers['Date'] = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
26                                         time.gmtime())
27     if not headers.has_key('x-ms-version'):
28         headers['x-ms-version'] = API_VERSION
29
30     StringToSign = method + "\n"
31     for h in header_order:
32         if h in headers:
33             StringToSign += headers[h] + "\n"
34         else:
35             StringToSign += "\n"
36
37     # Add Canonicalized Headers
38     canonized = []
39     for (k, v) in headers.items():
40         k = k.lower()
41         if k.startswith('x-ms-'):
42             canonized.append((k, v))
43     canonized.sort()
44     for (k, v) in canonized:
45         StringToSign += "%s:%s\n" % (k, v)
46
47     # Add CanonicalizedHeaders Resource
48     account_name = os.environ['AZURE_ACCOUNT_NAME']
49     account_name = 'bluesky'
50     resource = "/" + account_name
51     if '?' not in path:
52         resource += path
53     else:
54         (path, params) = path.split('?', 1)
55         params = [p.split('=') for p in params.split("&")]
56         params = dict((k.lower(), uri_decode(v)) for (k, v) in params)
57         resource += path
58         for k in sorted(params):
59             resource += "\n%s:%s" % (k, params[k])
60     StringToSign += resource
61
62     # print "String to sign:", repr(StringToSign)
63
64     secret_key = os.environ['AZURE_SECRET_KEY']
65     secret_key = base64.b64decode(secret_key)
66     h = hmac.new(secret_key, digestmod=hashlib.sha256)
67     h.update(StringToSign)
68
69     signature = base64.b64encode(h.digest())
70     headers['Authorization'] = "SharedKey %s:%s" % (account_name, signature)
71
72 class Connection:
73     def __init__(self):
74         self.host = os.environ['AZURE_ACCOUNT_NAME'] + ".blob.core.windows.net"
75         self.conn = httplib.HTTPConnection(self.host)
76
77     def make_request(self, path, method='GET', body="", headers={}):
78         headers = headers.copy()
79         headers['Content-Length'] = str(len(body))
80         if len(body) > 0:
81             headers['Content-MD5'] \
82                 = base64.b64encode(hashlib.md5(body).digest())
83         add_auth_headers(headers, method, path)
84
85         # req = "%s %s HTTP/1.1\r\nHost: %s\r\n" % (method, path, host)
86         # req = req + ''.join("%s: %s\r\n" % h for h in headers.items()) + "\r\n"
87         # print req
88
89         self.conn.request(method, path, body, headers)
90         response = self.conn.getresponse()
91         print "Response:", response.status
92         print "Headers:", response.getheaders()
93         body = response.read()
94
95 if __name__ == '__main__':
96     # generate_request("/?comp=list")
97     buf = 'A' * 1048576
98     conn = Connection()
99     for i in range(16):
100         conn.make_request('/benchmark/file-1M-' + str(i), 'PUT', buf,
101                           {'x-ms-blob-type': 'BlockBlob'})
102
103     conn = Connection()
104     for i in range(16):
105         conn.make_request('/benchmark/file-1M-' + str(i), 'GET')