Merge lp:~fwierzbicki/txaws/empty-instances-workaround into lp:txaws

Proposed by Frank Wierzbicki
Status: Work in progress
Proposed branch: lp:~fwierzbicki/txaws/empty-instances-workaround
Merge into: lp:txaws
Diff against target: 139 lines (+62/-6)
5 files modified
txaws/ec2/client.py (+10/-1)
txaws/ec2/tests/test_client.py (+32/-1)
txaws/exception.py (+3/-2)
txaws/testing/payload.py (+9/-1)
txaws/tests/test_exception.py (+8/-1)
To merge this branch: bzr merge lp:~fwierzbicki/txaws/empty-instances-workaround
Reviewer Review Type Date Requested Status
txAWS Committers Pending
Review via email: mp+85562@code.launchpad.net

Description of the change

This branch raises a more useful exception when it gets a TerminateInstancesResponse XML that lacks an instancesSet. This will allow us to see the original xml response from cloud deck so that we can work around this behavior -- see https://bugs.launchpad.net/nova/+bug/862680 for the motivating bug.

This branch also makes the error message parsing in AWSException more robust in the face of unexpected xml.

To post a comment you must log in.
110. By Frank Wierzbicki

Populate errors for nova exception.

Unmerged revisions

110. By Frank Wierzbicki

Populate errors for nova exception.

109. By Frank Wierzbicki

Comment update.

108. By Frank Wierzbicki

Lint fixes + comment updates.

107. By Frank Wierzbicki

Make error message parsing more robust in the face of invalid error messages.

106. By Frank Wierzbicki

Raise exception instead of sending empty list for bad nova output.

105. By Frank Wierzbicki

Ugly fix for ugly nova response to terminate_instances.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'txaws/ec2/client.py'
2--- txaws/ec2/client.py 2011-08-19 16:09:39 +0000
3+++ txaws/ec2/client.py 2012-01-09 17:27:28 +0000
4@@ -629,8 +629,17 @@
5 """
6 root = XML(xml_bytes)
7 result = []
8+ instances = root.find("instancesSet")
9+ if instances is None:
10+ # At this time, Nova returns an invalid response to
11+ # terminate_instances (missing instancesSet). See
12+ # https://bugs.launchpad.net/nova/+bug/862680.
13+ error = EC2Error(xml_bytes, 500, "Invalid missing instancesSet.")
14+ error.errors = [{"Message": "MissingInstancesSet"}]
15+ raise error
16+
17 # May be a more elegant way to do this:
18- for instance in root.find("instancesSet"):
19+ for instance in instances:
20 instanceId = instance.findtext("instanceId")
21 previousState = instance.find("previousState").findtext(
22 "name")
23
24=== modified file 'txaws/ec2/tests/test_client.py'
25--- txaws/ec2/tests/test_client.py 2011-08-29 19:51:50 +0000
26+++ txaws/ec2/tests/test_client.py 2012-01-09 17:27:28 +0000
27@@ -315,6 +315,38 @@
28 d.addCallback(check_transition)
29 return d
30
31+ # At this time, Nova returns an invalid response to terminate_instances.
32+ # See https://bugs.launchpad.net/nova/+bug/862680. txaws passes down a
33+ # 500 error, but with the original xml included so a sufficiently
34+ # motivated client can still work with it.
35+ def test_nova_terminate_instances(self):
36+
37+ class StubQuery(object):
38+
39+ def __init__(stub, action="", creds=None, endpoint=None,
40+ other_params={}):
41+ self.assertEqual(action, "TerminateInstances")
42+ self.assertEqual(creds.access_key, "foo")
43+ self.assertEqual(creds.secret_key, "bar")
44+ self.assertEqual(
45+ other_params,
46+ {"InstanceId.1": "i-1234", "InstanceId.2": "i-5678"})
47+
48+ def submit(self):
49+ return succeed(payload.nova_terminate_instances_result)
50+
51+ def check_error(error):
52+ self.assertEquals(
53+ str(error), ("Error Message: MissingInstancesSet"))
54+
55+ creds = AWSCredentials("foo", "bar")
56+ endpoint = AWSServiceEndpoint(uri=EC2_ENDPOINT_US)
57+ ec2 = client.EC2Client(creds=creds, endpoint=endpoint,
58+ query_factory=StubQuery)
59+ failure = ec2.terminate_instances("i-1234", "i-5678")
60+ d = self.assertFailure(failure, EC2Error)
61+ return d.addCallback(check_error)
62+
63 def check_parsed_run_instances(self, results):
64 instance = results[0]
65 # check reservations
66@@ -634,7 +666,6 @@
67 str(error),
68 ("Error Message: Group groupID1:GroupReferredTo is used by "
69 "groups: groupID2:UsingGroup"))
70-
71 creds = AWSCredentials("foo", "bar")
72 ec2 = client.EC2Client(creds, query_factory=StubQuery)
73 failure = ec2.delete_security_group("GroupReferredTo")
74
75=== modified file 'txaws/exception.py'
76--- txaws/exception.py 2010-03-29 17:16:46 +0000
77+++ txaws/exception.py 2012-01-09 17:27:28 +0000
78@@ -118,9 +118,10 @@
79 return "Multiple EC2 Errors"
80 elif count == 0:
81 return "Empty error list"
82- else:
83+ elif "Message" in self.errors[0]:
84 return self.errors[0]["Message"]
85-
86+ else:
87+ return "Error with invalid message."
88
89
90 class AWSResponseParseError(Exception):
91
92=== modified file 'txaws/testing/payload.py'
93--- txaws/testing/payload.py 2011-08-29 19:51:50 +0000
94+++ txaws/testing/payload.py 2012-01-09 17:27:28 +0000
95@@ -177,6 +177,15 @@
96 </TerminateInstancesResponse>
97 """ % (version.ec2_api,)
98
99+# Nova does not respond properly to terminate instances, and contains no
100+# instancesSet element. See
101+# https://bugs.launchpad.net/nova/+bug/862680 for more.
102+nova_terminate_instances_result = """\
103+<TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/%s/">
104+ <requestId>7ca9d4fd-db86-44da-a622-50d78f550701</requestId>
105+ <return>true</return>
106+</TerminateInstancesResponse>
107+""" % (version.ec2_api,)
108
109 sample_describe_security_groups_with_openstack = """\
110 <?xml version="1.0"?>
111@@ -985,4 +994,3 @@
112 </Grant>
113 </AccessControlList>
114 </AccessControlPolicy>"""
115-
116
117=== modified file 'txaws/tests/test_exception.py'
118--- txaws/tests/test_exception.py 2010-03-29 17:16:46 +0000
119+++ txaws/tests/test_exception.py 2012-01-09 17:27:28 +0000
120@@ -7,7 +7,6 @@
121 from txaws.exception import AWSResponseParseError
122 from txaws.util import XML
123
124-
125 REQUEST_ID = "0ef9fc37-6230-4d81-b2e6-1b36277d4247"
126
127
128@@ -112,3 +111,11 @@
129 error._set_500_error(XML(xml))
130 self.assertEquals(error.errors[0]["Code"], "500")
131 self.assertEquals(error.errors[0]["Message"], "Oops")
132+
133+ def test_broken_error_node(self):
134+ xml = "<Error><Code>500</Code><Broken>Oops</Broken></Error>"
135+ #error = AWSError(nova_terminate_instances_result, 500)
136+ error = AWSError(xml, 500)
137+ self.assertEquals(1, len(error.errors))
138+ self.assertEquals("Error Message: Error with invalid message.",
139+ str(error))

Subscribers

People subscribed via source and target branches