From 026efcd174cdb1b1d0fece9611dbae358de48387 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 24 Aug 2011 14:08:25 -0400 Subject: Updated FlavorsXMLSerialization tests to use etree and validation instead of minidom --- nova/api/openstack/schemas/v1.1/flavor.rng | 10 ++++++++++ nova/api/openstack/schemas/v1.1/flavors.rng | 6 ++++++ nova/api/openstack/schemas/v1.1/flavors_index.rng | 12 ++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 nova/api/openstack/schemas/v1.1/flavor.rng create mode 100644 nova/api/openstack/schemas/v1.1/flavors.rng create mode 100644 nova/api/openstack/schemas/v1.1/flavors_index.rng (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/flavor.rng b/nova/api/openstack/schemas/v1.1/flavor.rng new file mode 100644 index 000000000..a00e4e9ee --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/flavor.rng @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/nova/api/openstack/schemas/v1.1/flavors.rng b/nova/api/openstack/schemas/v1.1/flavors.rng new file mode 100644 index 000000000..b7a3acc01 --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/flavors.rng @@ -0,0 +1,6 @@ + + + + + diff --git a/nova/api/openstack/schemas/v1.1/flavors_index.rng b/nova/api/openstack/schemas/v1.1/flavors_index.rng new file mode 100644 index 000000000..d1a4fedb1 --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/flavors_index.rng @@ -0,0 +1,12 @@ + + + + + + + + + + + -- cgit From ba0bc2830e3a67617a0199a2a5079f5dfd3b22af Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 24 Aug 2011 15:07:57 -0400 Subject: Updated flavors xml serialization to use lxml instead of minidom --- nova/api/openstack/flavors.py | 70 ++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index fd36060da..f689aa7ab 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -16,12 +16,13 @@ # under the License. import webob -import xml.dom.minidom as minidom +from lxml import etree from nova import db from nova import exception from nova.api.openstack import views from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil class Controller(object): @@ -78,48 +79,49 @@ class ControllerV11(Controller): class FlavorXMLSerializer(wsgi.XMLDictSerializer): + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + def __init__(self): super(FlavorXMLSerializer, self).__init__(xmlns=wsgi.XMLNS_V11) - def _flavor_to_xml(self, xml_doc, flavor, detailed): - flavor_node = xml_doc.createElement('flavor') - flavor_node.setAttribute('id', str(flavor['id'])) - flavor_node.setAttribute('name', flavor['name']) + def _populate_flavor(self, flavor_elem, flavor_dict, detailed=False): + """Populate a flavor xml element from a dict.""" + flavor_elem.set('name', flavor_dict['name']) + flavor_elem.set('id', str(flavor_dict['id'])) if detailed: - flavor_node.setAttribute('ram', str(flavor['ram'])) - flavor_node.setAttribute('disk', str(flavor['disk'])) - - link_nodes = self._create_link_nodes(xml_doc, flavor['links']) - for link_node in link_nodes: - flavor_node.appendChild(link_node) - return flavor_node + flavor_elem.set('ram', str(flavor_dict['ram'])) + flavor_elem.set('disk', str(flavor_dict['disk'])) + for link in flavor_dict.get('links', []): + elem = etree.SubElement(flavor_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return flavor_elem - def _flavors_list_to_xml(self, xml_doc, flavors, detailed): - container_node = xml_doc.createElement('flavors') + def _to_xml(self, root): + """Convert the xml object to an xml string.""" - for flavor in flavors: - item_node = self._flavor_to_xml(xml_doc, flavor, detailed) - container_node.appendChild(item_node) - return container_node + return etree.tostring(root, encoding='UTF-8') def show(self, flavor_container): - xml_doc = minidom.Document() - flavor = flavor_container['flavor'] - node = self._flavor_to_xml(xml_doc, flavor, True) - return self.to_xml_string(node, True) - - def detail(self, flavors_container): - xml_doc = minidom.Document() - flavors = flavors_container['flavors'] - node = self._flavors_list_to_xml(xml_doc, flavors, True) - return self.to_xml_string(node, True) - - def index(self, flavors_container): - xml_doc = minidom.Document() - flavors = flavors_container['flavors'] - node = self._flavors_list_to_xml(xml_doc, flavors, False) - return self.to_xml_string(node, True) + flavor = etree.Element('flavor', nsmap=self.NSMAP) + self._populate_flavor(flavor, flavor_container['flavor'], True) + return self._to_xml(flavor) + + def detail(self, flavors_dict): + flavors = etree.Element('flavors', nsmap=self.NSMAP) + for flavor_dict in flavors_dict['flavors']: + flavor = etree.SubElement(flavors, 'flavor') + self._populate_flavor(flavor, flavor_dict, True) + return self._to_xml(flavors) + + def index(self, flavors_dict): + flavors = etree.Element('flavors', nsmap=self.NSMAP) + for flavor_dict in flavors_dict['flavors']: + flavor = etree.SubElement(flavors, 'flavor') + self._populate_flavor(flavor, flavor_dict, False) + return self._to_xml(flavors) def create_resource(version='1.0'): -- cgit From 08981ee7228aa0e4b68ec8e9016ef68b987a3ac3 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 24 Aug 2011 16:41:26 -0400 Subject: Updated ImageXMLSerialization tests to use etree instead of minidom Fixed incorrect server entity ids in tests --- nova/api/openstack/images.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 1c8fc10c9..59184d81a 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -230,9 +230,8 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): image_node.appendChild(server_node) metadata = image.get('metadata', {}).items() - if len(metadata) > 0: - metadata_node = self._create_metadata_node(xml_doc, metadata) - image_node.appendChild(metadata_node) + metadata_node = self._create_metadata_node(xml_doc, metadata) + image_node.appendChild(metadata_node) link_nodes = self._create_link_nodes(xml_doc, image['links']) -- cgit From f1ccdc547d083ffe4c5d03f26f2658d98bc21541 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 11:24:25 -0400 Subject: Updated ImagesXMLSerializer to use etree instead of minidom --- nova/api/openstack/images.py | 145 +++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 80 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 59184d81a..edd26c171 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -16,8 +16,8 @@ import urlparse import os.path +from lxml import etree import webob.exc -from xml.dom import minidom from nova import compute from nova import exception @@ -29,6 +29,7 @@ from nova.api.openstack import image_metadata from nova.api.openstack import servers from nova.api.openstack.views import images as images_view from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil LOG = log.getLogger('nova.api.openstack.images') @@ -206,92 +207,76 @@ class ControllerV11(Controller): class ImageXMLSerializer(wsgi.XMLDictSerializer): - xmlns = wsgi.XMLNS_V11 - - def __init__(self): - self.metadata_serializer = common.MetadataXMLSerializer() - - def _image_to_xml(self, xml_doc, image): - image_node = xml_doc.createElement('image') - image_node.setAttribute('id', str(image['id'])) - image_node.setAttribute('name', image['name']) - link_nodes = self._create_link_nodes(xml_doc, - image['links']) - for link_node in link_nodes: - image_node.appendChild(link_node) - return image_node - - def _image_to_xml_detailed(self, xml_doc, image): - image_node = xml_doc.createElement('image') - self._add_image_attributes(image_node, image) - - if 'server' in image: - server_node = self._create_server_node(xml_doc, image['server']) - image_node.appendChild(server_node) - - metadata = image.get('metadata', {}).items() - metadata_node = self._create_metadata_node(xml_doc, metadata) - image_node.appendChild(metadata_node) - - link_nodes = self._create_link_nodes(xml_doc, - image['links']) - for link_node in link_nodes: - image_node.appendChild(link_node) - - return image_node - - def _add_image_attributes(self, node, image): - node.setAttribute('id', str(image['id'])) - node.setAttribute('name', image['name']) - node.setAttribute('created', image['created']) - node.setAttribute('updated', image['updated']) - node.setAttribute('status', image['status']) - if 'progress' in image: - node.setAttribute('progress', str(image['progress'])) - - def _create_metadata_node(self, xml_doc, metadata): - return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) - - def _create_server_node(self, xml_doc, server): - server_node = xml_doc.createElement('server') - server_node.setAttribute('id', str(server['id'])) - link_nodes = self._create_link_nodes(xml_doc, - server['links']) - for link_node in link_nodes: - server_node.appendChild(link_node) - return server_node - - def _image_list_to_xml(self, xml_doc, images, detailed): - container_node = xml_doc.createElement('images') - if detailed: - image_to_xml = self._image_to_xml_detailed - else: - image_to_xml = self._image_to_xml + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + + def _create_metadata_node(self, metadata_dict): + metadata_elem = etree.Element('metadata', nsmap=self.NSMAP) + for (key, value) in metadata_dict.items(): + elem = etree.SubElement(metadata_elem, 'meta') + elem.set('key', key) + elem.text = value + + return metadata_elem - for image in images: - item_node = image_to_xml(xml_doc, image) - container_node.appendChild(item_node) - return container_node + def _create_server_node(self, server_dict): + server_elem = etree.Element('server', nsmap=self.NSMAP) + server_elem.set('id', str(server_dict['id'])) + for link in server_dict.get('links', []): + elem = etree.SubElement(server_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return server_elem + + def _populate_image(self, image_elem, image_dict, detailed=False): + """Populate an image xml element from a dict.""" + + image_elem.set('name', image_dict['name']) + image_elem.set('id', str(image_dict['id'])) + if detailed: + image_elem.set('updated', str(image_dict['updated'])) + image_elem.set('created', str(image_dict['created'])) + image_elem.set('status', str(image_dict['status'])) + if 'progress' in image_dict: + image_elem.set('progress', str(image_dict['progress'])) + if 'server' in image_dict: + server_elem = self._create_server_node(image_dict['server']) + image_elem.append(server_elem) + + meta_elem = self._create_metadata_node( + image_dict.get('metadata', {})) + image_elem.append(meta_elem) + + for link in image_dict.get('links', []): + elem = etree.SubElement(image_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return image_elem + + def _to_xml(self, root): + """Convert the xml object to an xml string.""" + + return etree.tostring(root, encoding='UTF-8') def index(self, images_dict): - xml_doc = minidom.Document() - node = self._image_list_to_xml(xml_doc, - images_dict['images'], - detailed=False) - return self.to_xml_string(node, True) + images = etree.Element('images', nsmap=self.NSMAP) + for image_dict in images_dict['images']: + image = etree.SubElement(images, 'image') + self._populate_image(image, image_dict, False) + return self._to_xml(images) def detail(self, images_dict): - xml_doc = minidom.Document() - node = self._image_list_to_xml(xml_doc, - images_dict['images'], - detailed=True) - return self.to_xml_string(node, True) + images = etree.Element('images', nsmap=self.NSMAP) + for image_dict in images_dict['images']: + image = etree.SubElement(images, 'image') + self._populate_image(image, image_dict, True) + return self._to_xml(images) def show(self, image_dict): - xml_doc = minidom.Document() - node = self._image_to_xml_detailed(xml_doc, - image_dict['image']) - return self.to_xml_string(node, True) + image = etree.Element('image', nsmap=self.NSMAP) + self._populate_image(image, image_dict['image'], True) + return self._to_xml(image) def create_resource(version='1.0'): -- cgit From 48b2de98d002a3f7dac03d29696e4c37ed4f983f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 12:05:53 -0400 Subject: Added schemas Updated metadata tests to use etree instead of minidom --- nova/api/openstack/schemas/v1.1/image.rng | 30 ++++++++++++++++++++++++ nova/api/openstack/schemas/v1.1/images.rng | 6 +++++ nova/api/openstack/schemas/v1.1/images_index.rng | 12 ++++++++++ nova/api/openstack/schemas/v1.1/metadata.rng | 9 +++++++ 4 files changed, 57 insertions(+) create mode 100644 nova/api/openstack/schemas/v1.1/image.rng create mode 100644 nova/api/openstack/schemas/v1.1/images.rng create mode 100644 nova/api/openstack/schemas/v1.1/images_index.rng create mode 100644 nova/api/openstack/schemas/v1.1/metadata.rng (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/image.rng b/nova/api/openstack/schemas/v1.1/image.rng new file mode 100644 index 000000000..887f76751 --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/image.rng @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nova/api/openstack/schemas/v1.1/images.rng b/nova/api/openstack/schemas/v1.1/images.rng new file mode 100644 index 000000000..064d4d9cc --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/images.rng @@ -0,0 +1,6 @@ + + + + + diff --git a/nova/api/openstack/schemas/v1.1/images_index.rng b/nova/api/openstack/schemas/v1.1/images_index.rng new file mode 100644 index 000000000..81af19cb5 --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/images_index.rng @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/nova/api/openstack/schemas/v1.1/metadata.rng b/nova/api/openstack/schemas/v1.1/metadata.rng new file mode 100644 index 000000000..b2f5d702a --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/metadata.rng @@ -0,0 +1,9 @@ + + + + + + + + -- cgit From e0b64c9aa0d2617d1d9e4dc0c35dc3899e0e527a Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 12:44:01 -0400 Subject: Updated MetadataXMLSerializer to use etree instead of minidom --- nova/api/openstack/common.py | 71 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index d9eb832f2..d9371b89a 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -16,6 +16,7 @@ # under the License. import functools +from lxml import etree import re import urlparse from xml.dom import minidom @@ -27,6 +28,7 @@ from nova import flags from nova import log as logging from nova import quota from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil from nova.compute import power_state as compute_power_state @@ -282,54 +284,53 @@ class MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer): class MetadataXMLSerializer(wsgi.XMLDictSerializer): + + NSMAP = {None: xmlutil.XMLNS_V11} def __init__(self, xmlns=wsgi.XMLNS_V11): super(MetadataXMLSerializer, self).__init__(xmlns=xmlns) - def _meta_item_to_xml(self, doc, key, value): - node = doc.createElement('meta') - doc.appendChild(node) - node.setAttribute('key', '%s' % key) - text = doc.createTextNode('%s' % value) - node.appendChild(text) - return node - - def meta_list_to_xml(self, xml_doc, meta_items): - container_node = xml_doc.createElement('metadata') - for (key, value) in meta_items: - item_node = self._meta_item_to_xml(xml_doc, key, value) - container_node.appendChild(item_node) - return container_node - - def _meta_list_to_xml_string(self, metadata_dict): - xml_doc = minidom.Document() - items = metadata_dict['metadata'].items() - container_node = self.meta_list_to_xml(xml_doc, items) - xml_doc.appendChild(container_node) - self._add_xmlns(container_node) - return xml_doc.toxml('UTF-8') + def _populate_metadata(self, metadata_elem, meta_dict): + for (key, value) in meta_dict.items(): + elem = etree.SubElement(metadata_elem, 'meta') + elem.set('key', str(key)) + elem.text = value + + def _populate_meta_item(self, meta_elem, meta_item_dict): + """Populate a meta xml element from a dict.""" + (key, value) = meta_item_dict.items()[0] + meta_elem.set('key', str(key)) + meta_elem.text = value + return meta_elem + + def _to_xml(self, root): + """Convert the xml object to an xml string.""" + + return etree.tostring(root, encoding='UTF-8') def index(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) + metadata = etree.Element('metadata', nsmap=self.NSMAP) + self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + return self._to_xml(metadata) def create(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) + metadata = etree.Element('metadata', nsmap=self.NSMAP) + self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + return self._to_xml(metadata) def update_all(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) - - def _meta_item_to_xml_string(self, meta_item_dict): - xml_doc = minidom.Document() - item_key, item_value = meta_item_dict.items()[0] - item_node = self._meta_item_to_xml(xml_doc, item_key, item_value) - xml_doc.appendChild(item_node) - self._add_xmlns(item_node) - return xml_doc.toxml('UTF-8') + metadata = etree.Element('metadata', nsmap=self.NSMAP) + self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + return self._to_xml(metadata) def show(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) + meta = etree.Element('meta', nsmap=self.NSMAP) + self._populate_meta_item(meta, meta_item_dict['meta']) + return self._to_xml(meta) def update(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) + meta = etree.Element('meta', nsmap=self.NSMAP) + self._populate_meta_item(meta, meta_item_dict['meta']) + return self._to_xml(meta) def default(self, *args, **kwargs): return '' -- cgit From 73704209a146bf51f51f445dc1ccc4410181ad6c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 14:58:31 -0400 Subject: Updated ServerXMLSerializer to use etree instead of minidom --- nova/api/openstack/schemas/v1.1/server.rng | 6 +- nova/api/openstack/servers.py | 215 ++++++++++++++--------------- 2 files changed, 105 insertions(+), 116 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/server.rng b/nova/api/openstack/schemas/v1.1/server.rng index dbd169a83..68f86373c 100644 --- a/nova/api/openstack/schemas/v1.1/server.rng +++ b/nova/api/openstack/schemas/v1.1/server.rng @@ -15,9 +15,6 @@ - - - @@ -47,4 +44,7 @@ + + + diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 27c67e79e..b978dea08 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -17,8 +17,8 @@ import base64 import os import traceback +from lxml import etree from webob import exc -from xml.dom import minidom import webob from nova import compute @@ -37,6 +37,7 @@ import nova.api.openstack.views.addresses import nova.api.openstack.views.flavors import nova.api.openstack.views.images import nova.api.openstack.views.servers +from nova.api.openstack import xmlutil LOG = logging.getLogger('nova.api.openstack.servers') @@ -835,123 +836,112 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer): class ServerXMLSerializer(wsgi.XMLDictSerializer): - xmlns = wsgi.XMLNS_V11 - - def __init__(self): - self.metadata_serializer = common.MetadataXMLSerializer() - self.addresses_serializer = ips.IPXMLSerializer() - - def _create_basic_entity_node(self, xml_doc, id, links, name): - basic_node = xml_doc.createElement(name) - basic_node.setAttribute('id', str(id)) - link_nodes = self._create_link_nodes(xml_doc, links) - for link_node in link_nodes: - basic_node.appendChild(link_node) - return basic_node - - def _create_metadata_node(self, xml_doc, metadata): - return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) - - def _create_addresses_node(self, xml_doc, addresses): - return self.addresses_serializer.networks_to_xml(xml_doc, addresses) - - def _add_server_attributes(self, node, server): - node.setAttribute('id', str(server['id'])) - node.setAttribute('uuid', str(server['uuid'])) - node.setAttribute('hostId', str(server['hostId'])) - node.setAttribute('name', server['name']) - node.setAttribute('created', str(server['created'])) - node.setAttribute('updated', str(server['updated'])) - node.setAttribute('status', server['status']) - if 'accessIPv4' in server: - node.setAttribute('accessIPv4', str(server['accessIPv4'])) - if 'accessIPv6' in server: - node.setAttribute('accessIPv6', str(server['accessIPv6'])) - if 'progress' in server: - node.setAttribute('progress', str(server['progress'])) - - def _server_to_xml(self, xml_doc, server): - server_node = xml_doc.createElement('server') - server_node.setAttribute('id', str(server['id'])) - server_node.setAttribute('name', server['name']) - link_nodes = self._create_link_nodes(xml_doc, - server['links']) - for link_node in link_nodes: - server_node.appendChild(link_node) - return server_node - - def _server_to_xml_detailed(self, xml_doc, server): - server_node = xml_doc.createElement('server') - self._add_server_attributes(server_node, server) - - link_nodes = self._create_link_nodes(xml_doc, - server['links']) - for link_node in link_nodes: - server_node.appendChild(link_node) - - if 'image' in server: - image_node = self._create_basic_entity_node(xml_doc, - server['image']['id'], - server['image']['links'], - 'image') - server_node.appendChild(image_node) - - if 'flavor' in server: - flavor_node = self._create_basic_entity_node(xml_doc, - server['flavor']['id'], - server['flavor']['links'], - 'flavor') - server_node.appendChild(flavor_node) - - metadata = server.get('metadata', {}).items() - if len(metadata) > 0: - metadata_node = self._create_metadata_node(xml_doc, metadata) - server_node.appendChild(metadata_node) - - addresses_node = self._create_addresses_node(xml_doc, - server['addresses']) - server_node.appendChild(addresses_node) - - return server_node - - def _server_list_to_xml(self, xml_doc, servers, detailed): - container_node = xml_doc.createElement('servers') + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + + def _create_metadata_node(self, metadata_dict): + metadata_elem = etree.Element('metadata', nsmap=self.NSMAP) + for (key, value) in metadata_dict.items(): + elem = etree.SubElement(metadata_elem, 'meta') + elem.set('key', key) + elem.text = value + + return metadata_elem + + def _create_image_node(self, image_dict): + image_elem = etree.Element('image', nsmap=self.NSMAP) + image_elem.set('id', str(image_dict['id'])) + for link in image_dict.get('links', []): + elem = etree.SubElement(image_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return image_elem + + def _create_flavor_node(self, flavor_dict): + flavor_elem = etree.Element('flavor', nsmap=self.NSMAP) + flavor_elem.set('id', str(flavor_dict['id'])) + for link in flavor_dict.get('links', []): + elem = etree.SubElement(flavor_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return flavor_elem + + def _create_addresses_node(self, addresses_dict): + addresses_elem = etree.Element('addresses', nsmap=self.NSMAP) + for (network_id, ip_dicts) in addresses_dict.items(): + network_node = etree.SubElement(addresses_elem, 'network') + network_node.set('id', str(network_id)) + for ip_dict in ip_dicts: + ip_elem = etree.SubElement(network_node, 'ip') + ip_elem.set('version', str(ip_dict['version'])) + ip_elem.set('addr', ip_dict['addr']) + return addresses_elem + + def _populate_server(self, server_elem, server_dict, detailed=False): + """Populate a server xml element from a dict.""" + + server_elem.set('name', server_dict['name']) + server_elem.set('id', str(server_dict['id'])) if detailed: - server_to_xml = self._server_to_xml_detailed - else: - server_to_xml = self._server_to_xml - - for server in servers: - item_node = server_to_xml(xml_doc, server) - container_node.appendChild(item_node) - return container_node + server_elem.set('uuid', str(server_dict['uuid'])) + server_elem.set('updated', str(server_dict['updated'])) + server_elem.set('created', str(server_dict['created'])) + server_elem.set('hostId', str(server_dict['hostId'])) + server_elem.set('accessIPv4', str(server_dict['accessIPv4'])) + server_elem.set('accessIPv6', str(server_dict['accessIPv6'])) + server_elem.set('status', str(server_dict['status'])) + if 'progress' in server_dict: + server_elem.set('progress', str(server_dict['progress'])) + image_elem = self._create_image_node(server_dict['image']) + server_elem.append(image_elem) + + flavor_elem = self._create_flavor_node(server_dict['flavor']) + server_elem.append(flavor_elem) + + meta_elem = self._create_metadata_node( + server_dict.get('metadata', {})) + server_elem.append(meta_elem) + + addresses_elem = self._create_addresses_node( + server_dict.get('addresses', {})) + server_elem.append(addresses_elem) + + for link in server_dict.get('links', []): + elem = etree.SubElement(server_elem, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + return server_elem + + def _to_xml(self, root): + """Convert the xml object to an xml string.""" + return etree.tostring(root, encoding='UTF-8') def index(self, servers_dict): - xml_doc = minidom.Document() - node = self._server_list_to_xml(xml_doc, - servers_dict['servers'], - detailed=False) - return self.to_xml_string(node, True) + servers = etree.Element('servers', nsmap=self.NSMAP) + for server_dict in servers_dict['servers']: + server = etree.SubElement(servers, 'server') + self._populate_server(server, server_dict, False) + return self._to_xml(servers) def detail(self, servers_dict): - xml_doc = minidom.Document() - node = self._server_list_to_xml(xml_doc, - servers_dict['servers'], - detailed=True) - return self.to_xml_string(node, True) + servers = etree.Element('servers', nsmap=self.NSMAP) + for server_dict in servers_dict['servers']: + server = etree.SubElement(servers, 'server') + self._populate_server(server, server_dict, True) + return self._to_xml(servers) def show(self, server_dict): - xml_doc = minidom.Document() - node = self._server_to_xml_detailed(xml_doc, - server_dict['server']) - return self.to_xml_string(node, True) + server = etree.Element('server', nsmap=self.NSMAP) + self._populate_server(server, server_dict['server'], True) + return self._to_xml(server) def create(self, server_dict): - xml_doc = minidom.Document() - node = self._server_to_xml_detailed(xml_doc, - server_dict['server']) - node.setAttribute('adminPass', server_dict['server']['adminPass']) - return self.to_xml_string(node, True) + server = etree.Element('server', nsmap=self.NSMAP) + self._populate_server(server, server_dict['server'], True) + server.set('adminPass', server_dict['server']['adminPass']) + return self._to_xml(server) def action(self, server_dict): #NOTE(bcwaldon): We need a way to serialize actions individually. This @@ -959,10 +949,9 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): return self.create(server_dict) def update(self, server_dict): - xml_doc = minidom.Document() - node = self._server_to_xml_detailed(xml_doc, - server_dict['server']) - return self.to_xml_string(node, True) + server = etree.Element('server', nsmap=self.NSMAP) + self._populate_server(server, server_dict['server'], True) + return self._to_xml(server) def create_resource(version='1.0'): -- cgit From 8e712b30911956531e346723fbbcaaa49f166ab7 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 15:12:34 -0400 Subject: Added addresses schema --- nova/api/openstack/schemas/v1.1/addresses.rng | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 nova/api/openstack/schemas/v1.1/addresses.rng (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/addresses.rng b/nova/api/openstack/schemas/v1.1/addresses.rng new file mode 100644 index 000000000..b498e8a63 --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/addresses.rng @@ -0,0 +1,14 @@ + + + + + + + + + + + + + -- cgit From aafd1ff68f2f6085ddf0d6762ed9ed594d23a321 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 15:30:52 -0400 Subject: updated addresses serializer to use etree instead of minidom --- nova/api/openstack/ips.py | 63 +++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index a74fae487..0147d66f8 100644 --- a/nova/api/openstack/ips.py +++ b/nova/api/openstack/ips.py @@ -15,14 +15,15 @@ # License for the specific language governing permissions and limitations # under the License. +from lxml import etree import time -from xml.dom import minidom from webob import exc import nova import nova.api.openstack.views.addresses from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil from nova import db @@ -102,42 +103,40 @@ class ControllerV11(Controller): class IPXMLSerializer(wsgi.XMLDictSerializer): + + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + def __init__(self, xmlns=wsgi.XMLNS_V11): super(IPXMLSerializer, self).__init__(xmlns=xmlns) - def _ip_to_xml(self, xml_doc, ip_dict): - ip_node = xml_doc.createElement('ip') - ip_node.setAttribute('addr', ip_dict['addr']) - ip_node.setAttribute('version', str(ip_dict['version'])) - return ip_node - - def _network_to_xml(self, xml_doc, network_id, ip_dicts): - network_node = xml_doc.createElement('network') - network_node.setAttribute('id', network_id) + def _create_addresses_node(self, addresses_dict): + addresses_elem = etree.Element('addresses', nsmap=self.NSMAP) + for (network_id, ip_dicts) in addresses_dict.items(): + network_elem = self._create_network_node(network_id, ip_dicts) + addresses_elem.append(network_elem) + return addresses_elem + def _create_network_node(self, network_id, ip_dicts): + network_elem = etree.Element('network', nsmap=self.NSMAP) + network_elem.set('id', str(network_id)) for ip_dict in ip_dicts: - ip_node = self._ip_to_xml(xml_doc, ip_dict) - network_node.appendChild(ip_node) - - return network_node - - def networks_to_xml(self, xml_doc, networks_container): - addresses_node = xml_doc.createElement('addresses') - for (network_id, ip_dicts) in networks_container.items(): - network_node = self._network_to_xml(xml_doc, network_id, ip_dicts) - addresses_node.appendChild(network_node) - return addresses_node - - def show(self, network_container): - (network_id, ip_dicts) = network_container.items()[0] - xml_doc = minidom.Document() - node = self._network_to_xml(xml_doc, network_id, ip_dicts) - return self.to_xml_string(node, False) - - def index(self, addresses_container): - xml_doc = minidom.Document() - node = self.networks_to_xml(xml_doc, addresses_container['addresses']) - return self.to_xml_string(node, False) + ip_elem = etree.SubElement(network_elem, 'ip') + ip_elem.set('version', str(ip_dict['version'])) + ip_elem.set('addr', ip_dict['addr']) + return network_elem + + def _to_xml(self, root): + """Convert the xml object to an xml string.""" + return etree.tostring(root, encoding='UTF-8') + + def show(self, network_dict): + (network_id, ip_dicts) = network_dict.items()[0] + network = self._create_network_node(network_id, ip_dicts) + return self._to_xml(network) + + def index(self, addresses_dict): + addresses = self._create_addresses_node(addresses_dict['addresses']) + return self._to_xml(addresses) def create_resource(version): -- cgit From b02a5e4f581590c1bf31dae1c9c2bc1e448a6106 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 16:35:04 -0400 Subject: DRYed up code by moving _to_xml into XMLDictSerializer --- nova/api/openstack/common.py | 5 ----- nova/api/openstack/flavors.py | 5 ----- nova/api/openstack/images.py | 5 ----- nova/api/openstack/ips.py | 6 +----- nova/api/openstack/servers.py | 4 ---- nova/api/openstack/wsgi.py | 5 +++++ 6 files changed, 6 insertions(+), 24 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index d9371b89a..7dde68975 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -302,11 +302,6 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer): meta_elem.text = value return meta_elem - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - - return etree.tostring(root, encoding='UTF-8') - def index(self, metadata_dict): metadata = etree.Element('metadata', nsmap=self.NSMAP) self._populate_metadata(metadata, metadata_dict.get('metadata', {})) diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index f689aa7ab..805aad772 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -99,11 +99,6 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer): elem.set('href', link['href']) return flavor_elem - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - - return etree.tostring(root, encoding='UTF-8') - def show(self, flavor_container): flavor = etree.Element('flavor', nsmap=self.NSMAP) self._populate_flavor(flavor, flavor_container['flavor'], True) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index edd26c171..48c53d6d5 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -254,11 +254,6 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): elem.set('href', link['href']) return image_elem - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - - return etree.tostring(root, encoding='UTF-8') - def index(self, images_dict): images = etree.Element('images', nsmap=self.NSMAP) for image_dict in images_dict['images']: diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index 0147d66f8..d5a715dda 100644 --- a/nova/api/openstack/ips.py +++ b/nova/api/openstack/ips.py @@ -104,7 +104,7 @@ class ControllerV11(Controller): class IPXMLSerializer(wsgi.XMLDictSerializer): - NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + NSMAP = {None: xmlutil.XMLNS_V11} def __init__(self, xmlns=wsgi.XMLNS_V11): super(IPXMLSerializer, self).__init__(xmlns=xmlns) @@ -125,10 +125,6 @@ class IPXMLSerializer(wsgi.XMLDictSerializer): ip_elem.set('addr', ip_dict['addr']) return network_elem - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - return etree.tostring(root, encoding='UTF-8') - def show(self, network_dict): (network_id, ip_dicts) = network_dict.items()[0] network = self._create_network_node(network_id, ip_dicts) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index b978dea08..fa5b7c023 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -914,10 +914,6 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): elem.set('href', link['href']) return server_elem - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - return etree.tostring(root, encoding='UTF-8') - def index(self, servers_dict): servers = etree.Element('servers', nsmap=self.NSMAP) for server_dict in servers_dict['servers']: diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 8641e960a..bdcadcb99 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -1,5 +1,6 @@ import json +from lxml import etree import webob from xml.dom import minidom from xml.parsers import expat @@ -392,6 +393,10 @@ class XMLDictSerializer(DictSerializer): link_nodes.append(link_node) return link_nodes + def _to_xml(self, root): + """Convert the xml object to an xml string.""" + return etree.tostring(root, encoding='UTF-8', xml_declaration=True) + class ResponseHeadersSerializer(ActionDispatcher): """Default response headers serialization""" -- cgit From 73311c4e71e72f2866bb47063ddf9b5a04c3736d Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 16:36:41 -0400 Subject: pep8 --- nova/api/openstack/common.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 7dde68975..1d1c56459 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -286,6 +286,7 @@ class MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer): class MetadataXMLSerializer(wsgi.XMLDictSerializer): NSMAP = {None: xmlutil.XMLNS_V11} + def __init__(self, xmlns=wsgi.XMLNS_V11): super(MetadataXMLSerializer, self).__init__(xmlns=xmlns) -- cgit From 1e6eed6b064632996b56ba6952b52c07e28c114c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 18:01:35 -0400 Subject: Updated limits serialization tests to use etree and added limits schema --- nova/api/openstack/schemas/v1.1/limits.rng | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 nova/api/openstack/schemas/v1.1/limits.rng (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/limits.rng b/nova/api/openstack/schemas/v1.1/limits.rng new file mode 100644 index 000000000..1af8108ec --- /dev/null +++ b/nova/api/openstack/schemas/v1.1/limits.rng @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit From e4966cc21ca34380be98a9f24c76404ca43f663f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 18:31:41 -0400 Subject: updated LimitsXMLSerializer to use etree and supply the xml declaration --- nova/api/openstack/limits.py | 81 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 41 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 86afa3b62..5ee9a05b0 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -20,6 +20,7 @@ Module dedicated functions/classes dealing with rate limiting requests. import copy import httplib import json +from lxml import etree import math import re import time @@ -38,6 +39,7 @@ from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack.views import limits as limits_views from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil # Convenience constants for the limits dictionary passed to Limiter(). @@ -81,52 +83,49 @@ class LimitsXMLSerializer(wsgi.XMLDictSerializer): xmlns = wsgi.XMLNS_V11 + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + def __init__(self): pass - def _create_rates_node(self, xml_doc, rates): - rates_node = xml_doc.createElement('rates') - for rate in rates: - rate_node = xml_doc.createElement('rate') - rate_node.setAttribute('uri', rate['uri']) - rate_node.setAttribute('regex', rate['regex']) - - for limit in rate['limit']: - limit_node = xml_doc.createElement('limit') - limit_node.setAttribute('value', str(limit['value'])) - limit_node.setAttribute('verb', limit['verb']) - limit_node.setAttribute('remaining', str(limit['remaining'])) - limit_node.setAttribute('unit', limit['unit']) - limit_node.setAttribute('next-available', - str(limit['next-available'])) - rate_node.appendChild(limit_node) - - rates_node.appendChild(rate_node) - return rates_node - - def _create_absolute_node(self, xml_doc, absolutes): - absolute_node = xml_doc.createElement('absolute') - for key, value in absolutes.iteritems(): - limit_node = xml_doc.createElement('limit') - limit_node.setAttribute('name', key) - limit_node.setAttribute('value', str(value)) - absolute_node.appendChild(limit_node) - return absolute_node - - def _limits_to_xml(self, xml_doc, limits): - limits_node = xml_doc.createElement('limits') - rates_node = self._create_rates_node(xml_doc, limits['rate']) - limits_node.appendChild(rates_node) - - absolute_node = self._create_absolute_node(xml_doc, limits['absolute']) - limits_node.appendChild(absolute_node) - - return limits_node + def _create_rates_node(self, rates_dict): + rates_elem = etree.Element('rates', nsmap=self.NSMAP) + for rate in rates_dict.items(): + rate_node = etree.SubElement(rates_elem, 'rate') + rate_node.set('uri', rate['uri']) + rate_node.set('regex', rate['regex']) + for limit in rate['limits']: + limit_elem = etree.SubElement(rate_node, 'limit') + limit_elem.set('value', str(rate['value'])) + limit_elem.set('verb', str(rate['verb'])) + limit_elem.set('remaining', str(rate['remaining'])) + limit_elem.set('unit', str(rate['unit'])) + limit_elem.set('next-available', str(rate['next-available'])) + return rates_elem + + def _create_absolute_node(self, absolute_dict): + absolute_elem = etree.Element('absolute', nsmap=self.NSMAP) + for key, value in absolute_dict.items(): + limit_elem = etree.SubElement(rate_node, 'limit') + limit_elem.set('name', str(key)) + limit_elem.set('value', str(value)) + return absolute_elem + + def _populate_limits(self, limits_elem, limits_dict): + """Populate a limits xml element from a dict.""" + + rates_elem = self._create_rates_node( + limits_dict.get('rates', {})) + limits_elem.append(rates_elem) + + absolutes_elem = self._create_absolute_node( + limits_dict.get('absolutes', {})) + limits_elem.append(absolutes_elem) def index(self, limits_dict): - xml_doc = minidom.Document() - node = self._limits_to_xml(xml_doc, limits_dict['limits']) - return self.to_xml_string(node, False) + limits = etree.Element('limits', nsmap=self.NSMAP) + self._populate_limits(limits, limits_dict) + return self._to_xml(limits) def create_resource(version='1.0'): -- cgit From 39169914aa43a911735267577e60bc977bcd5117 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 25 Aug 2011 21:50:18 -0400 Subject: Updated server and image XML serializers to take advantage of the addresses and metadata serializers --- nova/api/openstack/common.py | 9 ++++----- nova/api/openstack/images.py | 10 +++++----- nova/api/openstack/ips.py | 8 ++++---- nova/api/openstack/servers.py | 20 ++++++++------------ 4 files changed, 21 insertions(+), 26 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 1d1c56459..c3379cd11 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -290,7 +290,7 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer): def __init__(self, xmlns=wsgi.XMLNS_V11): super(MetadataXMLSerializer, self).__init__(xmlns=xmlns) - def _populate_metadata(self, metadata_elem, meta_dict): + def populate_metadata(self, metadata_elem, meta_dict): for (key, value) in meta_dict.items(): elem = etree.SubElement(metadata_elem, 'meta') elem.set('key', str(key)) @@ -301,21 +301,20 @@ class MetadataXMLSerializer(wsgi.XMLDictSerializer): (key, value) = meta_item_dict.items()[0] meta_elem.set('key', str(key)) meta_elem.text = value - return meta_elem def index(self, metadata_dict): metadata = etree.Element('metadata', nsmap=self.NSMAP) - self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + self.populate_metadata(metadata, metadata_dict.get('metadata', {})) return self._to_xml(metadata) def create(self, metadata_dict): metadata = etree.Element('metadata', nsmap=self.NSMAP) - self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + self.populate_metadata(metadata, metadata_dict.get('metadata', {})) return self._to_xml(metadata) def update_all(self, metadata_dict): metadata = etree.Element('metadata', nsmap=self.NSMAP) - self._populate_metadata(metadata, metadata_dict.get('metadata', {})) + self.populate_metadata(metadata, metadata_dict.get('metadata', {})) return self._to_xml(metadata) def show(self, meta_item_dict): diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 48c53d6d5..893674f21 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -209,13 +209,13 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + def __init__(self): + self.metadata_serializer = common.MetadataXMLSerializer() + def _create_metadata_node(self, metadata_dict): metadata_elem = etree.Element('metadata', nsmap=self.NSMAP) - for (key, value) in metadata_dict.items(): - elem = etree.SubElement(metadata_elem, 'meta') - elem.set('key', key) - elem.text = value - + self.metadata_serializer.populate_metadata(metadata_elem, + metadata_dict) return metadata_elem def _create_server_node(self, server_dict): diff --git a/nova/api/openstack/ips.py b/nova/api/openstack/ips.py index d5a715dda..7e644ba04 100644 --- a/nova/api/openstack/ips.py +++ b/nova/api/openstack/ips.py @@ -109,12 +109,10 @@ class IPXMLSerializer(wsgi.XMLDictSerializer): def __init__(self, xmlns=wsgi.XMLNS_V11): super(IPXMLSerializer, self).__init__(xmlns=xmlns) - def _create_addresses_node(self, addresses_dict): - addresses_elem = etree.Element('addresses', nsmap=self.NSMAP) + def populate_addresses_node(self, addresses_elem, addresses_dict): for (network_id, ip_dicts) in addresses_dict.items(): network_elem = self._create_network_node(network_id, ip_dicts) addresses_elem.append(network_elem) - return addresses_elem def _create_network_node(self, network_id, ip_dicts): network_elem = etree.Element('network', nsmap=self.NSMAP) @@ -131,7 +129,9 @@ class IPXMLSerializer(wsgi.XMLDictSerializer): return self._to_xml(network) def index(self, addresses_dict): - addresses = self._create_addresses_node(addresses_dict['addresses']) + addresses = etree.Element('addresses', nsmap=self.NSMAP) + self.populate_addresses_node(addresses, + addresses_dict.get('addresses', {})) return self._to_xml(addresses) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index fa5b7c023..bb403845d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -838,13 +838,14 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} + def __init__(self): + self.metadata_serializer = common.MetadataXMLSerializer() + self.addresses_serializer = ips.IPXMLSerializer() + def _create_metadata_node(self, metadata_dict): metadata_elem = etree.Element('metadata', nsmap=self.NSMAP) - for (key, value) in metadata_dict.items(): - elem = etree.SubElement(metadata_elem, 'meta') - elem.set('key', key) - elem.text = value - + self.metadata_serializer.populate_metadata(metadata_elem, + metadata_dict) return metadata_elem def _create_image_node(self, image_dict): @@ -869,13 +870,8 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): def _create_addresses_node(self, addresses_dict): addresses_elem = etree.Element('addresses', nsmap=self.NSMAP) - for (network_id, ip_dicts) in addresses_dict.items(): - network_node = etree.SubElement(addresses_elem, 'network') - network_node.set('id', str(network_id)) - for ip_dict in ip_dicts: - ip_elem = etree.SubElement(network_node, 'ip') - ip_elem.set('version', str(ip_dict['version'])) - ip_elem.set('addr', ip_dict['addr']) + self.addresses_serializer.populate_addresses_node(addresses_elem, + addresses_dict) return addresses_elem def _populate_server(self, server_elem, server_dict, detailed=False): -- cgit From e39ec75169ff3b7ac29212ca315ad213997a8cbc Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Sat, 27 Aug 2011 04:32:20 -0400 Subject: Updated VersionsXMLSerializer and corresponding tests to use lxml. --- nova/api/openstack/limits.py | 1 - nova/api/openstack/versions.py | 65 ++++++++++++++++++++---------------- nova/api/openstack/views/versions.py | 2 +- 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 5ee9a05b0..2896ac396 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -26,7 +26,6 @@ import re import time import urllib import webob.exc -from xml.dom import minidom from collections import defaultdict diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py index e2f892fb6..16a4e8bfd 100644 --- a/nova/api/openstack/versions.py +++ b/nova/api/openstack/versions.py @@ -16,12 +16,14 @@ # under the License. from datetime import datetime +from lxml import etree import webob import webob.dec from xml.dom import minidom import nova.api.openstack.views.versions from nova.api.openstack import wsgi +from nova.api.openstack import xmlutil VERSIONS = { @@ -159,22 +161,6 @@ class VersionsRequestDeserializer(wsgi.RequestDeserializer): class VersionsXMLSerializer(wsgi.XMLDictSerializer): - #TODO(wwolf): this is temporary until we get rid of toprettyxml - # in the base class (XMLDictSerializer), which I plan to do in - # another branch - def to_xml_string(self, node, has_atom=False): - self._add_xmlns(node, has_atom) - return node.toxml(encoding='UTF-8') - - def _versions_to_xml(self, versions, name="versions", xmlns=None): - root = self._xml_doc.createElement(name) - root.setAttribute("xmlns", wsgi.XMLNS_V11) - root.setAttribute("xmlns:atom", wsgi.XMLNS_ATOM) - - for version in versions: - root.appendChild(self._create_version_node(version)) - - return root def _create_media_types(self, media_types): base = self._xml_doc.createElement('media-types') @@ -209,24 +195,45 @@ class VersionsXMLSerializer(wsgi.XMLDictSerializer): return version_node - def index(self, data): - self._xml_doc = minidom.Document() - node = self._versions_to_xml(data['versions']) + def _populate_version(self, version_node, version): + version_node.set('id', version['id']) + version_node.set('status', version['status']) + if 'updated' in version: + version_node.set('updated', version['updated']) + if 'media-types' in version: + media_types = etree.SubElement(version_node, 'media-types') + for mtype in version['media-types']: + elem = etree.SubElement(media_types, 'media-type') + elem.set('base', mtype['base']) + elem.set('type', mtype['type']) + for link in version.get('links', []): + elem = etree.SubElement(version_node, + '{%s}link' % xmlutil.XMLNS_ATOM) + elem.set('rel', link['rel']) + elem.set('href', link['href']) + if 'type' in link: + elem.set('type', link['type']) + + NSMAP = {None: xmlutil.XMLNS_V11, 'atom': xmlutil.XMLNS_ATOM} - return self.to_xml_string(node) + def index(self, data): + root = etree.Element('versions', nsmap=self.NSMAP) + for version in data['versions']: + version_elem = etree.SubElement(root, 'version') + self._populate_version(version_elem, version) + return etree.tostring(root, encoding='UTF-8') def show(self, data): - self._xml_doc = minidom.Document() - node = self._create_version_node(data['version'], True) - - return self.to_xml_string(node) + root = etree.Element('version', nsmap=self.NSMAP) + self._populate_version(root, data['version']) + return etree.tostring(root, encoding='UTF-8') def multi(self, data): - self._xml_doc = minidom.Document() - node = self._versions_to_xml(data['choices'], 'choices', - xmlns=wsgi.XMLNS_V11) - - return self.to_xml_string(node) + root = etree.Element('choices', nsmap=self.NSMAP) + for version in data['choices']: + version_elem = etree.SubElement(root, 'version') + self._populate_version(version_elem, version) + return etree.tostring(root, encoding='UTF-8') class VersionsAtomSerializer(wsgi.XMLDictSerializer): diff --git a/nova/api/openstack/views/versions.py b/nova/api/openstack/views/versions.py index 03da80818..1ac398706 100644 --- a/nova/api/openstack/views/versions.py +++ b/nova/api/openstack/views/versions.py @@ -52,7 +52,7 @@ class ViewBuilder(object): def build_versions(self, versions): version_objs = [] - for version in versions: + for version in sorted(versions.keys()): version = versions[version] version_objs.append({ "id": version['id'], -- cgit From d99588a4caf855f3876ea83fa0d8517a77727aef Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 31 Aug 2011 19:32:55 -0400 Subject: Updated VersionsAtomSerializer.index to use lxml.etree to generate atom feed. --- nova/api/openstack/versions.py | 102 ++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 57 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py index 16a4e8bfd..0766e1eb7 100644 --- a/nova/api/openstack/versions.py +++ b/nova/api/openstack/versions.py @@ -162,39 +162,6 @@ class VersionsRequestDeserializer(wsgi.RequestDeserializer): class VersionsXMLSerializer(wsgi.XMLDictSerializer): - def _create_media_types(self, media_types): - base = self._xml_doc.createElement('media-types') - for type in media_types: - node = self._xml_doc.createElement('media-type') - node.setAttribute('base', type['base']) - node.setAttribute('type', type['type']) - base.appendChild(node) - - return base - - def _create_version_node(self, version, create_ns=False): - version_node = self._xml_doc.createElement('version') - if create_ns: - xmlns = wsgi.XMLNS_V11 - xmlns_atom = wsgi.XMLNS_ATOM - version_node.setAttribute('xmlns', xmlns) - version_node.setAttribute('xmlns:atom', xmlns_atom) - - version_node.setAttribute('id', version['id']) - version_node.setAttribute('status', version['status']) - if 'updated' in version: - version_node.setAttribute('updated', version['updated']) - - if 'media-types' in version: - media_types = self._create_media_types(version['media-types']) - version_node.appendChild(media_types) - - link_nodes = self._create_link_nodes(self._xml_doc, version['links']) - for link in link_nodes: - version_node.appendChild(link) - - return version_node - def _populate_version(self, version_node, version): version_node.set('id', version['id']) version_node.set('status', version['status']) @@ -237,6 +204,9 @@ class VersionsXMLSerializer(wsgi.XMLDictSerializer): class VersionsAtomSerializer(wsgi.XMLDictSerializer): + + NSMAP = {None: xmlutil.XMLNS_ATOM} + #TODO(wwolf): this is temporary until we get rid of toprettyxml # in the base class (XMLDictSerializer), which I plan to do in # another branch @@ -301,31 +271,53 @@ class VersionsAtomSerializer(wsgi.XMLDictSerializer): root.appendChild(author) root.appendChild(link) - def _create_list_meta(self, root, versions): - title = self._create_text_elem('title', "Available API Versions", - type='text') + def _create_feed(self, versions): + feed = etree.Element('feed', nsmap=self.NSMAP) + title = etree.SubElement(feed, 'title') + title.set('type', 'text') + title.text = 'Available API Versions' + # Set this updated to the most recently updated version recent = self._get_most_recent_update(versions) - updated = self._create_text_elem('updated', recent) + etree.SubElement(feed, 'updated').text = recent base_url = self._get_base_url(versions[0]['links'][0]['href']) - id = self._create_text_elem('id', base_url) + etree.SubElement(feed, 'id').text = base_url - link = self._xml_doc.createElement('link') - link.setAttribute('rel', 'self') - link.setAttribute('href', base_url) + link = etree.SubElement(feed, 'link') + link.set('rel', 'self') + link.set('href', base_url) - author = self._xml_doc.createElement('author') - author_name = self._create_text_elem('name', 'Rackspace') - author_uri = self._create_text_elem('uri', 'http://www.rackspace.com/') - author.appendChild(author_name) - author.appendChild(author_uri) + author = etree.SubElement(feed, 'author') + etree.SubElement(author, 'name').text = 'Rackspace' + etree.SubElement(author, 'uri').text = 'http://www.rackspace.com/' - root.appendChild(title) - root.appendChild(updated) - root.appendChild(id) - root.appendChild(author) - root.appendChild(link) + 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 def _create_version_entries(self, root, versions): for version in versions: @@ -361,12 +353,8 @@ class VersionsAtomSerializer(wsgi.XMLDictSerializer): root.appendChild(entry) def index(self, data): - self._xml_doc = minidom.Document() - node = self._xml_doc.createElementNS(self.xmlns, 'feed') - self._create_list_meta(node, data['versions']) - self._create_version_entries(node, data['versions']) - - return self.to_xml_string(node) + feed = self._create_feed(data['versions']) + return etree.tostring(feed, encoding='UTF-8') def show(self, data): self._xml_doc = minidom.Document() -- cgit From 13c74c252b0b7f900cde6a09201ea01c389f73a8 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 22:43:26 -0400 Subject: move GlanceImageService tests to proper module; remove translation of non-standard image attributes to properties; ensure all image properties are available, defaulting to None if not provided --- nova/api/openstack/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 1c8fc10c9..fcaa94651 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -50,7 +50,7 @@ class Controller(object): """Initialize new `ImageController`. :param compute_service: `nova.compute.api:API` - :param image_service: `nova.image.service:BaseImageService` + :param image_service: `nova.image.glance:GlancemageService` """ self._compute_service = compute_service or compute.API() -- cgit From 69aeb326d6da85a3b0566d973588eab6668ffa36 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 31 Aug 2011 23:13:21 -0400 Subject: remove BaseImageService --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index fe44191c8..80fa2c496 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -1472,7 +1472,7 @@ class CloudController(object): return image def _format_image(self, image): - """Convert from format defined by BaseImageService to S3 format.""" + """Convert from format defined by GlanceImageService to S3 format.""" i = {} image_type = self._image_type(image.get('container_format')) ec2_id = self.image_ec2_id(image.get('id'), image_type) -- cgit From 0c737cb60980b8db74496e7914322f567950c2c3 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Fri, 2 Sep 2011 01:07:30 -0400 Subject: Removing xml functions that are no longer called. --- nova/api/openstack/versions.py | 105 ++++++----------------------------------- 1 file changed, 15 insertions(+), 90 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py index 0766e1eb7..31dd9dc11 100644 --- a/nova/api/openstack/versions.py +++ b/nova/api/openstack/versions.py @@ -19,7 +19,6 @@ from datetime import datetime from lxml import etree import webob import webob.dec -from xml.dom import minidom import nova.api.openstack.views.versions from nova.api.openstack import wsgi @@ -188,32 +187,25 @@ class VersionsXMLSerializer(wsgi.XMLDictSerializer): for version in data['versions']: version_elem = etree.SubElement(root, 'version') self._populate_version(version_elem, version) - return etree.tostring(root, encoding='UTF-8') + return self._to_xml(root) def show(self, data): root = etree.Element('version', nsmap=self.NSMAP) self._populate_version(root, data['version']) - return etree.tostring(root, encoding='UTF-8') + return self._to_xml(root) def multi(self, data): root = etree.Element('choices', nsmap=self.NSMAP) for version in data['choices']: version_elem = etree.SubElement(root, 'version') self._populate_version(version_elem, version) - return etree.tostring(root, encoding='UTF-8') + return self._to_xml(root) class VersionsAtomSerializer(wsgi.XMLDictSerializer): NSMAP = {None: xmlutil.XMLNS_ATOM} - #TODO(wwolf): this is temporary until we get rid of toprettyxml - # in the base class (XMLDictSerializer), which I plan to do in - # another branch - def to_xml_string(self, node, has_atom=False): - self._add_xmlns(node, has_atom) - return node.toxml(encoding='UTF-8') - def __init__(self, metadata=None, xmlns=None): self.metadata = metadata or {} if not xmlns: @@ -221,14 +213,6 @@ class VersionsAtomSerializer(wsgi.XMLDictSerializer): else: self.xmlns = xmlns - def _create_text_elem(self, name, text, type=None): - elem = self._xml_doc.createElement(name) - if type: - elem.setAttribute('type', type) - elem_text = self._xml_doc.createTextNode(text) - elem.appendChild(elem_text) - return elem - def _get_most_recent_update(self, versions): recent = None for version in versions: @@ -246,47 +230,21 @@ class VersionsAtomSerializer(wsgi.XMLDictSerializer): link_href = link_href.rstrip('/') return link_href.rsplit('/', 1)[0] + '/' - def _create_detail_meta(self, root, version): - title = self._create_text_elem('title', "About This Version", - type='text') - - updated = self._create_text_elem('updated', version['updated']) - - uri = version['links'][0]['href'] - id = self._create_text_elem('id', uri) - - link = self._xml_doc.createElement('link') - link.setAttribute('rel', 'self') - link.setAttribute('href', uri) - - author = self._xml_doc.createElement('author') - author_name = self._create_text_elem('name', 'Rackspace') - author_uri = self._create_text_elem('uri', 'http://www.rackspace.com/') - author.appendChild(author_name) - author.appendChild(author_uri) - - root.appendChild(title) - root.appendChild(updated) - root.appendChild(id) - root.appendChild(author) - root.appendChild(link) - - def _create_feed(self, versions): + 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 = 'Available API Versions' + 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 - base_url = self._get_base_url(versions[0]['links'][0]['href']) - etree.SubElement(feed, 'id').text = base_url + etree.SubElement(feed, 'id').text = feed_id link = etree.SubElement(feed, 'link') link.set('rel', 'self') - link.set('href', base_url) + link.set('href', feed_id) author = etree.SubElement(feed, 'author') etree.SubElement(author, 'name').text = 'Rackspace' @@ -319,50 +277,17 @@ class VersionsAtomSerializer(wsgi.XMLDictSerializer): version['updated']) return entry - def _create_version_entries(self, root, versions): - for version in versions: - entry = self._xml_doc.createElement('entry') - - id = self._create_text_elem('id', version['links'][0]['href']) - title = self._create_text_elem('title', - 'Version %s' % version['id'], - type='text') - updated = self._create_text_elem('updated', version['updated']) - - entry.appendChild(id) - entry.appendChild(title) - entry.appendChild(updated) - - for link in version['links']: - link_node = self._xml_doc.createElement('link') - link_node.setAttribute('rel', link['rel']) - link_node.setAttribute('href', link['href']) - if 'type' in link: - link_node.setAttribute('type', link['type']) - - entry.appendChild(link_node) - - content = self._create_text_elem('content', - 'Version %s %s (%s)' % - (version['id'], - version['status'], - version['updated']), - type='text') - - entry.appendChild(content) - root.appendChild(entry) - def index(self, data): - feed = self._create_feed(data['versions']) - return etree.tostring(feed, encoding='UTF-8') + 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) def show(self, data): - self._xml_doc = minidom.Document() - node = self._xml_doc.createElementNS(self.xmlns, 'feed') - self._create_detail_meta(node, data['version']) - self._create_version_entries(node, [data['version']]) - - return self.to_xml_string(node) + version = data['version'] + feed_id = version['links'][0]['href'] + feed = self._create_feed([version], 'About This Version', feed_id) + return self._to_xml(feed) class VersionsHeadersSerializer(wsgi.ResponseHeadersSerializer): -- cgit From 9b35957eef001ae1c3329e9197984d3aca0da787 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Sun, 4 Sep 2011 05:39:21 -0400 Subject: Fixing xml serialization of limits resource. --- nova/api/openstack/limits.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index 2896ac396..f6df94eea 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -87,25 +87,25 @@ class LimitsXMLSerializer(wsgi.XMLDictSerializer): def __init__(self): pass - def _create_rates_node(self, rates_dict): + def _create_rates_node(self, rates): rates_elem = etree.Element('rates', nsmap=self.NSMAP) - for rate in rates_dict.items(): + for rate in rates: rate_node = etree.SubElement(rates_elem, 'rate') rate_node.set('uri', rate['uri']) rate_node.set('regex', rate['regex']) - for limit in rate['limits']: + for limit in rate['limit']: limit_elem = etree.SubElement(rate_node, 'limit') - limit_elem.set('value', str(rate['value'])) - limit_elem.set('verb', str(rate['verb'])) - limit_elem.set('remaining', str(rate['remaining'])) - limit_elem.set('unit', str(rate['unit'])) - limit_elem.set('next-available', str(rate['next-available'])) + limit_elem.set('value', str(limit['value'])) + limit_elem.set('verb', str(limit['verb'])) + limit_elem.set('remaining', str(limit['remaining'])) + limit_elem.set('unit', str(limit['unit'])) + limit_elem.set('next-available', str(limit['next-available'])) return rates_elem def _create_absolute_node(self, absolute_dict): absolute_elem = etree.Element('absolute', nsmap=self.NSMAP) for key, value in absolute_dict.items(): - limit_elem = etree.SubElement(rate_node, 'limit') + limit_elem = etree.SubElement(absolute_elem, 'limit') limit_elem.set('name', str(key)) limit_elem.set('value', str(value)) return absolute_elem @@ -114,16 +114,16 @@ class LimitsXMLSerializer(wsgi.XMLDictSerializer): """Populate a limits xml element from a dict.""" rates_elem = self._create_rates_node( - limits_dict.get('rates', {})) + limits_dict.get('rate', [])) limits_elem.append(rates_elem) absolutes_elem = self._create_absolute_node( - limits_dict.get('absolutes', {})) + limits_dict.get('absolute', {})) limits_elem.append(absolutes_elem) def index(self, limits_dict): limits = etree.Element('limits', nsmap=self.NSMAP) - self._populate_limits(limits, limits_dict) + self._populate_limits(limits, limits_dict['limits']) return self._to_xml(limits) -- cgit From 7d923d28d673340af1e168f99e7178cd01ea3ac3 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Mon, 5 Sep 2011 09:32:14 +0200 Subject: Make a security group rule that references another security group return ipPermission for each of tcp, udp, and icmp. --- nova/api/ec2/cloud.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index fe44191c8..14f5f69e2 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -572,18 +572,25 @@ class CloudController(object): g['ipPermissions'] = [] for rule in group.rules: r = {} - r['ipProtocol'] = rule.protocol - r['fromPort'] = rule.from_port - r['toPort'] = rule.to_port r['groups'] = [] r['ipRanges'] = [] if rule.group_id: source_group = db.security_group_get(context, rule.group_id) r['groups'] += [{'groupName': source_group.name, 'userId': source_group.project_id}] + for protocol, min_port, max_port in (('icmp', -1, -1), + ('tcp', 1, 65535), + ('udp', 1, 65536)): + r['ipProtocol'] = protocol + r['fromPort'] = min_port + r['toPort'] = max_port + g['ipPermissions'] += [dict(r)] else: + r['ipProtocol'] = rule.protocol + r['fromPort'] = rule.from_port + r['toPort'] = rule.to_port r['ipRanges'] += [{'cidrIp': rule.cidr}] - g['ipPermissions'] += [r] + g['ipPermissions'] += [r] return g def _rule_args_to_dict(self, context, kwargs): -- cgit From 2c16115e236760f3933eadd3a5d7d20dda39866d Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 6 Sep 2011 07:31:39 -0400 Subject: Update the v1.0 rescue admin action and the v1.1 rescue extension to generate 'adminPass'. Fixes an issue where rescue commands were broken on XenServer. lp#838518 --- nova/api/openstack/contrib/rescue.py | 13 ++++++++++--- nova/api/openstack/create_instance_helper.py | 4 ++-- nova/api/openstack/servers.py | 20 ++++++++++++++------ 3 files changed, 26 insertions(+), 11 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/rescue.py b/nova/api/openstack/contrib/rescue.py index 3de128895..f140664b3 100644 --- a/nova/api/openstack/contrib/rescue.py +++ b/nova/api/openstack/contrib/rescue.py @@ -18,11 +18,14 @@ import webob from webob import exc from nova import compute +from nova import flags from nova import log as logging +from nova import utils from nova.api.openstack import extensions as exts from nova.api.openstack import faults +FLAGS = flags.FLAGS LOG = logging.getLogger("nova.api.contrib.rescue") @@ -30,7 +33,7 @@ def wrap_errors(fn): """"Ensure errors are not passed along.""" def wrapped(*args): try: - fn(*args) + return fn(*args) except Exception, e: return faults.Fault(exc.HTTPInternalServerError()) return wrapped @@ -46,9 +49,13 @@ class Rescue(exts.ExtensionDescriptor): def _rescue(self, input_dict, req, instance_id): """Rescue an instance.""" context = req.environ["nova.context"] - self.compute_api.rescue(context, instance_id) + if input_dict['rescue'] and 'adminPass' in input_dict['rescue']: + password = input_dict["rescue"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) + self.compute_api.rescue(context, instance_id, rescue_password=password) - return webob.Response(status_int=202) + return {'adminPass': password} @wrap_errors def _unrescue(self, input_dict, req, instance_id): diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 29e071609..9c331f2bc 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -316,14 +316,14 @@ class CreateInstanceHelper(object): def _get_server_admin_password_old_style(self, server): """ Determine the admin password for a server on creation """ - return utils.generate_password(16) + return utils.generate_password(FLAGS.password_length) def _get_server_admin_password_new_style(self, server): """ Determine the admin password for a server on creation """ password = server.get('adminPass') if password is None: - return utils.generate_password(16) + return utils.generate_password(FLAGS.password_length) if not isinstance(password, basestring) or password == '': msg = _("Invalid adminPass") raise exc.HTTPBadRequest(explanation=msg) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 977958f5d..3506a4bca 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -477,16 +477,22 @@ class Controller(object): return webob.Response(status_int=202) @scheduler_api.redirect_handler - def rescue(self, req, id): + def rescue(self, req, id, body={}): """Permit users to rescue the server.""" context = req.environ["nova.context"] try: - self.compute_api.rescue(context, id) + if 'rescue' in body and body['rescue'] and \ + 'adminPass' in body['rescue']: + password = body["rescue"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) + self.compute_api.rescue(context, id, rescue_password=password) except Exception: readable = traceback.format_exc() LOG.exception(_("compute.api::rescue %s"), readable) raise exc.HTTPUnprocessableEntity() - return webob.Response(status_int=202) + + return {'adminPass': password} @scheduler_api.redirect_handler def unrescue(self, req, id): @@ -618,7 +624,7 @@ class ControllerV10(Controller): LOG.debug(msg) raise exc.HTTPBadRequest(explanation=msg) - password = utils.generate_password(16) + password = utils.generate_password(FLAGS.password_length) try: self.compute_api.rebuild(context, instance_id, image_id, password) @@ -760,8 +766,10 @@ class ControllerV11(Controller): self._validate_metadata(metadata) self._decode_personalities(personalities) - password = info["rebuild"].get("adminPass", - utils.generate_password(16)) + if 'rebuild' in info and 'adminPass' in info['rebuild']: + password = info["rebuild"]["adminPass"] + else: + password = utils.generate_password(FLAGS.password_length) try: self.compute_api.rebuild(context, instance_id, image_href, -- cgit From 71b7298788045d4832dd8ec44cba3785955aa847 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Tue, 6 Sep 2011 15:21:15 +0000 Subject: Implement deferred delete of instances --- nova/api/openstack/contrib/deferred_delete.py | 76 +++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 nova/api/openstack/contrib/deferred_delete.py (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/deferred_delete.py b/nova/api/openstack/contrib/deferred_delete.py new file mode 100644 index 000000000..54d8aac2a --- /dev/null +++ b/nova/api/openstack/contrib/deferred_delete.py @@ -0,0 +1,76 @@ +# Copyright 2011 Openstack, LLC +# 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. + +"""The deferred instance delete extension.""" + +import webob +from webob import exc + +from nova import compute +from nova import exception +from nova import log as logging +from nova.api.openstack import common +from nova.api.openstack import extensions +from nova.api.openstack import faults +from nova.api.openstack import servers + + +LOG = logging.getLogger("nova.api.contrib.deferred-delete") + + +class Deferred_delete(extensions.ExtensionDescriptor): + def __init__(self): + super(Deferred_delete, self).__init__() + self.compute_api = compute.API() + + def _restore(self, input_dict, req, instance_id): + "Restore a previously deleted instance." + + context = req.environ["nova.context"] + self.compute_api.restore(context, instance_id) + return webob.Response(status_int=202) + + def _force_delete(self, input_dict, req, instance_id): + "Force delete of instance before deferred cleanup." + + context = req.environ["nova.context"] + self.compute_api.force_delete(context, instance_id) + return webob.Response(status_int=202) + + def get_name(self): + return "DeferredDelete" + + def get_alias(self): + return "os-deferred-delete" + + def get_description(self): + return "Instance deferred delete" + + def get_namespace(self): + return "http://docs.openstack.org/ext/deferred-delete/api/v1.1" + + def get_updated(self): + return "2011-09-01T00:00:00+00:00" + + def get_actions(self): + """Return the actions the extension adds, as required by contract.""" + actions = [ + extensions.ActionExtension("servers", "restore", + self._restore), + extensions.ActionExtension("servers", "forceDelete", + self._force_delete), + ] + + return actions -- cgit From 35e0ae794f6cd5fda47c4795da34f9f57f52614f Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 6 Sep 2011 15:16:40 -0400 Subject: further cleanup --- nova/api/openstack/image_metadata.py | 58 +++++++++++++++++------------------- 1 file changed, 28 insertions(+), 30 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index 4d615ea96..adb6bee4b 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -17,6 +17,7 @@ from webob import exc +from nova import exception from nova import flags from nova import image from nova import utils @@ -33,21 +34,22 @@ class Controller(object): def __init__(self): self.image_service = image.get_default_image_service() - def _get_metadata(self, context, image_id, image=None): - if not image: - image = self.image_service.show(context, image_id) - metadata = image.get('properties', {}) - return metadata + def _get_image(self, context, image_id): + try: + return self.image_service.show(context, image_id) + except exception.NotFound: + msg = _("Image not found.") + raise exc.HTTPNotFound(explanation=msg) def index(self, req, image_id): """Returns the list of metadata for a given instance""" context = req.environ['nova.context'] - metadata = self._get_metadata(context, image_id) + metadata = self._get_image(context, image_id)['properties'] return dict(metadata=metadata) def show(self, req, image_id, id): context = req.environ['nova.context'] - metadata = self._get_metadata(context, image_id) + metadata = self._get_image(context, image_id)['properties'] if id in metadata: return {'meta': {id: metadata[id]}} else: @@ -55,15 +57,13 @@ class Controller(object): def create(self, req, image_id, body): context = req.environ['nova.context'] - img = self.image_service.show(context, image_id) - metadata = self._get_metadata(context, image_id, img) + image = self._get_image(context, image_id) if 'metadata' in body: for key, value in body['metadata'].iteritems(): - metadata[key] = value - common.check_img_metadata_quota_limit(context, metadata) - img['properties'] = metadata - self.image_service.update(context, image_id, img, None) - return dict(metadata=metadata) + image['properties'][key] = value + common.check_img_metadata_quota_limit(context, image['properties']) + self.image_service.update(context, image_id, image, None) + return dict(metadata=image['properties']) def update(self, req, image_id, id, body): context = req.environ['nova.context'] @@ -80,32 +80,30 @@ class Controller(object): if len(meta) > 1: expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) - img = self.image_service.show(context, image_id) - metadata = self._get_metadata(context, image_id, img) - metadata[id] = meta[id] - common.check_img_metadata_quota_limit(context, metadata) - img['properties'] = metadata - self.image_service.update(context, image_id, img, None) + + image = self._get_image(context, image_id) + image['properties'][id] = meta[id] + common.check_img_metadata_quota_limit(context, image['properties']) + self.image_service.update(context, image_id, image, None) return dict(meta=meta) def update_all(self, req, image_id, body): context = req.environ['nova.context'] - img = self.image_service.show(context, image_id) + image = self._get_image(context, image_id) metadata = body.get('metadata', {}) common.check_img_metadata_quota_limit(context, metadata) - img['properties'] = metadata - self.image_service.update(context, image_id, img, None) + image['properties'] = metadata + self.image_service.update(context, image_id, image, None) return dict(metadata=metadata) def delete(self, req, image_id, id): context = req.environ['nova.context'] - img = self.image_service.show(context, image_id) - metadata = self._get_metadata(context, image_id) - if not id in metadata: - raise exc.HTTPNotFound() - metadata.pop(id) - img['properties'] = metadata - self.image_service.update(context, image_id, img, None) + image = self._get_image(context, image_id) + if not id in image['properties']: + msg = _("Invalid metadata key") + raise exc.HTTPNotFound(explanation=msg) + image['properties'].pop(id) + self.image_service.update(context, image_id, image, None) def create_resource(): -- cgit From 9b12a6c5ec11fd6ef3e110e6f0574762060ac809 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 6 Sep 2011 15:19:37 -0400 Subject: Fixes an issue where 'invalid literal for int' would occur when listing images after making a v1.1 server snapshot (with a UUID). v1.1 image id's are now treated as strings (not integer ID's). The v1.0 API still tries to treat image id's as integers but doesn't fail miserably if they are uuid's either. This should pave the way for image ID's as uuids and more closely matches the v1.1 spec with regards to images and the server refs they contain. --- nova/api/openstack/common.py | 24 +++++------------------- nova/api/openstack/views/images.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 19 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index d743a66ef..dba3ec8e9 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -185,30 +185,16 @@ def limited_by_marker(items, request, max_limit=FLAGS.osapi_max_limit): def get_id_from_href(href): - """Return the id portion of a url as an int. + """Return the id or uuid portion of a url. Given: 'http://www.foo.com/bar/123?q=4' - Returns: 123 + Returns: '123' - In order to support local hrefs, the href argument can be just an id: - Given: '123' - Returns: 123 + Given: 'http://www.foo.com/bar/abc123?q=4' + Returns: 'abc123' """ - LOG.debug(_("Attempting to treat %(href)s as an integer ID.") % locals()) - - try: - return int(href) - except ValueError: - pass - - LOG.debug(_("Attempting to treat %(href)s as a URL.") % locals()) - - try: - return int(urlparse.urlsplit(href).path.split('/')[-1]) - except ValueError as error: - LOG.debug(_("Failed to parse ID from %(href)s: %(error)s") % locals()) - raise + return urlparse.urlsplit("%s" % href).path.split('/')[-1] def remove_version_from_href(href): diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 21f1b2d3e..20c99124b 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -70,6 +70,7 @@ class ViewBuilder(object): } self._build_server(image, image_obj) + self._build_image_id(image, image_obj) if detail: image.update({ @@ -95,6 +96,12 @@ class ViewBuilderV10(ViewBuilder): except (KeyError, ValueError): pass + def _build_image_id(self, image, image_obj): + try: + image['id'] = int(image_obj['id']) + except ValueError: + pass + class ViewBuilderV11(ViewBuilder): """OpenStack API v1.1 Image Builder""" @@ -118,6 +125,9 @@ class ViewBuilderV11(ViewBuilder): except KeyError: return + def _build_image_id(self, image, image_obj): + image['id'] = "%s" % image_obj['id'] + def generate_href(self, image_id): """Return an href string pointing to this object.""" return os.path.join(self.base_url, self.project_id, -- cgit From 4bf6508a026c62a7aa2423b1910c871ddc3f0916 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 8 Sep 2011 15:26:44 -0400 Subject: converting fix to just address ec2; updating test --- nova/api/ec2/cloud.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 049ca6f93..4f7030a5a 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -1200,8 +1200,10 @@ class CloudController(object): instances.append(instance) else: try: + # always filter out deleted instances + search_opts['deleted'] = False instances = self.compute_api.get_all(context, - search_opts=search_opts) + search_opts=search_opts) except exception.NotFound: instances = [] for instance in instances: -- cgit From aec647b3b42c4cd56a9509c2d1ac25ff12b0664e Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Thu, 8 Sep 2011 16:10:03 -0500 Subject: First pass at adding reboot_type to reboot codepath. --- nova/api/openstack/servers.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index d084ac360..f5447edc5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -334,9 +334,8 @@ class Controller(object): LOG.exception(msg) raise exc.HTTPBadRequest(explanation=msg) try: - # TODO(gundlach): pass reboot_type, support soft reboot in - # virt driver - self.compute_api.reboot(req.environ['nova.context'], id) + self.compute_api.reboot(req.environ['nova.context'], id, + reboot_type) except Exception, e: LOG.exception(_("Error in reboot %s"), e) raise exc.HTTPUnprocessableEntity() -- cgit From a8acd5fbd55ad4cd2cd502e95b2399657fbd162f Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 8 Sep 2011 16:02:10 -0700 Subject: if no public-key is given (--key), do not show public-keys in metadata service --- nova/api/ec2/cloud.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 049ca6f93..c6f24858a 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -304,11 +304,6 @@ class CloudController(object): instance_ref = db.instance_get(ctxt, instance_ref[0]['id']) mpi = self._get_mpi_data(ctxt, instance_ref['project_id']) - if instance_ref['key_name']: - keys = {'0': {'_name': instance_ref['key_name'], - 'openssh-key': instance_ref['key_data']}} - else: - keys = '' hostname = instance_ref['hostname'] host = instance_ref['host'] availability_zone = self._get_availability_zone_by_host(ctxt, host) @@ -336,11 +331,15 @@ class CloudController(object): 'placement': {'availability-zone': availability_zone}, 'public-hostname': hostname, 'public-ipv4': floating_ip or '', - 'public-keys': keys, 'reservation-id': instance_ref['reservation_id'], 'security-groups': security_groups, 'mpi': mpi}} + # public-keys should only show up if it is non-empty (if user specified one) + if instance_ref['key_name']: + data['keys'] = {'0': {'_name': instance_ref['key_name'], + 'openssh-key': instance_ref['key_data']}} + for image_type in ['kernel', 'ramdisk']: if instance_ref.get('%s_id' % image_type): ec2_id = self.image_ec2_id(instance_ref['%s_id' % image_type], -- cgit From f2c887824cd56fe83f4db2bf94279684a1daba05 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 8 Sep 2011 17:42:49 -0700 Subject: metadata key is 'public-keys', not 'keys' --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index c6f24858a..c8ff47864 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -337,7 +337,7 @@ class CloudController(object): # public-keys should only show up if it is non-empty (if user specified one) if instance_ref['key_name']: - data['keys'] = {'0': {'_name': instance_ref['key_name'], + data['public-keys'] = {'0': {'_name': instance_ref['key_name'], 'openssh-key': instance_ref['key_data']}} for image_type in ['kernel', 'ramdisk']: -- cgit From 3202b7a9193796170fbb25a793e40ff14f9b9621 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 8 Sep 2011 18:02:02 -0700 Subject: put key into meta-data, not top level 'data' --- nova/api/ec2/cloud.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index c8ff47864..bb860a131 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -337,8 +337,9 @@ class CloudController(object): # public-keys should only show up if it is non-empty (if user specified one) if instance_ref['key_name']: - data['public-keys'] = {'0': {'_name': instance_ref['key_name'], - 'openssh-key': instance_ref['key_data']}} + data['meta-data']['public-keys'] = { + '0': {'_name': instance_ref['key_name'], + 'openssh-key': instance_ref['key_data']}} for image_type in ['kernel', 'ramdisk']: if instance_ref.get('%s_id' % image_type): -- cgit From b890b992f3013a1959e3c3cdf1f149cacf4e569b Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Thu, 8 Sep 2011 21:30:21 -0400 Subject: Fixing security groups stuff --- nova/api/openstack/servers.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 6159041e8..7532313e5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -920,6 +920,13 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): addresses_elem = self._create_addresses_node( server_dict.get('addresses', {})) server_elem.append(addresses_elem) + groups = server_dict.get('security_groups') + if groups: + groups_elem = etree.SubElement(server_elem, 'security_groups') + for group in groups: + group_elem = etree.SubElement(groups_elem, + 'security_group') + group_elem.set('name', group['name']) for link in server_dict.get('links', []): elem = etree.SubElement(server_elem, @@ -963,19 +970,6 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): self._populate_server(server, server_dict['server'], True) return self._to_xml(server) - def _security_group_to_xml(self, doc, security_group): - node = doc.createElement('security_group') - node.setAttribute('name', str(security_group.get('name'))) - return node - - def _create_security_groups_node(self, xml_doc, security_groups): - security_groups_node = xml_doc.createElement('security_groups') - if security_groups: - for security_group in security_groups: - node = self._security_group_to_xml(xml_doc, security_group) - security_groups_node.appendChild(node) - return security_groups_node - def create_resource(version='1.0'): controller = { -- cgit From 7352e3e1eb7a4d29b556492a208e80439828f211 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 9 Sep 2011 09:48:38 -0400 Subject: removing key_name and config_drive from non-detailed server entity --- nova/api/openstack/views/servers.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index ac09b5864..473dc9e7e 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -145,6 +145,8 @@ class ViewBuilderV11(ViewBuilder): response['server']['accessIPv4'] = inst.get('access_ip_v4') or "" response['server']['accessIPv6'] = inst.get('access_ip_v6') or "" + response['server']['key_name'] = inst.get('key_name', '') + response['server']['config_drive'] = inst.get('config_drive') return response @@ -185,8 +187,6 @@ class ViewBuilderV11(ViewBuilder): def _build_extra(self, response, inst): self._build_links(response, inst) response['uuid'] = inst['uuid'] - response['key_name'] = inst.get('key_name', '') - self._build_config_drive(response, inst) def _build_links(self, response, inst): href = self.generate_href(inst["id"]) @@ -205,9 +205,6 @@ class ViewBuilderV11(ViewBuilder): response["links"] = links - def _build_config_drive(self, response, inst): - response['config_drive'] = inst.get('config_drive') - def generate_href(self, server_id): """Create an url that refers to a specific server id.""" return os.path.join(self.base_url, self.project_id, -- cgit From 5ddfd1c1add955aa14c5e5174b1942eb8f748031 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 9 Sep 2011 10:20:36 -0700 Subject: shorten comment to < 79 chars --- nova/api/ec2/cloud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index bb860a131..eafecbca8 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -335,7 +335,7 @@ class CloudController(object): 'security-groups': security_groups, 'mpi': mpi}} - # public-keys should only show up if it is non-empty (if user specified one) + # public-keys should be in meta-data only if user specified one if instance_ref['key_name']: data['meta-data']['public-keys'] = { '0': {'_name': instance_ref['key_name'], -- cgit From 3279898ffcd66870b8523e5281993311a513f0f9 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Fri, 9 Sep 2011 18:33:36 +0000 Subject: Use triple quotes for docstrings to be consistent --- nova/api/openstack/contrib/deferred_delete.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/deferred_delete.py b/nova/api/openstack/contrib/deferred_delete.py index 54d8aac2a..0dbee682e 100644 --- a/nova/api/openstack/contrib/deferred_delete.py +++ b/nova/api/openstack/contrib/deferred_delete.py @@ -36,14 +36,14 @@ class Deferred_delete(extensions.ExtensionDescriptor): self.compute_api = compute.API() def _restore(self, input_dict, req, instance_id): - "Restore a previously deleted instance." + """Restore a previously deleted instance.""" context = req.environ["nova.context"] self.compute_api.restore(context, instance_id) return webob.Response(status_int=202) def _force_delete(self, input_dict, req, instance_id): - "Force delete of instance before deferred cleanup." + """Force delete of instance before deferred cleanup.""" context = req.environ["nova.context"] self.compute_api.force_delete(context, instance_id) -- cgit From 2351c06f50d4556e564a7b0abb1653805e661330 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Fri, 9 Sep 2011 18:38:01 +0000 Subject: Make whitespace consistent --- nova/api/openstack/contrib/deferred_delete.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/deferred_delete.py b/nova/api/openstack/contrib/deferred_delete.py index 0dbee682e..13ee5511e 100644 --- a/nova/api/openstack/contrib/deferred_delete.py +++ b/nova/api/openstack/contrib/deferred_delete.py @@ -67,10 +67,10 @@ class Deferred_delete(extensions.ExtensionDescriptor): def get_actions(self): """Return the actions the extension adds, as required by contract.""" actions = [ - extensions.ActionExtension("servers", "restore", - self._restore), - extensions.ActionExtension("servers", "forceDelete", - self._force_delete), + extensions.ActionExtension("servers", "restore", + self._restore), + extensions.ActionExtension("servers", "forceDelete", + self._force_delete), ] return actions -- cgit From 65a0cc41b1b9ead5acd3128a4a6202bb02e3a6e5 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Fri, 9 Sep 2011 17:25:45 -0400 Subject: fixing image status mapping --- nova/api/openstack/views/images.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 21f1b2d3e..8983b2957 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -37,17 +37,18 @@ class ViewBuilder(object): def _format_status(self, image): """Update the status field to standardize format.""" status_mapping = { - 'pending': 'QUEUED', - 'decrypting': 'PREPARING', - 'untarring': 'SAVING', - 'available': 'ACTIVE', - 'killed': 'FAILED', + 'active': 'ACTIVE', + 'queued': 'SAVING', + 'saving': 'SAVING', + 'deleted': 'DELETED', + 'pending_delete': 'DELETED', + 'killed': 'ERROR', } try: - image['status'] = status_mapping[image['status']].upper() + image['status'] = status_mapping[image['status']] except KeyError: - image['status'] = image['status'].upper() + image['status'] = 'UNKNOWN' def _build_server(self, image, image_obj): """Indicates that you must use a ViewBuilder subclass.""" -- cgit From c890890c7ccbc7df1060d59747089b5e39c5510a Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sat, 10 Sep 2011 17:11:21 +0900 Subject: api/ec2: make get_metadata() return correct mappings The entries corresponding to volumes are in the form of ebs': --- nova/api/ec2/cloud.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4f7030a5a..50c551f86 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -272,11 +272,17 @@ class CloudController(object): mappings = {} mappings['ami'] = block_device.strip_dev(root_device_name) mappings['root'] = root_device_name + ebs_devices = [] - # 'ephemeralN' and 'swap' + # 'ephemeralN', 'swap' and ebs for bdm in db.block_device_mapping_get_all_by_instance( ctxt, instance_ref['id']): - if (bdm['volume_id'] or bdm['snapshot_id'] or bdm['no_device']): + if bdm['no_device']: + continue + + # ebs volume case + if (bdm['volume_id'] or bdm['snapshot_id']): + ebs_devices.append(bdm['device_name']) continue virtual_name = bdm['virtual_name'] @@ -286,6 +292,16 @@ class CloudController(object): if block_device.is_swap_or_ephemeral(virtual_name): mappings[virtual_name] = bdm['device_name'] + # NOTE(yamahata): I'm not sure how ebs device should be numbered. + # Right now sort by device name for deterministic + # result. + if ebs_devices: + nebs = 0 + ebs_devices.sort() + for ebs in ebs_devices: + mappings['ebs%d' % nebs] = ebs + nebs += 1 + return mappings def get_metadata(self, address): -- cgit From d8abe79da8dde2667936ee97d88d30d5cf0e6d7f Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sat, 10 Sep 2011 17:11:31 +0900 Subject: api/ec2/ebs: make metadata returns correct swap and ephemeral0 --- nova/api/ec2/cloud.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 50c551f86..0ad2d94f3 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -272,6 +272,12 @@ class CloudController(object): mappings = {} mappings['ami'] = block_device.strip_dev(root_device_name) mappings['root'] = root_device_name + default_local_device = instance_ref.get('default_local_device') + if default_local_device: + mappings['ephemeral0'] = default_local_device + default_swap_device = instance_ref.get('default_swap_device') + if default_swap_device: + mappings['swap'] = default_swap_device ebs_devices = [] # 'ephemeralN', 'swap' and ebs -- cgit From 9482275a60ab8caa546ec402f61c60b9f5e7e33f Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sat, 10 Sep 2011 13:56:54 -0400 Subject: Update GlanceClient, GlanceImageService, and Glance Xen plugin to work with Glance keystone. --- nova/api/auth.py | 1 + nova/api/openstack/create_instance_helper.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/auth.py b/nova/api/auth.py index cd0d38b3f..f73cae01e 100644 --- a/nova/api/auth.py +++ b/nova/api/auth.py @@ -70,6 +70,7 @@ class KeystoneContext(wsgi.Middleware): project_id, roles=roles, auth_token=auth_token, + strategy='keystone', remote_address=remote_address) req.environ['nova.context'] = ctx diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 67e669c17..e27ddf78b 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -92,7 +92,8 @@ class CreateInstanceHelper(object): if str(image_href).startswith(req.application_url): image_href = image_href.split('/').pop() try: - image_service, image_id = nova.image.get_image_service(image_href) + image_service, image_id = nova.image.get_image_service(context, + image_href) kernel_id, ramdisk_id = self._get_kernel_ramdisk_from_image( req, image_service, image_id) images = set([str(x['id']) for x in image_service.index(context)]) -- cgit From 6fafde1fa52d1eba0c77f403b9e2a6f77b5379cd Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 12 Sep 2011 09:20:11 -0400 Subject: Make quoting consistent. --- nova/api/openstack/contrib/rescue.py | 2 +- nova/api/openstack/servers.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/rescue.py b/nova/api/openstack/contrib/rescue.py index f140664b3..2e5dbab73 100644 --- a/nova/api/openstack/contrib/rescue.py +++ b/nova/api/openstack/contrib/rescue.py @@ -50,7 +50,7 @@ class Rescue(exts.ExtensionDescriptor): """Rescue an instance.""" context = req.environ["nova.context"] if input_dict['rescue'] and 'adminPass' in input_dict['rescue']: - password = input_dict["rescue"]["adminPass"] + password = input_dict['rescue']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) self.compute_api.rescue(context, instance_id, rescue_password=password) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 49f267eb9..2c6f9724c 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -483,7 +483,7 @@ class Controller(object): try: if 'rescue' in body and body['rescue'] and \ 'adminPass' in body['rescue']: - password = body["rescue"]["adminPass"] + password = body['rescue']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) self.compute_api.rescue(context, id, rescue_password=password) @@ -767,7 +767,7 @@ class ControllerV11(Controller): self._decode_personalities(personalities) if 'rebuild' in info and 'adminPass' in info['rebuild']: - password = info["rebuild"]["adminPass"] + password = info['rebuild']['adminPass'] else: password = utils.generate_password(FLAGS.password_length) -- cgit From 050be203cb43a12ca430eadfd30c87690b33b9cf Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Mon, 12 Sep 2011 20:10:57 +0000 Subject: Add support for vendor content types --- nova/api/openstack/versions.py | 7 +++++++ nova/api/openstack/wsgi.py | 20 +++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py index e2f892fb6..04d9915ca 100644 --- a/nova/api/openstack/versions.py +++ b/nova/api/openstack/versions.py @@ -100,13 +100,17 @@ class Versions(wsgi.Resource): body_serializers = { 'application/atom+xml': VersionsAtomSerializer(metadata=metadata), 'application/xml': VersionsXMLSerializer(metadata=metadata), + 'application/vnd.openstack.compute+xml': + VersionsXMLSerializer(metadata=metadata), } serializer = wsgi.ResponseSerializer( body_serializers=body_serializers, headers_serializer=headers_serializer) supported_content_types = ('application/json', + 'application/vnd.openstack.compute+json', 'application/xml', + 'application/vnd.openstack.compute+xml', 'application/atom+xml') deserializer = VersionsRequestDeserializer( supported_content_types=supported_content_types) @@ -383,12 +387,15 @@ def create_resource(version='1.0'): body_serializers = { 'application/xml': VersionsXMLSerializer(), + 'application/vnd.openstack.compute+xml': VersionsXMLSerializer(), 'application/atom+xml': VersionsAtomSerializer(), } serializer = wsgi.ResponseSerializer(body_serializers) supported_content_types = ('application/json', + 'application/vnd.openstack.compute+json', 'application/xml', + 'application/vnd.openstack.compute+xml', 'application/atom+xml') deserializer = wsgi.RequestDeserializer( supported_content_types=supported_content_types) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 8641e960a..ee6b87403 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -28,8 +28,12 @@ class Request(webob.Request): Based on the query extension then the Accept header. """ + LOG.info('supported = %s' % repr(supported_content_types)) supported_content_types = supported_content_types or \ - ('application/json', 'application/xml') + ('application/json', + 'application/vnd.openstack.compute+json', + 'application/xml', + 'application/vnd.openstack.compute+xml') parts = self.path.rsplit('.', 1) if len(parts) > 1: @@ -51,7 +55,10 @@ class Request(webob.Request): if not "Content-Type" in self.headers: return None - allowed_types = ("application/xml", "application/json") + allowed_types = ('application/json', + 'application/vnd.openstack.compute+json', + 'application/xml', + 'application/vnd.openstack.compute+xml') content_type = self.content_type if content_type not in allowed_types: @@ -191,11 +198,16 @@ class RequestDeserializer(object): supported_content_types=None): self.supported_content_types = supported_content_types or \ - ('application/json', 'application/xml') + ('application/json', + 'application/vnd.openstack.compute+json', + 'application/xml', + 'application/vnd.openstack.compute+xml') self.body_deserializers = { 'application/xml': XMLDeserializer(), + 'application/vnd.openstack.compute+xml': XMLDeserializer(), 'application/json': JSONDeserializer(), + 'application/vnd.openstack.compute+json': JSONDeserializer(), } self.body_deserializers.update(body_deserializers or {}) @@ -409,7 +421,9 @@ class ResponseSerializer(object): def __init__(self, body_serializers=None, headers_serializer=None): self.body_serializers = { 'application/xml': XMLDictSerializer(), + 'application/vnd.openstack.compute+xml': XMLDictSerializer(), 'application/json': JSONDictSerializer(), + 'application/vnd.openstack.compute+json': JSONDictSerializer(), } self.body_serializers.update(body_serializers or {}) -- cgit From e411fcd647e3cdcf415465288e527aecfd026fc5 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 13 Sep 2011 14:15:29 -0400 Subject: add additional data to flavor's ViewBuilder This adds missing fields that were trying to be used by python-novaclient. Previously, 'nova flavor-list' would have empty columns for fields other than 'disk' and 'ram'. Now all columns are filled in appropriately. --- nova/api/openstack/views/flavors.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py index aea34b424..023acce0d 100644 --- a/nova/api/openstack/views/flavors.py +++ b/nova/api/openstack/views/flavors.py @@ -48,6 +48,10 @@ class ViewBuilder(object): detail = { "ram": flavor_obj["memory_mb"], "disk": flavor_obj["local_gb"], + "swap": flavor_obj["swap"], + "rxtx_quota": flavor_obj["rxtx_quota"], + "rxtx_cap": flavor_obj["rxtx_cap"], + "vcpus": flavor_obj["vcpus"], } detail.update(simple) -- cgit From 877d92845a5d2002c4adc0c8398469e66fd0907e Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Tue, 13 Sep 2011 17:06:15 -0400 Subject: make tests pass --- nova/api/openstack/views/flavors.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py index 023acce0d..4c5e2c1e6 100644 --- a/nova/api/openstack/views/flavors.py +++ b/nova/api/openstack/views/flavors.py @@ -48,12 +48,11 @@ class ViewBuilder(object): detail = { "ram": flavor_obj["memory_mb"], "disk": flavor_obj["local_gb"], - "swap": flavor_obj["swap"], - "rxtx_quota": flavor_obj["rxtx_quota"], - "rxtx_cap": flavor_obj["rxtx_cap"], - "vcpus": flavor_obj["vcpus"], } + for key in ( "vcpus", "swap", "rxtx_quota", "rxtx_cap"): + detail[key] = flavor_obj.get(key,"") + detail.update(simple) return detail -- cgit From fa4dbed251f8ec0b0a44407005feaa86539a7823 Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Wed, 14 Sep 2011 10:21:45 -0500 Subject: remove unused import, make call to network api to get vifs for the instance --- nova/api/openstack/contrib/virtual_interfaces.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index dab61efc8..8c25ba285 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -16,11 +16,11 @@ """The virtual interfaces extension.""" from webob import exc -import webob from nova import compute from nova import exception from nova import log as logging +from nova import network from nova.api.openstack import common from nova.api.openstack import extensions from nova.api.openstack import faults @@ -51,6 +51,7 @@ class ServerVirtualInterfaceController(object): def __init__(self): self.compute_api = compute.API() + self.network_api = network.API() super(ServerVirtualInterfaceController, self).__init__() def _items(self, req, server_id, entity_maker): @@ -62,7 +63,8 @@ class ServerVirtualInterfaceController(object): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - vifs = instance['virtual_interfaces'] + vifs = self.network_api.get_vifs_by_instance(context, + instance['id']) limited_list = common.limited(vifs, req) res = [entity_maker(context, vif) for vif in limited_list] return {'virtual_interfaces': res} -- cgit From 4f27ce297ac74ac1c11f959cb44eb4bb3cd4b81a Mon Sep 17 00:00:00 2001 From: Jason Koelker Date: Wed, 14 Sep 2011 10:29:46 -0500 Subject: no need for the instance at all or compute --- nova/api/openstack/contrib/virtual_interfaces.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 8c25ba285..1981cd372 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -15,15 +15,10 @@ """The virtual interfaces extension.""" -from webob import exc - -from nova import compute -from nova import exception from nova import log as logging from nova import network from nova.api.openstack import common from nova.api.openstack import extensions -from nova.api.openstack import faults from nova.api.openstack import wsgi @@ -50,7 +45,6 @@ class ServerVirtualInterfaceController(object): """ def __init__(self): - self.compute_api = compute.API() self.network_api = network.API() super(ServerVirtualInterfaceController, self).__init__() @@ -58,13 +52,7 @@ class ServerVirtualInterfaceController(object): """Returns a list of VIFs, transformed through entity_maker.""" context = req.environ['nova.context'] - try: - instance = self.compute_api.get(context, server_id) - except exception.NotFound: - return faults.Fault(exc.HTTPNotFound()) - - vifs = self.network_api.get_vifs_by_instance(context, - instance['id']) + vifs = self.network_api.get_vifs_by_instance(context, server_id) limited_list = common.limited(vifs, req) res = [entity_maker(context, vif) for vif in limited_list] return {'virtual_interfaces': res} -- cgit From d36e59f4480265741018a1fd5160f5262b7e9331 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 11:54:13 -0400 Subject: add extension description for FlavorExtraData --- nova/api/openstack/contrib/flavorextradata.py | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 nova/api/openstack/contrib/flavorextradata.py (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/flavorextradata.py b/nova/api/openstack/contrib/flavorextradata.py new file mode 100644 index 000000000..d0554c7b4 --- /dev/null +++ b/nova/api/openstack/contrib/flavorextradata.py @@ -0,0 +1,46 @@ +# Copyright 2011 Canonical Ltd. +# 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. + +""" +The Flavor extra data extension +Openstack API version 1.1 lists "name", "ram", "disk", "vcpus" as flavor +attributes. This extension adds to that list: + rxtx_cap + rxtx_quota + swap +""" + +from nova.api.openstack import extensions + + +class Flavorextradata(extensions.ExtensionDescriptor): + """The Flavor extra data extension for the OpenStack API.""" + + def get_name(self): + return "FlavorExtraData" + + def get_alias(self): + return "os-flavor-extra-data" + + def get_description(self): + return "Provide additional data for flavors" + + def get_namespace(self): + return "http://docs.openstack.org/ext/flavor_extra_data/api/v1.1" + + def get_updated(self): + return "2011-09-14T00:00:00+00:00" + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 -- cgit From c20228123c1774a1e2aa1b4ee7155a62336f5934 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 11:55:18 -0400 Subject: fix white space for pep8 --- nova/api/openstack/views/flavors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py index 4c5e2c1e6..def969a6c 100644 --- a/nova/api/openstack/views/flavors.py +++ b/nova/api/openstack/views/flavors.py @@ -50,8 +50,8 @@ class ViewBuilder(object): "disk": flavor_obj["local_gb"], } - for key in ( "vcpus", "swap", "rxtx_quota", "rxtx_cap"): - detail[key] = flavor_obj.get(key,"") + for key in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"): + detail[key] = flavor_obj.get(key, "") detail.update(simple) -- cgit From 9f83b51ae2afeb45ed9bdcb8c3b63ced78f8050e Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 16:19:18 +0000 Subject: Remove debugging --- nova/api/openstack/wsgi.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 6eb1953b4..c342f6267 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -29,7 +29,6 @@ class Request(webob.Request): Based on the query extension then the Accept header. """ - LOG.info('supported = %s' % repr(supported_content_types)) supported_content_types = supported_content_types or \ ('application/json', 'application/vnd.openstack.compute+json', -- cgit From 092ff28b9f141368aed0d719140212e5fc8652f8 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 12:25:47 -0400 Subject: add attributes to xml api --- nova/api/openstack/flavors.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index fd36060da..c6c9f096f 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -90,6 +90,9 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer): flavor_node.setAttribute('ram', str(flavor['ram'])) flavor_node.setAttribute('disk', str(flavor['disk'])) + for attr in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"): + flavor_node.setAttribute(attr, str(flavor.get(attr,""))) + link_nodes = self._create_link_nodes(xml_doc, flavor['links']) for link_node in link_nodes: flavor_node.appendChild(link_node) -- cgit From 34a08d831418b934f4cceaae69dbf17d90ecd5e0 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 14 Sep 2011 12:32:00 -0400 Subject: removing toprettyxml --- nova/api/openstack/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index bdcadcb99..588fc030b 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -316,7 +316,7 @@ class XMLDictSerializer(DictSerializer): def to_xml_string(self, node, has_atom=False): self._add_xmlns(node, has_atom) - return node.toprettyxml(indent=' ', encoding='UTF-8') + 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 -- cgit From 95e06c5d88f5500805fb8d9505a4db61560bf8e1 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 12:59:10 -0400 Subject: update variable name after merge: flavor_node -> flavor_elem --- nova/api/openstack/flavors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index dd77f1a05..a419b7ec2 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -94,7 +94,7 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer): flavor_elem.set('disk', str(flavor_dict['disk'])) for attr in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"): - flavor_node.setAttribute(attr, str(flavor.get(attr,""))) + flavor_elem.setAttribute(attr, str(flavor.get(attr,""))) for link in flavor_dict.get('links', []): elem = etree.SubElement(flavor_elem, -- cgit From 2b41dd235b50e3003a42e0b860c5915d06d86071 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 17:23:40 +0000 Subject: Map vendor content types to their standard content type before serializing or deserializing. This is so we don't have to litter the code with both types when they are treated identically --- nova/api/openstack/wsgi.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index c342f6267..1c4724c8f 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -19,6 +19,21 @@ XMLNS_ATOM = 'http://www.w3.org/2005/Atom' LOG = logging.getLogger('nova.api.openstack.wsgi') +# The vendor content types should serialize identically to the non-vendor +# content types. So to avoid littering the code with both options, we +# map the vendor to the other when looking up the type +_CONTENT_TYPE_MAP = { + 'application/vnd.openstack.compute+json': 'application/json', + 'application/vnd.openstack.compute+xml': 'application/xml', +} + +_SUPPORTED_CONTENT_TYPES = ( + 'application/json', + 'application/vnd.openstack.compute+json', + 'application/xml', + 'application/vnd.openstack.compute+xml', +) + class Request(webob.Request): """Add some Openstack API-specific logic to the base webob.Request.""" @@ -30,10 +45,7 @@ class Request(webob.Request): """ supported_content_types = supported_content_types or \ - ('application/json', - 'application/vnd.openstack.compute+json', - 'application/xml', - 'application/vnd.openstack.compute+xml') + _SUPPORTED_CONTENT_TYPES parts = self.path.rsplit('.', 1) if len(parts) > 1: @@ -55,10 +67,7 @@ class Request(webob.Request): if not "Content-Type" in self.headers: return None - allowed_types = ('application/json', - 'application/vnd.openstack.compute+json', - 'application/xml', - 'application/vnd.openstack.compute+xml') + allowed_types = _SUPPORTED_CONTENT_TYPES content_type = self.content_type if content_type not in allowed_types: @@ -198,16 +207,11 @@ class RequestDeserializer(object): supported_content_types=None): self.supported_content_types = supported_content_types or \ - ('application/json', - 'application/vnd.openstack.compute+json', - 'application/xml', - 'application/vnd.openstack.compute+xml') + _SUPPORTED_CONTENT_TYPES self.body_deserializers = { 'application/xml': XMLDeserializer(), - 'application/vnd.openstack.compute+xml': XMLDeserializer(), 'application/json': JSONDeserializer(), - 'application/vnd.openstack.compute+json': JSONDeserializer(), } self.body_deserializers.update(body_deserializers or {}) @@ -261,6 +265,7 @@ class RequestDeserializer(object): def get_body_deserializer(self, content_type): try: + content_type = _CONTENT_TYPE_MAP.get(content_type, content_type) return self.body_deserializers[content_type] except (KeyError, TypeError): raise exception.InvalidContentType(content_type=content_type) @@ -425,9 +430,7 @@ class ResponseSerializer(object): def __init__(self, body_serializers=None, headers_serializer=None): self.body_serializers = { 'application/xml': XMLDictSerializer(), - 'application/vnd.openstack.compute+xml': XMLDictSerializer(), 'application/json': JSONDictSerializer(), - 'application/vnd.openstack.compute+json': JSONDictSerializer(), } self.body_serializers.update(body_serializers or {}) @@ -452,6 +455,7 @@ class ResponseSerializer(object): def serialize_body(self, response, data, content_type, action): response.headers['Content-Type'] = content_type if data is not None: + content_type = _CONTENT_TYPE_MAP.get(content_type, content_type) serializer = self.get_body_serializer(content_type) response.body = serializer.serialize(data, action) -- cgit From 1b836a4159bd324572f71dab4abcef5a8d3292e5 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 17:29:28 +0000 Subject: Add copyright --- nova/api/openstack/wsgi.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 1c4724c8f..c68a57cb5 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -1,3 +1,19 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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 json from lxml import etree -- cgit From d678d8c4d024a4154ecd2ea77a42063ad1253364 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 17:32:33 +0000 Subject: Remove unnecessary vendor content types now that they are mapped to standard content types automatically --- nova/api/openstack/versions.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/versions.py b/nova/api/openstack/versions.py index f4ae498b4..75a1d0ba4 100644 --- a/nova/api/openstack/versions.py +++ b/nova/api/openstack/versions.py @@ -101,8 +101,6 @@ class Versions(wsgi.Resource): body_serializers = { 'application/atom+xml': VersionsAtomSerializer(metadata=metadata), 'application/xml': VersionsXMLSerializer(metadata=metadata), - 'application/vnd.openstack.compute+xml': - VersionsXMLSerializer(metadata=metadata), } serializer = wsgi.ResponseSerializer( body_serializers=body_serializers, @@ -307,7 +305,6 @@ def create_resource(version='1.0'): body_serializers = { 'application/xml': VersionsXMLSerializer(), - 'application/vnd.openstack.compute+xml': VersionsXMLSerializer(), 'application/atom+xml': VersionsAtomSerializer(), } serializer = wsgi.ResponseSerializer(body_serializers) -- cgit From 8638db07c4ad2177249a70708969c7a1cba09037 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 17:55:15 +0000 Subject: Don't report the wrong content type if a mapped type doesn't exist --- nova/api/openstack/wsgi.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index c68a57cb5..fad516d4d 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -281,8 +281,8 @@ class RequestDeserializer(object): def get_body_deserializer(self, content_type): try: - content_type = _CONTENT_TYPE_MAP.get(content_type, content_type) - return self.body_deserializers[content_type] + ctype = _CONTENT_TYPE_MAP.get(content_type, content_type) + return self.body_deserializers[ctype] except (KeyError, TypeError): raise exception.InvalidContentType(content_type=content_type) @@ -471,13 +471,13 @@ class ResponseSerializer(object): def serialize_body(self, response, data, content_type, action): response.headers['Content-Type'] = content_type if data is not None: - content_type = _CONTENT_TYPE_MAP.get(content_type, content_type) serializer = self.get_body_serializer(content_type) response.body = serializer.serialize(data, action) def get_body_serializer(self, content_type): try: - return self.body_serializers[content_type] + ctype = _CONTENT_TYPE_MAP.get(content_type, content_type) + return self.body_serializers[ctype] except (KeyError, TypeError): raise exception.InvalidContentType(content_type=content_type) -- cgit From 9ce2e4f80f249d58622b7235aec55e823f9cd6c8 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 14:37:32 -0400 Subject: flavor_elem.setAttribute -> flavor_elem.set, flavor -> flavor_dict --- nova/api/openstack/flavors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index a419b7ec2..0c435ebeb 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -94,7 +94,7 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer): flavor_elem.set('disk', str(flavor_dict['disk'])) for attr in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"): - flavor_elem.setAttribute(attr, str(flavor.get(attr,""))) + flavor_elem.set(attr, str(flavor_dict.get(attr,""))) for link in flavor_dict.get('links', []): elem = etree.SubElement(flavor_elem, -- cgit From 74a1045dd133fe708cb0f42bd4fae4198ee337ff Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 14:51:55 -0400 Subject: add necessary fields to flavor.rng schema --- nova/api/openstack/schemas/v1.1/flavor.rng | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/schemas/v1.1/flavor.rng b/nova/api/openstack/schemas/v1.1/flavor.rng index a00e4e9ee..6d3adc8dc 100644 --- a/nova/api/openstack/schemas/v1.1/flavor.rng +++ b/nova/api/openstack/schemas/v1.1/flavor.rng @@ -4,6 +4,10 @@ + + + + -- cgit From aa0361c41d2e2feff18915ac93107727f52b15ca Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 14 Sep 2011 14:58:47 -0400 Subject: fix pep8 whitespace error --- nova/api/openstack/flavors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index 0c435ebeb..8a310c900 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -94,7 +94,7 @@ class FlavorXMLSerializer(wsgi.XMLDictSerializer): flavor_elem.set('disk', str(flavor_dict['disk'])) for attr in ("vcpus", "swap", "rxtx_quota", "rxtx_cap"): - flavor_elem.set(attr, str(flavor_dict.get(attr,""))) + flavor_elem.set(attr, str(flavor_dict.get(attr, ""))) for link in flavor_dict.get('links', []): elem = etree.SubElement(flavor_elem, -- cgit From cecc822c0bc10c8d5cc5168329ae04172c6e609e Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Wed, 14 Sep 2011 12:33:51 -0700 Subject: Use the correct method to get a builder. --- nova/api/openstack/contrib/volumes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/volumes.py b/nova/api/openstack/contrib/volumes.py index d62225e58..9d4254f1f 100644 --- a/nova/api/openstack/contrib/volumes.py +++ b/nova/api/openstack/contrib/volumes.py @@ -372,8 +372,7 @@ class BootFromVolumeController(servers.ControllerV11): for key in ['instance_type', 'image_ref']: inst[key] = extra_values[key] - builder = self._get_view_builder(req) - server = builder.build(inst, is_detail=True) + server = self._build_view(req, inst, is_detail=True) server['server']['adminPass'] = extra_values['password'] return server -- cgit From a5b339fb75e1e5f525a758ea1fb2fb35d1b9044a Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 14 Sep 2011 22:31:00 +0000 Subject: Cleanup state management to use vm_state instead of task_state Add schedule_delete() method so delete() actually does what it says it does --- nova/api/ec2/cloud.py | 1 + nova/api/openstack/common.py | 3 +++ nova/api/openstack/servers.py | 10 ++++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 0efb90d6e..ee9d658e8 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -89,6 +89,7 @@ _STATE_DESCRIPTION_MAP = { vm_states.BUILDING: 'pending', vm_states.REBUILDING: 'pending', vm_states.DELETED: 'terminated', + vm_states.SOFT_DELETE: 'terminated', vm_states.STOPPED: 'stopped', vm_states.MIGRATING: 'migrate', vm_states.RESIZING: 'resize', diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index a836a584c..66e18c557 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -78,6 +78,9 @@ _STATE_MAP = { vm_states.DELETED: { 'default': 'DELETED', }, + vm_states.SOFT_DELETE: { + 'default': 'DELETED', + }, } diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 5affd1f33..c81deb3ac 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -169,6 +169,12 @@ class Controller(object): server['server']['adminPass'] = extra_values['password'] return server + def _delete(self, context, id): + if FLAGS.reclaim_instance_interval: + self.compute_api.soft_delete(context, id) + else: + self.compute_api.delete(context, id) + @scheduler_api.redirect_handler def update(self, req, id, body): """Update server then pass on to version-specific controller""" @@ -566,7 +572,7 @@ class ControllerV10(Controller): def delete(self, req, id): """ Destroys a server """ try: - self.compute_api.delete(req.environ['nova.context'], id) + self._delete(req.environ['nova.context'], id) except exception.NotFound: raise exc.HTTPNotFound() return webob.Response(status_int=202) @@ -644,7 +650,7 @@ class ControllerV11(Controller): def delete(self, req, id): """ Destroys a server """ try: - self.compute_api.delete(req.environ['nova.context'], id) + self._delete(req.environ['nova.context'], id) except exception.NotFound: raise exc.HTTPNotFound() -- cgit From 63c4cc459a5b27040610ca9071ac578ecd43c059 Mon Sep 17 00:00:00 2001 From: Soren Hansen Date: Thu, 15 Sep 2011 18:15:19 +0200 Subject: Return three rules for describe_security_groups if a rule refers to a foreign group, but does not specify protocol/port. --- nova/api/ec2/cloud.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 14f5f69e2..5c876a3b7 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -578,13 +578,19 @@ class CloudController(object): source_group = db.security_group_get(context, rule.group_id) r['groups'] += [{'groupName': source_group.name, 'userId': source_group.project_id}] - for protocol, min_port, max_port in (('icmp', -1, -1), - ('tcp', 1, 65535), - ('udp', 1, 65536)): - r['ipProtocol'] = protocol - r['fromPort'] = min_port - r['toPort'] = max_port + if rule.protocol: + r['ipProtocol'] = rule.protocol + r['fromPort'] = rule.from_port + r['toPort'] = rule.to_port g['ipPermissions'] += [dict(r)] + else: + for protocol, min_port, max_port in (('icmp', -1, -1), + ('tcp', 1, 65535), + ('udp', 1, 65536)): + r['ipProtocol'] = protocol + r['fromPort'] = min_port + r['toPort'] = max_port + g['ipPermissions'] += [dict(r)] else: r['ipProtocol'] = rule.protocol r['fromPort'] = rule.from_port -- cgit From 340c0dd5250d6cdee08ccf86cf7a1e88cfbeea07 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Sun, 18 Sep 2011 16:01:28 -0400 Subject: catching AttributeError and adding tests --- nova/api/openstack/servers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 0ef246852..9152d92bf 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -151,6 +151,7 @@ class Controller(object): def create(self, req, body): """ Creates a new server for a given user """ + if 'server' in body: body['server']['key_name'] = self._get_key_name(req, body) @@ -656,7 +657,11 @@ class ControllerV11(Controller): def _get_key_name(self, req, body): if 'server' in body: - return body['server'].get('key_name') + try: + return body['server'].get('key_name') + except AttributeError: + msg = _("Malformed server entity") + raise exc.HTTPBadRequest(explanation=msg) def _image_ref_from_req_data(self, data): try: -- cgit From 4c29835b6e5bd89460846588994f75543e5c235a Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Sun, 18 Sep 2011 17:01:44 -0400 Subject: removing extra newline --- nova/api/openstack/servers.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 9152d92bf..856c3c613 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -151,7 +151,6 @@ class Controller(object): def create(self, req, body): """ Creates a new server for a given user """ - if 'server' in body: body['server']['key_name'] = self._get_key_name(req, body) -- cgit From 13e346df0bc88279242ed1c56ad39b36a22c8a39 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 20 Sep 2011 13:56:15 -0500 Subject: Refactored alternate link generation. --- nova/api/openstack/views/images.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 86e8d7f3a..c41123f5e 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -18,6 +18,10 @@ import os.path from nova.api.openstack import common +from nova import flags + + +FLAGS = flags.FLAGS class ViewBuilder(object): @@ -139,6 +143,7 @@ class ViewBuilderV11(ViewBuilder): image = ViewBuilder.build(self, image_obj, detail) href = self.generate_href(image_obj["id"]) bookmark = self.generate_bookmark(image_obj["id"]) + alternate = self.generate_alternate(image_obj["id"]) image["links"] = [ { @@ -149,6 +154,11 @@ class ViewBuilderV11(ViewBuilder): "rel": "bookmark", "href": bookmark, }, + { + "rel": "alternate", + "type": "application/vnd.openstack.image", + "href": alternate, + }, ] @@ -158,6 +168,13 @@ class ViewBuilderV11(ViewBuilder): return image def generate_bookmark(self, image_id): - """Create an url that refers to a specific flavor id.""" + """Create a URL that refers to a specific flavor id.""" return os.path.join(common.remove_version_from_href(self.base_url), self.project_id, "images", str(image_id)) + + def generate_alternate(self, image_id): + """Create an alternate link for a specific flavor id.""" + # TODO(jk0): This will eventually need to take SSL into consideration + # when supported in glance. + return "http://%s:%d/%s/images/%s" % (FLAGS.glance_host, + FLAGS.glance_port, self.project_id, str(image_id)) -- cgit From c07b24cdd6606950b0a4fef730c277b499eb65f4 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 20 Sep 2011 15:21:06 -0500 Subject: Fixed unit tests with some minor refactoring. --- nova/api/openstack/views/images.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index c41123f5e..659bfd463 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -18,10 +18,7 @@ import os.path from nova.api.openstack import common -from nova import flags - - -FLAGS = flags.FLAGS +from nova import utils class ViewBuilder(object): @@ -174,7 +171,7 @@ class ViewBuilderV11(ViewBuilder): def generate_alternate(self, image_id): """Create an alternate link for a specific flavor id.""" - # TODO(jk0): This will eventually need to take SSL into consideration - # when supported in glance. - return "http://%s:%d/%s/images/%s" % (FLAGS.glance_host, - FLAGS.glance_port, self.project_id, str(image_id)) + glance_url = utils.generate_glance_url() + + return "%s/%s/images/%s" % (glance_url, self.project_id, + str(image_id)) -- cgit From 10589faa5fbde09689641d5e64ddd41a341eaade Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 20 Sep 2011 16:11:49 -0500 Subject: Include 'type' in XML output. --- nova/api/openstack/images.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 4340cbe3e..d579ae716 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -251,6 +251,8 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): elem = etree.SubElement(image_elem, '{%s}link' % xmlutil.XMLNS_ATOM) elem.set('rel', link['rel']) + if 'type' in link: + elem.set('type', link['type']) elem.set('href', link['href']) return image_elem -- cgit From 43604520de242b46d8d6bdab1fada84bac57b4dc Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 20 Sep 2011 15:17:03 -0700 Subject: remove keystone --- nova/api/auth.py | 31 ------------------------------- nova/api/ec2/__init__.py | 48 ------------------------------------------------ 2 files changed, 79 deletions(-) (limited to 'nova/api') diff --git a/nova/api/auth.py b/nova/api/auth.py index cd0d38b3f..a94f28739 100644 --- a/nova/api/auth.py +++ b/nova/api/auth.py @@ -43,34 +43,3 @@ class InjectContext(wsgi.Middleware): def __call__(self, req): req.environ['nova.context'] = self.context return self.application - - -class KeystoneContext(wsgi.Middleware): - """Make a request context from keystone headers""" - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - try: - user_id = req.headers['X_USER'] - except KeyError: - return webob.exc.HTTPUnauthorized() - # get the roles - roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')] - project_id = req.headers['X_TENANT'] - # Get the auth token - auth_token = req.headers.get('X_AUTH_TOKEN', - req.headers.get('X_STORAGE_TOKEN')) - - # Build a context, including the auth_token... - remote_address = getattr(req, 'remote_address', '127.0.0.1') - remote_address = req.remote_addr - if FLAGS.use_forwarded_for: - remote_address = req.headers.get('X-Forwarded-For', remote_address) - ctx = context.RequestContext(user_id, - project_id, - roles=roles, - auth_token=auth_token, - remote_address=remote_address) - - req.environ['nova.context'] = ctx - return self.application diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 3b217e62e..57097fdf4 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -142,54 +142,6 @@ class Lockout(wsgi.Middleware): return res -class ToToken(wsgi.Middleware): - """Authenticate an EC2 request with keystone and convert to token.""" - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - # Read request signature and access id. - try: - signature = req.params['Signature'] - access = req.params['AWSAccessKeyId'] - except KeyError: - raise webob.exc.HTTPBadRequest() - - # Make a copy of args for authentication and signature verification. - auth_params = dict(req.params) - # Not part of authentication args - auth_params.pop('Signature') - - # Authenticate the request. - creds = {'ec2Credentials': {'access': access, - 'signature': signature, - 'host': req.host, - 'verb': req.method, - 'path': req.path, - 'params': auth_params, - }} - creds_json = utils.dumps(creds) - headers = {'Content-Type': 'application/json'} - o = urlparse(FLAGS.keystone_ec2_url) - if o.scheme == "http": - conn = httplib.HTTPConnection(o.netloc) - else: - conn = httplib.HTTPSConnection(o.netloc) - conn.request('POST', o.path, body=creds_json, headers=headers) - response = conn.getresponse().read() - conn.close() - - # NOTE(vish): We could save a call to keystone by - # having keystone return token, tenant, - # user, and roles from this call. - result = utils.loads(response) - # TODO(vish): check for errors - - token_id = result['auth']['token']['id'] - # Authenticated! - req.headers['X-Auth-Token'] = token_id - return self.application - - class NoAuth(wsgi.Middleware): """Add user:project as 'nova.context' to WSGI environ.""" -- cgit From 7e7880ea2c088c330a4e27c70ef23915c5b81d4a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 20 Sep 2011 15:52:03 -0700 Subject: remove keystone url flag --- nova/api/ec2/__init__.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 57097fdf4..14bf8676a 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -46,9 +46,6 @@ flags.DEFINE_integer('lockout_minutes', 15, 'Number of minutes to lockout if triggered.') flags.DEFINE_integer('lockout_window', 15, 'Number of minutes for lockout window.') -flags.DEFINE_string('keystone_ec2_url', - 'http://localhost:5000/v2.0/ec2tokens', - 'URL to get token from ec2 request.') flags.DECLARE('use_forwarded_for', 'nova.api.auth') -- cgit From 43f59d597c8c7e4cabe4f2dd3e7f9eeddff450e6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 21 Sep 2011 09:34:59 -0700 Subject: make sure kwargs are strings and not unicode --- nova/api/ec2/ec2utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/ec2/ec2utils.py b/nova/api/ec2/ec2utils.py index bcdf2ba78..aac8f9a1e 100644 --- a/nova/api/ec2/ec2utils.py +++ b/nova/api/ec2/ec2utils.py @@ -116,7 +116,7 @@ def dict_from_dotted_str(items): args = {} for key, value in items: parts = key.split(".") - key = camelcase_to_underscore(parts[0]) + key = str(camelcase_to_underscore(parts[0])) if isinstance(value, str) or isinstance(value, unicode): # NOTE(vish): Automatically convert strings back # into their respective values -- cgit