Repository: boto/boto

Issue:
Exception triggered by TerminateInstances against wrong API implementation
While working with boto against an OpenStack Essex cloud, we discovered that TerminateInstances would fail with:

```
Traceback (most recent call last):
  File "./terminate_one_instance.py", line 25, in <module>
    conn.terminate_instances([sys.argv[1]])
  File "/Users/priteau/.virtualenvs/boto-new/lib/python2.7/site-packages/boto/ec2/connection.py", line 888, in terminate_instances
    [('item', Instance)], verb='POST')
  File "/Users/priteau/.virtualenvs/boto-new/lib/python2.7/site-packages/boto/connection.py", line 1077, in get_list
    xml.sax.parseString(body, h)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/sax/__init__.py", line 49, in parseString
    parser.parse(inpsrc)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/sax/expatreader.py", line 107, in parse
    xmlreader.IncrementalParser.parse(self, source)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/sax/xmlreader.py", line 123, in parse
    self.feed(buffer)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/sax/expatreader.py", line 207, in feed
    self._parser.Parse(data, isFinal)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/sax/expatreader.py", line 304, in end_element
    self._cont_handler.endElement(name)
  File "/Users/priteau/.virtualenvs/boto-new/lib/python2.7/site-packages/boto/handler.py", line 39, in endElement
    self.nodes[-1][1].endElement(name, self.current_text, self.connection)
  File "/Users/priteau/.virtualenvs/boto-new/lib/python2.7/site-packages/boto/ec2/instance.py", line 347, in endElement
    self.state_code = int(value)
AttributeError: can't set attribute
```

This is caused by a bug in this version of OpenStack, which uses shutdownState instead of currentState. Here is an example of XML response sent by OpenStack Essex:

```
<?xml version="1.0" ?><TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/"><requestId>req-59a9ad52-0434-470c-ad48-4f89ded3a03e</requestId><instancesSet><item><instanceId>i-000043a2</instanceId><shutdownState><code>16</code><name>running</name></shutdownState><previousState><code>16</code><name>running</name></previousState></item></instancesSet></TerminateInstancesResponse>
```

It is fixed in more recent versions: https://github.com/openstack/nova/commit/0fa3f0e6da4e8f1d5d09e6797bb5eae806ece400

However, there is code in boto that tries to set state and state_code without a corresponding setter: https://github.com/boto/boto/blob/8ff08e596dd7d7ef37f6c5db465fcbe4bb3e025c/boto/ec2/instance.py#L343

You might not want to support an old version of OpenStack, but this code in boto is still incorrect. It would be fixed by removing the part parsing "code" and "name".



Discussion:

Resolving patch:
diff --git a/boto/ec2/instance.py b/boto/ec2/instance.py
--- a/boto/ec2/instance.py
+++ b/boto/ec2/instance.py
@@ -340,14 +340,6 @@ def endElement(self, name, value, connection):
             self.ami_launch_index = value
         elif name == 'previousState':
             self.previous_state = value
-        elif name == 'name':
-            self.state = value
-        elif name == 'code':
-            try:
-                self.state_code = int(value)
-            except ValueError:
-                boto.log.warning('Error converting code (%s) to int' % value)
-                self.state_code = value
         elif name == 'instanceType':
             self.instance_type = value
         elif name == 'rootDeviceName':


Test patch:
diff --git a/tests/unit/ec2/test_connection.py b/tests/unit/ec2/test_connection.py
--- a/tests/unit/ec2/test_connection.py
+++ b/tests/unit/ec2/test_connection.py
@@ -1192,5 +1192,32 @@ def test_vm_type_hvm(self):
             'Version'
         ])
 
+
+class TestTerminateInstances(TestEC2ConnectionBase):
+    def default_body(self):
+        return """<?xml version="1.0" ?>
+            <TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
+                <requestId>req-59a9ad52-0434-470c-ad48-4f89ded3a03e</requestId>
+                <instancesSet>
+                    <item>
+                        <instanceId>i-000043a2</instanceId>
+                        <shutdownState>
+                            <code>16</code>
+                            <name>running</name>
+                        </shutdownState>
+                        <previousState>
+                            <code>16</code>
+                            <name>running</name>
+                        </previousState>
+                    </item>
+                </instancesSet>
+            </TerminateInstancesResponse>
+        """
+
+    def test_terminate_bad_response(self):
+        self.set_http_response(status_code=200)
+        self.ec2.terminate_instances('foo')
+
+
 if __name__ == '__main__':
     unittest.main()