Merge lp:~franciscosouza/txaws/txaws-bundled-vpc into lp:txaws

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
Reviewer Review Type Date Requested Status
txAWS Committers Pending
Review via email: mp+135397@code.launchpad.net

Description of the change

client, ec2: bundling changes needed for VPC

I use this CL for patching only, original CL's are:

https://codereview.appspot.com/6852064/
https://codereview.appspot.com/6826065/
https://codereview.appspot.com/6814123/
https://codereview.appspot.com/6822097/

This one also includes a change in parsing of instance sets.

https://codereview.appspot.com/6851093/

To post a comment you must log in.
Revision history for this message
Chico (franciscossouza) wrote :

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/
https://codereview.appspot.com/6826065/
https://codereview.appspot.com/6814123/
https://codereview.appspot.com/6822097/

This one also includes a change in parsing of instance sets.

https://code.launchpad.net/~franciscosouza/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:
   A [revision details]
   M txaws/client/base.py
   M txaws/client/discover/tests/test_command.py
   M txaws/ec2/client.py
   M txaws/ec2/model.py
   M txaws/ec2/tests/test_client.py
   M txaws/ec2/tests/test_model.py
   M txaws/server/tests/test_call.py
   M txaws/testing/payload.py
   M txaws/version.py

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"

Subscribers

People subscribed via source and target branches