Repository: boto/boto

Issue:
cancel_spot_instance_requests return [Instance:None]
v.2.13.3
If i try to cancel spot request by id, for example id='sir-0f9faa32'

```
cancelled = e.conn.cancel_spot_instance_requests([id])
print cancelled
print [i.id for i in cancelled]
```

it returns 
[Instance:None]
[None]

so, i cant find out which spot request is cancelled, if i pass large list with ids and function returns me list with Nones, but less lenght

in docs written that it returns "A list of the instances terminated", but i think better to return list of cancelled requests with Ids



Discussion:
The Boto function is broken; the Amazon call doesn't return instances terminated but instead as you said a list of cancelled requests in the form of a spot instance request set.

http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-CancelSpotInstanceRequests.html says the following: "Important: Canceling a Spot Instance request does not terminate running Spot Instances associated with the request."


Resolving patch:
diff --git a/boto/ec2/connection.py b/boto/ec2/connection.py
--- a/boto/ec2/connection.py
+++ b/boto/ec2/connection.py
@@ -1516,7 +1516,7 @@ def cancel_spot_instance_requests(self, request_ids, dry_run=False):
         if dry_run:
             params['DryRun'] = 'true'
         return self.get_list('CancelSpotInstanceRequests', params,
-                             [('item', Instance)], verb='POST')
+                             [('item', SpotInstanceRequest)], verb='POST')
 
     def get_spot_datafeed_subscription(self, dry_run=False):
         """


Test patch:
diff --git a/tests/unit/ec2/test_spotinstance.py b/tests/unit/ec2/test_spotinstance.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/ec2/test_spotinstance.py
@@ -0,0 +1,42 @@
+from tests.unit import AWSMockServiceTestCase
+
+from boto.ec2.connection import EC2Connection
+
+
+class TestCancelSpotInstanceRequests(AWSMockServiceTestCase):
+
+    connection_class = EC2Connection
+
+    def default_body(self):
+        return """
+            <CancelSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-01/">
+              <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+              <spotInstanceRequestSet>
+                <item>
+                  <spotInstanceRequestId>sir-1a2b3c4d</spotInstanceRequestId>
+                  <state>cancelled</state>
+                </item>
+                <item>
+                  <spotInstanceRequestId>sir-9f8e7d6c</spotInstanceRequestId>
+                  <state>cancelled</state>
+                </item>
+              </spotInstanceRequestSet>
+            </CancelSpotInstanceRequestsResponse>
+        """
+
+    def test_cancel_spot_instance_requests(self):
+        self.set_http_response(status_code=200)
+        response = self.service_connection.cancel_spot_instance_requests(['sir-1a2b3c4d',
+                                                                          'sir-9f8e7d6c'])
+        self.assert_request_parameters({
+            'Action': 'CancelSpotInstanceRequests',
+            'SpotInstanceRequestId.1': 'sir-1a2b3c4d',
+            'SpotInstanceRequestId.2': 'sir-9f8e7d6c'},
+            ignore_params_values=['AWSAccessKeyId', 'SignatureMethod',
+                                  'SignatureVersion', 'Timestamp',
+                                  'Version'])
+        self.assertEqual(len(response), 2)
+        self.assertEqual(response[0].id, 'sir-1a2b3c4d')
+        self.assertEqual(response[0].state, 'cancelled')
+        self.assertEqual(response[1].id, 'sir-9f8e7d6c')
+        self.assertEqual(response[1].state, 'cancelled')