diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index c9bc4430e20..9a623072e5e 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -193,6 +193,12 @@ def _extract_server(self, node): if security_groups is not None: server["security_groups"] = security_groups + # NOTE(vish): this is not namespaced in json, so leave it without a + # namespace for now + block_device_mapping = self._extract_block_device_mapping(server_node) + if block_device_mapping is not None: + server["block_device_mapping"] = block_device_mapping + # NOTE(vish): Support this incorrect version because it was in the code # base for a while and we don't want to accidentally break # anyone that might be using it. @@ -206,6 +212,31 @@ def _extract_server(self, node): return server + def _extract_block_device_mapping(self, server_node): + """Marshal the block_device_mapping node of a parsed request""" + node = self.find_first_child_named(server_node, "block_device_mapping") + if node: + block_device_mapping = [] + for child in self.extract_elements(node): + if child.nodeName != "mapping": + continue + mapping = {} + attributes = ["volume_id", "snapshot_id", "device_name", + "virtual_name", "volume_size"] + for attr in attributes: + value = child.getAttribute(attr) + if value: + mapping[attr] = value + attributes = ["delete_on_termination", "no_device"] + for attr in attributes: + value = child.getAttribute(attr) + if value: + mapping[attr] = utils.bool_from_str(value) + block_device_mapping.append(mapping) + return block_device_mapping + else: + return None + def _extract_scheduler_hints(self, server_node): """Marshal the scheduler hints attribute of a parsed request""" node = self.find_first_child_named(server_node, diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index bde59592b6f..70b28c77231 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -3333,6 +3333,46 @@ def test_request_with_scheduler_hints(self): }} self.assertEquals(request['body'], expected) + def test_request_with_block_device_mapping(self): + serial_request = """ + + + + + + + """ + request = self.deserializer.deserialize(serial_request) + expected = {"server": { + "name": "new-server-test", + "imageRef": "1", + "flavorRef": "1", + "block_device_mapping": [ + { + "volume_id": "7329b667-50c7-46a6-b913-cb2a09dfeee0", + "device_name": "/dev/vda", + "virtual_name": "root", + "delete_on_termination": False, + }, + { + "snapshot_id": "f31efb24-34d2-43e1-8b44-316052956a39", + "device_name": "/dev/vdb", + "virtual_name": "ephemeral0", + "delete_on_termination": False, + }, + { + "device_name": "/dev/vdc", + "no_device": True, + }, + ] + }} + self.assertEquals(request['body'], expected) + class TestAddressesXMLSerialization(test.TestCase):