summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nova/api/openstack/compute/personality.py5
-rw-r--r--nova/compute/api.py10
-rw-r--r--nova/compute/manager.py13
-rw-r--r--nova/compute/utils.py10
-rw-r--r--nova/exception.py2
-rw-r--r--nova/network/linux_net.py46
-rw-r--r--nova/network/model.py2
-rw-r--r--nova/network/neutronv2/api.py5
-rw-r--r--nova/tests/functional/regressions/test_bug_1558866.py77
-rw-r--r--nova/tests/unit/api/openstack/compute/test_flavors_extra_specs.py6
-rw-r--r--nova/tests/unit/api/openstack/compute/test_serversV21.py12
-rw-r--r--nova/tests/unit/compute/test_compute_api.py4
-rw-r--r--nova/tests/unit/compute/test_compute_mgr.py4
-rw-r--r--nova/tests/unit/compute/test_compute_utils.py17
-rw-r--r--nova/tests/unit/network/test_linux_net.py55
-rw-r--r--nova/tests/unit/network/test_neutronv2.py4
-rw-r--r--nova/tests/unit/virt/libvirt/test_vif.py33
-rw-r--r--nova/tests/unit/volume/test_cinder.py19
-rw-r--r--nova/virt/libvirt/vif.py20
-rw-r--r--nova/volume/cinder.py3
-rw-r--r--releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml7
-rw-r--r--tox.ini6
22 files changed, 270 insertions, 90 deletions
diff --git a/nova/api/openstack/compute/personality.py b/nova/api/openstack/compute/personality.py
index 2d0aecfe21..4d15fb851d 100644
--- a/nova/api/openstack/compute/personality.py
+++ b/nova/api/openstack/compute/personality.py
@@ -49,9 +49,8 @@ class Personality(extensions.V21APIExtensionBase):
# server_update & server_rebuild
def server_create(self, server_dict, create_kwargs,
body_deprecated_param=None):
- if 'personality' in server_dict:
- create_kwargs['injected_files'] = self._get_injected_files(
- server_dict['personality'])
+ create_kwargs['injected_files'] = self._get_injected_files(
+ server_dict.get('personality', []))
def server_rebuild(self, server_dict, create_kwargs,
body_deprecated_param=None):
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 32ca41fd73..f16f6c4cad 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -937,7 +937,13 @@ class API(base.Base):
block_device.properties_root_device_name(
boot_meta.get('properties', {})))
- image_meta = objects.ImageMeta.from_dict(boot_meta)
+ try:
+ image_meta = objects.ImageMeta.from_dict(boot_meta)
+ except ValueError as e:
+ # there must be invalid values in the image meta properties so
+ # consider this an invalid request
+ msg = _('Invalid image metadata. Error: %s') % six.text_type(e)
+ raise exception.InvalidRequest(msg)
numa_topology = hardware.numa_get_constraints(
instance_type, image_meta)
@@ -2526,7 +2532,7 @@ class API(base.Base):
elevated, instance.uuid, 'finished')
# reverse quota reservation for increased resource usage
- deltas = compute_utils.reverse_upsize_quota_delta(context, migration)
+ deltas = compute_utils.reverse_upsize_quota_delta(context, instance)
quotas = compute_utils.reserve_quota_delta(context, deltas, instance)
instance.task_state = task_states.RESIZE_REVERTING
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 88a878e4bb..69841d2431 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -2296,10 +2296,19 @@ class ComputeManager(manager.Manager):
instance=instance)
except (cinder_exception.EndpointNotFound,
keystone_exception.EndpointNotFound) as exc:
- LOG.warning(_LW('Ignoring EndpointNotFound: %s'), exc,
+ LOG.warning(_LW('Ignoring EndpointNotFound for '
+ 'volume %(volume_id)s: %(exc)s'),
+ {'exc': exc, 'volume_id': bdm.volume_id},
instance=instance)
except cinder_exception.ClientException as exc:
- LOG.warning(_LW('Ignoring Unknown cinder exception: %s'), exc,
+ LOG.warning(_LW('Ignoring unknown cinder exception for '
+ 'volume %(volume_id)s: %(exc)s'),
+ {'exc': exc, 'volume_id': bdm.volume_id},
+ instance=instance)
+ except Exception as exc:
+ LOG.warning(_LW('Ignoring unknown exception for '
+ 'volume %(volume_id)s: %(exc)s'),
+ {'exc': exc, 'volume_id': bdm.volume_id},
instance=instance)
if notify:
diff --git a/nova/compute/utils.py b/nova/compute/utils.py
index df820e5f7a..3f8a8cafa0 100644
--- a/nova/compute/utils.py
+++ b/nova/compute/utils.py
@@ -455,16 +455,12 @@ def upsize_quota_delta(context, new_flavor, old_flavor):
return resize_quota_delta(context, new_flavor, old_flavor, 1, 1)
-def reverse_upsize_quota_delta(context, migration_ref):
+def reverse_upsize_quota_delta(context, instance):
"""Calculate deltas required to reverse a prior upsizing
quota adjustment.
"""
- old_flavor = objects.Flavor.get_by_id(
- context, migration_ref['old_instance_type_id'])
- new_flavor = objects.Flavor.get_by_id(
- context, migration_ref['new_instance_type_id'])
-
- return resize_quota_delta(context, new_flavor, old_flavor, -1, -1)
+ return resize_quota_delta(context, instance.new_flavor,
+ instance.old_flavor, -1, -1)
def downsize_quota_delta(context, instance):
diff --git a/nova/exception.py b/nova/exception.py
index a8cc90f099..5e9faefb99 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -1121,7 +1121,7 @@ class FlavorAccessNotFound(NotFound):
class FlavorExtraSpecUpdateCreateFailed(NovaException):
- msg_fmt = _("Flavor %(id)d extra spec cannot be updated or created "
+ msg_fmt = _("Flavor %(id)s extra spec cannot be updated or created "
"after %(retries)d retries.")
diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
index 6487580a28..a0eb22d192 100644
--- a/nova/network/linux_net.py
+++ b/nova/network/linux_net.py
@@ -37,6 +37,7 @@ import six
from nova import exception
from nova.i18n import _, _LE, _LW
+from nova.network import model as network_model
from nova import objects
from nova import paths
from nova.pci import utils as pci_utils
@@ -1342,7 +1343,7 @@ def _set_device_mtu(dev, mtu=None):
check_exit_code=[0, 2, 254])
-def _create_veth_pair(dev1_name, dev2_name):
+def _create_veth_pair(dev1_name, dev2_name, mtu=None):
"""Create a pair of veth devices with the specified names,
deleting any previous devices with those names.
"""
@@ -1355,7 +1356,7 @@ def _create_veth_pair(dev1_name, dev2_name):
utils.execute('ip', 'link', 'set', dev, 'up', run_as_root=True)
utils.execute('ip', 'link', 'set', dev, 'promisc', 'on',
run_as_root=True)
- _set_device_mtu(dev)
+ _set_device_mtu(dev, mtu)
def _ovs_vsctl(args):
@@ -1368,15 +1369,34 @@ def _ovs_vsctl(args):
raise exception.AgentError(method=full_args)
-def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id):
- _ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--',
- 'add-port', bridge, dev,
- '--', 'set', 'Interface', dev,
- 'external-ids:iface-id=%s' % iface_id,
- 'external-ids:iface-status=active',
- 'external-ids:attached-mac=%s' % mac,
- 'external-ids:vm-uuid=%s' % instance_id])
- _set_device_mtu(dev)
+def _create_ovs_vif_cmd(bridge, dev, iface_id, mac,
+ instance_id, interface_type=None):
+ cmd = ['--', '--if-exists', 'del-port', dev, '--',
+ 'add-port', bridge, dev,
+ '--', 'set', 'Interface', dev,
+ 'external-ids:iface-id=%s' % iface_id,
+ 'external-ids:iface-status=active',
+ 'external-ids:attached-mac=%s' % mac,
+ 'external-ids:vm-uuid=%s' % instance_id]
+ if interface_type:
+ cmd += ['type=%s' % interface_type]
+ return cmd
+
+
+def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id,
+ mtu=None, interface_type=None):
+ _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id,
+ mac, instance_id,
+ interface_type))
+ # Note at present there is no support for setting the
+ # mtu for vhost-user type ports.
+ if interface_type != network_model.OVS_VHOSTUSER_INTERFACE_TYPE:
+ _set_device_mtu(dev, mtu)
+ else:
+ LOG.debug("MTU not set on %(interface_name)s interface "
+ "of type %(interface_type)s.",
+ {'interface_name': dev,
+ 'interface_type': interface_type})
def delete_ovs_vif_port(bridge, dev):
@@ -1384,10 +1404,6 @@ def delete_ovs_vif_port(bridge, dev):
delete_net_dev(dev)
-def ovs_set_vhostuser_port_type(dev):
- _ovs_vsctl(['--', 'set', 'Interface', dev, 'type=dpdkvhostuser'])
-
-
def create_ivs_vif_port(dev, iface_id, mac, instance_id):
utils.execute('ivs-ctl', 'add-port',
dev, run_as_root=True)
diff --git a/nova/network/model.py b/nova/network/model.py
index c7376f862d..c7979d7c2a 100644
--- a/nova/network/model.py
+++ b/nova/network/model.py
@@ -77,6 +77,8 @@ VIF_DETAILS_VHOSTUSER_SOCKET = 'vhostuser_socket'
# Specifies whether vhost-user socket should be plugged
# into ovs bridge. Valid values are True and False
VIF_DETAILS_VHOSTUSER_OVS_PLUG = 'vhostuser_ovs_plug'
+# ovs vhost user interface type name
+OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser'
# Constants for dictionary keys in the 'vif_details' field that are
# valid for VIF_TYPE_TAP.
diff --git a/nova/network/neutronv2/api.py b/nova/network/neutronv2/api.py
index c04b60f722..7fb31c947b 100644
--- a/nova/network/neutronv2/api.py
+++ b/nova/network/neutronv2/api.py
@@ -1602,10 +1602,12 @@ class API(base_api.NetworkAPI):
def _nw_info_build_network(self, port, networks, subnets):
network_name = None
+ network_mtu = None
for net in networks:
if port['network_id'] == net['id']:
network_name = net['name']
tenant_id = net['tenant_id']
+ network_mtu = net.get('mtu')
break
else:
tenant_id = port['tenant_id']
@@ -1648,7 +1650,8 @@ class API(base_api.NetworkAPI):
bridge=bridge,
injected=CONF.flat_injected,
label=network_name,
- tenant_id=tenant_id
+ tenant_id=tenant_id,
+ mtu=network_mtu
)
network['subnets'] = subnets
port_profile = port.get('binding:profile')
diff --git a/nova/tests/functional/regressions/test_bug_1558866.py b/nova/tests/functional/regressions/test_bug_1558866.py
new file mode 100644
index 0000000000..378b629aa8
--- /dev/null
+++ b/nova/tests/functional/regressions/test_bug_1558866.py
@@ -0,0 +1,77 @@
+# Copyright 2016 IBM Corp.
+#
+# 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 datetime
+
+from oslo_config import cfg
+
+from nova import test
+from nova.tests import fixtures as nova_fixtures
+from nova.tests.functional.api import client as api_client
+from nova.tests.unit.image import fake as fake_image
+from nova.tests.unit import policy_fixture
+
+CONF = cfg.CONF
+CONF.import_opt('null_kernel', 'nova.compute.api')
+
+
+class TestServerGet(test.TestCase):
+
+ def setUp(self):
+ super(TestServerGet, self).setUp()
+ self.useFixture(policy_fixture.RealPolicyFixture())
+ api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
+ api_version='v2.1'))
+
+ self.api = api_fixture.api
+
+ # the image fake backend needed for image discovery
+ image_service = fake_image.stub_out_image_service(self)
+ self.addCleanup(fake_image.FakeImageService_reset)
+
+ # NOTE(mriedem): This image has an invalid architecture metadata value
+ # and is used for negative testing in the functional stack.
+ timestamp = datetime.datetime(2011, 1, 1, 1, 2, 3)
+ image = {'id': 'c456eb30-91d7-4f43-8f46-2efd9eccd744',
+ 'name': 'fake-image-invalid-arch',
+ 'created_at': timestamp,
+ 'updated_at': timestamp,
+ 'deleted_at': None,
+ 'deleted': False,
+ 'status': 'active',
+ 'is_public': False,
+ 'container_format': 'raw',
+ 'disk_format': 'raw',
+ 'size': '25165824',
+ 'properties': {'kernel_id': CONF.null_kernel,
+ 'ramdisk_id': CONF.null_kernel,
+ 'architecture': 'x64'}}
+ self.image_id = image_service.create(None, image)['id']
+ self.flavor_id = self.api.get_flavors()[0]['id']
+
+ def test_boot_server_with_invalid_image_meta(self):
+ """Regression test for bug #1558866.
+
+ Glance allows you to provide any architecture value for image meta
+ properties but nova validates the image metadata against the
+ nova.compute.arch.ALL values during the conversion to the ImageMeta
+ object. This test ensures we get a 400 back in that case rather than
+ a 500.
+ """
+ server = dict(name='server1',
+ imageRef=self.image_id,
+ flavorRef=self.flavor_id)
+ ex = self.assertRaises(api_client.OpenStackApiException,
+ self.api.post_server, {'server': server})
+ self.assertEqual(400, ex.response.status_code)
diff --git a/nova/tests/unit/api/openstack/compute/test_flavors_extra_specs.py b/nova/tests/unit/api/openstack/compute/test_flavors_extra_specs.py
index 783b3af289..b70a97a8ce 100644
--- a/nova/tests/unit/api/openstack/compute/test_flavors_extra_specs.py
+++ b/nova/tests/unit/api/openstack/compute/test_flavors_extra_specs.py
@@ -190,7 +190,8 @@ class FlavorsExtraSpecsTestV21(test.TestCase):
def test_create_flavor_db_duplicate(self):
def fake_instance_type_extra_specs_update_or_create(*args, **kwargs):
- raise exception.FlavorExtraSpecUpdateCreateFailed(id=1, retries=5)
+ raise exception.FlavorExtraSpecUpdateCreateFailed(id='1',
+ retries=5)
self.stubs.Set(nova.db,
'flavor_extra_specs_update_or_create',
@@ -348,7 +349,8 @@ class FlavorsExtraSpecsTestV21(test.TestCase):
def test_update_flavor_db_duplicate(self):
def fake_instance_type_extra_specs_update_or_create(*args, **kwargs):
- raise exception.FlavorExtraSpecUpdateCreateFailed(id=1, retries=5)
+ raise exception.FlavorExtraSpecUpdateCreateFailed(id='1',
+ retries=5)
self.stubs.Set(nova.db,
'flavor_extra_specs_update_or_create',
diff --git a/nova/tests/unit/api/openstack/compute/test_serversV21.py b/nova/tests/unit/api/openstack/compute/test_serversV21.py
index 5b36a7828c..3ec79c3d78 100644
--- a/nova/tests/unit/api/openstack/compute/test_serversV21.py
+++ b/nova/tests/unit/api/openstack/compute/test_serversV21.py
@@ -2984,6 +2984,18 @@ class ServersControllerCreateTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, self.req, body=self.body)
+ def test_create_instance_without_personality_should_get_empty_list(self):
+ old_create = compute_api.API.create
+ del self.body['server']['personality']
+
+ def create(*args, **kwargs):
+ self.assertEqual([], kwargs['injected_files'])
+ return old_create(*args, **kwargs)
+
+ self.stubs.Set(compute_api.API, 'create', create)
+
+ self._test_create_instance()
+
def test_create_instance_with_extra_personality_arg(self):
self.body['server']['personality'] = [
{
diff --git a/nova/tests/unit/compute/test_compute_api.py b/nova/tests/unit/compute/test_compute_api.py
index 2f20e2323b..d7278bea2b 100644
--- a/nova/tests/unit/compute/test_compute_api.py
+++ b/nova/tests/unit/compute/test_compute_api.py
@@ -1207,7 +1207,7 @@ class _ComputeAPIUnitTestMixIn(object):
self.context, fake_inst['uuid'], 'finished').AndReturn(
fake_mig)
compute_utils.reverse_upsize_quota_delta(
- self.context, fake_mig).AndReturn('deltas')
+ self.context, fake_inst).AndReturn('deltas')
resvs = ['resvs']
fake_quotas = objects.Quotas.from_reservations(self.context, resvs)
@@ -1265,7 +1265,7 @@ class _ComputeAPIUnitTestMixIn(object):
delta = ['delta']
compute_utils.reverse_upsize_quota_delta(
- self.context, fake_mig).AndReturn(delta)
+ self.context, fake_inst).AndReturn(delta)
resvs = ['resvs']
fake_quotas = objects.Quotas.from_reservations(self.context, resvs)
compute_utils.reserve_quota_delta(
diff --git a/nova/tests/unit/compute/test_compute_mgr.py b/nova/tests/unit/compute/test_compute_mgr.py
index 9dfb886f50..33b06709a3 100644
--- a/nova/tests/unit/compute/test_compute_mgr.py
+++ b/nova/tests/unit/compute/test_compute_mgr.py
@@ -1105,6 +1105,10 @@ class ComputeManagerUnitTestCase(test.NoDBTestCase):
exc = exception.DiskNotFound
self._test_shutdown_instance_exception(exc)
+ def test_shutdown_instance_other_exception(self):
+ exc = Exception('some other exception')
+ self._test_shutdown_instance_exception(exc)
+
def _test_init_instance_retries_reboot(self, instance, reboot_type,
return_power_state):
instance.host = self.compute.host
diff --git a/nova/tests/unit/compute/test_compute_utils.py b/nova/tests/unit/compute/test_compute_utils.py
index 187d13232b..b6fc319c58 100644
--- a/nova/tests/unit/compute/test_compute_utils.py
+++ b/nova/tests/unit/compute/test_compute_utils.py
@@ -723,8 +723,7 @@ class ComputeUtilsQuotaDeltaTestCase(test.TestCase):
deltas = compute_utils.downsize_quota_delta(self.context, inst)
self.assertEqual(expected_deltas, deltas)
- @mock.patch.object(objects.Flavor, 'get_by_id')
- def test_reverse_quota_delta(self, mock_get_flavor):
+ def test_reverse_quota_delta(self):
inst = create_instance(self.context, params=None)
inst.old_flavor = flavors.get_flavor_by_name('m1.tiny')
inst.new_flavor = flavors.get_flavor_by_name('m1.medium')
@@ -735,20 +734,8 @@ class ComputeUtilsQuotaDeltaTestCase(test.TestCase):
'ram': -1 * (inst.new_flavor['memory_mb'] -
inst.old_flavor['memory_mb'])
}
- updates = {'old_instance_type_id': inst.old_flavor['id'],
- 'new_instance_type_id': inst.new_flavor['id']}
-
- fake_migration = test_migration.fake_db_migration(**updates)
-
- def _flavor_get_by_id(context, type_id):
- if type_id == updates['old_instance_type_id']:
- return inst.old_flavor
- else:
- return inst.new_flavor
- mock_get_flavor.side_effect = _flavor_get_by_id
- deltas = compute_utils.reverse_upsize_quota_delta(self.context,
- fake_migration)
+ deltas = compute_utils.reverse_upsize_quota_delta(self.context, inst)
self.assertEqual(expected_deltas, deltas)
@mock.patch.object(objects.Quotas, 'reserve')
diff --git a/nova/tests/unit/network/test_linux_net.py b/nova/tests/unit/network/test_linux_net.py
index a75dc100be..26a531f2ca 100644
--- a/nova/tests/unit/network/test_linux_net.py
+++ b/nova/tests/unit/network/test_linux_net.py
@@ -34,6 +34,7 @@ from nova import db
from nova import exception
from nova.network import driver
from nova.network import linux_net
+from nova.network import model as network_model
from nova import objects
from nova import test
from nova import utils
@@ -1210,13 +1211,37 @@ class LinuxNetworkTestCase(test.NoDBTestCase):
linux_net._set_device_mtu('fake-dev')
ex.assert_has_calls(calls)
- def _ovs_vif_port(self, calls):
+ def _ovs_vif_port(self, calls, interface_type=None):
with mock.patch.object(utils, 'execute', return_value=('', '')) as ex:
linux_net.create_ovs_vif_port('fake-bridge', 'fake-dev',
'fake-iface-id', 'fake-mac',
- 'fake-instance-uuid')
+ 'fake-instance-uuid',
+ interface_type=interface_type)
ex.assert_has_calls(calls)
+ def test_ovs_vif_port_cmd(self):
+ expected = ['--', '--if-exists',
+ 'del-port', 'fake-dev', '--', 'add-port',
+ 'fake-bridge', 'fake-dev',
+ '--', 'set', 'Interface', 'fake-dev',
+ 'external-ids:iface-id=fake-iface-id',
+ 'external-ids:iface-status=active',
+ 'external-ids:attached-mac=fake-mac',
+ 'external-ids:vm-uuid=fake-instance-uuid'
+ ]
+ cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
+ 'fake-iface-id', 'fake-mac',
+ 'fake-instance-uuid')
+
+ self.assertEqual(expected, cmd)
+
+ expected += ['type=fake-type']
+ cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
+ 'fake-iface-id', 'fake-mac',
+ 'fake-instance-uuid',
+ 'fake-type')
+ self.assertEqual(expected, cmd)
+
def test_ovs_vif_port(self):
calls = [
mock.call('ovs-vsctl', '--timeout=120', '--', '--if-exists',
@@ -1231,6 +1256,22 @@ class LinuxNetworkTestCase(test.NoDBTestCase):
]
self._ovs_vif_port(calls)
+ @mock.patch.object(linux_net, '_ovs_vsctl')
+ @mock.patch.object(linux_net, '_create_ovs_vif_cmd')
+ @mock.patch.object(linux_net, '_set_device_mtu')
+ def test_ovs_vif_port_with_type_vhostuser(self, mock_set_device_mtu,
+ mock_create_cmd, mock_vsctl):
+ linux_net.create_ovs_vif_port(
+ 'fake-bridge',
+ 'fake-dev', 'fake-iface-id', 'fake-mac',
+ "fake-instance-uuid", mtu=1500,
+ interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE)
+ mock_create_cmd.assert_called_once_with('fake-bridge',
+ 'fake-dev', 'fake-iface-id', 'fake-mac',
+ "fake-instance-uuid", network_model.OVS_VHOSTUSER_INTERFACE_TYPE)
+ self.assertFalse(mock_set_device_mtu.called)
+ self.assertTrue(mock_vsctl.called)
+
def test_ovs_vif_port_with_mtu(self):
self.flags(network_device_mtu=10000)
calls = [
@@ -1371,16 +1412,6 @@ class LinuxNetworkTestCase(test.NoDBTestCase):
self.assertEqual(2, len(executes))
self.mox.UnsetStubs()
- def test_ovs_set_vhostuser_type(self):
- calls = [
- mock.call('ovs-vsctl', '--timeout=120', '--', 'set',
- 'Interface', 'fake-dev', 'type=dpdkvhostuser',
- run_as_root=True)
- ]
- with mock.patch.object(utils, 'execute', return_value=('', '')) as ex:
- linux_net.ovs_set_vhostuser_port_type('fake-dev')
- ex.assert_has_calls(calls)
-
@mock.patch('os.path.exists', return_value=True)
@mock.patch('nova.utils.execute')
def test_remove_bridge(self, mock_execute, mock_exists):
diff --git a/nova/tests/unit/network/test_neutronv2.py b/nova/tests/unit/network/test_neutronv2.py
index 7424cbb63f..295c672909 100644
--- a/nova/tests/unit/network/test_neutronv2.py
+++ b/nova/tests/unit/network/test_neutronv2.py
@@ -2391,7 +2391,8 @@ class TestNeutronv2(TestNeutronv2Base):
'binding:vif_type': vif_type,
}
fake_subnets = [model.Subnet(cidr='1.0.0.0/8')]
- fake_nets = [{'id': 'net-id', 'name': 'foo', 'tenant_id': 'tenant'}]
+ fake_nets = [{'id': 'net-id', 'name': 'foo', 'tenant_id': 'tenant',
+ 'mtu': 9000}]
api = neutronapi.API()
self.mox.ReplayAll()
neutronapi.get_client('fake')
@@ -2401,6 +2402,7 @@ class TestNeutronv2(TestNeutronv2Base):
self.assertEqual(net['id'], 'net-id')
self.assertEqual(net['label'], 'foo')
self.assertEqual(net.get_meta('tenant_id'), 'tenant')
+ self.assertEqual(9000, net.get_meta('mtu'))
self.assertEqual(net.get_meta('injected'), CONF.flat_injected)
return net, iid
diff --git a/nova/tests/unit/virt/libvirt/test_vif.py b/nova/tests/unit/virt/libvirt/test_vif.py
index 3bc8ab27f2..d7c18b615d 100644
--- a/nova/tests/unit/virt/libvirt/test_vif.py
+++ b/nova/tests/unit/virt/libvirt/test_vif.py
@@ -59,7 +59,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
subnets=[subnet_bridge_4,
subnet_bridge_6],
bridge_interface='eth0',
- vlan=99)
+ vlan=99, mtu=9000)
vif_bridge = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
@@ -89,7 +89,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
subnets=[subnet_bridge_4,
subnet_bridge_6],
bridge_interface=None,
- vlan=99)
+ vlan=99, mtu=1000)
network_ivs = network_model.Network(id='network-id-xxx-yyy-zzz',
bridge='br0',
@@ -312,7 +312,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
network_model.VIF_DETAILS_VHOSTUSER_SOCKET:
'/tmp/usv-xxx-yyy-zzz',
network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True},
- ovs_interfaceid='aaa-bbb-ccc'
+ ovs_interfaceid='aaa-bbb-ccc', mtu=1500
)
vif_vhostuser_no_path = network_model.VIF(id='vif-xxx-yyy-zzz',
@@ -665,7 +665,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
'device_exists': [mock.call('qbrvif-xxx-yyy'),
mock.call('qvovif-xxx-yyy')],
'_create_veth_pair': [mock.call('qvbvif-xxx-yyy',
- 'qvovif-xxx-yyy')],
+ 'qvovif-xxx-yyy', 1000)],
'execute': [mock.call('brctl', 'addbr', 'qbrvif-xxx-yyy',
run_as_root=True),
mock.call('brctl', 'setfd', 'qbrvif-xxx-yyy', 0,
@@ -679,7 +679,8 @@ class LibvirtVifTestCase(test.NoDBTestCase):
'create_ovs_vif_port': [mock.call('br0',
'qvovif-xxx-yyy', 'aaa-bbb-ccc',
'ca:fe:de:ad:be:ef',
- 'instance-uuid')]
+ 'instance-uuid',
+ 1000)]
}
# The disable_ipv6 call needs to be added in the middle, if required
if ipv6_exists:
@@ -799,7 +800,7 @@ class LibvirtVifTestCase(test.NoDBTestCase):
'device_exists': [mock.call('qbrvif-xxx-yyy'),
mock.call('qvovif-xxx-yyy')],
'_create_veth_pair': [mock.call('qvbvif-xxx-yyy',
- 'qvovif-xxx-yyy')],
+ 'qvovif-xxx-yyy', None)],
'execute': [mock.call('brctl', 'addbr', 'qbrvif-xxx-yyy',
run_as_root=True),
mock.call('brctl', 'setfd', 'qbrvif-xxx-yyy', 0,
@@ -1311,22 +1312,18 @@ class LibvirtVifTestCase(test.NoDBTestCase):
def test_vhostuser_ovs_plug(self):
calls = {
- 'create_ovs_vif_port': [mock.call('br0',
- 'usv-xxx-yyy-zzz',
- 'aaa-bbb-ccc',
- 'ca:fe:de:ad:be:ef',
- 'instance-uuid')],
- 'ovs_set_vhostuser_port_type': [mock.call('usv-xxx-yyy-zzz')]
+ 'create_ovs_vif_port': [
+ mock.call(
+ 'br0', 'usv-xxx-yyy-zzz', 'aaa-bbb-ccc',
+ 'ca:fe:de:ad:be:ef', 'instance-uuid', 9000,
+ interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE
+ )]
}
- with contextlib.nested(
- mock.patch.object(linux_net, 'create_ovs_vif_port'),
- mock.patch.object(linux_net, 'ovs_set_vhostuser_port_type')
- ) as (create_ovs_vif_port, ovs_set_vhostuser_port_type):
+ with mock.patch.object(linux_net,
+ 'create_ovs_vif_port') as create_ovs_vif_port:
d = vif.LibvirtGenericVIFDriver()
d.plug_vhostuser(self.instance, self.vif_vhostuser_ovs)
create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port'])
- ovs_set_vhostuser_port_type.assert_has_calls(
- calls['ovs_set_vhostuser_port_type'])
def test_vhostuser_ovs_unplug(self):
calls = {
diff --git a/nova/tests/unit/volume/test_cinder.py b/nova/tests/unit/volume/test_cinder.py
index 120a31e285..4334632268 100644
--- a/nova/tests/unit/volume/test_cinder.py
+++ b/nova/tests/unit/volume/test_cinder.py
@@ -293,6 +293,25 @@ class CinderApiTestCase(test.NoDBTestCase):
mock_cinderclient.return_value.volumes. \
initialize_connection.assert_called_once_with(volume_id, connector)
+ @mock.patch('nova.volume.cinder.LOG')
+ @mock.patch('nova.volume.cinder.cinderclient')
+ def test_initialize_connection_exception_no_code(
+ self, mock_cinderclient, mock_log):
+ mock_cinderclient.return_value.volumes. \
+ initialize_connection.side_effect = (
+ cinder_exception.ClientException(500, "500"))
+ mock_cinderclient.return_value.volumes. \
+ terminate_connection.side_effect = (
+ test.TestingException)
+
+ connector = {'host': 'fakehost1'}
+ self.assertRaises(cinder_exception.ClientException,
+ self.api.initialize_connection,
+ self.ctx,
+ 'id1',
+ connector)
+ self.assertIsNone(mock_log.error.call_args_list[1][0][1]['code'])
+
@mock.patch('nova.volume.cinder.cinderclient')
def test_initialize_connection_rollback(self, mock_cinderclient):
mock_cinderclient.return_value.volumes.\
diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py
index 5fcf492580..54a445faef 100644
--- a/nova/virt/libvirt/vif.py
+++ b/nova/virt/libvirt/vif.py
@@ -512,13 +512,15 @@ class LibvirtGenericVIFDriver(object):
check_exit_code=[0, 1])
if not linux_net.device_exists(v2_name):
- linux_net._create_veth_pair(v1_name, v2_name)
+ mtu = vif['network'].get_meta('mtu')
+ linux_net._create_veth_pair(v1_name, v2_name, mtu)
utils.execute('ip', 'link', 'set', br_name, 'up', run_as_root=True)
utils.execute('brctl', 'addif', br_name, v1_name, run_as_root=True)
if port == 'ovs':
linux_net.create_ovs_vif_port(self.get_bridge_name(vif),
v2_name, iface_id,
- vif['address'], instance.uuid)
+ vif['address'], instance.uuid,
+ mtu)
elif port == 'ivs':
linux_net.create_ivs_vif_port(v2_name, iface_id,
vif['address'], instance.uuid)
@@ -660,7 +662,9 @@ class LibvirtGenericVIFDriver(object):
dev = self.get_vif_devname(vif)
mac = vif['details'].get(network_model.VIF_DETAILS_TAP_MAC_ADDRESS)
linux_net.create_tap_dev(dev, mac)
- linux_net._set_device_mtu(dev)
+ network = vif.get('network')
+ mtu = network.get_meta('mtu') if network else None
+ linux_net._set_device_mtu(dev, mtu)
def plug_vhostuser(self, instance, vif):
ovs_plug = vif['details'].get(
@@ -670,10 +674,12 @@ class LibvirtGenericVIFDriver(object):
iface_id = self.get_ovs_interfaceid(vif)
port_name = os.path.basename(
vif['details'][network_model.VIF_DETAILS_VHOSTUSER_SOCKET])
- linux_net.create_ovs_vif_port(self.get_bridge_name(vif),
- port_name, iface_id, vif['address'],
- instance.uuid)
- linux_net.ovs_set_vhostuser_port_type(port_name)
+ mtu = vif['network'].get_meta('mtu')
+ linux_net.create_ovs_vif_port(
+ self.get_bridge_name(vif),
+ port_name, iface_id, vif['address'],
+ instance.uuid, mtu,
+ interface_type=network_model.OVS_VHOSTUSER_INTERFACE_TYPE)
def plug_vrouter(self, instance, vif):
"""Plug into Contrail's network port
diff --git a/nova/volume/cinder.py b/nova/volume/cinder.py
index 5a7c5aa106..e8748d1bc7 100644
--- a/nova/volume/cinder.py
+++ b/nova/volume/cinder.py
@@ -366,7 +366,8 @@ class API(object):
{'vol': volume_id,
'host': connector.get('host'),
'msg': six.text_type(exc),
- 'code': exc.code})
+ 'code': (
+ exc.code if hasattr(exc, 'code') else None)})
@translate_volume_exception
def terminate_connection(self, context, volume_id, connector):
diff --git a/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml b/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml
new file mode 100644
index 0000000000..642a7d2318
--- /dev/null
+++ b/releasenotes/notes/vhost-user-mtu-23d0af36a8adfa56.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - When plugging virtual interfaces of type vhost-user the MTU value will
+ not be applied to the interface by nova. vhost-user ports exist only in
+ userspace and are not backed by kernel netdevs, for this reason it is
+ not possible to set the mtu on a vhost-user interface using standard
+ tools such as ifconfig or ip link.
diff --git a/tox.ini b/tox.ini
index c54c644b8f..382f9ec8f8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-minversion = 1.8
+minversion = 2.0
envlist = py34,py27,functional,pep8,pip-missing-reqs
skipsdist = True
@@ -156,6 +156,10 @@ commands =
coverage html --include='nova/*' --omit='nova/openstack/common/*' -d covhtml -i
[testenv:venv]
+# NOTE(jaegerandi): This target does not use constraints because
+# upstream infra does not yet support it. Once that's fixed, we can
+# drop the install_command.
+install_command = pip install -U --force-reinstall {opts} {packages}
commands = {posargs}
[testenv:docs]