Nuke XML support from Nova REST API - Phase 2

In I5a580fc323c3809790b4a68a9f8f8129ecdc2cf0 we switched off XML support. In
this review we entirely remove all support for XML in the API.

Change-Id: Id384d0e8d350fdd68ed03c83b94f6e558d53eb28
This commit is contained in:
Davanum Srinivas 2014-12-08 08:32:02 -05:00 committed by Davanum Srinivas (dims)
parent 3ae2ddd4a2
commit 8454a2b4f3
79 changed files with 70 additions and 5348 deletions

View File

@ -23,8 +23,6 @@ import six.moves.urllib.parse as urlparse
import webob import webob
from webob import exc from webob import exc
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import task_states from nova.compute import task_states
from nova.compute import utils as compute_utils from nova.compute import utils as compute_utils
from nova.compute import vm_states from nova.compute import vm_states
@ -419,78 +417,6 @@ def raise_http_conflict_for_instance_invalid_state(exc, action, server_id):
raise webob.exc.HTTPConflict(explanation=msg) raise webob.exc.HTTPConflict(explanation=msg)
class MetadataDeserializer(wsgi.MetadataXMLDeserializer):
def deserialize(self, text):
dom = xmlutil.safe_minidom_parse_string(text)
metadata_node = self.find_first_child_named(dom, "metadata")
metadata = self.extract_metadata(metadata_node)
return {'body': {'metadata': metadata}}
class MetaItemDeserializer(wsgi.MetadataXMLDeserializer):
def deserialize(self, text):
dom = xmlutil.safe_minidom_parse_string(text)
metadata_item = self.extract_metadata(dom)
return {'body': {'meta': metadata_item}}
class MetadataXMLDeserializer(wsgi.XMLDeserializer):
def extract_metadata(self, metadata_node):
"""Marshal the metadata attribute of a parsed request."""
if metadata_node is None:
return {}
metadata = {}
for meta_node in self.find_children_named(metadata_node, "meta"):
key = meta_node.getAttribute("key")
metadata[key] = self.extract_text(meta_node)
return metadata
def _extract_metadata_container(self, datastring):
dom = xmlutil.safe_minidom_parse_string(datastring)
metadata_node = self.find_first_child_named(dom, "metadata")
metadata = self.extract_metadata(metadata_node)
return {'body': {'metadata': metadata}}
def create(self, datastring):
return self._extract_metadata_container(datastring)
def update_all(self, datastring):
return self._extract_metadata_container(datastring)
def update(self, datastring):
dom = xmlutil.safe_minidom_parse_string(datastring)
metadata_item = self.extract_metadata(dom)
return {'body': {'meta': metadata_item}}
metadata_nsmap = {None: xmlutil.XMLNS_V11}
class MetaItemTemplate(xmlutil.TemplateBuilder):
def construct(self):
sel = xmlutil.Selector('meta', xmlutil.get_items, 0)
root = xmlutil.TemplateElement('meta', selector=sel)
root.set('key', 0)
root.text = 1
return xmlutil.MasterTemplate(root, 1, nsmap=metadata_nsmap)
class MetadataTemplateElement(xmlutil.TemplateElement):
def will_render(self, datum):
return True
class MetadataTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = MetadataTemplateElement('metadata', selector='metadata')
elem = xmlutil.SubTemplateElement(root, 'meta',
selector=xmlutil.get_items)
elem.set('key', 0)
elem.text = 1
return xmlutil.MasterTemplate(root, 1, nsmap=metadata_nsmap)
def check_snapshots_enabled(f): def check_snapshots_enabled(f):
@functools.wraps(f) @functools.wraps(f)
def inner(*args, **kwargs): def inner(*args, **kwargs):

View File

@ -17,7 +17,6 @@ import webob
from webob import exc from webob import exc
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.console import api as console_api from nova.console import api as console_api
from nova import exception from nova import exception
@ -44,47 +43,12 @@ def _translate_detail_keys(cons):
return dict(console=info) return dict(console=info)
class ConsoleTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('console', selector='console')
id_elem = xmlutil.SubTemplateElement(root, 'id', selector='id')
id_elem.text = xmlutil.Selector()
port_elem = xmlutil.SubTemplateElement(root, 'port', selector='port')
port_elem.text = xmlutil.Selector()
host_elem = xmlutil.SubTemplateElement(root, 'host', selector='host')
host_elem.text = xmlutil.Selector()
passwd_elem = xmlutil.SubTemplateElement(root, 'password',
selector='password')
passwd_elem.text = xmlutil.Selector()
constype_elem = xmlutil.SubTemplateElement(root, 'console_type',
selector='console_type')
constype_elem.text = xmlutil.Selector()
return xmlutil.MasterTemplate(root, 1)
class ConsolesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('consoles')
console = xmlutil.SubTemplateElement(root, 'console',
selector='consoles')
console.append(ConsoleTemplate())
return xmlutil.MasterTemplate(root, 1)
class Controller(object): class Controller(object):
"""The Consoles controller for the OpenStack API.""" """The Consoles controller for the OpenStack API."""
def __init__(self): def __init__(self):
self.console_api = console_api.API() self.console_api = console_api.API()
@wsgi.serializers(xml=ConsolesTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns a list of consoles for this instance.""" """Returns a list of consoles for this instance."""
consoles = self.console_api.get_consoles( consoles = self.console_api.get_consoles(
@ -102,7 +66,6 @@ class Controller(object):
except exception.InstanceNotFound as e: except exception.InstanceNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
@wsgi.serializers(xml=ConsoleTemplate)
def show(self, req, server_id, id): def show(self, req, server_id, id):
"""Shows in-depth information on a specific console.""" """Shows in-depth information on a specific console."""
try: try:

View File

@ -16,8 +16,6 @@
import webob.exc import webob.exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import objects from nova import objects
@ -27,21 +25,6 @@ from nova import utils
authorize = extensions.extension_authorizer('compute', 'agents') authorize = extensions.extension_authorizer('compute', 'agents')
class AgentsIndexTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('agents')
elem = xmlutil.SubTemplateElement(root, 'agent', selector='agents')
elem.set('hypervisor')
elem.set('os')
elem.set('architecture')
elem.set('version')
elem.set('md5hash')
elem.set('agent_id')
elem.set('url')
return xmlutil.MasterTemplate(root, 1)
class AgentController(object): class AgentController(object):
"""The agent is talking about guest agent.The host can use this for """The agent is talking about guest agent.The host can use this for
things like accessing files on the disk, configuring networking, things like accessing files on the disk, configuring networking,
@ -64,7 +47,6 @@ class AgentController(object):
http://wiki.openstack.org/GuestAgent http://wiki.openstack.org/GuestAgent
http://wiki.openstack.org/GuestAgentXenStoreCommunication http://wiki.openstack.org/GuestAgentXenStoreCommunication
""" """
@wsgi.serializers(xml=AgentsIndexTemplate)
def index(self, req): def index(self, req):
"""Return a list of all agent builds. Filter by hypervisor.""" """Return a list of all agent builds. Filter by hypervisor."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -18,7 +18,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -30,25 +29,12 @@ authorize = extensions.extension_authorizer('compute',
'os-assisted-volume-snapshots') 'os-assisted-volume-snapshots')
def make_snapshot(elem):
elem.set('id')
elem.set('volumeId')
class SnapshotTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('snapshot', selector='snapshot')
make_snapshot(root)
return xmlutil.MasterTemplate(root, 1)
class AssistedVolumeSnapshotsController(wsgi.Controller): class AssistedVolumeSnapshotsController(wsgi.Controller):
def __init__(self): def __init__(self):
self.compute_api = compute.API() self.compute_api = compute.API()
super(AssistedVolumeSnapshotsController, self).__init__() super(AssistedVolumeSnapshotsController, self).__init__()
@wsgi.serializers(xml=SnapshotTemplate)
def create(self, req, body): def create(self, req, body):
"""Creates a new snapshot.""" """Creates a new snapshot."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -14,10 +14,8 @@
from oslo.config import cfg from oslo.config import cfg
from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import availability_zones from nova import availability_zones
from nova import objects from nova import objects
from nova import servicegroup from nova import servicegroup
@ -30,43 +28,6 @@ authorize_detail = extensions.extension_authorizer('compute',
'availability_zone:detail') 'availability_zone:detail')
def make_availability_zone(elem):
elem.set('name', 'zoneName')
zoneStateElem = xmlutil.SubTemplateElement(elem, 'zoneState',
selector='zoneState')
zoneStateElem.set('available')
hostsElem = xmlutil.SubTemplateElement(elem, 'hosts', selector='hosts')
hostElem = xmlutil.SubTemplateElement(hostsElem, 'host',
selector=xmlutil.get_items)
hostElem.set('name', 0)
svcsElem = xmlutil.SubTemplateElement(hostElem, 'services', selector=1)
svcElem = xmlutil.SubTemplateElement(svcsElem, 'service',
selector=xmlutil.get_items)
svcElem.set('name', 0)
svcStateElem = xmlutil.SubTemplateElement(svcElem, 'serviceState',
selector=1)
svcStateElem.set('available')
svcStateElem.set('active')
svcStateElem.set('updated_at')
# Attach metadata node
elem.append(common.MetadataTemplate())
class AvailabilityZonesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('availabilityZones')
zoneElem = xmlutil.SubTemplateElement(root, 'availabilityZone',
selector='availabilityZoneInfo')
make_availability_zone(zoneElem)
return xmlutil.MasterTemplate(root, 1, nsmap={
Availability_zone.alias: Availability_zone.namespace})
class AvailabilityZoneController(wsgi.Controller): class AvailabilityZoneController(wsgi.Controller):
"""The Availability Zone API controller for the OpenStack API.""" """The Availability Zone API controller for the OpenStack API."""
@ -139,7 +100,6 @@ class AvailabilityZoneController(wsgi.Controller):
"hosts": None}) "hosts": None})
return {'availabilityZoneInfo': result} return {'availabilityZoneInfo': result}
@wsgi.serializers(xml=AvailabilityZonesTemplate)
def index(self, req): def index(self, req):
"""Returns a summary list of availability zone.""" """Returns a summary list of availability zone."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -147,7 +107,6 @@ class AvailabilityZoneController(wsgi.Controller):
return self._describe_availability_zones(context) return self._describe_availability_zones(context)
@wsgi.serializers(xml=AvailabilityZonesTemplate)
def detail(self, req): def detail(self, req):
"""Returns a detailed list of availability zone.""" """Returns a detailed list of availability zone."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -21,7 +21,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _ from nova.i18n import _
from nova.openstack.common import log as logging from nova.openstack.common import log as logging
@ -58,25 +57,6 @@ CONF.import_opt('compute_driver', 'nova.virt.driver')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
def _interface_dict(interface_ref):
d = {}
for f in interface_fields:
d[f] = interface_ref.get(f)
return d
def _make_node_elem(elem):
for f in node_fields:
elem.set(f)
for f in node_ext_fields:
elem.set(f)
def _make_interface_elem(elem):
for f in interface_fields:
elem.set(f)
def _get_ironic_client(): def _get_ironic_client():
"""return an Ironic client.""" """return an Ironic client."""
# TODO(NobodyCam): Fix insecure setting # TODO(NobodyCam): Fix insecure setting
@ -99,31 +79,6 @@ def _no_ironic_proxy(cmd):
"action.") % {'cmd': cmd}) "action.") % {'cmd': cmd})
class NodeTemplate(xmlutil.TemplateBuilder):
def construct(self):
node_elem = xmlutil.TemplateElement('node', selector='node')
_make_node_elem(node_elem)
ifs_elem = xmlutil.TemplateElement('interfaces')
if_elem = xmlutil.SubTemplateElement(ifs_elem, 'interface',
selector='interfaces')
_make_interface_elem(if_elem)
node_elem.append(ifs_elem)
return xmlutil.MasterTemplate(node_elem, 1)
class NodesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('nodes')
node_elem = xmlutil.SubTemplateElement(root, 'node', selector='nodes')
_make_node_elem(node_elem)
ifs_elem = xmlutil.TemplateElement('interfaces')
if_elem = xmlutil.SubTemplateElement(ifs_elem, 'interface',
selector='interfaces')
_make_interface_elem(if_elem)
node_elem.append(ifs_elem)
return xmlutil.MasterTemplate(root, 1)
class BareMetalNodeController(wsgi.Controller): class BareMetalNodeController(wsgi.Controller):
"""The Bare-Metal Node API controller for the OpenStack API. """The Bare-Metal Node API controller for the OpenStack API.
@ -145,7 +100,6 @@ class BareMetalNodeController(wsgi.Controller):
d[f] = node_ref.get(f) d[f] = node_ref.get(f)
return d return d
@wsgi.serializers(xml=NodesTemplate)
def index(self, req): def index(self, req):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -164,7 +118,6 @@ class BareMetalNodeController(wsgi.Controller):
nodes.append(node) nodes.append(node)
return {'nodes': nodes} return {'nodes': nodes}
@wsgi.serializers(xml=NodeTemplate)
def show(self, req, id): def show(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -184,7 +137,6 @@ class BareMetalNodeController(wsgi.Controller):
node['interfaces'].append({'address': port.address}) node['interfaces'].append({'address': port.address})
return {'node': node} return {'node': node}
@wsgi.serializers(xml=NodeTemplate)
def create(self, req, body): def create(self, req, body):
_no_ironic_proxy("port-create") _no_ironic_proxy("port-create")

View File

@ -26,7 +26,6 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.cells import rpcapi as cells_rpcapi from nova.cells import rpcapi as cells_rpcapi
from nova.compute import api as compute from nova.compute import api as compute
from nova import exception from nova import exception
@ -41,95 +40,9 @@ CONF.import_opt('capabilities', 'nova.cells.opts', group='cells')
authorize = extensions.extension_authorizer('compute', 'cells') authorize = extensions.extension_authorizer('compute', 'cells')
def make_cell(elem):
elem.set('name')
elem.set('username')
elem.set('type')
elem.set('rpc_host')
elem.set('rpc_port')
caps = xmlutil.SubTemplateElement(elem, 'capabilities',
selector='capabilities')
cap = xmlutil.SubTemplateElement(caps, xmlutil.Selector(0),
selector=xmlutil.get_items)
cap.text = 1
make_capacity(elem)
def make_capacity(cell):
def get_units_by_mb(capacity_info):
return capacity_info['units_by_mb'].items()
capacity = xmlutil.SubTemplateElement(cell, 'capacities',
selector='capacities')
ram_free = xmlutil.SubTemplateElement(capacity, 'ram_free',
selector='ram_free')
ram_free.set('total_mb', 'total_mb')
unit_by_mb = xmlutil.SubTemplateElement(ram_free, 'unit_by_mb',
selector=get_units_by_mb)
unit_by_mb.set('mb', 0)
unit_by_mb.set('unit', 1)
disk_free = xmlutil.SubTemplateElement(capacity, 'disk_free',
selector='disk_free')
disk_free.set('total_mb', 'total_mb')
unit_by_mb = xmlutil.SubTemplateElement(disk_free, 'unit_by_mb',
selector=get_units_by_mb)
unit_by_mb.set('mb', 0)
unit_by_mb.set('unit', 1)
cell_nsmap = {None: wsgi.XMLNS_V10} cell_nsmap = {None: wsgi.XMLNS_V10}
class CellTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('cell', selector='cell')
make_cell(root)
return xmlutil.MasterTemplate(root, 1, nsmap=cell_nsmap)
class CellsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('cells')
elem = xmlutil.SubTemplateElement(root, 'cell', selector='cells')
make_cell(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=cell_nsmap)
class CellDeserializer(wsgi.XMLDeserializer):
"""Deserializer to handle xml-formatted cell create requests."""
def _extract_capabilities(self, cap_node):
caps = {}
for cap in cap_node.childNodes:
cap_name = cap.tagName
caps[cap_name] = self.extract_text(cap)
return caps
def _extract_cell(self, node):
cell = {}
cell_node = self.find_first_child_named(node, 'cell')
extract_fns = {
'capabilities': self._extract_capabilities,
'rpc_port': lambda child: int(self.extract_text(child)),
}
for child in cell_node.childNodes:
name = child.tagName
extract_fn = extract_fns.get(name, self.extract_text)
cell[name] = extract_fn(child)
return cell
def default(self, string):
"""Deserialize an xml-formatted cell create request."""
node = xmlutil.safe_minidom_parse_string(string)
return {'body': {'cell': self._extract_cell(node)}}
def _filter_keys(item, keys): def _filter_keys(item, keys):
"""Filters all model attributes except for keys """Filters all model attributes except for keys
item is a dict item is a dict
@ -197,7 +110,6 @@ class Controller(object):
items = [_scrub_cell(item, detail=detail) for item in items] items = [_scrub_cell(item, detail=detail) for item in items]
return dict(cells=items) return dict(cells=items)
@wsgi.serializers(xml=CellsTemplate)
@common.check_cells_enabled @common.check_cells_enabled
def index(self, req): def index(self, req):
"""Return all cells in brief.""" """Return all cells in brief."""
@ -205,7 +117,6 @@ class Controller(object):
authorize(ctxt) authorize(ctxt)
return self._get_cells(ctxt, req) return self._get_cells(ctxt, req)
@wsgi.serializers(xml=CellsTemplate)
@common.check_cells_enabled @common.check_cells_enabled
def detail(self, req): def detail(self, req):
"""Return all cells in detail.""" """Return all cells in detail."""
@ -213,7 +124,6 @@ class Controller(object):
authorize(ctxt) authorize(ctxt)
return self._get_cells(ctxt, req, detail=True) return self._get_cells(ctxt, req, detail=True)
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled @common.check_cells_enabled
def info(self, req): def info(self, req):
"""Return name and capabilities for this cell.""" """Return name and capabilities for this cell."""
@ -232,7 +142,6 @@ class Controller(object):
'capabilities': cell_capabs} 'capabilities': cell_capabs}
return dict(cell=cell) return dict(cell=cell)
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled @common.check_cells_enabled
def capacities(self, req, id=None): def capacities(self, req, id=None):
"""Return capacities for a given cell or all cells.""" """Return capacities for a given cell or all cells."""
@ -252,7 +161,6 @@ class Controller(object):
return dict(cell={"capacities": capacities}) return dict(cell={"capacities": capacities})
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled @common.check_cells_enabled
def show(self, req, id): def show(self, req, id):
"""Return data about the given cell name. 'id' is a cell name.""" """Return data about the given cell name. 'id' is a cell name."""
@ -344,8 +252,6 @@ class Controller(object):
# Now set the transport URL # Now set the transport URL
cell['transport_url'] = str(transport_url) cell['transport_url'] = str(transport_url)
@wsgi.serializers(xml=CellTemplate)
@wsgi.deserializers(xml=CellDeserializer)
@common.check_cells_enabled @common.check_cells_enabled
def create(self, req, body): def create(self, req, body):
"""Create a child cell entry.""" """Create a child cell entry."""
@ -369,8 +275,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message()) raise exc.HTTPForbidden(explanation=e.format_message())
return dict(cell=_scrub_cell(cell)) return dict(cell=_scrub_cell(cell))
@wsgi.serializers(xml=CellTemplate)
@wsgi.deserializers(xml=CellDeserializer)
@common.check_cells_enabled @common.check_cells_enabled
def update(self, req, id, body): def update(self, req, id, body):
"""Update a child cell entry. 'id' is the cell name to update.""" """Update a child cell entry. 'id' is the cell name to update."""

View File

@ -15,8 +15,6 @@
import webob.exc import webob.exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.cert.rpcapi import nova.cert.rpcapi
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -24,19 +22,6 @@ from nova.i18n import _
authorize = extensions.extension_authorizer('compute', 'certificates') authorize = extensions.extension_authorizer('compute', 'certificates')
def make_certificate(elem):
elem.set('data')
elem.set('private_key')
class CertificateTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('certificate',
selector='certificate')
make_certificate(root)
return xmlutil.MasterTemplate(root, 1)
def _translate_certificate_view(certificate, private_key=None): def _translate_certificate_view(certificate, private_key=None):
return { return {
'data': certificate, 'data': certificate,
@ -51,7 +36,6 @@ class CertificatesController(object):
self.cert_rpcapi = nova.cert.rpcapi.CertAPI() self.cert_rpcapi = nova.cert.rpcapi.CertAPI()
super(CertificatesController, self).__init__() super(CertificatesController, self).__init__()
@wsgi.serializers(xml=CertificateTemplate)
def show(self, req, id): def show(self, req, id):
"""Return certificate information.""" """Return certificate information."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -66,7 +50,6 @@ class CertificatesController(object):
raise webob.exc.HTTPNotFound(explanation=e.format_message()) raise webob.exc.HTTPNotFound(explanation=e.format_message())
return {'certificate': _translate_certificate_view(cert)} return {'certificate': _translate_certificate_view(cert)}
@wsgi.serializers(xml=CertificateTemplate)
def create(self, req, body=None): def create(self, req, body=None):
"""Create a certificate.""" """Create a certificate."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -19,8 +19,6 @@ from oslo.utils import timeutils
from webob import exc from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.cloudpipe import pipelib from nova.cloudpipe import pipelib
from nova import compute from nova import compute
from nova.compute import utils as compute_utils from nova.compute import utils as compute_utils
@ -37,26 +35,6 @@ CONF.import_opt('keys_path', 'nova.crypto')
authorize = extensions.extension_authorizer('compute', 'cloudpipe') authorize = extensions.extension_authorizer('compute', 'cloudpipe')
class CloudpipeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('cloudpipe')
elem = xmlutil.SubTemplateElement(root, 'instance_id',
selector='instance_id')
elem.text = str
return xmlutil.MasterTemplate(root, 1)
class CloudpipesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('cloudpipes')
elem1 = xmlutil.SubTemplateElement(root, 'cloudpipe',
selector='cloudpipes')
elem2 = xmlutil.SubTemplateElement(elem1, xmlutil.Selector(0),
selector=xmlutil.get_items)
elem2.text = 1
return xmlutil.MasterTemplate(root, 1)
class CloudpipeController(object): class CloudpipeController(object):
"""Handle creating and listing cloudpipe instances.""" """Handle creating and listing cloudpipe instances."""
@ -126,7 +104,6 @@ class CloudpipeController(object):
rv['state'] = 'invalid' rv['state'] = 'invalid'
return rv return rv
@wsgi.serializers(xml=CloudpipeTemplate)
def create(self, req, body): def create(self, req, body):
"""Create a new cloudpipe instance, if none exists. """Create a new cloudpipe instance, if none exists.
@ -154,7 +131,6 @@ class CloudpipeController(object):
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
return {'instance_id': instance['uuid']} return {'instance_id': instance['uuid']}
@wsgi.serializers(xml=CloudpipesTemplate)
def index(self, req): def index(self, req):
"""List running cloudpipe instances.""" """List running cloudpipe instances."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -18,26 +18,10 @@
from nova.api.openstack.compute import servers from nova.api.openstack.compute import servers
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'config_drive') authorize = extensions.soft_extension_authorizer('compute', 'config_drive')
class ServerConfigDriveTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
root.set('config_drive', 'config_drive')
return xmlutil.SlaveTemplate(root, 1)
class ServersConfigDriveTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
elem.set('config_drive', 'config_drive')
return xmlutil.SlaveTemplate(root, 1)
class Controller(servers.Controller): class Controller(servers.Controller):
def _add_config_drive(self, req, servers): def _add_config_drive(self, req, servers):
@ -49,7 +33,7 @@ class Controller(servers.Controller):
def _show(self, req, resp_obj): def _show(self, req, resp_obj):
if 'server' in resp_obj.obj: if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerConfigDriveTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
self._add_config_drive(req, [server]) self._add_config_drive(req, [server])
@ -63,7 +47,7 @@ class Controller(servers.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['nova.context'] context = req.environ['nova.context']
if 'servers' in resp_obj.obj and authorize(context): if 'servers' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ServersConfigDriveTemplate()) resp_obj.attach()
servers = resp_obj.obj['servers'] servers = resp_obj.obj['servers']
self._add_config_drive(req, servers) self._add_config_drive(req, servers)

View File

@ -19,7 +19,6 @@ from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _ from nova.i18n import _
ALIAS = 'OS-DCF' ALIAS = 'OS-DCF'
@ -43,21 +42,6 @@ def disk_config_from_api(value):
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
class ImageDiskConfigTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('image')
root.set('{%s}diskConfig' % XMLNS_DCF, API_DISK_CONFIG)
return xmlutil.SlaveTemplate(root, 1, nsmap={ALIAS: XMLNS_DCF})
class ImagesDiskConfigTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('images')
elem = xmlutil.SubTemplateElement(root, 'image', selector='images')
elem.set('{%s}diskConfig' % XMLNS_DCF, API_DISK_CONFIG)
return xmlutil.SlaveTemplate(root, 1, nsmap={ALIAS: XMLNS_DCF})
class ImageDiskConfigController(wsgi.Controller): class ImageDiskConfigController(wsgi.Controller):
def _add_disk_config(self, context, images): def _add_disk_config(self, context, images):
for image in images: for image in images:
@ -71,7 +55,7 @@ class ImageDiskConfigController(wsgi.Controller):
def show(self, req, resp_obj, id): def show(self, req, resp_obj, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
if 'image' in resp_obj.obj and authorize(context): if 'image' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImageDiskConfigTemplate()) resp_obj.attach()
image = resp_obj.obj['image'] image = resp_obj.obj['image']
self._add_disk_config(context, [image]) self._add_disk_config(context, [image])
@ -79,26 +63,11 @@ class ImageDiskConfigController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['nova.context'] context = req.environ['nova.context']
if 'images' in resp_obj.obj and authorize(context): if 'images' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImagesDiskConfigTemplate()) resp_obj.attach()
images = resp_obj.obj['images'] images = resp_obj.obj['images']
self._add_disk_config(context, images) self._add_disk_config(context, images)
class ServerDiskConfigTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
root.set('{%s}diskConfig' % XMLNS_DCF, API_DISK_CONFIG)
return xmlutil.SlaveTemplate(root, 1, nsmap={ALIAS: XMLNS_DCF})
class ServersDiskConfigTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
elem.set('{%s}diskConfig' % XMLNS_DCF, API_DISK_CONFIG)
return xmlutil.SlaveTemplate(root, 1, nsmap={ALIAS: XMLNS_DCF})
class ServerDiskConfigController(wsgi.Controller): class ServerDiskConfigController(wsgi.Controller):
def _add_disk_config(self, req, servers): def _add_disk_config(self, req, servers):
for server in servers: for server in servers:
@ -110,7 +79,7 @@ class ServerDiskConfigController(wsgi.Controller):
def _show(self, req, resp_obj): def _show(self, req, resp_obj):
if 'server' in resp_obj.obj: if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerDiskConfigTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
self._add_disk_config(req, [server]) self._add_disk_config(req, [server])
@ -124,7 +93,7 @@ class ServerDiskConfigController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['nova.context'] context = req.environ['nova.context']
if 'servers' in resp_obj.obj and authorize(context): if 'servers' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ServersDiskConfigTemplate()) resp_obj.attach()
servers = resp_obj.obj['servers'] servers = resp_obj.obj['servers']
self._add_disk_config(req, servers) self._add_disk_config(req, servers)

View File

@ -17,7 +17,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import availability_zones as avail_zone from nova import availability_zones as avail_zone
authorize = extensions.soft_extension_authorizer('compute', authorize = extensions.soft_extension_authorizer('compute',
@ -39,7 +38,7 @@ class ExtendedAZController(wsgi.Controller):
def show(self, req, resp_obj, id): def show(self, req, resp_obj, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
resp_obj.attach(xml=ExtendedAZTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
self._extend_server(context, server, db_instance) self._extend_server(context, server, db_instance)
@ -48,7 +47,7 @@ class ExtendedAZController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
resp_obj.attach(xml=ExtendedAZsTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -68,27 +67,3 @@ class Extended_availability_zone(extensions.ExtensionDescriptor):
controller = ExtendedAZController() controller = ExtendedAZController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.set('{%s}availability_zone' % Extended_availability_zone.namespace,
'%s:availability_zone' % Extended_availability_zone.alias)
class ExtendedAZTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
alias = Extended_availability_zone.alias
namespace = Extended_availability_zone.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})
class ExtendedAZsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
alias = Extended_availability_zone.alias
namespace = Extended_availability_zone.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})

View File

@ -17,10 +17,8 @@
import itertools import itertools
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute import ips
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
authorize = extensions.soft_extension_authorizer('compute', 'extended_ips') authorize = extensions.soft_extension_authorizer('compute', 'extended_ips')
@ -48,7 +46,7 @@ class ExtendedIpsController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsServerTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -60,7 +58,7 @@ class ExtendedIpsController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsServersTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -82,28 +80,3 @@ class Extended_ips(extensions.ExtensionDescriptor):
controller = ExtendedIpsController() controller = ExtendedIpsController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.append(ips.AddressesTemplate())
ip = elem['addresses']['network']['ip']
ip.set('{%s}type' % Extended_ips.namespace,
'%s:type' % Extended_ips.alias)
class ExtendedIpsServerTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_ips.alias: Extended_ips.namespace})
class ExtendedIpsServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_ips.alias: Extended_ips.namespace})

View File

@ -17,10 +17,8 @@
import itertools import itertools
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute import ips
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'extended_ips_mac') authorize = extensions.soft_extension_authorizer('compute', 'extended_ips_mac')
@ -46,7 +44,7 @@ class ExtendedIpsMacController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsMacServerTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -58,7 +56,7 @@ class ExtendedIpsMacController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsMacServersTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -80,27 +78,3 @@ class Extended_ips_mac(extensions.ExtensionDescriptor):
controller = ExtendedIpsMacController() controller = ExtendedIpsMacController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.append(ips.AddressesTemplate())
ip = elem['addresses']['network']['ip']
ip.set('{%s}mac_addr' % Extended_ips_mac.namespace,
'%s:mac_addr' % Extended_ips_mac.alias)
class ExtendedIpsMacServerTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_ips_mac.alias: Extended_ips_mac.namespace})
class ExtendedIpsMacServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_ips_mac.alias: Extended_ips_mac.namespace})

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', authorize = extensions.soft_extension_authorizer('compute',
'extended_server_attributes') 'extended_server_attributes')
@ -40,7 +39,7 @@ class ExtendedServerAttributesController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedServerAttributeTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -52,7 +51,7 @@ class ExtendedServerAttributesController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedServerAttributesTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
@ -75,31 +74,3 @@ class Extended_server_attributes(extensions.ExtensionDescriptor):
controller = ExtendedServerAttributesController() controller = ExtendedServerAttributesController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.set('{%s}instance_name' % Extended_server_attributes.namespace,
'%s:instance_name' % Extended_server_attributes.alias)
elem.set('{%s}host' % Extended_server_attributes.namespace,
'%s:host' % Extended_server_attributes.alias)
elem.set('{%s}hypervisor_hostname' % Extended_server_attributes.namespace,
'%s:hypervisor_hostname' % Extended_server_attributes.alias)
class ExtendedServerAttributeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
alias = Extended_server_attributes.alias
namespace = Extended_server_attributes.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})
class ExtendedServerAttributesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
alias = Extended_server_attributes.alias
namespace = Extended_server_attributes.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'extended_status') authorize = extensions.soft_extension_authorizer('compute', 'extended_status')
@ -35,7 +34,7 @@ class ExtendedStatusController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedStatusTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -47,7 +46,7 @@ class ExtendedStatusController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedStatusesTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -69,29 +68,3 @@ class Extended_status(extensions.ExtensionDescriptor):
controller = ExtendedStatusController() controller = ExtendedStatusController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.set('{%s}task_state' % Extended_status.namespace,
'%s:task_state' % Extended_status.alias)
elem.set('{%s}power_state' % Extended_status.namespace,
'%s:power_state' % Extended_status.alias)
elem.set('{%s}vm_state' % Extended_status.namespace,
'%s:vm_state' % Extended_status.alias)
class ExtendedStatusTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_status.alias: Extended_status.namespace})
class ExtendedStatusesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_status.alias: Extended_status.namespace})

View File

@ -15,29 +15,11 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import network from nova import network
authorize = extensions.soft_extension_authorizer('compute', 'extended_vif_net') authorize = extensions.soft_extension_authorizer('compute', 'extended_vif_net')
def make_vif(elem):
elem.set('{%s}net_id' % Extended_virtual_interfaces_net.namespace,
'%s:net_id' % Extended_virtual_interfaces_net.alias)
class ExtendedVirtualInterfaceNetTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('virtual_interfaces',
selector='virtual_interfaces')
elem = xmlutil.SubTemplateElement(root, 'virtual_interface',
selector='virtual_interfaces')
make_vif(elem)
return xmlutil.SlaveTemplate(root, 1,
nsmap={Extended_virtual_interfaces_net.alias:
Extended_virtual_interfaces_net.namespace})
class ExtendedServerVIFNetController(wsgi.Controller): class ExtendedServerVIFNetController(wsgi.Controller):
def __init__(self): def __init__(self):
super(ExtendedServerVIFNetController, self).__init__() super(ExtendedServerVIFNetController, self).__init__()
@ -49,7 +31,7 @@ class ExtendedServerVIFNetController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVirtualInterfaceNetTemplate()) resp_obj.attach()
for vif in resp_obj.obj['virtual_interfaces']: for vif in resp_obj.obj['virtual_interfaces']:
vif1 = self.network_api.get_vif_by_mac_address(context, vif1 = self.network_api.get_vif_by_mac_address(context,
vif['mac_address']) vif['mac_address'])

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import objects from nova import objects
@ -40,7 +39,7 @@ class ExtendedVolumesController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVolumesServerTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -52,7 +51,7 @@ class ExtendedVolumesController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVolumesServersTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -77,27 +76,3 @@ class Extended_volumes(extensions.ExtensionDescriptor):
def get_resources(self): def get_resources(self):
return [] return []
def make_server(elem):
volumes = xmlutil.SubTemplateElement(
elem, '{%s}volume_attached' % Extended_volumes.namespace,
selector='%s:volumes_attached' % Extended_volumes.alias)
volumes.set('id')
class ExtendedVolumesServerTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_volumes.alias: Extended_volumes.namespace})
class ExtendedVolumesServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Extended_volumes.alias: Extended_volumes.namespace})

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import objects from nova import objects
@ -30,44 +29,6 @@ soft_authorize = extensions.soft_extension_authorizer('compute',
authorize = extensions.extension_authorizer('compute', 'flavor_access') authorize = extensions.extension_authorizer('compute', 'flavor_access')
def make_flavor(elem):
elem.set('{%s}is_public' % Flavor_access.namespace,
'%s:is_public' % Flavor_access.alias)
def make_flavor_access(elem):
elem.set('flavor_id')
elem.set('tenant_id')
class FlavorTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
alias = Flavor_access.alias
namespace = Flavor_access.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})
class FlavorsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
alias = Flavor_access.alias
namespace = Flavor_access.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})
class FlavorAccessTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor_access')
elem = xmlutil.SubTemplateElement(root, 'access',
selector='flavor_access')
make_flavor_access(elem)
return xmlutil.MasterTemplate(root, 1)
def _marshall_flavor_access(flavor): def _marshall_flavor_access(flavor):
rval = [] rval = []
for project_id in flavor.projects: for project_id in flavor.projects:
@ -83,7 +44,6 @@ class FlavorAccessController(object):
def __init__(self): def __init__(self):
super(FlavorAccessController, self).__init__() super(FlavorAccessController, self).__init__()
@wsgi.serializers(xml=FlavorAccessTemplate)
def index(self, req, flavor_id): def index(self, req, flavor_id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -128,7 +88,7 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if soft_authorize(context): if soft_authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=FlavorTemplate()) resp_obj.attach()
db_flavor = req.get_db_flavor(id) db_flavor = req.get_db_flavor(id)
self._extend_flavor(resp_obj.obj['flavor'], db_flavor) self._extend_flavor(resp_obj.obj['flavor'], db_flavor)
@ -138,7 +98,7 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if soft_authorize(context): if soft_authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=FlavorsTemplate()) resp_obj.attach()
flavors = list(resp_obj.obj['flavors']) flavors = list(resp_obj.obj['flavors'])
for flavor_rval in flavors: for flavor_rval in flavors:
@ -150,13 +110,12 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if soft_authorize(context): if soft_authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=FlavorTemplate()) resp_obj.attach()
db_flavor = req.get_db_flavor(resp_obj.obj['flavor']['id']) db_flavor = req.get_db_flavor(resp_obj.obj['flavor']['id'])
self._extend_flavor(resp_obj.obj['flavor'], db_flavor) self._extend_flavor(resp_obj.obj['flavor'], db_flavor)
@wsgi.serializers(xml=FlavorAccessTemplate)
@wsgi.action("addTenantAccess") @wsgi.action("addTenantAccess")
def _addTenantAccess(self, req, id, body): def _addTenantAccess(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -180,7 +139,6 @@ class FlavorActionController(wsgi.Controller):
return _marshall_flavor_access(flavor) return _marshall_flavor_access(flavor)
@wsgi.serializers(xml=FlavorAccessTemplate)
@wsgi.action("removeTenantAccess") @wsgi.action("removeTenantAccess")
def _removeTenantAccess(self, req, id, body): def _removeTenantAccess(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_disabled') authorize = extensions.soft_extension_authorizer('compute', 'flavor_disabled')
@ -33,7 +32,7 @@ class FlavorDisabledController(wsgi.Controller):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
if 'flavor' in resp_obj.obj: if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorDisabledTemplate()) resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']]) self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends @wsgi.extends
@ -48,7 +47,7 @@ class FlavorDisabledController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
resp_obj.attach(xml=FlavorsDisabledTemplate()) resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors'])) self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -65,25 +64,3 @@ class Flavor_disabled(extensions.ExtensionDescriptor):
controller = FlavorDisabledController() controller = FlavorDisabledController()
extension = extensions.ControllerExtension(self, 'flavors', controller) extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension] return [extension]
def make_flavor(elem):
elem.set('{%s}disabled' % Flavor_disabled.namespace,
'%s:disabled' % Flavor_disabled.alias)
class FlavorDisabledTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Flavor_disabled.alias: Flavor_disabled.namespace})
class FlavorsDisabledTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Flavor_disabled.alias: Flavor_disabled.namespace})

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_rxtx') authorize = extensions.soft_extension_authorizer('compute', 'flavor_rxtx')
@ -33,7 +32,7 @@ class FlavorRxtxController(wsgi.Controller):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
if 'flavor' in resp_obj.obj: if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorRxtxTemplate()) resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']]) self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends @wsgi.extends
@ -48,7 +47,7 @@ class FlavorRxtxController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
resp_obj.attach(xml=FlavorsRxtxTemplate()) resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors'])) self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -65,23 +64,3 @@ class Flavor_rxtx(extensions.ExtensionDescriptor):
controller = FlavorRxtxController() controller = FlavorRxtxController()
extension = extensions.ControllerExtension(self, 'flavors', controller) extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension] return [extension]
def make_flavor(elem):
# NOTE(vish): this was originally added without a namespace
elem.set('rxtx_factor', xmlutil.EmptyStringSelector('rxtx_factor'))
class FlavorRxtxTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
return xmlutil.SlaveTemplate(root, 1)
class FlavorsRxtxTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.SlaveTemplate(root, 1)

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_swap') authorize = extensions.soft_extension_authorizer('compute', 'flavor_swap')
@ -33,7 +32,7 @@ class FlavorSwapController(wsgi.Controller):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
if 'flavor' in resp_obj.obj: if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorSwapTemplate()) resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']]) self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends @wsgi.extends
@ -48,7 +47,7 @@ class FlavorSwapController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
resp_obj.attach(xml=FlavorsSwapTemplate()) resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors'])) self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -65,23 +64,3 @@ class Flavor_swap(extensions.ExtensionDescriptor):
controller = FlavorSwapController() controller = FlavorSwapController()
extension = extensions.ControllerExtension(self, 'flavors', controller) extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension] return [extension]
def make_flavor(elem):
# NOTE(vish): this was originally added without a namespace
elem.set('swap', xmlutil.EmptyStringSelector('swap'))
class FlavorSwapTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
return xmlutil.SlaveTemplate(root, 1)
class FlavorsSwapTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.SlaveTemplate(root, 1)

View File

@ -24,7 +24,6 @@ attributes. This extension adds to that list:
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavorextradata') authorize = extensions.soft_extension_authorizer('compute', 'flavorextradata')
@ -41,7 +40,7 @@ class FlavorextradataController(wsgi.Controller):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
if 'flavor' in resp_obj.obj: if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorextradatumTemplate()) resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']]) self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends @wsgi.extends
@ -56,7 +55,7 @@ class FlavorextradataController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']): if not authorize(req.environ['nova.context']):
return return
resp_obj.attach(xml=FlavorextradataTemplate()) resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors'])) self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -73,27 +72,3 @@ class Flavorextradata(extensions.ExtensionDescriptor):
controller = FlavorextradataController() controller = FlavorextradataController()
extension = extensions.ControllerExtension(self, 'flavors', controller) extension = extensions.ControllerExtension(self, 'flavors', controller)
return [extension] return [extension]
def make_flavor(elem):
elem.set('{%s}ephemeral' % Flavorextradata.namespace,
'%s:ephemeral' % Flavorextradata.alias)
class FlavorextradatumTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root)
alias = Flavorextradata.alias
namespace = Flavorextradata.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})
class FlavorextradataTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
alias = Flavorextradata.alias
namespace = Flavorextradata.namespace
return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace})

View File

@ -19,8 +19,6 @@ import six
from webob import exc from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import flavors from nova.compute import flavors
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -30,21 +28,6 @@ from nova import utils
authorize = extensions.extension_authorizer('compute', 'flavorextraspecs') authorize = extensions.extension_authorizer('compute', 'flavorextraspecs')
class ExtraSpecsTemplate(xmlutil.TemplateBuilder):
def construct(self):
extra_specs_dict = xmlutil.make_flat_dict('extra_specs', colon_ns=True)
return xmlutil.MasterTemplate(extra_specs_dict, 1)
class ExtraSpecTemplate(xmlutil.TemplateBuilder):
def construct(self):
sel = xmlutil.Selector(xmlutil.get_items, 0)
root = xmlutil.TemplateElement('extra_spec', selector=sel)
root.set('key', 0)
root.text = 1
return xmlutil.MasterTemplate(root, 1)
class FlavorExtraSpecsController(object): class FlavorExtraSpecsController(object):
"""The flavor extra specs API controller for the OpenStack API.""" """The flavor extra specs API controller for the OpenStack API."""
@ -85,14 +68,12 @@ class FlavorExtraSpecsController(object):
except exception.InvalidInput as error: except exception.InvalidInput as error:
raise exc.HTTPBadRequest(explanation=error.format_message()) raise exc.HTTPBadRequest(explanation=error.format_message())
@wsgi.serializers(xml=ExtraSpecsTemplate)
def index(self, req, flavor_id): def index(self, req, flavor_id):
"""Returns the list of extra specs for a given flavor.""" """Returns the list of extra specs for a given flavor."""
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context, action='index') authorize(context, action='index')
return self._get_extra_specs(context, flavor_id) return self._get_extra_specs(context, flavor_id)
@wsgi.serializers(xml=ExtraSpecsTemplate)
def create(self, req, flavor_id, body): def create(self, req, flavor_id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context, action='create') authorize(context, action='create')
@ -109,7 +90,6 @@ class FlavorExtraSpecsController(object):
raise exc.HTTPNotFound(explanation=error.format_message()) raise exc.HTTPNotFound(explanation=error.format_message())
return body return body
@wsgi.serializers(xml=ExtraSpecTemplate)
def update(self, req, flavor_id, id, body): def update(self, req, flavor_id, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context, action='update') authorize(context, action='update')
@ -130,7 +110,6 @@ class FlavorExtraSpecsController(object):
raise exc.HTTPNotFound(explanation=error.format_message()) raise exc.HTTPNotFound(explanation=error.format_message())
return body return body
@wsgi.serializers(xml=ExtraSpecTemplate)
def show(self, req, flavor_id, id): def show(self, req, flavor_id, id):
"""Return a single extra spec item.""" """Return a single extra spec item."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -12,7 +12,6 @@
import webob import webob
from nova.api.openstack.compute import flavors as flavors_api
from nova.api.openstack.compute.views import flavors as flavors_view from nova.api.openstack.compute.views import flavors as flavors_view
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
@ -47,7 +46,6 @@ class FlavorManageController(wsgi.Controller):
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.action("create") @wsgi.action("create")
@wsgi.serializers(xml=flavors_api.FlavorTemplate)
def _create(self, req, body): def _create(self, req, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import network from nova import network
@ -28,55 +27,6 @@ from nova import network
authorize = extensions.extension_authorizer('compute', 'floating_ip_dns') authorize = extensions.extension_authorizer('compute', 'floating_ip_dns')
def make_dns_entry(elem):
elem.set('id')
elem.set('ip')
elem.set('type')
elem.set('domain')
elem.set('name')
def make_domain_entry(elem):
elem.set('domain')
elem.set('scope')
elem.set('project')
elem.set('availability_zone')
class FloatingIPDNSTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('dns_entry',
selector='dns_entry')
make_dns_entry(root)
return xmlutil.MasterTemplate(root, 1)
class FloatingIPDNSsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('dns_entries')
elem = xmlutil.SubTemplateElement(root, 'dns_entry',
selector='dns_entries')
make_dns_entry(elem)
return xmlutil.MasterTemplate(root, 1)
class DomainTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('domain_entry',
selector='domain_entry')
make_domain_entry(root)
return xmlutil.MasterTemplate(root, 1)
class DomainsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('domain_entries')
elem = xmlutil.SubTemplateElement(root, 'domain_entry',
selector='domain_entries')
make_domain_entry(elem)
return xmlutil.MasterTemplate(root, 1)
def _translate_dns_entry_view(dns_entry): def _translate_dns_entry_view(dns_entry):
result = {} result = {}
result['ip'] = dns_entry.get('ip') result['ip'] = dns_entry.get('ip')
@ -133,7 +83,6 @@ class FloatingIPDNSDomainController(object):
self.network_api = network.API() self.network_api = network.API()
super(FloatingIPDNSDomainController, self).__init__() super(FloatingIPDNSDomainController, self).__init__()
@wsgi.serializers(xml=DomainsTemplate)
def index(self, req): def index(self, req):
"""Return a list of available DNS domains.""" """Return a list of available DNS domains."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -152,7 +101,6 @@ class FloatingIPDNSDomainController(object):
return _translate_domain_entries_view(domainlist) return _translate_domain_entries_view(domainlist)
@wsgi.serializers(xml=DomainTemplate)
def update(self, req, id, body): def update(self, req, id, body):
"""Add or modify domain entry.""" """Add or modify domain entry."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -211,7 +159,6 @@ class FloatingIPDNSEntryController(object):
self.network_api = network.API() self.network_api = network.API()
super(FloatingIPDNSEntryController, self).__init__() super(FloatingIPDNSEntryController, self).__init__()
@wsgi.serializers(xml=FloatingIPDNSTemplate)
def show(self, req, domain_id, id): def show(self, req, domain_id, id):
"""Return the DNS entry that corresponds to domain_id and id.""" """Return the DNS entry that corresponds to domain_id and id."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -242,13 +189,11 @@ class FloatingIPDNSEntryController(object):
entrylist = [_create_dns_entry(floating_ip, entry, domain) entrylist = [_create_dns_entry(floating_ip, entry, domain)
for entry in entries] for entry in entries]
dns_entries = _translate_dns_entries_view(entrylist) dns_entries = _translate_dns_entries_view(entrylist)
return wsgi.ResponseObject(dns_entries, return wsgi.ResponseObject(dns_entries)
xml=FloatingIPDNSsTemplate)
entry = _create_dns_entry(entries[0], id, domain) entry = _create_dns_entry(entries[0], id, domain)
return _translate_dns_entry_view(entry) return _translate_dns_entry_view(entry)
@wsgi.serializers(xml=FloatingIPDNSTemplate)
def update(self, req, domain_id, id, body): def update(self, req, domain_id, id, body):
"""Add or modify dns entry.""" """Add or modify dns entry."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -13,8 +13,6 @@
# under the License. # under the License.
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import network from nova import network
@ -34,27 +32,6 @@ def _translate_floating_ip_pools_view(pools):
} }
def make_float_ip(elem):
elem.set('name')
class FloatingIPPoolTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('floating_ip_pool',
selector='floating_ip_pool')
make_float_ip(root)
return xmlutil.MasterTemplate(root, 1)
class FloatingIPPoolsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('floating_ip_pools')
elem = xmlutil.SubTemplateElement(root, 'floating_ip_pool',
selector='floating_ip_pools')
make_float_ip(elem)
return xmlutil.MasterTemplate(root, 1)
class FloatingIPPoolsController(object): class FloatingIPPoolsController(object):
"""The Floating IP Pool API controller for the OpenStack API.""" """The Floating IP Pool API controller for the OpenStack API."""
@ -62,7 +39,6 @@ class FloatingIPPoolsController(object):
self.network_api = network.API() self.network_api = network.API()
super(FloatingIPPoolsController, self).__init__() super(FloatingIPPoolsController, self).__init__()
@wsgi.serializers(xml=FloatingIPPoolsTemplate)
def index(self, req): def index(self, req):
"""Return a list of pools.""" """Return a list of pools."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -20,7 +20,6 @@ import webob
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova.compute import utils as compute_utils from nova.compute import utils as compute_utils
from nova import exception from nova import exception
@ -35,31 +34,6 @@ LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'floating_ips') authorize = extensions.extension_authorizer('compute', 'floating_ips')
def make_float_ip(elem):
elem.set('id')
elem.set('ip')
elem.set('pool')
elem.set('fixed_ip')
elem.set('instance_id')
class FloatingIPTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('floating_ip',
selector='floating_ip')
make_float_ip(root)
return xmlutil.MasterTemplate(root, 1)
class FloatingIPsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('floating_ips')
elem = xmlutil.SubTemplateElement(root, 'floating_ip',
selector='floating_ips')
make_float_ip(elem)
return xmlutil.MasterTemplate(root, 1)
def _translate_floating_ip_view(floating_ip): def _translate_floating_ip_view(floating_ip):
result = { result = {
'id': floating_ip['id'], 'id': floating_ip['id'],
@ -108,7 +82,6 @@ class FloatingIPController(object):
self.network_api = network.API() self.network_api = network.API()
super(FloatingIPController, self).__init__() super(FloatingIPController, self).__init__()
@wsgi.serializers(xml=FloatingIPTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given floating ip.""" """Return data about the given floating ip."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -122,7 +95,6 @@ class FloatingIPController(object):
return _translate_floating_ip_view(floating_ip) return _translate_floating_ip_view(floating_ip)
@wsgi.serializers(xml=FloatingIPsTemplate)
def index(self, req): def index(self, req):
"""Return a list of floating ips allocated to a project.""" """Return a list of floating ips allocated to a project."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -132,7 +104,6 @@ class FloatingIPController(object):
return _translate_floating_ips_view(floating_ips) return _translate_floating_ips_view(floating_ips)
@wsgi.serializers(xml=FloatingIPTemplate)
def create(self, req, body=None): def create(self, req, body=None):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -18,8 +18,6 @@
import webob.exc import webob.exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -29,72 +27,12 @@ LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'hosts') authorize = extensions.extension_authorizer('compute', 'hosts')
class HostIndexTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hosts')
elem = xmlutil.SubTemplateElement(root, 'host', selector='hosts')
elem.set('host_name')
elem.set('service')
elem.set('zone')
return xmlutil.MasterTemplate(root, 1)
class HostUpdateTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('host')
root.set('host')
root.set('status')
root.set('maintenance_mode')
return xmlutil.MasterTemplate(root, 1)
class HostActionTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('host')
root.set('host')
root.set('power_action')
return xmlutil.MasterTemplate(root, 1)
class HostShowTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('host')
elem = xmlutil.make_flat_dict('resource', selector='host',
subselector='resource')
root.append(elem)
return xmlutil.MasterTemplate(root, 1)
class HostUpdateDeserializer(wsgi.XMLDeserializer):
def default(self, string):
node = xmlutil.safe_minidom_parse_string(string)
updates = {}
updates_node = self.find_first_child_named(node, 'updates')
if updates_node is not None:
maintenance = self.find_first_child_named(updates_node,
'maintenance_mode')
if maintenance is not None:
updates[maintenance.tagName] = self.extract_text(maintenance)
status = self.find_first_child_named(updates_node, 'status')
if status is not None:
updates[status.tagName] = self.extract_text(status)
return dict(body=updates)
class HostController(object): class HostController(object):
"""The Hosts API controller for the OpenStack API.""" """The Hosts API controller for the OpenStack API."""
def __init__(self): def __init__(self):
self.api = compute.HostAPI() self.api = compute.HostAPI()
super(HostController, self).__init__() super(HostController, self).__init__()
@wsgi.serializers(xml=HostIndexTemplate)
def index(self, req): def index(self, req):
"""Returns a dict in the format: """Returns a dict in the format:
@ -148,8 +86,6 @@ class HostController(object):
'zone': service['availability_zone']}) 'zone': service['availability_zone']})
return {'hosts': hosts} return {'hosts': hosts}
@wsgi.serializers(xml=HostUpdateTemplate)
@wsgi.deserializers(xml=HostUpdateDeserializer)
def update(self, req, id, body): def update(self, req, id, body):
"""Updates a specified body. """Updates a specified body.
@ -261,15 +197,12 @@ class HostController(object):
raise webob.exc.HTTPBadRequest(explanation=e.format_message()) raise webob.exc.HTTPBadRequest(explanation=e.format_message())
return {"host": host_name, "power_action": result} return {"host": host_name, "power_action": result}
@wsgi.serializers(xml=HostActionTemplate)
def startup(self, req, id): def startup(self, req, id):
return self._host_power_action(req, host_name=id, action="startup") return self._host_power_action(req, host_name=id, action="startup")
@wsgi.serializers(xml=HostActionTemplate)
def shutdown(self, req, id): def shutdown(self, req, id):
return self._host_power_action(req, host_name=id, action="shutdown") return self._host_power_action(req, host_name=id, action="shutdown")
@wsgi.serializers(xml=HostActionTemplate)
def reboot(self, req, id): def reboot(self, req, id):
return self._host_power_action(req, host_name=id, action="reboot") return self._host_power_action(req, host_name=id, action="reboot")
@ -322,7 +255,6 @@ class HostController(object):
instance['ephemeral_gb']) instance['ephemeral_gb'])
return project_map return project_map
@wsgi.serializers(xml=HostShowTemplate)
def show(self, req, id): def show(self, req, id):
"""Shows the physical/usage resource given by hosts. """Shows the physical/usage resource given by hosts.

View File

@ -18,8 +18,6 @@
import webob.exc import webob.exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -29,104 +27,6 @@ from nova import servicegroup
authorize = extensions.extension_authorizer('compute', 'hypervisors') authorize = extensions.extension_authorizer('compute', 'hypervisors')
def make_hypervisor(elem, detail):
elem.set('hypervisor_hostname')
elem.set('id')
elem.set('state')
elem.set('status')
if detail:
elem.set('vcpus')
elem.set('memory_mb')
elem.set('local_gb')
elem.set('vcpus_used')
elem.set('memory_mb_used')
elem.set('local_gb_used')
elem.set('hypervisor_type')
elem.set('hypervisor_version')
elem.set('free_ram_mb')
elem.set('free_disk_gb')
elem.set('current_workload')
elem.set('running_vms')
elem.set('cpu_info')
elem.set('disk_available_least')
elem.set('host_ip')
service = xmlutil.SubTemplateElement(elem, 'service',
selector='service')
service.set('id')
service.set('host')
service.set('disabled_reason')
class HypervisorIndexTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisors')
elem = xmlutil.SubTemplateElement(root, 'hypervisor',
selector='hypervisors')
make_hypervisor(elem, False)
return xmlutil.MasterTemplate(root, 1)
class HypervisorDetailTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisors')
elem = xmlutil.SubTemplateElement(root, 'hypervisor',
selector='hypervisors')
make_hypervisor(elem, True)
return xmlutil.MasterTemplate(root, 1)
class HypervisorTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisor', selector='hypervisor')
make_hypervisor(root, True)
return xmlutil.MasterTemplate(root, 1)
class HypervisorUptimeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisor', selector='hypervisor')
make_hypervisor(root, False)
root.set('uptime')
return xmlutil.MasterTemplate(root, 1)
class HypervisorServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisors')
elem = xmlutil.SubTemplateElement(root, 'hypervisor',
selector='hypervisors')
make_hypervisor(elem, False)
servers = xmlutil.SubTemplateElement(elem, 'servers')
server = xmlutil.SubTemplateElement(servers, 'server',
selector='servers')
server.set('name')
server.set('uuid')
return xmlutil.MasterTemplate(root, 1)
class HypervisorStatisticsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('hypervisor_statistics',
selector='hypervisor_statistics')
root.set('count')
root.set('vcpus')
root.set('memory_mb')
root.set('local_gb')
root.set('vcpus_used')
root.set('memory_mb_used')
root.set('local_gb_used')
root.set('free_ram_mb')
root.set('free_disk_gb')
root.set('current_workload')
root.set('running_vms')
root.set('disk_available_least')
return xmlutil.MasterTemplate(root, 1)
class HypervisorsController(object): class HypervisorsController(object):
"""The Hypervisors API controller for the OpenStack API.""" """The Hypervisors API controller for the OpenStack API."""
@ -179,7 +79,6 @@ class HypervisorsController(object):
return hyp_dict return hyp_dict
@wsgi.serializers(xml=HypervisorIndexTemplate)
def index(self, req): def index(self, req):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -188,7 +87,6 @@ class HypervisorsController(object):
return dict(hypervisors=[self._view_hypervisor(hyp, False) return dict(hypervisors=[self._view_hypervisor(hyp, False)
for hyp in compute_nodes]) for hyp in compute_nodes])
@wsgi.serializers(xml=HypervisorDetailTemplate)
def detail(self, req): def detail(self, req):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -197,7 +95,6 @@ class HypervisorsController(object):
return dict(hypervisors=[self._view_hypervisor(hyp, True) return dict(hypervisors=[self._view_hypervisor(hyp, True)
for hyp in compute_nodes]) for hyp in compute_nodes])
@wsgi.serializers(xml=HypervisorTemplate)
def show(self, req, id): def show(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -209,7 +106,6 @@ class HypervisorsController(object):
raise webob.exc.HTTPNotFound(explanation=msg) raise webob.exc.HTTPNotFound(explanation=msg)
return dict(hypervisor=self._view_hypervisor(hyp, True)) return dict(hypervisor=self._view_hypervisor(hyp, True))
@wsgi.serializers(xml=HypervisorUptimeTemplate)
def uptime(self, req, id): def uptime(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -231,7 +127,6 @@ class HypervisorsController(object):
return dict(hypervisor=self._view_hypervisor(hyp, False, return dict(hypervisor=self._view_hypervisor(hyp, False,
uptime=uptime)) uptime=uptime))
@wsgi.serializers(xml=HypervisorIndexTemplate)
def search(self, req, id): def search(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -244,7 +139,6 @@ class HypervisorsController(object):
msg = _("No hypervisor matching '%s' could be found.") % id msg = _("No hypervisor matching '%s' could be found.") % id
raise webob.exc.HTTPNotFound(explanation=msg) raise webob.exc.HTTPNotFound(explanation=msg)
@wsgi.serializers(xml=HypervisorServersTemplate)
def servers(self, req, id): def servers(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -261,7 +155,6 @@ class HypervisorsController(object):
hypervisors.append(hyp) hypervisors.append(hyp)
return dict(hypervisors=hypervisors) return dict(hypervisors=hypervisors)
@wsgi.serializers(xml=HypervisorStatisticsTemplate)
def statistics(self, req): def statistics(self, req):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -15,32 +15,10 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'image_size') authorize = extensions.soft_extension_authorizer('compute', 'image_size')
def make_image(elem):
elem.set('{%s}size' % Image_size.namespace, '%s:size' % Image_size.alias)
class ImagesSizeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('images')
elem = xmlutil.SubTemplateElement(root, 'image', selector='images')
make_image(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Image_size.alias: Image_size.namespace})
class ImageSizeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('image', selector='image')
make_image(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Image_size.alias: Image_size.namespace})
class ImageSizeController(wsgi.Controller): class ImageSizeController(wsgi.Controller):
def _extend_image(self, image, image_cache): def _extend_image(self, image, image_cache):
@ -52,7 +30,7 @@ class ImageSizeController(wsgi.Controller):
context = req.environ["nova.context"] context = req.environ["nova.context"]
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ImageSizeTemplate()) resp_obj.attach()
image_resp = resp_obj.obj['image'] image_resp = resp_obj.obj['image']
# image guaranteed to be in the cache due to the core API adding # image guaranteed to be in the cache due to the core API adding
# it in its 'show' method # it in its 'show' method
@ -64,7 +42,7 @@ class ImageSizeController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ImagesSizeTemplate()) resp_obj.attach()
images_resp = list(resp_obj.obj['images']) images_resp = list(resp_obj.obj['images'])
# images guaranteed to be in the cache due to the core API adding # images guaranteed to be in the cache due to the core API adding
# it in its 'detail' method # it in its 'detail' method

View File

@ -18,7 +18,6 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
authorize_actions = extensions.extension_authorizer('compute', authorize_actions = extensions.extension_authorizer('compute',
@ -31,37 +30,6 @@ ACTION_KEYS = ['action', 'instance_uuid', 'request_id', 'user_id',
EVENT_KEYS = ['event', 'start_time', 'finish_time', 'result', 'traceback'] EVENT_KEYS = ['event', 'start_time', 'finish_time', 'result', 'traceback']
def make_actions(elem):
for key in ACTION_KEYS:
elem.set(key)
def make_action(elem):
for key in ACTION_KEYS:
elem.set(key)
event = xmlutil.TemplateElement('events', selector='events')
for key in EVENT_KEYS:
event.set(key)
elem.append(event)
class InstanceActionsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('instanceActions')
elem = xmlutil.SubTemplateElement(root, 'instanceAction',
selector='instanceActions')
make_actions(elem)
return xmlutil.MasterTemplate(root, 1)
class InstanceActionTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('instanceAction',
selector='instanceAction')
make_action(root)
return xmlutil.MasterTemplate(root, 1)
class InstanceActionsController(wsgi.Controller): class InstanceActionsController(wsgi.Controller):
def __init__(self): def __init__(self):
@ -81,7 +49,6 @@ class InstanceActionsController(wsgi.Controller):
event[key] = event_raw.get(key) event[key] = event_raw.get(key)
return event return event
@wsgi.serializers(xml=InstanceActionsTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns the list of actions recorded for a given instance.""" """Returns the list of actions recorded for a given instance."""
context = req.environ["nova.context"] context = req.environ["nova.context"]
@ -91,7 +58,6 @@ class InstanceActionsController(wsgi.Controller):
actions = [self._format_action(action) for action in actions_raw] actions = [self._format_action(action) for action in actions_raw]
return {'instanceActions': actions} return {'instanceActions': actions}
@wsgi.serializers(xml=InstanceActionTemplate)
def show(self, req, server_id, id): def show(self, req, server_id, id):
"""Return data about the given instance action.""" """Return data about the given instance action."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -21,7 +21,6 @@ import webob.exc
from nova.api.openstack.compute import servers from nova.api.openstack.compute import servers
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import api as compute_api from nova.compute import api as compute_api
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -31,21 +30,6 @@ authorize = extensions.extension_authorizer('compute', 'keypairs')
soft_authorize = extensions.soft_extension_authorizer('compute', 'keypairs') soft_authorize = extensions.soft_extension_authorizer('compute', 'keypairs')
class KeypairTemplate(xmlutil.TemplateBuilder):
def construct(self):
return xmlutil.MasterTemplate(xmlutil.make_flat_dict('keypair'), 1)
class KeypairsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('keypairs')
elem = xmlutil.make_flat_dict('keypair', selector='keypairs',
subselector='keypair')
root.append(elem)
return xmlutil.MasterTemplate(root, 1)
class KeypairController(object): class KeypairController(object):
"""Keypair API controller for the OpenStack API.""" """Keypair API controller for the OpenStack API."""
@ -62,7 +46,6 @@ class KeypairController(object):
clean[attr] = keypair[attr] clean[attr] = keypair[attr]
return clean return clean
@wsgi.serializers(xml=KeypairTemplate)
def create(self, req, body): def create(self, req, body):
"""Create or import keypair. """Create or import keypair.
@ -118,7 +101,6 @@ class KeypairController(object):
raise webob.exc.HTTPNotFound(explanation=exc.format_message()) raise webob.exc.HTTPNotFound(explanation=exc.format_message())
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.serializers(xml=KeypairTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data for the given key name.""" """Return data for the given key name."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -130,7 +112,6 @@ class KeypairController(object):
raise webob.exc.HTTPNotFound(explanation=exc.format_message()) raise webob.exc.HTTPNotFound(explanation=exc.format_message())
return {'keypair': keypair} return {'keypair': keypair}
@wsgi.serializers(xml=KeypairsTemplate)
def index(self, req): def index(self, req):
"""List of keypairs for a user.""" """List of keypairs for a user."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -143,21 +124,6 @@ class KeypairController(object):
return {'keypairs': rval} return {'keypairs': rval}
class ServerKeyNameTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
root.set('key_name', 'key_name')
return xmlutil.SlaveTemplate(root, 1)
class ServersKeyNameTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
elem.set('key_name', 'key_name')
return xmlutil.SlaveTemplate(root, 1)
class Controller(servers.Controller): class Controller(servers.Controller):
def _add_key_name(self, req, servers): def _add_key_name(self, req, servers):
@ -169,7 +135,7 @@ class Controller(servers.Controller):
def _show(self, req, resp_obj): def _show(self, req, resp_obj):
if 'server' in resp_obj.obj: if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerKeyNameTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
self._add_key_name(req, [server]) self._add_key_name(req, [server])
@ -183,7 +149,7 @@ class Controller(servers.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
context = req.environ['nova.context'] context = req.environ['nova.context']
if 'servers' in resp_obj.obj and soft_authorize(context): if 'servers' in resp_obj.obj and soft_authorize(context):
resp_obj.attach(xml=ServersKeyNameTemplate()) resp_obj.attach()
servers = resp_obj.obj['servers'] servers = resp_obj.obj['servers']
self._add_key_name(req, servers) self._add_key_name(req, servers)

View File

@ -11,8 +11,6 @@
# under the License. # under the License.
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova.objects import base as obj_base from nova.objects import base as obj_base
@ -39,33 +37,11 @@ def output(migrations_obj):
return objects return objects
class MigrationsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('migrations')
elem = xmlutil.SubTemplateElement(root, 'migration',
selector='migrations')
elem.set('id')
elem.set('source_node')
elem.set('dest_node')
elem.set('source_compute')
elem.set('dest_compute')
elem.set('dest_host')
elem.set('status')
elem.set('instance_uuid')
elem.set('old_instance_type_id')
elem.set('new_instance_type_id')
elem.set('created_at')
elem.set('updated_at')
return xmlutil.MasterTemplate(root, 1)
class MigrationsController(object): class MigrationsController(object):
"""Controller for accessing migrations in OpenStack API.""" """Controller for accessing migrations in OpenStack API."""
def __init__(self): def __init__(self):
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.serializers(xml=MigrationsTemplate)
def index(self, req): def index(self, req):
"""Return all migrations in progress.""" """Return all migrations in progress."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -17,7 +17,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.context import nova.context
from nova import db from nova import db
from nova import exception from nova import exception
@ -35,20 +34,6 @@ EXTENDED_QUOTAS = {'server_groups': 'os-server-group-quotas',
authorize = extensions.extension_authorizer('compute', 'quota_classes') authorize = extensions.extension_authorizer('compute', 'quota_classes')
class QuotaClassTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('quota_class_set',
selector='quota_class_set')
root.set('id')
for resource in QUOTAS.resources:
if resource not in EXTENDED_QUOTAS:
elem = xmlutil.SubTemplateElement(root, resource)
elem.text = resource
return xmlutil.MasterTemplate(root, 1)
class QuotaClassSetsController(wsgi.Controller): class QuotaClassSetsController(wsgi.Controller):
supported_quotas = [] supported_quotas = []
@ -74,7 +59,6 @@ class QuotaClassSetsController(wsgi.Controller):
return dict(quota_class_set=result) return dict(quota_class_set=result)
@wsgi.serializers(xml=QuotaClassTemplate)
def show(self, req, id): def show(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -85,7 +69,6 @@ class QuotaClassSetsController(wsgi.Controller):
except exception.Forbidden: except exception.Forbidden:
raise webob.exc.HTTPForbidden() raise webob.exc.HTTPForbidden()
@wsgi.serializers(xml=QuotaClassTemplate)
def update(self, req, id, body): def update(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.context import nova.context
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -40,19 +39,6 @@ authorize_show = extensions.extension_authorizer('compute', 'quotas:show')
authorize_delete = extensions.extension_authorizer('compute', 'quotas:delete') authorize_delete = extensions.extension_authorizer('compute', 'quotas:delete')
class QuotaTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('quota_set', selector='quota_set')
root.set('id')
for resource in QUOTAS.resources:
if resource not in EXTENDED_QUOTAS:
elem = xmlutil.SubTemplateElement(root, resource)
elem.text = resource
return xmlutil.MasterTemplate(root, 1)
class QuotaSetsController(wsgi.Controller): class QuotaSetsController(wsgi.Controller):
supported_quotas = [] supported_quotas = []
@ -113,7 +99,6 @@ class QuotaSetsController(wsgi.Controller):
else: else:
return dict((k, v['limit']) for k, v in values.items()) return dict((k, v['limit']) for k, v in values.items())
@wsgi.serializers(xml=QuotaTemplate)
def show(self, req, id): def show(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize_show(context) authorize_show(context)
@ -128,7 +113,6 @@ class QuotaSetsController(wsgi.Controller):
except exception.Forbidden: except exception.Forbidden:
raise webob.exc.HTTPForbidden() raise webob.exc.HTTPForbidden()
@wsgi.serializers(xml=QuotaTemplate)
def update(self, req, id, body): def update(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize_update(context) authorize_update(context)
@ -206,7 +190,6 @@ class QuotaSetsController(wsgi.Controller):
values = self._get_quotas(context, id, user_id=user_id) values = self._get_quotas(context, id, user_id=user_id)
return self._format_quota_set(None, values) return self._format_quota_set(None, values)
@wsgi.serializers(xml=QuotaTemplate)
def defaults(self, req, id): def defaults(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize_show(context) authorize_show(context)

View File

@ -11,7 +11,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from xml.dom import minidom
import six import six
import webob import webob
@ -20,7 +19,6 @@ from webob import exc
from nova.api.openstack.compute.contrib import security_groups as sg from nova.api.openstack.compute.contrib import security_groups as sg
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova.network.security_group import openstack_driver from nova.network.security_group import openstack_driver
@ -32,82 +30,12 @@ authorize = extensions.extension_authorizer('compute',
sg_nsmap = {None: wsgi.XMLNS_V11} sg_nsmap = {None: wsgi.XMLNS_V11}
def make_default_rule(elem):
elem.set('id')
proto = xmlutil.SubTemplateElement(elem, 'ip_protocol')
proto.text = 'ip_protocol'
from_port = xmlutil.SubTemplateElement(elem, 'from_port')
from_port.text = 'from_port'
to_port = xmlutil.SubTemplateElement(elem, 'to_port')
to_port.text = 'to_port'
ip_range = xmlutil.SubTemplateElement(elem, 'ip_range',
selector='ip_range')
cidr = xmlutil.SubTemplateElement(ip_range, 'cidr')
cidr.text = 'cidr'
class SecurityGroupDefaultRulesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('security_group_default_rules')
elem = xmlutil.SubTemplateElement(root, 'security_group_default_rule',
selector='security_group_default_rules')
make_default_rule(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
class SecurityGroupDefaultRuleTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('security_group_default_rule',
selector='security_group_default_rule')
make_default_rule(root)
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
class SecurityGroupDefaultRulesXMLDeserializer(wsgi.MetadataXMLDeserializer):
def default(self, string):
dom = minidom.parseString(string)
security_group_rule = self._extract_security_group_default_rule(dom)
return {'body': {'security_group_default_rule': security_group_rule}}
def _extract_security_group_default_rule(self, node):
sg_rule = {}
sg_rule_node = self.find_first_child_named(node,
'security_group_default_rule')
if sg_rule_node is not None:
ip_protocol_node = self.find_first_child_named(sg_rule_node,
"ip_protocol")
if ip_protocol_node is not None:
sg_rule['ip_protocol'] = self.extract_text(ip_protocol_node)
from_port_node = self.find_first_child_named(sg_rule_node,
"from_port")
if from_port_node is not None:
sg_rule['from_port'] = self.extract_text(from_port_node)
to_port_node = self.find_first_child_named(sg_rule_node, "to_port")
if to_port_node is not None:
sg_rule['to_port'] = self.extract_text(to_port_node)
cidr_node = self.find_first_child_named(sg_rule_node, "cidr")
if cidr_node is not None:
sg_rule['cidr'] = self.extract_text(cidr_node)
return sg_rule
class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase): class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
def __init__(self): def __init__(self):
self.security_group_api = ( self.security_group_api = (
openstack_driver.get_openstack_security_group_driver()) openstack_driver.get_openstack_security_group_driver())
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
@wsgi.deserializers(xml=SecurityGroupDefaultRulesXMLDeserializer)
def create(self, req, body): def create(self, req, body):
context = sg._authorize_context(req) context = sg._authorize_context(req)
authorize(context) authorize(context)
@ -141,7 +69,6 @@ class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
return self.security_group_api.new_cidr_ingress_rule( return self.security_group_api.new_cidr_ingress_rule(
cidr, ip_protocol, from_port, to_port) cidr, ip_protocol, from_port, to_port)
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
def show(self, req, id): def show(self, req, id):
context = sg._authorize_context(req) context = sg._authorize_context(req)
authorize(context) authorize(context)
@ -174,7 +101,6 @@ class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
return webob.Response(status_int=204) return webob.Response(status_int=204)
@wsgi.serializers(xml=SecurityGroupDefaultRulesTemplate)
def index(self, req): def index(self, req):
context = sg._authorize_context(req) context = sg._authorize_context(req)

View File

@ -27,7 +27,6 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -41,44 +40,6 @@ authorize = extensions.extension_authorizer('compute', 'security_groups')
softauth = extensions.soft_extension_authorizer('compute', 'security_groups') softauth = extensions.soft_extension_authorizer('compute', 'security_groups')
def make_rule(elem):
elem.set('id')
elem.set('parent_group_id')
proto = xmlutil.SubTemplateElement(elem, 'ip_protocol')
proto.text = 'ip_protocol'
from_port = xmlutil.SubTemplateElement(elem, 'from_port')
from_port.text = 'from_port'
to_port = xmlutil.SubTemplateElement(elem, 'to_port')
to_port.text = 'to_port'
group = xmlutil.SubTemplateElement(elem, 'group', selector='group')
name = xmlutil.SubTemplateElement(group, 'name')
name.text = 'name'
tenant_id = xmlutil.SubTemplateElement(group, 'tenant_id')
tenant_id.text = 'tenant_id'
ip_range = xmlutil.SubTemplateElement(elem, 'ip_range',
selector='ip_range')
cidr = xmlutil.SubTemplateElement(ip_range, 'cidr')
cidr.text = 'cidr'
def make_sg(elem):
elem.set('id')
elem.set('tenant_id')
elem.set('name')
desc = xmlutil.SubTemplateElement(elem, 'description')
desc.text = 'description'
rules = xmlutil.SubTemplateElement(elem, 'rules')
rule = xmlutil.SubTemplateElement(rules, 'rule', selector='rules')
make_rule(rule)
def _authorize_context(req): def _authorize_context(req):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -87,96 +48,6 @@ def _authorize_context(req):
sg_nsmap = {None: wsgi.XMLNS_V11} sg_nsmap = {None: wsgi.XMLNS_V11}
class SecurityGroupRuleTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('security_group_rule',
selector='security_group_rule')
make_rule(root)
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
class SecurityGroupTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('security_group',
selector='security_group')
make_sg(root)
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
class SecurityGroupsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('security_groups')
elem = xmlutil.SubTemplateElement(root, 'security_group',
selector='security_groups')
make_sg(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
class SecurityGroupXMLDeserializer(wsgi.MetadataXMLDeserializer):
"""Deserializer to handle xml-formatted security group requests."""
def default(self, string):
"""Deserialize an xml-formatted security group create request."""
dom = xmlutil.safe_minidom_parse_string(string)
security_group = {}
sg_node = self.find_first_child_named(dom,
'security_group')
if sg_node is not None:
if sg_node.hasAttribute('name'):
security_group['name'] = sg_node.getAttribute('name')
desc_node = self.find_first_child_named(sg_node,
"description")
if desc_node:
security_group['description'] = self.extract_text(desc_node)
return {'body': {'security_group': security_group}}
class SecurityGroupRulesXMLDeserializer(wsgi.MetadataXMLDeserializer):
"""Deserializer to handle xml-formatted security group requests."""
def default(self, string):
"""Deserialize an xml-formatted security group create request."""
dom = xmlutil.safe_minidom_parse_string(string)
security_group_rule = self._extract_security_group_rule(dom)
return {'body': {'security_group_rule': security_group_rule}}
def _extract_security_group_rule(self, node):
"""Marshal the security group rule attribute of a parsed request."""
sg_rule = {}
sg_rule_node = self.find_first_child_named(node,
'security_group_rule')
if sg_rule_node is not None:
ip_protocol_node = self.find_first_child_named(sg_rule_node,
"ip_protocol")
if ip_protocol_node is not None:
sg_rule['ip_protocol'] = self.extract_text(ip_protocol_node)
from_port_node = self.find_first_child_named(sg_rule_node,
"from_port")
if from_port_node is not None:
sg_rule['from_port'] = self.extract_text(from_port_node)
to_port_node = self.find_first_child_named(sg_rule_node, "to_port")
if to_port_node is not None:
sg_rule['to_port'] = self.extract_text(to_port_node)
parent_group_id_node = self.find_first_child_named(sg_rule_node,
"parent_group_id")
if parent_group_id_node is not None:
sg_rule['parent_group_id'] = self.extract_text(
parent_group_id_node)
group_id_node = self.find_first_child_named(sg_rule_node,
"group_id")
if group_id_node is not None:
sg_rule['group_id'] = self.extract_text(group_id_node)
cidr_node = self.find_first_child_named(sg_rule_node, "cidr")
if cidr_node is not None:
sg_rule['cidr'] = self.extract_text(cidr_node)
return sg_rule
@contextlib.contextmanager @contextlib.contextmanager
def translate_exceptions(): def translate_exceptions():
"""Translate nova exceptions to http exceptions.""" """Translate nova exceptions to http exceptions."""
@ -273,7 +144,6 @@ class SecurityGroupControllerBase(object):
class SecurityGroupController(SecurityGroupControllerBase): class SecurityGroupController(SecurityGroupControllerBase):
"""The Security group API controller for the OpenStack API.""" """The Security group API controller for the OpenStack API."""
@wsgi.serializers(xml=SecurityGroupTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given security group.""" """Return data about the given security group."""
context = _authorize_context(req) context = _authorize_context(req)
@ -298,7 +168,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.serializers(xml=SecurityGroupsTemplate)
def index(self, req): def index(self, req):
"""Returns a list of security groups.""" """Returns a list of security groups."""
context = _authorize_context(req) context = _authorize_context(req)
@ -320,8 +189,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
list(sorted(result, list(sorted(result,
key=lambda k: (k['tenant_id'], k['name'])))} key=lambda k: (k['tenant_id'], k['name'])))}
@wsgi.serializers(xml=SecurityGroupTemplate)
@wsgi.deserializers(xml=SecurityGroupXMLDeserializer)
def create(self, req, body): def create(self, req, body):
"""Creates a new security group.""" """Creates a new security group."""
context = _authorize_context(req) context = _authorize_context(req)
@ -341,7 +208,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
return {'security_group': self._format_security_group(context, return {'security_group': self._format_security_group(context,
group_ref)} group_ref)}
@wsgi.serializers(xml=SecurityGroupTemplate)
def update(self, req, id, body): def update(self, req, id, body):
"""Update a security group.""" """Update a security group."""
context = _authorize_context(req) context = _authorize_context(req)
@ -368,8 +234,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
class SecurityGroupRulesController(SecurityGroupControllerBase): class SecurityGroupRulesController(SecurityGroupControllerBase):
@wsgi.serializers(xml=SecurityGroupRuleTemplate)
@wsgi.deserializers(xml=SecurityGroupRulesXMLDeserializer)
def create(self, req, body): def create(self, req, body):
context = _authorize_context(req) context = _authorize_context(req)
@ -455,7 +319,6 @@ class SecurityGroupRulesController(SecurityGroupControllerBase):
class ServerSecurityGroupController(SecurityGroupControllerBase): class ServerSecurityGroupController(SecurityGroupControllerBase):
@wsgi.serializers(xml=SecurityGroupsTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns a list of security groups for the given instance.""" """Returns a list of security groups for the given instance."""
context = _authorize_context(req) context = _authorize_context(req)
@ -592,7 +455,7 @@ class SecurityGroupsOutputController(wsgi.Controller):
if not softauth(req.environ['nova.context']): if not softauth(req.environ['nova.context']):
return return
if 'server' in resp_obj.obj: if 'server' in resp_obj.obj:
resp_obj.attach(xml=SecurityGroupServerTemplate()) resp_obj.attach()
self._extend_servers(req, [resp_obj.obj['server']]) self._extend_servers(req, [resp_obj.obj['server']])
@wsgi.extends @wsgi.extends
@ -607,38 +470,10 @@ class SecurityGroupsOutputController(wsgi.Controller):
def detail(self, req, resp_obj): def detail(self, req, resp_obj):
if not softauth(req.environ['nova.context']): if not softauth(req.environ['nova.context']):
return return
resp_obj.attach(xml=SecurityGroupServersTemplate()) resp_obj.attach()
self._extend_servers(req, list(resp_obj.obj['servers'])) self._extend_servers(req, list(resp_obj.obj['servers']))
class SecurityGroupsTemplateElement(xmlutil.TemplateElement):
def will_render(self, datum):
return "security_groups" in datum
def make_server(elem):
secgrps = SecurityGroupsTemplateElement('security_groups')
elem.append(secgrps)
secgrp = xmlutil.SubTemplateElement(secgrps, 'security_group',
selector="security_groups")
secgrp.set('name')
class SecurityGroupServerTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
make_server(root)
return xmlutil.SlaveTemplate(root, 1)
class SecurityGroupServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1)
class Security_groups(extensions.ExtensionDescriptor): class Security_groups(extensions.ExtensionDescriptor):
"""Security group support.""" """Security group support."""
name = "SecurityGroups" name = "SecurityGroups"

View File

@ -18,7 +18,6 @@ import webob.exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -28,20 +27,10 @@ authorize = extensions.extension_authorizer('compute', 'server_diagnostics')
sd_nsmap = {None: wsgi.XMLNS_V11} sd_nsmap = {None: wsgi.XMLNS_V11}
class ServerDiagnosticsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('diagnostics')
elem = xmlutil.SubTemplateElement(root, xmlutil.Selector(0),
selector=xmlutil.get_items)
elem.text = 1
return xmlutil.MasterTemplate(root, 1, nsmap=sd_nsmap)
class ServerDiagnosticsController(object): class ServerDiagnosticsController(object):
def __init__(self): def __init__(self):
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.serializers(xml=ServerDiagnosticsTemplate)
def index(self, req, server_id): def index(self, req, server_id):
context = req.environ["nova.context"] context = req.environ["nova.context"]
authorize(context) authorize(context)

View File

@ -16,7 +16,6 @@ import webob
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -30,41 +29,12 @@ authorize = extensions.extension_authorizer('compute',
'os-server-external-events') 'os-server-external-events')
class EventTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('events')
elem1 = xmlutil.SubTemplateElement(root, 'event', selector='events')
elem2 = xmlutil.SubTemplateElement(elem1, xmlutil.Selector(0),
selector=xmlutil.get_items)
elem2.text = 1
return xmlutil.MasterTemplate(root, 1)
class EventDeserializer(wsgi.MetadataXMLDeserializer):
def _extract_event(self, event_node):
event = {}
for key in ('name', 'tag', 'server_uuid', 'status'):
node = self.find_first_child_named(event_node, key)
event[key] = self.extract_text(node)
return event
def default(self, string):
events = []
dom = xmlutil.safe_minidom_parse_string(string)
events_node = self.find_first_child_named(dom, 'events')
for event_node in self.find_children_named(events_node, 'event'):
events.append(self._extract_event(event_node))
return {'body': {'events': events}}
class ServerExternalEventsController(wsgi.Controller): class ServerExternalEventsController(wsgi.Controller):
def __init__(self): def __init__(self):
self.compute_api = compute.API() self.compute_api = compute.API()
super(ServerExternalEventsController, self).__init__() super(ServerExternalEventsController, self).__init__()
@wsgi.deserializers(xml=EventDeserializer)
@wsgi.serializers(xml=EventTemplate)
def create(self, req, body): def create(self, req, body):
"""Creates a new instance event.""" """Creates a new instance event."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import quota from nova import quota
QUOTAS = quota.QUOTAS QUOTAS = quota.QUOTAS
@ -39,27 +38,17 @@ class ExtendedQuotaSetsController(wsgi.Controller):
@wsgi.extends @wsgi.extends
def show(self, req, id, resp_obj): def show(self, req, id, resp_obj):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate()) resp_obj.attach()
@wsgi.extends @wsgi.extends
def update(self, req, id, body, resp_obj): def update(self, req, id, body, resp_obj):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate()) resp_obj.attach()
@wsgi.extends @wsgi.extends
def defaults(self, req, id, resp_obj): def defaults(self, req, id, resp_obj):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate()) resp_obj.attach()
class ExtendedQuotaSetsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('quota_set', selector='quota_set')
elem = xmlutil.SubTemplateElement(root, 'server_groups')
elem.text = 'server_groups'
elem = xmlutil.SubTemplateElement(root, 'server_group_members')
elem.text = 'server_group_members'
return xmlutil.SlaveTemplate(root, 1)
class ExtendedQuotaClassSetsController(wsgi.Controller): class ExtendedQuotaClassSetsController(wsgi.Controller):
@ -67,23 +56,12 @@ class ExtendedQuotaClassSetsController(wsgi.Controller):
@wsgi.extends @wsgi.extends
def show(self, req, id, resp_obj): def show(self, req, id, resp_obj):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaClassSetsTemplate()) resp_obj.attach()
@wsgi.extends @wsgi.extends
def update(self, req, id, body, resp_obj): def update(self, req, id, body, resp_obj):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaClassSetsTemplate()) resp_obj.attach()
class ExtendedQuotaClassSetsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('quota_class_set',
selector='quota_class_set')
elem = xmlutil.SubTemplateElement(root, 'server_groups')
elem.text = 'server_groups'
elem = xmlutil.SubTemplateElement(root, 'server_group_members')
elem.text = 'server_group_members'
return xmlutil.SlaveTemplate(root, 1)
class Server_group_quotas(extensions.ExtensionDescriptor): class Server_group_quotas(extensions.ExtensionDescriptor):

View File

@ -21,7 +21,6 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.exception import nova.exception
from nova.i18n import _ from nova.i18n import _
from nova.i18n import _LE from nova.i18n import _LE
@ -37,29 +36,7 @@ SUPPORTED_POLICIES = ['anti-affinity', 'affinity']
authorize = extensions.extension_authorizer('compute', 'server_groups') authorize = extensions.extension_authorizer('compute', 'server_groups')
def make_policy(elem): server_group_nsmap = {}
elem.text = str
def make_member(elem):
elem.text = str
def make_group(elem):
elem.set('name')
elem.set('id')
policies = xmlutil.SubTemplateElement(elem, 'policies')
policy = xmlutil.SubTemplateElement(policies, 'policy',
selector='policies')
make_policy(policy)
members = xmlutil.SubTemplateElement(elem, 'members')
member = xmlutil.SubTemplateElement(members, 'member',
selector='members')
make_member(member)
elem.append(common.MetadataTemplate())
server_group_nsmap = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM}
def _authorize_context(req): def _authorize_context(req):
@ -68,65 +45,6 @@ def _authorize_context(req):
return context return context
class ServerGroupTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server_group',
selector='server_group')
make_group(root)
return xmlutil.MasterTemplate(root, 1, nsmap=server_group_nsmap)
class ServerGroupsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server_groups')
elem = xmlutil.SubTemplateElement(root, 'server_group',
selector='server_groups')
# Note: listing server groups only shows name and uuid
make_group(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=server_group_nsmap)
class ServerGroupXMLDeserializer(wsgi.MetadataXMLDeserializer):
"""Deserializer to handle xml-formatted server group requests."""
metadata_deserializer = common.MetadataXMLDeserializer()
def default(self, string):
"""Deserialize an xml-formatted server group create request."""
dom = xmlutil.safe_minidom_parse_string(string)
server_group = self._extract_server_group(dom)
return {'body': {'server_group': server_group}}
def _extract_server_group(self, node):
"""Marshal the instance attribute of a parsed request."""
server_group = {}
sg_node = self.find_first_child_named(node, 'server_group')
if sg_node is not None:
if sg_node.hasAttribute('name'):
server_group['name'] = sg_node.getAttribute('name')
if sg_node.hasAttribute('id'):
server_group['id'] = sg_node.getAttribute('id')
policies = self._extract_policies(sg_node)
server_group['policies'] = policies or []
return server_group
def _extract_policies(self, server_group_node):
"""Marshal the server group policies element of a parsed request."""
policies_node = self.find_first_child_named(server_group_node,
'policies')
if policies_node is not None:
policy_nodes = self.find_children_named(policies_node,
'policy')
policies = []
if policy_nodes is not None:
for node in policy_nodes:
policies.append(node.firstChild.nodeValue)
return policies
class ServerGroupController(wsgi.Controller): class ServerGroupController(wsgi.Controller):
"""The Server group API controller for the OpenStack API.""" """The Server group API controller for the OpenStack API."""
@ -210,7 +128,6 @@ class ServerGroupController(wsgi.Controller):
msg = _("unsupported fields: %s") % subbody.keys() msg = _("unsupported fields: %s") % subbody.keys()
raise nova.exception.InvalidInput(reason=msg) raise nova.exception.InvalidInput(reason=msg)
@wsgi.serializers(xml=ServerGroupTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given server group.""" """Return data about the given server group."""
context = _authorize_context(req) context = _authorize_context(req)
@ -255,7 +172,6 @@ class ServerGroupController(wsgi.Controller):
return webob.Response(status_int=204) return webob.Response(status_int=204)
@wsgi.serializers(xml=ServerGroupsTemplate)
def index(self, req): def index(self, req):
"""Returns a list of server groups.""" """Returns a list of server groups."""
context = _authorize_context(req) context = _authorize_context(req)
@ -270,8 +186,6 @@ class ServerGroupController(wsgi.Controller):
for group in limited_list] for group in limited_list]
return {'server_groups': result} return {'server_groups': result}
@wsgi.serializers(xml=ServerGroupTemplate)
@wsgi.deserializers(xml=ServerGroupXMLDeserializer)
def create(self, req, body): def create(self, req, body):
"""Creates a new server group.""" """Creates a new server group."""
context = _authorize_context(req) context = _authorize_context(req)
@ -310,11 +224,6 @@ class ServerGroupController(wsgi.Controller):
return {'server_group': self._format_server_group(context, sg)} return {'server_group': self._format_server_group(context, sg)}
class ServerGroupsTemplateElement(xmlutil.TemplateElement):
def will_render(self, datum):
return "server_groups" in datum
class Server_groups(extensions.ExtensionDescriptor): class Server_groups(extensions.ExtensionDescriptor):
"""Server group support.""" """Server group support."""
name = "ServerGroups" name = "ServerGroups"

View File

@ -19,26 +19,17 @@ from nova.api.metadata import password
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
authorize = extensions.extension_authorizer('compute', 'server_password') authorize = extensions.extension_authorizer('compute', 'server_password')
class ServerPasswordTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('password', selector='password')
root.text = unicode
return xmlutil.MasterTemplate(root, 1)
class ServerPasswordController(object): class ServerPasswordController(object):
"""The Server Password API controller for the OpenStack API.""" """The Server Password API controller for the OpenStack API."""
def __init__(self): def __init__(self):
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.serializers(xml=ServerPasswordTemplate)
def index(self, req, server_id): def index(self, req, server_id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova.openstack.common import log as logging from nova.openstack.common import log as logging
@ -42,7 +41,7 @@ class ServerUsageController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ServerUsageTemplate()) resp_obj.attach()
server = resp_obj.obj['server'] server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to # server['id'] is guaranteed to be in the cache due to
@ -54,7 +53,7 @@ class ServerUsageController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
if authorize(context): if authorize(context):
# Attach our slave template to the response object # Attach our slave template to the response object
resp_obj.attach(xml=ServerUsagesTemplate()) resp_obj.attach()
servers = list(resp_obj.obj['servers']) servers = list(resp_obj.obj['servers'])
for server in servers: for server in servers:
db_instance = req.get_db_instance(server['id']) db_instance = req.get_db_instance(server['id'])
@ -76,27 +75,3 @@ class Server_usage(extensions.ExtensionDescriptor):
controller = ServerUsageController() controller = ServerUsageController()
extension = extensions.ControllerExtension(self, 'servers', controller) extension = extensions.ControllerExtension(self, 'servers', controller)
return [extension] return [extension]
def make_server(elem):
elem.set('{%s}launched_at' % Server_usage.namespace,
'%s:launched_at' % Server_usage.alias)
elem.set('{%s}terminated_at' % Server_usage.namespace,
'%s:terminated_at' % Server_usage.alias)
class ServerUsageTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Server_usage.alias: Server_usage.namespace})
class ServerUsagesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
return xmlutil.SlaveTemplate(root, 1, nsmap={
Server_usage.alias: Server_usage.namespace})

View File

@ -16,7 +16,6 @@ import webob.exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -26,48 +25,6 @@ from nova import utils
authorize = extensions.extension_authorizer('compute', 'services') authorize = extensions.extension_authorizer('compute', 'services')
class ServicesIndexTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('services')
elem = xmlutil.SubTemplateElement(root, 'service', selector='services')
elem.set('id')
elem.set('binary')
elem.set('host')
elem.set('zone')
elem.set('status')
elem.set('state')
elem.set('updated_at')
elem.set('disabled_reason')
return xmlutil.MasterTemplate(root, 1)
class ServiceUpdateTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('service', selector='service')
root.set('host')
root.set('binary')
root.set('status')
root.set('disabled_reason')
return xmlutil.MasterTemplate(root, 1)
class ServiceUpdateDeserializer(wsgi.XMLDeserializer):
def default(self, string):
node = xmlutil.safe_minidom_parse_string(string)
service = {}
service_node = self.find_first_child_named(node, 'service')
if service_node is None:
return service
service['host'] = service_node.getAttribute('host')
service['binary'] = service_node.getAttribute('binary')
service['disabled_reason'] = service_node.getAttribute(
'disabled_reason')
return dict(body=service)
class ServiceController(object): class ServiceController(object):
def __init__(self, ext_mgr=None, *args, **kwargs): def __init__(self, ext_mgr=None, *args, **kwargs):
@ -143,7 +100,6 @@ class ServiceController(object):
explanation = _("Service %s not found.") % id explanation = _("Service %s not found.") % id
raise webob.exc.HTTPNotFound(explanation=explanation) raise webob.exc.HTTPNotFound(explanation=explanation)
@wsgi.serializers(xml=ServicesIndexTemplate)
def index(self, req): def index(self, req):
"""Return a list of all running services.""" """Return a list of all running services."""
detailed = self.ext_mgr.is_loaded('os-extended-services') detailed = self.ext_mgr.is_loaded('os-extended-services')
@ -151,8 +107,6 @@ class ServiceController(object):
return {'services': services} return {'services': services}
@wsgi.deserializers(xml=ServiceUpdateDeserializer)
@wsgi.serializers(xml=ServiceUpdateTemplate)
def update(self, req, id, body): def update(self, req, id, body):
"""Enable/Disable scheduling for a service.""" """Enable/Disable scheduling for a service."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -22,8 +22,6 @@ import six.moves.urllib.parse as urlparse
from webob import exc from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import objects from nova import objects
@ -34,23 +32,6 @@ authorize_list = extensions.extension_authorizer('compute',
'simple_tenant_usage:list') 'simple_tenant_usage:list')
def make_usage(elem):
for subelem_tag in ('tenant_id', 'total_local_gb_usage',
'total_vcpus_usage', 'total_memory_mb_usage',
'total_hours', 'start', 'stop'):
subelem = xmlutil.SubTemplateElement(elem, subelem_tag)
subelem.text = subelem_tag
server_usages = xmlutil.SubTemplateElement(elem, 'server_usages')
server_usage = xmlutil.SubTemplateElement(server_usages, 'server_usage',
selector='server_usages')
for subelem_tag in ('instance_id', 'name', 'hours', 'memory_mb',
'local_gb', 'vcpus', 'tenant_id', 'flavor',
'started_at', 'ended_at', 'state', 'uptime'):
subelem = xmlutil.SubTemplateElement(server_usage, subelem_tag)
subelem.text = subelem_tag
def parse_strtime(dstr, fmt): def parse_strtime(dstr, fmt):
try: try:
return timeutils.parse_strtime(dstr, fmt) return timeutils.parse_strtime(dstr, fmt)
@ -58,22 +39,6 @@ def parse_strtime(dstr, fmt):
raise exception.InvalidStrTime(reason=six.text_type(e)) raise exception.InvalidStrTime(reason=six.text_type(e))
class SimpleTenantUsageTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('tenant_usage', selector='tenant_usage')
make_usage(root)
return xmlutil.MasterTemplate(root, 1)
class SimpleTenantUsagesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('tenant_usages')
elem = xmlutil.SubTemplateElement(root, 'tenant_usage',
selector='tenant_usages')
make_usage(elem)
return xmlutil.MasterTemplate(root, 1)
class SimpleTenantUsageController(object): class SimpleTenantUsageController(object):
def _hours_for(self, instance, period_start, period_stop): def _hours_for(self, instance, period_start, period_stop):
launched_at = instance.launched_at launched_at = instance.launched_at
@ -254,7 +219,6 @@ class SimpleTenantUsageController(object):
detailed = env.get('detailed', ['0'])[0] == '1' detailed = env.get('detailed', ['0'])[0] == '1'
return (period_start, period_stop, detailed) return (period_start, period_stop, detailed)
@wsgi.serializers(xml=SimpleTenantUsagesTemplate)
def index(self, req): def index(self, req):
"""Retrieve tenant_usage for all tenants.""" """Retrieve tenant_usage for all tenants."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -276,7 +240,6 @@ class SimpleTenantUsageController(object):
detailed=detailed) detailed=detailed)
return {'tenant_usages': usages} return {'tenant_usages': usages}
@wsgi.serializers(xml=SimpleTenantUsageTemplate)
def show(self, req, id): def show(self, req, id):
"""Retrieve tenant_usage for a specified tenant.""" """Retrieve tenant_usage for a specified tenant."""
tenant_id = id tenant_id = id

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import quota from nova import quota
@ -28,13 +27,6 @@ authorize_for_admin = extensions.extension_authorizer('compute',
'used_limits_for_admin') 'used_limits_for_admin')
class UsedLimitsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('limits', selector='limits')
root.set('{%s}usedLimits' % XMLNS, '%s:usedLimits' % ALIAS)
return xmlutil.SlaveTemplate(root, 1, nsmap={ALIAS: XMLNS})
class UsedLimitsController(wsgi.Controller): class UsedLimitsController(wsgi.Controller):
def __init__(self, ext_mgr): def __init__(self, ext_mgr):
@ -49,7 +41,7 @@ class UsedLimitsController(wsgi.Controller):
@wsgi.extends @wsgi.extends
def index(self, req, resp_obj): def index(self, req, resp_obj):
resp_obj.attach(xml=UsedLimitsTemplate()) resp_obj.attach()
context = req.environ['nova.context'] context = req.environ['nova.context']
project_id = self._project_id(context, req) project_id = self._project_id(context, req)
quotas = QUOTAS.get_project_quotas(context, project_id, usages=True) quotas = QUOTAS.get_project_quotas(context, project_id, usages=True)

View File

@ -18,7 +18,6 @@
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import network from nova import network
@ -29,16 +28,6 @@ authorize = extensions.extension_authorizer('compute', 'virtual_interfaces')
vif_nsmap = {None: wsgi.XMLNS_V11} vif_nsmap = {None: wsgi.XMLNS_V11}
class VirtualInterfaceTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('virtual_interfaces')
elem = xmlutil.SubTemplateElement(root, 'virtual_interface',
selector='virtual_interfaces')
elem.set('id')
elem.set('mac_address')
return xmlutil.MasterTemplate(root, 1, nsmap=vif_nsmap)
def _translate_vif_summary_view(_context, vif): def _translate_vif_summary_view(_context, vif):
"""Maps keys for VIF summary view.""" """Maps keys for VIF summary view."""
d = {} d = {}
@ -67,7 +56,6 @@ class ServerVirtualInterfaceController(object):
res = [entity_maker(context, vif) for vif in limited_list] res = [entity_maker(context, vif) for vif in limited_list]
return {'virtual_interfaces': res} return {'virtual_interfaces': res}
@wsgi.serializers(xml=VirtualInterfaceTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns the list of VIFs for a given instance.""" """Returns the list of VIFs for a given instance."""
authorize(req.environ['nova.context']) authorize(req.environ['nova.context'])

View File

@ -22,7 +22,6 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
@ -84,82 +83,6 @@ def _translate_volume_summary_view(context, vol):
return d return d
def make_volume(elem):
elem.set('id')
elem.set('status')
elem.set('size')
elem.set('availabilityZone')
elem.set('createdAt')
elem.set('displayName')
elem.set('displayDescription')
elem.set('volumeType')
elem.set('snapshotId')
attachments = xmlutil.SubTemplateElement(elem, 'attachments')
attachment = xmlutil.SubTemplateElement(attachments, 'attachment',
selector='attachments')
make_attachment(attachment)
# Attach metadata node
elem.append(common.MetadataTemplate())
class VolumeTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('volume', selector='volume')
make_volume(root)
return xmlutil.MasterTemplate(root, 1)
class VolumesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('volumes')
elem = xmlutil.SubTemplateElement(root, 'volume', selector='volumes')
make_volume(elem)
return xmlutil.MasterTemplate(root, 1)
class CommonDeserializer(wsgi.MetadataXMLDeserializer):
"""Common deserializer to handle xml-formatted volume requests.
Handles standard volume attributes as well as the optional metadata
attribute
"""
metadata_deserializer = common.MetadataXMLDeserializer()
def _extract_volume(self, node):
"""Marshal the volume attribute of a parsed request."""
vol = {}
volume_node = self.find_first_child_named(node, 'volume')
attributes = ['display_name', 'display_description', 'size',
'volume_type', 'availability_zone']
for attr in attributes:
if volume_node.getAttribute(attr):
vol[attr] = volume_node.getAttribute(attr)
metadata_node = self.find_first_child_named(volume_node, 'metadata')
if metadata_node is not None:
vol['metadata'] = self.extract_metadata(metadata_node)
return vol
class CreateDeserializer(CommonDeserializer):
"""Deserializer to handle xml-formatted create volume requests.
Handles standard volume attributes as well as the optional metadata
attribute
"""
def default(self, string):
"""Deserialize an xml-formatted volume create request."""
dom = xmlutil.safe_minidom_parse_string(string)
vol = self._extract_volume(dom)
return {'body': {'volume': vol}}
class VolumeController(wsgi.Controller): class VolumeController(wsgi.Controller):
"""The Volumes API controller for the OpenStack API.""" """The Volumes API controller for the OpenStack API."""
@ -167,7 +90,6 @@ class VolumeController(wsgi.Controller):
self.volume_api = volume.API() self.volume_api = volume.API()
super(VolumeController, self).__init__() super(VolumeController, self).__init__()
@wsgi.serializers(xml=VolumeTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given volume.""" """Return data about the given volume."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -193,12 +115,10 @@ class VolumeController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.serializers(xml=VolumesTemplate)
def index(self, req): def index(self, req):
"""Returns a summary list of volumes.""" """Returns a summary list of volumes."""
return self._items(req, entity_maker=_translate_volume_summary_view) return self._items(req, entity_maker=_translate_volume_summary_view)
@wsgi.serializers(xml=VolumesTemplate)
def detail(self, req): def detail(self, req):
"""Returns a detailed list of volumes.""" """Returns a detailed list of volumes."""
return self._items(req, entity_maker=_translate_volume_detail_view) return self._items(req, entity_maker=_translate_volume_detail_view)
@ -213,8 +133,6 @@ class VolumeController(wsgi.Controller):
res = [entity_maker(context, vol) for vol in limited_list] res = [entity_maker(context, vol) for vol in limited_list]
return {'volumes': res} return {'volumes': res}
@wsgi.serializers(xml=VolumeTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body): def create(self, req, body):
"""Creates a new volume.""" """Creates a new volume."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -297,30 +215,6 @@ def _translate_attachment_summary_view(volume_id, instance_uuid, mountpoint):
return d return d
def make_attachment(elem):
elem.set('id')
elem.set('serverId')
elem.set('volumeId')
elem.set('device')
class VolumeAttachmentTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('volumeAttachment',
selector='volumeAttachment')
make_attachment(root)
return xmlutil.MasterTemplate(root, 1)
class VolumeAttachmentsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('volumeAttachments')
elem = xmlutil.SubTemplateElement(root, 'volumeAttachment',
selector='volumeAttachments')
make_attachment(elem)
return xmlutil.MasterTemplate(root, 1)
class VolumeAttachmentController(wsgi.Controller): class VolumeAttachmentController(wsgi.Controller):
"""The volume attachment API controller for the OpenStack API. """The volume attachment API controller for the OpenStack API.
@ -335,7 +229,6 @@ class VolumeAttachmentController(wsgi.Controller):
self.ext_mgr = ext_mgr self.ext_mgr = ext_mgr
super(VolumeAttachmentController, self).__init__() super(VolumeAttachmentController, self).__init__()
@wsgi.serializers(xml=VolumeAttachmentsTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns the list of volume attachments for a given instance.""" """Returns the list of volume attachments for a given instance."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -343,7 +236,6 @@ class VolumeAttachmentController(wsgi.Controller):
return self._items(req, server_id, return self._items(req, server_id,
entity_maker=_translate_attachment_summary_view) entity_maker=_translate_attachment_summary_view)
@wsgi.serializers(xml=VolumeAttachmentTemplate)
def show(self, req, server_id, id): def show(self, req, server_id, id):
"""Return data about the given volume attachment.""" """Return data about the given volume attachment."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -381,7 +273,6 @@ class VolumeAttachmentController(wsgi.Controller):
"not in proper format (%s)") % volume_id "not in proper format (%s)") % volume_id
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
@wsgi.serializers(xml=VolumeAttachmentTemplate)
def create(self, req, server_id, body): def create(self, req, server_id, body):
"""Attach a volume to an instance.""" """Attach a volume to an instance."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -585,32 +476,6 @@ def _translate_snapshot_summary_view(context, vol):
return d return d
def make_snapshot(elem):
elem.set('id')
elem.set('status')
elem.set('size')
elem.set('createdAt')
elem.set('displayName')
elem.set('displayDescription')
elem.set('volumeId')
class SnapshotTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('snapshot', selector='snapshot')
make_snapshot(root)
return xmlutil.MasterTemplate(root, 1)
class SnapshotsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('snapshots')
elem = xmlutil.SubTemplateElement(root, 'snapshot',
selector='snapshots')
make_snapshot(elem)
return xmlutil.MasterTemplate(root, 1)
class SnapshotController(wsgi.Controller): class SnapshotController(wsgi.Controller):
"""The Snapshots API controller for the OpenStack API.""" """The Snapshots API controller for the OpenStack API."""
@ -618,7 +483,6 @@ class SnapshotController(wsgi.Controller):
self.volume_api = volume.API() self.volume_api = volume.API()
super(SnapshotController, self).__init__() super(SnapshotController, self).__init__()
@wsgi.serializers(xml=SnapshotTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given snapshot.""" """Return data about the given snapshot."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -644,12 +508,10 @@ class SnapshotController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.serializers(xml=SnapshotsTemplate)
def index(self, req): def index(self, req):
"""Returns a summary list of snapshots.""" """Returns a summary list of snapshots."""
return self._items(req, entity_maker=_translate_snapshot_summary_view) return self._items(req, entity_maker=_translate_snapshot_summary_view)
@wsgi.serializers(xml=SnapshotsTemplate)
def detail(self, req): def detail(self, req):
"""Returns a detailed list of snapshots.""" """Returns a detailed list of snapshots."""
return self._items(req, entity_maker=_translate_snapshot_detail_view) return self._items(req, entity_maker=_translate_snapshot_detail_view)
@ -664,7 +526,6 @@ class SnapshotController(wsgi.Controller):
res = [entity_maker(context, snapshot) for snapshot in limited_list] res = [entity_maker(context, snapshot) for snapshot in limited_list]
return {'snapshots': res} return {'snapshots': res}
@wsgi.serializers(xml=SnapshotTemplate)
def create(self, req, body): def create(self, req, body):
"""Creates a new snapshot.""" """Creates a new snapshot."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -19,48 +19,13 @@ import webob
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute.views import flavors as flavors_view from nova.api.openstack.compute.views import flavors as flavors_view
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import flavors from nova.compute import flavors
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova import utils from nova import utils
def make_flavor(elem, detailed=False): flavor_nsmap = {}
elem.set('name')
elem.set('id')
if detailed:
elem.set('ram')
elem.set('disk')
elem.set('vcpus', xmlutil.EmptyStringSelector('vcpus'))
xmlutil.make_links(elem, 'links')
flavor_nsmap = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM}
class FlavorTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavor', selector='flavor')
make_flavor(root, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=flavor_nsmap)
class MinimalFlavorsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=flavor_nsmap)
class FlavorsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('flavors')
elem = xmlutil.SubTemplateElement(root, 'flavor', selector='flavors')
make_flavor(elem, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=flavor_nsmap)
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
@ -68,20 +33,17 @@ class Controller(wsgi.Controller):
_view_builder_class = flavors_view.ViewBuilder _view_builder_class = flavors_view.ViewBuilder
@wsgi.serializers(xml=MinimalFlavorsTemplate)
def index(self, req): def index(self, req):
"""Return all flavors in brief.""" """Return all flavors in brief."""
limited_flavors = self._get_flavors(req) limited_flavors = self._get_flavors(req)
return self._view_builder.index(req, limited_flavors) return self._view_builder.index(req, limited_flavors)
@wsgi.serializers(xml=FlavorsTemplate)
def detail(self, req): def detail(self, req):
"""Return all flavors in detail.""" """Return all flavors in detail."""
limited_flavors = self._get_flavors(req) limited_flavors = self._get_flavors(req)
req.cache_db_flavors(limited_flavors) req.cache_db_flavors(limited_flavors)
return self._view_builder.detail(req, limited_flavors) return self._view_builder.detail(req, limited_flavors)
@wsgi.serializers(xml=FlavorTemplate)
def show(self, req, id): def show(self, req, id):
"""Return data about the given flavor id.""" """Return data about the given flavor id."""
try: try:

View File

@ -37,14 +37,12 @@ class Controller(object):
msg = _("Image not found.") msg = _("Image not found.")
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
@wsgi.serializers(xml=common.MetadataTemplate)
def index(self, req, image_id): def index(self, req, image_id):
"""Returns the list of metadata for a given instance.""" """Returns the list of metadata for a given instance."""
context = req.environ['nova.context'] context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties'] metadata = self._get_image(context, image_id)['properties']
return dict(metadata=metadata) return dict(metadata=metadata)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, image_id, id): def show(self, req, image_id, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties'] metadata = self._get_image(context, image_id)['properties']
@ -53,8 +51,6 @@ class Controller(object):
else: else:
raise exc.HTTPNotFound() raise exc.HTTPNotFound()
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def create(self, req, image_id, body): def create(self, req, image_id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
image = self._get_image(context, image_id) image = self._get_image(context, image_id)
@ -70,8 +66,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message()) raise exc.HTTPForbidden(explanation=e.format_message())
return dict(metadata=image['properties']) return dict(metadata=image['properties'])
@wsgi.serializers(xml=common.MetaItemTemplate)
@wsgi.deserializers(xml=common.MetaItemDeserializer)
def update(self, req, image_id, id, body): def update(self, req, image_id, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -99,8 +93,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message()) raise exc.HTTPForbidden(explanation=e.format_message())
return dict(meta=meta) return dict(meta=meta)
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def update_all(self, req, image_id, body): def update_all(self, req, image_id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
image = self._get_image(context, image_id) image = self._get_image(context, image_id)

View File

@ -18,7 +18,6 @@ import webob.exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute.views import images as views_images from nova.api.openstack.compute.views import images as views_images
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
import nova.image import nova.image
@ -36,52 +35,7 @@ SUPPORTED_FILTERS = {
} }
def make_image(elem, detailed=False): image_nsmap = {}
elem.set('name')
elem.set('id')
if detailed:
elem.set('updated')
elem.set('created')
elem.set('status')
elem.set('progress')
elem.set('minRam')
elem.set('minDisk')
server = xmlutil.SubTemplateElement(elem, 'server', selector='server')
server.set('id')
xmlutil.make_links(server, 'links')
elem.append(common.MetadataTemplate())
xmlutil.make_links(elem, 'links')
image_nsmap = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM}
class ImageTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('image', selector='image')
make_image(root, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=image_nsmap)
class MinimalImagesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('images')
elem = xmlutil.SubTemplateElement(root, 'image', selector='images')
make_image(elem)
xmlutil.make_links(root, 'images_links')
return xmlutil.MasterTemplate(root, 1, nsmap=image_nsmap)
class ImagesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('images')
elem = xmlutil.SubTemplateElement(root, 'image', selector='images')
make_image(elem, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=image_nsmap)
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
@ -120,7 +74,6 @@ class Controller(wsgi.Controller):
return filters return filters
@wsgi.serializers(xml=ImageTemplate)
def show(self, req, id): def show(self, req, id):
"""Return detailed information about a specific image. """Return detailed information about a specific image.
@ -157,7 +110,6 @@ class Controller(wsgi.Controller):
raise webob.exc.HTTPForbidden(explanation=explanation) raise webob.exc.HTTPForbidden(explanation=explanation)
return webob.exc.HTTPNoContent() return webob.exc.HTTPNoContent()
@wsgi.serializers(xml=MinimalImagesTemplate)
def index(self, req): def index(self, req):
"""Return an index listing of images available to the request. """Return an index listing of images available to the request.
@ -178,7 +130,6 @@ class Controller(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=e.format_message()) raise webob.exc.HTTPBadRequest(explanation=e.format_message())
return self._view_builder.index(req, images) return self._view_builder.index(req, images)
@wsgi.serializers(xml=ImagesTemplate)
def detail(self, req): def detail(self, req):
"""Return a detailed index listing of images available to the request. """Return a detailed index listing of images available to the request.

View File

@ -19,36 +19,10 @@ import nova
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute.views import addresses as view_addresses from nova.api.openstack.compute.views import addresses as view_addresses
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _ from nova.i18n import _
def make_network(elem): network_nsmap = {}
elem.set('id', 0)
ip = xmlutil.SubTemplateElement(elem, 'ip', selector=1)
ip.set('version')
ip.set('addr')
network_nsmap = {None: xmlutil.XMLNS_V11}
class NetworkTemplate(xmlutil.TemplateBuilder):
def construct(self):
sel = xmlutil.Selector(xmlutil.get_items, 0)
root = xmlutil.TemplateElement('network', selector=sel)
make_network(root)
return xmlutil.MasterTemplate(root, 1, nsmap=network_nsmap)
class AddressesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('addresses', selector='addresses')
elem = xmlutil.SubTemplateElement(root, 'network',
selector=xmlutil.get_items)
make_network(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=network_nsmap)
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
@ -60,14 +34,12 @@ class Controller(wsgi.Controller):
super(Controller, self).__init__(**kwargs) super(Controller, self).__init__(**kwargs)
self._compute_api = nova.compute.API() self._compute_api = nova.compute.API()
@wsgi.serializers(xml=AddressesTemplate)
def index(self, req, server_id): def index(self, req, server_id):
context = req.environ["nova.context"] context = req.environ["nova.context"]
instance = common.get_instance(self._compute_api, context, server_id) instance = common.get_instance(self._compute_api, context, server_id)
networks = common.get_networks_for_instance(context, instance) networks = common.get_networks_for_instance(context, instance)
return self._view_builder.index(networks) return self._view_builder.index(networks)
@wsgi.serializers(xml=NetworkTemplate)
def show(self, req, server_id, id): def show(self, req, server_id, id):
context = req.environ["nova.context"] context = req.environ["nova.context"]
instance = common.get_instance(self._compute_api, context, server_id) instance = common.get_instance(self._compute_api, context, server_id)

View File

@ -45,7 +45,6 @@ import webob.exc
from nova.api.openstack.compute.views import limits as limits_views from nova.api.openstack.compute.views import limits as limits_views
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _ from nova.i18n import _
from nova import quota from nova import quota
from nova import utils from nova import utils
@ -56,38 +55,12 @@ QUOTAS = quota.QUOTAS
LIMITS_PREFIX = "limits." LIMITS_PREFIX = "limits."
limits_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM} limits_nsmap = {}
class LimitsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('limits', selector='limits')
rates = xmlutil.SubTemplateElement(root, 'rates')
rate = xmlutil.SubTemplateElement(rates, 'rate', selector='rate')
rate.set('uri', 'uri')
rate.set('regex', 'regex')
limit = xmlutil.SubTemplateElement(rate, 'limit', selector='limit')
limit.set('value', 'value')
limit.set('verb', 'verb')
limit.set('remaining', 'remaining')
limit.set('unit', 'unit')
limit.set('next-available', 'next-available')
absolute = xmlutil.SubTemplateElement(root, 'absolute',
selector='absolute')
limit = xmlutil.SubTemplateElement(absolute, 'limit',
selector=xmlutil.get_items)
limit.set('name', 0)
limit.set('value', 1)
return xmlutil.MasterTemplate(root, 1, nsmap=limits_nsmap)
class LimitsController(object): class LimitsController(object):
"""Controller for accessing limits in the OpenStack API.""" """Controller for accessing limits in the OpenStack API."""
@wsgi.serializers(xml=LimitsTemplate)
def index(self, req): def index(self, req):
"""Return all global and rate limit information.""" """Return all global and rate limit information."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -55,13 +55,6 @@ CONF.import_opt('admin_tenant_name',
CONF.import_opt('compute_driver', 'nova.virt.driver') CONF.import_opt('compute_driver', 'nova.virt.driver')
def _interface_dict(interface_ref):
d = {}
for f in interface_fields:
d[f] = interface_ref.get(f)
return d
def _get_ironic_client(): def _get_ironic_client():
"""return an Ironic client.""" """return an Ironic client."""
# TODO(NobodyCam): Fix insecure setting # TODO(NobodyCam): Fix insecure setting

View File

@ -1,141 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-*- rnc -*-
RELAX NG Compact Syntax Grammar for the
Atom Format Specification Version 11
-->
<grammar xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:s="http://www.ascc.net/xml/schematron" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<choice>
<ref name="atomLink"/>
</choice>
</start>
<!-- Common attributes -->
<define name="atomCommonAttributes">
<optional>
<attribute name="xml:base">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="xml:lang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<zeroOrMore>
<ref name="undefinedAttribute"/>
</zeroOrMore>
</define>
<!-- atom:link -->
<define name="atomLink">
<element name="atom:link">
<ref name="atomCommonAttributes"/>
<attribute name="href">
<ref name="atomUri"/>
</attribute>
<optional>
<attribute name="rel">
<choice>
<ref name="atomNCName"/>
<ref name="atomUri"/>
</choice>
</attribute>
</optional>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<optional>
<attribute name="hreflang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<optional>
<attribute name="title"/>
</optional>
<optional>
<attribute name="length"/>
</optional>
<ref name="undefinedContent"/>
</element>
</define>
<!-- Low-level simple types -->
<define name="atomNCName">
<data type="string">
<param name="minLength">1</param>
<param name="pattern">[^:]*</param>
</data>
</define>
<!-- Whatever a media type is, it contains at least one slash -->
<define name="atomMediaType">
<data type="string">
<param name="pattern">.+/.+</param>
</data>
</define>
<!-- As defined in RFC 3066 -->
<define name="atomLanguageTag">
<data type="string">
<param name="pattern">[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*</param>
</data>
</define>
<!--
Unconstrained; it's not entirely clear how IRI fit into
xsd:anyURI so let's not try to constrain it here
-->
<define name="atomUri">
<text/>
</define>
<!-- Other Extensibility -->
<define name="undefinedAttribute">
<attribute>
<anyName>
<except>
<name>xml:base</name>
<name>xml:lang</name>
<nsName ns=""/>
</except>
</anyName>
</attribute>
</define>
<define name="undefinedContent">
<zeroOrMore>
<choice>
<text/>
<ref name="anyForeignElement"/>
</choice>
</zeroOrMore>
</define>
<define name="anyElement">
<element>
<anyName/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="anyForeignElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
</grammar>

View File

@ -1,597 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
-*- rnc -*-
RELAX NG Compact Syntax Grammar for the
Atom Format Specification Version 11
-->
<grammar xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:s="http://www.ascc.net/xml/schematron" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
<start>
<choice>
<ref name="atomFeed"/>
<ref name="atomEntry"/>
</choice>
</start>
<!-- Common attributes -->
<define name="atomCommonAttributes">
<optional>
<attribute name="xml:base">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="xml:lang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<zeroOrMore>
<ref name="undefinedAttribute"/>
</zeroOrMore>
</define>
<!-- Text Constructs -->
<define name="atomPlainTextConstruct">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<choice>
<value>text</value>
<value>html</value>
</choice>
</attribute>
</optional>
<text/>
</define>
<define name="atomXHTMLTextConstruct">
<ref name="atomCommonAttributes"/>
<attribute name="type">
<value>xhtml</value>
</attribute>
<ref name="xhtmlDiv"/>
</define>
<define name="atomTextConstruct">
<choice>
<ref name="atomPlainTextConstruct"/>
<ref name="atomXHTMLTextConstruct"/>
</choice>
</define>
<!-- Person Construct -->
<define name="atomPersonConstruct">
<ref name="atomCommonAttributes"/>
<interleave>
<element name="atom:name">
<text/>
</element>
<optional>
<element name="atom:uri">
<ref name="atomUri"/>
</element>
</optional>
<optional>
<element name="atom:email">
<ref name="atomEmailAddress"/>
</element>
</optional>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</define>
<!-- Date Construct -->
<define name="atomDateConstruct">
<ref name="atomCommonAttributes"/>
<data type="dateTime"/>
</define>
<!-- atom:feed -->
<define name="atomFeed">
<element name="atom:feed">
<s:rule context="atom:feed">
<s:assert test="atom:author or not(atom:entry[not(atom:author)])">An atom:feed must have an atom:author unless all of its atom:entry children have an atom:author.</s:assert>
</s:rule>
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<optional>
<ref name="atomGenerator"/>
</optional>
<optional>
<ref name="atomIcon"/>
</optional>
<ref name="atomId"/>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomLogo"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSubtitle"/>
</optional>
<ref name="atomTitle"/>
<ref name="atomUpdated"/>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
<zeroOrMore>
<ref name="atomEntry"/>
</zeroOrMore>
</element>
</define>
<!-- atom:entry -->
<define name="atomEntry">
<element name="atom:entry">
<s:rule context="atom:entry">
<s:assert test="atom:link[@rel='alternate'] or atom:link[not(@rel)] or atom:content">An atom:entry must have at least one atom:link element with a rel attribute of 'alternate' or an atom:content.</s:assert>
</s:rule>
<s:rule context="atom:entry">
<s:assert test="atom:author or ../atom:author or atom:source/atom:author">An atom:entry must have an atom:author if its feed does not.</s:assert>
</s:rule>
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<optional>
<ref name="atomContent"/>
</optional>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<ref name="atomId"/>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomPublished"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSource"/>
</optional>
<optional>
<ref name="atomSummary"/>
</optional>
<ref name="atomTitle"/>
<ref name="atomUpdated"/>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</element>
</define>
<!-- atom:content -->
<define name="atomInlineTextContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<choice>
<value>text</value>
<value>html</value>
</choice>
</attribute>
</optional>
<zeroOrMore>
<text/>
</zeroOrMore>
</element>
</define>
<define name="atomInlineXHTMLContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<attribute name="type">
<value>xhtml</value>
</attribute>
<ref name="xhtmlDiv"/>
</element>
</define>
<define name="atomInlineOtherContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="atomOutOfLineContent">
<element name="atom:content">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<attribute name="src">
<ref name="atomUri"/>
</attribute>
<empty/>
</element>
</define>
<define name="atomContent">
<choice>
<ref name="atomInlineTextContent"/>
<ref name="atomInlineXHTMLContent"/>
<ref name="atomInlineOtherContent"/>
<ref name="atomOutOfLineContent"/>
</choice>
</define>
<!-- atom:author -->
<define name="atomAuthor">
<element name="atom:author">
<ref name="atomPersonConstruct"/>
</element>
</define>
<!-- atom:category -->
<define name="atomCategory">
<element name="atom:category">
<ref name="atomCommonAttributes"/>
<attribute name="term"/>
<optional>
<attribute name="scheme">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="label"/>
</optional>
<ref name="undefinedContent"/>
</element>
</define>
<!-- atom:contributor -->
<define name="atomContributor">
<element name="atom:contributor">
<ref name="atomPersonConstruct"/>
</element>
</define>
<!-- atom:generator -->
<define name="atomGenerator">
<element name="atom:generator">
<ref name="atomCommonAttributes"/>
<optional>
<attribute name="uri">
<ref name="atomUri"/>
</attribute>
</optional>
<optional>
<attribute name="version"/>
</optional>
<text/>
</element>
</define>
<!-- atom:icon -->
<define name="atomIcon">
<element name="atom:icon">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:id -->
<define name="atomId">
<element name="atom:id">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:logo -->
<define name="atomLogo">
<element name="atom:logo">
<ref name="atomCommonAttributes"/>
<ref name="atomUri"/>
</element>
</define>
<!-- atom:link -->
<define name="atomLink">
<element name="atom:link">
<ref name="atomCommonAttributes"/>
<attribute name="href">
<ref name="atomUri"/>
</attribute>
<optional>
<attribute name="rel">
<choice>
<ref name="atomNCName"/>
<ref name="atomUri"/>
</choice>
</attribute>
</optional>
<optional>
<attribute name="type">
<ref name="atomMediaType"/>
</attribute>
</optional>
<optional>
<attribute name="hreflang">
<ref name="atomLanguageTag"/>
</attribute>
</optional>
<optional>
<attribute name="title"/>
</optional>
<optional>
<attribute name="length"/>
</optional>
<ref name="undefinedContent"/>
</element>
</define>
<!-- atom:published -->
<define name="atomPublished">
<element name="atom:published">
<ref name="atomDateConstruct"/>
</element>
</define>
<!-- atom:rights -->
<define name="atomRights">
<element name="atom:rights">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:source -->
<define name="atomSource">
<element name="atom:source">
<ref name="atomCommonAttributes"/>
<interleave>
<zeroOrMore>
<ref name="atomAuthor"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomCategory"/>
</zeroOrMore>
<zeroOrMore>
<ref name="atomContributor"/>
</zeroOrMore>
<optional>
<ref name="atomGenerator"/>
</optional>
<optional>
<ref name="atomIcon"/>
</optional>
<optional>
<ref name="atomId"/>
</optional>
<zeroOrMore>
<ref name="atomLink"/>
</zeroOrMore>
<optional>
<ref name="atomLogo"/>
</optional>
<optional>
<ref name="atomRights"/>
</optional>
<optional>
<ref name="atomSubtitle"/>
</optional>
<optional>
<ref name="atomTitle"/>
</optional>
<optional>
<ref name="atomUpdated"/>
</optional>
<zeroOrMore>
<ref name="extensionElement"/>
</zeroOrMore>
</interleave>
</element>
</define>
<!-- atom:subtitle -->
<define name="atomSubtitle">
<element name="atom:subtitle">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:summary -->
<define name="atomSummary">
<element name="atom:summary">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:title -->
<define name="atomTitle">
<element name="atom:title">
<ref name="atomTextConstruct"/>
</element>
</define>
<!-- atom:updated -->
<define name="atomUpdated">
<element name="atom:updated">
<ref name="atomDateConstruct"/>
</element>
</define>
<!-- Low-level simple types -->
<define name="atomNCName">
<data type="string">
<param name="minLength">1</param>
<param name="pattern">[^:]*</param>
</data>
</define>
<!-- Whatever a media type is, it contains at least one slash -->
<define name="atomMediaType">
<data type="string">
<param name="pattern">.+/.+</param>
</data>
</define>
<!-- As defined in RFC 3066 -->
<define name="atomLanguageTag">
<data type="string">
<param name="pattern">[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*</param>
</data>
</define>
<!--
Unconstrained; it's not entirely clear how IRI fit into
xsd:anyURI so let's not try to constrain it here
-->
<define name="atomUri">
<text/>
</define>
<!-- Whatever an email address is, it contains at least one @ -->
<define name="atomEmailAddress">
<data type="string">
<param name="pattern">.+@.+</param>
</data>
</define>
<!-- Simple Extension -->
<define name="simpleExtensionElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<text/>
</element>
</define>
<!-- Structured Extension -->
<define name="structuredExtensionElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<choice>
<group>
<oneOrMore>
<attribute>
<anyName/>
</attribute>
</oneOrMore>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</group>
<group>
<zeroOrMore>
<attribute>
<anyName/>
</attribute>
</zeroOrMore>
<group>
<optional>
<text/>
</optional>
<oneOrMore>
<ref name="anyElement"/>
</oneOrMore>
<zeroOrMore>
<choice>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</group>
</group>
</choice>
</element>
</define>
<!-- Other Extensibility -->
<define name="extensionElement">
<choice>
<ref name="simpleExtensionElement"/>
<ref name="structuredExtensionElement"/>
</choice>
</define>
<define name="undefinedAttribute">
<attribute>
<anyName>
<except>
<name>xml:base</name>
<name>xml:lang</name>
<nsName ns=""/>
</except>
</anyName>
</attribute>
</define>
<define name="undefinedContent">
<zeroOrMore>
<choice>
<text/>
<ref name="anyForeignElement"/>
</choice>
</zeroOrMore>
</define>
<define name="anyElement">
<element>
<anyName/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="anyForeignElement">
<element>
<anyName>
<except>
<nsName ns="http://www.w3.org/2005/Atom"/>
</except>
</anyName>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyElement"/>
</choice>
</zeroOrMore>
</element>
</define>
<!-- XHTML -->
<define name="anyXHTML">
<element>
<nsName ns="http://www.w3.org/1999/xhtml"/>
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyXHTML"/>
</choice>
</zeroOrMore>
</element>
</define>
<define name="xhtmlDiv">
<element name="xhtml:div">
<zeroOrMore>
<choice>
<attribute>
<anyName/>
</attribute>
<text/>
<ref name="anyXHTML"/>
</choice>
</zeroOrMore>
</element>
</define>
</grammar>

View File

@ -1,14 +0,0 @@
<element name="addresses" ns="http://docs.openstack.org/compute/api/v1.1"
xmlns="http://relaxng.org/ns/structure/1.0">
<zeroOrMore>
<element name="network">
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<element name="ip">
<attribute name="version"> <text/> </attribute>
<attribute name="addr"> <text/> </attribute>
</element>
</zeroOrMore>
</element>
</zeroOrMore>
</element>

View File

@ -1,11 +0,0 @@
<element name="extension" ns="http://docs.openstack.org/common/api/v1.0"
xmlns="http://relaxng.org/ns/structure/1.0">
<attribute name="alias"> <text/> </attribute>
<attribute name="name"> <text/> </attribute>
<attribute name="namespace"> <text/> </attribute>
<attribute name="updated"> <text/> </attribute>
<element name="description"> <text/> </element>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>

View File

@ -1,6 +0,0 @@
<element name="extensions" xmlns="http://relaxng.org/ns/structure/1.0"
ns="http://docs.openstack.org/common/api/v1.0">
<zeroOrMore>
<externalRef href="extension.rng"/>
</zeroOrMore>
</element>

View File

@ -1,11 +0,0 @@
<element name="flavor" ns="http://docs.openstack.org/compute/api/v1.1"
xmlns="http://relaxng.org/ns/structure/1.0">
<attribute name="name"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<attribute name="ram"> <text/> </attribute>
<attribute name="disk"> <text/> </attribute>
<attribute name="vcpus"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>

View File

@ -1,18 +0,0 @@
<element name="flavors" xmlns="http://relaxng.org/ns/structure/1.0"
ns="http://docs.openstack.org/compute/api/v1.1">
<choice>
<zeroOrMore>
<externalRef href="flavor.rng"/>
</zeroOrMore>
<zeroOrMore>
<!-- flavors index -->
<element name="flavor">
<attribute name="name"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>
</zeroOrMore>
</choice>
</element>

View File

@ -1,36 +0,0 @@
<element name="image" ns="http://docs.openstack.org/compute/api/v1.1"
xmlns="http://relaxng.org/ns/structure/1.0">
<attribute name="name"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<attribute name="updated"> <text/> </attribute>
<attribute name="created"> <text/> </attribute>
<attribute name="status"> <text/> </attribute>
<optional>
<attribute name="progress"> <text/> </attribute>
</optional>
<optional>
<attribute name="minDisk"> <text/> </attribute>
</optional>
<optional>
<attribute name="minRam"> <text/> </attribute>
</optional>
<optional>
<element name="server">
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>
</optional>
<element name="metadata">
<zeroOrMore>
<element name="meta">
<attribute name="key"> <text/> </attribute>
<text/>
</element>
</zeroOrMore>
</element>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>

View File

@ -1,23 +0,0 @@
<element name="images" xmlns="http://relaxng.org/ns/structure/1.0"
ns="http://docs.openstack.org/compute/api/v1.1">
<choice>
<zeroOrMore>
<externalRef href="image.rng"/>
</zeroOrMore>
<group>
<!-- images index -->
<zeroOrMore>
<element name="image">
<attribute name="name"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>
</zeroOrMore>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</group>
</choice>
</element>

View File

@ -1,28 +0,0 @@
<element name="limits" ns="http://docs.openstack.org/common/api/v1.0"
xmlns="http://relaxng.org/ns/structure/1.0">
<element name="rates">
<zeroOrMore>
<element name="rate">
<attribute name="uri"> <text/> </attribute>
<attribute name="regex"> <text/> </attribute>
<zeroOrMore>
<element name="limit">
<attribute name="value"> <text/> </attribute>
<attribute name="verb"> <text/> </attribute>
<attribute name="remaining"> <text/> </attribute>
<attribute name="unit"> <text/> </attribute>
<attribute name="next-available"> <text/> </attribute>
</element>
</zeroOrMore>
</element>
</zeroOrMore>
</element>
<element name="absolute">
<zeroOrMore>
<element name="limit">
<attribute name="name"> <text/> </attribute>
<attribute name="value"> <text/> </attribute>
</element>
</zeroOrMore>
</element>
</element>

View File

@ -1,9 +0,0 @@
<element name="metadata" ns="http://docs.openstack.org/compute/api/v1.1"
xmlns="http://relaxng.org/ns/structure/1.0">
<zeroOrMore>
<element name="meta">
<attribute name="key"> <text/> </attribute>
<text/>
</element>
</zeroOrMore>
</element>

View File

@ -1,59 +0,0 @@
<element name="server" ns="http://docs.openstack.org/compute/api/v1.1"
xmlns="http://relaxng.org/ns/structure/1.0">
<attribute name="name"> <text/> </attribute>
<attribute name="userId"> <text/> </attribute>
<attribute name="tenantId"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<attribute name="updated"> <text/> </attribute>
<attribute name="created"> <text/> </attribute>
<attribute name="hostId"> <text/> </attribute>
<attribute name="accessIPv4"> <text/> </attribute>
<attribute name="accessIPv6"> <text/> </attribute>
<attribute name="status"> <text/> </attribute>
<optional>
<attribute name="progress"> <text/> </attribute>
</optional>
<optional>
<attribute name="adminPass"><text/> </attribute>
</optional>
<element name="image">
<attribute name="id"> <text/> </attribute>
<externalRef href="../atom-link.rng"/>
</element>
<element name="flavor">
<attribute name="id"> <text/> </attribute>
<externalRef href="../atom-link.rng"/>
</element>
<optional>
<element name="fault">
<attribute name="code"> <text/> </attribute>
<attribute name="created"> <text/> </attribute>
<element name="message"> <text/> </element>
<element name="details"> <text/> </element>
</element>
</optional>
<element name="metadata">
<zeroOrMore>
<element name="meta">
<attribute name="key"> <text/> </attribute>
<text/>
</element>
</zeroOrMore>
</element>
<element name="addresses">
<zeroOrMore>
<element name="network">
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<element name="ip">
<attribute name="version"> <text/> </attribute>
<attribute name="addr"> <text/> </attribute>
</element>
</zeroOrMore>
</element>
</zeroOrMore>
</element>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>

View File

@ -1,23 +0,0 @@
<element name="servers" xmlns="http://relaxng.org/ns/structure/1.0"
ns="http://docs.openstack.org/compute/api/v1.1">
<choice>
<zeroOrMore>
<externalRef href="server.rng"/>
</zeroOrMore>
<group>
<!-- servers index -->
<zeroOrMore>
<element name="server">
<attribute name="name"> <text/> </attribute>
<attribute name="id"> <text/> </attribute>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>
</zeroOrMore>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</group>
</choice>
</element>

View File

@ -1,17 +0,0 @@
<element name="version" ns="http://docs.openstack.org/common/api/v1.0"
xmlns="http://relaxng.org/ns/structure/1.0">
<attribute name="id"/>
<attribute name="status"/>
<attribute name="updated"/>
<element name="media-types">
<oneOrMore>
<element name="media-type">
<attribute name="base"/>
<attribute name="type"/>
</element>
</oneOrMore>
</element>
<zeroOrMore>
<externalRef href="../atom-link.rng"/>
</zeroOrMore>
</element>

View File

@ -1,11 +0,0 @@
<element name="versions" xmlns="http://relaxng.org/ns/structure/1.0"
ns="http://docs.openstack.org/common/api/v1.0">
<oneOrMore>
<element name="version">
<attribute name="id"/>
<attribute name="status"/>
<attribute name="updated"/>
<externalRef href="../atom-link.rng"/>
</element>
</oneOrMore>
</element>

View File

@ -42,14 +42,11 @@ class Controller(object):
meta_dict[key] = value meta_dict[key] = value
return meta_dict return meta_dict
@wsgi.serializers(xml=common.MetadataTemplate)
def index(self, req, server_id): def index(self, req, server_id):
"""Returns the list of metadata for a given instance.""" """Returns the list of metadata for a given instance."""
context = req.environ['nova.context'] context = req.environ['nova.context']
return {'metadata': self._get_metadata(context, server_id)} return {'metadata': self._get_metadata(context, server_id)}
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def create(self, req, server_id, body): def create(self, req, server_id, body):
try: try:
metadata = body['metadata'] metadata = body['metadata']
@ -69,8 +66,6 @@ class Controller(object):
return {'metadata': new_metadata} return {'metadata': new_metadata}
@wsgi.serializers(xml=common.MetaItemTemplate)
@wsgi.deserializers(xml=common.MetaItemDeserializer)
def update(self, req, server_id, id, body): def update(self, req, server_id, id, body):
try: try:
meta_item = body['meta'] meta_item = body['meta']
@ -98,8 +93,6 @@ class Controller(object):
return {'meta': meta_item} return {'meta': meta_item}
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def update_all(self, req, server_id, body): def update_all(self, req, server_id, body):
try: try:
metadata = body['metadata'] metadata = body['metadata']
@ -154,7 +147,6 @@ class Controller(object):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'update metadata', server_id) 'update metadata', server_id)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, server_id, id): def show(self, req, server_id, id):
"""Return a single metadata item.""" """Return a single metadata item."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -28,16 +28,13 @@ import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute import ips
from nova.api.openstack.compute.views import servers as views_servers from nova.api.openstack.compute.views import servers as views_servers
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import block_device from nova import block_device
from nova import compute from nova import compute
from nova.compute import flavors from nova.compute import flavors
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova.i18n import _LW
from nova import objects from nova import objects
from nova.openstack.common import log as logging from nova.openstack.common import log as logging
from nova.openstack.common import uuidutils from nova.openstack.common import uuidutils
@ -64,421 +61,7 @@ LOG = logging.getLogger(__name__)
XML_WARNING = False XML_WARNING = False
def make_fault(elem): server_nsmap = {}
fault = xmlutil.SubTemplateElement(elem, 'fault', selector='fault')
fault.set('code')
fault.set('created')
msg = xmlutil.SubTemplateElement(fault, 'message')
msg.text = 'message'
det = xmlutil.SubTemplateElement(fault, 'details')
det.text = 'details'
def make_server(elem, detailed=False):
elem.set('name')
elem.set('id')
global XML_WARNING
if not XML_WARNING:
LOG.warning(_LW('XML support has been deprecated and may be removed '
'as early as the Juno release.'))
XML_WARNING = True
if detailed:
elem.set('userId', 'user_id')
elem.set('tenantId', 'tenant_id')
elem.set('updated')
elem.set('created')
elem.set('hostId')
elem.set('accessIPv4')
elem.set('accessIPv6')
elem.set('status')
elem.set('progress')
elem.set('reservation_id')
# Attach image node
image = xmlutil.SubTemplateElement(elem, 'image', selector='image')
image.set('id')
xmlutil.make_links(image, 'links')
# Attach flavor node
flavor = xmlutil.SubTemplateElement(elem, 'flavor', selector='flavor')
flavor.set('id')
xmlutil.make_links(flavor, 'links')
# Attach fault node
make_fault(elem)
# Attach metadata node
elem.append(common.MetadataTemplate())
# Attach addresses node
elem.append(ips.AddressesTemplate())
xmlutil.make_links(elem, 'links')
server_nsmap = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM}
class ServerTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server', selector='server')
make_server(root, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=server_nsmap)
class MinimalServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem)
xmlutil.make_links(root, 'servers_links')
return xmlutil.MasterTemplate(root, 1, nsmap=server_nsmap)
class ServersTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('servers')
elem = xmlutil.SubTemplateElement(root, 'server', selector='servers')
make_server(elem, detailed=True)
return xmlutil.MasterTemplate(root, 1, nsmap=server_nsmap)
class ServerAdminPassTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
root.set('adminPass')
return xmlutil.SlaveTemplate(root, 1, nsmap=server_nsmap)
class ServerMultipleCreateTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('server')
root.set('reservation_id')
return xmlutil.MasterTemplate(root, 1, nsmap=server_nsmap)
def FullServerTemplate():
master = ServerTemplate()
master.attach(ServerAdminPassTemplate())
return master
class CommonDeserializer(wsgi.MetadataXMLDeserializer):
"""Common deserializer to handle xml-formatted server create requests.
Handles standard server attributes as well as optional metadata
and personality attributes
"""
metadata_deserializer = common.MetadataXMLDeserializer()
def _extract_personality(self, server_node):
"""Marshal the personality attribute of a parsed request."""
node = self.find_first_child_named(server_node, "personality")
if node is not None:
personality = []
for file_node in self.find_children_named(node, "file"):
item = {}
if file_node.hasAttribute("path"):
item["path"] = file_node.getAttribute("path")
item["contents"] = self.extract_text(file_node)
personality.append(item)
return personality
else:
return None
def _extract_server(self, node):
"""Marshal the server attribute of a parsed request."""
server = {}
server_node = self.find_first_child_named(node, 'server')
attributes = ["name", "imageRef", "flavorRef", "adminPass",
"accessIPv4", "accessIPv6", "key_name",
"availability_zone", "min_count", "max_count"]
for attr in attributes:
if server_node.getAttribute(attr):
server[attr] = server_node.getAttribute(attr)
res_id = server_node.getAttribute('return_reservation_id')
if res_id:
server['return_reservation_id'] = \
strutils.bool_from_string(res_id)
scheduler_hints = self._extract_scheduler_hints(server_node)
if scheduler_hints:
server['OS-SCH-HNT:scheduler_hints'] = scheduler_hints
metadata_node = self.find_first_child_named(server_node, "metadata")
if metadata_node is not None:
server["metadata"] = self.extract_metadata(metadata_node)
user_data_node = self.find_first_child_named(server_node, "user_data")
if user_data_node is not None:
server["user_data"] = self.extract_text(user_data_node)
personality = self._extract_personality(server_node)
if personality is not None:
server["personality"] = personality
networks = self._extract_networks(server_node)
if networks is not None:
server["networks"] = networks
security_groups = self._extract_security_groups(server_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
block_device_mapping_v2 = self._extract_block_device_mapping_v2(
server_node)
if block_device_mapping_v2 is not None:
server["block_device_mapping_v2"] = block_device_mapping_v2
# 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')
if auto_disk_config:
server['OS-DCF:diskConfig'] = auto_disk_config
auto_disk_config = server_node.getAttribute('OS-DCF:diskConfig')
if auto_disk_config:
server['OS-DCF:diskConfig'] = auto_disk_config
config_drive = server_node.getAttribute('config_drive')
if config_drive:
server['config_drive'] = config_drive
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] = strutils.bool_from_string(value)
block_device_mapping.append(mapping)
return block_device_mapping
else:
return None
def _extract_block_device_mapping_v2(self, server_node):
"""Marshal the new block_device_mappings."""
node = self.find_first_child_named(server_node,
"block_device_mapping_v2")
if node:
block_device_mapping = []
for child in self.extract_elements(node):
if child.nodeName != "mapping":
continue
block_device_mapping.append(
dict((attr, child.getAttribute(attr))
for attr in block_device.bdm_new_api_fields
if child.getAttribute(attr)))
return block_device_mapping
def _extract_scheduler_hints(self, server_node):
"""Marshal the scheduler hints attribute of a parsed request."""
node = self.find_first_child_named_in_namespace(server_node,
"http://docs.openstack.org/compute/ext/scheduler-hints/api/v2",
"scheduler_hints")
if node:
scheduler_hints = {}
for child in self.extract_elements(node):
scheduler_hints.setdefault(child.nodeName, [])
value = self.extract_text(child).strip()
scheduler_hints[child.nodeName].append(value)
return scheduler_hints
else:
return None
def _extract_networks(self, server_node):
"""Marshal the networks attribute of a parsed request."""
node = self.find_first_child_named(server_node, "networks")
if node is not None:
networks = []
for network_node in self.find_children_named(node,
"network"):
item = {}
if network_node.hasAttribute("uuid"):
item["uuid"] = network_node.getAttribute("uuid")
if network_node.hasAttribute("fixed_ip"):
item["fixed_ip"] = network_node.getAttribute("fixed_ip")
if network_node.hasAttribute("port"):
item["port"] = network_node.getAttribute("port")
networks.append(item)
return networks
else:
return None
def _extract_security_groups(self, server_node):
"""Marshal the security_groups attribute of a parsed request."""
node = self.find_first_child_named(server_node, "security_groups")
if node is not None:
security_groups = []
for sg_node in self.find_children_named(node, "security_group"):
item = {}
name = self.find_attribute_or_element(sg_node, 'name')
if name:
item["name"] = name
security_groups.append(item)
return security_groups
else:
return None
class ActionDeserializer(CommonDeserializer):
"""Deserializer to handle xml-formatted server action requests.
Handles standard server attributes as well as optional metadata
and personality attributes
"""
def default(self, string):
dom = xmlutil.safe_minidom_parse_string(string)
action_node = dom.childNodes[0]
action_name = action_node.tagName
action_deserializer = {
'createImage': self._action_create_image,
'changePassword': self._action_change_password,
'reboot': self._action_reboot,
'rebuild': self._action_rebuild,
'resize': self._action_resize,
'confirmResize': self._action_confirm_resize,
'revertResize': self._action_revert_resize,
}.get(action_name, super(ActionDeserializer, self).default)
action_data = action_deserializer(action_node)
return {'body': {action_name: action_data}}
def _action_create_image(self, node):
return self._deserialize_image_action(node, ('name',))
def _action_change_password(self, node):
if not node.hasAttribute("adminPass"):
raise AttributeError("No adminPass was specified in request")
return {"adminPass": node.getAttribute("adminPass")}
def _action_reboot(self, node):
if not node.hasAttribute("type"):
raise AttributeError("No reboot type was specified in request")
return {"type": node.getAttribute("type")}
def _action_rebuild(self, node):
rebuild = {}
if node.hasAttribute("name"):
name = node.getAttribute("name")
if not name:
raise AttributeError("Name cannot be blank")
rebuild['name'] = name
if node.hasAttribute("auto_disk_config"):
rebuild['OS-DCF:diskConfig'] = node.getAttribute(
"auto_disk_config")
if node.hasAttribute("OS-DCF:diskConfig"):
rebuild['OS-DCF:diskConfig'] = node.getAttribute(
"OS-DCF:diskConfig")
metadata_node = self.find_first_child_named(node, "metadata")
if metadata_node is not None:
rebuild["metadata"] = self.extract_metadata(metadata_node)
personality = self._extract_personality(node)
if personality is not None:
rebuild["personality"] = personality
if not node.hasAttribute("imageRef"):
raise AttributeError("No imageRef was specified in request")
rebuild["imageRef"] = node.getAttribute("imageRef")
if node.hasAttribute("adminPass"):
rebuild["adminPass"] = node.getAttribute("adminPass")
if node.hasAttribute("accessIPv4"):
rebuild["accessIPv4"] = node.getAttribute("accessIPv4")
if node.hasAttribute("accessIPv6"):
rebuild["accessIPv6"] = node.getAttribute("accessIPv6")
if node.hasAttribute("preserve_ephemeral"):
rebuild["preserve_ephemeral"] = strutils.bool_from_string(
node.getAttribute("preserve_ephemeral"), strict=True)
return rebuild
def _action_resize(self, node):
resize = {}
if node.hasAttribute("flavorRef"):
resize["flavorRef"] = node.getAttribute("flavorRef")
else:
raise AttributeError("No flavorRef was specified in request")
if node.hasAttribute("auto_disk_config"):
resize['OS-DCF:diskConfig'] = node.getAttribute("auto_disk_config")
if node.hasAttribute("OS-DCF:diskConfig"):
resize['OS-DCF:diskConfig'] = node.getAttribute(
"OS-DCF:diskConfig")
return resize
def _action_confirm_resize(self, node):
return None
def _action_revert_resize(self, node):
return None
def _deserialize_image_action(self, node, allowed_attributes):
data = {}
for attribute in allowed_attributes:
value = node.getAttribute(attribute)
if value:
data[attribute] = value
metadata_node = self.find_first_child_named(node, 'metadata')
if metadata_node is not None:
metadata = self.metadata_deserializer.extract_metadata(
metadata_node)
data['metadata'] = metadata
return data
class CreateDeserializer(CommonDeserializer):
"""Deserializer to handle xml-formatted server create requests.
Handles standard server attributes as well as optional metadata
and personality attributes
"""
def default(self, string):
"""Deserialize an xml-formatted server create request."""
dom = xmlutil.safe_minidom_parse_string(string)
server = self._extract_server(dom)
return {'body': {'server': server}}
class Controller(wsgi.Controller): class Controller(wsgi.Controller):
@ -505,7 +88,6 @@ class Controller(wsgi.Controller):
self.compute_api = compute.API() self.compute_api = compute.API()
self.ext_mgr = ext_mgr self.ext_mgr = ext_mgr
@wsgi.serializers(xml=MinimalServersTemplate)
def index(self, req): def index(self, req):
"""Returns a list of server names and ids for a given user.""" """Returns a list of server names and ids for a given user."""
try: try:
@ -514,7 +96,6 @@ class Controller(wsgi.Controller):
raise exc.HTTPBadRequest(explanation=err.format_message()) raise exc.HTTPBadRequest(explanation=err.format_message())
return servers return servers
@wsgi.serializers(xml=ServersTemplate)
def detail(self, req): def detail(self, req):
"""Returns a list of server details for a given user.""" """Returns a list of server details for a given user."""
try: try:
@ -760,7 +341,6 @@ class Controller(wsgi.Controller):
expl = _('accessIPv6 is not proper IPv6 format') expl = _('accessIPv6 is not proper IPv6 format')
raise exc.HTTPBadRequest(explanation=expl) raise exc.HTTPBadRequest(explanation=expl)
@wsgi.serializers(xml=ServerTemplate)
def show(self, req, id): def show(self, req, id):
"""Returns server details by server id.""" """Returns server details by server id."""
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -768,8 +348,6 @@ class Controller(wsgi.Controller):
return self._view_builder.show(req, instance) return self._view_builder.show(req, instance)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body): def create(self, req, body):
"""Creates a new server for a given user.""" """Creates a new server for a given user."""
if not self.is_valid_body(body, 'server'): if not self.is_valid_body(body, 'server'):
@ -1013,8 +591,7 @@ class Controller(wsgi.Controller):
# If the caller wanted a reservation_id, return it # If the caller wanted a reservation_id, return it
if ret_resv_id: if ret_resv_id:
return wsgi.ResponseObject({'reservation_id': resv_id}, return wsgi.ResponseObject({'reservation_id': resv_id})
xml=ServerMultipleCreateTemplate)
req.cache_db_instances(instances) req.cache_db_instances(instances)
server = self._view_builder.create(req, instances[0]) server = self._view_builder.create(req, instances[0])
@ -1039,7 +616,6 @@ class Controller(wsgi.Controller):
else: else:
self.compute_api.delete(context, instance) self.compute_api.delete(context, instance)
@wsgi.serializers(xml=ServerTemplate)
def update(self, req, id, body): def update(self, req, id, body):
"""Update server then pass on to version-specific controller.""" """Update server then pass on to version-specific controller."""
if not self.is_valid_body(body, 'server'): if not self.is_valid_body(body, 'server'):
@ -1093,8 +669,6 @@ class Controller(wsgi.Controller):
return self._view_builder.show(req, instance) return self._view_builder.show(req, instance)
@wsgi.response(204) @wsgi.response(204)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('confirmResize') @wsgi.action('confirmResize')
def _action_confirm_resize(self, req, id, body): def _action_confirm_resize(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -1111,8 +685,6 @@ class Controller(wsgi.Controller):
'confirmResize', id) 'confirmResize', id)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('revertResize') @wsgi.action('revertResize')
def _action_revert_resize(self, req, id, body): def _action_revert_resize(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -1133,8 +705,6 @@ class Controller(wsgi.Controller):
return webob.Response(status_int=202) return webob.Response(status_int=202)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('reboot') @wsgi.action('reboot')
def _action_reboot(self, req, id, body): def _action_reboot(self, req, id, body):
if 'reboot' in body and 'type' in body['reboot']: if 'reboot' in body and 'type' in body['reboot']:
@ -1272,8 +842,6 @@ class Controller(wsgi.Controller):
return common.get_id_from_href(flavor_ref) return common.get_id_from_href(flavor_ref)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('changePassword') @wsgi.action('changePassword')
def _action_change_password(self, req, id, body): def _action_change_password(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -1301,8 +869,6 @@ class Controller(wsgi.Controller):
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('resize') @wsgi.action('resize')
def _action_resize(self, req, id, body): def _action_resize(self, req, id, body):
"""Resizes a given instance to the flavor size requested.""" """Resizes a given instance to the flavor size requested."""
@ -1322,8 +888,6 @@ class Controller(wsgi.Controller):
return self._resize(req, id, flavor_ref, **kwargs) return self._resize(req, id, flavor_ref, **kwargs)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('rebuild') @wsgi.action('rebuild')
def _action_rebuild(self, req, id, body): def _action_rebuild(self, req, id, body):
"""Rebuild an instance with the given attributes.""" """Rebuild an instance with the given attributes."""
@ -1426,8 +990,6 @@ class Controller(wsgi.Controller):
return self._add_location(robj) return self._add_location(robj)
@wsgi.response(202) @wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('createImage') @wsgi.action('createImage')
@common.check_snapshots_enabled @common.check_snapshots_enabled
def _action_create_image(self, req, id, body): def _action_create_image(self, req, id, body):

View File

@ -13,13 +13,10 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from lxml import etree
from oslo.config import cfg from oslo.config import cfg
from oslo.utils import timeutils
from nova.api.openstack.compute.views import versions as views_versions from nova.api.openstack.compute.views import versions as views_versions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
CONF = cfg.CONF CONF = cfg.CONF
@ -48,10 +45,6 @@ VERSIONS = {
}, },
], ],
"media-types": [ "media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2",
},
{ {
"base": "application/json", "base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2", "type": "application/vnd.openstack.compute+json;version=2",
@ -79,142 +72,7 @@ VERSIONS = {
} }
class MediaTypesTemplateElement(xmlutil.TemplateElement): version_nsmap = {}
def will_render(self, datum):
return 'media-types' in datum
def make_version(elem):
elem.set('id')
elem.set('status')
elem.set('updated')
mts = MediaTypesTemplateElement('media-types')
elem.append(mts)
mt = xmlutil.SubTemplateElement(mts, 'media-type', selector='media-types')
mt.set('base')
mt.set('type')
xmlutil.make_links(elem, 'links')
version_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM}
class VersionTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('version', selector='version')
make_version(root)
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
class VersionsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('versions')
elem = xmlutil.SubTemplateElement(root, 'version', selector='versions')
make_version(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
class ChoicesTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('choices')
elem = xmlutil.SubTemplateElement(root, 'version', selector='choices')
make_version(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap)
class AtomSerializer(wsgi.XMLDictSerializer):
NSMAP = {None: xmlutil.XMLNS_ATOM}
def __init__(self, metadata=None, xmlns=None):
self.metadata = metadata or {}
if not xmlns:
self.xmlns = wsgi.XMLNS_ATOM
else:
self.xmlns = xmlns
def _get_most_recent_update(self, versions):
recent = None
for version in versions:
updated = timeutils.parse_strtime(version['updated'],
'%Y-%m-%dT%H:%M:%SZ')
if not recent:
recent = updated
elif updated > recent:
recent = updated
return recent.strftime('%Y-%m-%dT%H:%M:%SZ')
def _get_base_url(self, link_href):
# Make sure no trailing /
link_href = link_href.rstrip('/')
return link_href.rsplit('/', 1)[0] + '/'
def _create_feed(self, versions, feed_title, feed_id):
feed = etree.Element('feed', nsmap=self.NSMAP)
title = etree.SubElement(feed, 'title')
title.set('type', 'text')
title.text = feed_title
# Set this updated to the most recently updated version
recent = self._get_most_recent_update(versions)
etree.SubElement(feed, 'updated').text = recent
etree.SubElement(feed, 'id').text = feed_id
link = etree.SubElement(feed, 'link')
link.set('rel', 'self')
link.set('href', feed_id)
author = etree.SubElement(feed, 'author')
etree.SubElement(author, 'name').text = 'Rackspace'
etree.SubElement(author, 'uri').text = 'http://www.rackspace.com/'
for version in versions:
feed.append(self._create_version_entry(version))
return feed
def _create_version_entry(self, version):
entry = etree.Element('entry')
etree.SubElement(entry, 'id').text = version['links'][0]['href']
title = etree.SubElement(entry, 'title')
title.set('type', 'text')
title.text = 'Version %s' % version['id']
etree.SubElement(entry, 'updated').text = version['updated']
for link in version['links']:
link_elem = etree.SubElement(entry, 'link')
link_elem.set('rel', link['rel'])
link_elem.set('href', link['href'])
if 'type' in link:
link_elem.set('type', link['type'])
content = etree.SubElement(entry, 'content')
content.set('type', 'text')
content.text = 'Version %s %s (%s)' % (version['id'],
version['status'],
version['updated'])
return entry
class VersionsAtomSerializer(AtomSerializer):
def default(self, data):
versions = data['versions']
feed_id = self._get_base_url(versions[0]['links'][0]['href'])
feed = self._create_feed(versions, 'Available API Versions', feed_id)
return self._to_xml(feed)
class VersionAtomSerializer(AtomSerializer):
def default(self, data):
version = data['version']
feed_id = version['links'][0]['href']
feed = self._create_feed([version], 'About This Version', feed_id)
return self._to_xml(feed)
class Versions(wsgi.Resource): class Versions(wsgi.Resource):
@ -223,14 +81,11 @@ class Versions(wsgi.Resource):
if not CONF.osapi_v3.enabled: if not CONF.osapi_v3.enabled:
del VERSIONS["v2.1"] del VERSIONS["v2.1"]
@wsgi.serializers(xml=VersionsTemplate,
atom=VersionsAtomSerializer)
def index(self, req, body=None): def index(self, req, body=None):
"""Return all versions.""" """Return all versions."""
builder = views_versions.get_view_builder(req) builder = views_versions.get_view_builder(req)
return builder.build_versions(VERSIONS) return builder.build_versions(VERSIONS)
@wsgi.serializers(xml=ChoicesTemplate)
@wsgi.response(300) @wsgi.response(300)
def multi(self, req, body=None): def multi(self, req, body=None):
"""Return multiple choices.""" """Return multiple choices."""
@ -249,8 +104,6 @@ class Versions(wsgi.Resource):
class VersionV2(object): class VersionV2(object):
@wsgi.serializers(xml=VersionTemplate,
atom=VersionAtomSerializer)
def show(self, req): def show(self, req):
builder = views_versions.get_view_builder(req) builder = views_versions.get_view_builder(req)
return builder.build_version(VERSIONS['v2.0']) return builder.build_version(VERSIONS['v2.0'])

View File

@ -25,7 +25,6 @@ import webob.exc
import nova.api.openstack import nova.api.openstack
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova.i18n import _ from nova.i18n import _
from nova.i18n import _LE from nova.i18n import _LE
@ -95,42 +94,8 @@ class ExtensionDescriptor(object):
return nsmap return nsmap
@classmethod
def xmlname(cls, name):
"""Synthesize element and attribute names."""
return '{%s}%s' % (cls.namespace, name) ext_nsmap = {}
def make_ext(elem):
elem.set('name')
elem.set('namespace')
elem.set('alias')
elem.set('updated')
desc = xmlutil.SubTemplateElement(elem, 'description')
desc.text = 'description'
xmlutil.make_links(elem, 'links')
ext_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM}
class ExtensionTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('extension', selector='extension')
make_ext(root)
return xmlutil.MasterTemplate(root, 1, nsmap=ext_nsmap)
class ExtensionsTemplate(xmlutil.TemplateBuilder):
def construct(self):
root = xmlutil.TemplateElement('extensions')
elem = xmlutil.SubTemplateElement(root, 'extension',
selector='extensions')
make_ext(elem)
return xmlutil.MasterTemplate(root, 1, nsmap=ext_nsmap)
class ExtensionsController(wsgi.Resource): class ExtensionsController(wsgi.Resource):
@ -149,14 +114,12 @@ class ExtensionsController(wsgi.Resource):
ext_data['links'] = [] # TODO(dprince): implement extension links ext_data['links'] = [] # TODO(dprince): implement extension links
return ext_data return ext_data
@wsgi.serializers(xml=ExtensionsTemplate)
def index(self, req): def index(self, req):
extensions = [] extensions = []
for ext in self.extension_manager.sorted_extensions(): for ext in self.extension_manager.sorted_extensions():
extensions.append(self._translate(ext)) extensions.append(self._translate(ext))
return dict(extensions=extensions) return dict(extensions=extensions)
@wsgi.serializers(xml=ExtensionTemplate)
def show(self, req, id): def show(self, req, id):
try: try:
# NOTE(dprince): the extensions alias is used as the 'id' for show # NOTE(dprince): the extensions alias is used as the 'id' for show

View File

@ -18,9 +18,7 @@ import functools
import inspect import inspect
import math import math
import time import time
from xml.dom import minidom
from lxml import etree
from oslo.serialization import jsonutils from oslo.serialization import jsonutils
from oslo.utils import strutils from oslo.utils import strutils
import six import six
@ -28,7 +26,6 @@ import webob
from nova.api.openstack import api_version_request as api_version from nova.api.openstack import api_version_request as api_version
from nova.api.openstack import versioned_method from nova.api.openstack import versioned_method
from nova.api.openstack import xmlutil
from nova import exception from nova import exception
from nova import i18n from nova import i18n
from nova.i18n import _ from nova.i18n import _
@ -42,8 +39,6 @@ from nova import wsgi
XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0' XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1' XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
_SUPPORTED_CONTENT_TYPES = ( _SUPPORTED_CONTENT_TYPES = (
@ -51,22 +46,11 @@ _SUPPORTED_CONTENT_TYPES = (
'application/vnd.openstack.compute+json', 'application/vnd.openstack.compute+json',
) )
_SUPPORTED_XML_CONTENT_TYPES = (
'application/xml',
'application/vnd.openstack.compute+xml',
)
_MEDIA_TYPE_MAP = { _MEDIA_TYPE_MAP = {
'application/vnd.openstack.compute+json': 'json', 'application/vnd.openstack.compute+json': 'json',
'application/json': 'json', 'application/json': 'json',
} }
_MEDIA_XML_TYPE_MAP = {
'application/vnd.openstack.compute+xml': 'xml',
'application/xml': 'xml',
'application/atom+xml': 'atom',
}
# These are typically automatically created by routes as either defaults # These are typically automatically created by routes as either defaults
# collection or member methods. # collection or member methods.
_ROUTES_METHODS = [ _ROUTES_METHODS = [
@ -94,21 +78,12 @@ VER_METHOD_ATTR = 'versioned_methods'
API_VERSION_REQUEST_HEADER = 'X-OpenStack-Compute-API-Version' API_VERSION_REQUEST_HEADER = 'X-OpenStack-Compute-API-Version'
# TODO(dims): Temporary, we already deprecated the v2 XML API in
# Juno, we should remove this before Kilo
DISABLE_XML_V2_API = True
def get_supported_content_types(): def get_supported_content_types():
if DISABLE_XML_V2_API:
return _SUPPORTED_CONTENT_TYPES return _SUPPORTED_CONTENT_TYPES
return _SUPPORTED_CONTENT_TYPES + _SUPPORTED_XML_CONTENT_TYPES
def get_media_map(): def get_media_map():
if DISABLE_XML_V2_API: return dict(_MEDIA_TYPE_MAP.items())
return _MEDIA_TYPE_MAP
return dict(_MEDIA_TYPE_MAP.items() + _MEDIA_XML_TYPE_MAP.items())
class Request(webob.Request): class Request(webob.Request):
@ -302,107 +277,6 @@ class JSONDeserializer(TextDeserializer):
return {'body': self._from_json(datastring)} return {'body': self._from_json(datastring)}
class XMLDeserializer(TextDeserializer):
def __init__(self, metadata=None):
""":param metadata: information needed to deserialize xml into
a dictionary.
"""
super(XMLDeserializer, self).__init__()
self.metadata = metadata or {}
def _from_xml(self, datastring):
plurals = set(self.metadata.get('plurals', {}))
node = xmlutil.safe_minidom_parse_string(datastring).childNodes[0]
return {node.nodeName: self._from_xml_node(node, plurals)}
def _from_xml_node(self, node, listnames):
"""Convert a minidom node to a simple Python type.
:param listnames: list of XML node names whose subnodes should
be considered list items.
"""
if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3:
return node.childNodes[0].nodeValue
elif node.nodeName in listnames:
return [self._from_xml_node(n, listnames) for n in node.childNodes]
else:
result = dict()
for attr in node.attributes.keys():
if not attr.startswith("xmlns"):
result[attr] = node.attributes[attr].nodeValue
for child in node.childNodes:
if child.nodeType != node.TEXT_NODE:
result[child.nodeName] = self._from_xml_node(child,
listnames)
return result
def find_first_child_named_in_namespace(self, parent, namespace, name):
"""Search a nodes children for the first child with a given name."""
for node in parent.childNodes:
if (node.localName == name and
node.namespaceURI and
node.namespaceURI == namespace):
return node
return None
def find_first_child_named(self, parent, name):
"""Search a nodes children for the first child with a given name."""
for node in parent.childNodes:
if node.localName == name:
return node
return None
def find_children_named(self, parent, name):
"""Return all of a nodes children who have the given name."""
for node in parent.childNodes:
if node.localName == name:
yield node
def extract_text(self, node):
"""Get the text field contained by the given node."""
ret_val = ""
for child in node.childNodes:
if child.nodeType == child.TEXT_NODE:
ret_val += child.nodeValue
return ret_val
def extract_elements(self, node):
"""Get only Element type childs from node."""
elements = []
for child in node.childNodes:
if child.nodeType == child.ELEMENT_NODE:
elements.append(child)
return elements
def find_attribute_or_element(self, parent, name):
"""Get an attribute value; fallback to an element if not found."""
if parent.hasAttribute(name):
return parent.getAttribute(name)
node = self.find_first_child_named(parent, name)
if node:
return self.extract_text(node)
return None
def default(self, datastring):
return {'body': self._from_xml(datastring)}
class MetadataXMLDeserializer(XMLDeserializer):
def extract_metadata(self, metadata_node):
"""Marshal the metadata attribute of a parsed request."""
metadata = {}
if metadata_node is not None:
for meta_node in self.find_children_named(metadata_node, "meta"):
key = meta_node.getAttribute("key")
metadata[key] = self.extract_text(meta_node)
return metadata
class DictSerializer(ActionDispatcher): class DictSerializer(ActionDispatcher):
"""Default request body serialization.""" """Default request body serialization."""
@ -420,76 +294,6 @@ class JSONDictSerializer(DictSerializer):
return jsonutils.dumps(data) return jsonutils.dumps(data)
class XMLDictSerializer(DictSerializer):
def __init__(self, metadata=None, xmlns=None):
""":param metadata: information needed to deserialize xml into
a dictionary.
:param xmlns: XML namespace to include with serialized xml
"""
super(XMLDictSerializer, self).__init__()
self.metadata = metadata or {}
self.xmlns = xmlns
def default(self, data):
# We expect data to contain a single key which is the XML root.
root_key = data.keys()[0]
doc = minidom.Document()
node = self._to_xml_node(doc, self.metadata, root_key, data[root_key])
return self.to_xml_string(node)
def to_xml_string(self, node, has_atom=False):
self._add_xmlns(node, has_atom)
return node.toxml('UTF-8')
# NOTE (ameade): the has_atom should be removed after all of the
# xml serializers and view builders have been updated to the current
# spec that required all responses include the xmlns:atom, the has_atom
# flag is to prevent current tests from breaking
def _add_xmlns(self, node, has_atom=False):
if self.xmlns is not None:
node.setAttribute('xmlns', self.xmlns)
if has_atom:
node.setAttribute('xmlns:atom', "http://www.w3.org/2005/Atom")
def _to_xml_node(self, doc, metadata, nodename, data):
"""Recursive method to convert data members to XML nodes."""
result = doc.createElement(nodename)
# TODO(bcwaldon): accomplish this without a type-check
if isinstance(data, list):
if nodename.endswith('s'):
singular = nodename[:-1]
else:
singular = 'item'
for item in data:
node = self._to_xml_node(doc, metadata, singular, item)
result.appendChild(node)
# TODO(bcwaldon): accomplish this without a type-check
elif isinstance(data, dict):
attrs = metadata.get('attributes', {}).get(nodename, {})
for k, v in data.items():
if k in attrs:
result.setAttribute(k, str(v))
else:
if k == "deleted":
v = str(bool(v))
node = self._to_xml_node(doc, metadata, k, v)
result.appendChild(node)
else:
# Type is atom
if not isinstance(data, six.string_types):
data = six.text_type(data)
node = doc.createTextNode(data)
result.appendChild(node)
return result
def _to_xml(self, root):
"""Convert the xml object to an xml string."""
return etree.tostring(root, encoding='UTF-8', xml_declaration=True)
def serializers(**serializers): def serializers(**serializers):
"""Attaches serializers to a method. """Attaches serializers to a method.
@ -688,15 +492,6 @@ def action_peek_json(body):
return decoded.keys()[0] return decoded.keys()[0]
def action_peek_xml(body):
"""Determine action to invoke."""
dom = xmlutil.safe_minidom_parse_string(body)
action_node = dom.childNodes[0]
return action_node.tagName
class ResourceExceptionHandler(object): class ResourceExceptionHandler(object):
"""Context manager to handle Resource exceptions. """Context manager to handle Resource exceptions.
@ -767,16 +562,13 @@ class Resource(wsgi.Application):
self.controller = controller self.controller = controller
default_deserializers = dict(xml=XMLDeserializer, default_deserializers = dict(json=JSONDeserializer)
json=JSONDeserializer)
default_deserializers.update(deserializers) default_deserializers.update(deserializers)
self.default_deserializers = default_deserializers self.default_deserializers = default_deserializers
self.default_serializers = dict(xml=XMLDictSerializer, self.default_serializers = dict(json=JSONDictSerializer)
json=JSONDictSerializer)
self.action_peek = dict(xml=action_peek_xml, self.action_peek = dict(json=action_peek_json)
json=action_peek_json)
self.action_peek.update(action_peek or {}) self.action_peek.update(action_peek or {})
# Copy over the actions dictionary # Copy over the actions dictionary
@ -1385,14 +1177,8 @@ class Fault(webob.exc.HTTPException):
self.wrapped_exc.headers['Vary'] = \ self.wrapped_exc.headers['Vary'] = \
API_VERSION_REQUEST_HEADER API_VERSION_REQUEST_HEADER
# 'code' is an attribute on the fault tag itself
metadata = {'attributes': {fault_name: 'code'}}
xml_serializer = XMLDictSerializer(metadata, XMLNS_V11)
content_type = req.best_match_content_type() content_type = req.best_match_content_type()
serializer = { serializer = {
'application/xml': xml_serializer,
'application/json': JSONDictSerializer(), 'application/json': JSONDictSerializer(),
}[content_type] }[content_type]
@ -1435,16 +1221,13 @@ class RateLimitFault(webob.exc.HTTPException):
""" """
user_locale = request.best_match_language() user_locale = request.best_match_language()
content_type = request.best_match_content_type() content_type = request.best_match_content_type()
metadata = {"attributes": {"overLimit": ["code", "retryAfter"]}}
self.content['overLimit']['message'] = \ self.content['overLimit']['message'] = \
i18n.translate(self.content['overLimit']['message'], user_locale) i18n.translate(self.content['overLimit']['message'], user_locale)
self.content['overLimit']['details'] = \ self.content['overLimit']['details'] = \
i18n.translate(self.content['overLimit']['details'], user_locale) i18n.translate(self.content['overLimit']['details'], user_locale)
xml_serializer = XMLDictSerializer(metadata, XMLNS_V11)
serializer = { serializer = {
'application/xml': xml_serializer,
'application/json': JSONDictSerializer(), 'application/json': JSONDictSerializer(),
}[content_type] }[content_type]

View File

@ -1,995 +0,0 @@
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os.path
from xml.dom import minidom
from xml.parsers import expat
from xml import sax
from xml.sax import expatreader
from lxml import etree
import six
from nova import exception
from nova.i18n import _
from nova import utils
XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
XMLNS_COMMON_V10 = 'http://docs.openstack.org/common/api/v1.0'
XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
def validate_schema(xml, schema_name, version='v1.1'):
if isinstance(xml, str):
xml = etree.fromstring(xml)
base_path = 'nova/api/openstack/compute/schemas/'
if schema_name not in ('atom', 'atom-link'):
base_path += '%s/' % version
schema_path = os.path.join(utils.novadir(),
'%s%s.rng' % (base_path, schema_name))
schema_doc = etree.parse(schema_path)
relaxng = etree.RelaxNG(schema_doc)
relaxng.assertValid(xml)
class Selector(object):
"""Selects datum to operate on from an object."""
def __init__(self, *chain):
"""Initialize the selector.
Each argument is a subsequent index into the object.
"""
self.chain = chain
def __repr__(self):
"""Return a representation of the selector."""
return "Selector" + repr(self.chain)
def __call__(self, obj, do_raise=False):
"""Select a datum to operate on.
Selects the relevant datum within the object.
:param obj: The object from which to select the object.
:param do_raise: If False (the default), return None if the
indexed datum does not exist. Otherwise,
raise a KeyError.
"""
# Walk the selector list
for elem in self.chain:
# If it's callable, call it
if callable(elem):
obj = elem(obj)
else:
if obj == '':
return ''
# Use indexing
try:
obj = obj[elem]
except (KeyError, IndexError):
# No sense going any further
if do_raise:
# Convert to a KeyError, for consistency
raise KeyError(elem)
return None
# Return the finally-selected object
return obj
def get_items(obj):
"""Get items in obj."""
return list(obj.items())
def get_items_without_dict(obj):
"""Get items in obj but omit any items containing a dict."""
obj_list = list(obj.items())
for item in obj_list:
if isinstance(list(item)[1], dict):
obj_list.remove(item)
return obj_list
class EmptyStringSelector(Selector):
"""Returns the empty string if Selector would return None."""
def __call__(self, obj, do_raise=False):
"""Returns empty string if the selected value does not exist."""
try:
return super(EmptyStringSelector, self).__call__(obj, True)
except KeyError:
return ""
class ConstantSelector(object):
"""Returns a constant."""
def __init__(self, value):
"""Initialize the selector.
:param value: The value to return.
"""
self.value = value
def __repr__(self):
"""Return a representation of the selector."""
return repr(self.value)
def __call__(self, _obj, _do_raise=False):
"""Select a datum to operate on.
Returns a constant value. Compatible with
Selector.__call__().
"""
return self.value
class TemplateElement(object):
"""Represent an element in the template."""
def __init__(self, tag, attrib=None, selector=None, subselector=None,
colon_ns=False, **extra):
"""Initialize an element.
Initializes an element in the template. Keyword arguments
specify attributes to be set on the element; values must be
callables. See TemplateElement.set() for more information.
:param tag: The name of the tag to create.
:param attrib: An optional dictionary of element attributes.
:param selector: An optional callable taking an object and
optional boolean do_raise indicator and
returning the object bound to the element.
:param subselector: An optional callable taking an object and
optional boolean do_raise indicator and
returning the object bound to the element.
This is used to further refine the datum
object returned by selector in the event
that it is a list of objects.
:colon_ns: An optional flag indicating whether to support k:v
type tagname, if True the k:v type tagname will
be supported by adding the k into the namespace.
"""
# Convert selector into a Selector
if selector is None:
selector = Selector()
elif not callable(selector):
selector = Selector(selector)
# Convert subselector into a Selector
if subselector is not None and not callable(subselector):
subselector = Selector(subselector)
self.tag = tag
self.selector = selector
self.subselector = subselector
self.attrib = {}
self._text = None
self._children = []
self._childmap = {}
self.colon_ns = colon_ns
# Run the incoming attributes through set() so that they
# become selectorized
if not attrib:
attrib = {}
attrib.update(extra)
for k, v in attrib.items():
self.set(k, v)
def __repr__(self):
"""Return a representation of the template element."""
return ('<%s.%s %r at %#x>' %
(self.__class__.__module__, self.__class__.__name__,
self.tag, id(self)))
def __len__(self):
"""Return the number of child elements."""
return len(self._children)
def __contains__(self, key):
"""Determine whether a child node named by key exists."""
return key in self._childmap
def __getitem__(self, idx):
"""Retrieve a child node by index or name."""
if isinstance(idx, six.string_types):
# Allow access by node name
return self._childmap[idx]
else:
return self._children[idx]
def append(self, elem):
"""Append a child to the element."""
# Unwrap templates...
elem = elem.unwrap()
# Avoid duplications
if elem.tag in self._childmap:
raise KeyError(elem.tag)
self._children.append(elem)
self._childmap[elem.tag] = elem
def extend(self, elems):
"""Append children to the element."""
# Pre-evaluate the elements
elemmap = {}
elemlist = []
for elem in elems:
# Unwrap templates...
elem = elem.unwrap()
# Avoid duplications
if elem.tag in self._childmap or elem.tag in elemmap:
raise KeyError(elem.tag)
elemmap[elem.tag] = elem
elemlist.append(elem)
# Update the children
self._children.extend(elemlist)
self._childmap.update(elemmap)
def insert(self, idx, elem):
"""Insert a child element at the given index."""
# Unwrap templates...
elem = elem.unwrap()
# Avoid duplications
if elem.tag in self._childmap:
raise KeyError(elem.tag)
self._children.insert(idx, elem)
self._childmap[elem.tag] = elem
def remove(self, elem):
"""Remove a child element."""
# Unwrap templates...
elem = elem.unwrap()
# Check if element exists
if elem.tag not in self._childmap or self._childmap[elem.tag] != elem:
raise ValueError(_('element is not a child'))
self._children.remove(elem)
del self._childmap[elem.tag]
def get(self, key):
"""Get an attribute.
Returns a callable which performs datum selection.
:param key: The name of the attribute to get.
"""
return self.attrib[key]
def set(self, key, value=None):
"""Set an attribute.
:param key: The name of the attribute to set.
:param value: A callable taking an object and optional boolean
do_raise indicator and returning the datum bound
to the attribute. If None, a Selector() will be
constructed from the key. If a string, a
Selector() will be constructed from the string.
"""
# Convert value to a selector
if value is None:
value = Selector(key)
elif not callable(value):
value = Selector(value)
self.attrib[key] = value
def keys(self):
"""Return the attribute names."""
return self.attrib.keys()
def items(self):
"""Return the attribute names and values."""
return self.attrib.items()
def unwrap(self):
"""Unwraps a template to return a template element."""
# We are a template element
return self
def wrap(self):
"""Wraps a template element to return a template."""
# Wrap in a basic Template
return Template(self)
def apply(self, elem, obj):
"""Apply text and attributes to an etree.Element.
Applies the text and attribute instructions in the template
element to an etree.Element instance.
:param elem: An etree.Element instance.
:param obj: The base object associated with this template
element.
"""
# Start with the text...
if self.text is not None:
elem.text = unicode(self.text(obj))
# Now set up all the attributes...
for key, value in self.attrib.items():
try:
elem.set(key, unicode(value(obj, True)))
except KeyError:
# Attribute has no value, so don't include it
pass
def _render(self, parent, datum, patches, nsmap):
"""Internal rendering.
Renders the template node into an etree.Element object.
Returns the etree.Element object.
:param parent: The parent etree.Element instance.
:param datum: The datum associated with this template element.
:param patches: A list of other template elements that must
also be applied.
:param nsmap: An optional namespace dictionary to be
associated with the etree.Element instance.
"""
# Allocate a node
if callable(self.tag):
tagname = self.tag(datum)
else:
tagname = self.tag
if self.colon_ns:
if ':' in tagname:
if nsmap is None:
nsmap = {}
colon_key, colon_name = tagname.split(':')
nsmap[colon_key] = colon_key
tagname = '{%s}%s' % (colon_key, colon_name)
elem = etree.Element(tagname, nsmap=nsmap)
# If we have a parent, append the node to the parent
if parent is not None:
parent.append(elem)
# If the datum is None, do nothing else
if datum is None:
return elem
# Apply this template element to the element
self.apply(elem, datum)
# Additionally, apply the patches
for patch in patches:
patch.apply(elem, datum)
# We have fully rendered the element; return it
return elem
def render(self, parent, obj, patches=None, nsmap=None):
"""Render an object.
Renders an object against this template node. Returns a list
of two-item tuples, where the first item is an etree.Element
instance and the second item is the datum associated with that
instance.
:param parent: The parent for the etree.Element instances.
:param obj: The object to render this template element
against.
:param patches: A list of other template elements to apply
when rendering this template element.
:param nsmap: An optional namespace dictionary to attach to
the etree.Element instances.
"""
patches = patches or []
# First, get the datum we're rendering
data = None if obj is None else self.selector(obj)
# Check if we should render at all
if not self.will_render(data):
return []
elif data is None:
return [(self._render(parent, None, patches, nsmap), None)]
# Make the data into a list if it isn't already
if not isinstance(data, list):
data = [data]
elif parent is None:
raise ValueError(_('root element selecting a list'))
# Render all the elements
elems = []
for datum in data:
if self.subselector is not None:
datum = self.subselector(datum)
elems.append((self._render(parent, datum, patches, nsmap), datum))
# Return all the elements rendered, as well as the
# corresponding datum for the next step down the tree
return elems
def will_render(self, datum):
"""Hook method.
An overridable hook method to determine whether this template
element will be rendered at all. By default, returns False
(inhibiting rendering) if the datum is None.
:param datum: The datum associated with this template element.
"""
# Don't render if datum is None
return datum is not None
def _text_get(self):
"""Template element text.
Either None or a callable taking an object and optional
boolean do_raise indicator and returning the datum bound to
the text of the template element.
"""
return self._text
def _text_set(self, value):
# Convert value to a selector
if value is not None and not callable(value):
value = Selector(value)
self._text = value
def _text_del(self):
self._text = None
text = property(_text_get, _text_set, _text_del)
def tree(self):
"""Return string representation of the template tree.
Returns a representation of the template rooted at this
element as a string, suitable for inclusion in debug logs.
"""
# Build the inner contents of the tag...
contents = [self.tag, '!selector=%r' % self.selector]
# Add the text...
if self.text is not None:
contents.append('!text=%r' % self.text)
# Add all the other attributes
for key, value in self.attrib.items():
contents.append('%s=%r' % (key, value))
# If there are no children, return it as a closed tag
if len(self) == 0:
return '<%s/>' % ' '.join([str(i) for i in contents])
# OK, recurse to our children
children = [c.tree() for c in self]
# Return the result
return ('<%s>%s</%s>' %
(' '.join(contents), ''.join(children), self.tag))
def SubTemplateElement(parent, tag, attrib=None, selector=None,
subselector=None, colon_ns=False, **extra):
"""Create a template element as a child of another.
Corresponds to the etree.SubElement interface. Parameters are as
for TemplateElement, with the addition of the parent.
"""
# Convert attributes
attrib = attrib or {}
attrib.update(extra)
# Get a TemplateElement
elem = TemplateElement(tag, attrib=attrib, selector=selector,
subselector=subselector, colon_ns=colon_ns)
# Append the parent safely
if parent is not None:
parent.append(elem)
return elem
class Template(object):
"""Represent a template."""
def __init__(self, root, nsmap=None):
"""Initialize a template.
:param root: The root element of the template.
:param nsmap: An optional namespace dictionary to be
associated with the root element of the
template.
"""
self.root = root.unwrap() if root is not None else None
self.nsmap = nsmap or {}
self.serialize_options = dict(encoding='UTF-8', xml_declaration=True)
def _serialize(self, parent, obj, siblings, nsmap=None):
"""Internal serialization.
Recursive routine to build a tree of etree.Element instances
from an object based on the template. Returns the first
etree.Element instance rendered, or None.
:param parent: The parent etree.Element instance. Can be
None.
:param obj: The object to render.
:param siblings: The TemplateElement instances against which
to render the object.
:param nsmap: An optional namespace dictionary to be
associated with the etree.Element instance
rendered.
"""
# First step, render the element
elems = siblings[0].render(parent, obj, siblings[1:], nsmap)
# Now, recurse to all child elements
seen = set()
for idx, sibling in enumerate(siblings):
for child in sibling:
# Have we handled this child already?
if child.tag in seen:
continue
seen.add(child.tag)
# Determine the child's siblings
nieces = [child]
for sib in siblings[idx + 1:]:
if child.tag in sib:
nieces.append(sib[child.tag])
# Now we recurse for every data element
for elem, datum in elems:
self._serialize(elem, datum, nieces)
# Return the first element; at the top level, this will be the
# root element
if elems:
return elems[0][0]
def serialize(self, obj, *args, **kwargs):
"""Serialize an object.
Serializes an object against the template. Returns a string
with the serialized XML. Positional and keyword arguments are
passed to etree.tostring().
:param obj: The object to serialize.
"""
elem = self.make_tree(obj)
if elem is None:
return ''
for k, v in self.serialize_options.items():
kwargs.setdefault(k, v)
# Serialize it into XML
return etree.tostring(elem, *args, **kwargs)
def make_tree(self, obj):
"""Create a tree.
Serializes an object against the template. Returns an Element
node with appropriate children.
:param obj: The object to serialize.
"""
# If the template is empty, return the empty string
if self.root is None:
return None
# Get the siblings and nsmap of the root element
siblings = self._siblings()
nsmap = self._nsmap()
# Form the element tree
return self._serialize(None, obj, siblings, nsmap)
def _siblings(self):
"""Hook method for computing root siblings.
An overridable hook method to return the siblings of the root
element. By default, this is the root element itself.
"""
return [self.root]
def _nsmap(self):
"""Hook method for computing the namespace dictionary.
An overridable hook method to return the namespace dictionary.
"""
return self.nsmap.copy()
def unwrap(self):
"""Unwraps a template to return a template element."""
# Return the root element
return self.root
def wrap(self):
"""Wraps a template element to return a template."""
# We are a template
return self
def apply(self, master):
"""Hook method for determining slave applicability.
An overridable hook method used to determine if this template
is applicable as a slave to a given master template.
:param master: The master template to test.
"""
return True
def tree(self):
"""Return string representation of the template tree.
Returns a representation of the template as a string, suitable
for inclusion in debug logs.
"""
return "%r: %s" % (self, self.root.tree())
class MasterTemplate(Template):
"""Represent a master template.
Master templates are versioned derivatives of templates that
additionally allow slave templates to be attached. Slave
templates allow modification of the serialized result without
directly changing the master.
"""
def __init__(self, root, version, nsmap=None):
"""Initialize a master template.
:param root: The root element of the template.
:param version: The version number of the template.
:param nsmap: An optional namespace dictionary to be
associated with the root element of the
template.
"""
super(MasterTemplate, self).__init__(root, nsmap)
self.version = version
self.slaves = []
def __repr__(self):
"""Return string representation of the template."""
return ("<%s.%s object version %s at %#x>" %
(self.__class__.__module__, self.__class__.__name__,
self.version, id(self)))
def _siblings(self):
"""Hook method for computing root siblings.
An overridable hook method to return the siblings of the root
element. This is the root element plus the root elements of
all the slave templates.
"""
return [self.root] + [slave.root for slave in self.slaves]
def _nsmap(self):
"""Hook method for computing the namespace dictionary.
An overridable hook method to return the namespace dictionary.
The namespace dictionary is computed by taking the master
template's namespace dictionary and updating it from all the
slave templates.
"""
nsmap = self.nsmap.copy()
for slave in self.slaves:
nsmap.update(slave._nsmap())
return nsmap
def attach(self, *slaves):
"""Attach one or more slave templates.
Attaches one or more slave templates to the master template.
Slave templates must have a root element with the same tag as
the master template. The slave template's apply() method will
be called to determine if the slave should be applied to this
master; if it returns False, that slave will be skipped.
(This allows filtering of slaves based on the version of the
master template.)
"""
slave_list = []
for slave in slaves:
slave = slave.wrap()
# Make sure we have a tree match
if slave.root.tag != self.root.tag:
msg = _("Template tree mismatch; adding slave %(slavetag)s to "
"master %(mastertag)s") % {'slavetag': slave.root.tag,
'mastertag': self.root.tag}
raise ValueError(msg)
# Make sure slave applies to this template
if not slave.apply(self):
continue
slave_list.append(slave)
# Add the slaves
self.slaves.extend(slave_list)
def copy(self):
"""Return a copy of this master template."""
# Return a copy of the MasterTemplate
tmp = self.__class__(self.root, self.version, self.nsmap)
tmp.slaves = self.slaves[:]
return tmp
class SlaveTemplate(Template):
"""Represent a slave template.
Slave templates are versioned derivatives of templates. Each
slave has a minimum version and optional maximum version of the
master template to which they can be attached.
"""
def __init__(self, root, min_vers, max_vers=None, nsmap=None):
"""Initialize a slave template.
:param root: The root element of the template.
:param min_vers: The minimum permissible version of the master
template for this slave template to apply.
:param max_vers: An optional upper bound for the master
template version.
:param nsmap: An optional namespace dictionary to be
associated with the root element of the
template.
"""
super(SlaveTemplate, self).__init__(root, nsmap)
self.min_vers = min_vers
self.max_vers = max_vers
def __repr__(self):
"""Return string representation of the template."""
return ("<%s.%s object versions %s-%s at %#x>" %
(self.__class__.__module__, self.__class__.__name__,
self.min_vers, self.max_vers, id(self)))
def apply(self, master):
"""Hook method for determining slave applicability.
An overridable hook method used to determine if this template
is applicable as a slave to a given master template. This
version requires the master template to have a version number
between min_vers and max_vers.
:param master: The master template to test.
"""
# Does the master meet our minimum version requirement?
if master.version < self.min_vers:
return False
# How about our maximum version requirement?
if self.max_vers is not None and master.version > self.max_vers:
return False
return True
class TemplateBuilder(object):
"""Template builder.
This class exists to allow templates to be lazily built without
having to build them each time they are needed. It must be
subclassed, and the subclass must implement the construct()
method, which must return a Template (or subclass) instance. The
constructor will always return the template returned by
construct(), or, if it has a copy() method, a copy of that
template.
"""
_tmpl = None
def __new__(cls, copy=True):
"""Construct and return a template.
:param copy: If True (the default), a copy of the template
will be constructed and returned, if possible.
"""
# Do we need to construct the template?
if cls._tmpl is None:
tmp = super(TemplateBuilder, cls).__new__(cls)
# Construct the template
cls._tmpl = tmp.construct()
# If the template has a copy attribute, return the result of
# calling it
if copy and hasattr(cls._tmpl, 'copy'):
return cls._tmpl.copy()
# Return the template
return cls._tmpl
def construct(self):
"""Construct a template.
Called to construct a template instance, which it must return.
Only called once.
"""
raise NotImplementedError(_("subclasses must implement construct()!"))
def make_links(parent, selector=None):
"""Attach an Atom <links> element to the parent."""
elem = SubTemplateElement(parent, '{%s}link' % XMLNS_ATOM,
selector=selector)
elem.set('rel')
elem.set('type')
elem.set('href')
# Just for completeness...
return elem
def make_flat_dict(name, selector=None, subselector=None,
ns=None, colon_ns=False, root=None,
ignore_sub_dicts=False):
"""Utility for simple XML templates that traditionally used
XMLDictSerializer with no metadata. Returns a template element
where the top-level element has the given tag name, and where
sub-elements have tag names derived from the object's keys and
text derived from the object's values.
:param root: if None, this will create the root.
:param ignore_sub_dicts: If True, ignores any dict objects inside the
object. If False, causes an error if there is a
dict object present.
"""
# Set up the names we need...
if ns is None:
elemname = name
tagname = Selector(0)
else:
elemname = '{%s}%s' % (ns, name)
tagname = lambda obj, do_raise=False: '{%s}%s' % (ns, obj[0])
if selector is None:
selector = name
if not root:
# Build the root element
root = TemplateElement(elemname, selector=selector,
subselector=subselector, colon_ns=colon_ns)
choice = get_items if ignore_sub_dicts is False else get_items_without_dict
# Build an element to represent all the keys and values
elem = SubTemplateElement(root, tagname, selector=choice,
colon_ns=colon_ns)
elem.text = 1
# Return the template
return root
class ProtectedExpatParser(expatreader.ExpatParser):
"""An expat parser which disables DTD's and entities by default."""
def __init__(self, forbid_dtd=True, forbid_entities=True,
*args, **kwargs):
# Python 2.x old style class
expatreader.ExpatParser.__init__(self, *args, **kwargs)
self.forbid_dtd = forbid_dtd
self.forbid_entities = forbid_entities
def start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
raise ValueError("Inline DTD forbidden")
def entity_decl(self, entityName, is_parameter_entity, value, base,
systemId, publicId, notationName):
raise ValueError("<!ENTITY> entity declaration forbidden")
def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
# expat 1.2
raise ValueError("<!ENTITY> unparsed entity forbidden")
def external_entity_ref(self, context, base, systemId, publicId):
raise ValueError("<!ENTITY> external entity forbidden")
def notation_decl(self, name, base, sysid, pubid):
raise ValueError("<!ENTITY> notation forbidden")
def reset(self):
expatreader.ExpatParser.reset(self)
if self.forbid_dtd:
self._parser.StartDoctypeDeclHandler = self.start_doctype_decl
self._parser.EndDoctypeDeclHandler = None
if self.forbid_entities:
self._parser.EntityDeclHandler = self.entity_decl
self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl
self._parser.ExternalEntityRefHandler = self.external_entity_ref
self._parser.NotationDeclHandler = self.notation_decl
try:
self._parser.SkippedEntityHandler = None
except AttributeError:
# some pyexpat versions do not support SkippedEntity
pass
def safe_minidom_parse_string(xml_string):
"""Parse an XML string using minidom safely."""
try:
return minidom.parseString(xml_string, parser=ProtectedExpatParser())
except (sax.SAXParseException, ValueError,
expat.ExpatError, LookupError) as e:
# NOTE(Vijaya Erukala): XML input such as
# <?xml version="1.0" encoding="TF-8"?>
# raises LookupError: unknown encoding: TF-8
raise exception.MalformedRequestBody(reason=six.text_type(e))

View File

@ -1,28 +0,0 @@
<domain type='kvm' id='100'>
<name>i-A9B8C7D6</name>
<uuid>12a345bc-67c8-901d-2e34-56f7g89012h3</uuid>
<memory>524288</memory>
<currentMemory>524288</currentMemory>
<vcpu>1</vcpu>
<os/>
<features>
<acpi/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/bin/kvm</emulator>
<disk type='file' device='disk'>
<source file='/var/lib/fakevirt/instances/i-A9B8C7D6/disk'/>
<target dev='sda' bus='scsi'/>
</disk>
<interface type='bridge'>
<mac address='a0:1b:c2:3d:4e:f5'/>
<source bridge='fakebr2000'/>
<target dev='vnet1'/>
<model type='e1000'/>
</interface>
</devices>
</domain>

View File

@ -39,7 +39,6 @@ from oslotest import moxstubout
import six import six
import testtools import testtools
from nova.api.openstack import wsgi
from nova import context from nova import context
from nova import db from nova import db
from nova.network import manager as network_manager from nova.network import manager as network_manager
@ -150,12 +149,6 @@ class skipIf(object):
'classes') 'classes')
class skipXmlTest(skipIf):
def __init__(self, reason):
super(skipXmlTest, self).__init__(wsgi.DISABLE_XML_V2_API,
reason)
def _patch_mock_to_raise_for_invalid_assert_calls(): def _patch_mock_to_raise_for_invalid_assert_calls():
def raise_for_invalid_assert_calls(wrapped): def raise_for_invalid_assert_calls(wrapped):
def wrapper(_self, name): def wrapper(_self, name):

View File

@ -16,16 +16,11 @@
import copy import copy
import uuid as stdlib_uuid import uuid as stdlib_uuid
import feedparser
from lxml import etree
from oslo.serialization import jsonutils from oslo.serialization import jsonutils
import webob import webob
from nova.api.openstack.compute import versions
from nova.api.openstack.compute import views from nova.api.openstack.compute import views
from nova.api.openstack import xmlutil
from nova import test from nova import test
from nova.tests.unit.api.openstack import common
from nova.tests.unit.api.openstack import fakes from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import matchers from nova.tests.unit import matchers
@ -59,10 +54,6 @@ EXP_VERSIONS = {
}, },
], ],
"media-types": [ "media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2",
},
{ {
"base": "application/json", "base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2", "type": "application/vnd.openstack.compute+json;version=2",
@ -161,11 +152,6 @@ class VersionsTestV20(test.NoDBTestCase):
}, },
], ],
"media-types": [ "media-types": [
{
"base": "application/xml",
"type": "application/"
"vnd.openstack.compute+xml;version=2",
},
{ {
"base": "application/json", "base": "application/json",
"type": "application/" "type": "application/"
@ -189,131 +175,6 @@ class VersionsTestV20(test.NoDBTestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(404, res.status_int) self.assertEqual(404, res.status_int)
@test.skipXmlTest("Nova v2 XML support is disabled")
def test_get_version_2_detail_xml(self):
req = webob.Request.blank('/v2/')
req.accept = "application/xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
self.assertEqual(res.content_type, "application/xml")
version = etree.XML(res.body)
xmlutil.validate_schema(version, 'version')
expected = EXP_VERSIONS['v2.0']
self.assertTrue(version.xpath('/ns:version', namespaces=NS))
media_types = version.xpath('ns:media-types/ns:media-type',
namespaces=NS)
self.assertTrue(common.compare_media_types(media_types,
expected['media-types']))
for key in ['id', 'status', 'updated']:
self.assertEqual(version.get(key), expected[key])
links = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(links,
[{'rel': 'self', 'href': 'http://localhost/v2/'}]
+ expected['links']))
@test.skipXmlTest("Nova v2 XML support is disabled")
def test_get_version_list_xml(self):
req = webob.Request.blank('/')
req.accept = "application/xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
self.assertEqual(res.content_type, "application/xml")
root = etree.XML(res.body)
xmlutil.validate_schema(root, 'versions')
self.assertTrue(root.xpath('/ns:versions', namespaces=NS))
versions = root.xpath('ns:version', namespaces=NS)
self.assertEqual(len(versions), 2)
for i, v in enumerate(['v2.0', 'v2.1']):
version = versions[i]
expected = EXP_VERSIONS[v]
for key in ['id', 'status', 'updated']:
self.assertEqual(version.get(key), expected[key])
(link,) = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(link,
[{'rel': 'self', 'href': 'http://localhost/%s/' % v}]))
@test.skipXmlTest("Nova v2 XML support is disabled")
def test_get_version_2_detail_atom(self):
req = webob.Request.blank('/v2/')
req.accept = "application/atom+xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
self.assertEqual("application/atom+xml", res.content_type)
xmlutil.validate_schema(etree.XML(res.body), 'atom')
f = feedparser.parse(res.body)
self.assertEqual(f.feed.title, 'About This Version')
self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z')
self.assertEqual(f.feed.id, 'http://localhost/v2/')
self.assertEqual(f.feed.author, 'Rackspace')
self.assertEqual(f.feed.author_detail.href,
'http://www.rackspace.com/')
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(f.feed.links[0]['rel'], 'self')
self.assertEqual(len(f.entries), 1)
entry = f.entries[0]
self.assertEqual(entry.id, 'http://localhost/v2/')
self.assertEqual(entry.title, 'Version v2.0')
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
self.assertEqual(len(entry.content), 1)
self.assertEqual(entry.content[0].value,
'Version v2.0 CURRENT (2011-01-21T11:33:21Z)')
self.assertEqual(len(entry.links), 2)
self.assertEqual(entry.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(entry.links[0]['rel'], 'self')
self.assertEqual(entry.links[1], {
'href': EXP_LINKS['v2.0']['html'],
'type': 'text/html',
'rel': 'describedby'})
@test.skipXmlTest("Nova v2 XML support is disabled")
def test_get_version_list_atom(self):
req = webob.Request.blank('/')
req.accept = "application/atom+xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
self.assertEqual(res.content_type, "application/atom+xml")
f = feedparser.parse(res.body)
self.assertEqual(f.feed.title, 'Available API Versions')
self.assertEqual(f.feed.updated, '2013-07-23T11:33:21Z')
self.assertEqual(f.feed.id, 'http://localhost/')
self.assertEqual(f.feed.author, 'Rackspace')
self.assertEqual(f.feed.author_detail.href,
'http://www.rackspace.com/')
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/')
self.assertEqual(f.feed.links[0]['rel'], 'self')
self.assertEqual(len(f.entries), 2)
entry = f.entries[0]
self.assertEqual(entry.id, 'http://localhost/v2/')
self.assertEqual(entry.title, 'Version v2.0')
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
self.assertEqual(len(entry.content), 1)
self.assertEqual(entry.content[0].value,
'Version v2.0 CURRENT (2011-01-21T11:33:21Z)')
self.assertEqual(len(entry.links), 1)
self.assertEqual(entry.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(entry.links[0]['rel'], 'self')
entry = f.entries[1]
self.assertEqual(entry.id, 'http://localhost/v2/')
self.assertEqual(entry.title, 'Version v2.1')
self.assertEqual(entry.updated, '2013-07-23T11:33:21Z')
self.assertEqual(len(entry.content), 1)
self.assertEqual(entry.content[0].value,
'Version v2.1 EXPERIMENTAL (2013-07-23T11:33:21Z)')
self.assertEqual(len(entry.links), 1)
self.assertEqual(entry.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(entry.links[0]['rel'], 'self')
def test_multi_choice_image(self): def test_multi_choice_image(self):
req = webob.Request.blank('/images/1') req = webob.Request.blank('/images/1')
req.accept = "application/json" req.accept = "application/json"
@ -333,11 +194,6 @@ class VersionsTestV20(test.NoDBTestCase):
}, },
], ],
"media-types": [ "media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml"
";version=2"
},
{ {
"base": "application/json", "base": "application/json",
"type": "application/vnd.openstack.compute+json" "type": "application/vnd.openstack.compute+json"
@ -367,47 +223,6 @@ class VersionsTestV20(test.NoDBTestCase):
self.assertThat(jsonutils.loads(res.body), self.assertThat(jsonutils.loads(res.body),
matchers.DictMatches(expected)) matchers.DictMatches(expected))
@test.skipXmlTest("Nova v2 XML support is disabled")
def test_multi_choice_image_xml(self):
req = webob.Request.blank('/images/1')
req.accept = "application/xml"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 300)
self.assertEqual(res.content_type, "application/xml")
root = etree.XML(res.body)
self.assertTrue(root.xpath('/ns:choices', namespaces=NS))
versions = root.xpath('ns:version', namespaces=NS)
self.assertEqual(len(versions), 2)
version = versions[0]
self.assertEqual(version.get('id'), 'v2.0')
self.assertEqual(version.get('status'), 'CURRENT')
media_types = version.xpath('ns:media-types/ns:media-type',
namespaces=NS)
self.assertTrue(common.
compare_media_types(media_types,
EXP_VERSIONS['v2.0']['media-types']
))
links = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(links,
[{'rel': 'self', 'href': 'http://localhost/v2/images/1'}]))
version = versions[1]
self.assertEqual(version.get('id'), 'v2.1')
self.assertEqual(version.get('status'), 'EXPERIMENTAL')
media_types = version.xpath('ns:media-types/ns:media-type',
namespaces=NS)
self.assertTrue(common.
compare_media_types(media_types,
EXP_VERSIONS['v2.1']['media-types']
))
links = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(links,
[{'rel': 'self', 'href': 'http://localhost/v2/images/1'}]))
def test_multi_choice_server_atom(self): def test_multi_choice_server_atom(self):
"""Make sure multi choice responses do not have content-type """Make sure multi choice responses do not have content-type
application/atom+xml (should use default of json) application/atom+xml (should use default of json)
@ -438,11 +253,6 @@ class VersionsTestV20(test.NoDBTestCase):
}, },
], ],
"media-types": [ "media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml"
";version=2"
},
{ {
"base": "application/json", "base": "application/json",
"type": "application/vnd.openstack.compute+json" "type": "application/vnd.openstack.compute+json"
@ -537,208 +347,6 @@ class VersionsViewBuilderTests(test.NoDBTestCase):
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
class VersionsSerializerTests(test.NoDBTestCase):
def test_versions_list_xml_serializer(self):
versions_data = {
'versions': [
{
"id": "2.7",
"updated": "2011-07-18T11:30:00Z",
"status": "DEPRECATED",
"links": [
{
"rel": "self",
"href": "http://test/v2",
},
],
},
]
}
serializer = versions.VersionsTemplate()
response = serializer.serialize(versions_data)
root = etree.XML(response)
xmlutil.validate_schema(root, 'versions')
self.assertTrue(root.xpath('/ns:versions', namespaces=NS))
version_elems = root.xpath('ns:version', namespaces=NS)
self.assertEqual(len(version_elems), 1)
version = version_elems[0]
self.assertEqual(version.get('id'), versions_data['versions'][0]['id'])
self.assertEqual(version.get('status'),
versions_data['versions'][0]['status'])
(link,) = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(link, [{
'rel': 'self',
'href': 'http://test/v2',
'type': 'application/atom+xml'}]))
def test_versions_multi_xml_serializer(self):
versions_data = {
'choices': [
{
"id": "2.7",
"updated": "2011-07-18T11:30:00Z",
"status": "DEPRECATED",
"media-types": EXP_VERSIONS['v2.0']['media-types'],
"links": [
{
"rel": "self",
"href": "http://test/v2/images",
},
],
},
]
}
serializer = versions.ChoicesTemplate()
response = serializer.serialize(versions_data)
root = etree.XML(response)
self.assertTrue(root.xpath('/ns:choices', namespaces=NS))
(version,) = root.xpath('ns:version', namespaces=NS)
self.assertEqual(version.get('id'), versions_data['choices'][0]['id'])
self.assertEqual(version.get('status'),
versions_data['choices'][0]['status'])
media_types = list(version)[0]
self.assertEqual(media_types.tag.split('}')[1], "media-types")
media_types = version.xpath('ns:media-types/ns:media-type',
namespaces=NS)
self.assertTrue(common.compare_media_types(media_types,
versions_data['choices'][0]['media-types']))
(link,) = version.xpath('atom:link', namespaces=NS)
self.assertTrue(common.compare_links(link,
versions_data['choices'][0]['links']))
def test_versions_list_atom_serializer(self):
versions_data = {
'versions': [
{
"id": "2.9.8",
"updated": "2011-07-20T11:40:00Z",
"status": "CURRENT",
"links": [
{
"rel": "self",
"href": "http://test/2.9.8",
},
],
},
]
}
serializer = versions.VersionsAtomSerializer()
response = serializer.serialize(versions_data)
f = feedparser.parse(response)
self.assertEqual(f.feed.title, 'Available API Versions')
self.assertEqual(f.feed.updated, '2011-07-20T11:40:00Z')
self.assertEqual(f.feed.id, 'http://test/')
self.assertEqual(f.feed.author, 'Rackspace')
self.assertEqual(f.feed.author_detail.href,
'http://www.rackspace.com/')
self.assertEqual(f.feed.links[0]['href'], 'http://test/')
self.assertEqual(f.feed.links[0]['rel'], 'self')
self.assertEqual(len(f.entries), 1)
entry = f.entries[0]
self.assertEqual(entry.id, 'http://test/2.9.8')
self.assertEqual(entry.title, 'Version 2.9.8')
self.assertEqual(entry.updated, '2011-07-20T11:40:00Z')
self.assertEqual(len(entry.content), 1)
self.assertEqual(entry.content[0].value,
'Version 2.9.8 CURRENT (2011-07-20T11:40:00Z)')
self.assertEqual(len(entry.links), 1)
self.assertEqual(entry.links[0]['href'], 'http://test/2.9.8')
self.assertEqual(entry.links[0]['rel'], 'self')
def test_version_detail_atom_serializer(self):
versions_data = {
"version": {
"id": "v2.0",
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"links": [
{
"rel": "self",
"href": "http://localhost/v2/",
},
{
"rel": "describedby",
"type": "text/html",
"href": EXP_LINKS['v2.0']['html'],
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml"
";version=2",
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json"
";version=2",
}
],
},
}
serializer = versions.VersionAtomSerializer()
response = serializer.serialize(versions_data)
f = feedparser.parse(response)
self.assertEqual(f.feed.title, 'About This Version')
self.assertEqual(f.feed.updated, '2011-01-21T11:33:21Z')
self.assertEqual(f.feed.id, 'http://localhost/v2/')
self.assertEqual(f.feed.author, 'Rackspace')
self.assertEqual(f.feed.author_detail.href,
'http://www.rackspace.com/')
self.assertEqual(f.feed.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(f.feed.links[0]['rel'], 'self')
self.assertEqual(len(f.entries), 1)
entry = f.entries[0]
self.assertEqual(entry.id, 'http://localhost/v2/')
self.assertEqual(entry.title, 'Version v2.0')
self.assertEqual(entry.updated, '2011-01-21T11:33:21Z')
self.assertEqual(len(entry.content), 1)
self.assertEqual(entry.content[0].value,
'Version v2.0 CURRENT (2011-01-21T11:33:21Z)')
self.assertEqual(len(entry.links), 2)
self.assertEqual(entry.links[0]['href'], 'http://localhost/v2/')
self.assertEqual(entry.links[0]['rel'], 'self')
self.assertEqual(entry.links[1], {
'rel': 'describedby',
'type': 'text/html',
'href': EXP_LINKS['v2.0']['html']})
def test_multi_choice_image_with_body(self):
req = webob.Request.blank('/images/1')
req.accept = "application/json"
req.method = 'POST'
req.content_type = "application/json"
req.body = "{\"foo\": \"bar\"}"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(300, res.status_int)
self.assertEqual("application/json", res.content_type)
def test_get_version_list_with_body(self):
req = webob.Request.blank('/')
req.accept = "application/json"
req.method = 'POST'
req.content_type = "application/json"
req.body = "{\"foo\": \"bar\"}"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(200, res.status_int)
self.assertEqual("application/json", res.content_type)
# NOTE(oomichi): Now version API of v2.0 covers "/"(root). # NOTE(oomichi): Now version API of v2.0 covers "/"(root).
# So this class tests "/v2.1" only for v2.1 API. # So this class tests "/v2.1" only for v2.1 API.
class VersionsTestV21(test.NoDBTestCase): class VersionsTestV21(test.NoDBTestCase):