cinder/cinder/volume/drivers/veritas_cnfs.py

187 lines
7.6 KiB
Python

# Copyright (c) 2017 Veritas Technologies LLC
# 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 os
from oslo_log import log as logging
from oslo_utils import excutils
from cinder import exception
from cinder.i18n import _
from cinder import interface
import cinder.privsep.path
from cinder.volume.drivers import nfs
LOG = logging.getLogger(__name__)
@interface.volumedriver
class VeritasCNFSDriver(nfs.NfsDriver):
"""Veritas Clustered NFS based cinder driver
.. code-block:: default
Version History:
1.0.0 - Initial driver implementations for Kilo.
1.0.1 - Liberty release driver not implemented.
Place holder for Liberty release in case we
need to support.
1.0.2 - cinder.interface.volumedriver decorator.
Mitaka/Newton/Okata Release
1.0.3 - Seperate create_cloned_volume() and
create_volume_from_snapshot () functionality.
Pike Release
Executes commands relating to Volumes.
"""
VERSION = "1.0.3"
# ThirdPartySytems wiki page
CI_WIKI_NAME = "Veritas_Access_CI"
DRIVER_VOLUME_TYPE = 'nfs'
def __init__(self, *args, **kwargs):
self._execute = None
self._context = None
super(VeritasCNFSDriver, self).__init__(*args, **kwargs)
def do_setup(self, context):
self._context = context
super(VeritasCNFSDriver, self).do_setup(context)
opts = self.configuration.nfs_mount_options
if not opts or opts.find('vers=3') == -1 or (
opts.find('nfsvers=3')) == -1:
msg = _("NFS is not configured to use NFSv3")
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from snapshot."""
LOG.debug('VeritasNFSDriver create_volume_from_snapshot called '
'volume_id = %(volume)s and snapshot_id = %(snapshot)s',
{'volume': volume.id, 'snapshot': snapshot.id})
snap_name = snapshot.name
vol_size = volume.size
snap_size = snapshot.volume_size
self._do_clone_volume(snapshot, snap_name, volume)
volume.provider_location = snapshot.provider_location
if vol_size != snap_size:
try:
self.extend_volume(volume, vol_size)
except exception.ExtendVolumeError as ex:
with excutils.save_and_reraise_exception():
LOG.error('Failed to extend Volume: %s', ex.msg)
path = self.local_path(volume)
self._delete_file(path)
return {'provider_location': volume.provider_location}
def _get_vol_by_id(self, volid):
vol = self.db.volume_get(self._context, volid)
return vol
def _delete_file(self, path):
"""Deletes file from disk and return result as boolean."""
try:
LOG.debug('Deleting file at path %s', path)
self._execute('rm', '-f', path, run_as_root=True)
except OSError as ex:
LOG.warning('Exception during deleting %s', ex.strerror)
def create_snapshot(self, snapshot):
"""Create a snapshot of the volume."""
src_vol_id = snapshot.volume_id
src_vol_name = snapshot.volume_name
src_vol = self._get_vol_by_id(src_vol_id)
self._do_clone_volume(src_vol, src_vol_name, snapshot)
snapshot.provider_location = src_vol.provider_location
LOG.debug("VeritasNFSDriver create_snapshot %r",
snapshot.provider_location)
return {'provider_location': snapshot.provider_location}
def delete_snapshot(self, snapshot):
"""Delete a snapshot."""
if not snapshot.provider_location:
LOG.warning('Snapshot %s does not have provider_location '
'specified, skipping', snapshot.name)
return
self._ensure_share_mounted(snapshot.provider_location)
snap_path = self.local_path(snapshot)
self._delete_file(snap_path)
def create_cloned_volume(self, volume, src_vref):
"""Create a clone of the volume."""
LOG.debug('VeritasNFSDriver create_cloned_volume called '
'volume_id = %(volume)s and src_vol_id = %(src_vol_id)s',
{'volume': volume.id, 'src_vol_id': src_vref.id})
src_vol_name = src_vref.name
vol_size = volume.size
src_vol_size = src_vref.size
self._do_clone_volume(src_vref, src_vol_name, volume)
volume.provider_location = src_vref.provider_location
if vol_size != src_vol_size:
try:
self.extend_volume(volume, vol_size)
except exception.ExtendVolumeError as ex:
with excutils.save_and_reraise_exception():
LOG.error('Failed to extend Volume: %s', ex.msg)
path = self.local_path(volume)
self._delete_file(path)
return {'provider_location': volume.provider_location}
def _get_local_volume_path(self, provider_loc, vol_name):
mnt_path = self._get_mount_point_for_share(provider_loc)
vol_path = os.path.join(mnt_path, vol_name)
return vol_path
def _do_clone_volume(self, src_vol, src_vol_name, tgt_vol):
cnfs_share = src_vol.provider_location
tgt_vol_name = tgt_vol.name
tgt_vol_path = self._get_local_volume_path(cnfs_share, tgt_vol_name)
src_vol_path = self._get_local_volume_path(cnfs_share, src_vol_name)
tgt_vol_path_spl = tgt_vol_path + "::snap:vxfs:"
cinder.privsep.path.symlink(src_vol_path, tgt_vol_path_spl)
LOG.debug("VeritasNFSDriver: do_clone_volume %(src_vol_path)s "
"%(tgt_vol_path)s %(tgt_vol_path_spl)s",
{'src_vol_path': src_vol_path,
'tgt_vol_path_spl': tgt_vol_path_spl,
'tgt_vol_path': tgt_vol_path})
if not os.path.exists(tgt_vol_path):
self._execute('rm', '-f', tgt_vol_path_spl, run_as_root=True)
msg = _("Filesnap over NFS is not supported, "
"removing the ::snap:vxfs: file")
LOG.error(msg)
raise exception.NfsException(msg)
def extend_volume(self, volume, size):
"""Extend the volume to new size"""
path = self.local_path(volume)
self._execute('truncate', '-s', '%sG' % size, path, run_as_root=True)
LOG.debug("VeritasNFSDriver: extend_volume volume_id = %s", volume.id)
def _update_volume_stats(self):
super(VeritasCNFSDriver, self)._update_volume_stats()
backend_name = self.configuration.safe_get('volume_backend_name')
res_percentage = self.configuration.safe_get('reserved_percentage')
self._stats["volume_backend_name"] = backend_name or 'VeritasCNFS'
self._stats["vendor_name"] = 'Veritas'
self._stats["reserved_percentage"] = res_percentage or 0
self._stats["driver_version"] = self.VERSION
self._stats["storage_protocol"] = self.DRIVER_VOLUME_TYPE