Merge lp:~dreamhosters/txaws/921347-get-bucket-lifecycle-3 into lp:txaws

Proposed by Arsene Rei
Status: Merged
Merged at revision: 121
Proposed branch: lp:~dreamhosters/txaws/921347-get-bucket-lifecycle-3
Merge into: lp:txaws
Diff against target: 220 lines (+165/-1)
4 files modified
txaws/s3/client.py (+31/-1)
txaws/s3/model.py (+22/-0)
txaws/s3/tests/test_client.py (+78/-0)
txaws/testing/payload.py (+34/-0)
To merge this branch: bzr merge lp:~dreamhosters/txaws/921347-get-bucket-lifecycle-3
Reviewer Review Type Date Requested Status
Duncan McGreggor Approve
Review via email: mp+90228@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Duncan McGreggor (oubiwann) wrote :

That's more like it :-)

+1, looks good! Welcome to txAWS!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'txaws/s3/client.py'
2--- txaws/s3/client.py 2012-01-24 23:18:36 +0000
3+++ txaws/s3/client.py 2012-01-26 00:55:10 +0000
4@@ -20,7 +20,8 @@
5 from txaws.client.base import BaseClient, BaseQuery, error_wrapper
6 from txaws.s3.acls import AccessControlPolicy
7 from txaws.s3.model import (
8- Bucket, BucketItem, BucketListing, ItemOwner, RequestPayment)
9+ Bucket, BucketItem, BucketListing, ItemOwner, LifecycleConfiguration,
10+ LifecycleConfigurationRule, RequestPayment)
11 from txaws.s3.exception import S3Error
12 from txaws.service import AWSServiceEndpoint, S3_ENDPOINT
13 from txaws.util import XML, calculate_md5
14@@ -180,6 +181,35 @@
15 root = XML(xml_bytes)
16 return root.text or ""
17
18+ def get_bucket_lifecycle(self, bucket):
19+ """
20+ Get the lifecycle configuration of a bucket.
21+
22+ @param bucket: The name of the bucket.
23+ @return: A C{Deferred} that will fire with the bucket's lifecycle
24+ configuration.
25+ """
26+ query = self.query_factory(
27+ action='GET', creds=self.creds, endpoint=self.endpoint,
28+ bucket=bucket, object_name='?lifecycle')
29+ return query.submit().addCallback(self._parse_lifecycle_config)
30+
31+ def _parse_lifecycle_config(self, xml_bytes):
32+ """Parse a C{LifecycleConfiguration} XML document."""
33+ root = XML(xml_bytes)
34+ contents = []
35+ rules = []
36+
37+ for content_data in root.findall("Rule"):
38+ id = content_data.findtext("ID")
39+ prefix = content_data.findtext("Prefix")
40+ status = content_data.findtext("Status")
41+ expiration = int(content_data.findtext("Expiration/Days"))
42+ rules.append(
43+ LifecycleConfigurationRule(id, prefix, status, expiration))
44+
45+ return LifecycleConfiguration(rules)
46+
47 def get_bucket_acl(self, bucket):
48 """
49 Get the access control policy for a bucket.
50
51=== modified file 'txaws/s3/model.py'
52--- txaws/s3/model.py 2011-03-26 12:32:44 +0000
53+++ txaws/s3/model.py 2012-01-26 00:55:10 +0000
54@@ -34,6 +34,9 @@
55
56
57 class BucketListing(object):
58+ """
59+ A mapping for the data in a bucket listing.
60+ """
61 def __init__(self, name, prefix, marker, max_keys, is_truncated,
62 contents=None, common_prefixes=None):
63 self.name = name
64@@ -45,6 +48,25 @@
65 self.common_prefixes = common_prefixes
66
67
68+class LifecycleConfiguration(object):
69+ """
70+ Returns the lifecycle configuration information set on the bucket.
71+ """
72+ def __init__(self, rules):
73+ self.rules = rules
74+
75+
76+class LifecycleConfigurationRule(object):
77+ """
78+ Container for elements that describe a lifecycle rule.
79+ """
80+ def __init__(self, id, prefix, status, expiration):
81+ self.id = id
82+ self.prefix = prefix
83+ self.status = status
84+ self.expiration = expiration
85+
86+
87 class FileChunk(object):
88 """
89 An Amazon S3 file chunk.
90
91=== modified file 'txaws/s3/tests/test_client.py'
92--- txaws/s3/tests/test_client.py 2012-01-24 23:18:36 +0000
93+++ txaws/s3/tests/test_client.py 2012-01-26 00:55:10 +0000
94@@ -231,6 +231,84 @@
95 d = s3.get_bucket_location("mybucket")
96 return d.addCallback(check_results)
97
98+ def test_get_bucket_lifecycle_multiple_rules(self):
99+ """
100+ L{S3Client.get_bucket_lifecycle} creates a L{Query} to get a bucket's
101+ lifecycle. It parses the returned C{LifecycleConfiguration} XML
102+ document and returns a C{Deferred} that fires with the bucket's region.
103+ """
104+
105+ class StubQuery(client.Query):
106+
107+ def __init__(query, action, creds, endpoint, bucket=None,
108+ object_name=None):
109+ super(StubQuery, query).__init__(action=action, creds=creds,
110+ bucket=bucket,
111+ object_name=object_name)
112+ self.assertEquals(action, "GET")
113+ self.assertEqual(creds.access_key, "foo")
114+ self.assertEqual(creds.secret_key, "bar")
115+ self.assertEqual(query.bucket, "mybucket")
116+ self.assertEqual(query.object_name, "?lifecycle")
117+ self.assertEqual(query.data, "")
118+ self.assertEqual(query.metadata, {})
119+ self.assertEqual(query.amz_headers, {})
120+
121+ def submit(query, url_context=None):
122+ return succeed(payload.
123+ sample_s3_get_bucket_lifecycle_multiple_rules_result)
124+
125+ def check_results(lifecycle_config):
126+ self.assertTrue(len(lifecycle_config.rules) == 2)
127+ rule = lifecycle_config.rules[1]
128+ self.assertEquals(rule.id, 'another-id')
129+ self.assertEquals(rule.prefix, 'another-logs')
130+ self.assertEquals(rule.status, 'Disabled')
131+ self.assertEquals(rule.expiration, 37)
132+
133+ creds = AWSCredentials("foo", "bar")
134+ s3 = client.S3Client(creds, query_factory=StubQuery)
135+ d = s3.get_bucket_lifecycle("mybucket")
136+ return d.addCallback(check_results)
137+
138+ def test_get_bucket_lifecycle(self):
139+ """
140+ L{S3Client.get_bucket_lifecycle} creates a L{Query} to get a bucket's
141+ lifecycle. It parses the returned C{LifecycleConfiguration} XML
142+ document and returns a C{Deferred} that fires with the bucket's region.
143+ """
144+
145+ class StubQuery(client.Query):
146+
147+ def __init__(query, action, creds, endpoint, bucket=None,
148+ object_name=None):
149+ super(StubQuery, query).__init__(action=action, creds=creds,
150+ bucket=bucket,
151+ object_name=object_name)
152+ self.assertEquals(action, "GET")
153+ self.assertEqual(creds.access_key, "foo")
154+ self.assertEqual(creds.secret_key, "bar")
155+ self.assertEqual(query.bucket, "mybucket")
156+ self.assertEqual(query.object_name, "?lifecycle")
157+ self.assertEqual(query.data, "")
158+ self.assertEqual(query.metadata, {})
159+ self.assertEqual(query.amz_headers, {})
160+
161+ def submit(query, url_context=None):
162+ return succeed(payload.sample_s3_get_bucket_lifecycle_result)
163+
164+ def check_results(lifecycle_config):
165+ rule = lifecycle_config.rules[0]
166+ self.assertEquals(rule.id, '30-day-log-deletion-rule')
167+ self.assertEquals(rule.prefix, 'logs')
168+ self.assertEquals(rule.status, 'Enabled')
169+ self.assertEquals(rule.expiration, 30)
170+
171+ creds = AWSCredentials("foo", "bar")
172+ s3 = client.S3Client(creds, query_factory=StubQuery)
173+ d = s3.get_bucket_lifecycle("mybucket")
174+ return d.addCallback(check_results)
175+
176 def test_delete_bucket(self):
177
178 class StubQuery(client.Query):
179
180=== modified file 'txaws/testing/payload.py'
181--- txaws/testing/payload.py 2012-01-24 22:52:02 +0000
182+++ txaws/testing/payload.py 2012-01-26 00:55:10 +0000
183@@ -1007,3 +1007,37 @@
184 </Grant>
185 </AccessControlList>
186 </AccessControlPolicy>"""
187+
188+sample_s3_get_bucket_lifecycle_result = """\
189+<?xml version="1.0" encoding="UTF-8"?>
190+<LifecycleConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
191+ <Rule>
192+ <ID>30-day-log-deletion-rule</ID>
193+ <Prefix>logs</Prefix>
194+ <Status>Enabled</Status>
195+ <Expiration>
196+ <Days>30</Days>
197+ </Expiration>
198+ </Rule>
199+</LifecycleConfiguration>"""
200+
201+sample_s3_get_bucket_lifecycle_multiple_rules_result = """\
202+<?xml version="1.0" encoding="UTF-8"?>
203+<LifecycleConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
204+ <Rule>
205+ <ID>30-day-log-deletion-rule</ID>
206+ <Prefix>logs</Prefix>
207+ <Status>Enabled</Status>
208+ <Expiration>
209+ <Days>30</Days>
210+ </Expiration>
211+ </Rule>
212+ <Rule>
213+ <ID>another-id</ID>
214+ <Prefix>another-logs</Prefix>
215+ <Status>Disabled</Status>
216+ <Expiration>
217+ <Days>37</Days>
218+ </Expiration>
219+ </Rule>
220+</LifecycleConfiguration>"""

Subscribers

People subscribed via source and target branches