Merge lp:~franciscosouza/txaws/txaws-bundled-vpc into lp:txaws
- txaws-bundled-vpc
- Merge into trunk
Proposed by
Francisco Souza
Status: | Merged |
---|---|
Merged at revision: | 153 |
Proposed branch: | lp:~franciscosouza/txaws/txaws-bundled-vpc |
Merge into: | lp:txaws |
Diff against target: |
945 lines (+354/-95) 9 files modified
txaws/client/base.py (+24/-9) txaws/client/discover/tests/test_command.py (+8/-8) txaws/ec2/client.py (+55/-19) txaws/ec2/model.py (+2/-1) txaws/ec2/tests/test_client.py (+217/-35) txaws/ec2/tests/test_model.py (+6/-4) txaws/server/tests/test_call.py (+1/-1) txaws/testing/payload.py (+40/-17) txaws/version.py (+1/-1) |
To merge this branch: | bzr merge lp:~franciscosouza/txaws/txaws-bundled-vpc |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
txAWS Committers | Pending | ||
Review via email: mp+135397@code.launchpad.net |
Commit message
Description of the change
client, ec2: bundling changes needed for VPC
I use this CL for patching only, original CL's are:
https:/
https:/
https:/
https:/
This one also includes a change in parsing of instance sets.
To post a comment you must log in.
Revision history for this message
Chico (franciscossouza) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'txaws/client/base.py' |
2 | --- txaws/client/base.py 2012-05-16 02:35:26 +0000 |
3 | +++ txaws/client/base.py 2012-11-21 12:35:25 +0000 |
4 | @@ -1,3 +1,6 @@ |
5 | +import os |
6 | +import urlparse |
7 | + |
8 | try: |
9 | from xml.etree.ElementTree import ParseError |
10 | except ImportError: |
11 | @@ -6,16 +9,16 @@ |
12 | import warnings |
13 | from StringIO import StringIO |
14 | |
15 | +from twisted.internet.endpoints import TCP4ClientEndpoint |
16 | from twisted.internet.ssl import ClientContextFactory |
17 | from twisted.internet.protocol import Protocol |
18 | from twisted.internet.defer import Deferred, succeed, fail |
19 | from twisted.python import failure |
20 | from twisted.web import http |
21 | from twisted.web.iweb import UNKNOWN_LENGTH |
22 | -from twisted.web.client import HTTPClientFactory |
23 | -from twisted.web.client import Agent |
24 | +from twisted.web.client import Agent, ProxyAgent |
25 | from twisted.web.client import ResponseDone |
26 | -from twisted.web.http import NO_CONTENT |
27 | +from twisted.web.http import NO_CONTENT, PotentialDataLoss |
28 | from twisted.web.http_headers import Headers |
29 | from twisted.web.error import Error as TwistedWebError |
30 | try: |
31 | @@ -130,7 +133,7 @@ |
32 | self._received += len(bytes) |
33 | |
34 | def connectionLost(self, reason): |
35 | - reason.trap(ResponseDone) |
36 | + reason.trap(ResponseDone, PotentialDataLoss) |
37 | d = self.finished |
38 | self.finished = None |
39 | streaming = self.content_length is UNKNOWN_LENGTH |
40 | @@ -220,16 +223,28 @@ |
41 | if (self.body_producer is None) and (data is not None): |
42 | self.body_producer = FileBodyProducer(StringIO(data)) |
43 | if scheme == "https": |
44 | - if self.endpoint.ssl_hostname_verification: |
45 | - contextFactory = WebVerifyingContextFactory(host) |
46 | + proxy_endpoint = os.environ.get("https_proxy") |
47 | + if proxy_endpoint: |
48 | + proxy_url = urlparse.urlparse(proxy_endpoint) |
49 | + endpoint = TCP4ClientEndpoint(self.reactor, proxy_url.hostname, proxy_url.port) |
50 | + agent = ProxyAgent(endpoint) |
51 | else: |
52 | - contextFactory = WebClientContextFactory() |
53 | - agent = Agent(self.reactor, contextFactory) |
54 | + if self.endpoint.ssl_hostname_verification: |
55 | + contextFactory = WebVerifyingContextFactory(host) |
56 | + else: |
57 | + contextFactory = WebClientContextFactory() |
58 | + agent = Agent(self.reactor, contextFactory) |
59 | self.client.url = url |
60 | d = agent.request(method, url, self.request_headers, |
61 | self.body_producer) |
62 | else: |
63 | - agent = Agent(self.reactor) |
64 | + proxy_endpoint = os.environ.get("http_proxy") |
65 | + if proxy_endpoint: |
66 | + proxy_url = urlparse.urlparse(proxy_endpoint) |
67 | + endpoint = TCP4ClientEndpoint(self.reactor, proxy_url.hostname, proxy_url.port) |
68 | + agent = ProxyAgent(endpoint) |
69 | + else: |
70 | + agent = Agent(self.reactor) |
71 | d = agent.request(method, url, self.request_headers, |
72 | self.body_producer) |
73 | d.addCallback(self._handle_response) |
74 | |
75 | === modified file 'txaws/client/discover/tests/test_command.py' |
76 | --- txaws/client/discover/tests/test_command.py 2012-01-27 02:10:24 +0000 |
77 | +++ txaws/client/discover/tests/test_command.py 2012-11-21 12:35:25 +0000 |
78 | @@ -74,9 +74,9 @@ |
79 | url = ( |
80 | "http://endpoint?AWSAccessKeyId=key&" |
81 | "Action=DescribeRegions&" |
82 | - "Signature=3%2BHSkQQosF1Sr9AL3kdY31tEfTWQ2whjJOUSc3kvc2c%3D&" |
83 | + "Signature=7fyxNidMkL%2B85udGOxqm%2BgM2o1gLyeLG2a0UOmfBOXQ%3D&" |
84 | "SignatureMethod=HmacSHA256&SignatureVersion=2&" |
85 | - "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2009-11-30") |
86 | + "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2012-08-15") |
87 | self.assertEqual("GET", self.method) |
88 | self.assertEqual(url, self.url) |
89 | self.assertEqual("URL: %s\n" |
90 | @@ -99,9 +99,9 @@ |
91 | url = ( |
92 | "http://endpoint?AWSAccessKeyId=key&" |
93 | "Action=DescribeRegions&RegionName.0=us-west-1&" |
94 | - "Signature=6D8aCgSPQOYixowRHy26aRFzK2Vwgixl9uwegYX9nLA%3D&" |
95 | + "Signature=FL4JjDKbWdg531q1KKUPild%2BvyqspA5wxSmOeWXWsJI%3D&" |
96 | "SignatureMethod=HmacSHA256&SignatureVersion=2&" |
97 | - "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2009-11-30") |
98 | + "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2012-08-15") |
99 | self.assertEqual("GET", self.method) |
100 | self.assertEqual(url, self.url) |
101 | self.assertEqual("URL: %s\n" |
102 | @@ -128,9 +128,9 @@ |
103 | url = ( |
104 | "http://endpoint?AWSAccessKeyId=key&" |
105 | "Action=DescribeRegions&RegionName.0=us-west-1&" |
106 | - "Signature=6D8aCgSPQOYixowRHy26aRFzK2Vwgixl9uwegYX9nLA%3D&" |
107 | + "Signature=FL4JjDKbWdg531q1KKUPild%2BvyqspA5wxSmOeWXWsJI%3D&" |
108 | "SignatureMethod=HmacSHA256&SignatureVersion=2&" |
109 | - "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2009-11-30") |
110 | + "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2012-08-15") |
111 | self.assertEqual("GET", self.method) |
112 | self.assertEqual(url, self.url) |
113 | self.assertEqual("URL: %s\n" |
114 | @@ -185,9 +185,9 @@ |
115 | url = ( |
116 | "http://endpoint?AWSAccessKeyId=key&" |
117 | "Action=DescribeRegions&RegionName.0=us-west-1&" |
118 | - "Signature=6D8aCgSPQOYixowRHy26aRFzK2Vwgixl9uwegYX9nLA%3D&" |
119 | + "Signature=FL4JjDKbWdg531q1KKUPild%2BvyqspA5wxSmOeWXWsJI%3D&" |
120 | "SignatureMethod=HmacSHA256&SignatureVersion=2&" |
121 | - "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2009-11-30") |
122 | + "Timestamp=2010-06-04T23%3A40%3A00Z&Version=2012-08-15") |
123 | self.assertEqual("GET", self.method) |
124 | self.assertEqual(url, self.url) |
125 | self.assertEqual("URL: %s\n" |
126 | |
127 | === modified file 'txaws/ec2/client.py' |
128 | --- txaws/ec2/client.py 2012-05-05 00:17:02 +0000 |
129 | +++ txaws/ec2/client.py 2012-11-21 12:35:25 +0000 |
130 | @@ -48,7 +48,7 @@ |
131 | def run_instances(self, image_id, min_count, max_count, |
132 | security_groups=None, key_name=None, instance_type=None, |
133 | user_data=None, availability_zone=None, kernel_id=None, |
134 | - ramdisk_id=None): |
135 | + ramdisk_id=None, subnet_id=None, security_group_ids=None): |
136 | """Run new instances. |
137 | |
138 | TODO: blockDeviceMapping, monitoring, subnetId |
139 | @@ -57,9 +57,21 @@ |
140 | "MaxCount": str(max_count)} |
141 | if key_name is not None: |
142 | params["KeyName"] = key_name |
143 | - if security_groups is not None: |
144 | + if subnet_id is not None: |
145 | + params["SubnetId"] = subnet_id |
146 | + if security_group_ids is not None: |
147 | + for i, id in enumerate(security_group_ids): |
148 | + params["SecurityGroupId.%d" % (i + 1)] = id |
149 | + else: |
150 | + msg = "You must specify the security_group_ids with the subnet_id" |
151 | + raise ValueError(msg) |
152 | + elif security_groups is not None: |
153 | for i, name in enumerate(security_groups): |
154 | params["SecurityGroup.%d" % (i + 1)] = name |
155 | + else: |
156 | + msg = ("You must specify either the subnet_id and " |
157 | + "security_group_ids or security_groups") |
158 | + raise ValueError(msg) |
159 | if user_data is not None: |
160 | params["UserData"] = b64encode(user_data) |
161 | if instance_type is not None: |
162 | @@ -110,28 +122,37 @@ |
163 | d = query.submit() |
164 | return d.addCallback(self.parser.describe_security_groups) |
165 | |
166 | - def create_security_group(self, name, description): |
167 | + def create_security_group(self, name, description, vpc_id=None): |
168 | """Create security group. |
169 | |
170 | @param name: Name of the new security group. |
171 | @param description: Description of the new security group. |
172 | + @param vpc_id: ID of the VPC to which the security group will belong. |
173 | @return: A C{Deferred} that will fire with a truth value for the |
174 | success of the operation. |
175 | """ |
176 | parameters = {"GroupName": name, "GroupDescription": description} |
177 | + if vpc_id: |
178 | + parameters["VpcId"] = vpc_id |
179 | query = self.query_factory( |
180 | action="CreateSecurityGroup", creds=self.creds, |
181 | endpoint=self.endpoint, other_params=parameters) |
182 | d = query.submit() |
183 | - return d.addCallback(self.parser.truth_return) |
184 | + return d.addCallback(self.parser.create_security_group) |
185 | |
186 | - def delete_security_group(self, name): |
187 | + def delete_security_group(self, name=None, id=None): |
188 | """ |
189 | - @param name: Name of the new security group. |
190 | + @param name: Name of the security group. |
191 | + @param id: Id of the security group. |
192 | @return: A C{Deferred} that will fire with a truth value for the |
193 | success of the operation. |
194 | """ |
195 | - parameter = {"GroupName": name} |
196 | + if name: |
197 | + parameter = {"GroupName": name} |
198 | + elif id: |
199 | + parameter = {"GroupId": id} |
200 | + else: |
201 | + raise ValueError("You must provide either the security group name or id") |
202 | query = self.query_factory( |
203 | action="DeleteSecurityGroup", creds=self.creds, |
204 | endpoint=self.endpoint, other_params=parameter) |
205 | @@ -139,7 +160,7 @@ |
206 | return d.addCallback(self.parser.truth_return) |
207 | |
208 | def authorize_security_group( |
209 | - self, group_name, source_group_name="", source_group_owner_id="", |
210 | + self, group_name=None, group_id=None, source_group_name="", source_group_owner_id="", |
211 | ip_protocol="", from_port="", to_port="", cidr_ip=""): |
212 | """ |
213 | There are two ways to use C{authorize_security_group}: |
214 | @@ -150,6 +171,8 @@ |
215 | |
216 | @param group_name: The group you will be modifying with a new |
217 | authorization. |
218 | + @param group_id: The id of the group you will be modifying with |
219 | + a new authorization. |
220 | |
221 | Optionally, the following parameters: |
222 | @param source_group_name: Name of security group to authorize access to |
223 | @@ -188,7 +211,12 @@ |
224 | msg = ("You must specify either both group parameters or " |
225 | "all the ip parameters.") |
226 | raise ValueError(msg) |
227 | - parameters["GroupName"] = group_name |
228 | + if group_id: |
229 | + parameters["GroupId"] = group_id |
230 | + elif group_name: |
231 | + parameters["GroupName"] = group_name |
232 | + else: |
233 | + raise ValueError("You must specify either the group name of the group id.") |
234 | query = self.query_factory( |
235 | action="AuthorizeSecurityGroupIngress", creds=self.creds, |
236 | endpoint=self.endpoint, other_params=parameters) |
237 | @@ -224,7 +252,7 @@ |
238 | return d |
239 | |
240 | def revoke_security_group( |
241 | - self, group_name, source_group_name="", source_group_owner_id="", |
242 | + self, group_name=None, group_id=None, source_group_name="", source_group_owner_id="", |
243 | ip_protocol="", from_port="", to_port="", cidr_ip=""): |
244 | """ |
245 | There are two ways to use C{revoke_security_group}: |
246 | @@ -273,7 +301,12 @@ |
247 | msg = ("You must specify either both group parameters or " |
248 | "all the ip parameters.") |
249 | raise ValueError(msg) |
250 | - parameters["GroupName"] = group_name |
251 | + if group_id: |
252 | + parameters["GroupId"] = group_id |
253 | + elif group_name: |
254 | + parameters["GroupName"] = group_name |
255 | + else: |
256 | + raise ValueError("You must specify either the group name of the group id.") |
257 | query = self.query_factory( |
258 | action="RevokeSecurityGroupIngress", creds=self.creds, |
259 | endpoint=self.endpoint, other_params=parameters) |
260 | @@ -547,6 +580,10 @@ |
261 | ipAddress, stateReason, architecture, rootDeviceName, |
262 | blockDeviceMapping, instanceLifecycle, spotInstanceRequestId. |
263 | """ |
264 | + for group_data in instance_data.find("groupSet"): |
265 | + group_id = group_data.findtext("groupId") |
266 | + group_name = group_data.findtext("groupName") |
267 | + reservation.groups.append((group_id, group_name)) |
268 | instance_id = instance_data.findtext("instanceId") |
269 | instance_state = instance_data.find( |
270 | "instanceState").findtext("name") |
271 | @@ -599,16 +636,10 @@ |
272 | results = [] |
273 | # May be a more elegant way to do this: |
274 | for reservation_data in root.find("reservationSet"): |
275 | - # Get the security group information. |
276 | - groups = [] |
277 | - for group_data in reservation_data.find("groupSet"): |
278 | - group_id = group_data.findtext("groupId") |
279 | - groups.append(group_id) |
280 | # Create a reservation object with the parsed data. |
281 | reservation = model.Reservation( |
282 | reservation_id=reservation_data.findtext("reservationId"), |
283 | - owner_id=reservation_data.findtext("ownerId"), |
284 | - groups=groups) |
285 | + owner_id=reservation_data.findtext("ownerId")) |
286 | # Get the list of instances. |
287 | instances = self.instances_set( |
288 | reservation_data, reservation) |
289 | @@ -670,6 +701,7 @@ |
290 | root = XML(xml_bytes) |
291 | result = [] |
292 | for group_info in root.findall("securityGroupInfo/item"): |
293 | + id = group_info.findtext("groupId") |
294 | name = group_info.findtext("groupName") |
295 | description = group_info.findtext("groupDescription") |
296 | owner_id = group_info.findtext("ownerId") |
297 | @@ -709,11 +741,15 @@ |
298 | for user_id, group_name in allowed_groups] |
299 | |
300 | security_group = model.SecurityGroup( |
301 | - name, description, owner_id=owner_id, |
302 | + id, name, description, owner_id=owner_id, |
303 | groups=allowed_groups, ips=allowed_ips) |
304 | result.append(security_group) |
305 | return result |
306 | |
307 | + def create_security_group(self, xml_bytes): |
308 | + root = XML(xml_bytes) |
309 | + return root.findtext("groupId") |
310 | + |
311 | def truth_return(self, xml_bytes): |
312 | """Parse the XML for a truth value. |
313 | |
314 | |
315 | === modified file 'txaws/ec2/model.py' |
316 | --- txaws/ec2/model.py 2012-03-02 22:00:10 +0000 |
317 | +++ txaws/ec2/model.py 2012-11-21 12:35:25 +0000 |
318 | @@ -80,7 +80,8 @@ |
319 | @ivar allowed_ips: The sequence of L{IPPermission} instances for this |
320 | security group. |
321 | """ |
322 | - def __init__(self, name, description, owner_id="", groups=None, ips=None): |
323 | + def __init__(self, id, name, description, owner_id="", groups=None, ips=None): |
324 | + self.id = id |
325 | self.name = name |
326 | self.description = description |
327 | self.owner_id = owner_id |
328 | |
329 | === modified file 'txaws/ec2/tests/test_client.py' |
330 | --- txaws/ec2/tests/test_client.py 2012-03-02 22:00:10 +0000 |
331 | +++ txaws/ec2/tests/test_client.py 2012-11-21 12:35:25 +0000 |
332 | @@ -171,7 +171,8 @@ |
333 | self.assertEquals(reservation.owner_id, "123456789012") |
334 | # check groups |
335 | group = reservation.groups[0] |
336 | - self.assertEquals(group, "default") |
337 | + self.assertEquals(group[0], "sg-64f9eb08") |
338 | + self.assertEquals(group[1], "default") |
339 | # check instance |
340 | self.assertEquals(instance.instance_id, "i-abcdef01") |
341 | self.assertEquals(instance.instance_state, "running") |
342 | @@ -201,7 +202,8 @@ |
343 | self.assertEquals(reservation.owner_id, "123456789012") |
344 | # check groups |
345 | group = reservation.groups[0] |
346 | - self.assertEquals(group, "default") |
347 | + self.assertEquals(group[0], "sg-64f9eb08") |
348 | + self.assertEquals(group[1], "default") |
349 | # check instance |
350 | self.assertEquals(instance.instance_id, "i-abcdef01") |
351 | self.assertEquals(instance.instance_state, "running") |
352 | @@ -331,7 +333,8 @@ |
353 | self.assertEquals(reservation.owner_id, "495219933132") |
354 | # check groups |
355 | group = reservation.groups[0] |
356 | - self.assertEquals(group, "default") |
357 | + self.assertEquals(group[0], "sg-64f9eb08") |
358 | + self.assertEquals(group[1], "default") |
359 | # check instance |
360 | self.assertEquals(instance.instance_id, "i-2ba64342") |
361 | self.assertEquals(instance.instance_state, "pending") |
362 | @@ -377,6 +380,59 @@ |
363 | ramdisk_id=u"r-1234") |
364 | d.addCallback(self.check_parsed_run_instances) |
365 | |
366 | + def test_run_instances_with_subnet(self): |
367 | + class StubQuery(object): |
368 | + def __init__(stub, action="", creds=None, endpoint=None, |
369 | + other_params={}): |
370 | + self.assertEqual(action, "RunInstances") |
371 | + self.assertEqual(creds.access_key, "foo") |
372 | + self.assertEqual(creds.secret_key, "bar") |
373 | + self.assertEquals( |
374 | + other_params, |
375 | + {"ImageId": "ami-1234", "MaxCount": "2", "MinCount": "1", |
376 | + "SecurityGroupId.1": u"sg-a72d9f92e", "KeyName": u"default", |
377 | + "UserData": "Zm9v", "InstanceType": u"m1.small", |
378 | + "Placement.AvailabilityZone": u"us-east-1b", |
379 | + "KernelId": u"k-1234", "RamdiskId": u"r-1234", |
380 | + "SubnetId": "subnet-a72d829f"}) |
381 | + |
382 | + def submit(self): |
383 | + return succeed( |
384 | + payload.sample_run_instances_result) |
385 | + |
386 | + creds = AWSCredentials("foo", "bar") |
387 | + ec2 = client.EC2Client(creds, query_factory=StubQuery) |
388 | + d = ec2.run_instances("ami-1234", 1, 2, security_group_ids=[u"sg-a72d9f92e"], |
389 | + key_name=u"default", user_data=u"foo", instance_type=u"m1.small", |
390 | + availability_zone=u"us-east-1b", kernel_id=u"k-1234", |
391 | + ramdisk_id=u"r-1234", subnet_id="subnet-a72d829f") |
392 | + d.addCallback(self.check_parsed_run_instances) |
393 | + |
394 | + def test_run_instances_with_subnet_but_without_secgroup_id(self): |
395 | + creds = AWSCredentials("foo", "bar") |
396 | + ec2 = client.EC2Client(creds) |
397 | + error = self.assertRaises(ValueError, ec2.run_instances, "ami-1234", 1, 2, |
398 | + key_name=u"default", user_data=u"foo", instance_type=u"m1.small", |
399 | + availability_zone=u"us-east-1b", kernel_id=u"k-1234", |
400 | + ramdisk_id=u"r-1234", subnet_id="subnet-a72d829f") |
401 | + self.assertEqual( |
402 | + str(error), |
403 | + "You must specify the security_group_ids with the subnet_id" |
404 | + ) |
405 | + |
406 | + def test_run_instances_without_subnet_and_secgroups(self): |
407 | + creds = AWSCredentials("foo", "bar") |
408 | + ec2 = client.EC2Client(creds) |
409 | + error = self.assertRaises(ValueError, ec2.run_instances, "ami-1234", 1, 2, |
410 | + key_name=u"default", user_data=u"foo", instance_type=u"m1.small", |
411 | + availability_zone=u"us-east-1b", kernel_id=u"k-1234", |
412 | + ramdisk_id=u"r-1234") |
413 | + self.assertEqual( |
414 | + str(error), |
415 | + ("You must specify either the subnet_id and " |
416 | + "security_group_ids or security_groups") |
417 | + ) |
418 | + |
419 | |
420 | class EC2ClientSecurityGroupsTestCase(TXAWSTestCase): |
421 | |
422 | @@ -400,6 +456,7 @@ |
423 | |
424 | def check_results(security_groups): |
425 | [security_group] = security_groups |
426 | + self.assertEquals(security_group.id, "sg-a1a1a1") |
427 | self.assertEquals(security_group.owner_id, |
428 | "UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM") |
429 | self.assertEquals(security_group.name, "WebServers") |
430 | @@ -440,6 +497,7 @@ |
431 | security_group = security_groups[0] |
432 | self.assertEquals(security_group.owner_id, |
433 | "UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM") |
434 | + self.assertEquals(security_group.id, "sg-a1a1a1") |
435 | self.assertEquals(security_group.name, "MessageServers") |
436 | self.assertEquals(security_group.description, "Message Servers") |
437 | self.assertEquals(security_group.allowed_groups, []) |
438 | @@ -451,6 +509,7 @@ |
439 | security_group = security_groups[1] |
440 | self.assertEquals(security_group.owner_id, |
441 | "UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM") |
442 | + self.assertEquals(security_group.id, "sg-c3c3c3") |
443 | self.assertEquals(security_group.name, "WebServers") |
444 | self.assertEquals(security_group.description, "Web Servers") |
445 | self.assertEquals([(pair.user_id, pair.group_name) |
446 | @@ -583,14 +642,45 @@ |
447 | def submit(self): |
448 | return succeed(payload.sample_create_security_group) |
449 | |
450 | + def check_result(id): |
451 | + self.assertEquals(id, "sg-1a2b3c4d") |
452 | + |
453 | creds = AWSCredentials("foo", "bar") |
454 | ec2 = client.EC2Client(creds, query_factory=StubQuery) |
455 | d = ec2.create_security_group( |
456 | "WebServers", |
457 | "The group for the web server farm.") |
458 | - return self.assertTrue(d) |
459 | - |
460 | - def test_delete_security_group(self): |
461 | + return d.addCallback(check_result) |
462 | + |
463 | + def test_create_security_group_with_VPC(self): |
464 | + class StubQuery(object): |
465 | + |
466 | + def __init__(stub, action="", creds=None, endpoint=None, |
467 | + other_params={}): |
468 | + self.assertEqual(action, "CreateSecurityGroup") |
469 | + self.assertEqual(creds.access_key, "foo") |
470 | + self.assertEqual(creds.secret_key, "bar") |
471 | + self.assertEqual(other_params, { |
472 | + "GroupName": "WebServers", |
473 | + "GroupDescription": "The group for the web server farm.", |
474 | + "VpcId": "vpc-a4f2", |
475 | + }) |
476 | + |
477 | + def submit(self): |
478 | + return succeed(payload.sample_create_security_group) |
479 | + |
480 | + def check_result(id): |
481 | + self.assertEquals(id, "sg-1a2b3c4d") |
482 | + |
483 | + creds = AWSCredentials("foo", "bar") |
484 | + ec2 = client.EC2Client(creds, query_factory=StubQuery) |
485 | + d = ec2.create_security_group( |
486 | + "WebServers", |
487 | + "The group for the web server farm.", |
488 | + "vpc-a4f2") |
489 | + return d.addCallback(check_result) |
490 | + |
491 | + def test_delete_security_group_using_name(self): |
492 | """ |
493 | L{EC2Client.delete_security_group} returns a C{Deferred} that |
494 | eventually fires with a true value, indicating the success of the |
495 | @@ -615,6 +705,40 @@ |
496 | d = ec2.delete_security_group("WebServers") |
497 | return self.assertTrue(d) |
498 | |
499 | + def test_delete_security_group_using_id(self): |
500 | + """ |
501 | + L{EC2Client.delete_security_group} returns a C{Deferred} that |
502 | + eventually fires with a true value, indicating the success of the |
503 | + operation. |
504 | + """ |
505 | + class StubQuery(object): |
506 | + |
507 | + def __init__(stub, action="", creds=None, endpoint=None, |
508 | + other_params={}): |
509 | + self.assertEqual(action, "DeleteSecurityGroup") |
510 | + self.assertEqual(creds.access_key, "foo") |
511 | + self.assertEqual(creds.secret_key, "bar") |
512 | + self.assertEqual(other_params, { |
513 | + "GroupId": "sg-a1a1a1", |
514 | + }) |
515 | + |
516 | + def submit(self): |
517 | + return succeed(payload.sample_delete_security_group) |
518 | + |
519 | + creds = AWSCredentials("foo", "bar") |
520 | + ec2 = client.EC2Client(creds, query_factory=StubQuery) |
521 | + d = ec2.delete_security_group(id="sg-a1a1a1") |
522 | + return self.assertTrue(d) |
523 | + |
524 | + def test_delete_security_group_without_id_and_name(self): |
525 | + creds = AWSCredentials("foo", "bar") |
526 | + ec2 = client.EC2Client(creds) |
527 | + error = self.assertRaises(ValueError, ec2.delete_security_group) |
528 | + self.assertEquals( |
529 | + str(error), |
530 | + "You must provide either the security group name or id", |
531 | + ) |
532 | + |
533 | def test_delete_security_group_failure(self): |
534 | """ |
535 | L{EC2Client.delete_security_group} returns a C{Deferred} that |
536 | @@ -676,9 +800,42 @@ |
537 | creds = AWSCredentials("foo", "bar") |
538 | ec2 = client.EC2Client(creds, query_factory=StubQuery) |
539 | d = ec2.authorize_security_group( |
540 | - "WebServers", source_group_name="AppServers", |
541 | - source_group_owner_id="123456789123") |
542 | - return self.assertTrue(d) |
543 | + group_name="WebServers", source_group_name="AppServers", |
544 | + source_group_owner_id="123456789123") |
545 | + return self.assertTrue(d) |
546 | + |
547 | + def test_authorize_security_group_using_group_id(self): |
548 | + class StubQuery(object): |
549 | + |
550 | + def __init__(stub, action="", creds=None, endpoint=None, |
551 | + other_params={}): |
552 | + self.assertEqual(action, "AuthorizeSecurityGroupIngress") |
553 | + self.assertEqual(creds.access_key, "foo") |
554 | + self.assertEqual(creds.secret_key, "bar") |
555 | + self.assertEqual(other_params, { |
556 | + "GroupId": "sg-a1b2c3d4e5f6", |
557 | + "SourceSecurityGroupName": "AppServers", |
558 | + "SourceSecurityGroupOwnerId": "123456789123", |
559 | + }) |
560 | + |
561 | + def submit(self): |
562 | + return succeed(payload.sample_authorize_security_group) |
563 | + |
564 | + creds = AWSCredentials("foo", "bar") |
565 | + ec2 = client.EC2Client(creds, query_factory=StubQuery) |
566 | + d = ec2.authorize_security_group( |
567 | + group_id="sg-a1b2c3d4e5f6", source_group_name="AppServers", |
568 | + source_group_owner_id="123456789123") |
569 | + return self.assertTrue(d) |
570 | + |
571 | + def test_authorize_security_group_without_group_id_and_group_name(self): |
572 | + creds = AWSCredentials("foo", "bar") |
573 | + ec2 = client.EC2Client(creds) |
574 | + error = self.assertRaises(ValueError, ec2.authorize_security_group, |
575 | + source_group_name="AppServers", source_group_owner_id="123456789123") |
576 | + self.assertEquals( |
577 | + str(error), |
578 | + "You must specify either the group name of the group id.") |
579 | |
580 | def test_authorize_security_group_with_ip_permissions(self): |
581 | """ |
582 | @@ -707,7 +864,7 @@ |
583 | creds = AWSCredentials("foo", "bar") |
584 | ec2 = client.EC2Client(creds, query_factory=StubQuery) |
585 | d = ec2.authorize_security_group( |
586 | - "WebServers", ip_protocol="tcp", from_port="22", to_port="80", |
587 | + group_name="WebServers", ip_protocol="tcp", from_port="22", to_port="80", |
588 | cidr_ip="0.0.0.0/0") |
589 | return self.assertTrue(d) |
590 | |
591 | @@ -722,16 +879,12 @@ |
592 | """ |
593 | creds = AWSCredentials("foo", "bar") |
594 | ec2 = client.EC2Client(creds) |
595 | - self.assertRaises(ValueError, ec2.authorize_security_group, |
596 | - "WebServers", ip_protocol="tcp", from_port="22") |
597 | - try: |
598 | - ec2.authorize_security_group( |
599 | - "WebServers", ip_protocol="tcp", from_port="22") |
600 | - except Exception, error: |
601 | - self.assertEquals( |
602 | - str(error), |
603 | - ("You must specify either both group parameters or all the " |
604 | - "ip parameters.")) |
605 | + error = self.assertRaises(ValueError, ec2.authorize_security_group, |
606 | + group_name="WebServers", ip_protocol="tcp", from_port="22") |
607 | + self.assertEquals( |
608 | + str(error), |
609 | + ("You must specify either both group parameters or all the " |
610 | + "ip parameters.")) |
611 | |
612 | def test_authorize_group_permission(self): |
613 | """ |
614 | @@ -822,6 +975,30 @@ |
615 | source_group_owner_id="123456789123") |
616 | return self.assertTrue(d) |
617 | |
618 | + def test_revoke_security_group_using_group_id(self): |
619 | + class StubQuery(object): |
620 | + |
621 | + def __init__(stub, action="", creds=None, endpoint=None, |
622 | + other_params={}): |
623 | + self.assertEqual(action, "RevokeSecurityGroupIngress") |
624 | + self.assertEqual(creds.access_key, "foo") |
625 | + self.assertEqual(creds.secret_key, "bar") |
626 | + self.assertEqual(other_params, { |
627 | + "GroupId": "sg-a1a1a1", |
628 | + "SourceSecurityGroupName": "AppServers", |
629 | + "SourceSecurityGroupOwnerId": "123456789123", |
630 | + }) |
631 | + |
632 | + def submit(self): |
633 | + return succeed(payload.sample_revoke_security_group) |
634 | + |
635 | + creds = AWSCredentials("foo", "bar") |
636 | + ec2 = client.EC2Client(creds, query_factory=StubQuery) |
637 | + d = ec2.revoke_security_group( |
638 | + group_id="sg-a1a1a1", source_group_name="AppServers", |
639 | + source_group_owner_id="123456789123") |
640 | + return self.assertTrue(d) |
641 | + |
642 | def test_revoke_security_group_with_ip_permissions(self): |
643 | """ |
644 | L{EC2Client.revoke_security_group} returns a C{Deferred} that |
645 | @@ -853,6 +1030,15 @@ |
646 | cidr_ip="0.0.0.0/0") |
647 | return self.assertTrue(d) |
648 | |
649 | + def test_revoke_security_group_without_group_id_and_group_name(self): |
650 | + creds = AWSCredentials("foo", "bar") |
651 | + ec2 = client.EC2Client(creds) |
652 | + error = self.assertRaises(ValueError, ec2.revoke_security_group, |
653 | + source_group_name="AppServers", source_group_owner_id="123456789123") |
654 | + self.assertEquals( |
655 | + str(error), |
656 | + "You must specify either the group name of the group id.") |
657 | + |
658 | def test_revoke_security_group_with_missing_parameters(self): |
659 | """ |
660 | L{EC2Client.revoke_security_group} returns a C{Deferred} that |
661 | @@ -864,16 +1050,12 @@ |
662 | """ |
663 | creds = AWSCredentials("foo", "bar") |
664 | ec2 = client.EC2Client(creds) |
665 | - self.assertRaises(ValueError, ec2.authorize_security_group, |
666 | - "WebServers", ip_protocol="tcp", from_port="22") |
667 | - try: |
668 | - ec2.authorize_security_group( |
669 | - "WebServers", ip_protocol="tcp", from_port="22") |
670 | - except Exception, error: |
671 | - self.assertEquals( |
672 | - str(error), |
673 | - ("You must specify either both group parameters or all the " |
674 | - "ip parameters.")) |
675 | + error = self.assertRaises(ValueError, ec2.revoke_security_group, |
676 | + group_name="WebServers", ip_protocol="tcp", from_port="22") |
677 | + self.assertEquals( |
678 | + str(error), |
679 | + ("You must specify either both group parameters or all the " |
680 | + "ip parameters.")) |
681 | |
682 | def test_revoke_group_permission(self): |
683 | """ |
684 | @@ -1561,7 +1743,7 @@ |
685 | {"AWSAccessKeyId": "foo", |
686 | "Action": "DescribeInstances", |
687 | "SignatureVersion": "2", |
688 | - "Version": "2009-11-30"}) |
689 | + "Version": "2012-08-15"}) |
690 | |
691 | def test_init_other_args_are_params(self): |
692 | query = client.Query( |
693 | @@ -1575,7 +1757,7 @@ |
694 | "InstanceId.0": "12345", |
695 | "SignatureVersion": "2", |
696 | "Timestamp": "2007-11-12T13:14:15Z", |
697 | - "Version": "2009-11-30"}) |
698 | + "Version": "2012-08-15"}) |
699 | |
700 | def test_no_timestamp_if_expires_in_other_params(self): |
701 | """ |
702 | @@ -1593,7 +1775,7 @@ |
703 | "Action": "DescribeInstances", |
704 | "SignatureVersion": "2", |
705 | "Expires": "2007-11-12T13:14:15Z", |
706 | - "Version": "2009-11-30"}) |
707 | + "Version": "2012-08-15"}) |
708 | |
709 | def test_sign(self): |
710 | query = client.Query( |
711 | @@ -1601,7 +1783,7 @@ |
712 | endpoint=self.endpoint, |
713 | time_tuple=(2007, 11, 12, 13, 14, 15, 0, 0, 0)) |
714 | query.sign() |
715 | - self.assertEqual("G4c2NtQaFNhWWT8EWPVIIOpHVr0mGUYwJVYss9krsMU=", |
716 | + self.assertEqual("c0gbkemrGEJdqxWOl2UZYaygYiBLVjrpWBs7bTN7Ndo=", |
717 | query.params["Signature"]) |
718 | |
719 | def test_old_sign(self): |
720 | @@ -1612,7 +1794,7 @@ |
721 | other_params={"SignatureVersion": "1"}) |
722 | query.sign() |
723 | self.assertEqual( |
724 | - "9xP+PIs/3QXW+4mWX6WGR4nGqfE=", query.params["Signature"]) |
725 | + "7tWrIC5VYvXOjVE+roVoyDUt2Yw=", query.params["Signature"]) |
726 | |
727 | def test_unsupported_sign(self): |
728 | query = client.Query( |
729 | |
730 | === modified file 'txaws/ec2/tests/test_model.py' |
731 | --- txaws/ec2/tests/test_model.py 2012-01-23 01:04:25 +0000 |
732 | +++ txaws/ec2/tests/test_model.py 2012-11-21 12:35:25 +0000 |
733 | @@ -8,7 +8,8 @@ |
734 | class SecurityGroupTestCase(TXAWSTestCase): |
735 | |
736 | def test_creation_defaults(self): |
737 | - group = model.SecurityGroup("name", "desc") |
738 | + group = model.SecurityGroup("sg-a3f2", "name", "desc") |
739 | + self.assertEquals(group.id, "sg-a3f2") |
740 | self.assertEquals(group.name, "name") |
741 | self.assertEquals(group.description, "desc") |
742 | self.assertEquals(group.owner_id, "") |
743 | @@ -18,14 +19,15 @@ |
744 | def test_creation_all_parameters(self): |
745 | user = "somegal24" |
746 | other_groups = [ |
747 | - model.SecurityGroup("other1", "another group 1"), |
748 | - model.SecurityGroup("other2", "another group 2")] |
749 | + model.SecurityGroup("sg-other1", "other1", "another group 1"), |
750 | + model.SecurityGroup("sg-other2", "other2", "another group 2")] |
751 | user_group_pairs = [ |
752 | model.UserIDGroupPair(user, other_groups[0].name), |
753 | model.UserIDGroupPair(user, other_groups[1].name)] |
754 | ips = [model.IPPermission("tcp", "80", "80", "10.0.1.0/24")] |
755 | group = model.SecurityGroup( |
756 | - "name", "desc", owner_id="me", groups=user_group_pairs, ips=ips) |
757 | + "id", "name", "desc", owner_id="me", groups=user_group_pairs, ips=ips) |
758 | + self.assertEquals(group.id, "id") |
759 | self.assertEquals(group.name, "name") |
760 | self.assertEquals(group.description, "desc") |
761 | self.assertEquals(group.owner_id, "me") |
762 | |
763 | === modified file 'txaws/server/tests/test_call.py' |
764 | --- txaws/server/tests/test_call.py 2012-01-27 02:10:24 +0000 |
765 | +++ txaws/server/tests/test_call.py 2012-11-21 12:35:25 +0000 |
766 | @@ -11,4 +11,4 @@ |
767 | 2009-11-30, which is the earliest version we support. |
768 | """ |
769 | call = Call() |
770 | - self.assertEqual(call.version, "2009-11-30") |
771 | + self.assertEqual(call.version, "2012-08-15") |
772 | |
773 | === modified file 'txaws/testing/payload.py' |
774 | --- txaws/testing/payload.py 2012-05-16 02:47:12 +0000 |
775 | +++ txaws/testing/payload.py 2012-11-21 12:35:25 +0000 |
776 | @@ -9,11 +9,7 @@ |
777 | <item> |
778 | <reservationId>r-cf24b1a6</reservationId> |
779 | <ownerId>123456789012</ownerId> |
780 | - <groupSet> |
781 | - <item> |
782 | - <groupId>default</groupId> |
783 | - </item> |
784 | - </groupSet> |
785 | + <groupSet/> |
786 | <instancesSet> |
787 | <item> |
788 | <instanceId>i-abcdef01</instanceId> |
789 | @@ -22,6 +18,12 @@ |
790 | <code>16</code> |
791 | <name>running</name> |
792 | </instanceState> |
793 | + <groupSet> |
794 | + <item> |
795 | + <groupId>sg-64f9eb08</groupId> |
796 | + <groupName>default</groupName> |
797 | + </item> |
798 | + </groupSet> |
799 | <privateDnsName>domU-12-31-39-03-15-11.compute-1.internal\ |
800 | </privateDnsName> |
801 | <dnsName>ec2-75-101-245-65.compute-1.amazonaws.com</dnsName> |
802 | @@ -48,11 +50,7 @@ |
803 | <item> |
804 | <reservationId>r-cf24b1a6</reservationId> |
805 | <ownerId>123456789012</ownerId> |
806 | - <groupSet> |
807 | - <item> |
808 | - <groupId>default</groupId> |
809 | - </item> |
810 | - </groupSet> |
811 | + <groupSet/> |
812 | <instancesSet> |
813 | <item> |
814 | <instanceId>i-abcdef01</instanceId> |
815 | @@ -67,6 +65,12 @@ |
816 | <privateIpAddress>10.0.0.1</privateIpAddress> |
817 | <ipAddress>75.101.245.65</ipAddress> |
818 | <reason/> |
819 | + <groupSet> |
820 | + <item> |
821 | + <groupId>sg-64f9eb08</groupId> |
822 | + <groupName>default</groupName> |
823 | + </item> |
824 | + </groupSet> |
825 | <keyName>keyname</keyName> |
826 | <amiLaunchIndex>0</amiLaunchIndex> |
827 | <productCodes> |
828 | @@ -92,18 +96,14 @@ |
829 | <RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/%s/"> |
830 | <reservationId>r-47a5402e</reservationId> |
831 | <ownerId>495219933132</ownerId> |
832 | - <groupSet> |
833 | - <item> |
834 | - <groupId>default</groupId> |
835 | - </item> |
836 | - </groupSet> |
837 | + <groupSet/> |
838 | <instancesSet> |
839 | <item> |
840 | <instanceId>i-2ba64342</instanceId> |
841 | <imageId>ami-60a54009</imageId> |
842 | <instanceState> |
843 | <code>0</code> |
844 | - <name>pending</name> |
845 | + <name>pending</name> |
846 | </instanceState> |
847 | <privateDnsName></privateDnsName> |
848 | <dnsName></dnsName> |
849 | @@ -111,6 +111,12 @@ |
850 | <amiLaunchIndex>0</amiLaunchIndex> |
851 | <instanceType>m1.small</instanceType> |
852 | <launchTime>2007-08-07T11:51:50.000Z</launchTime> |
853 | + <groupSet> |
854 | + <item> |
855 | + <groupId>sg-64f9eb08</groupId> |
856 | + <groupName>default</groupName> |
857 | + </item> |
858 | + </groupSet> |
859 | <placement> |
860 | <availabilityZone>us-east-1b</availabilityZone> |
861 | </placement> |
862 | @@ -120,7 +126,7 @@ |
863 | <imageId>ami-60a54009</imageId> |
864 | <instanceState> |
865 | <code>0</code> |
866 | - <name>pending</name> |
867 | + <name>pending</name> |
868 | </instanceState> |
869 | <privateDnsName></privateDnsName> |
870 | <dnsName></dnsName> |
871 | @@ -128,6 +134,12 @@ |
872 | <amiLaunchIndex>1</amiLaunchIndex> |
873 | <instanceType>m1.small</instanceType> |
874 | <launchTime>2007-08-07T11:51:50.000Z</launchTime> |
875 | + <groupSet> |
876 | + <item> |
877 | + <groupId>sg-64f9eb08</groupId> |
878 | + <groupName>default</groupName> |
879 | + </item> |
880 | + </groupSet> |
881 | <placement> |
882 | <availabilityZone>us-east-1b</availabilityZone> |
883 | </placement> |
884 | @@ -145,6 +157,12 @@ |
885 | <amiLaunchIndex>2</amiLaunchIndex> |
886 | <instanceType>m1.small</instanceType> |
887 | <launchTime>2007-08-07T11:51:50.000Z</launchTime> |
888 | + <groupSet> |
889 | + <item> |
890 | + <groupId>sg-64f9eb08</groupId> |
891 | + <groupName>default</groupName> |
892 | + </item> |
893 | + </groupSet> |
894 | <placement> |
895 | <availabilityZone>us-east-1b</availabilityZone> |
896 | </placement> |
897 | @@ -213,6 +231,7 @@ |
898 | <fromPort/> |
899 | </item> |
900 | </ipPermissions> |
901 | + <groupId>sg-a1a1a1</groupId> |
902 | <groupName>WebServers</groupName> |
903 | <groupDescription>Web servers</groupDescription> |
904 | <ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId> |
905 | @@ -228,6 +247,7 @@ |
906 | <securityGroupInfo> |
907 | <item> |
908 | <ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId> |
909 | + <groupId>sg-a1a1a1</groupId> |
910 | <groupName>WebServers</groupName> |
911 | <groupDescription>Web Servers</groupDescription> |
912 | <ipPermissions> |
913 | @@ -256,6 +276,7 @@ |
914 | <securityGroupInfo> |
915 | <item> |
916 | <ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId> |
917 | + <groupId>sg-a1a1a1</groupId> |
918 | <groupName>MessageServers</groupName> |
919 | <groupDescription>Message Servers</groupDescription> |
920 | <ipPermissions> |
921 | @@ -274,6 +295,7 @@ |
922 | </item> |
923 | <item> |
924 | <ownerId>UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM</ownerId> |
925 | + <groupId>sg-c3c3c3</groupId> |
926 | <groupName>WebServers</groupName> |
927 | <groupDescription>Web Servers</groupDescription> |
928 | <ipPermissions> |
929 | @@ -457,6 +479,7 @@ |
930 | sample_create_security_group = """\ |
931 | <CreateSecurityGroupResponse xmlns="http://ec2.amazonaws.com/doc/%s/"> |
932 | <return>true</return> |
933 | + <groupId>sg-1a2b3c4d</groupId> |
934 | </CreateSecurityGroupResponse> |
935 | """ % (version.ec2_api,) |
936 | |
937 | |
938 | === modified file 'txaws/version.py' |
939 | --- txaws/version.py 2012-01-24 23:18:36 +0000 |
940 | +++ txaws/version.py 2012-11-21 12:35:25 +0000 |
941 | @@ -1,3 +1,3 @@ |
942 | txaws = "0.2.3" |
943 | -ec2_api = "2009-11-30" |
944 | +ec2_api = "2012-08-15" |
945 | s3_api = "2006-03-01" |
Reviewers: mp+135397_ code.launchpad. net,
Message:
Please take a look.
Description:
client, ec2: bundling changes needed for VPC
I use this CL for patching only, original CL's are:
https:/ /codereview. appspot. com/6852064/ /codereview. appspot. com/6826065/ /codereview. appspot. com/6814123/ /codereview. appspot. com/6822097/
https:/
https:/
https:/
This one also includes a change in parsing of instance sets.
https:/ /code.launchpad .net/~francisco souza/txaws/ txaws-bundled- vpc/+merge/ 135397
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/6851093/
Affected files: base.py discover/ tests/test_ command. py tests/test_ client. py tests/test_ model.py tests/test_ call.py payload. py
A [revision details]
M txaws/client/
M txaws/client/
M txaws/ec2/client.py
M txaws/ec2/model.py
M txaws/ec2/
M txaws/ec2/
M txaws/server/
M txaws/testing/
M txaws/version.py