deleted brick

This commit is contained in:
Yulia Portnova 2013-09-05 10:20:33 +03:00
parent 3daf82a5d9
commit 65d8167a0f
5 changed files with 0 additions and 884 deletions

@ -1,16 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# 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.

@ -1,16 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# 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.

@ -1,468 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# 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.
"""
Helper code for the iSCSI volume driver.
"""
import os
import re
from oslo.config import cfg
from manila import exception
from manila import flags
from manila.openstack.common import log as logging
from manila import utils
from manila.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
iscsi_helper_opt = [cfg.StrOpt('iscsi_helper',
default='tgtadm',
help='iscsi target user-land tool to use'),
cfg.StrOpt('volumes_dir',
default='$state_path/volumes',
help='Volume configuration file storage '
'directory'),
cfg.StrOpt('iet_conf',
default='/etc/iet/ietd.conf',
help='IET configuration file'),
cfg.StrOpt('lio_initiator_iqns',
default='',
help=('Comma-separatd list of initiator IQNs '
'allowed to connect to the '
'iSCSI target. (From Nova compute nodes.)'
)
),
cfg.StrOpt('iscsi_iotype',
default='fileio',
help=('Sets the behavior of the iSCSI target '
'to either perform blockio or fileio '
'optionally, auto can be set and Manila '
'will autodetect type of backing device')
)
]
FLAGS = flags.FLAGS
FLAGS.register_opts(iscsi_helper_opt)
FLAGS.import_opt('volume_name_template', 'manila.db')
class TargetAdmin(object):
"""iSCSI target administration.
Base class for iSCSI target admin helpers.
"""
def __init__(self, cmd, execute):
self._cmd = cmd
self.set_execute(execute)
def set_execute(self, execute):
"""Set the function to be used to execute commands."""
self._execute = execute
def _run(self, *args, **kwargs):
self._execute(self._cmd, *args, run_as_root=True, **kwargs)
def create_iscsi_target(self, name, tid, lun, path,
chap_auth=None, **kwargs):
"""Create a iSCSI target and logical unit"""
raise NotImplementedError()
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
"""Remove a iSCSI target and logical unit"""
raise NotImplementedError()
def _new_target(self, name, tid, **kwargs):
"""Create a new iSCSI target."""
raise NotImplementedError()
def _delete_target(self, tid, **kwargs):
"""Delete a target."""
raise NotImplementedError()
def show_target(self, tid, iqn=None, **kwargs):
"""Query the given target ID."""
raise NotImplementedError()
def _new_logicalunit(self, tid, lun, path, **kwargs):
"""Create a new LUN on a target using the supplied path."""
raise NotImplementedError()
def _delete_logicalunit(self, tid, lun, **kwargs):
"""Delete a logical unit from a target."""
raise NotImplementedError()
class TgtAdm(TargetAdmin):
"""iSCSI target administration using tgtadm."""
def __init__(self, execute=utils.execute):
super(TgtAdm, self).__init__('tgtadm', execute)
def _get_target(self, iqn):
(out, err) = self._execute('tgt-admin', '--show', run_as_root=True)
lines = out.split('\n')
for line in lines:
if iqn in line:
parsed = line.split()
tid = parsed[1]
return tid[:-1]
return None
def create_iscsi_target(self, name, tid, lun, path,
chap_auth=None, **kwargs):
# Note(jdg) tid and lun aren't used by TgtAdm but remain for
# compatibility
utils.ensure_tree(FLAGS.volumes_dir)
vol_id = name.split(':')[1]
if chap_auth is None:
volume_conf = """
<target %s>
backing-store %s
</target>
""" % (name, path)
else:
volume_conf = """
<target %s>
backing-store %s
%s
</target>
""" % (name, path, chap_auth)
LOG.info(_('Creating iscsi_target for: %s') % vol_id)
volumes_dir = FLAGS.volumes_dir
volume_path = os.path.join(volumes_dir, vol_id)
f = open(volume_path, 'w+')
f.write(volume_conf)
f.close()
old_persist_file = None
old_name = kwargs.get('old_name', None)
if old_name is not None:
old_persist_file = os.path.join(volumes_dir, old_name)
try:
(out, err) = self._execute('tgt-admin',
'--update',
name,
run_as_root=True)
except exception.ProcessExecutionError, e:
LOG.error(_("Failed to create iscsi target for volume "
"id:%(vol_id)s.") % locals())
#Don't forget to remove the persistent file we created
os.unlink(volume_path)
raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
iqn = '%s%s' % (FLAGS.iscsi_target_prefix, vol_id)
tid = self._get_target(iqn)
if tid is None:
LOG.error(_("Failed to create iscsi target for volume "
"id:%(vol_id)s. Please ensure your tgtd config file "
"contains 'include %(volumes_dir)s/*'") % locals())
raise exception.NotFound()
if old_persist_file is not None and os.path.exists(old_persist_file):
os.unlink(old_persist_file)
return tid
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
LOG.info(_('Removing iscsi_target for: %s') % vol_id)
vol_uuid_file = FLAGS.volume_name_template % vol_id
volume_path = os.path.join(FLAGS.volumes_dir, vol_uuid_file)
if os.path.isfile(volume_path):
iqn = '%s%s' % (FLAGS.iscsi_target_prefix,
vol_uuid_file)
else:
raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
try:
# NOTE(vish): --force is a workaround for bug:
# https://bugs.launchpad.net/manila/+bug/1159948
self._execute('tgt-admin',
'--force',
'--delete',
iqn,
run_as_root=True)
except exception.ProcessExecutionError, e:
LOG.error(_("Failed to remove iscsi target for volume "
"id:%(vol_id)s.") % locals())
raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
os.unlink(volume_path)
def show_target(self, tid, iqn=None, **kwargs):
if iqn is None:
raise exception.InvalidParameterValue(
err=_('valid iqn needed for show_target'))
tid = self._get_target(iqn)
if tid is None:
raise exception.NotFound()
class IetAdm(TargetAdmin):
"""iSCSI target administration using ietadm."""
def __init__(self, execute=utils.execute):
super(IetAdm, self).__init__('ietadm', execute)
def _iotype(self, path):
if FLAGS.iscsi_iotype == 'auto':
return 'blockio' if volume_utils.is_block(path) else 'fileio'
else:
return FLAGS.iscsi_iotype
def create_iscsi_target(self, name, tid, lun, path,
chap_auth=None, **kwargs):
# NOTE (jdg): Address bug: 1175207
kwargs.pop('old_name', None)
self._new_target(name, tid, **kwargs)
self._new_logicalunit(tid, lun, path, **kwargs)
if chap_auth is not None:
(type, username, password) = chap_auth.split()
self._new_auth(tid, type, username, password, **kwargs)
conf_file = FLAGS.iet_conf
if os.path.exists(conf_file):
try:
volume_conf = """
Target %s
%s
Lun 0 Path=%s,Type=%s
""" % (name, chap_auth, path, self._iotype(path))
with utils.temporary_chown(conf_file):
f = open(conf_file, 'a+')
f.write(volume_conf)
f.close()
except exception.ProcessExecutionError, e:
vol_id = name.split(':')[1]
LOG.error(_("Failed to create iscsi target for volume "
"id:%(vol_id)s.") % locals())
raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
return tid
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
LOG.info(_('Removing iscsi_target for volume: %s') % vol_id)
self._delete_logicalunit(tid, lun, **kwargs)
self._delete_target(tid, **kwargs)
vol_uuid_file = FLAGS.volume_name_template % vol_id
conf_file = FLAGS.iet_conf
if os.path.exists(conf_file):
with utils.temporary_chown(conf_file):
try:
iet_conf_text = open(conf_file, 'r+')
full_txt = iet_conf_text.readlines()
new_iet_conf_txt = []
count = 0
for line in full_txt:
if count > 0:
count -= 1
continue
elif re.search(vol_uuid_file, line):
count = 2
continue
else:
new_iet_conf_txt.append(line)
iet_conf_text.seek(0)
iet_conf_text.truncate(0)
iet_conf_text.writelines(new_iet_conf_txt)
finally:
iet_conf_text.close()
def _new_target(self, name, tid, **kwargs):
self._run('--op', 'new',
'--tid=%s' % tid,
'--params', 'Name=%s' % name,
**kwargs)
def _delete_target(self, tid, **kwargs):
self._run('--op', 'delete',
'--tid=%s' % tid,
**kwargs)
def show_target(self, tid, iqn=None, **kwargs):
self._run('--op', 'show',
'--tid=%s' % tid,
**kwargs)
def _new_logicalunit(self, tid, lun, path, **kwargs):
self._run('--op', 'new',
'--tid=%s' % tid,
'--lun=%d' % lun,
'--params', 'Path=%s,Type=%s' % (path, self._iotype(path)),
**kwargs)
def _delete_logicalunit(self, tid, lun, **kwargs):
self._run('--op', 'delete',
'--tid=%s' % tid,
'--lun=%d' % lun,
**kwargs)
def _new_auth(self, tid, type, username, password, **kwargs):
self._run('--op', 'new',
'--tid=%s' % tid,
'--user',
'--params=%s=%s,Password=%s' % (type, username, password),
**kwargs)
class FakeIscsiHelper(object):
def __init__(self):
self.tid = 1
def set_execute(self, execute):
self._execute = execute
def create_iscsi_target(self, *args, **kwargs):
self.tid += 1
return self.tid
class LioAdm(TargetAdmin):
"""iSCSI target administration for LIO using python-rtslib."""
def __init__(self, execute=utils.execute):
super(LioAdm, self).__init__('rtstool', execute)
try:
self._execute('rtstool', 'verify')
except (OSError, exception.ProcessExecutionError):
LOG.error(_('rtstool is not installed correctly'))
raise
def _get_target(self, iqn):
(out, err) = self._execute('rtstool',
'get-targets',
run_as_root=True)
lines = out.split('\n')
for line in lines:
if iqn in line:
return line
return None
def create_iscsi_target(self, name, tid, lun, path,
chap_auth=None, **kwargs):
# tid and lun are not used
vol_id = name.split(':')[1]
LOG.info(_('Creating iscsi_target for volume: %s') % vol_id)
# rtstool requires chap_auth, but unit tests don't provide it
chap_auth_userid = 'test_id'
chap_auth_password = 'test_pass'
if chap_auth != None:
(chap_auth_userid, chap_auth_password) = chap_auth.split(' ')[1:]
extra_args = []
if FLAGS.lio_initiator_iqns:
extra_args.append(FLAGS.lio_initiator_iqns)
try:
command_args = ['rtstool',
'create',
path,
name,
chap_auth_userid,
chap_auth_password]
if extra_args != []:
command_args += extra_args
self._execute(*command_args, run_as_root=True)
except exception.ProcessExecutionError as e:
LOG.error(_("Failed to create iscsi target for volume "
"id:%(vol_id)s.") % locals())
LOG.error("%s" % str(e))
raise exception.ISCSITargetCreateFailed(volume_id=vol_id)
iqn = '%s%s' % (FLAGS.iscsi_target_prefix, vol_id)
tid = self._get_target(iqn)
if tid is None:
LOG.error(_("Failed to create iscsi target for volume "
"id:%(vol_id)s.") % locals())
raise exception.NotFound()
return tid
def remove_iscsi_target(self, tid, lun, vol_id, **kwargs):
LOG.info(_('Removing iscsi_target: %s') % vol_id)
vol_uuid_name = 'volume-%s' % vol_id
iqn = '%s%s' % (FLAGS.iscsi_target_prefix, vol_uuid_name)
try:
self._execute('rtstool',
'delete',
iqn,
run_as_root=True)
except exception.ProcessExecutionError as e:
LOG.error(_("Failed to remove iscsi target for volume "
"id:%(vol_id)s.") % locals())
LOG.error("%s" % str(e))
raise exception.ISCSITargetRemoveFailed(volume_id=vol_id)
def show_target(self, tid, iqn=None, **kwargs):
if iqn is None:
raise exception.InvalidParameterValue(
err=_('valid iqn needed for show_target'))
tid = self._get_target(iqn)
if tid is None:
raise exception.NotFound()
def initialize_connection(self, volume, connector):
volume_iqn = volume['provider_location'].split(' ')[1]
(auth_method, auth_user, auth_pass) = \
volume['provider_auth'].split(' ', 3)
# Add initiator iqns to target ACL
try:
self._execute('rtstool', 'add-initiator',
volume_iqn,
auth_user,
auth_pass,
connector['initiator'],
run_as_root=True)
except exception.ProcessExecutionError as e:
LOG.error(_("Failed to add initiator iqn %s to target") %
connector['initiator'])
raise exception.ISCSITargetAttachFailed(volume_id=volume['id'])
def get_target_admin():
if FLAGS.iscsi_helper == 'tgtadm':
return TgtAdm()
elif FLAGS.iscsi_helper == 'fake':
return FakeIscsiHelper()
elif FLAGS.iscsi_helper == 'lioadm':
return LioAdm()
else:
return IetAdm()

@ -1,16 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# 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.

@ -1,368 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# 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.
"""
LVM class for performing LVM operations.
"""
import math
from itertools import izip
from manila.openstack.common.gettextutils import _
from manila.openstack.common import log as logging
from manila.openstack.common import processutils as putils
LOG = logging.getLogger(__name__)
class VolumeGroupNotFound(Exception):
def __init__(self, vg_name):
message = (_('Unable to find Volume Group: %s') % vg_name)
super(VolumeGroupNotFound, self).__init__(message)
class VolumeGroupCreationFailed(Exception):
def __init__(self, vg_name):
message = (_('Failed to create Volume Group: %s') % vg_name)
super(VolumeGroupCreationFailed, self).__init__(message)
class LVM(object):
"""LVM object to enable various LVM related operations."""
def __init__(self, vg_name, create_vg=False,
physical_volumes=None):
"""Initialize the LVM object.
The LVM object is based on an LVM VolumeGroup, one instantiation
for each VolumeGroup you have/use.
:param vg_name: Name of existing VG or VG to create
:param create_vg: Indicates the VG doesn't exist
and we want to create it
:param physical_volumes: List of PVs to build VG on
"""
self.vg_name = vg_name
self.pv_list = []
self.lv_list = []
self.vg_size = 0
self.vg_available_space = 0
self.vg_lv_count = 0
self.vg_uuid = None
if create_vg and physical_volumes is not None:
self.pv_list = physical_volumes
try:
self._create_vg(physical_volumes)
except putils.ProcessExecutionError as err:
LOG.exception(_('Error creating Volume Group'))
LOG.error(_('Cmd :%s') % err.cmd)
LOG.error(_('StdOut :%s') % err.stdout)
LOG.error(_('StdErr :%s') % err.stderr)
raise VolumeGroupCreationFailed(vg_name=self.vg_name)
if self._vg_exists() is False:
LOG.error(_('Unable to locate Volume Group %s') % vg_name)
raise VolumeGroupNotFound(vg_name=vg_name)
def _size_str(self, size_in_g):
if '.00' in size_in_g:
size_in_g = size_in_g.replace('.00', '')
if int(size_in_g) == 0:
return '100M'
return '%sG' % size_in_g
def _vg_exists(self):
"""Simple check to see if VG exists.
:returns: True if vg specified in object exists, else False
"""
exists = False
cmd = ['vgs', '--noheadings', '-o', 'name']
(out, err) = putils.execute(*cmd, root_helper='sudo', run_as_root=True)
if out is not None:
volume_groups = out.split()
if self.vg_name in volume_groups:
exists = True
return exists
def _create_vg(self, pv_list):
cmd = ['vgcreate', self.vg_name, ','.join(pv_list)]
putils.execute(*cmd, root_helper='sudo', run_as_root=True)
def _get_vg_uuid(self):
(out, err) = putils.execute('vgs', '--noheadings',
'-o uuid', self.vg_name)
if out is not None:
return out.split()
else:
return []
@staticmethod
def supports_thin_provisioning():
"""Static method to check for thin LVM support on a system.
:returns: True if supported, False otherwise
"""
cmd = ['vgs', '--version']
(out, err) = putils.execute(*cmd, root_helper='sudo', run_as_root=True)
lines = out.split('\n')
for line in lines:
if 'LVM version' in line:
version_list = line.split()
version = version_list[2]
if '(2)' in version:
version = version.replace('(2)', '')
version_tuple = tuple(map(int, version.split('.')))
if version_tuple >= (2, 2, 95):
return True
return False
@staticmethod
def get_all_volumes(vg_name=None):
"""Static method to get all LV's on a system.
:param vg_name: optional, gathers info for only the specified VG
:returns: List of Dictionaries with LV info
"""
cmd = ['lvs', '--noheadings', '-o', 'vg_name,name,size']
if vg_name is not None:
cmd += [vg_name]
(out, err) = putils.execute(*cmd, root_helper='sudo', run_as_root=True)
lv_list = []
if out is not None:
volumes = out.split()
for vg, name, size in izip(*[iter(volumes)] * 3):
lv_list.append({"vg": vg, "name": name, "size": size})
return lv_list
def get_volumes(self):
"""Get all LV's associated with this instantiation (VG).
:returns: List of Dictionaries with LV info
"""
self.lv_list = self.get_all_volumes(self.vg_name)
return self.lv_list
def get_volume(self, name):
"""Get reference object of volume specified by name.
:returns: dict representation of Logical Volume if exists
"""
ref_list = self.get_volumes()
for r in ref_list:
if r['name'] == name:
return r
@staticmethod
def get_all_physical_volumes(vg_name=None):
"""Static method to get all PVs on a system.
:param vg_name: optional, gathers info for only the specified VG
:returns: List of Dictionaries with PV info
"""
cmd = ['pvs', '--noheadings',
'-o', 'vg_name,name,size,free',
'--separator', ':']
if vg_name is not None:
cmd += [vg_name]
(out, err) = putils.execute(*cmd, root_helper='sudo', run_as_root=True)
pv_list = []
if out is not None:
pvs = out.split()
for pv in pvs:
fields = pv.split(':')
pv_list.append({'vg': fields[0],
'name': fields[1],
'size': fields[2],
'available': fields[3]})
return pv_list
def get_physical_volumes(self):
"""Get all PVs associated with this instantiation (VG).
:returns: List of Dictionaries with PV info
"""
self.pv_list = self.get_all_physical_volumes(self.vg_name)
return self.pv_list
@staticmethod
def get_all_volume_groups(vg_name=None):
"""Static method to get all VGs on a system.
:param vg_name: optional, gathers info for only the specified VG
:returns: List of Dictionaries with VG info
"""
cmd = ['vgs', '--noheadings',
'-o', 'name,size,free,lv_count,uuid',
'--separator', ':']
if vg_name is not None:
cmd += [vg_name]
(out, err) = putils.execute(*cmd, root_helper='sudo', run_as_root=True)
vg_list = []
if out is not None:
vgs = out.split()
for vg in vgs:
fields = vg.split(':')
vg_list.append({'name': fields[0],
'size': fields[1],
'available': fields[2],
'lv_count': fields[3],
'uuid': fields[4]})
return vg_list
def update_volume_group_info(self):
"""Update VG info for this instantiation.
Used to update member fields of object and
provide a dict of info for caller.
:returns: Dictionaries of VG info
"""
vg_list = self.get_all_volume_groups(self.vg_name)
if len(vg_list) != 1:
LOG.error(_('Unable to find VG: %s') % self.vg_name)
raise VolumeGroupNotFound(vg_name=self.vg_name)
self.vg_size = vg_list[0]['size']
self.vg_available_space = vg_list[0]['available']
self.vg_lv_count = vg_list[0]['lv_count']
self.vg_uuid = vg_list[0]['uuid']
return vg_list[0]
def create_thin_pool(self, name=None, size_str=0):
"""Creates a thin provisioning pool for this VG.
:param name: Name to use for pool, default is "<vg-name>-pool"
:param size_str: Size to allocate for pool, default is entire VG
"""
if not self.supports_thin_provisioning():
LOG.error(_('Requested to setup thin provisioning, '
'however current LVM version does not '
'support it.'))
return None
if name is None:
name = '%s-pool' % self.vg_name
if size_str == 0:
self.update_volume_group_info()
size_str = self.vg_size
self.create_volume(name, size_str, 'thin')
def create_volume(self, name, size_str, lv_type='default', mirror_count=0):
"""Creates a logical volume on the object's VG.
:param name: Name to use when creating Logical Volume
:param size_str: Size to use when creating Logical Volume
:param lv_type: Type of Volume (default or thin)
:param mirror_count: Use LVM mirroring with specified count
"""
size = self._size_str(size_str)
cmd = ['lvcreate', '-n', name, self.vg_name]
if lv_type == 'thin':
cmd += ['-T', '-V', size]
else:
cmd += ['-L', size]
if mirror_count > 0:
cmd += ['-m', mirror_count, '--nosync']
terras = int(size[:-1]) / 1024.0
if terras >= 1.5:
rsize = int(2 ** math.ceil(math.log(terras) / math.log(2)))
# NOTE(vish): Next power of two for region size. See:
# http://red.ht/U2BPOD
cmd += ['-R', str(rsize)]
putils.execute(*cmd,
root_helper='sudo',
run_as_root=True)
def create_lv_snapshot(self, name, source_lv_name, lv_type='default'):
"""Creates a snapshot of a logical volume.
:param name: Name to assign to new snapshot
:param source_lv_name: Name of Logical Volume to snapshot
:param lv_type: Type of LV (default or thin)
"""
source_lvref = self.get_volume(source_lv_name)
if source_lvref is None:
LOG.error(_("Unable to find LV: %s") % source_lv_name)
return False
cmd = ['lvcreate', '--name', name,
'--snapshot', '%s/%s' % (self.vg_name, source_lv_name)]
if lv_type != 'thin':
size = source_lvref['size']
cmd += ['-L', size]
putils.execute(*cmd,
root_helper='sudo',
run_as_root=True)
def delete(self, name):
"""Delete logical volume or snapshot.
:param name: Name of LV to delete
"""
putils.execute('lvremove',
'-f',
'%s/%s' % (self.vg_name, name),
root_helper='sudo', run_as_root=True)
def revert(self, snapshot_name):
"""Revert an LV from snapshot.
:param snapshot_name: Name of snapshot to revert
"""
putils.execute('lvconvert', '--merge',
snapshot_name, root_helper='sudo',
run_as_root=True)