Makes scheduler hints and disk config xml correct

The scheduler hints and disk config extensions were not using
proper prefixes when deserializing xml. This patch modifes
them to deserialize properly. It leaves the old deserialization
in place as well so anyone using the broken implementation
will continue to work.

It also updates the api samples to use the new format. Note that
the proper fix required changing the alias for the scheduler hints
extension, since the alias is used for xml, so the samples had
to be moved.

Finally it fixes an issue with deserialization, allowing it to
support multiple hints with the same name.

Part of bug 1050997

Change-Id: I9969582d65d44de25388f07b6d2013fb7d093fb2
This commit is contained in:
Vishvananda Ishaya 2012-09-18 12:02:50 -07:00
parent 71c9677d80
commit 8d43c3fba1
17 changed files with 121 additions and 57 deletions

@ -0,0 +1,12 @@
<server
xmlns="http://docs.openstack.org/compute/api/v1.1"
xmlns:OS-SCH-HNT="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2"
name='new-server-test'
imageRef='70a599e0-31e7-49b7-b260-868f441e862b'
flavorRef='1'
>
<OS-SCH-HNT:scheduler_hints>
<hypervisor>xen</hypervisor>
<near>eb999657-dd6b-464e-8713-95c532ac3b18</near>
</OS-SCH-HNT:scheduler_hints>
</server>

@ -48,6 +48,14 @@
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1", "namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1",
"updated": "2011-09-14T00:00:00+00:00" "updated": "2011-09-14T00:00:00+00:00"
}, },
{
"alias": "OS-SCH-HNT",
"description": "Pass arbitrary key/value pairs to the scheduler",
"links": [],
"name": "SchedulerHints",
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"updated": "2011-07-19T00:00:00+00:00"
},
{ {
"alias": "os-admin-actions", "alias": "os-admin-actions",
"description": "Enable admin-only server actions\n\n Actions include: pause, unpause, suspend, resume, migrate,\n resetNetwork, injectNetworkInfo, lock, unlock, createBackup\n ", "description": "Enable admin-only server actions\n\n Actions include: pause, unpause, suspend, resume, migrate,\n resetNetwork, injectNetworkInfo, lock, unlock, createBackup\n ",
@ -264,14 +272,6 @@
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1", "namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
"updated": "2011-08-18T00:00:00+00:00" "updated": "2011-08-18T00:00:00+00:00"
}, },
{
"alias": "os-scheduler-hints",
"description": "Pass arbitrary key/value pairs to the scheduler",
"links": [],
"name": "SchedulerHints",
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"updated": "2011-07-19T00:00:00+00:00"
},
{ {
"alias": "os-security-groups", "alias": "os-security-groups",
"description": "Security group support", "description": "Security group support",

@ -18,6 +18,9 @@
<extension alias="OS-FLV-EXT-DATA" updated="2011-09-14T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1" name="FlavorExtraData"> <extension alias="OS-FLV-EXT-DATA" updated="2011-09-14T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1" name="FlavorExtraData">
<description>Provide additional data for flavors</description> <description>Provide additional data for flavors</description>
</extension> </extension>
<extension alias="OS-SCH-HNT" updated="2011-07-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2" name="SchedulerHints">
<description>Pass arbitrary key/value pairs to the scheduler</description>
</extension>
<extension alias="os-admin-actions" updated="2011-09-20T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/admin-actions/api/v1.1" name="AdminActions"> <extension alias="os-admin-actions" updated="2011-09-20T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/admin-actions/api/v1.1" name="AdminActions">
<description>Enable admin-only server actions <description>Enable admin-only server actions
@ -113,9 +116,6 @@
<extension alias="os-rescue" updated="2011-08-18T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue"> <extension alias="os-rescue" updated="2011-08-18T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
<description>Instance rescue mode</description> <description>Instance rescue mode</description>
</extension> </extension>
<extension alias="os-scheduler-hints" updated="2011-07-19T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2" name="SchedulerHints">
<description>Pass arbitrary key/value pairs to the scheduler</description>
</extension>
<extension alias="os-security-groups" updated="2011-07-21T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups"> <extension alias="os-security-groups" updated="2011-07-21T00:00:00+00:00" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
<description>Security group support</description> <description>Security group support</description>
</extension> </extension>

@ -1,10 +0,0 @@
<server
name='new-server-test'
imageRef='70a599e0-31e7-49b7-b260-868f441e862b'
flavorRef='1'
>
<scheduler_hints>
<hypervisor>xen</hypervisor>
<near>eb999657-dd6b-464e-8713-95c532ac3b18</near>
</scheduler_hints>
</server>

@ -29,13 +29,13 @@ class SchedulerHintsController(wsgi.Controller):
def _extract_scheduler_hints(body): def _extract_scheduler_hints(body):
hints = {} hints = {}
attr = '%s:scheduler_hints' % Scheduler_hints.alias
try: try:
if 'os:scheduler_hints' in body:
# NOTE(vish): This is for legacy support
hints.update(body['os:scheduler_hints']) hints.update(body['os:scheduler_hints'])
elif attr in body:
# Ignore if data is not present hints.update(body[attr])
except KeyError:
pass
# Fail if non-dict provided # Fail if non-dict provided
except ValueError: except ValueError:
msg = _("Malformed scheduler_hints attribute") msg = _("Malformed scheduler_hints attribute")
@ -56,7 +56,7 @@ class Scheduler_hints(extensions.ExtensionDescriptor):
"""Pass arbitrary key/value pairs to the scheduler""" """Pass arbitrary key/value pairs to the scheduler"""
name = "SchedulerHints" name = "SchedulerHints"
alias = "os-scheduler-hints" alias = "OS-SCH-HNT"
namespace = ("http://docs.openstack.org/compute/ext/" namespace = ("http://docs.openstack.org/compute/ext/"
"scheduler-hints/api/v2") "scheduler-hints/api/v2")
updated = "2011-07-19T00:00:00+00:00" updated = "2011-07-19T00:00:00+00:00"

@ -171,7 +171,7 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
scheduler_hints = self._extract_scheduler_hints(server_node) scheduler_hints = self._extract_scheduler_hints(server_node)
if scheduler_hints: if scheduler_hints:
server['os:scheduler_hints'] = scheduler_hints server['OS-SCH-HNT:scheduler_hints'] = scheduler_hints
metadata_node = self.find_first_child_named(server_node, "metadata") metadata_node = self.find_first_child_named(server_node, "metadata")
if metadata_node is not None: if metadata_node is not None:
@ -193,19 +193,34 @@ class CommonDeserializer(wsgi.MetadataXMLDeserializer):
if security_groups is not None: if security_groups is not None:
server["security_groups"] = security_groups server["security_groups"] = security_groups
# 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.
auto_disk_config = server_node.getAttribute('auto_disk_config') auto_disk_config = server_node.getAttribute('auto_disk_config')
if auto_disk_config: if auto_disk_config:
server['auto_disk_config'] = utils.bool_from_str(auto_disk_config) server['OS-DCF:diskConfig'] = utils.bool_from_str(auto_disk_config)
auto_disk_config = server_node.getAttribute('OS-DCF:diskConfig')
if auto_disk_config:
server['OS-DCF:diskConfig'] = utils.bool_from_str(auto_disk_config)
return server return server
def _extract_scheduler_hints(self, server_node): def _extract_scheduler_hints(self, server_node):
"""Marshal the scheduler hints attribute of a parsed request""" """Marshal the scheduler hints attribute of a parsed request"""
node = self.find_first_child_named(server_node, "scheduler_hints") node = self.find_first_child_named(server_node,
"OS-SCH-HNT:scheduler_hints")
# NOTE(vish): Support the os: prefix because it is what we use
# for json, even though OS-SCH-HNT: is more correct
if not node:
node = self.find_first_child_named(server_node,
"os:scheduler_hints")
if node: if node:
scheduler_hints = {} scheduler_hints = {}
for child in self.extract_elements(node): for child in self.extract_elements(node):
scheduler_hints[child.nodeName] = self.extract_text(child) scheduler_hints.setdefault(child.nodeName, [])
value = self.extract_text(child).strip()
scheduler_hints[child.nodeName].append(value)
return scheduler_hints return scheduler_hints
else: else:
return None return None
@ -774,7 +789,7 @@ class Controller(wsgi.Controller):
auto_disk_config = server_dict.get('auto_disk_config') auto_disk_config = server_dict.get('auto_disk_config')
scheduler_hints = {} scheduler_hints = {}
if self.ext_mgr.is_loaded('os-scheduler-hints'): if self.ext_mgr.is_loaded('OS-SCH-HNT'):
scheduler_hints = server_dict.get('scheduler_hints', {}) scheduler_hints = server_dict.get('scheduler_hints', {})
try: try:

@ -1972,7 +1972,7 @@ class ServersControllerCreateTest(test.TestCase):
self._test_create_extra(params) self._test_create_extra(params)
def test_create_instance_with_scheduler_hints_enabled(self): def test_create_instance_with_scheduler_hints_enabled(self):
self.ext_mgr.extensions = {'os-scheduler-hints': 'fake'} self.ext_mgr.extensions = {'OS-SCH-HNT': 'fake'}
hints = {'a': 'b'} hints = {'a': 'b'}
params = {'scheduler_hints': hints} params = {'scheduler_hints': hints}
old_create = nova.compute.api.API.create old_create = nova.compute.api.API.create
@ -3288,6 +3288,51 @@ class TestServerCreateRequestXMLDeserializer(test.TestCase):
}} }}
self.assertEquals(request['body'], expected) self.assertEquals(request['body'], expected)
def test_request_with_disk_config(self):
serial_request = """
<server xmlns="http://docs.openstack.org/compute/api/v2"
xmlns:OS-DCF="http://docs.openstack.org/compute/ext/disk_config/api/v1.1"
name="new-server-test" imageRef="1" flavorRef="1"
OS-DCF:diskConfig="True">
</server>"""
request = self.deserializer.deserialize(serial_request)
expected = {"server": {
"name": "new-server-test",
"imageRef": "1",
"flavorRef": "1",
"OS-DCF:diskConfig": True,
}}
self.assertEquals(request['body'], expected)
def test_request_with_scheduler_hints(self):
serial_request = """
<server xmlns="http://docs.openstack.org/compute/api/v2"
xmlns:OS-SCH-HNT=
"http://docs.openstack.org/compute/ext/scheduler-hints/api/v2"
name="new-server-test" imageRef="1" flavorRef="1">
<OS-SCH-HNT:scheduler_hints>
<different_host>
7329b667-50c7-46a6-b913-cb2a09dfeee0
</different_host>
<different_host>
f31efb24-34d2-43e1-8b44-316052956a39
</different_host>
</OS-SCH-HNT:scheduler_hints>
</server>"""
request = self.deserializer.deserialize(serial_request)
expected = {"server": {
"name": "new-server-test",
"imageRef": "1",
"flavorRef": "1",
"OS-SCH-HNT:scheduler_hints": {
"different_host": [
"7329b667-50c7-46a6-b913-cb2a09dfeee0",
"f31efb24-34d2-43e1-8b44-316052956a39",
]
}
}}
self.assertEquals(request['body'], expected)
class TestAddressesXMLSerialization(test.TestCase): class TestAddressesXMLSerialization(test.TestCase):

@ -0,0 +1,12 @@
<server
xmlns="http://docs.openstack.org/compute/api/v1.1"
xmlns:OS-SCH-HNT="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2"
name='new-server-test'
imageRef='%(image_id)s'
flavorRef='1'
>
<OS-SCH-HNT:scheduler_hints>
<hypervisor>xen</hypervisor>
<near>%(image_near)s</near>
</OS-SCH-HNT:scheduler_hints>
</server>

@ -48,6 +48,14 @@
"namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1", "namespace": "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1",
"updated": "%(timestamp)s" "updated": "%(timestamp)s"
}, },
{
"alias": "OS-SCH-HNT",
"description": "%(text)s",
"links": [],
"name": "SchedulerHints",
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"updated": "%(timestamp)s"
},
{ {
"alias": "os-admin-actions", "alias": "os-admin-actions",
"description": "%(text)s", "description": "%(text)s",
@ -264,14 +272,6 @@
"namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1", "namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1",
"updated": "%(timestamp)s" "updated": "%(timestamp)s"
}, },
{
"alias": "os-scheduler-hints",
"description": "%(text)s",
"links": [],
"name": "SchedulerHints",
"namespace": "http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"updated": "%(timestamp)s"
},
{ {
"alias": "os-security-groups", "alias": "os-security-groups",
"description": "%(text)s", "description": "%(text)s",

@ -18,6 +18,9 @@
<extension alias="OS-FLV-EXT-DATA" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1" name="FlavorExtraData"> <extension alias="OS-FLV-EXT-DATA" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1" name="FlavorExtraData">
<description>%(text)s</description> <description>%(text)s</description>
</extension> </extension>
<extension alias="OS-SCH-HNT" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2" name="SchedulerHints">
<description>%(text)s</description>
</extension>
<extension alias="os-admin-actions" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/admin-actions/api/v1.1" name="AdminActions"> <extension alias="os-admin-actions" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/admin-actions/api/v1.1" name="AdminActions">
<description>%(text)s</description> <description>%(text)s</description>
</extension> </extension>
@ -99,9 +102,6 @@
<extension alias="os-rescue" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue"> <extension alias="os-rescue" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/rescue/api/v1.1" name="Rescue">
<description>%(text)s</description> <description>%(text)s</description>
</extension> </extension>
<extension alias="os-scheduler-hints" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/scheduler-hints/api/v2" name="SchedulerHints">
<description>%(text)s</description>
</extension>
<extension alias="os-security-groups" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups"> <extension alias="os-security-groups" updated="%(timestamp)s" namespace="http://docs.openstack.org/compute/ext/securitygroups/api/v1.1" name="SecurityGroups">
<description>%(text)s</description> <description>%(text)s</description>
</extension> </extension>

@ -1,10 +0,0 @@
<server
name='new-server-test'
imageRef='%(image_id)s'
flavorRef='1'
>
<scheduler_hints>
<hypervisor>xen</hypervisor>
<near>%(image_near)s</near>
</scheduler_hints>
</server>