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
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 utils as compute_utils
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)
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):
@functools.wraps(f)
def inner(*args, **kwargs):

View File

@ -17,7 +17,6 @@ import webob
from webob import exc
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.console import api as console_api
from nova import exception
@ -44,47 +43,12 @@ def _translate_detail_keys(cons):
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):
"""The Consoles controller for the OpenStack API."""
def __init__(self):
self.console_api = console_api.API()
@wsgi.serializers(xml=ConsolesTemplate)
def index(self, req, server_id):
"""Returns a list of consoles for this instance."""
consoles = self.console_api.get_consoles(
@ -102,7 +66,6 @@ class Controller(object):
except exception.InstanceNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message())
@wsgi.serializers(xml=ConsoleTemplate)
def show(self, req, server_id, id):
"""Shows in-depth information on a specific console."""
try:

View File

@ -16,8 +16,6 @@
import webob.exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova import objects
@ -27,21 +25,6 @@ from nova import utils
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):
"""The agent is talking about guest agent.The host can use this for
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/GuestAgentXenStoreCommunication
"""
@wsgi.serializers(xml=AgentsIndexTemplate)
def index(self, req):
"""Return a list of all agent builds. Filter by hypervisor."""
context = req.environ['nova.context']

View File

@ -18,7 +18,6 @@ import webob
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 exception
from nova.i18n import _
@ -30,25 +29,12 @@ authorize = extensions.extension_authorizer('compute',
'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):
def __init__(self):
self.compute_api = compute.API()
super(AssistedVolumeSnapshotsController, self).__init__()
@wsgi.serializers(xml=SnapshotTemplate)
def create(self, req, body):
"""Creates a new snapshot."""
context = req.environ['nova.context']

View File

@ -14,10 +14,8 @@
from oslo.config import cfg
from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import availability_zones
from nova import objects
from nova import servicegroup
@ -30,43 +28,6 @@ authorize_detail = extensions.extension_authorizer('compute',
'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):
"""The Availability Zone API controller for the OpenStack API."""
@ -139,7 +100,6 @@ class AvailabilityZoneController(wsgi.Controller):
"hosts": None})
return {'availabilityZoneInfo': result}
@wsgi.serializers(xml=AvailabilityZonesTemplate)
def index(self, req):
"""Returns a summary list of availability zone."""
context = req.environ['nova.context']
@ -147,7 +107,6 @@ class AvailabilityZoneController(wsgi.Controller):
return self._describe_availability_zones(context)
@wsgi.serializers(xml=AvailabilityZonesTemplate)
def detail(self, req):
"""Returns a detailed list of availability zone."""
context = req.environ['nova.context']

View File

@ -21,7 +21,6 @@ import webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _
from nova.openstack.common import log as logging
@ -58,25 +57,6 @@ CONF.import_opt('compute_driver', 'nova.virt.driver')
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():
"""return an Ironic client."""
# TODO(NobodyCam): Fix insecure setting
@ -99,31 +79,6 @@ def _no_ironic_proxy(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):
"""The Bare-Metal Node API controller for the OpenStack API.
@ -145,7 +100,6 @@ class BareMetalNodeController(wsgi.Controller):
d[f] = node_ref.get(f)
return d
@wsgi.serializers(xml=NodesTemplate)
def index(self, req):
context = req.environ['nova.context']
authorize(context)
@ -164,7 +118,6 @@ class BareMetalNodeController(wsgi.Controller):
nodes.append(node)
return {'nodes': nodes}
@wsgi.serializers(xml=NodeTemplate)
def show(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -184,7 +137,6 @@ class BareMetalNodeController(wsgi.Controller):
node['interfaces'].append({'address': port.address})
return {'node': node}
@wsgi.serializers(xml=NodeTemplate)
def create(self, req, body):
_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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.cells import rpcapi as cells_rpcapi
from nova.compute import api as compute
from nova import exception
@ -41,95 +40,9 @@ CONF.import_opt('capabilities', 'nova.cells.opts', group='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}
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):
"""Filters all model attributes except for keys
item is a dict
@ -197,7 +110,6 @@ class Controller(object):
items = [_scrub_cell(item, detail=detail) for item in items]
return dict(cells=items)
@wsgi.serializers(xml=CellsTemplate)
@common.check_cells_enabled
def index(self, req):
"""Return all cells in brief."""
@ -205,7 +117,6 @@ class Controller(object):
authorize(ctxt)
return self._get_cells(ctxt, req)
@wsgi.serializers(xml=CellsTemplate)
@common.check_cells_enabled
def detail(self, req):
"""Return all cells in detail."""
@ -213,7 +124,6 @@ class Controller(object):
authorize(ctxt)
return self._get_cells(ctxt, req, detail=True)
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled
def info(self, req):
"""Return name and capabilities for this cell."""
@ -232,7 +142,6 @@ class Controller(object):
'capabilities': cell_capabs}
return dict(cell=cell)
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled
def capacities(self, req, id=None):
"""Return capacities for a given cell or all cells."""
@ -252,7 +161,6 @@ class Controller(object):
return dict(cell={"capacities": capacities})
@wsgi.serializers(xml=CellTemplate)
@common.check_cells_enabled
def show(self, req, id):
"""Return data about the given cell name. 'id' is a cell name."""
@ -344,8 +252,6 @@ class Controller(object):
# Now set the transport URL
cell['transport_url'] = str(transport_url)
@wsgi.serializers(xml=CellTemplate)
@wsgi.deserializers(xml=CellDeserializer)
@common.check_cells_enabled
def create(self, req, body):
"""Create a child cell entry."""
@ -369,8 +275,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(cell=_scrub_cell(cell))
@wsgi.serializers(xml=CellTemplate)
@wsgi.deserializers(xml=CellDeserializer)
@common.check_cells_enabled
def update(self, req, id, body):
"""Update a child cell entry. 'id' is the cell name to update."""

View File

@ -15,8 +15,6 @@
import webob.exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.cert.rpcapi
from nova import exception
from nova.i18n import _
@ -24,19 +22,6 @@ from nova.i18n import _
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):
return {
'data': certificate,
@ -51,7 +36,6 @@ class CertificatesController(object):
self.cert_rpcapi = nova.cert.rpcapi.CertAPI()
super(CertificatesController, self).__init__()
@wsgi.serializers(xml=CertificateTemplate)
def show(self, req, id):
"""Return certificate information."""
context = req.environ['nova.context']
@ -66,7 +50,6 @@ class CertificatesController(object):
raise webob.exc.HTTPNotFound(explanation=e.format_message())
return {'certificate': _translate_certificate_view(cert)}
@wsgi.serializers(xml=CertificateTemplate)
def create(self, req, body=None):
"""Create a certificate."""
context = req.environ['nova.context']

View File

@ -19,8 +19,6 @@ from oslo.utils import timeutils
from webob import exc
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 import compute
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')
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):
"""Handle creating and listing cloudpipe instances."""
@ -126,7 +104,6 @@ class CloudpipeController(object):
rv['state'] = 'invalid'
return rv
@wsgi.serializers(xml=CloudpipeTemplate)
def create(self, req, body):
"""Create a new cloudpipe instance, if none exists.
@ -154,7 +131,6 @@ class CloudpipeController(object):
raise exc.HTTPBadRequest(explanation=msg)
return {'instance_id': instance['uuid']}
@wsgi.serializers(xml=CloudpipesTemplate)
def index(self, req):
"""List running cloudpipe instances."""
context = req.environ['nova.context']

View File

@ -18,26 +18,10 @@
from nova.api.openstack.compute import servers
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
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):
def _add_config_drive(self, req, servers):
@ -49,7 +33,7 @@ class Controller(servers.Controller):
def _show(self, req, resp_obj):
if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerConfigDriveTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
self._add_config_drive(req, [server])
@ -63,7 +47,7 @@ class Controller(servers.Controller):
def detail(self, req, resp_obj):
context = req.environ['nova.context']
if 'servers' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ServersConfigDriveTemplate())
resp_obj.attach()
servers = resp_obj.obj['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 wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _
ALIAS = 'OS-DCF'
@ -43,21 +42,6 @@ def disk_config_from_api(value):
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):
def _add_disk_config(self, context, images):
for image in images:
@ -71,7 +55,7 @@ class ImageDiskConfigController(wsgi.Controller):
def show(self, req, resp_obj, id):
context = req.environ['nova.context']
if 'image' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImageDiskConfigTemplate())
resp_obj.attach()
image = resp_obj.obj['image']
self._add_disk_config(context, [image])
@ -79,26 +63,11 @@ class ImageDiskConfigController(wsgi.Controller):
def detail(self, req, resp_obj):
context = req.environ['nova.context']
if 'images' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ImagesDiskConfigTemplate())
resp_obj.attach()
images = resp_obj.obj['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):
def _add_disk_config(self, req, servers):
for server in servers:
@ -110,7 +79,7 @@ class ServerDiskConfigController(wsgi.Controller):
def _show(self, req, resp_obj):
if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerDiskConfigTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
self._add_disk_config(req, [server])
@ -124,7 +93,7 @@ class ServerDiskConfigController(wsgi.Controller):
def detail(self, req, resp_obj):
context = req.environ['nova.context']
if 'servers' in resp_obj.obj and authorize(context):
resp_obj.attach(xml=ServersDiskConfigTemplate())
resp_obj.attach()
servers = resp_obj.obj['servers']
self._add_disk_config(req, servers)

View File

@ -17,7 +17,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import availability_zones as avail_zone
authorize = extensions.soft_extension_authorizer('compute',
@ -39,7 +38,7 @@ class ExtendedAZController(wsgi.Controller):
def show(self, req, resp_obj, id):
context = req.environ['nova.context']
if authorize(context):
resp_obj.attach(xml=ExtendedAZTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
self._extend_server(context, server, db_instance)
@ -48,7 +47,7 @@ class ExtendedAZController(wsgi.Controller):
def detail(self, req, resp_obj):
context = req.environ['nova.context']
if authorize(context):
resp_obj.attach(xml=ExtendedAZsTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -67,28 +66,4 @@ class Extended_availability_zone(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ExtendedAZController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -17,10 +17,8 @@
import itertools
from nova.api.openstack import common
from nova.api.openstack.compute import ips
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
authorize = extensions.soft_extension_authorizer('compute', 'extended_ips')
@ -48,7 +46,7 @@ class ExtendedIpsController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsServerTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -60,7 +58,7 @@ class ExtendedIpsController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsServersTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -81,29 +79,4 @@ class Extended_ips(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ExtendedIpsController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -17,10 +17,8 @@
import itertools
from nova.api.openstack import common
from nova.api.openstack.compute import ips
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'extended_ips_mac')
@ -46,7 +44,7 @@ class ExtendedIpsMacController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsMacServerTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -58,7 +56,7 @@ class ExtendedIpsMacController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedIpsMacServersTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -79,28 +77,4 @@ class Extended_ips_mac(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ExtendedIpsMacController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute',
'extended_server_attributes')
@ -40,7 +39,7 @@ class ExtendedServerAttributesController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedServerAttributeTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -52,7 +51,7 @@ class ExtendedServerAttributesController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedServerAttributesTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
@ -74,32 +73,4 @@ class Extended_server_attributes(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ExtendedServerAttributesController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'extended_status')
@ -35,7 +34,7 @@ class ExtendedStatusController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedStatusTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -47,7 +46,7 @@ class ExtendedStatusController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedStatusesTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -68,30 +67,4 @@ class Extended_status(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ExtendedStatusController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -15,29 +15,11 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import network
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):
def __init__(self):
super(ExtendedServerVIFNetController, self).__init__()
@ -49,7 +31,7 @@ class ExtendedServerVIFNetController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVirtualInterfaceNetTemplate())
resp_obj.attach()
for vif in resp_obj.obj['virtual_interfaces']:
vif1 = self.network_api.get_vif_by_mac_address(context,
vif['mac_address'])

View File

@ -16,7 +16,6 @@
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 objects
@ -40,7 +39,7 @@ class ExtendedVolumesController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVolumesServerTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -52,7 +51,7 @@ class ExtendedVolumesController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedVolumesServersTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -76,28 +75,4 @@ class Extended_volumes(extensions.ExtensionDescriptor):
return [extension]
def get_resources(self):
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})
return []

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova import objects
@ -30,44 +29,6 @@ soft_authorize = extensions.soft_extension_authorizer('compute',
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):
rval = []
for project_id in flavor.projects:
@ -83,7 +44,6 @@ class FlavorAccessController(object):
def __init__(self):
super(FlavorAccessController, self).__init__()
@wsgi.serializers(xml=FlavorAccessTemplate)
def index(self, req, flavor_id):
context = req.environ['nova.context']
authorize(context)
@ -128,7 +88,7 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context']
if soft_authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=FlavorTemplate())
resp_obj.attach()
db_flavor = req.get_db_flavor(id)
self._extend_flavor(resp_obj.obj['flavor'], db_flavor)
@ -138,7 +98,7 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context']
if soft_authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=FlavorsTemplate())
resp_obj.attach()
flavors = list(resp_obj.obj['flavors'])
for flavor_rval in flavors:
@ -150,13 +110,12 @@ class FlavorActionController(wsgi.Controller):
context = req.environ['nova.context']
if soft_authorize(context):
# 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'])
self._extend_flavor(resp_obj.obj['flavor'], db_flavor)
@wsgi.serializers(xml=FlavorAccessTemplate)
@wsgi.action("addTenantAccess")
def _addTenantAccess(self, req, id, body):
context = req.environ['nova.context']
@ -180,7 +139,6 @@ class FlavorActionController(wsgi.Controller):
return _marshall_flavor_access(flavor)
@wsgi.serializers(xml=FlavorAccessTemplate)
@wsgi.action("removeTenantAccess")
def _removeTenantAccess(self, req, id, body):
context = req.environ['nova.context']

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_disabled')
@ -33,7 +32,7 @@ class FlavorDisabledController(wsgi.Controller):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorDisabledTemplate())
resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
@ -48,7 +47,7 @@ class FlavorDisabledController(wsgi.Controller):
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorsDisabledTemplate())
resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -64,26 +63,4 @@ class Flavor_disabled(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = FlavorDisabledController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
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})
return [extension]

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_rxtx')
@ -33,7 +32,7 @@ class FlavorRxtxController(wsgi.Controller):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorRxtxTemplate())
resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
@ -48,7 +47,7 @@ class FlavorRxtxController(wsgi.Controller):
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorsRxtxTemplate())
resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -64,24 +63,4 @@ class Flavor_rxtx(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = FlavorRxtxController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
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)
return [extension]

View File

@ -16,7 +16,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavor_swap')
@ -33,7 +32,7 @@ class FlavorSwapController(wsgi.Controller):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorSwapTemplate())
resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
@ -48,7 +47,7 @@ class FlavorSwapController(wsgi.Controller):
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorsSwapTemplate())
resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -64,24 +63,4 @@ class Flavor_swap(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = FlavorSwapController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
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)
return [extension]

View File

@ -24,7 +24,6 @@ attributes. This extension adds to that list:
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
authorize = extensions.soft_extension_authorizer('compute', 'flavorextradata')
@ -41,7 +40,7 @@ class FlavorextradataController(wsgi.Controller):
if not authorize(req.environ['nova.context']):
return
if 'flavor' in resp_obj.obj:
resp_obj.attach(xml=FlavorextradatumTemplate())
resp_obj.attach()
self._extend_flavors(req, [resp_obj.obj['flavor']])
@wsgi.extends
@ -56,7 +55,7 @@ class FlavorextradataController(wsgi.Controller):
def detail(self, req, resp_obj):
if not authorize(req.environ['nova.context']):
return
resp_obj.attach(xml=FlavorextradataTemplate())
resp_obj.attach()
self._extend_flavors(req, list(resp_obj.obj['flavors']))
@ -72,28 +71,4 @@ class Flavorextradata(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = FlavorextradataController()
extension = extensions.ControllerExtension(self, 'flavors', controller)
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})
return [extension]

View File

@ -19,8 +19,6 @@ import six
from webob import exc
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 import exception
from nova.i18n import _
@ -30,21 +28,6 @@ from nova import utils
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):
"""The flavor extra specs API controller for the OpenStack API."""
@ -85,14 +68,12 @@ class FlavorExtraSpecsController(object):
except exception.InvalidInput as error:
raise exc.HTTPBadRequest(explanation=error.format_message())
@wsgi.serializers(xml=ExtraSpecsTemplate)
def index(self, req, flavor_id):
"""Returns the list of extra specs for a given flavor."""
context = req.environ['nova.context']
authorize(context, action='index')
return self._get_extra_specs(context, flavor_id)
@wsgi.serializers(xml=ExtraSpecsTemplate)
def create(self, req, flavor_id, body):
context = req.environ['nova.context']
authorize(context, action='create')
@ -109,7 +90,6 @@ class FlavorExtraSpecsController(object):
raise exc.HTTPNotFound(explanation=error.format_message())
return body
@wsgi.serializers(xml=ExtraSpecTemplate)
def update(self, req, flavor_id, id, body):
context = req.environ['nova.context']
authorize(context, action='update')
@ -130,7 +110,6 @@ class FlavorExtraSpecsController(object):
raise exc.HTTPNotFound(explanation=error.format_message())
return body
@wsgi.serializers(xml=ExtraSpecTemplate)
def show(self, req, flavor_id, id):
"""Return a single extra spec item."""
context = req.environ['nova.context']

View File

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

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova import network
@ -28,55 +27,6 @@ from nova import network
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):
result = {}
result['ip'] = dns_entry.get('ip')
@ -133,7 +83,6 @@ class FloatingIPDNSDomainController(object):
self.network_api = network.API()
super(FloatingIPDNSDomainController, self).__init__()
@wsgi.serializers(xml=DomainsTemplate)
def index(self, req):
"""Return a list of available DNS domains."""
context = req.environ['nova.context']
@ -152,7 +101,6 @@ class FloatingIPDNSDomainController(object):
return _translate_domain_entries_view(domainlist)
@wsgi.serializers(xml=DomainTemplate)
def update(self, req, id, body):
"""Add or modify domain entry."""
context = req.environ['nova.context']
@ -211,7 +159,6 @@ class FloatingIPDNSEntryController(object):
self.network_api = network.API()
super(FloatingIPDNSEntryController, self).__init__()
@wsgi.serializers(xml=FloatingIPDNSTemplate)
def show(self, req, domain_id, id):
"""Return the DNS entry that corresponds to domain_id and id."""
context = req.environ['nova.context']
@ -242,13 +189,11 @@ class FloatingIPDNSEntryController(object):
entrylist = [_create_dns_entry(floating_ip, entry, domain)
for entry in entries]
dns_entries = _translate_dns_entries_view(entrylist)
return wsgi.ResponseObject(dns_entries,
xml=FloatingIPDNSsTemplate)
return wsgi.ResponseObject(dns_entries)
entry = _create_dns_entry(entries[0], id, domain)
return _translate_dns_entry_view(entry)
@wsgi.serializers(xml=FloatingIPDNSTemplate)
def update(self, req, domain_id, id, body):
"""Add or modify dns entry."""
context = req.environ['nova.context']

View File

@ -13,8 +13,6 @@
# under the License.
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
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):
"""The Floating IP Pool API controller for the OpenStack API."""
@ -62,7 +39,6 @@ class FloatingIPPoolsController(object):
self.network_api = network.API()
super(FloatingIPPoolsController, self).__init__()
@wsgi.serializers(xml=FloatingIPPoolsTemplate)
def index(self, req):
"""Return a list of pools."""
context = req.environ['nova.context']

View File

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

View File

@ -18,8 +18,6 @@
import webob.exc
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 exception
from nova.i18n import _
@ -29,72 +27,12 @@ LOG = logging.getLogger(__name__)
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):
"""The Hosts API controller for the OpenStack API."""
def __init__(self):
self.api = compute.HostAPI()
super(HostController, self).__init__()
@wsgi.serializers(xml=HostIndexTemplate)
def index(self, req):
"""Returns a dict in the format:
@ -148,8 +86,6 @@ class HostController(object):
'zone': service['availability_zone']})
return {'hosts': hosts}
@wsgi.serializers(xml=HostUpdateTemplate)
@wsgi.deserializers(xml=HostUpdateDeserializer)
def update(self, req, id, body):
"""Updates a specified body.
@ -261,15 +197,12 @@ class HostController(object):
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
return {"host": host_name, "power_action": result}
@wsgi.serializers(xml=HostActionTemplate)
def startup(self, req, id):
return self._host_power_action(req, host_name=id, action="startup")
@wsgi.serializers(xml=HostActionTemplate)
def shutdown(self, req, id):
return self._host_power_action(req, host_name=id, action="shutdown")
@wsgi.serializers(xml=HostActionTemplate)
def reboot(self, req, id):
return self._host_power_action(req, host_name=id, action="reboot")
@ -322,7 +255,6 @@ class HostController(object):
instance['ephemeral_gb'])
return project_map
@wsgi.serializers(xml=HostShowTemplate)
def show(self, req, id):
"""Shows the physical/usage resource given by hosts.

View File

@ -18,8 +18,6 @@
import webob.exc
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 exception
from nova.i18n import _
@ -29,104 +27,6 @@ from nova import servicegroup
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):
"""The Hypervisors API controller for the OpenStack API."""
@ -179,7 +79,6 @@ class HypervisorsController(object):
return hyp_dict
@wsgi.serializers(xml=HypervisorIndexTemplate)
def index(self, req):
context = req.environ['nova.context']
authorize(context)
@ -188,7 +87,6 @@ class HypervisorsController(object):
return dict(hypervisors=[self._view_hypervisor(hyp, False)
for hyp in compute_nodes])
@wsgi.serializers(xml=HypervisorDetailTemplate)
def detail(self, req):
context = req.environ['nova.context']
authorize(context)
@ -197,7 +95,6 @@ class HypervisorsController(object):
return dict(hypervisors=[self._view_hypervisor(hyp, True)
for hyp in compute_nodes])
@wsgi.serializers(xml=HypervisorTemplate)
def show(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -209,7 +106,6 @@ class HypervisorsController(object):
raise webob.exc.HTTPNotFound(explanation=msg)
return dict(hypervisor=self._view_hypervisor(hyp, True))
@wsgi.serializers(xml=HypervisorUptimeTemplate)
def uptime(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -231,7 +127,6 @@ class HypervisorsController(object):
return dict(hypervisor=self._view_hypervisor(hyp, False,
uptime=uptime))
@wsgi.serializers(xml=HypervisorIndexTemplate)
def search(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -244,7 +139,6 @@ class HypervisorsController(object):
msg = _("No hypervisor matching '%s' could be found.") % id
raise webob.exc.HTTPNotFound(explanation=msg)
@wsgi.serializers(xml=HypervisorServersTemplate)
def servers(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -261,7 +155,6 @@ class HypervisorsController(object):
hypervisors.append(hyp)
return dict(hypervisors=hypervisors)
@wsgi.serializers(xml=HypervisorStatisticsTemplate)
def statistics(self, req):
context = req.environ['nova.context']
authorize(context)

View File

@ -15,32 +15,10 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
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):
def _extend_image(self, image, image_cache):
@ -52,7 +30,7 @@ class ImageSizeController(wsgi.Controller):
context = req.environ["nova.context"]
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ImageSizeTemplate())
resp_obj.attach()
image_resp = resp_obj.obj['image']
# image guaranteed to be in the cache due to the core API adding
# it in its 'show' method
@ -64,7 +42,7 @@ class ImageSizeController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ImagesSizeTemplate())
resp_obj.attach()
images_resp = list(resp_obj.obj['images'])
# images guaranteed to be in the cache due to the core API adding
# 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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import 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']
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):
def __init__(self):
@ -81,7 +49,6 @@ class InstanceActionsController(wsgi.Controller):
event[key] = event_raw.get(key)
return event
@wsgi.serializers(xml=InstanceActionsTemplate)
def index(self, req, server_id):
"""Returns the list of actions recorded for a given instance."""
context = req.environ["nova.context"]
@ -91,7 +58,6 @@ class InstanceActionsController(wsgi.Controller):
actions = [self._format_action(action) for action in actions_raw]
return {'instanceActions': actions}
@wsgi.serializers(xml=InstanceActionTemplate)
def show(self, req, server_id, id):
"""Return data about the given instance action."""
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 import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import api as compute_api
from nova import exception
from nova.i18n import _
@ -31,21 +30,6 @@ authorize = extensions.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):
"""Keypair API controller for the OpenStack API."""
@ -62,7 +46,6 @@ class KeypairController(object):
clean[attr] = keypair[attr]
return clean
@wsgi.serializers(xml=KeypairTemplate)
def create(self, req, body):
"""Create or import keypair.
@ -118,7 +101,6 @@ class KeypairController(object):
raise webob.exc.HTTPNotFound(explanation=exc.format_message())
return webob.Response(status_int=202)
@wsgi.serializers(xml=KeypairTemplate)
def show(self, req, id):
"""Return data for the given key name."""
context = req.environ['nova.context']
@ -130,7 +112,6 @@ class KeypairController(object):
raise webob.exc.HTTPNotFound(explanation=exc.format_message())
return {'keypair': keypair}
@wsgi.serializers(xml=KeypairsTemplate)
def index(self, req):
"""List of keypairs for a user."""
context = req.environ['nova.context']
@ -143,21 +124,6 @@ class KeypairController(object):
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):
def _add_key_name(self, req, servers):
@ -169,7 +135,7 @@ class Controller(servers.Controller):
def _show(self, req, resp_obj):
if 'server' in resp_obj.obj:
resp_obj.attach(xml=ServerKeyNameTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
self._add_key_name(req, [server])
@ -183,7 +149,7 @@ class Controller(servers.Controller):
def detail(self, req, resp_obj):
context = req.environ['nova.context']
if 'servers' in resp_obj.obj and soft_authorize(context):
resp_obj.attach(xml=ServersKeyNameTemplate())
resp_obj.attach()
servers = resp_obj.obj['servers']
self._add_key_name(req, servers)

View File

@ -11,8 +11,6 @@
# under the License.
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova.objects import base as obj_base
@ -39,33 +37,11 @@ def output(migrations_obj):
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):
"""Controller for accessing migrations in OpenStack API."""
def __init__(self):
self.compute_api = compute.API()
@wsgi.serializers(xml=MigrationsTemplate)
def index(self, req):
"""Return all migrations in progress."""
context = req.environ['nova.context']

View File

@ -17,7 +17,6 @@ import webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.context
from nova import db
from nova import exception
@ -35,20 +34,6 @@ EXTENDED_QUOTAS = {'server_groups': 'os-server-group-quotas',
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):
supported_quotas = []
@ -74,7 +59,6 @@ class QuotaClassSetsController(wsgi.Controller):
return dict(quota_class_set=result)
@wsgi.serializers(xml=QuotaClassTemplate)
def show(self, req, id):
context = req.environ['nova.context']
authorize(context)
@ -85,7 +69,6 @@ class QuotaClassSetsController(wsgi.Controller):
except exception.Forbidden:
raise webob.exc.HTTPForbidden()
@wsgi.serializers(xml=QuotaClassTemplate)
def update(self, req, id, body):
context = req.environ['nova.context']
authorize(context)

View File

@ -19,7 +19,6 @@ import webob
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.context
from nova import exception
from nova.i18n import _
@ -40,19 +39,6 @@ authorize_show = extensions.extension_authorizer('compute', 'quotas:show')
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):
supported_quotas = []
@ -113,7 +99,6 @@ class QuotaSetsController(wsgi.Controller):
else:
return dict((k, v['limit']) for k, v in values.items())
@wsgi.serializers(xml=QuotaTemplate)
def show(self, req, id):
context = req.environ['nova.context']
authorize_show(context)
@ -128,7 +113,6 @@ class QuotaSetsController(wsgi.Controller):
except exception.Forbidden:
raise webob.exc.HTTPForbidden()
@wsgi.serializers(xml=QuotaTemplate)
def update(self, req, id, body):
context = req.environ['nova.context']
authorize_update(context)
@ -206,7 +190,6 @@ class QuotaSetsController(wsgi.Controller):
values = self._get_quotas(context, id, user_id=user_id)
return self._format_quota_set(None, values)
@wsgi.serializers(xml=QuotaTemplate)
def defaults(self, req, id):
context = req.environ['nova.context']
authorize_show(context)

View File

@ -11,7 +11,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from xml.dom import minidom
import six
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 import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova.network.security_group import openstack_driver
@ -32,82 +30,12 @@ authorize = extensions.extension_authorizer('compute',
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):
def __init__(self):
self.security_group_api = (
openstack_driver.get_openstack_security_group_driver())
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
@wsgi.deserializers(xml=SecurityGroupDefaultRulesXMLDeserializer)
def create(self, req, body):
context = sg._authorize_context(req)
authorize(context)
@ -141,7 +69,6 @@ class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
return self.security_group_api.new_cidr_ingress_rule(
cidr, ip_protocol, from_port, to_port)
@wsgi.serializers(xml=SecurityGroupDefaultRuleTemplate)
def show(self, req, id):
context = sg._authorize_context(req)
authorize(context)
@ -174,7 +101,6 @@ class SecurityGroupDefaultRulesController(sg.SecurityGroupControllerBase):
return webob.Response(status_int=204)
@wsgi.serializers(xml=SecurityGroupDefaultRulesTemplate)
def index(self, 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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
from nova.i18n import _
@ -41,44 +40,6 @@ authorize = extensions.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):
context = req.environ['nova.context']
authorize(context)
@ -87,96 +48,6 @@ def _authorize_context(req):
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
def translate_exceptions():
"""Translate nova exceptions to http exceptions."""
@ -273,7 +144,6 @@ class SecurityGroupControllerBase(object):
class SecurityGroupController(SecurityGroupControllerBase):
"""The Security group API controller for the OpenStack API."""
@wsgi.serializers(xml=SecurityGroupTemplate)
def show(self, req, id):
"""Return data about the given security group."""
context = _authorize_context(req)
@ -298,7 +168,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
return webob.Response(status_int=202)
@wsgi.serializers(xml=SecurityGroupsTemplate)
def index(self, req):
"""Returns a list of security groups."""
context = _authorize_context(req)
@ -320,8 +189,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
list(sorted(result,
key=lambda k: (k['tenant_id'], k['name'])))}
@wsgi.serializers(xml=SecurityGroupTemplate)
@wsgi.deserializers(xml=SecurityGroupXMLDeserializer)
def create(self, req, body):
"""Creates a new security group."""
context = _authorize_context(req)
@ -341,7 +208,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
return {'security_group': self._format_security_group(context,
group_ref)}
@wsgi.serializers(xml=SecurityGroupTemplate)
def update(self, req, id, body):
"""Update a security group."""
context = _authorize_context(req)
@ -368,8 +234,6 @@ class SecurityGroupController(SecurityGroupControllerBase):
class SecurityGroupRulesController(SecurityGroupControllerBase):
@wsgi.serializers(xml=SecurityGroupRuleTemplate)
@wsgi.deserializers(xml=SecurityGroupRulesXMLDeserializer)
def create(self, req, body):
context = _authorize_context(req)
@ -455,7 +319,6 @@ class SecurityGroupRulesController(SecurityGroupControllerBase):
class ServerSecurityGroupController(SecurityGroupControllerBase):
@wsgi.serializers(xml=SecurityGroupsTemplate)
def index(self, req, server_id):
"""Returns a list of security groups for the given instance."""
context = _authorize_context(req)
@ -592,7 +455,7 @@ class SecurityGroupsOutputController(wsgi.Controller):
if not softauth(req.environ['nova.context']):
return
if 'server' in resp_obj.obj:
resp_obj.attach(xml=SecurityGroupServerTemplate())
resp_obj.attach()
self._extend_servers(req, [resp_obj.obj['server']])
@wsgi.extends
@ -607,38 +470,10 @@ class SecurityGroupsOutputController(wsgi.Controller):
def detail(self, req, resp_obj):
if not softauth(req.environ['nova.context']):
return
resp_obj.attach(xml=SecurityGroupServersTemplate())
resp_obj.attach()
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):
"""Security group support."""
name = "SecurityGroups"

View File

@ -18,7 +18,6 @@ import webob.exc
from nova.api.openstack import common
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 exception
from nova.i18n import _
@ -28,20 +27,10 @@ authorize = extensions.extension_authorizer('compute', 'server_diagnostics')
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):
def __init__(self):
self.compute_api = compute.API()
@wsgi.serializers(xml=ServerDiagnosticsTemplate)
def index(self, req, server_id):
context = req.environ["nova.context"]
authorize(context)

View File

@ -16,7 +16,6 @@ import webob
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 exception
from nova.i18n import _
@ -30,41 +29,12 @@ authorize = extensions.extension_authorizer('compute',
'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):
def __init__(self):
self.compute_api = compute.API()
super(ServerExternalEventsController, self).__init__()
@wsgi.deserializers(xml=EventDeserializer)
@wsgi.serializers(xml=EventTemplate)
def create(self, req, body):
"""Creates a new instance event."""
context = req.environ['nova.context']

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import quota
QUOTAS = quota.QUOTAS
@ -39,27 +38,17 @@ class ExtendedQuotaSetsController(wsgi.Controller):
@wsgi.extends
def show(self, req, id, resp_obj):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate())
resp_obj.attach()
@wsgi.extends
def update(self, req, id, body, resp_obj):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate())
resp_obj.attach()
@wsgi.extends
def defaults(self, req, id, resp_obj):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaSetsTemplate())
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)
resp_obj.attach()
class ExtendedQuotaClassSetsController(wsgi.Controller):
@ -67,23 +56,12 @@ class ExtendedQuotaClassSetsController(wsgi.Controller):
@wsgi.extends
def show(self, req, id, resp_obj):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaClassSetsTemplate())
resp_obj.attach()
@wsgi.extends
def update(self, req, id, body, resp_obj):
# Attach our slave template to the response object
resp_obj.attach(xml=ExtendedQuotaClassSetsTemplate())
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)
resp_obj.attach()
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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
import nova.exception
from nova.i18n import _
from nova.i18n import _LE
@ -37,29 +36,7 @@ SUPPORTED_POLICIES = ['anti-affinity', 'affinity']
authorize = extensions.extension_authorizer('compute', 'server_groups')
def make_policy(elem):
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}
server_group_nsmap = {}
def _authorize_context(req):
@ -68,65 +45,6 @@ def _authorize_context(req):
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):
"""The Server group API controller for the OpenStack API."""
@ -210,7 +128,6 @@ class ServerGroupController(wsgi.Controller):
msg = _("unsupported fields: %s") % subbody.keys()
raise nova.exception.InvalidInput(reason=msg)
@wsgi.serializers(xml=ServerGroupTemplate)
def show(self, req, id):
"""Return data about the given server group."""
context = _authorize_context(req)
@ -255,7 +172,6 @@ class ServerGroupController(wsgi.Controller):
return webob.Response(status_int=204)
@wsgi.serializers(xml=ServerGroupsTemplate)
def index(self, req):
"""Returns a list of server groups."""
context = _authorize_context(req)
@ -270,8 +186,6 @@ class ServerGroupController(wsgi.Controller):
for group in limited_list]
return {'server_groups': result}
@wsgi.serializers(xml=ServerGroupTemplate)
@wsgi.deserializers(xml=ServerGroupXMLDeserializer)
def create(self, req, body):
"""Creates a new server group."""
context = _authorize_context(req)
@ -310,11 +224,6 @@ class ServerGroupController(wsgi.Controller):
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):
"""Server group support."""
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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
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):
"""The Server Password API controller for the OpenStack API."""
def __init__(self):
self.compute_api = compute.API()
@wsgi.serializers(xml=ServerPasswordTemplate)
def index(self, req, server_id):
context = req.environ['nova.context']
authorize(context)

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova.openstack.common import log as logging
@ -42,7 +41,7 @@ class ServerUsageController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ServerUsageTemplate())
resp_obj.attach()
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
@ -54,7 +53,7 @@ class ServerUsageController(wsgi.Controller):
context = req.environ['nova.context']
if authorize(context):
# Attach our slave template to the response object
resp_obj.attach(xml=ServerUsagesTemplate())
resp_obj.attach()
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
@ -75,28 +74,4 @@ class Server_usage(extensions.ExtensionDescriptor):
def get_controller_extensions(self):
controller = ServerUsageController()
extension = extensions.ControllerExtension(self, 'servers', controller)
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})
return [extension]

View File

@ -16,7 +16,6 @@ import webob.exc
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 exception
from nova.i18n import _
@ -26,48 +25,6 @@ from nova import utils
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):
def __init__(self, ext_mgr=None, *args, **kwargs):
@ -143,7 +100,6 @@ class ServiceController(object):
explanation = _("Service %s not found.") % id
raise webob.exc.HTTPNotFound(explanation=explanation)
@wsgi.serializers(xml=ServicesIndexTemplate)
def index(self, req):
"""Return a list of all running services."""
detailed = self.ext_mgr.is_loaded('os-extended-services')
@ -151,8 +107,6 @@ class ServiceController(object):
return {'services': services}
@wsgi.deserializers(xml=ServiceUpdateDeserializer)
@wsgi.serializers(xml=ServiceUpdateTemplate)
def update(self, req, id, body):
"""Enable/Disable scheduling for a service."""
context = req.environ['nova.context']

View File

@ -22,8 +22,6 @@ import six.moves.urllib.parse as urlparse
from webob import exc
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova import objects
@ -34,23 +32,6 @@ authorize_list = extensions.extension_authorizer('compute',
'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):
try:
return timeutils.parse_strtime(dstr, fmt)
@ -58,22 +39,6 @@ def parse_strtime(dstr, fmt):
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):
def _hours_for(self, instance, period_start, period_stop):
launched_at = instance.launched_at
@ -254,7 +219,6 @@ class SimpleTenantUsageController(object):
detailed = env.get('detailed', ['0'])[0] == '1'
return (period_start, period_stop, detailed)
@wsgi.serializers(xml=SimpleTenantUsagesTemplate)
def index(self, req):
"""Retrieve tenant_usage for all tenants."""
context = req.environ['nova.context']
@ -276,7 +240,6 @@ class SimpleTenantUsageController(object):
detailed=detailed)
return {'tenant_usages': usages}
@wsgi.serializers(xml=SimpleTenantUsageTemplate)
def show(self, req, id):
"""Retrieve tenant_usage for a specified tenant."""
tenant_id = id

View File

@ -14,7 +14,6 @@
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import quota
@ -28,13 +27,6 @@ authorize_for_admin = extensions.extension_authorizer('compute',
'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):
def __init__(self, ext_mgr):
@ -49,7 +41,7 @@ class UsedLimitsController(wsgi.Controller):
@wsgi.extends
def index(self, req, resp_obj):
resp_obj.attach(xml=UsedLimitsTemplate())
resp_obj.attach()
context = req.environ['nova.context']
project_id = self._project_id(context, req)
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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova import network
@ -29,16 +28,6 @@ authorize = extensions.extension_authorizer('compute', 'virtual_interfaces')
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):
"""Maps keys for VIF summary view."""
d = {}
@ -67,7 +56,6 @@ class ServerVirtualInterfaceController(object):
res = [entity_maker(context, vif) for vif in limited_list]
return {'virtual_interfaces': res}
@wsgi.serializers(xml=VirtualInterfaceTemplate)
def index(self, req, server_id):
"""Returns the list of VIFs for a given instance."""
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 extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
from nova import exception
from nova.i18n import _
@ -84,82 +83,6 @@ def _translate_volume_summary_view(context, vol):
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):
"""The Volumes API controller for the OpenStack API."""
@ -167,7 +90,6 @@ class VolumeController(wsgi.Controller):
self.volume_api = volume.API()
super(VolumeController, self).__init__()
@wsgi.serializers(xml=VolumeTemplate)
def show(self, req, id):
"""Return data about the given volume."""
context = req.environ['nova.context']
@ -193,12 +115,10 @@ class VolumeController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.serializers(xml=VolumesTemplate)
def index(self, req):
"""Returns a summary list of volumes."""
return self._items(req, entity_maker=_translate_volume_summary_view)
@wsgi.serializers(xml=VolumesTemplate)
def detail(self, req):
"""Returns a detailed list of volumes."""
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]
return {'volumes': res}
@wsgi.serializers(xml=VolumeTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body):
"""Creates a new volume."""
context = req.environ['nova.context']
@ -297,30 +215,6 @@ def _translate_attachment_summary_view(volume_id, instance_uuid, mountpoint):
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):
"""The volume attachment API controller for the OpenStack API.
@ -335,7 +229,6 @@ class VolumeAttachmentController(wsgi.Controller):
self.ext_mgr = ext_mgr
super(VolumeAttachmentController, self).__init__()
@wsgi.serializers(xml=VolumeAttachmentsTemplate)
def index(self, req, server_id):
"""Returns the list of volume attachments for a given instance."""
context = req.environ['nova.context']
@ -343,7 +236,6 @@ class VolumeAttachmentController(wsgi.Controller):
return self._items(req, server_id,
entity_maker=_translate_attachment_summary_view)
@wsgi.serializers(xml=VolumeAttachmentTemplate)
def show(self, req, server_id, id):
"""Return data about the given volume attachment."""
context = req.environ['nova.context']
@ -381,7 +273,6 @@ class VolumeAttachmentController(wsgi.Controller):
"not in proper format (%s)") % volume_id
raise exc.HTTPBadRequest(explanation=msg)
@wsgi.serializers(xml=VolumeAttachmentTemplate)
def create(self, req, server_id, body):
"""Attach a volume to an instance."""
context = req.environ['nova.context']
@ -585,32 +476,6 @@ def _translate_snapshot_summary_view(context, vol):
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):
"""The Snapshots API controller for the OpenStack API."""
@ -618,7 +483,6 @@ class SnapshotController(wsgi.Controller):
self.volume_api = volume.API()
super(SnapshotController, self).__init__()
@wsgi.serializers(xml=SnapshotTemplate)
def show(self, req, id):
"""Return data about the given snapshot."""
context = req.environ['nova.context']
@ -644,12 +508,10 @@ class SnapshotController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.serializers(xml=SnapshotsTemplate)
def index(self, req):
"""Returns a summary list of snapshots."""
return self._items(req, entity_maker=_translate_snapshot_summary_view)
@wsgi.serializers(xml=SnapshotsTemplate)
def detail(self, req):
"""Returns a detailed list of snapshots."""
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]
return {'snapshots': res}
@wsgi.serializers(xml=SnapshotTemplate)
def create(self, req, body):
"""Creates a new snapshot."""
context = req.environ['nova.context']

View File

@ -19,48 +19,13 @@ import webob
from nova.api.openstack import common
from nova.api.openstack.compute.views import flavors as flavors_view
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.compute import flavors
from nova import exception
from nova.i18n import _
from nova import utils
def make_flavor(elem, detailed=False):
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)
flavor_nsmap = {}
class Controller(wsgi.Controller):
@ -68,20 +33,17 @@ class Controller(wsgi.Controller):
_view_builder_class = flavors_view.ViewBuilder
@wsgi.serializers(xml=MinimalFlavorsTemplate)
def index(self, req):
"""Return all flavors in brief."""
limited_flavors = self._get_flavors(req)
return self._view_builder.index(req, limited_flavors)
@wsgi.serializers(xml=FlavorsTemplate)
def detail(self, req):
"""Return all flavors in detail."""
limited_flavors = self._get_flavors(req)
req.cache_db_flavors(limited_flavors)
return self._view_builder.detail(req, limited_flavors)
@wsgi.serializers(xml=FlavorTemplate)
def show(self, req, id):
"""Return data about the given flavor id."""
try:

View File

@ -37,14 +37,12 @@ class Controller(object):
msg = _("Image not found.")
raise exc.HTTPNotFound(explanation=msg)
@wsgi.serializers(xml=common.MetadataTemplate)
def index(self, req, image_id):
"""Returns the list of metadata for a given instance."""
context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties']
return dict(metadata=metadata)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, image_id, id):
context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties']
@ -53,8 +51,6 @@ class Controller(object):
else:
raise exc.HTTPNotFound()
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def create(self, req, image_id, body):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
@ -70,8 +66,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(metadata=image['properties'])
@wsgi.serializers(xml=common.MetaItemTemplate)
@wsgi.deserializers(xml=common.MetaItemDeserializer)
def update(self, req, image_id, id, body):
context = req.environ['nova.context']
@ -99,8 +93,6 @@ class Controller(object):
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(meta=meta)
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def update_all(self, req, image_id, body):
context = req.environ['nova.context']
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.compute.views import images as views_images
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
import nova.image
@ -36,52 +35,7 @@ SUPPORTED_FILTERS = {
}
def make_image(elem, detailed=False):
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)
image_nsmap = {}
class Controller(wsgi.Controller):
@ -120,7 +74,6 @@ class Controller(wsgi.Controller):
return filters
@wsgi.serializers(xml=ImageTemplate)
def show(self, req, id):
"""Return detailed information about a specific image.
@ -157,7 +110,6 @@ class Controller(wsgi.Controller):
raise webob.exc.HTTPForbidden(explanation=explanation)
return webob.exc.HTTPNoContent()
@wsgi.serializers(xml=MinimalImagesTemplate)
def index(self, req):
"""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())
return self._view_builder.index(req, images)
@wsgi.serializers(xml=ImagesTemplate)
def detail(self, req):
"""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.compute.views import addresses as view_addresses
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _
def make_network(elem):
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)
network_nsmap = {}
class Controller(wsgi.Controller):
@ -60,14 +34,12 @@ class Controller(wsgi.Controller):
super(Controller, self).__init__(**kwargs)
self._compute_api = nova.compute.API()
@wsgi.serializers(xml=AddressesTemplate)
def index(self, req, server_id):
context = req.environ["nova.context"]
instance = common.get_instance(self._compute_api, context, server_id)
networks = common.get_networks_for_instance(context, instance)
return self._view_builder.index(networks)
@wsgi.serializers(xml=NetworkTemplate)
def show(self, req, server_id, id):
context = req.environ["nova.context"]
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 import wsgi
from nova.api.openstack import xmlutil
from nova.i18n import _
from nova import quota
from nova import utils
@ -56,38 +55,12 @@ QUOTAS = quota.QUOTAS
LIMITS_PREFIX = "limits."
limits_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM}
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)
limits_nsmap = {}
class LimitsController(object):
"""Controller for accessing limits in the OpenStack API."""
@wsgi.serializers(xml=LimitsTemplate)
def index(self, req):
"""Return all global and rate limit information."""
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')
def _interface_dict(interface_ref):
d = {}
for f in interface_fields:
d[f] = interface_ref.get(f)
return d
def _get_ironic_client():
"""return an Ironic client."""
# 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
return meta_dict
@wsgi.serializers(xml=common.MetadataTemplate)
def index(self, req, server_id):
"""Returns the list of metadata for a given instance."""
context = req.environ['nova.context']
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):
try:
metadata = body['metadata']
@ -69,8 +66,6 @@ class Controller(object):
return {'metadata': new_metadata}
@wsgi.serializers(xml=common.MetaItemTemplate)
@wsgi.deserializers(xml=common.MetaItemDeserializer)
def update(self, req, server_id, id, body):
try:
meta_item = body['meta']
@ -98,8 +93,6 @@ class Controller(object):
return {'meta': meta_item}
@wsgi.serializers(xml=common.MetadataTemplate)
@wsgi.deserializers(xml=common.MetadataDeserializer)
def update_all(self, req, server_id, body):
try:
metadata = body['metadata']
@ -154,7 +147,6 @@ class Controller(object):
common.raise_http_conflict_for_instance_invalid_state(state_error,
'update metadata', server_id)
@wsgi.serializers(xml=common.MetaItemTemplate)
def show(self, req, server_id, id):
"""Return a single metadata item."""
context = req.environ['nova.context']

View File

@ -28,16 +28,13 @@ import webob
from webob import exc
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 import wsgi
from nova.api.openstack import xmlutil
from nova import block_device
from nova import compute
from nova.compute import flavors
from nova import exception
from nova.i18n import _
from nova.i18n import _LW
from nova import objects
from nova.openstack.common import log as logging
from nova.openstack.common import uuidutils
@ -64,421 +61,7 @@ LOG = logging.getLogger(__name__)
XML_WARNING = False
def make_fault(elem):
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}}
server_nsmap = {}
class Controller(wsgi.Controller):
@ -505,7 +88,6 @@ class Controller(wsgi.Controller):
self.compute_api = compute.API()
self.ext_mgr = ext_mgr
@wsgi.serializers(xml=MinimalServersTemplate)
def index(self, req):
"""Returns a list of server names and ids for a given user."""
try:
@ -514,7 +96,6 @@ class Controller(wsgi.Controller):
raise exc.HTTPBadRequest(explanation=err.format_message())
return servers
@wsgi.serializers(xml=ServersTemplate)
def detail(self, req):
"""Returns a list of server details for a given user."""
try:
@ -760,7 +341,6 @@ class Controller(wsgi.Controller):
expl = _('accessIPv6 is not proper IPv6 format')
raise exc.HTTPBadRequest(explanation=expl)
@wsgi.serializers(xml=ServerTemplate)
def show(self, req, id):
"""Returns server details by server id."""
context = req.environ['nova.context']
@ -768,8 +348,6 @@ class Controller(wsgi.Controller):
return self._view_builder.show(req, instance)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=CreateDeserializer)
def create(self, req, body):
"""Creates a new server for a given user."""
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 ret_resv_id:
return wsgi.ResponseObject({'reservation_id': resv_id},
xml=ServerMultipleCreateTemplate)
return wsgi.ResponseObject({'reservation_id': resv_id})
req.cache_db_instances(instances)
server = self._view_builder.create(req, instances[0])
@ -1039,7 +616,6 @@ class Controller(wsgi.Controller):
else:
self.compute_api.delete(context, instance)
@wsgi.serializers(xml=ServerTemplate)
def update(self, req, id, body):
"""Update server then pass on to version-specific controller."""
if not self.is_valid_body(body, 'server'):
@ -1093,8 +669,6 @@ class Controller(wsgi.Controller):
return self._view_builder.show(req, instance)
@wsgi.response(204)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('confirmResize')
def _action_confirm_resize(self, req, id, body):
context = req.environ['nova.context']
@ -1111,8 +685,6 @@ class Controller(wsgi.Controller):
'confirmResize', id)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('revertResize')
def _action_revert_resize(self, req, id, body):
context = req.environ['nova.context']
@ -1133,8 +705,6 @@ class Controller(wsgi.Controller):
return webob.Response(status_int=202)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('reboot')
def _action_reboot(self, req, id, body):
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)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('changePassword')
def _action_change_password(self, req, id, body):
context = req.environ['nova.context']
@ -1301,8 +869,6 @@ class Controller(wsgi.Controller):
raise exc.HTTPBadRequest(explanation=msg)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('resize')
def _action_resize(self, req, id, body):
"""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)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('rebuild')
def _action_rebuild(self, req, id, body):
"""Rebuild an instance with the given attributes."""
@ -1426,8 +990,6 @@ class Controller(wsgi.Controller):
return self._add_location(robj)
@wsgi.response(202)
@wsgi.serializers(xml=FullServerTemplate)
@wsgi.deserializers(xml=ActionDeserializer)
@wsgi.action('createImage')
@common.check_snapshots_enabled
def _action_create_image(self, req, id, body):

View File

@ -13,13 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
from lxml import etree
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 import wsgi
from nova.api.openstack import xmlutil
CONF = cfg.CONF
@ -48,10 +45,6 @@ VERSIONS = {
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2",
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2",
@ -79,142 +72,7 @@ VERSIONS = {
}
class MediaTypesTemplateElement(xmlutil.TemplateElement):
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)
version_nsmap = {}
class Versions(wsgi.Resource):
@ -223,14 +81,11 @@ class Versions(wsgi.Resource):
if not CONF.osapi_v3.enabled:
del VERSIONS["v2.1"]
@wsgi.serializers(xml=VersionsTemplate,
atom=VersionsAtomSerializer)
def index(self, req, body=None):
"""Return all versions."""
builder = views_versions.get_view_builder(req)
return builder.build_versions(VERSIONS)
@wsgi.serializers(xml=ChoicesTemplate)
@wsgi.response(300)
def multi(self, req, body=None):
"""Return multiple choices."""
@ -249,8 +104,6 @@ class Versions(wsgi.Resource):
class VersionV2(object):
@wsgi.serializers(xml=VersionTemplate,
atom=VersionAtomSerializer)
def show(self, req):
builder = views_versions.get_view_builder(req)
return builder.build_version(VERSIONS['v2.0'])

View File

@ -25,7 +25,6 @@ import webob.exc
import nova.api.openstack
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import exception
from nova.i18n import _
from nova.i18n import _LE
@ -95,42 +94,8 @@ class ExtensionDescriptor(object):
return nsmap
@classmethod
def xmlname(cls, name):
"""Synthesize element and attribute names."""
return '{%s}%s' % (cls.namespace, name)
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)
ext_nsmap = {}
class ExtensionsController(wsgi.Resource):
@ -149,14 +114,12 @@ class ExtensionsController(wsgi.Resource):
ext_data['links'] = [] # TODO(dprince): implement extension links
return ext_data
@wsgi.serializers(xml=ExtensionsTemplate)
def index(self, req):
extensions = []
for ext in self.extension_manager.sorted_extensions():
extensions.append(self._translate(ext))
return dict(extensions=extensions)
@wsgi.serializers(xml=ExtensionTemplate)
def show(self, req, id):
try:
# NOTE(dprince): the extensions alias is used as the 'id' for show

View File

@ -18,9 +18,7 @@ import functools
import inspect
import math
import time
from xml.dom import minidom
from lxml import etree
from oslo.serialization import jsonutils
from oslo.utils import strutils
import six
@ -28,7 +26,6 @@ import webob
from nova.api.openstack import api_version_request as api_version
from nova.api.openstack import versioned_method
from nova.api.openstack import xmlutil
from nova import exception
from nova import i18n
from nova.i18n import _
@ -42,8 +39,6 @@ from nova import wsgi
XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0'
XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1'
XMLNS_ATOM = 'http://www.w3.org/2005/Atom'
LOG = logging.getLogger(__name__)
_SUPPORTED_CONTENT_TYPES = (
@ -51,22 +46,11 @@ _SUPPORTED_CONTENT_TYPES = (
'application/vnd.openstack.compute+json',
)
_SUPPORTED_XML_CONTENT_TYPES = (
'application/xml',
'application/vnd.openstack.compute+xml',
)
_MEDIA_TYPE_MAP = {
'application/vnd.openstack.compute+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
# collection or member methods.
_ROUTES_METHODS = [
@ -94,21 +78,12 @@ VER_METHOD_ATTR = 'versioned_methods'
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():
if DISABLE_XML_V2_API:
return _SUPPORTED_CONTENT_TYPES
return _SUPPORTED_CONTENT_TYPES + _SUPPORTED_XML_CONTENT_TYPES
return _SUPPORTED_CONTENT_TYPES
def get_media_map():
if DISABLE_XML_V2_API:
return _MEDIA_TYPE_MAP
return dict(_MEDIA_TYPE_MAP.items() + _MEDIA_XML_TYPE_MAP.items())
return dict(_MEDIA_TYPE_MAP.items())
class Request(webob.Request):
@ -302,107 +277,6 @@ class JSONDeserializer(TextDeserializer):
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):
"""Default request body serialization."""
@ -420,76 +294,6 @@ class JSONDictSerializer(DictSerializer):
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):
"""Attaches serializers to a method.
@ -688,15 +492,6 @@ def action_peek_json(body):
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):
"""Context manager to handle Resource exceptions.
@ -767,16 +562,13 @@ class Resource(wsgi.Application):
self.controller = controller
default_deserializers = dict(xml=XMLDeserializer,
json=JSONDeserializer)
default_deserializers = dict(json=JSONDeserializer)
default_deserializers.update(deserializers)
self.default_deserializers = default_deserializers
self.default_serializers = dict(xml=XMLDictSerializer,
json=JSONDictSerializer)
self.default_serializers = dict(json=JSONDictSerializer)
self.action_peek = dict(xml=action_peek_xml,
json=action_peek_json)
self.action_peek = dict(json=action_peek_json)
self.action_peek.update(action_peek or {})
# Copy over the actions dictionary
@ -1385,14 +1177,8 @@ class Fault(webob.exc.HTTPException):
self.wrapped_exc.headers['Vary'] = \
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()
serializer = {
'application/xml': xml_serializer,
'application/json': JSONDictSerializer(),
}[content_type]
@ -1435,16 +1221,13 @@ class RateLimitFault(webob.exc.HTTPException):
"""
user_locale = request.best_match_language()
content_type = request.best_match_content_type()
metadata = {"attributes": {"overLimit": ["code", "retryAfter"]}}
self.content['overLimit']['message'] = \
i18n.translate(self.content['overLimit']['message'], user_locale)
self.content['overLimit']['details'] = \
i18n.translate(self.content['overLimit']['details'], user_locale)
xml_serializer = XMLDictSerializer(metadata, XMLNS_V11)
serializer = {
'application/xml': xml_serializer,
'application/json': JSONDictSerializer(),
}[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 testtools
from nova.api.openstack import wsgi
from nova import context
from nova import db
from nova.network import manager as network_manager
@ -150,12 +149,6 @@ class skipIf(object):
'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 raise_for_invalid_assert_calls(wrapped):
def wrapper(_self, name):

View File

@ -16,16 +16,11 @@
import copy
import uuid as stdlib_uuid
import feedparser
from lxml import etree
from oslo.serialization import jsonutils
import webob
from nova.api.openstack.compute import versions
from nova.api.openstack.compute import views
from nova.api.openstack import xmlutil
from nova import test
from nova.tests.unit.api.openstack import common
from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import matchers
@ -59,10 +54,6 @@ EXP_VERSIONS = {
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2",
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2",
@ -161,11 +152,6 @@ class VersionsTestV20(test.NoDBTestCase):
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/"
"vnd.openstack.compute+xml;version=2",
},
{
"base": "application/json",
"type": "application/"
@ -189,131 +175,6 @@ class VersionsTestV20(test.NoDBTestCase):
res = req.get_response(fakes.wsgi_app())
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):
req = webob.Request.blank('/images/1')
req.accept = "application/json"
@ -333,11 +194,6 @@ class VersionsTestV20(test.NoDBTestCase):
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml"
";version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json"
@ -367,47 +223,6 @@ class VersionsTestV20(test.NoDBTestCase):
self.assertThat(jsonutils.loads(res.body),
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):
"""Make sure multi choice responses do not have content-type
application/atom+xml (should use default of json)
@ -438,11 +253,6 @@ class VersionsTestV20(test.NoDBTestCase):
},
],
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml"
";version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json"
@ -537,208 +347,6 @@ class VersionsViewBuilderTests(test.NoDBTestCase):
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).
# So this class tests "/v2.1" only for v2.1 API.
class VersionsTestV21(test.NoDBTestCase):