fb4184f1e6
Change Idcbada705c1d38ac5fd7c600141c2de7020eae25 in Ocata started preferring Cinder connection info for getting RBD auth values since Nova needs to be using the same settings as Cinder for volume auth. However, that introduced a problem for guest connections made before that change, where the secret_uuid might not have been configured on the Cinder side and that's what is stored in the block_device_mappings.connection_info column and is what we're checking in _set_auth_config_rbd. Before Ocata this wasn't a problem because we'd use the Nova configuration values for the rbd_secret_uuid if set. But since Ocata it is a problem since we don't consult nova.conf if auth was enabled, but not completely configured, on the Cinder side. So this adds a fallback check to set the secret_uuid from nova.conf if it wasn't set in the connection_info via Cinder originally. A note is also added to caution about removing any fallback mechanism on the nova side - something we'd need to consider before we could likely drop this code. Co-Authored-By: Tadas Ustinavičius <tadas@ring.lt> NOTE(mriedem): The unit test is modified slightly to not pass an instance to the disconnect_volume method as that was only available starting in Pike:b66b7d4f9d
Change-Id: I6fc7108817fcd9df4a342c9dabbf14ab7911d06a Closes-Bug: #1687581 (cherry picked from commitf2d27f6a8a
)
234 lines
11 KiB
Python
234 lines
11 KiB
Python
# 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 mock
|
|
|
|
import nova.conf
|
|
from nova.tests.unit.virt.libvirt.volume import test_volume
|
|
from nova.virt.libvirt import host
|
|
from nova.virt.libvirt.volume import net
|
|
|
|
CONF = nova.conf.CONF
|
|
|
|
|
|
class LibvirtNetVolumeDriverTestCase(
|
|
test_volume.LibvirtISCSIVolumeBaseTestCase):
|
|
"""Tests the libvirt network volume driver."""
|
|
|
|
def _assertNetworkAndProtocolEquals(self, tree):
|
|
self.assertEqual('network', tree.get('type'))
|
|
self.assertEqual('rbd', tree.find('./source').get('protocol'))
|
|
rbd_name = '%s/%s' % ('rbd', self.name)
|
|
self.assertEqual(rbd_name, tree.find('./source').get('name'))
|
|
|
|
def _assertISCSINetworkAndProtocolEquals(self, tree):
|
|
self.assertEqual('network', tree.get('type'))
|
|
self.assertEqual('iscsi', tree.find('./source').get('protocol'))
|
|
iscsi_name = '%s/%s' % (self.iqn, self.vol['id'])
|
|
self.assertEqual(iscsi_name, tree.find('./source').get('name'))
|
|
|
|
def sheepdog_connection(self, volume):
|
|
return {
|
|
'driver_volume_type': 'sheepdog',
|
|
'data': {
|
|
'name': volume['name']
|
|
}
|
|
}
|
|
|
|
def test_libvirt_sheepdog_driver(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.sheepdog_connection(self.vol)
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self.assertEqual('network', tree.get('type'))
|
|
self.assertEqual('sheepdog', tree.find('./source').get('protocol'))
|
|
self.assertEqual(self.name, tree.find('./source').get('name'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def rbd_connection(self, volume):
|
|
return {
|
|
'driver_volume_type': 'rbd',
|
|
'data': {
|
|
'name': '%s/%s' % ('rbd', volume['name']),
|
|
'auth_enabled': CONF.libvirt.rbd_user is not None,
|
|
'auth_username': CONF.libvirt.rbd_user,
|
|
'secret_type': 'ceph',
|
|
'secret_uuid': CONF.libvirt.rbd_secret_uuid,
|
|
'qos_specs': {
|
|
'total_bytes_sec': '1048576',
|
|
'read_iops_sec': '500',
|
|
}
|
|
}
|
|
}
|
|
|
|
def test_libvirt_rbd_driver(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertIsNone(tree.find('./source/auth'))
|
|
self.assertEqual('1048576', tree.find('./iotune/total_bytes_sec').text)
|
|
self.assertEqual('500', tree.find('./iotune/read_iops_sec').text)
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_hosts(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
hosts = ['example.com', '1.2.3.4', '::1']
|
|
ports = [None, '6790', '6791']
|
|
connection_info['data']['hosts'] = hosts
|
|
connection_info['data']['ports'] = ports
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertIsNone(tree.find('./source/auth'))
|
|
found_hosts = tree.findall('./source/host')
|
|
self.assertEqual(hosts, [host.get('name') for host in found_hosts])
|
|
self.assertEqual(ports, [host.get('port') for host in found_hosts])
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_auth_enabled(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
secret_type = 'ceph'
|
|
connection_info['data']['auth_enabled'] = True
|
|
connection_info['data']['auth_username'] = self.user
|
|
connection_info['data']['secret_type'] = secret_type
|
|
connection_info['data']['secret_uuid'] = self.uuid
|
|
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertEqual(self.user, tree.find('./auth').get('username'))
|
|
self.assertEqual(secret_type, tree.find('./auth/secret').get('type'))
|
|
self.assertEqual(self.uuid, tree.find('./auth/secret').get('uuid'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_auth_enabled_flags(self):
|
|
# The values from the cinder connection_info take precedence over
|
|
# nova.conf values.
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
secret_type = 'ceph'
|
|
connection_info['data']['auth_enabled'] = True
|
|
connection_info['data']['auth_username'] = self.user
|
|
connection_info['data']['secret_type'] = secret_type
|
|
connection_info['data']['secret_uuid'] = self.uuid
|
|
|
|
flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'
|
|
flags_user = 'bar'
|
|
self.flags(rbd_user=flags_user,
|
|
rbd_secret_uuid=flags_uuid,
|
|
group='libvirt')
|
|
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertEqual(self.user, tree.find('./auth').get('username'))
|
|
self.assertEqual(secret_type, tree.find('./auth/secret').get('type'))
|
|
self.assertEqual(self.uuid, tree.find('./auth/secret').get('uuid'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_auth_enabled_flags_secret_uuid_fallback(self):
|
|
"""The values from the cinder connection_info take precedence over
|
|
nova.conf values, unless it's old connection data where the
|
|
secret_uuid wasn't set on the cinder side for the original connection
|
|
which is now persisted in the
|
|
nova.block_device_mappings.connection_info column and used here. In
|
|
this case we fallback to use the local config for secret_uuid.
|
|
"""
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
secret_type = 'ceph'
|
|
connection_info['data']['auth_enabled'] = True
|
|
connection_info['data']['auth_username'] = self.user
|
|
connection_info['data']['secret_type'] = secret_type
|
|
# Fake out cinder not setting the secret_uuid in the old connection.
|
|
connection_info['data']['secret_uuid'] = None
|
|
|
|
flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'
|
|
flags_user = 'bar'
|
|
self.flags(rbd_user=flags_user,
|
|
rbd_secret_uuid=flags_uuid,
|
|
group='libvirt')
|
|
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertEqual(self.user, tree.find('./auth').get('username'))
|
|
self.assertEqual(secret_type, tree.find('./auth/secret').get('type'))
|
|
# Assert that the secret_uuid comes from CONF.libvirt.rbd_secret_uuid.
|
|
self.assertEqual(flags_uuid, tree.find('./auth/secret').get('uuid'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_auth_disabled(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
secret_type = 'ceph'
|
|
connection_info['data']['auth_enabled'] = False
|
|
connection_info['data']['auth_username'] = self.user
|
|
connection_info['data']['secret_type'] = secret_type
|
|
connection_info['data']['secret_uuid'] = self.uuid
|
|
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertIsNone(tree.find('./auth'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
def test_libvirt_rbd_driver_auth_disabled_flags_override(self):
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.rbd_connection(self.vol)
|
|
secret_type = 'ceph'
|
|
connection_info['data']['auth_enabled'] = False
|
|
connection_info['data']['auth_username'] = self.user
|
|
connection_info['data']['secret_type'] = secret_type
|
|
connection_info['data']['secret_uuid'] = self.uuid
|
|
|
|
# NOTE: Supplying the rbd_secret_uuid will enable authentication
|
|
# locally in nova-compute even if not enabled in nova-volume/cinder
|
|
flags_uuid = '37152720-1785-11e2-a740-af0c1d8b8e4b'
|
|
flags_user = 'bar'
|
|
self.flags(rbd_user=flags_user,
|
|
rbd_secret_uuid=flags_uuid,
|
|
group='libvirt')
|
|
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertNetworkAndProtocolEquals(tree)
|
|
self.assertEqual(flags_user, tree.find('./auth').get('username'))
|
|
self.assertEqual(secret_type, tree.find('./auth/secret').get('type'))
|
|
self.assertEqual(flags_uuid, tree.find('./auth/secret').get('uuid'))
|
|
libvirt_driver.disconnect_volume(connection_info, "vde")
|
|
|
|
@mock.patch.object(host.Host, 'find_secret')
|
|
@mock.patch.object(host.Host, 'create_secret')
|
|
@mock.patch.object(host.Host, 'delete_secret')
|
|
def test_libvirt_iscsi_net_driver(self, mock_delete, mock_create,
|
|
mock_find):
|
|
mock_find.return_value = test_volume.FakeSecret()
|
|
mock_create.return_value = test_volume.FakeSecret()
|
|
libvirt_driver = net.LibvirtNetVolumeDriver(self.fake_host)
|
|
connection_info = self.iscsi_connection(self.vol, self.location,
|
|
self.iqn, auth=True)
|
|
secret_type = 'iscsi'
|
|
flags_user = connection_info['data']['auth_username']
|
|
conf = libvirt_driver.get_config(connection_info, self.disk_info)
|
|
tree = conf.format_dom()
|
|
self._assertISCSINetworkAndProtocolEquals(tree)
|
|
self.assertEqual(flags_user, tree.find('./auth').get('username'))
|
|
self.assertEqual(secret_type, tree.find('./auth/secret').get('type'))
|
|
self.assertEqual(test_volume.SECRET_UUID,
|
|
tree.find('./auth/secret').get('uuid'))
|
|
libvirt_driver.disconnect_volume(connection_info, 'vde')
|