From 54be28647ac3ad401006bca3069b1dfc1a65d093 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 12 Jul 2011 14:35:09 -0400 Subject: server create deserialization functional and tested --- nova/api/openstack/create_instance_helper.py | 81 ++++-- nova/api/openstack/servers.py | 63 +++- nova/api/openstack/wsgi.py | 21 ++ nova/tests/api/openstack/test_servers.py | 414 ++++++++++++++++++++++++--- 4 files changed, 508 insertions(+), 71 deletions(-) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 2654e3c40..eea973a56 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -180,7 +180,7 @@ class CreateInstanceHelper(object): Overrides normal behavior in the case of xml content """ if request.content_type == "application/xml": - deserializer = ServerCreateRequestXMLDeserializer() + deserializer = ServerXMLDeserializer() return deserializer.deserialize(request.body) else: return self._deserialize(request.body, request.get_content_type()) @@ -295,9 +295,15 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): """Marshal the server attribute of a parsed request""" server = {} server_node = self._find_first_child_named(node, 'server') - for attr in ["name", "imageId", "flavorId", "imageRef", "flavorRef"]: + for attr in ["name", "imageId", "flavorId"]: if server_node.getAttribute(attr): server[attr] = server_node.getAttribute(attr) + image = self._extract_image(server_node) + if image is not None: + server["image"] = image + flavor = self._extract_flavor(server_node) + if flavor is not None: + server["flavor"] = flavor metadata = self._extract_metadata(server_node) if metadata is not None: server["metadata"] = metadata @@ -306,6 +312,56 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): server["personality"] = personality return server + def _extract_image(self, server_node): + """Retrieve an image entity from the server node""" + image_node = self._find_first_child_named(server_node, "image") + if image_node is None: + return None + + image = {} + image_id = image_node.getAttribute('id') + if image_id: + image['id'] = image_id + + image_links = self._extract_links_from_node(image_node) + if len(image_links) > 0: + image['links'] = image_links + + return image + + def _extract_flavor(self, server_node): + """Retrieve a flavor entity from the server node""" + flavor_node = self._find_first_child_named(server_node, "flavor") + if flavor_node is None: + return None + + flavor = {} + flavor_id = flavor_node.getAttribute('id') + if flavor_id: + flavor['id'] = flavor_id + + flavor_links = self._extract_links_from_node(flavor_node) + if len(flavor_links) > 0: + flavor['links'] = flavor_links + + return flavor + + def _extract_links_from_node(self, parent_node): + """Retrieve link entities from a links container provided node""" + links = [] + + for link_node in self._find_children_named(parent_node, 'atom:link'): + link = {} + link_rel = link_node.getAttribute('rel') + if link_rel is not None: + link['rel'] = link_rel + link_href = link_node.getAttribute('href') + if link_href is not None: + link['href'] = link_href + links.append(link) + + return links + def _extract_metadata(self, server_node): """Marshal the metadata attribute of a parsed request""" metadata_node = self._find_first_child_named(server_node, "metadata") @@ -331,24 +387,3 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): item["contents"] = self._extract_text(file_node) personality.append(item) return personality - - def _find_first_child_named(self, parent, name): - """Search a nodes children for the first child with a given name""" - for node in parent.childNodes: - if node.nodeName == name: - return node - return None - - def _find_children_named(self, parent, name): - """Return all of a nodes children who have the given name""" - for node in parent.childNodes: - if node.nodeName == name: - yield node - - def _extract_text(self, node): - """Get the text field contained by the given node""" - if len(node.childNodes) == 1: - child = node.childNodes[0] - if child.nodeType == child.TEXT_NODE: - return child.nodeValue - return "" diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 12af44a8d..f239044ff 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -492,11 +492,68 @@ class ControllerV11(Controller): return faults.Fault(exc.HTTPNotFound()) def _image_ref_from_req_data(self, data): - return data['server']['imageRef'] + try: + image = data['server']['image'] + except (AttributeError, KeyError): + msg = _("Missing image entity") + raise exc.HTTPBadRequest(explanation=msg) + + try: + links = image.get('links', []) + except AttributeError: + msg = _("Malformed image entity") + raise exc.HTTPBadRequest(explanation=msg) + + image_ref = None + for link in links: + try: + if link.get('rel') == 'bookmark': + image_ref = link.get('href') + break + except AttributeError: + msg = _("Malformed image link") + raise exc.HTTPBadRequest(explanation=msg) + + if image_ref is None: + try: + image_ref = image['id'] + except KeyError: + msg = _("Missing id attribute on image entity") + raise exc.HTTPBadRequest(explanation=msg) + + return image_ref def _flavor_id_from_req_data(self, data): - href = data['server']['flavorRef'] - return common.get_id_from_href(href) + try: + flavor = data['server']['flavor'] + except (AttributeError, KeyError): + msg = _("Missing flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + + try: + links = flavor.get('links', []) + except AttributeError: + msg = _("Malformed flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + + flavor_ref = None + for link in links: + try: + if link.get('rel') == 'bookmark': + flavor_ref = link.get('href') + break + except AttributeError: + msg = _("Malformed flavor link") + raise exc.HTTPBadRequest(explanation=msg) + + if flavor_ref is None: + try: + return flavor['id'] + except (KeyError, AttributeError): + msg = _("Missing id attribute in flavor entity") + raise exc.HTTPBadRequest(explanation=msg) + else: + return common.get_id_from_href(flavor_ref) def _get_view_builder(self, req): base_url = req.application_url diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 8eff9e441..0ece2cff0 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -134,6 +134,27 @@ class XMLDeserializer(TextDeserializer): listnames) return result + def _find_first_child_named(self, parent, name): + """Search a nodes children for the first child with a given name""" + for node in parent.childNodes: + if node.nodeName == name: + return node + return None + + def _find_children_named(self, parent, name): + """Return all of a nodes children who have the given name""" + for node in parent.childNodes: + if node.nodeName == name: + yield node + + def _extract_text(self, node): + """Get the text field contained by the given node""" + if len(node.childNodes) == 1: + child = node.childNodes[0] + if child.nodeType == child.TEXT_NODE: + return child.nodeValue + return "" + def default(self, datastring): return {'body': self._from_xml(datastring)} diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 775f66ad0..cb7e03934 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -612,7 +612,7 @@ class ServersTest(test.TestCase): "_get_kernel_ramdisk_from_image", kernel_ramdisk_mapping) self.stubs.Set(nova.compute.api.API, "_find_host", find_host) - def _test_create_instance_helper(self): + def test_create_instance(self): self._setup_for_create_instance() body = dict(server=dict( @@ -626,6 +626,7 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual('server_test', server['name']) @@ -633,10 +634,6 @@ class ServersTest(test.TestCase): self.assertEqual(2, server['flavorId']) self.assertEqual(3, server['imageId']) self.assertEqual(FAKE_UUID, server['uuid']) - self.assertEqual(res.status_int, 200) - - def test_create_instance(self): - self._test_create_instance_helper() def test_create_instance_has_uuid(self): """Tests at the db-layer instead of API layer since that's where the @@ -692,7 +689,27 @@ class ServersTest(test.TestCase): def test_create_instance_no_key_pair(self): fakes.stub_out_key_pair_funcs(self.stubs, have_key_pair=False) - self._test_create_instance_helper() + self._setup_for_create_instance() + + body = dict(server=dict( + name='server_test', imageId=3, flavorId=2, + metadata={'hello': 'world', 'open': 'stack'}, + personality={})) + req = webob.Request.blank('/v1.0/servers') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + + server = json.loads(res.body)['server'] + self.assertEqual(16, len(server['adminPass'])) + self.assertEqual('server_test', server['name']) + self.assertEqual(1, server['id']) + self.assertEqual(2, server['flavorId']) + self.assertEqual(3, server['imageId']) + self.assertEqual(FAKE_UUID, server['uuid']) + self.assertEqual(res.status_int, 200) def test_create_instance_no_name(self): self._setup_for_create_instance() @@ -765,18 +782,34 @@ class ServersTest(test.TestCase): def test_create_instance_v1_1(self): self._setup_for_create_instance() - image_href = 'http://localhost/v1.1/images/2' - flavor_ref = 'http://localhost/v1.1/flavors/3' + image_href = 'http://localhost/v1.1/images/3' + flavor_href = 'http://localhost/v1.1/flavors/2' + body = { 'server': { 'name': 'server_test', - 'imageRef': image_href, - 'flavorRef': flavor_ref, + 'image': { + 'id': 3, + 'links': [ + {'rel': 'bookmark', 'href': image_href}, + ], + }, + 'flavor': { + 'id': 2, + 'links': [ + {'rel': 'bookmark', 'href': flavor_href}, + ], + }, 'metadata': { 'hello': 'world', 'open': 'stack', }, - 'personality': {}, + 'personality': [ + { + "path" : "/etc/banner.txt", + "contents" : "MQ==", + }, + ], }, } @@ -787,40 +820,102 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual('server_test', server['name']) self.assertEqual(1, server['id']) - self.assertEqual(flavor_ref, server['flavorRef']) + self.assertEqual(flavor_href, server['flavorRef']) self.assertEqual(image_href, server['imageRef']) - self.assertEqual(res.status_int, 200) + self.assertFalse('personality' in server) - def test_create_instance_v1_1_bad_href(self): + def test_create_instance_v1_1_image_id(self): self._setup_for_create_instance() - image_href = 'http://localhost/v1.1/images/asdf' + image_id = 2 flavor_ref = 'http://localhost/v1.1/flavors/3' - body = dict(server=dict( - name='server_test', imageRef=image_href, flavorRef=flavor_ref, - metadata={'hello': 'world', 'open': 'stack'}, - personality={})) + body = { + 'server': { + 'name': 'server_test', + 'image': {'id': image_id}, + 'flavor': {'id': 3}, + }, + } + + req = webob.Request.blank('/v1.1/servers') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 200) + server = json.loads(res.body)['server'] + self.assertEqual(flavor_ref, server['flavorRef']) + + def test_create_instance_v1_1_image_link(self): + self._setup_for_create_instance() + + image_ref = 'http://localhost/v1.1/image/3' + body = { + 'server': { + 'name': 'server_test', + 'image': { + 'links':[ + {'rel': 'self', 'href': 'http://google.com'}, + {'rel': 'bookmark', 'href': image_ref}, + ], + }, + 'flavor': {'id': 3}, + }, + } + req = webob.Request.blank('/v1.1/servers') req.method = 'POST' req.body = json.dumps(body) req.headers["content-type"] = "application/json" + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 200) + server = json.loads(res.body)['server'] + self.assertEqual(image_ref, server['imageRef']) + + def test_create_instance_v1_1_no_valid_image(self): + self._setup_for_create_instance() + + body = { + 'server': { + 'name': 'server_test', + 'image': {}, + 'flavor': {'id': 3}, + }, + } + + req = webob.Request.blank('/v1.1/servers') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 400) - def test_create_instance_v1_1_local_href(self): + def test_create_instance_v1_1_flavor_link(self): self._setup_for_create_instance() - image_id = 2 flavor_ref = 'http://localhost/v1.1/flavors/3' + body = { 'server': { 'name': 'server_test', - 'imageRef': image_id, - 'flavorRef': flavor_ref, + 'image': {'id': 3}, + 'flavor': { + 'id': 2, + 'links': [ + {'rel': 'bookmark', 'href': flavor_ref}, + ], + }, }, } @@ -831,11 +926,55 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] - self.assertEqual(1, server['id']) self.assertEqual(flavor_ref, server['flavorRef']) - self.assertEqual(image_id, server['imageRef']) + + def test_create_instance_v1_1_flavor_id(self): + self._setup_for_create_instance() + + flavor_ref = 'http://localhost/v1.1/flavors/2' + + body = { + 'server': { + 'name': 'server_test', + 'image': {'id': 3}, + 'flavor': {'id': 2}, + }, + } + + req = webob.Request.blank('/v1.1/servers') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + server = json.loads(res.body)['server'] + self.assertEqual(flavor_ref, server['flavorRef']) + + def test_create_instance_v1_1_no_valid_flavor(self): + self._setup_for_create_instance() + + body = { + 'server': { + 'name': 'server_test', + 'image': {'id': 3}, + 'flavor': {}, + }, + } + + req = webob.Request.blank('/v1.1/servers') + req.method = 'POST' + req.body = json.dumps(body) + req.headers["content-type"] = "application/json" + + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 400) + + def test_create_instance_with_admin_pass_v1_0(self): self._setup_for_create_instance() @@ -858,7 +997,7 @@ class ServersTest(test.TestCase): self.assertNotEqual(res['server']['adminPass'], body['server']['adminPass']) - def test_create_instance_with_admin_pass_v1_1(self): + def test_create_instance_v1_1_admin_pass(self): self._setup_for_create_instance() image_href = 'http://localhost/v1.1/images/2' @@ -866,8 +1005,8 @@ class ServersTest(test.TestCase): body = { 'server': { 'name': 'server_test', - 'imageRef': image_href, - 'flavorRef': flavor_ref, + 'image': {'id': 3}, + 'flavor': {'id': 3}, 'adminPass': 'testpass', }, } @@ -876,20 +1015,22 @@ class ServersTest(test.TestCase): req.method = 'POST' req.body = json.dumps(body) req.headers['content-type'] = "application/json" + res = req.get_response(fakes.wsgi_app()) + + self.assertEqual(res.status_int, 200) + server = json.loads(res.body)['server'] self.assertEqual(server['adminPass'], body['server']['adminPass']) - def test_create_instance_with_empty_admin_pass_v1_1(self): + def test_create_instance_v1_1_admin_pass_empty(self): self._setup_for_create_instance() - image_href = 'http://localhost/v1.1/images/2' - flavor_ref = 'http://localhost/v1.1/flavors/3' body = { 'server': { 'name': 'server_test', - 'imageRef': image_href, - 'flavorRef': flavor_ref, + 'image': {'id': 3}, + 'flavor': {'id': 3}, 'adminPass': '', }, } @@ -1644,7 +1785,7 @@ class ServersTest(test.TestCase): self.assertEqual(res_dict['server']['status'], 'SHUTOFF') -class TestServerCreateRequestXMLDeserializer(unittest.TestCase): +class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): def setUp(self): self.deserializer = create_instance_helper.ServerXMLDeserializer() @@ -1652,7 +1793,7 @@ class TestServerCreateRequestXMLDeserializer(unittest.TestCase): def test_minimal_request(self): serial_request = """ """ + name="new-server-test" imageId="1" flavorId="1" />""" request = self.deserializer.deserialize(serial_request, 'create') expected = {"server": { "name": "new-server-test", @@ -1924,19 +2065,202 @@ b25zLiINCg0KLVJpY2hhcmQgQmFjaA==""", request = self.deserializer.deserialize(serial_request, 'create') self.assertEqual(request['body'], expected) - def test_request_xmlser_with_flavor_image_href(self): + +class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): + + def setUp(self): + self.deserializer = create_instance_helper.ServerXMLDeserializer() + + def test_minimal_request(self): serial_request = """ - - """ + + + +""" request = self.deserializer.deserialize(serial_request, 'create') - self.assertEquals(request['body']["server"]["flavorRef"], - "http://localhost:8774/v1.1/flavors/1") - self.assertEquals(request['body']["server"]["imageRef"], - "http://localhost:8774/v1.1/images/1") + expected = { + "server": { + "name": "new-server-test", + "image": {"id": "1"}, + "flavor": {"id": "2"}, + }, + } + self.assertEquals(request['body'], expected) + def test_image_link(self): + serial_request = """ + + + + + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": "http://localhost:8774/v1.1/images/2", + }, + ], + }, + "flavor": {"id": "3"}, + }, + } + self.assertEquals(request['body'], expected) + + def test_flavor_link(self): + serial_request = """ + + + + + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": {"id": "1"}, + "flavor": { + "id": "2", + "links": [ + { + "rel": "bookmark", + "href": "http://localhost:8774/v1.1/flavors/3", + }, + ], + }, + }, + } + self.assertEquals(request['body'], expected) + + def test_empty_metadata_personality(self): + serial_request = """ + + + + + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": {"id": "1"}, + "flavor": {"id": "2"}, + "metadata": {}, + "personality": [], + }, + } + self.assertEquals(request['body'], expected) + + def test_multiple_metadata_items(self): + serial_request = """ + + + + + two + snack + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": {"id": "1"}, + "flavor": {"id": "2"}, + "metadata": {"one": "two", "open": "snack"}, + }, + } + self.assertEquals(request['body'], expected) + + def test_multiple_personality_files(self): + serial_request = """ + + + + + MQ== + Mg== + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": {"id": "1"}, + "flavor": {"id": "2"}, + "personality": [ + {"path": "/etc/banner.txt", "contents": "MQ=="}, + {"path": "/etc/hosts", "contents": "Mg=="}, + ], + }, + } + self.assertEquals(request['body'], expected) + + def test_spec_request(self): + serial_request = """ + + + + + + + + Apache1 + + + Mg== + +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "image": { + "id": "52415800-8b69-11e0-9b19-734f6f006e54", + "links": [ + { + "rel": "self", + "href": "http://servers.api.openstack.org/" + \ + "v1.1/1234/images/52415800-8b69-11" + \ + "e0-9b19-734f6f006e54", + }, + { + "rel": "bookmark", + "href": "http://servers.api.openstack.org/" + \ + "1234/images/52415800-8b69-11e0-9b" + \ + "19-734f6f006e54", + }, + ], + }, + "flavor": {"id": "52415800-8b69-11e0-9b19-734f1195ff37"}, + "metadata": {"My Server Name": "Apache1"}, + "personality": [ + { + "path": "/etc/banner.txt", + "contents": "Mg==", + }, + ], + }, + } + self.assertEquals(request['body'], expected) class TestServerInstanceCreation(test.TestCase): -- cgit From 07baabb67d9491da61fa5bfe9adc52f7ff744e22 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 12 Jul 2011 16:02:39 -0400 Subject: cleanup --- nova/api/openstack/create_instance_helper.py | 24 ++++++---------- nova/api/openstack/servers.py | 41 ++++++++++++---------------- nova/tests/api/openstack/test_servers.py | 37 +++++++------------------ 3 files changed, 37 insertions(+), 65 deletions(-) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index eea973a56..e46bc9d98 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -320,12 +320,10 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): image = {} image_id = image_node.getAttribute('id') - if image_id: + if image_id is not None: image['id'] = image_id - image_links = self._extract_links_from_node(image_node) - if len(image_links) > 0: - image['links'] = image_links + image['links'] = self._extract_links_from_node(image_node) return image @@ -340,9 +338,7 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): if flavor_id: flavor['id'] = flavor_id - flavor_links = self._extract_links_from_node(flavor_node) - if len(flavor_links) > 0: - flavor['links'] = flavor_links + flavor['links'] = self._extract_links_from_node(flavor_node) return flavor @@ -351,14 +347,12 @@ class ServerXMLDeserializer(wsgi.XMLDeserializer): links = [] for link_node in self._find_children_named(parent_node, 'atom:link'): - link = {} - link_rel = link_node.getAttribute('rel') - if link_rel is not None: - link['rel'] = link_rel - link_href = link_node.getAttribute('href') - if link_href is not None: - link['href'] = link_href - links.append(link) + link = { + 'rel': link_node.getAttribute('rel'), + 'href': link_node.getAttribute('href'), + } + if link['rel'] is not None and link['href'] is not None: + links.append(link) return links diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index f239044ff..1e8749f56 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -491,10 +491,21 @@ class ControllerV11(Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) + def _href_from_bookmark_links(self, links) + for link in links: + try: + if link.get('rel') == 'bookmark': + href = link.get('href') + if href is not None: + return href + except AttributeError: + msg = _("Malformed link entity") + raise exc.HTTPBadRequest(explanation=msg) + def _image_ref_from_req_data(self, data): try: image = data['server']['image'] - except (AttributeError, KeyError): + except (TypeError, KeyError): msg = _("Missing image entity") raise exc.HTTPBadRequest(explanation=msg) @@ -504,29 +515,21 @@ class ControllerV11(Controller): msg = _("Malformed image entity") raise exc.HTTPBadRequest(explanation=msg) - image_ref = None - for link in links: - try: - if link.get('rel') == 'bookmark': - image_ref = link.get('href') - break - except AttributeError: - msg = _("Malformed image link") - raise exc.HTTPBadRequest(explanation=msg) + image_ref = self._href_from_bookmark_links(links) if image_ref is None: try: - image_ref = image['id'] + return image['id'] except KeyError: msg = _("Missing id attribute on image entity") raise exc.HTTPBadRequest(explanation=msg) - - return image_ref + else: + return image_ref def _flavor_id_from_req_data(self, data): try: flavor = data['server']['flavor'] - except (AttributeError, KeyError): + except (TypeError, KeyError): msg = _("Missing flavor entity") raise exc.HTTPBadRequest(explanation=msg) @@ -536,15 +539,7 @@ class ControllerV11(Controller): msg = _("Malformed flavor entity") raise exc.HTTPBadRequest(explanation=msg) - flavor_ref = None - for link in links: - try: - if link.get('rel') == 'bookmark': - flavor_ref = link.get('href') - break - except AttributeError: - msg = _("Malformed flavor link") - raise exc.HTTPBadRequest(explanation=msg) + flavor_ref = self._href_from_bookmark_links(links) if flavor_ref is None: try: diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index cb7e03934..83b43b8ac 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -612,7 +612,7 @@ class ServersTest(test.TestCase): "_get_kernel_ramdisk_from_image", kernel_ramdisk_mapping) self.stubs.Set(nova.compute.api.API, "_find_host", find_host) - def test_create_instance(self): + def _test_create_instance_helper(self): self._setup_for_create_instance() body = dict(server=dict( @@ -635,6 +635,9 @@ class ServersTest(test.TestCase): self.assertEqual(3, server['imageId']) self.assertEqual(FAKE_UUID, server['uuid']) + def test_create_instance(self): + self._test_create_instance_helper() + def test_create_instance_has_uuid(self): """Tests at the db-layer instead of API layer since that's where the UUID is generated @@ -689,27 +692,7 @@ class ServersTest(test.TestCase): def test_create_instance_no_key_pair(self): fakes.stub_out_key_pair_funcs(self.stubs, have_key_pair=False) - self._setup_for_create_instance() - - body = dict(server=dict( - name='server_test', imageId=3, flavorId=2, - metadata={'hello': 'world', 'open': 'stack'}, - personality={})) - req = webob.Request.blank('/v1.0/servers') - req.method = 'POST' - req.body = json.dumps(body) - req.headers["content-type"] = "application/json" - - res = req.get_response(fakes.wsgi_app()) - - server = json.loads(res.body)['server'] - self.assertEqual(16, len(server['adminPass'])) - self.assertEqual('server_test', server['name']) - self.assertEqual(1, server['id']) - self.assertEqual(2, server['flavorId']) - self.assertEqual(3, server['imageId']) - self.assertEqual(FAKE_UUID, server['uuid']) - self.assertEqual(res.status_int, 200) + self._test_create_instance_helper() def test_create_instance_no_name(self): self._setup_for_create_instance() @@ -782,20 +765,20 @@ class ServersTest(test.TestCase): def test_create_instance_v1_1(self): self._setup_for_create_instance() - image_href = 'http://localhost/v1.1/images/3' - flavor_href = 'http://localhost/v1.1/flavors/2' + image_href = 'http://localhost/v1.1/images/2' + flavor_href = 'http://localhost/v1.1/flavors/3' body = { 'server': { 'name': 'server_test', 'image': { - 'id': 3, + 'id': 2, 'links': [ {'rel': 'bookmark', 'href': image_href}, ], }, 'flavor': { - 'id': 2, + 'id': 3, 'links': [ {'rel': 'bookmark', 'href': flavor_href}, ], @@ -1793,7 +1776,7 @@ class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): def test_minimal_request(self): serial_request = """ """ + name="new-server-test" imageId="1" flavorId="1"/>""" request = self.deserializer.deserialize(serial_request, 'create') expected = {"server": { "name": "new-server-test", -- cgit From 486afc9b9e38a68c18b80daab4f23c5b936ee185 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Wed, 13 Jul 2011 11:17:05 -0400 Subject: pep8 --- nova/api/openstack/servers.py | 2 +- nova/tests/api/openstack/test_servers.py | 44 ++++++++++++++++------------- nova/tests/integrated/integrated_helpers.py | 4 +-- nova/tests/integrated/test_servers.py | 21 +++++++------- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 1e8749f56..50d1442d4 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -491,7 +491,7 @@ class ControllerV11(Controller): except exception.NotFound: return faults.Fault(exc.HTTPNotFound()) - def _href_from_bookmark_links(self, links) + def _href_from_bookmark_links(self, links): for link in links: try: if link.get('rel') == 'bookmark': diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 83b43b8ac..ea3837519 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -789,8 +789,8 @@ class ServersTest(test.TestCase): }, 'personality': [ { - "path" : "/etc/banner.txt", - "contents" : "MQ==", + "path": "/etc/banner.txt", + "contents": "MQ==", }, ], }, @@ -844,7 +844,7 @@ class ServersTest(test.TestCase): 'server': { 'name': 'server_test', 'image': { - 'links':[ + 'links': [ {'rel': 'self', 'href': 'http://google.com'}, {'rel': 'bookmark', 'href': image_ref}, ], @@ -957,8 +957,6 @@ class ServersTest(test.TestCase): self.assertEqual(res.status_int, 400) - - def test_create_instance_with_admin_pass_v1_0(self): self._setup_for_create_instance() @@ -2064,8 +2062,8 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1"}, - "flavor": {"id": "2"}, + "image": {"id": "1", "links": []}, + "flavor": {"id": "2", "links": []}, }, } self.assertEquals(request['body'], expected) @@ -2091,7 +2089,7 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): }, ], }, - "flavor": {"id": "3"}, + "flavor": {"id": "3", "links": []}, }, } self.assertEquals(request['body'], expected) @@ -2108,7 +2106,7 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1"}, + "image": {"id": "1", "links": []}, "flavor": { "id": "2", "links": [ @@ -2134,8 +2132,8 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1"}, - "flavor": {"id": "2"}, + "image": {"id": "1", "links": []}, + "flavor": {"id": "2", "links": []}, "metadata": {}, "personality": [], }, @@ -2156,8 +2154,8 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1"}, - "flavor": {"id": "2"}, + "image": {"id": "1", "links": []}, + "flavor": {"id": "2", "links": []}, "metadata": {"one": "two", "open": "snack"}, }, } @@ -2177,8 +2175,8 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1"}, - "flavor": {"id": "2"}, + "image": {"id": "1", "links": []}, + "flavor": {"id": "2", "links": []}, "personality": [ {"path": "/etc/banner.txt", "contents": "MQ=="}, {"path": "/etc/hosts", "contents": "Mg=="}, @@ -2188,6 +2186,10 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): self.assertEquals(request['body'], expected) def test_spec_request(self): + image_self_link = "http://servers.api.openstack.org/v1.1/1234/" + \ + "images/52415800-8b69-11e0-9b19-734f6f006e54" + image_bookmark_link = "http://servers.api.openstack.org/1234/" + \ + "images/52415800-8b69-11e0-9b19-734f6f006e54" serial_request = """ + href="%s"/> + href="%s"/> @@ -2211,7 +2213,7 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): Mg== -""" +""" % (image_self_link, image_bookmark_link) request = self.deserializer.deserialize(serial_request, 'create') expected = { "server": { @@ -2233,7 +2235,10 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): }, ], }, - "flavor": {"id": "52415800-8b69-11e0-9b19-734f1195ff37"}, + "flavor": { + "id": "52415800-8b69-11e0-9b19-734f1195ff37", + "links": [], + }, "metadata": {"My Server Name": "Apache1"}, "personality": [ { @@ -2245,6 +2250,7 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): } self.assertEquals(request['body'], expected) + class TestServerInstanceCreation(test.TestCase): def setUp(self): diff --git a/nova/tests/integrated/integrated_helpers.py b/nova/tests/integrated/integrated_helpers.py index 47bd8c1e4..eb611ae0d 100644 --- a/nova/tests/integrated/integrated_helpers.py +++ b/nova/tests/integrated/integrated_helpers.py @@ -205,12 +205,12 @@ class _IntegratedTestBase(test.TestCase): image_href = 'http://fake.server/%s' % image_href # We now have a valid imageId - server['imageRef'] = image_href + server['image'] = {'links': [{'rel':'bookmark', 'href': image_href}]} # Set a valid flavorId flavor = self.api.get_flavors()[0] LOG.debug("Using flavor: %s" % flavor) - server['flavorRef'] = 'http://fake.server/%s' % flavor['id'] + server['flavor'] = {'id': flavor['id']} # Set a valid server name server_name = self.user.get_unused_server_name() diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index fcb517cf5..5c1812c76 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -49,31 +49,30 @@ class ServersTest(integrated_helpers._IntegratedTestBase): post = {'server': server} - # Without an imageRef, this throws 500. + # Without an image, this throws 400. # TODO(justinsb): Check whatever the spec says should be thrown here self.assertRaises(client.OpenStackApiException, self.api.post_server, post) - # With an invalid imageRef, this throws 500. - server['imageRef'] = self.user.get_invalid_image() + # With an invalid image entity, this throws 400. + bookmark = {'rel': 'bookmark', 'href': self.user.get_invalid_image()} + server['image'] = {'links': [bookmark]} # TODO(justinsb): Check whatever the spec says should be thrown here self.assertRaises(client.OpenStackApiException, self.api.post_server, post) - # Add a valid imageId/imageRef - server['imageId'] = good_server.get('imageId') - server['imageRef'] = good_server.get('imageRef') + # Add a valid image entity + server['image'] = good_server.get('image', {}) - # Without flavorId, this throws 500 + # Without a flavor entity, this throws 400 # TODO(justinsb): Check whatever the spec says should be thrown here self.assertRaises(client.OpenStackApiException, self.api.post_server, post) - # Set a valid flavorId/flavorRef - server['flavorRef'] = good_server.get('flavorRef') - server['flavorId'] = good_server.get('flavorId') + # Set a valid flavor etity + server['flavor'] = good_server.get('flavor', {}) - # Without a name, this throws 500 + # Without a name, this throws 400 # TODO(justinsb): Check whatever the spec says should be thrown here self.assertRaises(client.OpenStackApiException, self.api.post_server, post) -- cgit From 74d8a358193c9119f2edd17300eebd699ed6e755 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 15 Jul 2011 16:30:39 -0400 Subject: Added ServerXMLSerializationTest --- nova/tests/api/openstack/test_servers.py | 142 +++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 6 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index c0ccb3ef2..27308ee4e 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2927,12 +2927,12 @@ class ServersViewBuilderV11Test(test.TestCase): }, "flavor": { "id": "1", - "links": [ - { - "rel": "bookmark", - "href": flavor_bookmark, - }, - ], + "links": [ + { + "rel": "bookmark", + "href": flavor_bookmark, + }, + ], }, "addresses": {}, "metadata": { @@ -2954,3 +2954,133 @@ class ServersViewBuilderV11Test(test.TestCase): output = self.view_builder.build(self.instance, True) self.assertDictMatch(output, expected_server) + + +class ServerXMLSerializationTest(test.TestCase): + + TIMESTAMP = "2010-10-11T10:30:22Z" + SERVER_HREF = 'http://localhost/v1.1/servers/123' + SERVER_BOOKMARK = 'http://localhost/servers/123' + IMAGE_BOOKMARK = 'http://localhost/images/5' + FLAVOR_BOOKMARK = 'http://localhost/flavors/1' + + def test_show(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'show') + actual = minidom.parseString(output.replace(" ", "")) + + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + expected = minidom.parseString(""" + + + + + + + + + + Stack + + + 1 + + + + + + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From 64a9c37cbf070345831ba6e4db646c5d972e179b Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:17:08 -0400 Subject: Added ServerXMLSerializer with working 'show' method Factored out MetadataXMLSerializer from images and servers into common --- nova/api/openstack/common.py | 50 ++++++++++++++++++ nova/api/openstack/image_metadata.py | 49 ------------------ nova/api/openstack/images.py | 4 +- nova/api/openstack/servers.py | 89 ++++++++++++++++++++++++++++++++ nova/tests/api/openstack/test_servers.py | 12 +++-- 5 files changed, 150 insertions(+), 54 deletions(-) diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 8e12ce0c0..8a78292aa 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -17,12 +17,14 @@ import re from urlparse import urlparse +from xml.dom import minidom import webob from nova import exception from nova import flags from nova import log as logging +from nova.api.openstack import wsgi LOG = logging.getLogger('nova.api.openstack.common') @@ -162,3 +164,51 @@ def remove_version_from_href(href): msg = _('href does not contain version') raise ValueError(msg) return new_href + + +class MetadataXMLSerializer(wsgi.XMLDictSerializer): + 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.toprettyxml(indent=' ', encoding='UTF-8') + + def index(self, metadata_dict): + return self._meta_list_to_xml_string(metadata_dict) + + def create(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.toprettyxml(indent=' ', encoding='UTF-8') + + def show(self, meta_item_dict): + return self._meta_item_to_xml_string(meta_item_dict['meta']) + + def update(self, meta_item_dict): + return self._meta_item_to_xml_string(meta_item_dict['meta']) diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index 4f33844fa..dd1a3f130 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -16,7 +16,6 @@ # under the License. from webob import exc -from xml.dom import minidom from nova import flags from nova import image @@ -111,54 +110,6 @@ class Controller(object): self.image_service.update(context, image_id, img, None) -class ImageMetadataXMLSerializer(wsgi.XMLDictSerializer): - def __init__(self, xmlns=wsgi.XMLNS_V11): - super(ImageMetadataXMLSerializer, 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.toprettyxml(indent=' ', encoding='UTF-8') - - def index(self, metadata_dict): - return self._meta_list_to_xml_string(metadata_dict) - - def create(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.toprettyxml(indent=' ', encoding='UTF-8') - - def show(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) - - def update(self, meta_item_dict): - return self._meta_item_to_xml_string(meta_item_dict['meta']) - - def create_resource(): body_serializers = { 'application/xml': ImageMetadataXMLSerializer(), diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index d0317583e..6c7c0feb9 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -278,9 +278,9 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): xmlns = wsgi.XMLNS_V11 def __init__(self): - self.metadata_serializer = image_metadata.ImageMetadataXMLSerializer() + self.metadata_serializer = common.MetadataXMLSerializer() - def _image_to_xml(self, xml_doc, image): + 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']) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 93f8e832c..b07b903f8 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -17,6 +17,7 @@ import base64 import traceback from webob import exc +from xml.dom import minidom from nova import compute from nova import db @@ -612,6 +613,94 @@ class HeadersSerializer(wsgi.ResponseHeadersSerializer): response.status_int = 204 +class ServerXMLSerializer(wsgi.XMLDictSerializer): + + xmlns = wsgi.XMLNS_V11 + + def __init__(self): + self.metadata_serializer = common.MetadataXMLSerializer() + + 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): + addresses_node = xml_doc.createElement('addresses') + for name, network_dict in addresses.items(): + network_node = self._create_network_node(xml_doc, + name, + network_dict) + addresses_node.appendChild(network_node) + return addresses_node + + def _create_network_node(self, xml_doc, network_name, network_dict): + network_node = xml_doc.createElement('network') + network_node.setAttribute('id', network_name) + for ip in network_dict: + ip_node = xml_doc.createElement('ip') + ip_node.setAttribute('version', str(ip['version'])) + ip_node.setAttribute('addr', ip['addr']) + network_node.appendChild(ip_node) + return network_node + + + 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', server['created']) + node.setAttribute('updated', server['updated']) + node.setAttribute('status', server['status']) + if 'progress' in server: + node.setAttribute('progress', str(server['progress'])) + + 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) + + image_node = self._create_basic_entity_node(xml_doc, + server['image']['id'], + server['image']['links'], + 'image') + server_node.appendChild(image_node) + + 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 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) + + def create_resource(version='1.0'): controller = { '1.0': ControllerV10, diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 27308ee4e..ff878bba6 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2964,6 +2964,12 @@ class ServerXMLSerializationTest(test.TestCase): IMAGE_BOOKMARK = 'http://localhost/images/5' FLAVOR_BOOKMARK = 'http://localhost/flavors/1' + def setUp(self): + self.maxDiff = None + + def tearDown(self): + pass + def test_show(self): serializer = servers.ServerXMLSerializer() @@ -3048,12 +3054,14 @@ class ServerXMLSerializationTest(test.TestCase): uuid="%(expected_uuid)s" xmlns="http://docs.openstack.org/compute/api/v1.1" xmlns:atom="http://www.w3.org/2005/Atom" - name="Image1" + name="test_server" updated="%(expected_now)s" created="%(expected_now)s" hostId="e4d909c290d0fb1ca068ffaddf22cbd0" status="BUILD" progress="0"> + + @@ -3078,8 +3086,6 @@ class ServerXMLSerializationTest(test.TestCase): - - """.replace(" ", "") % (locals())) -- cgit From 7af043463a350cfc71c45ff719354511173b5c39 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:39:27 -0400 Subject: Moved Metadata Serialization Test --- nova/api/openstack/image_metadata.py | 3 +- nova/api/openstack/images.py | 2 +- nova/tests/api/openstack/test_common.py | 132 ++++++++++++++++++++++++ nova/tests/api/openstack/test_image_metadata.py | 132 ------------------------ 4 files changed, 135 insertions(+), 134 deletions(-) diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index dd1a3f130..d1065a4e3 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -21,6 +21,7 @@ from nova import flags from nova import image from nova import quota from nova import utils +from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import wsgi @@ -112,7 +113,7 @@ class Controller(object): def create_resource(): body_serializers = { - 'application/xml': ImageMetadataXMLSerializer(), + 'application/xml': common.MetadataXMLSerializer(), } serializer = wsgi.ResponseSerializer(body_serializers) diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 6c7c0feb9..df7bf0cf9 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -280,7 +280,7 @@ class ImageXMLSerializer(wsgi.XMLDictSerializer): def __init__(self): self.metadata_serializer = common.MetadataXMLSerializer() - def image_to_xml(self, xml_doc, image): + 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']) diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py index 4c4d03995..eec3f8f64 100644 --- a/nova/tests/api/openstack/test_common.py +++ b/nova/tests/api/openstack/test_common.py @@ -20,6 +20,7 @@ Test suites for 'common' code used throughout the OpenStack HTTP API. """ import webob.exc +import xml.dom.minidom as minidom from webob import Request @@ -247,3 +248,134 @@ class MiscFunctionsTest(test.TestCase): self.assertRaises(ValueError, common.get_id_from_href, fixture) + + +class MetadataXMLSerializationTest(test.TestCase): + + def test_index_xml(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'one': 'two', + 'three': 'four', + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + + four + + + two + + + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index_xml_null(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + None: None, + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + + None + + + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index_xml_unicode(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + u'three': u'Jos\xe9', + }, + } + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(u""" + + + Jos\xe9 + + + """.encode("UTF-8").replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_show_xml(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'meta': { + 'one': 'two', + }, + } + output = serializer.serialize(fixture, 'show') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + two + + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_update_item_xml(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'meta': { + 'one': 'two', + }, + } + output = serializer.serialize(fixture, 'update') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + two + + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_create_xml(self): + serializer = common.MetadataXMLSerializer() + fixture = { + 'metadata': { + 'key9': 'value9', + 'key2': 'value2', + 'key1': 'value1', + }, + } + output = serializer.serialize(fixture, 'create') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + + value2 + + + value9 + + + value1 + + + """.replace(" ", "")) + + self.assertEqual(expected.toxml(), actual.toxml()) diff --git a/nova/tests/api/openstack/test_image_metadata.py b/nova/tests/api/openstack/test_image_metadata.py index d9fb61e2a..17cd35693 100644 --- a/nova/tests/api/openstack/test_image_metadata.py +++ b/nova/tests/api/openstack/test_image_metadata.py @@ -19,7 +19,6 @@ import json import stubout import unittest import webob -import xml.dom.minidom as minidom from nova import flags @@ -219,134 +218,3 @@ class ImageMetaDataTest(test.TestCase): req.headers["content-type"] = "application/json" res = req.get_response(fakes.wsgi_app()) self.assertEqual(400, res.status_int) - - -class ImageMetadataXMLSerializationTest(test.TestCase): - - def test_index_xml(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - 'one': 'two', - 'three': 'four', - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - four - - - two - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_index_xml_null(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - None: None, - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - None - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_index_xml_unicode(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - u'three': u'Jos\xe9', - }, - } - output = serializer.serialize(fixture, 'index') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(u""" - - - Jos\xe9 - - - """.encode("UTF-8").replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_show_xml(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'meta': { - 'one': 'two', - }, - } - output = serializer.serialize(fixture, 'show') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - two - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_update_item_xml(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'meta': { - 'one': 'two', - }, - } - output = serializer.serialize(fixture, 'update') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - two - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_create_xml(self): - serializer = openstack.image_metadata.ImageMetadataXMLSerializer() - fixture = { - 'metadata': { - 'key9': 'value9', - 'key2': 'value2', - 'key1': 'value1', - }, - } - output = serializer.serialize(fixture, 'create') - actual = minidom.parseString(output.replace(" ", "")) - - expected = minidom.parseString(""" - - - value2 - - - value9 - - - value1 - - - """.replace(" ", "")) - - self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From c538d38d890e74382e928d225e8abdc57da9760e Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sat, 16 Jul 2011 19:45:28 -0400 Subject: pep8 --- nova/api/openstack/image_metadata.py | 2 +- nova/api/openstack/servers.py | 1 - nova/tests/api/openstack/test_servers.py | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/nova/api/openstack/image_metadata.py b/nova/api/openstack/image_metadata.py index d1065a4e3..b9b782f92 100644 --- a/nova/api/openstack/image_metadata.py +++ b/nova/api/openstack/image_metadata.py @@ -21,7 +21,7 @@ from nova import flags from nova import image from nova import quota from nova import utils -from nova.api.openstack import common +from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import wsgi diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index b07b903f8..1a85fda58 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -650,7 +650,6 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): network_node.appendChild(ip_node) return network_node - def _add_server_attributes(self, node, server): node.setAttribute('id', str(server['id'])) node.setAttribute('uuid', str(server['uuid'])) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index ff878bba6..4d43be03d 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2771,8 +2771,7 @@ class ServersViewBuilderV11Test(test.TestCase): address_builder, flavor_builder, image_builder, - base_url - ) + base_url) return view_builder def test_build_server(self): -- cgit From 712493f65415a7a5fc727f6b316c66ef90f1cad5 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 14:50:44 -0400 Subject: added index to servers xml serializer --- nova/api/openstack/servers.py | 29 ++++++++++++++++ nova/tests/api/openstack/test_servers.py | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 1a85fda58..8d59c8626 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -661,6 +661,16 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): 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) @@ -693,6 +703,25 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): return server_node + def _server_list_to_xml(self, xml_doc, servers, detailed): + container_node = xml_doc.createElement('servers') + 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 + + 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) + def show(self, server_dict): xml_doc = minidom.Document() node = self._server_to_xml_detailed(xml_doc, diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 4d43be03d..6ef789d33 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3089,3 +3089,60 @@ class ServerXMLSerializationTest(test.TestCase): """.replace(" ", "") % (locals())) self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index(self): + serializer = servers.ServerXMLSerializer() + + expected_server_href = 'http://localhost/v1.1/servers/1' + expected_server_bookmark = 'http://localhost/servers/1' + expected_server_href_2 = 'http://localhost/v1.1/servers/2' + expected_server_bookmark_2 = 'http://localhost/servers/2' + fixture = { "servers": [ + { + "id": 1, + "name": "test_server", + 'links': [ + { + 'href': expected_server_href, + 'rel': 'self', + }, + { + 'href': expected_server_bookmark, + 'rel': 'bookmark', + }, + ], + }, + { + "id": 2, + "name": "test_server_2", + 'links': [ + { + 'href': expected_server_href_2, + 'rel': 'self', + }, + { + 'href': expected_server_bookmark_2, + 'rel': 'bookmark', + }, + ], + }, + ]} + + output = serializer.serialize(fixture, 'index') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From baaaa80d36570d5734ac823bc49be8ff2477e5c2 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 21:24:02 -0400 Subject: added 'detail' to server XML serializer --- nova/api/openstack/servers.py | 7 ++ nova/tests/api/openstack/test_servers.py | 188 +++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 8d59c8626..82630397f 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -722,6 +722,13 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): detailed=False) return self.to_xml_string(node, True) + 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) + def show(self, server_dict): xml_doc = minidom.Document() node = self._server_to_xml_detailed(xml_doc, diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 6ef789d33..037e35545 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3146,3 +3146,191 @@ class ServerXMLSerializationTest(test.TestCase): """.replace(" ", "") % (locals())) self.assertEqual(expected.toxml(), actual.toxml()) + + def test_detail(self): + serializer = servers.ServerXMLSerializer() + + expected_server_href = 'http://localhost/v1.1/servers/1' + expected_server_bookmark = 'http://localhost/servers/1' + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + + expected_server_href_2 = 'http://localhost/v1.1/servers/2' + expected_server_bookmark_2 = 'http://localhost/servers/2' + fixture = { "servers": [ + { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": expected_image_bookmark, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": expected_flavor_bookmark, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + }, + "metadata": { + "Number": "1", + }, + "links": [ + { + "href": expected_server_href, + "rel": "self", + }, + { + "href": expected_server_bookmark, + "rel": "bookmark", + }, + ], + }, + { + "id": 2, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 100, + "name": "test_server_2", + "status": "ACTIVE", + "hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0', + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": expected_image_bookmark, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": expected_flavor_bookmark, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + }, + "metadata": { + "Number": "2", + }, + "links": [ + { + "href": expected_server_href_2, + "rel": "self", + }, + { + "href": expected_server_bookmark_2, + "rel": "bookmark", + }, + ], + }, + ]} + + output = serializer.serialize(fixture, 'detail') + actual = minidom.parseString(output.replace(" ", "")) + + expected = minidom.parseString(""" + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + 2 + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From 8ab775585fee4af7b30a28a5bffae46c23ec76d1 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 21:36:57 -0400 Subject: added 'create' to server XML serializer --- nova/api/openstack/servers.py | 7 ++ nova/tests/api/openstack/test_servers.py | 123 +++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 82630397f..4a29e1454 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -735,6 +735,13 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): server_dict['server']) return self.to_xml_string(node, True) + 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) + def create_resource(version='1.0'): controller = { diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 037e35545..3b50b4331 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3090,6 +3090,129 @@ class ServerXMLSerializationTest(test.TestCase): self.assertEqual(expected.toxml(), actual.toxml()) + def test_create(self): + serializer = servers.ServerXMLSerializer() + + fixture = { + "server": { + "id": 1, + "uuid": FAKE_UUID, + 'created': self.TIMESTAMP, + 'updated': self.TIMESTAMP, + "progress": 0, + "name": "test_server", + "status": "BUILD", + "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0", + "adminPass": "test_password", + "image": { + "id": "5", + "links": [ + { + "rel": "bookmark", + "href": self.IMAGE_BOOKMARK, + }, + ], + }, + "flavor": { + "id": "1", + "links": [ + { + "rel": "bookmark", + "href": self.FLAVOR_BOOKMARK, + }, + ], + }, + "addresses": { + "network_one": [ + { + "version": 4, + "addr": "67.23.10.138", + }, + { + "version": 6, + "addr": "::babe:67.23.10.138", + }, + ], + "network_two": [ + { + "version": 4, + "addr": "67.23.10.139", + }, + { + "version": 6, + "addr": "::babe:67.23.10.139", + }, + ], + }, + "metadata": { + "Open": "Stack", + "Number": "1", + }, + 'links': [ + { + 'href': self.SERVER_HREF, + 'rel': 'self', + }, + { + 'href': self.SERVER_BOOKMARK, + 'rel': 'bookmark', + }, + ], + } + } + + output = serializer.serialize(fixture, 'create') + actual = minidom.parseString(output.replace(" ", "")) + + expected_server_href = self.SERVER_HREF + expected_server_bookmark = self.SERVER_BOOKMARK + expected_image_bookmark = self.IMAGE_BOOKMARK + expected_flavor_bookmark = self.FLAVOR_BOOKMARK + expected_now = self.TIMESTAMP + expected_uuid = FAKE_UUID + expected = minidom.parseString(""" + + + + + + + + + + + + Stack + + + 1 + + + + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + def test_index(self): serializer = servers.ServerXMLSerializer() -- cgit From e23e70afd096ca1d7ad22c776f6f439986bbc8b5 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 22:28:16 -0400 Subject: updated servers to use ServerXMLSerializer --- nova/api/openstack/servers.py | 3 +- nova/tests/api/openstack/test_servers.py | 71 ++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4a29e1454..a6229125d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -773,8 +773,7 @@ def create_resource(version='1.0'): headers_serializer = HeadersSerializer() body_serializers = { - 'application/xml': wsgi.XMLDictSerializer(metadata=metadata, - xmlns=xmlns), + 'application/xml': ServerXMLSerializer(), } body_deserializers = { diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 3b50b4331..413996fdc 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -392,6 +392,77 @@ class ServersTest(test.TestCase): self.assertDictMatch(res_dict, expected_server) + def test_get_server_by_id_v1_1_xml(self): + image_bookmark = "http://localhost/images/10" + flavor_ref = "http://localhost/v1.1/flavors/1" + flavor_id = "1" + flavor_bookmark = "http://localhost/flavors/1" + server_href = "http://localhost/v1.1/servers/1" + server_bookmark = "http://localhost/servers/1" + + public_ip = '192.168.0.3' + private_ip = '172.19.0.1' + interfaces = [ + { + 'network': {'label': 'public'}, + 'fixed_ips': [ + {'address': public_ip}, + ], + }, + { + 'network': {'label': 'private'}, + 'fixed_ips': [ + {'address': private_ip}, + ], + }, + ] + new_return_server = return_server_with_interfaces(interfaces) + self.stubs.Set(nova.db.api, 'instance_get', new_return_server) + + req = webob.Request.blank('/v1.1/servers/1') + req.headers['Accept'] = 'application/xml' + res = req.get_response(fakes.wsgi_app()) + actual = minidom.parseString(res.body.replace(' ', '')) + expected_uuid = FAKE_UUID + expected_updated = "2010-11-11T11:00:00Z" + expected_created = "2010-10-10T12:00:00Z" + expected = minidom.parseString(""" + + + + + + + + + + + + 1 + + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + def test_get_server_with_active_status_by_id_v1_1(self): image_bookmark = "http://localhost/images/10" flavor_ref = "http://localhost/v1.1/flavors/1" -- cgit From 596b38b8c899727c4750aa9b5a05a1ab2c2ecad3 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 22:29:28 -0400 Subject: pep8 --- nova/tests/api/openstack/test_servers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 413996fdc..782db21ec 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -3291,7 +3291,7 @@ class ServerXMLSerializationTest(test.TestCase): expected_server_bookmark = 'http://localhost/servers/1' expected_server_href_2 = 'http://localhost/v1.1/servers/2' expected_server_bookmark_2 = 'http://localhost/servers/2' - fixture = { "servers": [ + fixture = {"servers": [ { "id": 1, "name": "test_server", @@ -3353,7 +3353,7 @@ class ServerXMLSerializationTest(test.TestCase): expected_server_href_2 = 'http://localhost/v1.1/servers/2' expected_server_bookmark_2 = 'http://localhost/servers/2' - fixture = { "servers": [ + fixture = {"servers": [ { "id": 1, "uuid": FAKE_UUID, -- cgit From b9d316452a1e2a204e56d1434feade1ab0bd281c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Sun, 17 Jul 2011 22:50:10 -0400 Subject: Updated servers to choose XML serializer based on api version --- nova/api/openstack/servers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index a6229125d..6d55b856d 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -772,8 +772,13 @@ def create_resource(version='1.0'): headers_serializer = HeadersSerializer() + xml_serializer = { + '1.0': wsgi.XMLDictSerializer(metadata, wsgi.XMLNS_V10), + '1.1': ServerXMLSerializer(), + }[version] + body_serializers = { - 'application/xml': ServerXMLSerializer(), + 'application/xml': xml_serializer, } body_deserializers = { -- cgit From 422d5329276f5c2252d7328d4112be7c696a274a Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 09:57:39 -0400 Subject: Updated ServerXMLSerializer to utilize the IPXMLSerializer --- nova/api/openstack/servers.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4e6f0d7b5..11dafc272 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -28,6 +28,7 @@ from nova import log as logging from nova import utils from nova.api.openstack import common from nova.api.openstack import create_instance_helper as helper +from nova.api.openstack import ips import nova.api.openstack.views.addresses import nova.api.openstack.views.flavors import nova.api.openstack.views.images @@ -608,6 +609,7 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): 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) @@ -621,23 +623,7 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): return self.metadata_serializer.meta_list_to_xml(xml_doc, metadata) def _create_addresses_node(self, xml_doc, addresses): - addresses_node = xml_doc.createElement('addresses') - for name, network_dict in addresses.items(): - network_node = self._create_network_node(xml_doc, - name, - network_dict) - addresses_node.appendChild(network_node) - return addresses_node - - def _create_network_node(self, xml_doc, network_name, network_dict): - network_node = xml_doc.createElement('network') - network_node.setAttribute('id', network_name) - for ip in network_dict: - ip_node = xml_doc.createElement('ip') - ip_node.setAttribute('version', str(ip['version'])) - ip_node.setAttribute('addr', ip['addr']) - network_node.appendChild(ip_node) - return network_node + return self.addresses_serializer.networks_to_xml(xml_doc, addresses) def _add_server_attributes(self, node, server): node.setAttribute('id', str(server['id'])) -- cgit From 1ad5f2eaf49904d8e14546d59699b1472a1a5bb2 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 12:57:06 -0400 Subject: xml deserialization works now --- nova/api/openstack/create_instance_helper.py | 79 +++---------- nova/api/openstack/wsgi.py | 9 +- nova/tests/api/openstack/test_servers.py | 162 ++++++++++++--------------- 3 files changed, 90 insertions(+), 160 deletions(-) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index 03272443a..b717b8ac0 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -303,79 +303,30 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): """Marshal the server attribute of a parsed request""" server = {} server_node = self.find_first_child_named(node, 'server') - for attr in ["name", "imageId", "flavorId"]: + + attributes = ["name", "imageId", "flavorId", "imageRef", + "flavorRef", "adminPass"] + for attr in attributes: if server_node.getAttribute(attr): server[attr] = server_node.getAttribute(attr) - image = self._extract_image(server_node) - if image is not None: - server["image"] = image - flavor = self._extract_flavor(server_node) - if flavor is not None: - server["flavor"] = flavor - metadata_node = self.find_first_child_named(server_node, "metadata") - metadata = self.extract_metadata(metadata_node) - if metadata is not None: - server["metadata"] = metadata - personality = self._extract_personality(server_node) - if personality is not None: - server["personality"] = personality - return server - - def _extract_image(self, server_node): - """Retrieve an image entity from the server node""" - image_node = self.find_first_child_named(server_node, "image") - if image_node is None: - return None - - image = {} - image_id = image_node.getAttribute('id') - if image_id is not None: - image['id'] = image_id - - image['links'] = self._extract_links_from_node(image_node) - - return image - def _extract_flavor(self, server_node): - """Retrieve a flavor entity from the server node""" - flavor_node = self.find_first_child_named(server_node, "flavor") - if flavor_node is None: - return None - - flavor = {} - flavor_id = flavor_node.getAttribute('id') - if flavor_id: - flavor['id'] = flavor_id - - flavor['links'] = self._extract_links_from_node(flavor_node) - - return flavor - - def _extract_links_from_node(self, parent_node): - """Retrieve link entities from a links container provided node""" - links = [] + metadata_node = self.find_first_child_named(server_node, "metadata") + server["metadata"] = self.extract_metadata(metadata_node) - for link_node in self.find_children_named(parent_node, 'atom:link'): - link = { - 'rel': link_node.getAttribute('rel'), - 'href': link_node.getAttribute('href'), - } - if link['rel'] is not None and link['href'] is not None: - links.append(link) + server["personality"] = self._extract_personality(server_node) - return links + return server def _extract_personality(self, server_node): """Marshal the personality attribute of a parsed request""" personality_node = \ self.find_first_child_named(server_node, "personality") - if personality_node is None: - return None personality = [] - for file_node in self.find_children_named(personality_node, "file"): - item = {} - if file_node.hasAttribute("path"): - item["path"] = file_node.getAttribute("path") - item["contents"] = self.extract_text(file_node) - personality.append(item) + if personality_node is not None: + for file_node in self.find_children_named(personality_node, "file"): + item = {} + if file_node.hasAttribute("path"): + item["path"] = file_node.getAttribute("path") + item["contents"] = self.extract_text(file_node) + personality.append(item) return personality diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index a28443d12..53dab22e8 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -165,12 +165,11 @@ class MetadataXMLDeserializer(XMLDeserializer): def extract_metadata(self, metadata_node): """Marshal the metadata attribute of a parsed request""" - if metadata_node is None: - return None metadata = {} - for meta_node in self.find_children_named(metadata_node, "meta"): - key = meta_node.getAttribute("key") - metadata[key] = self.extract_text(meta_node) + if metadata_node is not None: + for meta_node in self.find_children_named(metadata_node, "meta"): + key = meta_node.getAttribute("key") + metadata[key] = self.extract_text(meta_node) return metadata diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 9ff0a3d04..97cebd29c 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2530,77 +2530,85 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): def test_minimal_request(self): serial_request = """ - - - -""" +""" + request = self.deserializer.deserialize(serial_request, 'create') + expected = { + "server": { + "name": "new-server-test", + "imageRef": "1", + "flavorRef": "2", + "metadata": {}, + "personality": [], + }, + } + self.assertEquals(request['body'], expected) + + def test_admin_pass(self): + serial_request = """ +""" request = self.deserializer.deserialize(serial_request, 'create') expected = { "server": { "name": "new-server-test", - "image": {"id": "1", "links": []}, - "flavor": {"id": "2", "links": []}, + "imageRef": "1", + "flavorRef": "2", + "adminPass": "1234", + "metadata": {}, + "personality": [], }, } self.assertEquals(request['body'], expected) + def test_image_link(self): serial_request = """ - - - - - -""" +""" request = self.deserializer.deserialize(serial_request, 'create') expected = { "server": { "name": "new-server-test", - "image": { - "id": "1", - "links": [ - { - "rel": "bookmark", - "href": "http://localhost:8774/v1.1/images/2", - }, - ], - }, - "flavor": {"id": "3", "links": []}, + "imageRef": "http://localhost:8774/v1.1/images/2", + "flavorRef": "3", + "metadata": {}, + "personality": [], }, } self.assertEquals(request['body'], expected) def test_flavor_link(self): serial_request = """ - - - - - -""" +""" request = self.deserializer.deserialize(serial_request, 'create') expected = { "server": { "name": "new-server-test", - "image": {"id": "1", "links": []}, - "flavor": { - "id": "2", - "links": [ - { - "rel": "bookmark", - "href": "http://localhost:8774/v1.1/flavors/3", - }, - ], - }, + "imageRef": "1", + "flavorRef": "http://localhost:8774/v1.1/flavors/3", + "metadata": {}, + "personality": [], }, } self.assertEquals(request['body'], expected) def test_empty_metadata_personality(self): serial_request = """ - - - + """ @@ -2608,8 +2616,8 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1", "links": []}, - "flavor": {"id": "2", "links": []}, + "imageRef": "1", + "flavorRef": "2", "metadata": {}, "personality": [], }, @@ -2618,9 +2626,10 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): def test_multiple_metadata_items(self): serial_request = """ - - - + two snack @@ -2630,18 +2639,20 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1", "links": []}, - "flavor": {"id": "2", "links": []}, + "imageRef": "1", + "flavorRef": "2", "metadata": {"one": "two", "open": "snack"}, + "personality": [], }, } self.assertEquals(request['body'], expected) def test_multiple_personality_files(self): serial_request = """ - - - + MQ== Mg== @@ -2651,8 +2662,9 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): expected = { "server": { "name": "new-server-test", - "image": {"id": "1", "links": []}, - "flavor": {"id": "2", "links": []}, + "imageRef": "1", + "flavorRef": "2", + "metadata": {}, "personality": [ {"path": "/etc/banner.txt", "contents": "MQ=="}, {"path": "/etc/hosts", "contents": "Mg=="}, @@ -2662,59 +2674,27 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): self.assertEquals(request['body'], expected) def test_spec_request(self): - image_self_link = "http://servers.api.openstack.org/v1.1/1234/" + \ - "images/52415800-8b69-11e0-9b19-734f6f006e54" image_bookmark_link = "http://servers.api.openstack.org/1234/" + \ "images/52415800-8b69-11e0-9b19-734f6f006e54" serial_request = """ - - - - - Apache1 Mg== -""" % (image_self_link, image_bookmark_link) +""" % (image_bookmark_link) request = self.deserializer.deserialize(serial_request, 'create') expected = { "server": { "name": "new-server-test", - "image": { - "id": "52415800-8b69-11e0-9b19-734f6f006e54", - "links": [ - { - "rel": "self", - "href": "http://servers.api.openstack.org/" + \ - "v1.1/1234/images/52415800-8b69-11" + \ - "e0-9b19-734f6f006e54", - }, - { - "rel": "bookmark", - "href": "http://servers.api.openstack.org/" + \ - "1234/images/52415800-8b69-11e0-9b" + \ - "19-734f6f006e54", - }, - ], - }, - "flavor": { - "id": "52415800-8b69-11e0-9b19-734f1195ff37", - "links": [], - }, + "imageRef": "http://servers.api.openstack.org/1234/" + \ + "images/52415800-8b69-11e0-9b19-734f6f006e54", + "flavorRef": "52415800-8b69-11e0-9b19-734f1195ff37", "metadata": {"My Server Name": "Apache1"}, "personality": [ { -- cgit From 3db1c53486fdb669ac2bab303335548d7a7c617d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 13:28:11 -0400 Subject: updating imageRef and flavorRef parsing --- nova/api/openstack/servers.py | 42 ++++---------------------------- nova/tests/api/openstack/test_servers.py | 29 ++++++++-------------- 2 files changed, 15 insertions(+), 56 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index e1f845f36..06112eee3 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -493,51 +493,19 @@ class ControllerV11(Controller): def _image_ref_from_req_data(self, data): try: - image = data['server']['image'] + return data['server']['imageRef'] except (TypeError, KeyError): - msg = _("Missing image entity") + msg = _("Missing imageRef attribute") raise exc.HTTPBadRequest(explanation=msg) - try: - links = image.get('links', []) - except AttributeError: - msg = _("Malformed image entity") - raise exc.HTTPBadRequest(explanation=msg) - - image_ref = self._href_from_bookmark_links(links) - - if image_ref is None: - try: - return image['id'] - except KeyError: - msg = _("Missing id attribute on image entity") - raise exc.HTTPBadRequest(explanation=msg) - else: - return image_ref - def _flavor_id_from_req_data(self, data): try: - flavor = data['server']['flavor'] + flavor_ref = data['server']['flavorRef'] except (TypeError, KeyError): - msg = _("Missing flavor entity") + msg = _("Missing flavorRef attribute") raise exc.HTTPBadRequest(explanation=msg) - try: - links = flavor.get('links', []) - except AttributeError: - msg = _("Malformed flavor entity") - raise exc.HTTPBadRequest(explanation=msg) - - flavor_ref = self._href_from_bookmark_links(links) - - if flavor_ref is None: - try: - return flavor['id'] - except (KeyError, AttributeError): - msg = _("Missing id attribute in flavor entity") - raise exc.HTTPBadRequest(explanation=msg) - else: - return common.get_id_from_href(flavor_ref) + return common.get_id_from_href(flavor_ref) def _build_view(self, req, instance, is_detail=False): base_url = req.application_url diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 97cebd29c..cae04e6ab 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1267,18 +1267,8 @@ class ServersTest(test.TestCase): body = { 'server': { 'name': 'server_test', - 'image': { - 'id': 2, - 'links': [ - {'rel': 'bookmark', 'href': image_href}, - ], - }, - 'flavor': { - 'id': 3, - 'links': [ - {'rel': 'bookmark', 'href': flavor_ref}, - ], - }, + 'imageRef': image_href, + 'flavorRef': flavor_ref, 'metadata': { 'hello': 'world', 'open': 'stack', @@ -1299,14 +1289,14 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) + print res.body self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) + self.assertEqual(1, server['id']) self.assertEqual('server_test', server['name']) self.assertEqual(expected_flavor, server['flavor']) self.assertEqual(expected_image, server['image']) - self.assertEqual(res.status_int, 200) - #self.assertEqual(1, server['id']) def test_create_instance_v1_1_invalid_flavor_href(self): self._setup_for_create_instance() @@ -1360,7 +1350,7 @@ class ServersTest(test.TestCase): self._setup_for_create_instance() image_id = "2" - flavor_ref = 'http://localhost/flavors/3' + flavor_ref = 'http://localhost/v1.1/flavors/3' expected_flavor = { "id": "3", "links": [ @@ -1394,6 +1384,7 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) + print res.body self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(expected_flavor, server['flavor']) @@ -1428,8 +1419,8 @@ class ServersTest(test.TestCase): body = { 'server': { 'name': 'server_test', - 'image': {'id': 3}, - 'flavor': {'id': 3}, + 'imageRef': 3, + 'flavorRef': 3, 'adminPass': 'testpass', }, } @@ -1452,8 +1443,8 @@ class ServersTest(test.TestCase): body = { 'server': { 'name': 'server_test', - 'image': {'id': 3}, - 'flavor': {'id': 3}, + 'imageRef': 3, + 'flavorRef': 3, 'adminPass': '', }, } -- cgit From 94866fef798a6b72061720cb654442cd194b9f5f Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 13:47:37 -0400 Subject: reverting tests to use imageRef, flavorRef --- nova/api/openstack/create_instance_helper.py | 7 +++-- nova/tests/api/openstack/test_servers.py | 5 +++- nova/tests/integrated/integrated_helpers.py | 4 +-- nova/tests/integrated/test_servers.py | 40 ++++++++-------------------- 4 files changed, 20 insertions(+), 36 deletions(-) diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py index b717b8ac0..1342397c4 100644 --- a/nova/api/openstack/create_instance_helper.py +++ b/nova/api/openstack/create_instance_helper.py @@ -319,11 +319,10 @@ class ServerXMLDeserializer(wsgi.MetadataXMLDeserializer): def _extract_personality(self, server_node): """Marshal the personality attribute of a parsed request""" - personality_node = \ - self.find_first_child_named(server_node, "personality") + node = self.find_first_child_named(server_node, "personality") personality = [] - if personality_node is not None: - for file_node in self.find_children_named(personality_node, "file"): + if node is not None: + for file_node in self.find_children_named(node, "file"): item = {} if file_node.hasAttribute("path"): item["path"] = file_node.getAttribute("path") diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index cae04e6ab..ff6f5d13a 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -2247,6 +2247,8 @@ class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): "name": "new-server-test", "imageId": "1", "flavorId": "1", + "metadata": {}, + "personality": [], }} self.assertEquals(request['body'], expected) @@ -2262,6 +2264,7 @@ class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): "imageId": "1", "flavorId": "1", "metadata": {}, + "personality": [], }} self.assertEquals(request['body'], expected) @@ -2276,6 +2279,7 @@ class TestServerCreateRequestXMLDeserializerV10(unittest.TestCase): "name": "new-server-test", "imageId": "1", "flavorId": "1", + "metadata": {}, "personality": [], }} self.assertEquals(request['body'], expected) @@ -2557,7 +2561,6 @@ class TestServerCreateRequestXMLDeserializerV11(unittest.TestCase): } self.assertEquals(request['body'], expected) - def test_image_link(self): serial_request = """ Date: Tue, 26 Jul 2011 13:49:04 -0400 Subject: fixed minor issues --- nova/api/openstack/servers.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 11dafc272..194ec82d5 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -630,8 +630,8 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): node.setAttribute('uuid', str(server['uuid'])) node.setAttribute('hostId', str(server['hostId'])) node.setAttribute('name', server['name']) - node.setAttribute('created', server['created']) - node.setAttribute('updated', server['updated']) + node.setAttribute('created', str(server['created'])) + node.setAttribute('updated', str(server['updated'])) node.setAttribute('status', server['status']) if 'progress' in server: node.setAttribute('progress', str(server['progress'])) @@ -655,17 +655,19 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer): for link_node in link_nodes: server_node.appendChild(link_node) - image_node = self._create_basic_entity_node(xml_doc, + 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) + server_node.appendChild(image_node) - flavor_node = self._create_basic_entity_node(xml_doc, + 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) + server_node.appendChild(flavor_node) metadata = server.get('metadata', {}).items() if len(metadata) > 0: -- cgit From e56d49721a22a1c337c6543c37bdd798a5c5230d Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 13:55:07 -0400 Subject: cleanup --- nova/tests/api/openstack/test_servers.py | 5 ----- nova/tests/integrated/test_servers.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index ff6f5d13a..719c4592b 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1289,7 +1289,6 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) - print res.body self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) @@ -1384,7 +1383,6 @@ class ServersTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) - print res.body self.assertEqual(res.status_int, 200) server = json.loads(res.body)['server'] self.assertEqual(expected_flavor, server['flavor']) @@ -1429,11 +1427,8 @@ class ServersTest(test.TestCase): req.method = 'POST' req.body = json.dumps(body) req.headers['content-type'] = "application/json" - res = req.get_response(fakes.wsgi_app()) - self.assertEqual(res.status_int, 200) - server = json.loads(res.body)['server'] self.assertEqual(server['adminPass'], body['server']['adminPass']) diff --git a/nova/tests/integrated/test_servers.py b/nova/tests/integrated/test_servers.py index fcb517cf5..67b3c485a 100644 --- a/nova/tests/integrated/test_servers.py +++ b/nova/tests/integrated/test_servers.py @@ -285,6 +285,26 @@ class ServersTest(integrated_helpers._IntegratedTestBase): # Cleanup self._delete_server(created_server_id) + def test_rename_server(self): + """Test building and renaming a server.""" + + # Create a server + server = self._build_minimal_create_server_request() + created_server = self.api.post_server({'server': server}) + LOG.debug("created_server: %s" % created_server) + server_id = created_server['id'] + self.assertTrue(server_id) + + # Rename the server to 'new-name' + self.api.put_server(server_id, {'server': {'name': 'new-name'}}) + + # Check the name of the server + created_server = self.api.get_server(server_id) + self.assertEqual(created_server['name'], 'new-name') + + # Cleanup + self._delete_server(server_id) + if __name__ == "__main__": unittest.main() -- cgit From 24e1f23dbaf9ffd3f42fe05c24b980a6a0f09499 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 14:06:02 -0400 Subject: removing extra function --- nova/api/openstack/servers.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 06112eee3..618778ea3 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -480,17 +480,6 @@ class ControllerV11(Controller): except exception.NotFound: raise exc.HTTPNotFound() - def _href_from_bookmark_links(self, links): - for link in links: - try: - if link.get('rel') == 'bookmark': - href = link.get('href') - if href is not None: - return href - except AttributeError: - msg = _("Malformed link entity") - raise exc.HTTPBadRequest(explanation=msg) - def _image_ref_from_req_data(self, data): try: return data['server']['imageRef'] -- cgit From f8a182d6196a9f1ba0065912e2b703ea61a1c260 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Tue, 26 Jul 2011 14:09:49 -0400 Subject: adding assert to check for progress attribute --- nova/tests/api/openstack/test_servers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 719c4592b..5e88686c4 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1293,6 +1293,7 @@ class ServersTest(test.TestCase): server = json.loads(res.body)['server'] self.assertEqual(16, len(server['adminPass'])) self.assertEqual(1, server['id']) + self.assertEqual(0, server['progress']) self.assertEqual('server_test', server['name']) self.assertEqual(expected_flavor, server['flavor']) self.assertEqual(expected_image, server['image']) -- cgit From 2e652f4cc72976ecc471a6c6f3b48afb3eb5a420 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 16:42:16 -0400 Subject: Updated test stubs to contain the correct data Updated created and updated in responses to use correct time format --- nova/api/openstack/views/servers.py | 15 +++++++++++++-- nova/tests/api/openstack/test_servers.py | 19 +++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index be25e1e40..c90801724 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -15,6 +15,7 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import hashlib import os @@ -149,8 +150,10 @@ class ViewBuilderV11(ViewBuilder): def _build_detail(self, inst): response = super(ViewBuilderV11, self)._build_detail(inst) - response['server']['created'] = inst['created_at'] - response['server']['updated'] = inst['updated_at'] + response['server']['created'] = \ + self._convert_timeformat(inst['created_at']) + response['server']['updated'] = \ + self._convert_timeformat(inst['updated_at']) if 'status' in response['server']: if response['server']['status'] == "ACTIVE": response['server']['progress'] = 100 @@ -221,3 +224,11 @@ class ViewBuilderV11(ViewBuilder): """Create an url that refers to a specific flavor id.""" return os.path.join(common.remove_version_from_href(self.base_url), "servers", str(server_id)) + + def _convert_timeformat(self, time): + """Converts the given time into the common time format + + :param time: should be a datetime + + """ + return time.strftime(utils.TIME_FORMAT) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index 4ca79434f..e154fb4fa 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -16,6 +16,7 @@ # under the License. import base64 +import datetime import json import unittest from xml.dom import minidom @@ -172,8 +173,10 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None, instance = { "id": int(id), - "created_at": "2010-10-10T12:00:00Z", - "updated_at": "2010-11-11T11:00:00Z", + "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", + "%Y-%m-%d %H:%M:%S"), + "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", + "%Y-%m-%d %H:%M:%S"), "admin_pass": "", "user_id": user_id, "project_id": "", @@ -1048,8 +1051,10 @@ class ServersTest(test.TestCase): 'uuid': FAKE_UUID, 'instance_type': dict(inst_type), 'image_ref': image_ref, - 'created_at': '2010-10-10T12:00:00Z', - 'updated_at': '2010-11-11T11:00:00Z', + "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", + "%Y-%m-%d %H:%M:%S"), + "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", + "%Y-%m-%d %H:%M:%S"), } def server_update(context, id, params): @@ -2901,8 +2906,10 @@ class ServersViewBuilderV11Test(test.TestCase): def _get_instance(self): instance = { "id": 1, - "created_at": "2010-10-10T12:00:00Z", - "updated_at": "2010-11-11T11:00:00Z", + "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", + "%Y-%m-%d %H:%M:%S"), + "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", + "%Y-%m-%d %H:%M:%S"), "admin_pass": "", "user_id": "", "project_id": "", -- cgit From e4e9d7550c2eb29c5d8fed3af0b9112976d262de Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 20:44:29 +0000 Subject: Update security gropu rules to properly support new format and boto 2.0 --- nova/api/ec2/cloud.py | 53 +++++++++++++++++++++++++++++++----------------- nova/tests/test_api.py | 8 +++++++- nova/tests/test_cloud.py | 19 ++++++++++++++++- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 10720a804..4b8c4cf80 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -539,15 +539,20 @@ class CloudController(object): return rules if 'ip_ranges' in kwargs: rules = self._cidr_args_split(kwargs) + else: + rules = [kwargs] finalset = [] for rule in rules: if 'groups' in rule: groups_values = self._groups_args_split(rule) for groups_value in groups_values: - finalset.append(groups_value) + final = self._rule_dict_last_step(context, **groups_value) + finalset.append(final) else: if rule: - finalset.append(rule) + final = self._rule_dict_last_step(context, **rule) + finalset.append(final) + LOG.warn(finalset) return finalset def _cidr_args_split(self, kwargs): @@ -590,6 +595,9 @@ class CloudController(object): db.security_group_get_by_name(context.elevated(), source_project_id, source_security_group_name) + notfound = exception.SecurityGroupNotFound + if not source_security_group: + raise notfound(security_group_id=source_security_group_name) values['group_id'] = source_security_group['id'] elif cidr_ip: # If this fails, it throws an exception. This is what we want. @@ -628,7 +636,7 @@ class CloudController(object): for rule in security_group.rules: if 'group_id' in values: if rule['group_id'] == values['group_id']: - return True + return rule['id'] else: is_duplicate = True for key in ('cidr', 'from_port', 'to_port', 'protocol'): @@ -636,7 +644,7 @@ class CloudController(object): is_duplicate = False break if is_duplicate: - return True + return rule['id'] return False def revoke_security_group_ingress(self, context, group_name=None, @@ -659,23 +667,30 @@ class CloudController(object): msg = "Revoke security group ingress %s" LOG.audit(_(msg), security_group['name'], context=context) + prevalues = [] + try: + prevalues = kwargs['ip_permissions'] + except KeyError: + prevalues.append(kwargs) + postvalues = [] + for values in prevalues: + rulesvalues = self._rule_args_to_dict(context, values) + if not rulesvalues: + err = "%s Not enough parameters to build a valid rule" + raise exception.ApiError(_(err % rulesvalues)) - criteria = self._rule_args_to_dict(context, kwargs)[0] - if criteria is None: - raise exception.ApiError(_("Not enough parameters to build a " - "valid rule.")) - - for rule in security_group.rules: - match = True - for (k, v) in criteria.iteritems(): - if getattr(rule, k, False) != v: - match = False - if match: - db.security_group_rule_destroy(context, rule['id']) - self.compute_api.trigger_security_group_rules_refresh(context, - security_group_id=security_group['id']) + rule_id = None + for values_for_rule in rulesvalues: + values_for_rule['parent_group_id'] = security_group.id + rule_id = self._security_group_rule_exists(security_group, + values_for_rule) + if rule_id: + db.security_group_rule_destroy(context, rule_id) + self.compute_api.trigger_security_group_rules_refresh(context, + security_group_id=security_group['id']) + if rule_id: return True - raise exception.ApiError(_("No rule for the specified parameters.")) + raise exception.ApiError(_("No rule for the specified parameters.")) # TODO(soren): This has only been tested with Boto as the client. # Unfortunately, it seems Boto is using an old API diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index 26ac5ff24..cd5609834 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -213,7 +213,11 @@ class ApiEc2TestCase(test.TestCase): self.http = FakeHttplibConnection( self.app, '%s:8773' % (self.host), False) # pylint: disable=E1103 - self.ec2.new_http_connection(host, is_secure).AndReturn(self.http) + if boto.Version >= '2': + self.ec2.new_http_connection(host or '%s:8773' % (self.host), + is_secure).AndReturn(self.http) + else: + self.ec2.new_http_connection(host, is_secure).AndReturn(self.http) return self.http def test_return_valid_isoformat(self): @@ -400,6 +404,8 @@ class ApiEc2TestCase(test.TestCase): self.assertEquals(int(group.rules[0].from_port), 80) self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(len(group.rules[0].grants), 1) + from nova import log + log.warn(group.rules[0].grants[0].__dict__) self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0') self.expect_http() diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 136082cc1..f87edc407 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -287,13 +287,30 @@ class CloudTestCase(test.TestCase): 'ip_protocol': u'tcp'}]} self.assertTrue(authz(self.context, group_name=sec['name'], **kwargs)) - def test_authorize_security_group_ingress_ip_permissions_groups(self): + def test_authorize_security_group_fail_missing_source_group(self): kwargs = {'project_id': self.context.project_id, 'name': 'test'} sec = db.security_group_create(self.context, kwargs) authz = self.cloud.authorize_security_group_ingress kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, 'ip_ranges':{'1': {'cidr_ip': u'0.0.0.0/0'}, '2': {'cidr_ip': u'10.10.10.10/32'}}, + 'groups': {'1': {'user_id': u'someuser', + 'group_name': u'somegroup1'}}, + 'ip_protocol': u'tcp'}]} + self.assertRaises(exception.SecurityGroupNotFound, authz, + self.context, group_name=sec['name'], **kwargs) + + def test_authorize_security_group_ingress_ip_permissions_groups(self): + kwargs = {'project_id': self.context.project_id, 'name': 'test'} + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'somegroup1'}) + sec = db.security_group_create(self.context, + {'project_id': 'someuser', + 'name': 'othergroup2'}) + sec = db.security_group_create(self.context, kwargs) + authz = self.cloud.authorize_security_group_ingress + kwargs = {'ip_permissions': [{'to_port': 81, 'from_port': 81, 'groups': {'1': {'user_id': u'someuser', 'group_name': u'somegroup1'}, '2': {'user_id': u'someuser', -- cgit From 5bd11c44f791cfe4c371b33cd1b1253013a8f836 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 20:49:46 +0000 Subject: remove some logging, remove extra if --- nova/api/ec2/cloud.py | 6 ++---- nova/tests/test_api.py | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4b8c4cf80..4045dfc61 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -549,10 +549,8 @@ class CloudController(object): final = self._rule_dict_last_step(context, **groups_value) finalset.append(final) else: - if rule: - final = self._rule_dict_last_step(context, **rule) - finalset.append(final) - LOG.warn(finalset) + final = self._rule_dict_last_step(context, **rule) + finalset.append(final) return finalset def _cidr_args_split(self, kwargs): diff --git a/nova/tests/test_api.py b/nova/tests/test_api.py index cd5609834..fe7fd8402 100644 --- a/nova/tests/test_api.py +++ b/nova/tests/test_api.py @@ -404,8 +404,6 @@ class ApiEc2TestCase(test.TestCase): self.assertEquals(int(group.rules[0].from_port), 80) self.assertEquals(int(group.rules[0].to_port), 81) self.assertEquals(len(group.rules[0].grants), 1) - from nova import log - log.warn(group.rules[0].grants[0].__dict__) self.assertEquals(str(group.rules[0].grants[0]), '0.0.0.0/0') self.expect_http() -- cgit From b97203f88c8e7926d32e8ddf664ba356869c9642 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 16:55:02 -0400 Subject: pep8 --- nova/tests/api/openstack/test_servers.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index e154fb4fa..e355ac014 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -1046,15 +1046,17 @@ class ServersTest(test.TestCase): def instance_create(context, inst): inst_type = instance_types.get_instance_type_by_flavor_id(3) image_ref = 'http://localhost/images/2' + created_at = datetime.datetime.strptime("2010-10-10 12:00:00", + "%Y-%m-%d %H:%M:%S"), + updated_at = datetime.datetime.strptime("2010-11-11 11:00:00", + "%Y-%m-%d %H:%M:%S"), return {'id': 1, 'display_name': 'server_test', 'uuid': FAKE_UUID, 'instance_type': dict(inst_type), 'image_ref': image_ref, - "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", - "%Y-%m-%d %H:%M:%S"), - "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", - "%Y-%m-%d %H:%M:%S"), + "created_at": created_at, + "updated_at": updated_at, } def server_update(context, id, params): @@ -2904,12 +2906,14 @@ class ServersViewBuilderV11Test(test.TestCase): pass def _get_instance(self): + created_at = datetime.datetime.strptime("2010-10-10 12:00:00", + "%Y-%m-%d %H:%M:%S"), + updated_at = datetime.datetime.strptime("2010-11-11 11:00:00", + "%Y-%m-%d %H:%M:%S"), instance = { "id": 1, - "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", - "%Y-%m-%d %H:%M:%S"), - "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", - "%Y-%m-%d %H:%M:%S"), + "created_at": created_at, + "updated_at": updated_at, "admin_pass": "", "user_id": "", "project_id": "", -- cgit From d4b2a2b3d552103414e4052773ac97939c66fa53 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 20:58:02 +0000 Subject: pep8 and simplify rule refresh logic --- nova/api/ec2/cloud.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py index 4045dfc61..0294c09c5 100644 --- a/nova/api/ec2/cloud.py +++ b/nova/api/ec2/cloud.py @@ -670,25 +670,26 @@ class CloudController(object): prevalues = kwargs['ip_permissions'] except KeyError: prevalues.append(kwargs) - postvalues = [] + rule_id = None for values in prevalues: rulesvalues = self._rule_args_to_dict(context, values) if not rulesvalues: err = "%s Not enough parameters to build a valid rule" raise exception.ApiError(_(err % rulesvalues)) - rule_id = None for values_for_rule in rulesvalues: values_for_rule['parent_group_id'] = security_group.id rule_id = self._security_group_rule_exists(security_group, values_for_rule) if rule_id: db.security_group_rule_destroy(context, rule_id) - self.compute_api.trigger_security_group_rules_refresh(context, - security_group_id=security_group['id']) - if rule_id: - return True - raise exception.ApiError(_("No rule for the specified parameters.")) + if rule_id: + # NOTE(vish): we removed a rule, so refresh + self.compute_api.trigger_security_group_rules_refresh( + context, + security_group_id=security_group['id']) + return True + raise exception.ApiError(_("No rule for the specified parameters.")) # TODO(soren): This has only been tested with Boto as the client. # Unfortunately, it seems Boto is using an old API @@ -734,15 +735,17 @@ class CloudController(object): postvalues.append(values_for_rule) for values_for_rule in postvalues: - security_group_rule = db.security_group_rule_create(context, - values_for_rule) + security_group_rule = db.security_group_rule_create( + context, + values_for_rule) - self.compute_api.trigger_security_group_rules_refresh(context, - security_group_id=security_group['id']) + if postvalues: + self.compute_api.trigger_security_group_rules_refresh( + context, + security_group_id=security_group['id']) + return True - group = db.security_group_get_by_name(context, context.project_id, - security_group['name']) - return True + raise exception.ApiError(_("No rule for the specified parameters.")) def _get_source_project_id(self, context, source_security_group_owner_id): if source_security_group_owner_id: -- cgit From 9da71385e90a281483aac86a48e36a0e63bfe155 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 26 Jul 2011 17:18:27 -0400 Subject: cleanup --- nova/tests/api/openstack/test_servers.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py index e355ac014..7c465314f 100644 --- a/nova/tests/api/openstack/test_servers.py +++ b/nova/tests/api/openstack/test_servers.py @@ -173,10 +173,8 @@ def stub_instance(id, user_id=1, private_address=None, public_addresses=None, instance = { "id": int(id), - "created_at": datetime.datetime.strptime("2010-10-10 12:00:00", - "%Y-%m-%d %H:%M:%S"), - "updated_at": datetime.datetime.strptime("2010-11-11 11:00:00", - "%Y-%m-%d %H:%M:%S"), + "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), + "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), "admin_pass": "", "user_id": user_id, "project_id": "", @@ -1046,17 +1044,13 @@ class ServersTest(test.TestCase): def instance_create(context, inst): inst_type = instance_types.get_instance_type_by_flavor_id(3) image_ref = 'http://localhost/images/2' - created_at = datetime.datetime.strptime("2010-10-10 12:00:00", - "%Y-%m-%d %H:%M:%S"), - updated_at = datetime.datetime.strptime("2010-11-11 11:00:00", - "%Y-%m-%d %H:%M:%S"), return {'id': 1, 'display_name': 'server_test', 'uuid': FAKE_UUID, 'instance_type': dict(inst_type), 'image_ref': image_ref, - "created_at": created_at, - "updated_at": updated_at, + "created_at": datetime.datetime(2010, 10, 10, 12, 0, 0), + "updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0), } def server_update(context, id, params): @@ -2906,10 +2900,8 @@ class ServersViewBuilderV11Test(test.TestCase): pass def _get_instance(self): - created_at = datetime.datetime.strptime("2010-10-10 12:00:00", - "%Y-%m-%d %H:%M:%S"), - updated_at = datetime.datetime.strptime("2010-11-11 11:00:00", - "%Y-%m-%d %H:%M:%S"), + created_at = datetime.datetime(2010, 10, 10, 12, 0, 0) + updated_at = datetime.datetime(2010, 11, 11, 11, 0, 0) instance = { "id": 1, "created_at": created_at, -- cgit From 5c812bbdc15e0cf974026fcfaacd54e7a9f144cc Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 21:29:24 +0000 Subject: cherry-pick tr3buchet's fix for milestone branch --- nova/compute/manager.py | 2 +- nova/network/api.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 31627fe3b..893c18aef 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -868,7 +868,7 @@ class ComputeManager(manager.SchedulerDependentManager): """ self.network_api.add_fixed_ip_to_instance(context, instance_id, - network_id) + self.host, network_id) self.inject_network_info(context, instance_id) self.reset_network(context, instance_id) diff --git a/nova/network/api.py b/nova/network/api.py index 33a9fe239..247768722 100644 --- a/nova/network/api.py +++ b/nova/network/api.py @@ -164,9 +164,10 @@ class API(base.Base): {'method': 'deallocate_for_instance', 'args': args}) - def add_fixed_ip_to_instance(self, context, instance_id, network_id): + def add_fixed_ip_to_instance(self, context, instance_id, host, network_id): """Adds a fixed ip to instance from specified network.""" args = {'instance_id': instance_id, + 'host': host, 'network_id': network_id} rpc.cast(context, FLAGS.network_topic, {'method': 'add_fixed_ip_to_instance', -- cgit From 4f313565881608a19dd77be818e2c80c4e0e9c95 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 22:48:36 +0000 Subject: cloud tests all passing again --- nova/tests/test_cloud.py | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/nova/tests/test_cloud.py b/nova/tests/test_cloud.py index 136082cc1..927edb861 100644 --- a/nova/tests/test_cloud.py +++ b/nova/tests/test_cloud.py @@ -121,7 +121,6 @@ class CloudTestCase(test.TestCase): public_ip=address) db.floating_ip_destroy(self.context, address) - @test.skip_test("Skipping this pending future merge") def test_allocate_address(self): address = "10.10.10.10" allocate = self.cloud.allocate_address @@ -161,13 +160,10 @@ class CloudTestCase(test.TestCase): # ApiError: Floating ip is in use. Disassociate it before releasing. self.assertRaises(exception.ApiError, release, self.context, address) - @test.skip_test("Skipping this pending future merge") def test_associate_disassociate_address(self): """Verifies associate runs cleanly without raising an exception""" address = "10.10.10.10" - db.floating_ip_create(self.context, - {'address': address, - 'host': self.network.host}) + db.floating_ip_create(self.context, {'address': address}) self.cloud.allocate_address(self.context) # TODO(jkoelker) Probably need to query for instance_type_id and # make sure we get a valid one @@ -175,11 +171,14 @@ class CloudTestCase(test.TestCase): 'instance_type_id': 1}) networks = db.network_get_all(self.context) for network in networks: - self.network.set_network_host(self.context, network['id']) + db.network_update(self.context, network['id'], + {'host': self.network.host}) project_id = self.context.project_id type_id = inst['instance_type_id'] ips = self.network.allocate_for_instance(self.context, instance_id=inst['id'], + host=inst['host'], + vpn=None, instance_type_id=type_id, project_id=project_id) # TODO(jkoelker) Make this mas bueno @@ -405,8 +404,6 @@ class CloudTestCase(test.TestCase): db.service_destroy(self.context, service1['id']) db.service_destroy(self.context, service2['id']) - # NOTE(jkoelker): this test relies on fixed_ip being in instances - @test.skip_test("EC2 stuff needs fixed_ip in instance_ref") def test_describe_snapshots(self): """Makes sure describe_snapshots works and filters results.""" vol = db.volume_create(self.context, {}) @@ -1041,12 +1038,6 @@ class CloudTestCase(test.TestCase): self.cloud.delete_key_pair(self.context, 'test') def test_run_instances(self): - # stub out the rpc call - def stub_cast(*args, **kwargs): - pass - - self.stubs.Set(rpc, 'cast', stub_cast) - kwargs = {'image_id': FLAGS.default_image, 'instance_type': FLAGS.default_instance_type, 'max_count': 1} @@ -1056,7 +1047,7 @@ class CloudTestCase(test.TestCase): self.assertEqual(instance['imageId'], 'ami-00000001') self.assertEqual(instance['displayName'], 'Server 1') self.assertEqual(instance['instanceId'], 'i-00000001') - self.assertEqual(instance['instanceState']['name'], 'scheduling') + self.assertEqual(instance['instanceState']['name'], 'running') self.assertEqual(instance['instanceType'], 'm1.small') def test_run_instances_image_state_none(self): @@ -1128,16 +1119,15 @@ class CloudTestCase(test.TestCase): self.assertEqual('c00l 1m4g3', inst['display_name']) db.instance_destroy(self.context, inst['id']) - # NOTE(jkoelker): This test relies on mac_address in instance - @test.skip_test("EC2 stuff needs mac_address in instance_ref") def test_update_of_instance_wont_update_private_fields(self): inst = db.instance_create(self.context, {}) + host = inst['host'] ec2_id = ec2utils.id_to_ec2_id(inst['id']) self.cloud.update_instance(self.context, ec2_id, display_name='c00l 1m4g3', - mac_address='DE:AD:BE:EF') + host='otherhost') inst = db.instance_get(self.context, inst['id']) - self.assertEqual(None, inst['mac_address']) + self.assertEqual(host, inst['host']) db.instance_destroy(self.context, inst['id']) def test_update_of_volume_display_fields(self): @@ -1193,7 +1183,6 @@ class CloudTestCase(test.TestCase): elevated = self.context.elevated(read_deleted=True) self._wait_for_state(elevated, instance_id, is_deleted) - @test.skip_test("skipping, test is hanging with multinic for rpc reasons") def test_stop_start_instance(self): """Makes sure stop/start instance works""" # enforce periodic tasks run in short time to avoid wait for 60s. @@ -1251,7 +1240,6 @@ class CloudTestCase(test.TestCase): self.assertEqual(vol['status'], "available") self.assertEqual(vol['attach_status'], "detached") - @test.skip_test("skipping, test is hanging with multinic for rpc reasons") def test_stop_start_with_volume(self): """Make sure run instance with block device mapping works""" @@ -1320,7 +1308,6 @@ class CloudTestCase(test.TestCase): self._restart_compute_service() - @test.skip_test("skipping, test is hanging with multinic for rpc reasons") def test_stop_with_attached_volume(self): """Make sure attach info is reflected to block device mapping""" # enforce periodic tasks run in short time to avoid wait for 60s. @@ -1396,7 +1383,6 @@ class CloudTestCase(test.TestCase): greenthread.sleep(0.3) return result['snapshotId'] - @test.skip_test("skipping, test is hanging with multinic for rpc reasons") def test_run_with_snapshot(self): """Makes sure run/stop/start instance with snapshot works.""" vol = self._volume_create() -- cgit From 54de340991c6c2dbd50d6efa4054102eef6df3a0 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 27 Jul 2011 00:40:50 +0000 Subject: fix the skipped tests in vmwareapi xenapi and quota --- nova/tests/test_quota.py | 3 +- nova/tests/test_vmwareapi.py | 107 ++++++++++++++++------------------- nova/tests/test_xenapi.py | 56 +++++++++--------- nova/tests/vmwareapi/db_fakes.py | 10 ++-- nova/tests/vmwareapi/stubs.py | 7 +++ nova/virt/vmwareapi/fake.py | 10 ++++ nova/virt/vmwareapi/network_utils.py | 1 + nova/virt/vmwareapi/vm_util.py | 3 +- nova/virt/vmwareapi/vmops.py | 7 ++- nova/virt/xenapi/vmops.py | 2 +- 10 files changed, 110 insertions(+), 96 deletions(-) diff --git a/nova/tests/test_quota.py b/nova/tests/test_quota.py index 69d2deafe..a35caadf8 100644 --- a/nova/tests/test_quota.py +++ b/nova/tests/test_quota.py @@ -269,11 +269,10 @@ class QuotaTestCase(test.TestCase): for volume_id in volume_ids: db.volume_destroy(self.context, volume_id) - @test.skip_test def test_too_many_addresses(self): address = '192.168.0.100' db.floating_ip_create(context.get_admin_context(), - {'address': address, 'host': FLAGS.host, + {'address': address, 'project_id': self.project.id}) self.assertRaises(quota.QuotaError, self.network.allocate_floating_ip, diff --git a/nova/tests/test_vmwareapi.py b/nova/tests/test_vmwareapi.py index cbf7801cf..7313508a6 100644 --- a/nova/tests/test_vmwareapi.py +++ b/nova/tests/test_vmwareapi.py @@ -19,9 +19,6 @@ Test suite for VMWareAPI. """ -import stubout - -from nova import context from nova import db from nova import flags from nova import test @@ -41,51 +38,66 @@ FLAGS = flags.FLAGS class VMWareAPIVMTestCase(test.TestCase): """Unit tests for Vmware API connection calls.""" - # NOTE(jkoelker): This is leaking stubs into the db module. - # Commenting out until updated for multi-nic. - #def setUp(self): - # super(VMWareAPIVMTestCase, self).setUp() - # self.flags(vmwareapi_host_ip='test_url', - # vmwareapi_host_username='test_username', - # vmwareapi_host_password='test_pass') - # self.manager = manager.AuthManager() - # self.user = self.manager.create_user('fake', 'fake', 'fake', - # admin=True) - # self.project = self.manager.create_project('fake', 'fake', 'fake') - # self.network = utils.import_object(FLAGS.network_manager) - # self.stubs = stubout.StubOutForTesting() - # vmwareapi_fake.reset() - # db_fakes.stub_out_db_instance_api(self.stubs) - # stubs.set_stubs(self.stubs) - # glance_stubs.stubout_glance_client(self.stubs, - # glance_stubs.FakeGlance) - # self.conn = vmwareapi_conn.get_connection(False) - - #def tearDown(self): - # super(VMWareAPIVMTestCase, self).tearDown() - # vmwareapi_fake.cleanup() - # self.manager.delete_project(self.project) - # self.manager.delete_user(self.user) - # self.stubs.UnsetAll() + def setUp(self): + super(VMWareAPIVMTestCase, self).setUp() + self.flags(vmwareapi_host_ip='test_url', + vmwareapi_host_username='test_username', + vmwareapi_host_password='test_pass') + self.manager = manager.AuthManager() + self.user = self.manager.create_user('fake', 'fake', 'fake', + admin=True) + self.project = self.manager.create_project('fake', 'fake', 'fake') + self.network = utils.import_object(FLAGS.network_manager) + vmwareapi_fake.reset() + db_fakes.stub_out_db_instance_api(self.stubs) + stubs.set_stubs(self.stubs) + glance_stubs.stubout_glance_client(self.stubs) + self.conn = vmwareapi_conn.get_connection(False) + # NOTE(vish): none of the network plugging code is actually + # being tested + self.network_info = [({'bridge': 'fa0', + 'id': 0, + 'vlan': None, + 'bridge_interface': None, + 'injected': True}, + {'broadcast': '192.168.0.255', + 'dns': ['192.168.0.1'], + 'gateway': '192.168.0.1', + 'gateway6': 'dead:beef::1', + 'ip6s': [{'enabled': '1', + 'ip': 'dead:beef::dcad:beff:feef:0', + 'netmask': '64'}], + 'ips': [{'enabled': '1', + 'ip': '192.168.0.100', + 'netmask': '255.255.255.0'}], + 'label': 'fake', + 'mac': 'DE:AD:BE:EF:00:00', + 'rxtx_cap': 3})] + + def tearDown(self): + super(VMWareAPIVMTestCase, self).tearDown() + vmwareapi_fake.cleanup() + self.manager.delete_project(self.project) + self.manager.delete_user(self.user) def _create_instance_in_the_db(self): values = {'name': 1, 'id': 1, 'project_id': self.project.id, 'user_id': self.user.id, - 'image_id': "1", + 'image_ref': "1", 'kernel_id': "1", 'ramdisk_id': "1", + 'mac_address': "de:ad:be:ef:be:ef", 'instance_type': 'm1.large', - 'mac_address': 'aa:bb:cc:dd:ee:ff', } - self.instance = db.instance_create(values) + self.instance = db.instance_create(None, values) def _create_vm(self): """Create and spawn the VM.""" self._create_instance_in_the_db() self.type_data = db.instance_type_get_by_name(None, 'm1.large') - self.conn.spawn(self.instance) + self.conn.spawn(self.instance, self.network_info) self._check_vm_record() def _check_vm_record(self): @@ -129,24 +141,20 @@ class VMWareAPIVMTestCase(test.TestCase): self.assertEquals(info["mem"], mem_kib) self.assertEquals(info["num_cpu"], self.type_data['vcpus']) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_list_instances(self): instances = self.conn.list_instances() self.assertEquals(len(instances), 0) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_list_instances_1(self): self._create_vm() instances = self.conn.list_instances() self.assertEquals(len(instances), 1) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_spawn(self): self._create_vm() info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_snapshot(self): self._create_vm() info = self.conn.get_info(1) @@ -155,27 +163,23 @@ class VMWareAPIVMTestCase(test.TestCase): info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_snapshot_non_existent(self): self._create_instance_in_the_db() self.assertRaises(Exception, self.conn.snapshot, self.instance, "Test-Snapshot") - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_reboot(self): self._create_vm() info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - self.conn.reboot(self.instance) + self.conn.reboot(self.instance, self.network_info) info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_reboot_non_existent(self): self._create_instance_in_the_db() self.assertRaises(Exception, self.conn.reboot, self.instance) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_reboot_not_poweredon(self): self._create_vm() info = self.conn.get_info(1) @@ -185,7 +189,6 @@ class VMWareAPIVMTestCase(test.TestCase): self._check_vm_info(info, power_state.PAUSED) self.assertRaises(Exception, self.conn.reboot, self.instance) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_suspend(self): self._create_vm() info = self.conn.get_info(1) @@ -194,13 +197,11 @@ class VMWareAPIVMTestCase(test.TestCase): info = self.conn.get_info(1) self._check_vm_info(info, power_state.PAUSED) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_suspend_non_existent(self): self._create_instance_in_the_db() self.assertRaises(Exception, self.conn.suspend, self.instance, self.dummy_callback_handler) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_resume(self): self._create_vm() info = self.conn.get_info(1) @@ -212,13 +213,11 @@ class VMWareAPIVMTestCase(test.TestCase): info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_resume_non_existent(self): self._create_instance_in_the_db() self.assertRaises(Exception, self.conn.resume, self.instance, self.dummy_callback_handler) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_resume_not_suspended(self): self._create_vm() info = self.conn.get_info(1) @@ -226,49 +225,41 @@ class VMWareAPIVMTestCase(test.TestCase): self.assertRaises(Exception, self.conn.resume, self.instance, self.dummy_callback_handler) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_get_info(self): self._create_vm() info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_destroy(self): self._create_vm() info = self.conn.get_info(1) self._check_vm_info(info, power_state.RUNNING) instances = self.conn.list_instances() self.assertEquals(len(instances), 1) - self.conn.destroy(self.instance) + self.conn.destroy(self.instance, self.network_info) instances = self.conn.list_instances() self.assertEquals(len(instances), 0) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_destroy_non_existent(self): self._create_instance_in_the_db() - self.assertEquals(self.conn.destroy(self.instance), None) + self.assertEquals(self.conn.destroy(self.instance, self.network_info), + None) - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_pause(self): pass - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_unpause(self): pass - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_diagnostics(self): pass - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_get_console_output(self): pass - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def test_get_ajax_console(self): pass - @test.skip_test("DB stubbing not removed, needs updating for multi-nic") def dummy_callback_handler(self, ret): """ Dummy callback function to be passed to suspend, resume, etc., calls. diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 199a8bc52..4338eb7a0 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -396,18 +396,22 @@ class XenAPIVMTestCase(test.TestCase): def _test_spawn(self, image_ref, kernel_id, ramdisk_id, instance_type_id="3", os_type="linux", architecture="x86-64", instance_id=1, - check_injection=False): + check_injection=False, + create_record=True): stubs.stubout_loopingcall_start(self.stubs) - values = {'id': instance_id, - 'project_id': self.project.id, - 'user_id': self.user.id, - 'image_ref': image_ref, - 'kernel_id': kernel_id, - 'ramdisk_id': ramdisk_id, - 'instance_type_id': instance_type_id, - 'os_type': os_type, - 'architecture': architecture} - instance = db.instance_create(self.context, values) + if create_record: + values = {'id': instance_id, + 'project_id': self.project.id, + 'user_id': self.user.id, + 'image_ref': image_ref, + 'kernel_id': kernel_id, + 'ramdisk_id': ramdisk_id, + 'instance_type_id': instance_type_id, + 'os_type': os_type, + 'architecture': architecture} + instance = db.instance_create(self.context, values) + else: + instance = db.instance_get(self.context, instance_id) network_info = [({'bridge': 'fa0', 'id': 0, 'injected': True}, {'broadcast': '192.168.0.255', 'dns': ['192.168.0.1'], @@ -599,41 +603,38 @@ class XenAPIVMTestCase(test.TestCase): # guest agent is detected self.assertFalse(self._tee_executed) - @test.skip_test("Never gets an address, not sure why") def test_spawn_vlanmanager(self): self.flags(xenapi_image_service='glance', network_manager='nova.network.manager.VlanManager', - network_driver='nova.network.xenapi_net', vlan_interface='fake0') def dummy(*args, **kwargs): pass - self.stubs.Set(VMOps, 'create_vifs', dummy) + self.stubs.Set(vmops.VMOps, 'create_vifs', dummy) # Reset network table xenapi_fake.reset_table('network') # Instance id = 2 will use vlan network (see db/fakes.py) ctxt = self.context.elevated() - instance_ref = self._create_instance(2) - network_bk = self.network - # Ensure we use xenapi_net driver - self.network = utils.import_object(FLAGS.network_manager) + instance = self._create_instance(2, False) networks = self.network.db.network_get_all(ctxt) for network in networks: - self.network.set_network_host(ctxt, network['id']) - - self.network.allocate_for_instance(ctxt, instance_id=instance_ref.id, - instance_type_id=1, project_id=self.project.id) - self.network.setup_compute_network(ctxt, instance_ref.id) + self.network.set_network_host(ctxt, network) + + self.network.allocate_for_instance(ctxt, + instance_id=2, + host=FLAGS.host, + vpn=None, + instance_type_id=1, + project_id=self.project.id) self._test_spawn(glance_stubs.FakeGlance.IMAGE_MACHINE, glance_stubs.FakeGlance.IMAGE_KERNEL, glance_stubs.FakeGlance.IMAGE_RAMDISK, - instance_id=instance_ref.id, + instance_id=2, create_record=False) # TODO(salvatore-orlando): a complete test here would require # a check for making sure the bridge for the VM's VIF is # consistent with bridge specified in nova db - self.network = network_bk def test_spawn_with_network_qos(self): self._create_instance() @@ -663,7 +664,7 @@ class XenAPIVMTestCase(test.TestCase): self.vm = None self.stubs.UnsetAll() - def _create_instance(self, instance_id=1): + def _create_instance(self, instance_id=1, spawn=True): """Creates and spawns a test instance.""" stubs.stubout_loopingcall_start(self.stubs) values = { @@ -691,7 +692,8 @@ class XenAPIVMTestCase(test.TestCase): 'label': 'fake', 'mac': 'DE:AD:BE:EF:00:00', 'rxtx_cap': 3})] - self.conn.spawn(instance, network_info) + if spawn: + self.conn.spawn(instance, network_info) return instance diff --git a/nova/tests/vmwareapi/db_fakes.py b/nova/tests/vmwareapi/db_fakes.py index d4eb87daf..afd672c7a 100644 --- a/nova/tests/vmwareapi/db_fakes.py +++ b/nova/tests/vmwareapi/db_fakes.py @@ -70,8 +70,8 @@ def stub_out_db_instance_api(stubs): 'launch_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), 'instance_type': values['instance_type'], 'memory_mb': type_data['memory_mb'], - 'mac_address': values['mac_address'], 'vcpus': type_data['vcpus'], + 'mac_addresses': [{'address': values['mac_address']}], 'local_gb': type_data['local_gb'], } return FakeModel(base_options) @@ -83,6 +83,8 @@ def stub_out_db_instance_api(stubs): 'bridge': 'vmnet0', 'netmask': '255.255.255.0', 'gateway': '10.10.10.1', + 'broadcast': '10.10.10.255', + 'dns1': 'fake', 'vlan': 100} return FakeModel(fields) @@ -90,7 +92,7 @@ def stub_out_db_instance_api(stubs): """Stubs out the db.instance_action_create method.""" pass - def fake_instance_get_fixed_address(context, instance_id): + def fake_instance_get_fixed_addresses(context, instance_id): """Stubs out the db.instance_get_fixed_address method.""" return '10.10.10.10' @@ -103,7 +105,7 @@ def stub_out_db_instance_api(stubs): stubs.Set(db, 'instance_create', fake_instance_create) stubs.Set(db, 'network_get_by_instance', fake_network_get_by_instance) stubs.Set(db, 'instance_action_create', fake_instance_action_create) - stubs.Set(db, 'instance_get_fixed_address', - fake_instance_get_fixed_address) + stubs.Set(db, 'instance_get_fixed_addresses', + fake_instance_get_fixed_addresses) stubs.Set(db, 'instance_type_get_all', fake_instance_type_get_all) stubs.Set(db, 'instance_type_get_by_name', fake_instance_type_get_by_name) diff --git a/nova/tests/vmwareapi/stubs.py b/nova/tests/vmwareapi/stubs.py index a648efb16..0ed5e9b68 100644 --- a/nova/tests/vmwareapi/stubs.py +++ b/nova/tests/vmwareapi/stubs.py @@ -22,6 +22,8 @@ Stubouts for the test suite from nova.virt import vmwareapi_conn from nova.virt.vmwareapi import fake from nova.virt.vmwareapi import vmware_images +from nova.virt.vmwareapi import vmops +from nova.virt.vmwareapi import network_utils def fake_get_vim_object(arg): @@ -36,10 +38,15 @@ def fake_is_vim_object(arg, module): def set_stubs(stubs): """Set the stubs.""" + stubs.Set(vmops.VMWareVMOps, 'plug_vifs', fake.fake_plug_vifs) + stubs.Set(network_utils, 'get_network_with_the_name', + fake.fake_get_network) stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image) stubs.Set(vmware_images, 'get_vmdk_size_and_properties', fake.fake_get_vmdk_size_and_properties) stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image) + stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object", + fake_get_vim_object) stubs.Set(vmwareapi_conn.VMWareAPISession, "_get_vim_object", fake_get_vim_object) stubs.Set(vmwareapi_conn.VMWareAPISession, "_is_vim_object", diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 7370684bd..4c62d18bb 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -402,6 +402,16 @@ def _remove_file(file_path): lst_files.remove(file) +def fake_plug_vifs(*args, **kwargs): + """Fakes plugging vifs.""" + pass + + +def fake_get_network(*args, **kwargs): + """Fake get network.""" + return [{'type': 'fake'}] + + def fake_fetch_image(image, instance, **kwargs): """Fakes fetch image call. Just adds a reference to the db for the file.""" ds_name = kwargs.get("datastore_name") diff --git a/nova/virt/vmwareapi/network_utils.py b/nova/virt/vmwareapi/network_utils.py index 08e3bf0b1..ec3b93fe7 100644 --- a/nova/virt/vmwareapi/network_utils.py +++ b/nova/virt/vmwareapi/network_utils.py @@ -46,6 +46,7 @@ def get_network_with_the_name(session, network_name="vmnet0"): "get_properties_for_a_collection_of_objects", "Network", vm_networks, ["summary.name"]) network_obj = {} + LOG.warn(vm_networks) for network in vm_networks: # Get network properties if network._type == 'DistributedVirtualPortgroup': diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py index 55578dd3c..82b5f7214 100644 --- a/nova/virt/vmwareapi/vm_util.py +++ b/nova/virt/vmwareapi/vm_util.py @@ -110,7 +110,8 @@ def create_network_spec(client_factory, network_name, mac_address, # ephemeral. Invalid configuration if set to static and the NIC does # not come up on boot if set to dynamic. backing = None - if (network_ref['type'] == "DistributedVirtualPortgroup"): + if (network_ref and + network_ref['type'] == "DistributedVirtualPortgroup"): backing_name = \ 'ns0:VirtualEthernetCardDistributedVirtualPortBackingInfo' backing = \ diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index 7e7d2dac3..1ee8fa1c0 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -734,13 +734,14 @@ class VMWareVMOps(object): net_mask = network["netmask"] gateway = network["gateway"] broadcast = network["broadcast"] - dns = network["dns"] + # TODO(vish): add support for dns2 + dns = network["dns1"] addresses = db.instance_get_fixed_addresses(admin_context, instance['id']) ip_addr = addresses[0] if addresses else None - machine_id_chanfge_spec = \ + machine_id_change_spec = \ vm_util.get_machine_id_change_spec(client_factory, mac_address, ip_addr, net_mask, gateway, broadcast, dns) @@ -750,7 +751,7 @@ class VMWareVMOps(object): 'ip_addr': ip_addr})) reconfig_task = self._session._call_method(self._session._get_vim(), "ReconfigVM_Task", vm_ref, - spec=machine_id_chanfge_spec) + spec=machine_id_change_spec) self._session._wait_for_task(instance.id, reconfig_task) LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id " "with ip - %(ip_addr)s") % diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 0473abb97..6154cb9e7 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -1092,7 +1092,7 @@ class VMOps(object): LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,' ' network %(network_ref)s.') % locals()) - def plug_vifs(instance, network_info): + def plug_vifs(self, instance, network_info): """Set up VIF networking on the host.""" for (network, mapping) in network_info: self.vif_driver.plug(self._session, instance, network, mapping) -- cgit From fc87e8acff4ef3b0e048f66c2cddfb6880f1fd60 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 27 Jul 2011 01:01:43 +0000 Subject: fix the first round of missing data --- nova/tests/test_libvirt.py | 26 ++++++-------------------- nova/virt/libvirt/netutils.py | 1 + 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index ad0931a89..e01da1c79 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -280,7 +280,6 @@ class LibvirtConnTestCase(test.TestCase): return db.service_create(context.get_admin_context(), service_ref) - @test.skip_test("Please review this test to ensure intent") def test_preparing_xml_info(self): conn = connection.LibvirtConnection(True) instance_ref = db.instance_create(self.context, self.test_instance) @@ -296,27 +295,23 @@ class LibvirtConnTestCase(test.TestCase): _create_network_info(2)) self.assertTrue(len(result['nics']) == 2) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_xml_and_uri_no_ramdisk_no_kernel(self): instance_data = dict(self.test_instance) self._check_xml_and_uri(instance_data, expect_kernel=False, expect_ramdisk=False) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_xml_and_uri_no_ramdisk(self): instance_data = dict(self.test_instance) instance_data['kernel_id'] = 'aki-deadbeef' self._check_xml_and_uri(instance_data, expect_kernel=True, expect_ramdisk=False) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_xml_and_uri_no_kernel(self): instance_data = dict(self.test_instance) instance_data['ramdisk_id'] = 'ari-deadbeef' self._check_xml_and_uri(instance_data, expect_kernel=False, expect_ramdisk=False) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_xml_and_uri(self): instance_data = dict(self.test_instance) instance_data['ramdisk_id'] = 'ari-deadbeef' @@ -324,7 +319,6 @@ class LibvirtConnTestCase(test.TestCase): self._check_xml_and_uri(instance_data, expect_kernel=True, expect_ramdisk=True) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_xml_and_uri_rescue(self): instance_data = dict(self.test_instance) instance_data['ramdisk_id'] = 'ari-deadbeef' @@ -332,7 +326,6 @@ class LibvirtConnTestCase(test.TestCase): self._check_xml_and_uri(instance_data, expect_kernel=True, expect_ramdisk=True, rescue=True) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_lxc_container_and_uri(self): instance_data = dict(self.test_instance) self._check_xml_and_container(instance_data) @@ -743,7 +736,6 @@ class LibvirtConnTestCase(test.TestCase): db.volume_destroy(self.context, volume_ref['id']) db.instance_destroy(self.context, instance_ref['id']) - @test.skip_test("test needs rewrite: instance no longer has mac_address") def test_spawn_with_network_info(self): # Skip if non-libvirt environment if not self.lazy_load_library_exists(): @@ -895,7 +887,6 @@ class IptablesFirewallTestCase(test.TestCase): 'project_id': 'fake', 'instance_type_id': 1}) - @test.skip_test("skipping libvirt tests depends on get_network_info shim") def test_static_filters(self): instance_ref = self._create_instance_ref() ip = '10.11.12.13' @@ -1047,7 +1038,6 @@ class IptablesFirewallTestCase(test.TestCase): self.assertEquals(ipv6_network_rules, ipv6_rules_per_network * networks_count) - @test.skip_test("skipping libvirt tests") def test_do_refresh_security_group_rules(self): instance_ref = self._create_instance_ref() self.mox.StubOutWithMock(self.fw, @@ -1058,7 +1048,6 @@ class IptablesFirewallTestCase(test.TestCase): self.mox.ReplayAll() self.fw.do_refresh_security_group_rules("fake") - @test.skip_test("skip libvirt test project_get_network no longer exists") def test_unfilter_instance_undefines_nwfilter(self): # Skip if non-libvirt environment if not self.lazy_load_library_exists(): @@ -1092,7 +1081,6 @@ class IptablesFirewallTestCase(test.TestCase): db.instance_destroy(admin_ctxt, instance_ref['id']) - @test.skip_test("skip libvirt test project_get_network no longer exists") def test_provider_firewall_rules(self): # setup basic instance data instance_ref = self._create_instance_ref() @@ -1259,7 +1247,6 @@ class NWFilterTestCase(test.TestCase): inst.update(params) return db.instance_type_create(context, inst)['id'] - @test.skip_test('Skipping this test') def test_creates_base_rule_first(self): # These come pre-defined by libvirt self.defined_filters = ['no-mac-spoofing', @@ -1293,13 +1280,13 @@ class NWFilterTestCase(test.TestCase): ip = '10.11.12.13' - #network_ref = db.project_get_networks(self.context, 'fake')[0] - #fixed_ip = {'address': ip, 'network_id': network_ref['id']} + network_ref = db.project_get_networks(self.context, 'fake')[0] + fixed_ip = {'address': ip, 'network_id': network_ref['id']} - #admin_ctxt = context.get_admin_context() - #db.fixed_ip_create(admin_ctxt, fixed_ip) - #db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - # 'instance_id': inst_id}) + admin_ctxt = context.get_admin_context() + db.fixed_ip_create(admin_ctxt, fixed_ip) + db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, + 'instance_id': inst_id}) self._setup_networking(instance_ref['id'], ip=ip) @@ -1336,7 +1323,6 @@ class NWFilterTestCase(test.TestCase): "fake") self.assertEquals(len(result), 3) - @test.skip_test("skip libvirt test project_get_network no longer exists") def test_unfilter_instance_undefines_nwfilters(self): admin_ctxt = context.get_admin_context() diff --git a/nova/virt/libvirt/netutils.py b/nova/virt/libvirt/netutils.py index 041eacb2d..019f4ce2b 100644 --- a/nova/virt/libvirt/netutils.py +++ b/nova/virt/libvirt/netutils.py @@ -89,6 +89,7 @@ def get_network_info(instance): 'label': network['label'], 'gateway': network['gateway'], 'broadcast': network['broadcast'], + 'dhcp_server': network['gateway'], 'mac': vif['address'], 'rxtx_cap': flavor['rxtx_cap'], 'dns': [], -- cgit From 6a757bbbbda208a7e141e56e2334c5a501645adb Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 22:55:58 -0700 Subject: fix more tests --- nova/tests/test_libvirt.py | 11 +++++++---- nova/virt/libvirt/netutils.py | 10 +++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index e01da1c79..377c92aca 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -1065,11 +1065,13 @@ class IptablesFirewallTestCase(test.TestCase): instance = db.instance_get(self.context, inst_id) ip = '10.11.12.13' - network_ref = db.project_get_network(self.context, 'fake') + network_ref = db.project_get_networks(self.context, 'fake')[0] fixed_ip = {'address': ip, 'network_id': network_ref['id']} db.fixed_ip_create(admin_ctxt, fixed_ip) db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, 'instance_id': inst_id}) + + _setup_networking(inst_id, ip) self.fw.setup_basic_filtering(instance) self.fw.prepare_instance_filter(instance) self.fw.apply_instance_filter(instance) @@ -1086,7 +1088,7 @@ class IptablesFirewallTestCase(test.TestCase): instance_ref = self._create_instance_ref() nw_info = _create_network_info(1) ip = '10.11.12.13' - network_ref = db.project_get_network(self.context, 'fake') + network_ref = db.project_get_networks(self.context, 'fake')[0] admin_ctxt = context.get_admin_context() fixed_ip = {'address': ip, 'network_id': network_ref['id']} db.fixed_ip_create(admin_ctxt, fixed_ip) @@ -1288,7 +1290,7 @@ class NWFilterTestCase(test.TestCase): db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, 'instance_id': inst_id}) - self._setup_networking(instance_ref['id'], ip=ip) + _setup_networking(instance_ref['id'], ip=ip) def _ensure_all_called(): instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'], @@ -1341,7 +1343,7 @@ class NWFilterTestCase(test.TestCase): instance = db.instance_get(self.context, inst_id) ip = '10.11.12.13' - network_ref = db.project_get_network(self.context, 'fake') + network_ref = db.project_get_networks(self.context, 'fake')[0] fixed_ip = {'address': ip, 'network_id': network_ref['id']} db.fixed_ip_create(admin_ctxt, fixed_ip) db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, @@ -1350,6 +1352,7 @@ class NWFilterTestCase(test.TestCase): self.fw.prepare_instance_filter(instance) self.fw.apply_instance_filter(instance) original_filter_count = len(fakefilter.filters) + raise Exception(original_filter_count) self.fw.unfilter_instance(instance) # should undefine 2 filters: instance and instance-secgroup diff --git a/nova/virt/libvirt/netutils.py b/nova/virt/libvirt/netutils.py index 019f4ce2b..5f57387c6 100644 --- a/nova/virt/libvirt/netutils.py +++ b/nova/virt/libvirt/netutils.py @@ -25,6 +25,7 @@ import netaddr from nova import context from nova import db +from nova import exception from nova import flags from nova import ipv6 from nova import utils @@ -55,10 +56,13 @@ def get_network_info(instance): # we should cache network_info admin_context = context.get_admin_context() - fixed_ips = db.fixed_ip_get_by_instance(admin_context, instance['id']) + + try: + fixed_ips = db.fixed_ip_get_by_instance(admin_context, instance['id']) + except exception.FixedIpNotFoundForInstance: + fixed_ips = [] + vifs = db.virtual_interface_get_by_instance(admin_context, instance['id']) - networks = db.network_get_all_by_instance(admin_context, - instance['id']) flavor = db.instance_type_get(admin_context, instance['instance_type_id']) network_info = [] -- cgit From d64a54098bcecbb4c1001e99c1bf4c29b326265a Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 23:13:03 -0700 Subject: cleanup network create --- nova/tests/test_libvirt.py | 95 +++++++++------------------------------------- 1 file changed, 18 insertions(+), 77 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 377c92aca..d12bd34f7 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -88,7 +88,7 @@ def _setup_networking(instance_id, ip='1.2.3.4'): 'virtual_interface_id': vif_ref['id']} db.fixed_ip_create(ctxt, fixed_ip) db.fixed_ip_update(ctxt, ip, {'allocated': True, - 'instance_id': instance_id}) + 'instance_id': instance_id}) class CacheConcurrencyTestCase(test.TestCase): @@ -177,13 +177,13 @@ class LibvirtConnTestCase(test.TestCase): self.context = context.get_admin_context() FLAGS.instances_path = '' self.call_libvirt_dependant_setup = False + self.test_ip = '10.11.12.13' def tearDown(self): self.manager.delete_project(self.project) self.manager.delete_user(self.user) super(LibvirtConnTestCase, self).tearDown() - test_ip = '10.11.12.13' test_instance = {'memory_kb': '1024000', 'basepath': '/some/path', 'bridge_name': 'br100', @@ -425,24 +425,7 @@ class LibvirtConnTestCase(test.TestCase): user_context = context.RequestContext(project=self.project, user=self.user) instance_ref = db.instance_create(user_context, instance) - # Re-get the instance so it's bound to an actual session - instance_ref = db.instance_get(user_context, instance_ref['id']) - network_ref = db.project_get_networks(context.get_admin_context(), - self.project.id)[0] - - vif = {'address': '56:12:12:12:12:12', - 'network_id': network_ref['id'], - 'instance_id': instance_ref['id']} - vif_ref = db.virtual_interface_create(self.context, vif) - fixed_ip = {'address': self.test_ip, - 'network_id': network_ref['id'], - 'virtual_interface_id': vif_ref['id']} - - ctxt = context.get_admin_context() - fixed_ip_ref = db.fixed_ip_create(ctxt, fixed_ip) - db.fixed_ip_update(ctxt, self.test_ip, - {'allocated': True, - 'instance_id': instance_ref['id']}) + _setup_networking(instance_ref['id'], self.test_ip) self.flags(libvirt_type='lxc') conn = connection.LibvirtConnection(True) @@ -474,7 +457,7 @@ class LibvirtConnTestCase(test.TestCase): network_ref = db.project_get_networks(context.get_admin_context(), self.project.id)[0] - _setup_networking(instance_ref['id'], ip=self.test_ip) + _setup_networking(instance_ref['id'], self.test_ip) type_uri_map = {'qemu': ('qemu:///system', [(lambda t: t.find('.').get('type'), 'qemu'), @@ -822,6 +805,7 @@ class IptablesFirewallTestCase(test.TestCase): """setup_basic_rules in nwfilter calls this.""" pass self.fake_libvirt_connection = FakeLibvirtConnection() + self.test_ip = '10.11.12.13' self.fw = firewall.IptablesFirewallDriver( get_connection=lambda: self.fake_libvirt_connection) @@ -889,24 +873,9 @@ class IptablesFirewallTestCase(test.TestCase): def test_static_filters(self): instance_ref = self._create_instance_ref() - ip = '10.11.12.13' - - network_ref = db.project_get_networks(self.context, - 'fake', - associate=True)[0] - vif = {'address': '56:12:12:12:12:12', - 'network_id': network_ref['id'], - 'instance_id': instance_ref['id']} - vif_ref = db.virtual_interface_create(self.context, vif) - - fixed_ip = {'address': ip, - 'network_id': network_ref['id'], - 'virtual_interface_id': vif_ref['id']} - admin_ctxt = context.get_admin_context() - db.fixed_ip_create(admin_ctxt, fixed_ip) - db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - 'instance_id': instance_ref['id']}) + _setup_networking(instance_ref['id'], self.test_ip) + admin_ctxt = context.get_admin_context() secgroup = db.security_group_create(admin_ctxt, {'user_id': 'fake', 'project_id': 'fake', @@ -1061,22 +1030,13 @@ class IptablesFirewallTestCase(test.TestCase): self.fw.nwfilter._conn.nwfilterLookupByName =\ fakefilter.nwfilterLookupByName instance_ref = self._create_instance_ref() - inst_id = instance_ref['id'] - instance = db.instance_get(self.context, inst_id) - - ip = '10.11.12.13' - network_ref = db.project_get_networks(self.context, 'fake')[0] - fixed_ip = {'address': ip, 'network_id': network_ref['id']} - db.fixed_ip_create(admin_ctxt, fixed_ip) - db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - 'instance_id': inst_id}) - _setup_networking(inst_id, ip) - self.fw.setup_basic_filtering(instance) - self.fw.prepare_instance_filter(instance) - self.fw.apply_instance_filter(instance) + _setup_networking(instance_ref['id'], self.test_ip) + self.fw.setup_basic_filtering(instance_ref) + self.fw.prepare_instance_filter(instance_ref) + self.fw.apply_instance_filter(instance_ref) original_filter_count = len(fakefilter.filters) - self.fw.unfilter_instance(instance) + self.fw.unfilter_instance(instance_ref) # should undefine just the instance filter self.assertEqual(original_filter_count - len(fakefilter.filters), 1) @@ -1087,13 +1047,7 @@ class IptablesFirewallTestCase(test.TestCase): # setup basic instance data instance_ref = self._create_instance_ref() nw_info = _create_network_info(1) - ip = '10.11.12.13' - network_ref = db.project_get_networks(self.context, 'fake')[0] - admin_ctxt = context.get_admin_context() - fixed_ip = {'address': ip, 'network_id': network_ref['id']} - db.fixed_ip_create(admin_ctxt, fixed_ip) - db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - 'instance_id': instance_ref['id']}) + _setup_networking(instance_ref['id'], self.test_ip) # FRAGILE: peeks at how the firewall names chains chain_name = 'inst-%s' % instance_ref['id'] @@ -1105,6 +1059,7 @@ class IptablesFirewallTestCase(test.TestCase): if rule.chain == 'provider'] self.assertEqual(0, len(rules)) + admin_ctxt = context.get_admin_context() # add a rule and send the update message, check for 1 rule provider_fw0 = db.provider_fw_rule_create(admin_ctxt, {'protocol': 'tcp', @@ -1163,6 +1118,7 @@ class NWFilterTestCase(test.TestCase): self.fake_libvirt_connection = Mock() + self.test_ip = '10.11.12.13' self.fw = firewall.NWFilterFirewall( lambda: self.fake_libvirt_connection) @@ -1280,17 +1236,7 @@ class NWFilterTestCase(test.TestCase): instance_ref = self._create_instance() inst_id = instance_ref['id'] - ip = '10.11.12.13' - - network_ref = db.project_get_networks(self.context, 'fake')[0] - fixed_ip = {'address': ip, 'network_id': network_ref['id']} - - admin_ctxt = context.get_admin_context() - db.fixed_ip_create(admin_ctxt, fixed_ip) - db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - 'instance_id': inst_id}) - - _setup_networking(instance_ref['id'], ip=ip) + _setup_networking(instance_ref['id'], self.test_ip) def _ensure_all_called(): instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'], @@ -1315,7 +1261,7 @@ class NWFilterTestCase(test.TestCase): self.fw.apply_instance_filter(instance) _ensure_all_called() self.teardown_security_group() - db.instance_destroy(admin_ctxt, instance_ref['id']) + db.instance_destroy(context.get_admin_context, instance_ref['id']) def test_create_network_filters(self): instance_ref = self._create_instance() @@ -1342,12 +1288,7 @@ class NWFilterTestCase(test.TestCase): instance = db.instance_get(self.context, inst_id) - ip = '10.11.12.13' - network_ref = db.project_get_networks(self.context, 'fake')[0] - fixed_ip = {'address': ip, 'network_id': network_ref['id']} - db.fixed_ip_create(admin_ctxt, fixed_ip) - db.fixed_ip_update(admin_ctxt, ip, {'allocated': True, - 'instance_id': inst_id}) + _setup_networking(instance_ref['id'], self.test_ip) self.fw.setup_basic_filtering(instance) self.fw.prepare_instance_filter(instance) self.fw.apply_instance_filter(instance) -- cgit From f1f191c381a43af1f8dc87246e7c4973cf50f78e Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 23:22:50 -0700 Subject: couple more fixes --- nova/tests/test_libvirt.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index d12bd34f7..084fb5ca7 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -737,17 +737,7 @@ class LibvirtConnTestCase(test.TestCase): conn.firewall_driver.setattr('setup_basic_filtering', fake_none) conn.firewall_driver.setattr('prepare_instance_filter', fake_none) - network = db.project_get_networks(context.get_admin_context(), - self.project.id)[0] - ip_dict = {'ip': self.test_ip, - 'netmask': network['netmask'], - 'enabled': '1'} - mapping = {'label': network['label'], - 'gateway': network['gateway'], - 'mac': instance['mac_address'], - 'dns': [network['dns']], - 'ips': [ip_dict]} - network_info = [(network, mapping)] + network_info = _create_network_info() try: conn.spawn(instance, network_info) @@ -1293,7 +1283,6 @@ class NWFilterTestCase(test.TestCase): self.fw.prepare_instance_filter(instance) self.fw.apply_instance_filter(instance) original_filter_count = len(fakefilter.filters) - raise Exception(original_filter_count) self.fw.unfilter_instance(instance) # should undefine 2 filters: instance and instance-secgroup -- cgit From 8c40dba0785dadf479e232c26023def4c5a38761 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 23:33:53 -0700 Subject: fake plug for vif driver --- nova/tests/test_libvirt.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 084fb5ca7..65c06a06c 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -232,6 +232,16 @@ class LibvirtConnTestCase(test.TestCase): def setattr(self, key, val): self.__setattr__(key, val) + def plug(self, instance, network, mapping): + return { + 'id': 'fake', + 'bridge_name': 'fake', + 'mac_address': 'fake', + 'ip_address': 'fake', + 'dhcp_server': 'fake', + 'extra_params': 'fake' + } + # Creating mocks fake = FakeLibvirtConnection() fakeip = FakeIptablesFirewallDriver -- cgit From 32e17ebeac99510dd155ce5560192ee6de9d83ab Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 23:41:15 -0700 Subject: fix the last of them --- nova/tests/test_libvirt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 65c06a06c..452e608d4 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -1240,7 +1240,7 @@ class NWFilterTestCase(test.TestCase): def _ensure_all_called(): instance_filter = 'nova-instance-%s-%s' % (instance_ref['name'], - '00A0C914C829') + '561212121212') secgroup_filter = 'nova-secgroup-%s' % self.security_group['id'] for required in [secgroup_filter, 'allow-dhcp-server', 'no-arp-spoofing', 'no-ip-spoofing', @@ -1261,7 +1261,7 @@ class NWFilterTestCase(test.TestCase): self.fw.apply_instance_filter(instance) _ensure_all_called() self.teardown_security_group() - db.instance_destroy(context.get_admin_context, instance_ref['id']) + db.instance_destroy(context.get_admin_context(), instance_ref['id']) def test_create_network_filters(self): instance_ref = self._create_instance() -- cgit From 30eea9c5f15775c96046091c874ee34bf366d566 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Tue, 26 Jul 2011 23:50:49 -0700 Subject: fix typo in attach_volume --- nova/virt/libvirt/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 96f9c41f9..cc51449c1 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -351,7 +351,7 @@ class LibvirtConnection(driver.ComputeDriver): virt_dom = self._lookup_by_name(instance_name) mount_device = mountpoint.rpartition("/")[2] (type, protocol, name) = \ - self._get_volume_device_info(vol['device_path']) + self._get_volume_device_info(device_path) if type == 'block': xml = """ -- cgit From 9008b1f291ae38a4de9b5af5087b1815b3562e3f Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 27 Jul 2011 09:19:45 -0700 Subject: add invalid device test and make sure NovaExceptions don't get wrapped --- nova/exception.py | 3 ++- nova/tests/test_libvirt.py | 9 +++++++++ nova/virt/libvirt/connection.py | 4 ---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nova/exception.py b/nova/exception.py index 38e705417..ea046b712 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -116,7 +116,8 @@ def wrap_exception(notifier=None, publisher_id=None, event_type=None, notifier.notify(publisher_id, temp_type, temp_level, payload) - if not isinstance(e, Error): + if (not isinstance(e, Error) and + not isinstance(e, NovaException)): #exc_type, exc_value, exc_traceback = sys.exc_info() LOG.exception(_('Uncaught exception')) #logging.error(traceback.extract_stack(exc_traceback)) diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index ad0931a89..9a42556c2 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -412,6 +412,15 @@ class LibvirtConnTestCase(test.TestCase): self.assertEquals(snapshot['status'], 'active') self.assertEquals(snapshot['name'], snapshot_name) + def test_attach_invalid_device(self): + self.create_fake_libvirt_mock() + connection.LibvirtConnection._conn.lookupByName = self.fake_lookup + self.mox.ReplayAll() + conn = connection.LibvirtConnection(False) + self.assertRaises(exception.InvalidDevicePath, + conn.attach_volume, + "fake", "bad/device/path", "/dev/fake") + def test_multi_nic(self): instance_data = dict(self.test_instance) network_info = _create_network_info(2) diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index cc51449c1..c27e92feb 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -364,9 +364,6 @@ class LibvirtConnection(driver.ComputeDriver): """ % (protocol, name, mount_device) - else: - raise exception.InvalidDevicePath(path=device_path) - virt_dom.attachDevice(xml) def _get_disk_xml(self, xml, device): @@ -955,7 +952,6 @@ class LibvirtConnection(driver.ComputeDriver): return True return False - @exception.wrap_exception def _get_volume_device_info(self, device_path): if device_path.startswith('/dev/'): return ('block', None, None) -- cgit From a0b536064620e4d18ab00c1154ec3b597ab16a67 Mon Sep 17 00:00:00 2001 From: Trey Morris Date: Wed, 27 Jul 2011 11:44:14 -0500 Subject: updated nova-manage create network. better help, handling of required args, and exceptions. Also updated FLAG flat_network_bridge to default to None --- bin/nova-manage | 89 ++++++++++++++++++++++++++---------------------- nova/exception.py | 4 +++ nova/network/manager.py | 8 ++--- nova/tests/fake_flags.py | 1 + nova/virt/libvirt/vif.py | 2 +- 5 files changed, 59 insertions(+), 45 deletions(-) diff --git a/bin/nova-manage b/bin/nova-manage index b63bd326f..c1a5d8c5f 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -631,21 +631,24 @@ class NetworkCommands(object): """Class for managing networks.""" @args('--label', dest="label", metavar='