cinder/cinder/volume/drivers/hitachi/hbsd_common.py

825 lines
31 KiB
Python

# Copyright (C) 2014, Hitachi, Ltd.
#
# 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.
"""
Common class for Hitachi storage drivers.
"""
import re
import threading
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
import six
from cinder import exception
from cinder.i18n import _LE, _LI, _LW
from cinder import utils
from cinder.volume.drivers.hitachi import hbsd_basiclib as basic_lib
from cinder.volume.drivers.hitachi import hbsd_horcm as horcm
from cinder.volume.drivers.hitachi import hbsd_snm2 as snm2
from cinder.volume import utils as volume_utils
"""
Version history:
1.0.0 - Initial driver
1.1.0 - Add manage_existing/manage_existing_get_size/unmanage methods
"""
VERSION = '1.1.0'
PARAM_RANGE = {
'hitachi_copy_check_interval': {'min': 1, 'max': 600},
'hitachi_async_copy_check_interval': {'min': 1, 'max': 600},
'hitachi_copy_speed': {'min': 1, 'max': 15},
}
DEFAULT_LDEV_RANGE = [0, 65535]
COPY_METHOD = ('FULL', 'THIN')
VALID_DP_VOLUME_STATUS = ['available', 'in-use']
VALID_V_VOLUME_STATUS = ['available']
SYSTEM_LOCK_FILE = basic_lib.LOCK_DIR + 'system'
SERVICE_LOCK_PATH_BASE = basic_lib.LOCK_DIR + 'service_'
STORAGE_LOCK_PATH_BASE = basic_lib.LOCK_DIR + 'storage_'
LOG = logging.getLogger(__name__)
volume_opts = [
cfg.StrOpt('hitachi_serial_number',
help='Serial number of storage system'),
cfg.StrOpt('hitachi_unit_name',
help='Name of an array unit'),
cfg.IntOpt('hitachi_pool_id',
help='Pool ID of storage system'),
cfg.IntOpt('hitachi_thin_pool_id',
help='Thin pool ID of storage system'),
cfg.StrOpt('hitachi_ldev_range',
help='Range of logical device of storage system'),
cfg.StrOpt('hitachi_default_copy_method',
default='FULL',
help='Default copy method of storage system'),
cfg.IntOpt('hitachi_copy_speed',
default=3,
help='Copy speed of storage system'),
cfg.IntOpt('hitachi_copy_check_interval',
default=3,
help='Interval to check copy'),
cfg.IntOpt('hitachi_async_copy_check_interval',
default=10,
help='Interval to check copy asynchronously'),
cfg.StrOpt('hitachi_target_ports',
help='Control port names for HostGroup or iSCSI Target'),
cfg.StrOpt('hitachi_group_range',
help='Range of group number'),
cfg.BoolOpt('hitachi_group_request',
default=False,
secret=True,
help='Request for creating HostGroup or iSCSI Target'),
]
CONF = cfg.CONF
CONF.register_opts(volume_opts)
class TryLock(object):
def __init__(self):
self.lock = threading.RLock()
self.desc = None
def set_desc(self, description):
self.desc = description
def __enter__(self):
if not self.lock.acquire(False):
msg = basic_lib.output_err(660, desc=self.desc)
raise exception.HBSDError(message=msg)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.lock.release()
class HBSDCommon(object):
def __init__(self, conf, parent, context, db):
self.configuration = conf
self.generated_from = parent
self.context = context
self.db = db
self.system_lock_file = SYSTEM_LOCK_FILE
self.service_lock_file = '%s%s' % (SERVICE_LOCK_PATH_BASE,
conf.config_group)
if conf.hitachi_serial_number:
self.storage_lock_file = '%s%s' % (STORAGE_LOCK_PATH_BASE,
six.text_type(
conf.hitachi_serial_number))
elif conf.hitachi_unit_name:
self.storage_lock_file = '%s%s' % (STORAGE_LOCK_PATH_BASE,
six.text_type(
conf.hitachi_unit_name))
self.storage_obj_lock = threading.Lock()
self.volinfo_lock = threading.Lock()
self.volume_info = {}
self.output_first = True
def get_volume(self, volume_id):
return self.db.volume_get(self.context, volume_id)
def get_volume_metadata(self, volume_id):
return self.db.volume_metadata_get(self.context, volume_id)
def get_snapshot_metadata(self, snapshot_id):
return self.db.snapshot_metadata_get(self.context, snapshot_id)
def _update_volume_metadata(self, volume_id, volume_metadata):
self.db.volume_metadata_update(self.context, volume_id,
volume_metadata, False)
def get_ldev(self, obj):
if not obj:
return None
ldev = obj.get('provider_location')
if not ldev or not ldev.isdigit():
return None
else:
return int(ldev)
def get_value(self, obj, name, key):
if not obj:
return None
if obj.get(name):
if isinstance(obj[name], dict):
return obj[name].get(key)
else:
for i in obj[name]:
if i['key'] == key:
return i['value']
return None
def get_is_vvol(self, obj, name):
return self.get_value(obj, name, 'type') == 'V-VOL'
def get_volume_is_vvol(self, volume):
return self.get_is_vvol(volume, 'volume_metadata')
def get_snapshot_is_vvol(self, snapshot):
return self.get_is_vvol(snapshot, 'metadata')
def get_copy_method(self, volume):
method = self.get_value(volume, 'volume_metadata', 'copy_method')
if method:
if method not in COPY_METHOD:
msg = basic_lib.output_err(602, meta='copy_method')
raise exception.HBSDError(message=msg)
elif (method == 'THIN'
and self.configuration.hitachi_thin_pool_id is None):
msg = basic_lib.output_err(601, param='hitachi_thin_pool_id')
raise exception.HBSDError(message=msg)
else:
method = self.configuration.hitachi_default_copy_method
return method
def _string2int(self, num):
if not num:
return None
if num.isdigit():
return int(num, 10)
if not re.match(r'\w\w:\w\w:\w\w', num):
return None
try:
num = int(num.replace(':', ''), 16)
except ValueError:
return None
return num
def _range2list(self, conf, param):
str = getattr(conf, param)
lists = str.split('-')
if len(lists) != 2:
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
first_type = None
for i in range(len(lists)):
if lists[i].isdigit():
lists[i] = int(lists[i], 10)
if first_type == 'hex':
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
first_type = 'dig'
else:
if (first_type == 'dig'
or not re.match('\w\w:\w\w:\w\w', lists[i])):
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
try:
lists[i] = int(lists[i].replace(':', ''), 16)
first_type = 'hex'
except Exception:
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
if lists[0] > lists[1]:
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
return lists
def output_param_to_log(self, storage_protocol):
essential_inherited_param = ['volume_backend_name', 'volume_driver']
conf = self.configuration
LOG.info(basic_lib.set_msg(1, config_group=conf.config_group))
version = self.command.get_comm_version()
if conf.hitachi_unit_name:
prefix = 'HSNM2 version'
else:
prefix = 'RAID Manager version'
LOG.info(_LI('\t%(prefix)-35s : %(version)s'),
{'prefix': prefix, 'version': version})
for param in essential_inherited_param:
value = conf.safe_get(param)
LOG.info(_LI('\t%(param)-35s : %(value)s'),
{'param': param, 'value': value})
for opt in volume_opts:
if not opt.secret:
value = getattr(conf, opt.name)
LOG.info(_LI('\t%(name)-35s : %(value)s'),
{'name': opt.name, 'value': value})
if storage_protocol == 'iSCSI':
value = getattr(conf, 'hitachi_group_request')
LOG.info(_LI('\t%(request)-35s : %(value)s'),
{'request': 'hitachi_group_request', 'value': value})
def check_param(self):
conf = self.configuration
if conf.hitachi_unit_name and conf.hitachi_serial_number:
msg = basic_lib.output_err(604)
raise exception.HBSDError(message=msg)
if not conf.hitachi_unit_name and not conf.hitachi_serial_number:
msg = basic_lib.output_err(605)
raise exception.HBSDError(message=msg)
if conf.hitachi_pool_id is None:
msg = basic_lib.output_err(601, param='hitachi_pool_id')
raise exception.HBSDError(message=msg)
for param in PARAM_RANGE.keys():
_value = getattr(conf, param)
if (_value and
(not PARAM_RANGE[param]['min'] <= _value <=
PARAM_RANGE[param]['max'])):
msg = basic_lib.output_err(601, param=param)
raise exception.HBSDError(message=msg)
if conf.hitachi_default_copy_method not in COPY_METHOD:
msg = basic_lib.output_err(601,
param='hitachi_default_copy_method')
raise exception.HBSDError(message=msg)
if (conf.hitachi_default_copy_method == 'THIN'
and conf.hitachi_thin_pool_id is None):
msg = basic_lib.output_err(601, param='hitachi_thin_pool_id')
raise exception.HBSDError(message=msg)
for param in ('hitachi_ldev_range', 'hitachi_group_range'):
if not getattr(conf, param):
continue
else:
_value = self._range2list(conf, param)
setattr(conf, param, _value)
if conf.hitachi_target_ports:
conf.hitachi_target_ports = conf.hitachi_target_ports.split(',')
for opt in volume_opts:
getattr(conf, opt.name)
if conf.hitachi_unit_name:
self.command = snm2.HBSDSNM2(conf)
else:
conf.append_config_values(horcm.volume_opts)
self.command = horcm.HBSDHORCM(conf)
self.command.check_param()
self.pair_flock = self.command.set_pair_flock()
self.horcmgr_flock = self.command.set_horcmgr_flock()
def create_lock_file(self):
basic_lib.create_empty_file(self.system_lock_file)
basic_lib.create_empty_file(self.service_lock_file)
basic_lib.create_empty_file(self.storage_lock_file)
self.command.create_lock_file()
def _add_ldev(self, volume_num, capacity, pool_id, is_vvol):
self.command.comm_add_ldev(pool_id, volume_num, capacity, is_vvol)
def _get_unused_volume_num(self, ldev_range):
return self.command.get_unused_ldev(ldev_range)
def add_volinfo(self, ldev, id=None, type='volume'):
with self.volinfo_lock:
if ldev not in self.volume_info:
self.init_volinfo(self.volume_info, ldev)
if id:
desc = '%s %s' % (type, id)
self.volume_info[ldev]['in_use'].set_desc(desc)
def delete_pair(self, ldev, all_split=True, is_vvol=None):
paired_info = self.command.get_paired_info(ldev)
LOG.debug('paired_info: %s', paired_info)
pvol = paired_info['pvol']
svols = paired_info['svol']
driver = self.generated_from
restart = False
svol_list = []
try:
if pvol is None:
return
elif pvol == ldev:
for svol in svols[:]:
if svol['is_vvol'] or svol['status'] != basic_lib.PSUS:
continue
self.command.delete_pair(pvol, svol['lun'], False)
restart = True
driver.pair_terminate_connection(svol['lun'])
svols.remove(svol)
if all_split and svols:
svol_list.append(six.text_type(svols[0]['lun']))
for svol in svols[1:]:
svol_list.append(', %d' % svol['lun'])
msg = basic_lib.output_err(616, pvol=pvol,
svol=''.join(svol_list))
raise exception.HBSDBusy(message=msg)
if not svols:
driver.pair_terminate_connection(pvol)
else:
self.add_volinfo(pvol)
if not self.volume_info[pvol]['in_use'].lock.acquire(False):
desc = self.volume_info[pvol]['in_use'].desc
msg = basic_lib.output_err(660, desc=desc)
raise exception.HBSDBusy(message=msg)
try:
paired_info = self.command.get_paired_info(ldev)
if paired_info['pvol'] is None:
return
svol = paired_info['svol'][0]
if svol['status'] != basic_lib.PSUS:
msg = basic_lib.output_err(616, pvol=pvol, svol=ldev)
raise exception.HBSDBusy(message=msg)
self.command.delete_pair(pvol, ldev, svol['is_vvol'])
if not svol['is_vvol']:
restart = True
driver.pair_terminate_connection(ldev)
paired_info = self.command.get_paired_info(pvol)
if paired_info['pvol'] is None:
driver.pair_terminate_connection(pvol)
finally:
self.volume_info[pvol]['in_use'].lock.release()
except Exception:
with excutils.save_and_reraise_exception():
if restart:
try:
self.command.restart_pair_horcm()
except Exception as e:
LOG.warning(_LW('Failed to restart horcm: %s'), e)
else:
if (all_split or is_vvol) and restart:
try:
self.command.restart_pair_horcm()
except Exception as e:
LOG.warning(_LW('Failed to restart horcm: %s'), e)
def copy_async_data(self, pvol, svol, is_vvol):
path_list = []
driver = self.generated_from
try:
with self.pair_flock:
self.delete_pair(pvol, all_split=False, is_vvol=is_vvol)
paired_info = self.command.get_paired_info(pvol)
if paired_info['pvol'] is None:
driver.pair_initialize_connection(pvol)
path_list.append(pvol)
driver.pair_initialize_connection(svol)
path_list.append(svol)
self.command.comm_create_pair(pvol, svol, is_vvol)
except Exception:
with excutils.save_and_reraise_exception():
for ldev in path_list:
try:
driver.pair_terminate_connection(ldev)
except Exception as ex:
LOG.warning(basic_lib.set_msg(310, ldev=ldev,
reason=ex))
def copy_sync_data(self, src_ldev, dest_ldev, size):
src_vol = {'provider_location': six.text_type(src_ldev),
'id': 'src_vol'}
dest_vol = {'provider_location': six.text_type(dest_ldev),
'id': 'dest_vol'}
properties = utils.brick_get_connector_properties()
driver = self.generated_from
src_info = None
dest_info = None
try:
dest_info = driver._attach_volume(self.context, dest_vol,
properties)
src_info = driver._attach_volume(self.context, src_vol,
properties)
volume_utils.copy_volume(src_info['device']['path'],
dest_info['device']['path'], size * 1024,
self.configuration.volume_dd_blocksize)
finally:
if dest_info:
driver._detach_volume(self.context, dest_info,
dest_vol, properties)
if src_info:
driver._detach_volume(self.context, src_info,
src_vol, properties)
self.command.discard_zero_page(dest_ldev)
def copy_data(self, pvol, size, p_is_vvol, method):
type = 'Normal'
is_vvol = method == 'THIN'
svol = self._create_volume(size, is_vvol=is_vvol)
try:
if p_is_vvol:
self.copy_sync_data(pvol, svol, size)
else:
if is_vvol:
type = 'V-VOL'
self.copy_async_data(pvol, svol, is_vvol)
except Exception:
with excutils.save_and_reraise_exception():
try:
self.delete_ldev(svol, is_vvol)
except Exception as ex:
LOG.warning(basic_lib.set_msg(313, ldev=svol,
reason=ex))
return six.text_type(svol), type
def add_lun(self, command, hostgroups, ldev, is_once=False):
lock = basic_lib.get_process_lock(self.storage_lock_file)
with lock:
self.command.comm_add_lun(command, hostgroups, ldev, is_once)
def create_ldev(self, size, ldev_range, pool_id, is_vvol):
LOG.debug('create start (normal)')
for i in basic_lib.DEFAULT_TRY_RANGE:
LOG.debug('Try number: %(tries)s / %(max_tries)s',
{'tries': i + 1,
'max_tries': len(basic_lib.DEFAULT_TRY_RANGE)})
new_ldev = self._get_unused_volume_num(ldev_range)
try:
self._add_ldev(new_ldev, size, pool_id, is_vvol)
except exception.HBSDNotFound:
LOG.warning(basic_lib.set_msg(312, resource='LDEV'))
continue
else:
break
else:
msg = basic_lib.output_err(636)
raise exception.HBSDError(message=msg)
LOG.debug('create end (normal: %s)', new_ldev)
self.init_volinfo(self.volume_info, new_ldev)
return new_ldev
def _create_volume(self, size, is_vvol=False):
ldev_range = self.configuration.hitachi_ldev_range
if not ldev_range:
ldev_range = DEFAULT_LDEV_RANGE
pool_id = self.configuration.hitachi_pool_id
lock = basic_lib.get_process_lock(self.storage_lock_file)
with self.storage_obj_lock, lock:
ldev = self.create_ldev(size, ldev_range, pool_id, is_vvol)
return ldev
def create_volume(self, volume):
volume_metadata = self.get_volume_metadata(volume['id'])
volume_metadata['type'] = 'Normal'
size = volume['size']
ldev = self._create_volume(size)
volume_metadata['ldev'] = six.text_type(ldev)
return {'provider_location': six.text_type(ldev),
'metadata': volume_metadata}
def delete_ldev(self, ldev, is_vvol):
LOG.debug('Call delete_ldev (LDEV: %(ldev)d is_vvol: %(vvol)s)',
{'ldev': ldev, 'vvol': is_vvol})
with self.pair_flock:
self.delete_pair(ldev)
self.command.comm_delete_ldev(ldev, is_vvol)
with self.volinfo_lock:
if ldev in self.volume_info:
self.volume_info.pop(ldev)
LOG.debug('delete_ldev is finished '
'(LDEV: %(ldev)d, is_vvol: %(vvol)s)',
{'ldev': ldev, 'vvol': is_vvol})
def delete_volume(self, volume):
ldev = self.get_ldev(volume)
if ldev is None:
LOG.warning(basic_lib.set_msg(304, method='delete_volume',
id=volume['id']))
return
self.add_volinfo(ldev, volume['id'])
if not self.volume_info[ldev]['in_use'].lock.acquire(False):
desc = self.volume_info[ldev]['in_use'].desc
basic_lib.output_err(660, desc=desc)
raise exception.VolumeIsBusy(volume_name=volume['name'])
try:
is_vvol = self.get_volume_is_vvol(volume)
try:
self.delete_ldev(ldev, is_vvol)
except exception.HBSDNotFound:
with self.volinfo_lock:
if ldev in self.volume_info:
self.volume_info.pop(ldev)
LOG.warning(basic_lib.set_msg(
305, type='volume', id=volume['id']))
except exception.HBSDBusy:
raise exception.VolumeIsBusy(volume_name=volume['name'])
finally:
if ldev in self.volume_info:
self.volume_info[ldev]['in_use'].lock.release()
def check_volume_status(self, volume, is_vvol):
if not is_vvol:
status = VALID_DP_VOLUME_STATUS
else:
status = VALID_V_VOLUME_STATUS
if volume['status'] not in status:
msg = basic_lib.output_err(654, status=volume['status'])
raise exception.HBSDError(message=msg)
def create_snapshot(self, snapshot):
src_ref = self.get_volume(snapshot['volume_id'])
pvol = self.get_ldev(src_ref)
if pvol is None:
msg = basic_lib.output_err(624, type='volume', id=src_ref['id'])
raise exception.HBSDError(message=msg)
self.add_volinfo(pvol, src_ref['id'])
with self.volume_info[pvol]['in_use']:
is_vvol = self.get_volume_is_vvol(src_ref)
self.check_volume_status(src_ref, is_vvol)
size = snapshot['volume_size']
snap_metadata = snapshot.get('metadata')
method = None if is_vvol else self.get_copy_method(src_ref)
svol, type = self.copy_data(pvol, size, is_vvol, method)
if type == 'V-VOL':
snap_metadata['type'] = type
snap_metadata['ldev'] = svol
return {'provider_location': svol,
'metadata': snap_metadata}
def delete_snapshot(self, snapshot):
ldev = self.get_ldev(snapshot)
if ldev is None:
LOG.warning(basic_lib.set_msg(
304, method='delete_snapshot', id=snapshot['id']))
return
self.add_volinfo(ldev, id=snapshot['id'], type='snapshot')
if not self.volume_info[ldev]['in_use'].lock.acquire(False):
desc = self.volume_info[ldev]['in_use'].desc
basic_lib.output_err(660, desc=desc)
raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
try:
is_vvol = self.get_snapshot_is_vvol(snapshot)
try:
self.delete_ldev(ldev, is_vvol)
except exception.HBSDNotFound:
with self.volinfo_lock:
if ldev in self.volume_info:
self.volume_info.pop(ldev)
LOG.warning(basic_lib.set_msg(
305, type='snapshot', id=snapshot['id']))
except exception.HBSDBusy:
raise exception.SnapshotIsBusy(snapshot_name=snapshot['name'])
finally:
if ldev in self.volume_info:
self.volume_info[ldev]['in_use'].lock.release()
def create_cloned_volume(self, volume, src_vref):
pvol = self.get_ldev(src_vref)
if pvol is None:
msg = basic_lib.output_err(624, type='volume', id=src_vref['id'])
raise exception.HBSDError(message=msg)
self.add_volinfo(pvol, src_vref['id'])
with self.volume_info[pvol]['in_use']:
is_vvol = self.get_volume_is_vvol(src_vref)
self.check_volume_status(self.get_volume(src_vref['id']), is_vvol)
size = volume['size']
src_size = src_vref['size']
if size < src_size:
msg = basic_lib.output_err(617, type='volume',
volume_id=volume['id'])
raise exception.HBSDError(message=msg)
metadata = self.get_volume_metadata(volume['id'])
method = None if is_vvol else self.get_copy_method(volume)
svol, type = self.copy_data(pvol, src_size, is_vvol, method)
if size > src_size:
self.extend_volume(volume, size)
metadata['type'] = type
metadata['volume'] = src_vref['id']
metadata['ldev'] = svol
return {'provider_location': svol, 'metadata': metadata}
def create_volume_from_snapshot(self, volume, snapshot):
pvol = self.get_ldev(snapshot)
if pvol is None:
msg = basic_lib.output_err(624, type='snapshot', id=snapshot['id'])
raise exception.HBSDError(message=msg)
self.add_volinfo(pvol, id=snapshot['id'], type='snapshot')
with self.volume_info[pvol]['in_use']:
is_vvol = self.get_snapshot_is_vvol(snapshot)
if snapshot['status'] != 'available':
msg = basic_lib.output_err(655, status=snapshot['status'])
raise exception.HBSDError(message=msg)
size = volume['size']
src_size = snapshot['volume_size']
if size != src_size:
msg = basic_lib.output_err(617, type='snapshot',
volume_id=volume['id'])
raise exception.HBSDError(message=msg)
metadata = self.get_volume_metadata(volume['id'])
method = None if is_vvol else self.get_copy_method(volume)
svol, type = self.copy_data(pvol, size, is_vvol, method)
metadata['type'] = type
metadata['snapshot'] = snapshot['id']
metadata['ldev'] = svol
return {'provider_location': svol, 'metadata': metadata}
def _extend_volume(self, ldev, old_size, new_size):
with self.pair_flock:
self.delete_pair(ldev)
self.command.comm_extend_ldev(ldev, old_size, new_size)
def extend_volume(self, volume, new_size):
pvol = self.get_ldev(volume)
self.add_volinfo(pvol, volume['id'])
with self.volume_info[pvol]['in_use']:
if self.get_volume_is_vvol(volume):
msg = basic_lib.output_err(618, volume_id=volume['id'])
raise exception.HBSDError(message=msg)
self._extend_volume(pvol, volume['size'], new_size)
def output_backend_available_once(self):
if self.output_first:
self.output_first = False
LOG.warning(basic_lib.set_msg(
3, config_group=self.configuration.config_group))
def update_volume_stats(self, storage_protocol):
data = {}
total_gb = None
free_gb = None
data['volume_backend_name'] = self.configuration.safe_get(
'volume_backend_name') or 'HBSD%s' % storage_protocol
data['vendor_name'] = 'Hitachi'
data['driver_version'] = VERSION
data['storage_protocol'] = storage_protocol
try:
total_gb, free_gb = self.command.comm_get_dp_pool(
self.configuration.hitachi_pool_id)
except Exception as ex:
LOG.error(_LE('Failed to update volume status: %s'), ex)
return None
data['total_capacity_gb'] = total_gb
data['free_capacity_gb'] = free_gb
data['reserved_percentage'] = self.configuration.safe_get(
'reserved_percentage')
data['QoS_support'] = False
LOG.debug('Updating volume status (%s)', data)
return data
def init_volinfo(self, vol_info, ldev):
vol_info[ldev] = {'in_use': TryLock(), 'lock': threading.Lock()}
def manage_existing(self, volume, existing_ref):
"""Manage an existing Hitachi storage volume.
existing_ref is a dictionary of the form:
For HUS 100 Family,
{'ldev': <logical device number on storage>,
'unit_name': <storage device name>}
For VSP G1000/VSP/HUS VM,
{'ldev': <logical device number on storage>,
'serial_number': <product number of storage system>}
"""
ldev = self._string2int(existing_ref.get('ldev'))
LOG.info(basic_lib.set_msg(4, volume_id=volume['id'], ldev=ldev))
return {'provider_location': ldev}
def _manage_existing_get_size(self, volume, existing_ref):
"""Return size of volume for manage_existing."""
ldev = self._string2int(existing_ref.get('ldev'))
if ldev is None:
msg = basic_lib.output_err(701)
raise exception.HBSDError(data=msg)
size = self.command.get_ldev_size_in_gigabyte(ldev, existing_ref)
metadata = {'type': basic_lib.NORMAL_VOLUME_TYPE, 'ldev': ldev}
self._update_volume_metadata(volume['id'], metadata)
return size
def manage_existing_get_size(self, volume, existing_ref):
try:
return self._manage_existing_get_size(volume, existing_ref)
except exception.HBSDError as ex:
raise exception.ManageExistingInvalidReference(
existing_ref=existing_ref,
reason=six.text_type(ex))
def _unmanage(self, volume, ldev):
with self.horcmgr_flock:
self.delete_pair(ldev)
with self.volinfo_lock:
if ldev in self.volume_info:
self.volume_info.pop(ldev)
def unmanage(self, volume):
"""Remove the specified volume from Cinder management."""
ldev = self.get_ldev(volume)
if ldev is None:
return
self.add_volinfo(ldev, volume['id'])
if not self.volume_info[ldev]['in_use'].lock.acquire(False):
desc = self.volume_info[ldev]['in_use'].desc
basic_lib.output_err(660, desc=desc)
raise exception.HBSDVolumeIsBusy(volume_name=volume['name'])
is_vvol = self.get_volume_is_vvol(volume)
if is_vvol:
basic_lib.output_err(706, volume_id=volume['id'],
volume_type=basic_lib.NORMAL_VOLUME_TYPE)
raise exception.HBSDVolumeIsBusy(volume_name=volume['name'])
try:
self._unmanage(volume, ldev)
except exception.HBSDBusy:
raise exception.HBSDVolumeIsBusy(volume_name=volume['name'])
else:
LOG.info(basic_lib.set_msg(5, volume_id=volume['id'], ldev=ldev))
finally:
if ldev in self.volume_info:
self.volume_info[ldev]['in_use'].lock.release()