Merge lp:~justin-fathomdb/nova/skip-validation-openstack11 into lp:~hudson-openstack/nova/trunk

Proposed by justinsb
Status: Work in progress
Proposed branch: lp:~justin-fathomdb/nova/skip-validation-openstack11
Merge into: lp:~hudson-openstack/nova/trunk
Prerequisite: lp:~justin-fathomdb/nova/check-xsd
Diff against target: 151 lines (+82/-0)
4 files modified
nova/api/openstack/servers.py (+10/-0)
nova/api/openstack/validation.py (+8/-0)
nova/tests/api/openstack/test_servers.py (+36/-0)
nova/wsgi.py (+28/-0)
To merge this branch: bzr merge lp:~justin-fathomdb/nova/skip-validation-openstack11
Reviewer Review Type Date Requested Status
Dan Prince (community) Needs Fixing
Christopher MacGown (community) Approve
termie (community) Approve
Review via email: mp+56702@code.launchpad.net

Description of the change

While the OS API 1.1 schema is broken, let's have a flag to skip validation of it

To post a comment you must log in.
Revision history for this message
justinsb (justin-fathomdb) wrote :

This branch also has an additional pre-req (though it probably doesn't need it) - the osapi-xml-serialization branch. Hence the diff below is not yet very useful until the pre-reqs merge. It's really just this bit:

 +# NOTE(justinsb): Until the OS 1.1 schema is fixed, don't bother checking it
30 +flags.DEFINE_bool('validate_openstack_11',
31 + False,
32 + 'Should we validate openstack 1.1 schema?')
33

+ if xmlns == common.XML_NS_V11:
41 + if not FLAGS.validate_openstack_11:
42 + return True
43 +
44

Revision history for this message
termie (termie) wrote :

Ah, I see here where the flag I was discussing in the other patch is defined.

As a somewhat arbitrary stylistic approach for XML in python, I feel that the current best library is etree rather than minidom, the syntax is much more pythonic (and no mixedCase) and requires less push-ups than DOM. Not gating this patch in any way, but worth looking into.

For example, most of the foo.getAttribute('bar', 'baz') would just be foo.get('bar', 'baz')

review: Approve
Revision history for this message
Christopher MacGown (0x44) wrote :

This lgtm.

review: Approve
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

The prerequisite lp:~justin-fathomdb/nova/check-xsd has not yet been merged into lp:nova.

Revision history for this message
Dan Prince (dan-prince) wrote :

Hi Justin,

I get a conflict when trying to merge this branch w/ trunk:

Text conflict in nova/wsgi.py

review: Needs Fixing
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

The prerequisite lp:~justin-fathomdb/nova/check-xsd has not yet been merged into lp:nova.

Revision history for this message
Brian Waldon (bcwaldon) wrote :

Quite a few conflicts...

Unmerged revisions

856. By justinsb

Fix pep8

855. By justinsb

Temporary workaround - don't bother validating against the broken OpenStack 1.1 schema

854. By justinsb

Better formed output: if an order is specified for elements, follow the order

853. By justinsb

Merged with lp:~rackspace-titan/nova/osapi-xml-serialization

852. By justinsb

Merged with lp:~justin-fathomdb/nova/bug740576 and thereby with trunk

851. By justinsb

For now, tolerate the stuff that's broken and dial back the tests so that we don't have to raise 200 bugs yet

850. By justinsb

Imported 1.1 schema from http://bazaar.launchpad.net/~annegentle/openstack-manuals/trunk/files/head:/doc/source/docbkx/openstack-compute-api/

849. By justinsb

Added validation code

848. By justinsb

Merged with trunk

847. By justinsb

Moved CloudServers v1.0 under nova/api/openstack/schemas

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/api/openstack/servers.py'
2--- nova/api/openstack/servers.py 2011-04-06 21:02:16 +0000
3+++ nova/api/openstack/servers.py 2011-04-07 07:07:33 +0000
4@@ -55,6 +55,16 @@
5 "imageRef"],
6 "link": ["rel", "type", "href"],
7 },
8+ "elements": {
9+ "server": ["metadata", "addresses", "personality"],
10+ },
11+ "dict_collections": {
12+ "metadata": {"item_name": "meta", "item_key": "key"},
13+ },
14+ "list_collections": {
15+ "public": {"item_name": "ip", "item_key": "addr"},
16+ "private": {"item_name": "ip", "item_key": "addr"},
17+ },
18 },
19 }
20
21
22=== modified file 'nova/api/openstack/validation.py'
23--- nova/api/openstack/validation.py 2011-04-07 07:07:33 +0000
24+++ nova/api/openstack/validation.py 2011-04-07 07:07:33 +0000
25@@ -39,6 +39,10 @@
26 flags.DEFINE_bool('raise_error_on_validation_warnings',
27 False,
28 'Treat XML validation failures as errors?')
29+# NOTE(justinsb): Until the OS 1.1 schema is fixed, don't bother checking it
30+flags.DEFINE_bool('validate_openstack_11',
31+ False,
32+ 'Should we validate openstack 1.1 schema?')
33
34
35 class OutputValidator(object):
36@@ -70,6 +74,10 @@
37 LOG.warning(_("No XML namespace for XML: %s") % xml_text)
38 return False
39
40+ if xmlns == common.XML_NS_V11:
41+ if not FLAGS.validate_openstack_11:
42+ return True
43+
44 xmlschema = common.load_xml_schema(xmlns)
45 if not xmlschema:
46 LOG.warning(_("Unknown XML namespace: %s") % xmlns)
47
48=== modified file 'nova/tests/api/openstack/test_servers.py'
49--- nova/tests/api/openstack/test_servers.py 2011-04-04 17:56:19 +0000
50+++ nova/tests/api/openstack/test_servers.py 2011-04-07 07:07:33 +0000
51@@ -192,6 +192,26 @@
52 print res_dict['server']
53 self.assertEqual(res_dict['server']['links'], expected_links)
54
55+ def test_get_server_by_id_with_addresses_xml(self):
56+ private = "192.168.0.3"
57+ public = ["1.2.3.4"]
58+ new_return_server = return_server_with_addresses(private, public)
59+ self.stubs.Set(nova.db.api, 'instance_get', new_return_server)
60+ req = webob.Request.blank('/v1.0/servers/1')
61+ req.headers['Accept'] = 'application/xml'
62+ res = req.get_response(fakes.wsgi_app())
63+ dom = minidom.parseString(res.body)
64+ server = dom.childNodes[0]
65+ self.assertEquals(server.nodeName, 'server')
66+ self.assertEquals(server.getAttribute('id'), '1')
67+ self.assertEquals(server.getAttribute('name'), 'server1')
68+ (public,) = server.getElementsByTagName('public')
69+ (ip,) = public.getElementsByTagName('ip')
70+ self.assertEquals(ip.getAttribute('addr'), '1.2.3.4')
71+ (private,) = server.getElementsByTagName('private')
72+ (ip,) = private.getElementsByTagName('ip')
73+ self.assertEquals(ip.getAttribute('addr'), '192.168.0.3')
74+
75 def test_get_server_by_id_with_addresses(self):
76 private = "192.168.0.3"
77 public = ["1.2.3.4"]
78@@ -618,6 +638,22 @@
79 res = req.get_response(fakes.wsgi_app())
80 self.assertEqual(res.status_int, 404)
81
82+ def test_get_all_server_details_xml_v1_0(self):
83+ req = webob.Request.blank('/v1.0/servers/detail')
84+ req.headers['Accept'] = 'application/xml'
85+ res = req.get_response(fakes.wsgi_app())
86+ print res.body
87+ dom = minidom.parseString(res.body)
88+ for i, server in enumerate(dom.getElementsByTagName('server')):
89+ self.assertEqual(server.getAttribute('id'), str(i))
90+ self.assertEqual(server.getAttribute('hostId'), '')
91+ self.assertEqual(server.getAttribute('name'), 'server%d' % i)
92+ self.assertEqual(server.getAttribute('imageId'), '10')
93+ self.assertEqual(server.getAttribute('status'), 'BUILD')
94+ (meta,) = server.getElementsByTagName('meta')
95+ self.assertEqual(meta.getAttribute('key'), 'seq')
96+ self.assertEqual(meta.firstChild.data.strip(), str(i))
97+
98 def test_get_all_server_details_v1_0(self):
99 req = webob.Request.blank('/v1.0/servers/detail')
100 res = req.get_response(fakes.wsgi_app())
101
102=== modified file 'nova/wsgi.py'
103--- nova/wsgi.py 2011-04-07 07:07:33 +0000
104+++ nova/wsgi.py 2011-04-07 07:07:33 +0000
105@@ -517,6 +517,14 @@
106 result.setAttribute('xmlns', xmlns)
107
108 if type(data) is list:
109+ collections = metadata.get('list_collections', {})
110+ if nodename in collections:
111+ metadata = collections[nodename]
112+ for item in data:
113+ node = doc.createElement(metadata['item_name'])
114+ node.setAttribute(metadata['item_key'], str(item))
115+ result.appendChild(node)
116+ return result
117 singular = metadata.get('plurals', {}).get(nodename, None)
118 if singular is None:
119 if nodename.endswith('s'):
120@@ -527,11 +535,31 @@
121 node = self._to_xml_node(doc, metadata, singular, item)
122 result.appendChild(node)
123 elif type(data) is dict:
124+ collections = metadata.get('dict_collections', {})
125+ if nodename in collections:
126+ metadata = collections[nodename]
127+ for k, v in data.items():
128+ node = doc.createElement(metadata['item_name'])
129+ node.setAttribute(metadata['item_key'], str(k))
130+ text = doc.createTextNode(str(v))
131+ node.appendChild(text)
132+ result.appendChild(node)
133+ return result
134+
135+ # Output each attribute either as an element or as an attribute.
136+ # If the elements are specified, follow that order.
137 attrs = metadata.get('attributes', {}).get(nodename, {})
138+ found_elements = []
139 for k, v in data.items():
140 if k in attrs:
141 result.setAttribute(k, str(v))
142 else:
143+ found_elements.append(k)
144+ elements = metadata.get('elements', {}).get(nodename,
145+ found_elements)
146+ for k in elements:
147+ v = data.get(k, None)
148+ if v is not None:
149 node = self._to_xml_node(doc, metadata, k, v)
150 result.appendChild(node)
151 else: