summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorAlex Meade <alex.meade@rackspace.com>2011-08-22 03:17:04 +0000
committerTarmac <>2011-08-22 03:17:04 +0000
commit0af1508c38bcf027153dd91c0d862307e90a164e (patch)
tree54985025aadfc8d862b82a6815e30a19a83973ad /nova
parent34f35990ed675a9360db3cbb317b9560755b22ef (diff)
parentc7e0aa577d1747ddb74703c5c46f3e180985c458 (diff)
Adds accessIPv4 and accessIPv6 to servers requests and responses as per the current spec.
Diffstat (limited to 'nova')
-rw-r--r--nova/api/openstack/create_instance_helper.py5
-rw-r--r--nova/api/openstack/schemas/v1.1/server.rng50
-rw-r--r--nova/api/openstack/schemas/v1.1/servers.rng6
-rw-r--r--nova/api/openstack/schemas/v1.1/servers_index.rng12
-rw-r--r--nova/api/openstack/servers.py14
-rw-r--r--nova/api/openstack/views/servers.py4
-rw-r--r--nova/compute/api.py14
-rw-r--r--nova/db/sqlalchemy/migrate_repo/versions/039_add_instances_accessip.py48
-rw-r--r--nova/db/sqlalchemy/models.py5
-rw-r--r--nova/tests/api/openstack/test_servers.py758
10 files changed, 699 insertions, 217 deletions
diff --git a/nova/api/openstack/create_instance_helper.py b/nova/api/openstack/create_instance_helper.py
index 73e48dca5..339f260b9 100644
--- a/nova/api/openstack/create_instance_helper.py
+++ b/nova/api/openstack/create_instance_helper.py
@@ -167,6 +167,8 @@ class CreateInstanceHelper(object):
key_name=key_name,
key_data=key_data,
metadata=server_dict.get('metadata', {}),
+ access_ip_v4=server_dict.get('accessIPv4'),
+ access_ip_v6=server_dict.get('accessIPv6'),
injected_files=injected_files,
admin_password=password,
zone_blob=zone_blob,
@@ -464,7 +466,8 @@ class ServerXMLDeserializerV11(wsgi.MetadataXMLDeserializer):
server = {}
server_node = self.find_first_child_named(node, 'server')
- attributes = ["name", "imageRef", "flavorRef", "adminPass"]
+ attributes = ["name", "imageRef", "flavorRef", "adminPass",
+ "accessIPv4", "accessIPv6"]
for attr in attributes:
if server_node.getAttribute(attr):
server[attr] = server_node.getAttribute(attr)
diff --git a/nova/api/openstack/schemas/v1.1/server.rng b/nova/api/openstack/schemas/v1.1/server.rng
new file mode 100644
index 000000000..dbd169a83
--- /dev/null
+++ b/nova/api/openstack/schemas/v1.1/server.rng
@@ -0,0 +1,50 @@
+<element name="server" ns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="name"> <text/> </attribute>
+ <attribute name="id"> <text/> </attribute>
+ <attribute name="uuid"> <text/> </attribute>
+ <attribute name="updated"> <text/> </attribute>
+ <attribute name="created"> <text/> </attribute>
+ <attribute name="hostId"> <text/> </attribute>
+ <attribute name="accessIPv4"> <text/> </attribute>
+ <attribute name="accessIPv6"> <text/> </attribute>
+ <attribute name="status"> <text/> </attribute>
+ <optional>
+ <attribute name="progress"> <text/> </attribute>
+ </optional>
+ <optional>
+ <attribute name="adminPass"> <text/> </attribute>
+ </optional>
+ <zeroOrMore>
+ <externalRef href="../atom-link.rng"/>
+ </zeroOrMore>
+ <element name="image">
+ <attribute name="id"> <text/> </attribute>
+ <externalRef href="../atom-link.rng"/>
+ </element>
+ <element name="flavor">
+ <attribute name="id"> <text/> </attribute>
+ <externalRef href="../atom-link.rng"/>
+ </element>
+ <element name="metadata">
+ <zeroOrMore>
+ <element name="meta">
+ <attribute name="key"> <text/> </attribute>
+ <text/>
+ </element>
+ </zeroOrMore>
+ </element>
+ <element name="addresses">
+ <zeroOrMore>
+ <element name="network">
+ <attribute name="id"> <text/> </attribute>
+ <zeroOrMore>
+ <element name="ip">
+ <attribute name="version"> <text/> </attribute>
+ <attribute name="addr"> <text/> </attribute>
+ </element>
+ </zeroOrMore>
+ </element>
+ </zeroOrMore>
+ </element>
+</element>
diff --git a/nova/api/openstack/schemas/v1.1/servers.rng b/nova/api/openstack/schemas/v1.1/servers.rng
new file mode 100644
index 000000000..4e2bb8853
--- /dev/null
+++ b/nova/api/openstack/schemas/v1.1/servers.rng
@@ -0,0 +1,6 @@
+<element name="servers" xmlns="http://relaxng.org/ns/structure/1.0"
+ ns="http://docs.openstack.org/compute/api/v1.1">
+ <zeroOrMore>
+ <externalRef href="server.rng"/>
+ </zeroOrMore>
+</element>
diff --git a/nova/api/openstack/schemas/v1.1/servers_index.rng b/nova/api/openstack/schemas/v1.1/servers_index.rng
new file mode 100644
index 000000000..768f0912d
--- /dev/null
+++ b/nova/api/openstack/schemas/v1.1/servers_index.rng
@@ -0,0 +1,12 @@
+<element name="servers" ns="http://docs.openstack.org/compute/api/v1.1"
+ xmlns="http://relaxng.org/ns/structure/1.0">
+ <zeroOrMore>
+ <element name="server">
+ <attribute name="name"> <text/> </attribute>
+ <attribute name="id"> <text/> </attribute>
+ <zeroOrMore>
+ <externalRef href="../atom-link.rng"/>
+ </zeroOrMore>
+ </element>
+ </zeroOrMore>
+</element>
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index 41e63ec3c..1d1975a1c 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -163,7 +163,7 @@ class Controller(object):
@scheduler_api.redirect_handler
def update(self, req, id, body):
- """Update server name then pass on to version-specific controller"""
+ """Update server then pass on to version-specific controller"""
if len(req.body) == 0:
raise exc.HTTPUnprocessableEntity()
@@ -178,6 +178,14 @@ class Controller(object):
self.helper._validate_server_name(name)
update_dict['display_name'] = name.strip()
+ if 'accessIPv4' in body['server']:
+ access_ipv4 = body['server']['accessIPv4']
+ update_dict['access_ip_v4'] = access_ipv4.strip()
+
+ if 'accessIPv6' in body['server']:
+ access_ipv6 = body['server']['accessIPv6']
+ update_dict['access_ip_v6'] = access_ipv6.strip()
+
try:
self.compute_api.update(ctxt, id, **update_dict)
except exception.NotFound:
@@ -837,6 +845,10 @@ class ServerXMLSerializer(wsgi.XMLDictSerializer):
node.setAttribute('created', str(server['created']))
node.setAttribute('updated', str(server['updated']))
node.setAttribute('status', server['status'])
+ if 'accessIPv4' in server:
+ node.setAttribute('accessIPv4', str(server['accessIPv4']))
+ if 'accessIPv6' in server:
+ node.setAttribute('accessIPv6', str(server['accessIPv6']))
if 'progress' in server:
node.setAttribute('progress', str(server['progress']))
diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py
index edc328129..d2c1b0ba1 100644
--- a/nova/api/openstack/views/servers.py
+++ b/nova/api/openstack/views/servers.py
@@ -143,6 +143,10 @@ class ViewBuilderV11(ViewBuilder):
response['server']['progress'] = 100
elif response['server']['status'] == "BUILD":
response['server']['progress'] = 0
+
+ response['server']['accessIPv4'] = inst.get('access_ip_v4') or ""
+ response['server']['accessIPv6'] = inst.get('access_ip_v6') or ""
+
return response
def _build_image(self, response, inst):
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 0c6beacaa..d3cce8568 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -153,7 +153,7 @@ class API(base.Base):
key_name=None, key_data=None, security_group='default',
availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
- reservation_id=None):
+ reservation_id=None, access_ip_v4=None, access_ip_v6=None):
"""Verify all the input parameters regardless of the provisioning
strategy being performed."""
@@ -247,6 +247,8 @@ class API(base.Base):
'key_data': key_data,
'locked': False,
'metadata': metadata,
+ 'access_ip_v4': access_ip_v4,
+ 'access_ip_v6': access_ip_v6,
'availability_zone': availability_zone,
'os_type': os_type,
'architecture': architecture,
@@ -437,7 +439,8 @@ class API(base.Base):
key_name=None, key_data=None, security_group='default',
availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
- reservation_id=None, block_device_mapping=None):
+ reservation_id=None, block_device_mapping=None,
+ access_ip_v4=None, access_ip_v6=None):
"""Provision the instances by passing the whole request to
the Scheduler for execution. Returns a Reservation ID
related to the creation of all of these instances."""
@@ -453,7 +456,7 @@ class API(base.Base):
key_name, key_data, security_group,
availability_zone, user_data, metadata,
injected_files, admin_password, zone_blob,
- reservation_id)
+ reservation_id, access_ip_v4, access_ip_v6)
self._ask_scheduler_to_create_instance(context, base_options,
instance_type, zone_blob,
@@ -471,7 +474,8 @@ class API(base.Base):
key_name=None, key_data=None, security_group='default',
availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None, zone_blob=None,
- reservation_id=None, block_device_mapping=None):
+ reservation_id=None, block_device_mapping=None,
+ access_ip_v4=None, access_ip_v6=None):
"""
Provision the instances by sending off a series of single
instance requests to the Schedulers. This is fine for trival
@@ -495,7 +499,7 @@ class API(base.Base):
key_name, key_data, security_group,
availability_zone, user_data, metadata,
injected_files, admin_password, zone_blob,
- reservation_id)
+ reservation_id, access_ip_v4, access_ip_v6)
block_device_mapping = block_device_mapping or []
instances = []
diff --git a/nova/db/sqlalchemy/migrate_repo/versions/039_add_instances_accessip.py b/nova/db/sqlalchemy/migrate_repo/versions/039_add_instances_accessip.py
new file mode 100644
index 000000000..39f0dd6ce
--- /dev/null
+++ b/nova/db/sqlalchemy/migrate_repo/versions/039_add_instances_accessip.py
@@ -0,0 +1,48 @@
+# Copyright 2011 OpenStack LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from sqlalchemy import Column, Integer, MetaData, Table, String
+
+meta = MetaData()
+
+accessIPv4 = Column(
+ 'access_ip_v4',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False),
+ nullable=True)
+
+accessIPv6 = Column(
+ 'access_ip_v6',
+ String(length=255, convert_unicode=False, assert_unicode=None,
+ unicode_error=None, _warn_on_bytestring=False),
+ nullable=True)
+
+instances = Table('instances', meta,
+ Column('id', Integer(), primary_key=True, nullable=False),
+ )
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine;
+ # bind migrate_engine to your metadata
+ meta.bind = migrate_engine
+ instances.create_column(accessIPv4)
+ instances.create_column(accessIPv6)
+
+
+def downgrade(migrate_engine):
+ # Operations to reverse the above upgrade go here.
+ meta.bind = migrate_engine
+ instances.drop_column('access_ip_v4')
+ instances.drop_column('access_ip_v6')
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 0e2bace83..a487ab28d 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -231,6 +231,11 @@ class Instance(BASE, NovaBase):
root_device_name = Column(String(255))
+ # User editable field meant to represent what ip should be used
+ # to connect to the instance
+ access_ip_v4 = Column(String(255))
+ access_ip_v6 = Column(String(255))
+
# TODO(vish): see Ewan's email about state improvements, probably
# should be in a driver base class or some such
# vmstate_state = running, halted, suspended, paused
diff --git a/nova/tests/api/openstack/test_servers.py b/nova/tests/api/openstack/test_servers.py
index 437620854..d3eb4c517 100644
--- a/nova/tests/api/openstack/test_servers.py
+++ b/nova/tests/api/openstack/test_servers.py
@@ -19,6 +19,7 @@ import base64
import datetime
import json
import unittest
+from lxml import etree
from xml.dom import minidom
import webob
@@ -32,6 +33,7 @@ import nova.api.openstack
from nova.api.openstack import create_instance_helper
from nova.api.openstack import servers
from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
import nova.compute.api
from nova.compute import instance_types
from nova.compute import power_state
@@ -46,6 +48,8 @@ from nova.tests.api.openstack import fakes
FAKE_UUID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
+NS = "{http://docs.openstack.org/compute/api/v1.1}"
+ATOMNS = "{http://www.w3.org/2005/Atom}"
def fake_gen_uuid():
@@ -145,7 +149,8 @@ def instance_addresses(context, instance_id):
def stub_instance(id, user_id='fake', project_id='fake', private_address=None,
public_addresses=None, host=None, power_state=0,
reservation_id="", uuid=FAKE_UUID, image_ref="10",
- flavor_id="1", interfaces=None, name=None):
+ flavor_id="1", interfaces=None, name=None,
+ access_ipv4=None, access_ipv6=None):
metadata = []
metadata.append(InstanceMetadata(key='seq', value=id))
@@ -197,6 +202,8 @@ def stub_instance(id, user_id='fake', project_id='fake', private_address=None,
"display_description": "",
"locked": False,
"metadata": metadata,
+ "access_ip_v4": access_ipv4,
+ "access_ip_v6": access_ipv6,
"uuid": uuid,
"virtual_interfaces": interfaces}
@@ -334,6 +341,8 @@ class ServersTest(test.TestCase):
"progress": 0,
"name": "server1",
"status": "BUILD",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "10",
@@ -431,6 +440,8 @@ class ServersTest(test.TestCase):
created="%(expected_created)s"
hostId=""
status="BUILD"
+ accessIPv4=""
+ accessIPv6=""
progress="0">
<atom:link href="%(server_href)s" rel="self"/>
<atom:link href="%(server_bookmark)s" rel="bookmark"/>
@@ -496,6 +507,8 @@ class ServersTest(test.TestCase):
"progress": 100,
"name": "server1",
"status": "ACTIVE",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "10",
@@ -587,6 +600,8 @@ class ServersTest(test.TestCase):
"progress": 100,
"name": "server1",
"status": "ACTIVE",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "10",
@@ -1379,6 +1394,8 @@ class ServersTest(test.TestCase):
'display_name': 'server_test',
'uuid': FAKE_UUID,
'instance_type': dict(inst_type),
+ 'access_ip_v4': '1.2.3.4',
+ 'access_ip_v6': 'fead::1234',
'image_ref': image_ref,
"created_at": datetime.datetime(2010, 10, 10, 12, 0, 0),
"updated_at": datetime.datetime(2010, 11, 11, 11, 0, 0),
@@ -1579,6 +1596,70 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_create_instance_with_access_ip_v1_1(self):
+ self._setup_for_create_instance()
+
+ # proper local hrefs must start with 'http://localhost/v1.1/'
+ image_href = 'http://localhost/v1.1/images/2'
+ flavor_ref = 'http://localhost/flavors/3'
+ access_ipv4 = '1.2.3.4'
+ access_ipv6 = 'fead::1234'
+ expected_flavor = {
+ "id": "3",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/flavors/3',
+ },
+ ],
+ }
+ expected_image = {
+ "id": "2",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": 'http://localhost/images/2',
+ },
+ ],
+ }
+ body = {
+ 'server': {
+ 'name': 'server_test',
+ 'imageRef': image_href,
+ 'flavorRef': flavor_ref,
+ 'accessIPv4': access_ipv4,
+ 'accessIPv6': access_ipv6,
+ 'metadata': {
+ 'hello': 'world',
+ 'open': 'stack',
+ },
+ 'personality': [
+ {
+ "path": "/etc/banner.txt",
+ "contents": "MQ==",
+ },
+ ],
+ },
+ }
+
+ 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, 202)
+ 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'])
+ self.assertEqual(access_ipv4, server['accessIPv4'])
+ self.assertEqual(access_ipv6, server['accessIPv6'])
+
def test_create_instance_v1_1(self):
self._setup_for_create_instance()
@@ -1636,6 +1717,8 @@ class ServersTest(test.TestCase):
self.assertEqual('server_test', server['name'])
self.assertEqual(expected_flavor, server['flavor'])
self.assertEqual(expected_image, server['image'])
+ self.assertEqual('1.2.3.4', server['accessIPv4'])
+ self.assertEqual('fead::1234', server['accessIPv6'])
def test_create_instance_v1_1_invalid_flavor_href(self):
self._setup_for_create_instance()
@@ -1879,6 +1962,28 @@ class ServersTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
+ def test_update_server_all_attributes_v1_1(self):
+ self.stubs.Set(nova.db.api, 'instance_get',
+ return_server_with_attributes(name='server_test',
+ access_ipv4='0.0.0.0',
+ access_ipv6='beef::0123'))
+ req = webob.Request.blank('/v1.1/servers/1')
+ req.method = 'PUT'
+ req.content_type = 'application/json'
+ body = {'server': {
+ 'name': 'server_test',
+ 'accessIPv4': '0.0.0.0',
+ 'accessIPv6': 'beef::0123',
+ }}
+ req.body = json.dumps(body)
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['id'], 1)
+ self.assertEqual(res_dict['server']['name'], 'server_test')
+ self.assertEqual(res_dict['server']['accessIPv4'], '0.0.0.0')
+ self.assertEqual(res_dict['server']['accessIPv6'], 'beef::0123')
+
def test_update_server_name_v1_1(self):
self.stubs.Set(nova.db.api, 'instance_get',
return_server_with_attributes(name='server_test'))
@@ -1892,6 +1997,32 @@ class ServersTest(test.TestCase):
self.assertEqual(res_dict['server']['id'], 1)
self.assertEqual(res_dict['server']['name'], 'server_test')
+ def test_update_server_access_ipv4_v1_1(self):
+ self.stubs.Set(nova.db.api, 'instance_get',
+ return_server_with_attributes(access_ipv4='0.0.0.0'))
+ req = webob.Request.blank('/v1.1/servers/1')
+ req.method = 'PUT'
+ req.content_type = 'application/json'
+ req.body = json.dumps({'server': {'accessIPv4': '0.0.0.0'}})
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['id'], 1)
+ self.assertEqual(res_dict['server']['accessIPv4'], '0.0.0.0')
+
+ def test_update_server_access_ipv6_v1_1(self):
+ self.stubs.Set(nova.db.api, 'instance_get',
+ return_server_with_attributes(access_ipv6='beef::0123'))
+ req = webob.Request.blank('/v1.1/servers/1')
+ req.method = 'PUT'
+ req.content_type = 'application/json'
+ req.body = json.dumps({'server': {'accessIPv6': 'beef::0123'}})
+ res = req.get_response(fakes.wsgi_app())
+ self.assertEqual(res.status_int, 200)
+ res_dict = json.loads(res.body)
+ self.assertEqual(res_dict['server']['id'], 1)
+ self.assertEqual(res_dict['server']['accessIPv6'], 'beef::0123')
+
def test_update_server_adminPass_ignored_v1_1(self):
inst_dict = dict(name='server_test', adminPass='bacon')
self.body = json.dumps(dict(server=inst_dict))
@@ -2491,6 +2622,62 @@ class TestServerCreateRequestXMLDeserializerV11(test.TestCase):
}
self.assertEquals(request['body'], expected)
+ def test_access_ipv4(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2"
+ accessIPv4="1.2.3.4"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "accessIPv4": "1.2.3.4",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_access_ipv6(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2"
+ accessIPv6="fead::1234"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "accessIPv6": "fead::1234",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
+ def test_access_ip(self):
+ serial_request = """
+<server xmlns="http://docs.openstack.org/compute/api/v1.1"
+ name="new-server-test"
+ imageRef="1"
+ flavorRef="2"
+ accessIPv4="1.2.3.4"
+ accessIPv6="fead::1234"/>"""
+ request = self.deserializer.deserialize(serial_request, 'create')
+ expected = {
+ "server": {
+ "name": "new-server-test",
+ "imageRef": "1",
+ "flavorRef": "2",
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
+ },
+ }
+ self.assertEquals(request['body'], expected)
+
def test_admin_pass(self):
serial_request = """
<server xmlns="http://docs.openstack.org/compute/api/v1.1"
@@ -3039,6 +3226,8 @@ class ServersViewBuilderV11Test(test.TestCase):
"display_description": "",
"locked": False,
"metadata": [],
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
#"address": ,
#"floating_ips": [{"address":ip} for ip in public_addresses]}
"uuid": "deadbeef-feed-edee-beef-d0ea7beefedd"}
@@ -3093,6 +3282,8 @@ class ServersViewBuilderV11Test(test.TestCase):
"progress": 0,
"name": "test_server",
"status": "BUILD",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "5",
@@ -3144,6 +3335,8 @@ class ServersViewBuilderV11Test(test.TestCase):
"progress": 100,
"name": "test_server",
"status": "ACTIVE",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "5",
@@ -3181,6 +3374,114 @@ class ServersViewBuilderV11Test(test.TestCase):
output = self.view_builder.build(self.instance, True)
self.assertDictMatch(output, expected_server)
+ def test_build_server_detail_with_accessipv4(self):
+
+ self.instance['access_ip_v4'] = '1.2.3.4'
+
+ image_bookmark = "http://localhost/images/5"
+ flavor_bookmark = "http://localhost/flavors/1"
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": '',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {},
+ "metadata": {},
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, True)
+ self.assertDictMatch(output, expected_server)
+
+ def test_build_server_detail_with_accessipv6(self):
+
+ self.instance['access_ip_v6'] = 'fead::1234'
+
+ image_bookmark = "http://localhost/images/5"
+ flavor_bookmark = "http://localhost/flavors/1"
+ expected_server = {
+ "server": {
+ "id": 1,
+ "uuid": self.instance['uuid'],
+ "updated": "2010-11-11T11:00:00Z",
+ "created": "2010-10-10T12:00:00Z",
+ "progress": 0,
+ "name": "test_server",
+ "status": "BUILD",
+ "hostId": '',
+ "image": {
+ "id": "5",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": image_bookmark,
+ },
+ ],
+ },
+ "flavor": {
+ "id": "1",
+ "links": [
+ {
+ "rel": "bookmark",
+ "href": flavor_bookmark,
+ },
+ ],
+ },
+ "addresses": {},
+ "metadata": {},
+ "accessIPv4": "",
+ "accessIPv6": "fead::1234",
+ "links": [
+ {
+ "rel": "self",
+ "href": "http://localhost/v1.1/servers/1",
+ },
+ {
+ "rel": "bookmark",
+ "href": "http://localhost/servers/1",
+ },
+ ],
+ }
+ }
+
+ output = self.view_builder.build(self.instance, True)
+ self.assertDictMatch(output, expected_server)
+
def test_build_server_detail_with_metadata(self):
metadata = []
@@ -3199,6 +3500,8 @@ class ServersViewBuilderV11Test(test.TestCase):
"progress": 0,
"name": "test_server",
"status": "BUILD",
+ "accessIPv4": "",
+ "accessIPv6": "",
"hostId": '',
"image": {
"id": "5",
@@ -3265,6 +3568,8 @@ class ServerXMLSerializationTest(test.TestCase):
"name": "test_server",
"status": "BUILD",
"hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
"image": {
"id": "5",
"links": [
@@ -3323,7 +3628,9 @@ class ServerXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture, 'show')
- actual = minidom.parseString(output.replace(" ", ""))
+ print output
+ root = etree.XML(output)
+ xmlutil.validate_schema(root, 'server')
expected_server_href = self.SERVER_HREF
expected_server_bookmark = self.SERVER_BOOKMARK
@@ -3331,47 +3638,57 @@ class ServerXMLSerializationTest(test.TestCase):
expected_flavor_bookmark = self.FLAVOR_BOOKMARK
expected_now = self.TIMESTAMP
expected_uuid = FAKE_UUID
- expected = minidom.parseString("""
- <server id="1"
- uuid="%(expected_uuid)s"
- xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="test_server"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
- status="BUILD"
- progress="0">
- <atom:link href="%(expected_server_href)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
- <image id="5">
- <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
- </image>
- <flavor id="1">
- <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
- </flavor>
- <metadata>
- <meta key="Open">
- Stack
- </meta>
- <meta key="Number">
- 1
- </meta>
- </metadata>
- <addresses>
- <network id="network_one">
- <ip version="4" addr="67.23.10.138"/>
- <ip version="6" addr="::babe:67.23.10.138"/>
- </network>
- <network id="network_two">
- <ip version="4" addr="67.23.10.139"/>
- <ip version="6" addr="::babe:67.23.10.139"/>
- </network>
- </addresses>
- </server>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
+ server_dict = fixture['server']
+
+ for key in ['name', 'id', 'uuid', 'created', 'accessIPv4',
+ 'updated', 'progress', 'status', 'hostId',
+ 'accessIPv6']:
+ self.assertEqual(root.get(key), str(server_dict[key]))
+
+ link_nodes = root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 2)
+ for i, link in enumerate(server_dict['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ metadata_root = root.find('{0}metadata'.format(NS))
+ metadata_elems = metadata_root.findall('{0}meta'.format(NS))
+ self.assertEqual(len(metadata_elems), 2)
+ for i, metadata_elem in enumerate(metadata_elems):
+ (meta_key, meta_value) = server_dict['metadata'].items()[i]
+ self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
+ self.assertEqual(str(metadata_elem.text).strip(), str(meta_value))
+
+ image_root = root.find('{0}image'.format(NS))
+ self.assertEqual(image_root.get('id'), server_dict['image']['id'])
+ link_nodes = image_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['image']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ flavor_root = root.find('{0}flavor'.format(NS))
+ self.assertEqual(flavor_root.get('id'), server_dict['flavor']['id'])
+ link_nodes = flavor_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['flavor']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ addresses_root = root.find('{0}addresses'.format(NS))
+ addresses_dict = server_dict['addresses']
+ network_elems = addresses_root.findall('{0}network'.format(NS))
+ self.assertEqual(len(network_elems), 2)
+ for i, network_elem in enumerate(network_elems):
+ network = addresses_dict.items()[i]
+ self.assertEqual(str(network_elem.get('id')), str(network[0]))
+ ip_elems = network_elem.findall('{0}ip'.format(NS))
+ for z, ip_elem in enumerate(ip_elems):
+ ip = network[1][z]
+ self.assertEqual(str(ip_elem.get('version')),
+ str(ip['version']))
+ self.assertEqual(str(ip_elem.get('addr')),
+ str(ip['addr']))
def test_create(self):
serializer = servers.ServerXMLSerializer()
@@ -3385,6 +3702,8 @@ class ServerXMLSerializationTest(test.TestCase):
"progress": 0,
"name": "test_server",
"status": "BUILD",
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
"hostId": "e4d909c290d0fb1ca068ffaddf22cbd0",
"adminPass": "test_password",
"image": {
@@ -3445,7 +3764,9 @@ class ServerXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture, 'create')
- actual = minidom.parseString(output.replace(" ", ""))
+ print output
+ root = etree.XML(output)
+ xmlutil.validate_schema(root, 'server')
expected_server_href = self.SERVER_HREF
expected_server_bookmark = self.SERVER_BOOKMARK
@@ -3453,48 +3774,57 @@ class ServerXMLSerializationTest(test.TestCase):
expected_flavor_bookmark = self.FLAVOR_BOOKMARK
expected_now = self.TIMESTAMP
expected_uuid = FAKE_UUID
- expected = minidom.parseString("""
- <server id="1"
- uuid="%(expected_uuid)s"
- xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="test_server"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
- status="BUILD"
- adminPass="test_password"
- progress="0">
- <atom:link href="%(expected_server_href)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
- <image id="5">
- <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
- </image>
- <flavor id="1">
- <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
- </flavor>
- <metadata>
- <meta key="Open">
- Stack
- </meta>
- <meta key="Number">
- 1
- </meta>
- </metadata>
- <addresses>
- <network id="network_one">
- <ip version="4" addr="67.23.10.138"/>
- <ip version="6" addr="::babe:67.23.10.138"/>
- </network>
- <network id="network_two">
- <ip version="4" addr="67.23.10.139"/>
- <ip version="6" addr="::babe:67.23.10.139"/>
- </network>
- </addresses>
- </server>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
+ server_dict = fixture['server']
+
+ for key in ['name', 'id', 'uuid', 'created', 'accessIPv4',
+ 'updated', 'progress', 'status', 'hostId',
+ 'accessIPv6', 'adminPass']:
+ self.assertEqual(root.get(key), str(server_dict[key]))
+
+ link_nodes = root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 2)
+ for i, link in enumerate(server_dict['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ metadata_root = root.find('{0}metadata'.format(NS))
+ metadata_elems = metadata_root.findall('{0}meta'.format(NS))
+ self.assertEqual(len(metadata_elems), 2)
+ for i, metadata_elem in enumerate(metadata_elems):
+ (meta_key, meta_value) = server_dict['metadata'].items()[i]
+ self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
+ self.assertEqual(str(metadata_elem.text).strip(), str(meta_value))
+
+ image_root = root.find('{0}image'.format(NS))
+ self.assertEqual(image_root.get('id'), server_dict['image']['id'])
+ link_nodes = image_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['image']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ flavor_root = root.find('{0}flavor'.format(NS))
+ self.assertEqual(flavor_root.get('id'), server_dict['flavor']['id'])
+ link_nodes = flavor_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['flavor']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ addresses_root = root.find('{0}addresses'.format(NS))
+ addresses_dict = server_dict['addresses']
+ network_elems = addresses_root.findall('{0}network'.format(NS))
+ self.assertEqual(len(network_elems), 2)
+ for i, network_elem in enumerate(network_elems):
+ network = addresses_dict.items()[i]
+ self.assertEqual(str(network_elem.get('id')), str(network[0]))
+ ip_elems = network_elem.findall('{0}ip'.format(NS))
+ for z, ip_elem in enumerate(ip_elems):
+ ip = network[1][z]
+ self.assertEqual(str(ip_elem.get('version')),
+ str(ip['version']))
+ self.assertEqual(str(ip_elem.get('addr')),
+ str(ip['addr']))
def test_index(self):
serializer = servers.ServerXMLSerializer()
@@ -3535,23 +3865,21 @@ class ServerXMLSerializationTest(test.TestCase):
]}
output = serializer.serialize(fixture, 'index')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <servers xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <server id="1" name="test_server">
- <atom:link href="%(expected_server_href)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
- </server>
- <server id="2" name="test_server_2">
- <atom:link href="%(expected_server_href_2)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/>
- </server>
- </servers>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
+ print output
+ root = etree.XML(output)
+ xmlutil.validate_schema(root, 'servers_index')
+ server_elems = root.findall('{0}server'.format(NS))
+ self.assertEqual(len(server_elems), 2)
+ for i, server_elem in enumerate(server_elems):
+ server_dict = fixture['servers'][i]
+ for key in ['name', 'id']:
+ self.assertEqual(server_elem.get(key), str(server_dict[key]))
+
+ link_nodes = server_elem.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 2)
+ for i, link in enumerate(server_dict['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
def test_detail(self):
serializer = servers.ServerXMLSerializer()
@@ -3574,6 +3902,8 @@ class ServerXMLSerializationTest(test.TestCase):
"progress": 0,
"name": "test_server",
"status": "BUILD",
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
"hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
"image": {
"id": "5",
@@ -3627,6 +3957,8 @@ class ServerXMLSerializationTest(test.TestCase):
"progress": 100,
"name": "test_server_2",
"status": "ACTIVE",
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
"hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
"image": {
"id": "5",
@@ -3675,71 +4007,63 @@ class ServerXMLSerializationTest(test.TestCase):
]}
output = serializer.serialize(fixture, 'detail')
- actual = minidom.parseString(output.replace(" ", ""))
-
- expected = minidom.parseString("""
- <servers xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <server id="1"
- uuid="%(expected_uuid)s"
- name="test_server"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
- status="BUILD"
- progress="0">
- <atom:link href="%(expected_server_href)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
- <image id="5">
- <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
- </image>
- <flavor id="1">
- <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
- </flavor>
- <metadata>
- <meta key="Number">
- 1
- </meta>
- </metadata>
- <addresses>
- <network id="network_one">
- <ip version="4" addr="67.23.10.138"/>
- <ip version="6" addr="::babe:67.23.10.138"/>
- </network>
- </addresses>
- </server>
- <server id="2"
- uuid="%(expected_uuid)s"
- name="test_server_2"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
- status="ACTIVE"
- progress="100">
- <atom:link href="%(expected_server_href_2)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark_2)s" rel="bookmark"/>
- <image id="5">
- <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
- </image>
- <flavor id="1">
- <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
- </flavor>
- <metadata>
- <meta key="Number">
- 2
- </meta>
- </metadata>
- <addresses>
- <network id="network_one">
- <ip version="4" addr="67.23.10.138"/>
- <ip version="6" addr="::babe:67.23.10.138"/>
- </network>
- </addresses>
- </server>
- </servers>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
+ print output
+ root = etree.XML(output)
+ xmlutil.validate_schema(root, 'servers')
+ server_elems = root.findall('{0}server'.format(NS))
+ self.assertEqual(len(server_elems), 2)
+ for i, server_elem in enumerate(server_elems):
+ server_dict = fixture['servers'][i]
+
+ for key in ['name', 'id', 'uuid', 'created', 'accessIPv4',
+ 'updated', 'progress', 'status', 'hostId',
+ 'accessIPv6']:
+ self.assertEqual(server_elem.get(key), str(server_dict[key]))
+
+ link_nodes = server_elem.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 2)
+ for i, link in enumerate(server_dict['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ metadata_root = server_elem.find('{0}metadata'.format(NS))
+ metadata_elems = metadata_root.findall('{0}meta'.format(NS))
+ for i, metadata_elem in enumerate(metadata_elems):
+ (meta_key, meta_value) = server_dict['metadata'].items()[i]
+ self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
+ self.assertEqual(str(metadata_elem.text).strip(),
+ str(meta_value))
+
+ image_root = server_elem.find('{0}image'.format(NS))
+ self.assertEqual(image_root.get('id'), server_dict['image']['id'])
+ link_nodes = image_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['image']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ flavor_root = server_elem.find('{0}flavor'.format(NS))
+ self.assertEqual(flavor_root.get('id'),
+ server_dict['flavor']['id'])
+ link_nodes = flavor_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['flavor']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ addresses_root = server_elem.find('{0}addresses'.format(NS))
+ addresses_dict = server_dict['addresses']
+ network_elems = addresses_root.findall('{0}network'.format(NS))
+ for i, network_elem in enumerate(network_elems):
+ network = addresses_dict.items()[i]
+ self.assertEqual(str(network_elem.get('id')), str(network[0]))
+ ip_elems = network_elem.findall('{0}ip'.format(NS))
+ for z, ip_elem in enumerate(ip_elems):
+ ip = network[1][z]
+ self.assertEqual(str(ip_elem.get('version')),
+ str(ip['version']))
+ self.assertEqual(str(ip_elem.get('addr')),
+ str(ip['addr']))
def test_update(self):
serializer = servers.ServerXMLSerializer()
@@ -3754,6 +4078,8 @@ class ServerXMLSerializationTest(test.TestCase):
"name": "test_server",
"status": "BUILD",
"hostId": 'e4d909c290d0fb1ca068ffaddf22cbd0',
+ "accessIPv4": "1.2.3.4",
+ "accessIPv6": "fead::1234",
"image": {
"id": "5",
"links": [
@@ -3812,7 +4138,9 @@ class ServerXMLSerializationTest(test.TestCase):
}
output = serializer.serialize(fixture, 'update')
- actual = minidom.parseString(output.replace(" ", ""))
+ print output
+ root = etree.XML(output)
+ xmlutil.validate_schema(root, 'server')
expected_server_href = self.SERVER_HREF
expected_server_bookmark = self.SERVER_BOOKMARK
@@ -3820,44 +4148,54 @@ class ServerXMLSerializationTest(test.TestCase):
expected_flavor_bookmark = self.FLAVOR_BOOKMARK
expected_now = self.TIMESTAMP
expected_uuid = FAKE_UUID
- expected = minidom.parseString("""
- <server id="1"
- uuid="%(expected_uuid)s"
- xmlns="http://docs.openstack.org/compute/api/v1.1"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="test_server"
- updated="%(expected_now)s"
- created="%(expected_now)s"
- hostId="e4d909c290d0fb1ca068ffaddf22cbd0"
- status="BUILD"
- progress="0">
- <atom:link href="%(expected_server_href)s" rel="self"/>
- <atom:link href="%(expected_server_bookmark)s" rel="bookmark"/>
- <image id="5">
- <atom:link rel="bookmark" href="%(expected_image_bookmark)s"/>
- </image>
- <flavor id="1">
- <atom:link rel="bookmark" href="%(expected_flavor_bookmark)s"/>
- </flavor>
- <metadata>
- <meta key="Open">
- Stack
- </meta>
- <meta key="Number">
- 1
- </meta>
- </metadata>
- <addresses>
- <network id="network_one">
- <ip version="4" addr="67.23.10.138"/>
- <ip version="6" addr="::babe:67.23.10.138"/>
- </network>
- <network id="network_two">
- <ip version="4" addr="67.23.10.139"/>
- <ip version="6" addr="::babe:67.23.10.139"/>
- </network>
- </addresses>
- </server>
- """.replace(" ", "") % (locals()))
-
- self.assertEqual(expected.toxml(), actual.toxml())
+ server_dict = fixture['server']
+
+ for key in ['name', 'id', 'uuid', 'created', 'accessIPv4',
+ 'updated', 'progress', 'status', 'hostId',
+ 'accessIPv6']:
+ self.assertEqual(root.get(key), str(server_dict[key]))
+
+ link_nodes = root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 2)
+ for i, link in enumerate(server_dict['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ metadata_root = root.find('{0}metadata'.format(NS))
+ metadata_elems = metadata_root.findall('{0}meta'.format(NS))
+ self.assertEqual(len(metadata_elems), 2)
+ for i, metadata_elem in enumerate(metadata_elems):
+ (meta_key, meta_value) = server_dict['metadata'].items()[i]
+ self.assertEqual(str(metadata_elem.get('key')), str(meta_key))
+ self.assertEqual(str(metadata_elem.text).strip(), str(meta_value))
+
+ image_root = root.find('{0}image'.format(NS))
+ self.assertEqual(image_root.get('id'), server_dict['image']['id'])
+ link_nodes = image_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['image']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ flavor_root = root.find('{0}flavor'.format(NS))
+ self.assertEqual(flavor_root.get('id'), server_dict['flavor']['id'])
+ link_nodes = flavor_root.findall('{0}link'.format(ATOMNS))
+ self.assertEqual(len(link_nodes), 1)
+ for i, link in enumerate(server_dict['flavor']['links']):
+ for key, value in link.items():
+ self.assertEqual(link_nodes[i].get(key), value)
+
+ addresses_root = root.find('{0}addresses'.format(NS))
+ addresses_dict = server_dict['addresses']
+ network_elems = addresses_root.findall('{0}network'.format(NS))
+ self.assertEqual(len(network_elems), 2)
+ for i, network_elem in enumerate(network_elems):
+ network = addresses_dict.items()[i]
+ self.assertEqual(str(network_elem.get('id')), str(network[0]))
+ ip_elems = network_elem.findall('{0}ip'.format(NS))
+ for z, ip_elem in enumerate(ip_elems):
+ ip = network[1][z]
+ self.assertEqual(str(ip_elem.get('version')),
+ str(ip['version']))
+ self.assertEqual(str(ip_elem.get('addr')),
+ str(ip['addr']))