From aee7778549904dc89fbd792ee60924932621a720 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Fri, 5 Aug 2011 15:02:29 +0900 Subject: Added migration to add uuid to virtual interfaces. Added uuid column to models --- .../versions/037_add_uuid_to_virtual_interfaces.py | 44 ++++++++++++++++++++++ nova/db/sqlalchemy/models.py | 2 + 2 files changed, 46 insertions(+) create mode 100644 nova/db/sqlalchemy/migrate_repo/versions/037_add_uuid_to_virtual_interfaces.py diff --git a/nova/db/sqlalchemy/migrate_repo/versions/037_add_uuid_to_virtual_interfaces.py b/nova/db/sqlalchemy/migrate_repo/versions/037_add_uuid_to_virtual_interfaces.py new file mode 100644 index 000000000..0f542cbec --- /dev/null +++ b/nova/db/sqlalchemy/migrate_repo/versions/037_add_uuid_to_virtual_interfaces.py @@ -0,0 +1,44 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (C) 2011 Midokura KK +# +# 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, String, Table + +from nova import utils + + +meta = MetaData() + +virtual_interfaces = Table("virtual_interfaces", meta, + Column("id", Integer(), primary_key=True, + nullable=False)) +uuid_column = Column("uuid", String(36)) + + +def upgrade(migrate_engine): + meta.bind = migrate_engine + virtual_interfaces.create_column(uuid_column) + + rows = migrate_engine.execute(virtual_interfaces.select()) + for row in rows: + vif_uuid = str(utils.gen_uuid()) + migrate_engine.execute(virtual_interfaces.update()\ + .where(virtual_interfaces.c.id == row[0])\ + .values(uuid=vif_uuid)) + + +def downgrade(migrate_engine): + meta.bind = migrate_engine + virtual_interfaces.drop_column(uuid_column) diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 9f4c7a0aa..3ab0a2b0c 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -565,6 +565,8 @@ class VirtualInterface(BASE, NovaBase): instance_id = Column(Integer, ForeignKey('instances.id'), nullable=False) instance = relationship(Instance, backref=backref('virtual_interfaces')) + uuid = Column(String(36)) + @property def fixed_ipv6(self): cidr_v6 = self.network.cidr_v6 -- cgit From 7407a1a86c4039bdc541e9a26cc68c9c93f49bc3 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Fri, 5 Aug 2011 18:29:32 +0900 Subject: Added virtual interfaces REST API extension controller --- nova/api/openstack/contrib/virtual_interfaces.py | 102 +++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 nova/api/openstack/contrib/virtual_interfaces.py diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py new file mode 100644 index 000000000..3466d31c7 --- /dev/null +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -0,0 +1,102 @@ +# Copyright (C) 2011 Midokura KK +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""The virtual interfaces extension.""" + +from webob import exc +import webob + +from nova import compute +from nova import exception +from nova import log as logging +from nova.api.openstack import common +from nova.api.openstack import extensions +from nova.api.openstack import faults + + +LOG = logging.getLogger("nova.api.virtual_interfaces") + + +def _translate_vif_summary_view(_context, vif): + """Maps keys for attachment summary view.""" + d = {} + d['id'] = vif['uuid'] + d['macAddress'] = vif['address'] + d['serverId'] = vif['instance_id'] + return d + + +class ServerVirtualInterfaceController(object): + """The instance VIF API controller for the Openstack API. + """ + + _serialization_metadata = { + 'application/xml': { + 'attributes': { + 'serverVirtualInterface': ['id', + 'macAddress']}}} + + def __init__(self): + self.compute_api = compute.API() + super(ServerVirtualInterfaceController, self).__init__() + + def _items(self, req, server_id, entity_maker): + """Returns a list of VIFs, transformed through entity_maker.""" + context = req.environ['nova.context'] + + try: + instance = self.compute_api.get(context, server_id) + except exception.NotFound: + return faults.Fault(exc.HTTPNotFound()) + + vifs = instance['virtual_interfaces'] + limited_list = common.limited(vifs, req) + res = [entity_maker(context, vif) for vif in limited_list] + return {'serverVirtualInterfaces': res} + + def index(self, req, server_id): + """Returns the list of VIFs for a given instance.""" + return self._items(req, server_id, + entity_maker=_translate_vif_summary_view) + + +class VirtualInterfaces(extensions.ExtensionDescriptor): + + def get_name(self): + return "VirtualInterfaces" + + def get_alias(self): + return "os-virtual_interfaces" + + def get_description(self): + return "Virtual interface support" + + def get_namespace(self): + return "http://docs.openstack.org/ext/virtual_interfaces/api/v1.1" + + def get_updated(self): + return "2011-08-05T00:00:00+00:00" + + def get_resources(self): + resources = [] + + res = extensions.ResourceExtension('os-virtual_interfaces', + ServerVirtualInterfaceController(), + parent=dict( + member_name='server', + collection_name='servers')) + resources.append(res) + + return resources -- cgit From 92c6ee9dc7eeaa44bf6162387b5815fc0cdb1c71 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Tue, 16 Aug 2011 17:51:45 +0900 Subject: Fixed the naming of the extension --- nova/api/openstack/contrib/virtual_interfaces.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 3466d31c7..38246aeb5 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -72,13 +72,13 @@ class ServerVirtualInterfaceController(object): entity_maker=_translate_vif_summary_view) -class VirtualInterfaces(extensions.ExtensionDescriptor): +class Virtual_interfaces(extensions.ExtensionDescriptor): def get_name(self): - return "VirtualInterfaces" + return "Virtual_interfaces" def get_alias(self): - return "os-virtual_interfaces" + return "os-virtual-interfaces" def get_description(self): return "Virtual interface support" @@ -92,7 +92,7 @@ class VirtualInterfaces(extensions.ExtensionDescriptor): def get_resources(self): resources = [] - res = extensions.ResourceExtension('os-virtual_interfaces', + res = extensions.ResourceExtension('os-virtual-interfaces', ServerVirtualInterfaceController(), parent=dict( member_name='server', -- cgit From ee06de65b674a7a91597bc9121b3bd3bd11e658b Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Tue, 16 Aug 2011 18:37:50 +0900 Subject: Added uuid to allocate_mac_address --- nova/network/manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/network/manager.py b/nova/network/manager.py index b1b3f8ba2..f115c66f1 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -523,7 +523,8 @@ class NetworkManager(manager.SchedulerDependentManager): for network in networks: vif = {'address': self.generate_mac_address(), 'instance_id': instance_id, - 'network_id': network['id']} + 'network_id': network['id'], + 'uuid': utils.gen_uuid()} # try FLAG times to create a vif record with a unique mac_address for i in range(FLAGS.create_unique_mac_address_attempts): try: -- cgit From c3c164455f9b5d4ea994a4453342ccb00d987766 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Tue, 16 Aug 2011 18:52:29 +0900 Subject: Include vif UUID in the network info dictionary --- nova/network/manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nova/network/manager.py b/nova/network/manager.py index f115c66f1..f32f8e837 100644 --- a/nova/network/manager.py +++ b/nova/network/manager.py @@ -499,6 +499,7 @@ class NetworkManager(manager.SchedulerDependentManager): 'dhcp_server': dhcp_server, 'broadcast': network['broadcast'], 'mac': vif['address'], + 'vif_uuid': vif['uuid'], 'rxtx_cap': flavor['rxtx_cap'], 'dns': [], 'ips': [ip_dict(ip) for ip in network_IPs], -- cgit From 536c1e95a68569abda6fe8ee4e3f571976521c8e Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 16 Aug 2011 20:36:49 -0700 Subject: add new vif uuid for OVS vifplug for libvirt + xenserver --- nova/virt/libvirt/vif.py | 13 +++++++------ nova/virt/xenapi/vif.py | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 4cb9abda4..67366fdbe 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -98,10 +98,12 @@ class LibvirtBridgeDriver(VIFDriver): class LibvirtOpenVswitchDriver(VIFDriver): """VIF driver for Open vSwitch.""" + def get_dev_name(_self, iface_id): + return "tap-" + iface_id[0:15] + def plug(self, instance, network, mapping): - vif_id = str(instance['id']) + "-" + str(network['id']) - dev = "tap-%s" % vif_id - iface_id = "nova-" + vif_id + iface_id = mapping['vif_uuid'] + dev = self.get_dev_name(iface_id) if not linux_net._device_exists(dev): utils.execute('ip', 'tuntap', 'add', dev, 'mode', 'tap', run_as_root=True) @@ -125,11 +127,10 @@ class LibvirtOpenVswitchDriver(VIFDriver): def unplug(self, instance, network, mapping): """Unplug the VIF from the network by deleting the port from the bridge.""" - vif_id = str(instance['id']) + "-" + str(network['id']) - dev = "tap-%s" % vif_id + dev = self.get_dev_name(mapping['vif_uuid']) try: utils.execute('ovs-vsctl', 'del-port', - network['bridge'], dev, run_as_root=True) + FLAGS.libvirt_ovs_bridge, dev, run_as_root=True) utils.execute('ip', 'link', 'delete', dev, run_as_root=True) except exception.ProcessExecutionError: LOG.warning(_("Failed while unplugging vif of instance '%s'"), diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py index 527602243..2f25efeb2 100644 --- a/nova/virt/xenapi/vif.py +++ b/nova/virt/xenapi/vif.py @@ -128,12 +128,12 @@ class XenAPIOpenVswitchDriver(VIFDriver): vif_rec['VM'] = vm_ref vif_rec['MAC'] = network_mapping['mac'] vif_rec['MTU'] = '1500' - vif_id = "nova-" + str(instance['id']) + "-" + str(network['id']) vif_rec['qos_algorithm_type'] = "" vif_rec['qos_algorithm_params'] = {} # OVS on the hypervisor monitors this key and uses it to # set the iface-id attribute - vif_rec['other_config'] = {"nicira-iface-id": vif_id} + vif_rec['other_config'] = \ + {"nicira-iface-id": network_mapping['vif_uuid']} return vif_rec def unplug(self, instance, network, mapping): -- cgit From 77e1e0d3359bce9e5e30134f141151fc271a2e4b Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 19:05:29 +0900 Subject: Removed serverId from the response --- nova/api/openstack/contrib/virtual_interfaces.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 38246aeb5..86d1128fd 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -34,7 +34,6 @@ def _translate_vif_summary_view(_context, vif): d = {} d['id'] = vif['uuid'] d['macAddress'] = vif['address'] - d['serverId'] = vif['instance_id'] return d -- cgit From 623aa3a38cab6cc617fb5fb512cdc733f69b4887 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 19:07:14 +0900 Subject: Added virtual interfaces API test --- .../openstack/contrib/test_virtual_interfaces.py | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 nova/tests/api/openstack/contrib/test_virtual_interfaces.py diff --git a/nova/tests/api/openstack/contrib/test_virtual_interfaces.py b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py new file mode 100644 index 000000000..a3a177e33 --- /dev/null +++ b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py @@ -0,0 +1,55 @@ +# Copyright (C) 2011 Midokura KK +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import json +import stubout +import webob + +from nova import test +from nova import compute +from nova.tests.api.openstack import fakes +from nova.api.openstack.contrib.virtual_interfaces import \ + ServerVirtualInterfaceController + + +def compute_api_get(self, context, server_id): + return {'virtual_interfaces': [ + {'uuid': '00000000-0000-0000-0000-00000000000000000', + 'address': '00-00-00-00-00-00'}, + {'uuid': '11111111-1111-1111-1111-11111111111111111', + 'address': '11-11-11-11-11-11'}]} + + +class ServerVirtualInterfaceTest(test.TestCase): + + def setUp(self): + super(ServerVirtualInterfaceTest, self).setUp() + self.controller = ServerVirtualInterfaceController() + self.stubs.Set(compute.api.API, "get", compute_api_get) + + def tearDown(self): + super(ServerVirtualInterfaceTest, self).tearDown() + + def test_get_virtual_interfaces_list(self): + req = webob.Request.blank('/v1.1/servers/1/os-virtual-interfaces') + res = req.get_response(fakes.wsgi_app()) + self.assertEqual(res.status_int, 200) + res_dict = json.loads(res.body) + response = {'serverVirtualInterfaces': [ + {'id': '00000000-0000-0000-0000-00000000000000000', + 'macAddress': '00-00-00-00-00-00'}, + {'id': '11111111-1111-1111-1111-11111111111111111', + 'macAddress': '11-11-11-11-11-11'}]} + self.assertEqual(res_dict, response) -- cgit From 751c8b4ff0e94b4f665af5541b9249637623d193 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 19:58:26 +0900 Subject: Added XML support and changed JSON output keys --- nova/api/openstack/contrib/virtual_interfaces.py | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 86d1128fd..715a54d52 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -24,16 +24,17 @@ from nova import log as logging from nova.api.openstack import common from nova.api.openstack import extensions from nova.api.openstack import faults +from nova.api.openstack import wsgi LOG = logging.getLogger("nova.api.virtual_interfaces") def _translate_vif_summary_view(_context, vif): - """Maps keys for attachment summary view.""" + """Maps keys for VIF summary view.""" d = {} d['id'] = vif['uuid'] - d['macAddress'] = vif['address'] + d['mac_address'] = vif['address'] return d @@ -41,12 +42,6 @@ class ServerVirtualInterfaceController(object): """The instance VIF API controller for the Openstack API. """ - _serialization_metadata = { - 'application/xml': { - 'attributes': { - 'serverVirtualInterface': ['id', - 'macAddress']}}} - def __init__(self): self.compute_api = compute.API() super(ServerVirtualInterfaceController, self).__init__() @@ -63,7 +58,7 @@ class ServerVirtualInterfaceController(object): vifs = instance['virtual_interfaces'] limited_list = common.limited(vifs, req) res = [entity_maker(context, vif) for vif in limited_list] - return {'serverVirtualInterfaces': res} + return {'virtual_interfaces': res} def index(self, req, server_id): """Returns the list of VIFs for a given instance.""" @@ -91,11 +86,24 @@ class Virtual_interfaces(extensions.ExtensionDescriptor): def get_resources(self): resources = [] + metadata = _get_metadata() + body_serializers = { + 'application/xml': wsgi.XMLDictSerializer(metadata=metadata, + xmlns=wsgi.XMLNS_V11)} + serializer = wsgi.ResponseSerializer(body_serializers, None) res = extensions.ResourceExtension('os-virtual-interfaces', ServerVirtualInterfaceController(), parent=dict( member_name='server', - collection_name='servers')) + collection_name='servers'), + serializer=serializer) resources.append(res) return resources + + +def _get_metadata(): + metadata = { + "attributes": { + 'virtual_interface': ["id", "mac_address"]}} + return metadata -- cgit From ad8081a5b3abfc63834594c5dbf8ac1bb0721a4b Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 19:58:57 +0900 Subject: Fixed vif test to match the JSON key change --- nova/tests/api/openstack/contrib/test_virtual_interfaces.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nova/tests/api/openstack/contrib/test_virtual_interfaces.py b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py index a3a177e33..d541a9e95 100644 --- a/nova/tests/api/openstack/contrib/test_virtual_interfaces.py +++ b/nova/tests/api/openstack/contrib/test_virtual_interfaces.py @@ -47,9 +47,9 @@ class ServerVirtualInterfaceTest(test.TestCase): res = req.get_response(fakes.wsgi_app()) self.assertEqual(res.status_int, 200) res_dict = json.loads(res.body) - response = {'serverVirtualInterfaces': [ + response = {'virtual_interfaces': [ {'id': '00000000-0000-0000-0000-00000000000000000', - 'macAddress': '00-00-00-00-00-00'}, + 'mac_address': '00-00-00-00-00-00'}, {'id': '11111111-1111-1111-1111-11111111111111111', - 'macAddress': '11-11-11-11-11-11'}]} + 'mac_address': '11-11-11-11-11-11'}]} self.assertEqual(res_dict, response) -- cgit From 4407405244c3797ed1c0433eec7686e15340dca7 Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 20:12:24 +0900 Subject: Cleaned up the file --- nova/api/openstack/contrib/virtual_interfaces.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 715a54d52..2d3850e12 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -38,6 +38,13 @@ def _translate_vif_summary_view(_context, vif): return d +def _get_metadata(): + metadata = { + "attributes": { + 'virtual_interface': ["id", "mac_address"]}} + return metadata + + class ServerVirtualInterfaceController(object): """The instance VIF API controller for the Openstack API. """ @@ -100,10 +107,3 @@ class Virtual_interfaces(extensions.ExtensionDescriptor): resources.append(res) return resources - - -def _get_metadata(): - metadata = { - "attributes": { - 'virtual_interface': ["id", "mac_address"]}} - return metadata -- cgit From 5415a59d473fb9ed374e746fb36f30fc664c4dec Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 20:17:09 +0900 Subject: Updated get_updated time --- nova/api/openstack/contrib/virtual_interfaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index 2d3850e12..b3bb00a8f 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -88,7 +88,7 @@ class Virtual_interfaces(extensions.ExtensionDescriptor): return "http://docs.openstack.org/ext/virtual_interfaces/api/v1.1" def get_updated(self): - return "2011-08-05T00:00:00+00:00" + return "2011-08-17T00:00:00+00:00" def get_resources(self): resources = [] -- cgit From 2e44657a20cdd620d982b252ca35413c07fd3c2b Mon Sep 17 00:00:00 2001 From: Ryu Ishimoto Date: Wed, 17 Aug 2011 20:23:21 +0900 Subject: Cleaned up the extension metadata API data --- nova/api/openstack/contrib/virtual_interfaces.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/nova/api/openstack/contrib/virtual_interfaces.py b/nova/api/openstack/contrib/virtual_interfaces.py index b3bb00a8f..dab61efc8 100644 --- a/nova/api/openstack/contrib/virtual_interfaces.py +++ b/nova/api/openstack/contrib/virtual_interfaces.py @@ -76,10 +76,10 @@ class ServerVirtualInterfaceController(object): class Virtual_interfaces(extensions.ExtensionDescriptor): def get_name(self): - return "Virtual_interfaces" + return "VirtualInterfaces" def get_alias(self): - return "os-virtual-interfaces" + return "virtual_interfaces" def get_description(self): return "Virtual interface support" @@ -98,12 +98,11 @@ class Virtual_interfaces(extensions.ExtensionDescriptor): 'application/xml': wsgi.XMLDictSerializer(metadata=metadata, xmlns=wsgi.XMLNS_V11)} serializer = wsgi.ResponseSerializer(body_serializers, None) - res = extensions.ResourceExtension('os-virtual-interfaces', - ServerVirtualInterfaceController(), - parent=dict( - member_name='server', - collection_name='servers'), - serializer=serializer) + res = extensions.ResourceExtension( + 'os-virtual-interfaces', + controller=ServerVirtualInterfaceController(), + parent=dict(member_name='server', collection_name='servers'), + serializer=serializer) resources.append(res) return resources -- cgit