Introduce LibvirtBaseFileSystemVolumeDriver

This adds the LibvirtBaseFileSystemVolumeDriver abstract base class
which the NFS, GPFS, Scality, SMBFS, GlusterFS and Quobyte volume
drivers will extend in subsequent changes.

The initial implementation handles the common work of getting the mount
and device paths for connecting and disconnecting volumes.

Part of blueprint consolidate-libvirt-fs-volume-drivers

Change-Id: I2a8b2cb27e731ebd1711cf0cd6dbcabb42fad4c1
This commit is contained in:
Matt Riedemann 2015-07-16 13:37:28 -07:00
parent b113f627cd
commit b4190670a4
2 changed files with 153 additions and 0 deletions

View File

@ -0,0 +1,58 @@
# Copyright 2015 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 os
import mock
from nova import test
from nova import utils
from nova.virt.libvirt.volume import fs
FAKE_MOUNT_POINT = '/var/lib/nova/fake-mount'
FAKE_SHARE = 'fake-share'
NORMALIZED_SHARE = FAKE_SHARE + '-normalized'
HASHED_SHARE = utils.get_hash_str(NORMALIZED_SHARE)
FAKE_DEVICE_NAME = 'fake-device'
class FakeFileSystemVolumeDriver(fs.LibvirtBaseFileSystemVolumeDriver):
def _get_mount_point_base(self):
return FAKE_MOUNT_POINT
def _normalize_export(self, export):
return NORMALIZED_SHARE
class LibvirtBaseFileSystemVolumeDriverTestCase(test.NoDBTestCase):
"""Tests the basic behavior of the LibvirtBaseFileSystemVolumeDriver"""
def setUp(self):
super(LibvirtBaseFileSystemVolumeDriverTestCase, self).setUp()
self.connection = mock.Mock()
self.driver = FakeFileSystemVolumeDriver(self.connection)
self.connection_info = {
'data': {
'export': FAKE_SHARE,
'name': FAKE_DEVICE_NAME,
}
}
def test_get_device_path(self):
path = self.driver._get_device_path(self.connection_info)
expected_path = os.path.join(FAKE_MOUNT_POINT,
HASHED_SHARE,
FAKE_DEVICE_NAME)
self.assertEqual(expected_path, path)

View File

@ -0,0 +1,95 @@
# Copyright 2015 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 abc
import os
import six
from nova import utils
from nova.virt.libvirt.volume import volume as libvirt_volume
@six.add_metaclass(abc.ABCMeta)
class LibvirtBaseFileSystemVolumeDriver(
libvirt_volume.LibvirtBaseVolumeDriver):
"""The base class for file system type volume drivers"""
def __init__(self, connection):
super(LibvirtBaseFileSystemVolumeDriver,
self).__init__(connection, is_block_dev=False)
@abc.abstractmethod
def _get_mount_point_base(self):
"""Return the mount point path prefix.
This is used to build the device path.
:returns: The mount point path prefix.
"""
raise NotImplementedError('_get_mount_point_base')
def _normalize_export(self, export):
"""Normalize the export (share) if necessary.
Subclasses should override this method if they have a non-standard
export value, e.g. if the export is a URL. By default this method just
returns the export value passed in unchanged.
:param export: The export (share) value to normalize.
:returns: The normalized export value.
"""
return export
def _get_mount_path(self, connection_info):
"""Returns the mount path prefix using the mount point base and share.
:param connection_info: dict of the form
::
connection_info = {
'data': {
'export': the file system share,
...
}
...
}
:returns: The mount path prefix.
"""
share = self._normalize_export(connection_info['data']['export'])
return os.path.join(self._get_mount_point_base(),
utils.get_hash_str(share))
def _get_device_path(self, connection_info):
"""Returns the hashed path to the device.
:param connection_info: dict of the form
::
connection_info = {
'data': {
'export': the file system share,
'name': the name of the device,
...
}
...
}
:returns: The full path to the device.
"""
mount_path = self._get_mount_path(connection_info)
return os.path.join(mount_path, connection_info['data']['name'])