
Our cinder.conf.sample lists all of the options that are defined by drivers in the [DEFAULT] section. Since removal of single-backend config (without enabled_backends) this is misleading as those options are functional only when defined in [<backend_name>] section. This commit aims to move all of the driver options to [backend_defaults] section. Assumption is that this will affect only sample config generation and should not break anything else. Change-Id: Ia4766eb313e15adc92a92875519b22db64e95d65
433 lines
16 KiB
Python
433 lines
16 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.
|
|
"""
|
|
iSCSI Cinder volume driver for Hitachi storage.
|
|
|
|
"""
|
|
|
|
import os
|
|
import threading
|
|
|
|
from oslo_config import cfg
|
|
from oslo_log import log as logging
|
|
from oslo_log import versionutils
|
|
import six
|
|
|
|
from cinder import exception
|
|
from cinder.i18n import _
|
|
from cinder import interface
|
|
from cinder import utils
|
|
from cinder.volume import configuration
|
|
import cinder.volume.driver
|
|
from cinder.volume.drivers.hitachi import hbsd_basiclib as basic_lib
|
|
from cinder.volume.drivers.hitachi import hbsd_common as common
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
CHAP_METHOD = ('None', 'CHAP None', 'CHAP')
|
|
|
|
volume_opts = [
|
|
cfg.BoolOpt('hitachi_add_chap_user',
|
|
default=False,
|
|
help='Add CHAP user'),
|
|
cfg.StrOpt('hitachi_auth_method',
|
|
help='iSCSI authentication method'),
|
|
cfg.StrOpt('hitachi_auth_user',
|
|
default='%sCHAP-user' % basic_lib.NAME_PREFIX,
|
|
help='iSCSI authentication username'),
|
|
cfg.StrOpt('hitachi_auth_password',
|
|
default='%sCHAP-password' % basic_lib.NAME_PREFIX,
|
|
help='iSCSI authentication password', secret=True),
|
|
]
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opts(volume_opts, group=configuration.SHARED_CONF_GROUP)
|
|
|
|
|
|
@interface.volumedriver
|
|
class HBSDISCSIDriver(cinder.volume.driver.ISCSIDriver):
|
|
VERSION = common.VERSION
|
|
|
|
# ThirdPartySystems wiki page
|
|
CI_WIKI_NAME = ["Hitachi_HBSD_CI", "Hitachi_HBSD2_CI"]
|
|
|
|
SUPPORTED = False
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
os.environ['LANG'] = 'C'
|
|
super(HBSDISCSIDriver, self).__init__(*args, **kwargs)
|
|
self.db = kwargs.get('db')
|
|
self.common = None
|
|
self.configuration.append_config_values(common.volume_opts)
|
|
self._stats = {}
|
|
self.context = None
|
|
self.do_setup_status = threading.Event()
|
|
|
|
def _check_param(self):
|
|
self.configuration.append_config_values(volume_opts)
|
|
if (self.configuration.hitachi_auth_method and
|
|
self.configuration.hitachi_auth_method not in CHAP_METHOD):
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(601, param='hitachi_auth_method'))
|
|
if self.configuration.hitachi_auth_method == 'None':
|
|
self.configuration.hitachi_auth_method = None
|
|
for opt in volume_opts:
|
|
getattr(self.configuration, opt.name)
|
|
|
|
def check_param(self):
|
|
try:
|
|
self.common.check_param()
|
|
self._check_param()
|
|
except exception.HBSDError:
|
|
raise
|
|
except Exception as ex:
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(601, param=six.text_type(ex)))
|
|
|
|
def output_param_to_log(self):
|
|
lock = basic_lib.get_process_lock(self.common.system_lock_file)
|
|
|
|
with lock:
|
|
self.common.output_param_to_log('iSCSI')
|
|
for opt in volume_opts:
|
|
if not opt.secret:
|
|
value = getattr(self.configuration, opt.name)
|
|
LOG.info('\t%(name)-35s : %(value)s',
|
|
{'name': opt.name, 'value': value})
|
|
|
|
def _delete_lun_iscsi(self, hostgroups, ldev):
|
|
try:
|
|
self.common.command.comm_delete_lun_iscsi(hostgroups, ldev)
|
|
except exception.HBSDNotFound:
|
|
LOG.warning(basic_lib.set_msg(301, ldev=ldev))
|
|
|
|
def _add_target(self, hostgroups, ldev):
|
|
self.common.add_lun('autargetmap', hostgroups, ldev)
|
|
|
|
def _add_initiator(self, hgs, port, gid, host_iqn):
|
|
self.common.command.comm_add_initiator(port, gid, host_iqn)
|
|
hgs.append({'port': port, 'gid': int(gid), 'detected': True})
|
|
LOG.debug("Create iSCSI target for %s", hgs)
|
|
|
|
def _get_unused_gid_iscsi(self, port):
|
|
group_range = self.configuration.hitachi_group_range
|
|
if not group_range:
|
|
group_range = basic_lib.DEFAULT_GROUP_RANGE
|
|
return self.common.command.get_unused_gid_iscsi(group_range, port)
|
|
|
|
def _delete_iscsi_target(self, port, target_no, target_alias):
|
|
ret, _stdout, _stderr = self.common.command.delete_iscsi_target(
|
|
port, target_no, target_alias)
|
|
if ret:
|
|
LOG.warning(basic_lib.set_msg(
|
|
307, port=port, tno=target_no, alias=target_alias))
|
|
|
|
def _delete_chap_user(self, port):
|
|
ret, _stdout, _stderr = self.common.command.delete_chap_user(port)
|
|
if ret:
|
|
LOG.warning(basic_lib.set_msg(
|
|
303, user=self.configuration.hitachi_auth_user))
|
|
|
|
def _get_hostgroup_info_iscsi(self, hgs, host_iqn):
|
|
return self.common.command.comm_get_hostgroup_info_iscsi(
|
|
hgs, host_iqn, self.configuration.hitachi_target_ports)
|
|
|
|
def _discovery_iscsi_target(self, hostgroups):
|
|
for hostgroup in hostgroups:
|
|
ip_addr, ip_port = self.common.command.comm_get_iscsi_ip(
|
|
hostgroup['port'])
|
|
target_iqn = self.common.command.comm_get_target_iqn(
|
|
hostgroup['port'], hostgroup['gid'])
|
|
hostgroup['ip_addr'] = ip_addr
|
|
hostgroup['ip_port'] = ip_port
|
|
hostgroup['target_iqn'] = target_iqn
|
|
LOG.debug("ip_addr=%(addr)s ip_port=%(port)s target_iqn=%(iqn)s",
|
|
{'addr': ip_addr, 'port': ip_port, 'iqn': target_iqn})
|
|
|
|
def _fill_groups(self, hgs, ports, target_iqn, target_alias, add_iqn):
|
|
for port in ports:
|
|
added_hostgroup = False
|
|
added_user = False
|
|
LOG.debug('Create target (hgs: %(hgs)s port: %(port)s '
|
|
'target_iqn: %(tiqn)s target_alias: %(alias)s '
|
|
'add_iqn: %(aiqn)s)',
|
|
{'hgs': hgs, 'port': port, 'tiqn': target_iqn,
|
|
'alias': target_alias, 'aiqn': add_iqn})
|
|
gid = self.common.command.get_gid_from_targetiqn(
|
|
target_iqn, target_alias, port)
|
|
if gid is None:
|
|
for retry_cnt in basic_lib.DEFAULT_TRY_RANGE:
|
|
gid = None
|
|
try:
|
|
gid = self._get_unused_gid_iscsi(port)
|
|
self.common.command.comm_add_hostgrp_iscsi(
|
|
port, gid, target_alias, target_iqn)
|
|
added_hostgroup = True
|
|
except exception.HBSDNotFound:
|
|
LOG.warning(basic_lib.set_msg(312, resource='GID'))
|
|
continue
|
|
except Exception as ex:
|
|
LOG.warning(basic_lib.set_msg(
|
|
309, port=port, alias=target_alias,
|
|
reason=ex))
|
|
break
|
|
else:
|
|
LOG.debug('Completed to add target'
|
|
'(port: %(port)s gid: %(gid)d)',
|
|
{'port': port, 'gid': gid})
|
|
break
|
|
if gid is None:
|
|
LOG.error('Failed to add target(port: %s)', port)
|
|
continue
|
|
try:
|
|
if added_hostgroup:
|
|
if self.configuration.hitachi_auth_method:
|
|
added_user = self.common.command.set_chap_authention(
|
|
port, gid)
|
|
self.common.command.comm_set_hostgrp_reportportal(
|
|
port, target_alias)
|
|
self._add_initiator(hgs, port, gid, add_iqn)
|
|
except Exception as ex:
|
|
LOG.warning(basic_lib.set_msg(
|
|
316, port=port, reason=ex))
|
|
if added_hostgroup:
|
|
if added_user:
|
|
self._delete_chap_user(port)
|
|
self._delete_iscsi_target(port, gid, target_alias)
|
|
|
|
def add_hostgroup_core(self, hgs, ports, target_iqn,
|
|
target_alias, add_iqn):
|
|
if ports:
|
|
self._fill_groups(hgs, ports, target_iqn, target_alias, add_iqn)
|
|
|
|
def add_hostgroup_master(self, hgs, master_iqn, host_ip, security_ports):
|
|
target_ports = self.configuration.hitachi_target_ports
|
|
group_request = self.configuration.hitachi_group_request
|
|
target_alias = '%s%s' % (basic_lib.NAME_PREFIX, host_ip)
|
|
if target_ports and group_request:
|
|
target_iqn = '%s.target' % master_iqn
|
|
|
|
diff_ports = []
|
|
for port in security_ports:
|
|
for hostgroup in hgs:
|
|
if hostgroup['port'] == port:
|
|
break
|
|
else:
|
|
diff_ports.append(port)
|
|
|
|
self.add_hostgroup_core(hgs, diff_ports, target_iqn,
|
|
target_alias, master_iqn)
|
|
if not hgs:
|
|
raise exception.HBSDError(message=basic_lib.output_err(649))
|
|
|
|
def add_hostgroup(self):
|
|
properties = utils.brick_get_connector_properties()
|
|
if 'initiator' not in properties:
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(650, resource='HBA'))
|
|
LOG.debug("initiator: %s", properties['initiator'])
|
|
hostgroups = []
|
|
security_ports = self._get_hostgroup_info_iscsi(
|
|
hostgroups, properties['initiator'])
|
|
self.add_hostgroup_master(hostgroups, properties['initiator'],
|
|
properties['ip'], security_ports)
|
|
|
|
def _get_properties(self, volume, hostgroups):
|
|
conf = self.configuration
|
|
properties = {}
|
|
self._discovery_iscsi_target(hostgroups)
|
|
hostgroup = hostgroups[0]
|
|
|
|
properties['target_discovered'] = True
|
|
properties['target_portal'] = "%s:%s" % (hostgroup['ip_addr'],
|
|
hostgroup['ip_port'])
|
|
properties['target_iqn'] = hostgroup['target_iqn']
|
|
properties['target_lun'] = hostgroup['lun']
|
|
|
|
if conf.hitachi_auth_method:
|
|
properties['auth_method'] = 'CHAP'
|
|
properties['auth_username'] = conf.hitachi_auth_user
|
|
properties['auth_password'] = conf.hitachi_auth_password
|
|
|
|
return properties
|
|
|
|
def do_setup(self, context):
|
|
self.context = context
|
|
self.common = common.HBSDCommon(self.configuration, self,
|
|
context, self.db)
|
|
msg = _("The HBSD iSCSI driver is deprecated and "
|
|
"will be removed in P release")
|
|
versionutils.report_deprecated_feature(LOG, msg)
|
|
|
|
self.check_param()
|
|
|
|
self.common.create_lock_file()
|
|
|
|
self.common.command.connect_storage()
|
|
|
|
lock = basic_lib.get_process_lock(self.common.service_lock_file)
|
|
with lock:
|
|
self.add_hostgroup()
|
|
|
|
self.output_param_to_log()
|
|
self.do_setup_status.set()
|
|
|
|
def check_for_setup_error(self):
|
|
pass
|
|
|
|
def extend_volume(self, volume, new_size):
|
|
self.do_setup_status.wait()
|
|
self.common.extend_volume(volume, new_size)
|
|
|
|
def get_volume_stats(self, refresh=False):
|
|
if refresh:
|
|
if self.do_setup_status.isSet():
|
|
self.common.output_backend_available_once()
|
|
_stats = self.common.update_volume_stats("iSCSI")
|
|
if _stats:
|
|
self._stats = _stats
|
|
return self._stats
|
|
|
|
def create_volume(self, volume):
|
|
self.do_setup_status.wait()
|
|
metadata = self.common.create_volume(volume)
|
|
return metadata
|
|
|
|
def delete_volume(self, volume):
|
|
self.do_setup_status.wait()
|
|
self.common.delete_volume(volume)
|
|
|
|
def create_snapshot(self, snapshot):
|
|
self.do_setup_status.wait()
|
|
metadata = self.common.create_snapshot(snapshot)
|
|
return metadata
|
|
|
|
def delete_snapshot(self, snapshot):
|
|
self.do_setup_status.wait()
|
|
self.common.delete_snapshot(snapshot)
|
|
|
|
def create_cloned_volume(self, volume, src_vref):
|
|
self.do_setup_status.wait()
|
|
metadata = self.common.create_cloned_volume(volume, src_vref)
|
|
return metadata
|
|
|
|
def create_volume_from_snapshot(self, volume, snapshot):
|
|
self.do_setup_status.wait()
|
|
metadata = self.common.create_volume_from_snapshot(volume, snapshot)
|
|
return metadata
|
|
|
|
def _initialize_connection(self, ldev, connector, src_hgs=None):
|
|
LOG.debug("Call _initialize_connection "
|
|
"(config_group: %(group)s ldev: %(ldev)d)",
|
|
{'group': self.configuration.config_group, 'ldev': ldev})
|
|
if src_hgs:
|
|
hostgroups = src_hgs[:]
|
|
else:
|
|
hostgroups = []
|
|
security_ports = self._get_hostgroup_info_iscsi(
|
|
hostgroups, connector['initiator'])
|
|
self.add_hostgroup_master(hostgroups, connector['initiator'],
|
|
connector['ip'], security_ports)
|
|
|
|
self._add_target(hostgroups, ldev)
|
|
|
|
return hostgroups
|
|
|
|
def initialize_connection(self, volume, connector):
|
|
self.do_setup_status.wait()
|
|
ldev = self.common.get_ldev(volume)
|
|
if ldev is None:
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(619, volume_id=volume['id']))
|
|
self.common.add_volinfo(ldev, volume['id'])
|
|
with self.common.volume_info[ldev]['lock'],\
|
|
self.common.volume_info[ldev]['in_use']:
|
|
hostgroups = self._initialize_connection(ldev, connector)
|
|
protocol = 'iscsi'
|
|
properties = self._get_properties(volume, hostgroups)
|
|
LOG.debug('Initialize volume_info: %s',
|
|
self.common.volume_info)
|
|
|
|
LOG.debug('HFCDrv: properties=%s', properties)
|
|
return {
|
|
'driver_volume_type': protocol,
|
|
'data': properties
|
|
}
|
|
|
|
def _terminate_connection(self, ldev, connector, src_hgs):
|
|
LOG.debug("Call _terminate_connection(config_group: %s)",
|
|
self.configuration.config_group)
|
|
hostgroups = src_hgs[:]
|
|
self._delete_lun_iscsi(hostgroups, ldev)
|
|
|
|
LOG.debug("*** _terminate_ ***")
|
|
|
|
def terminate_connection(self, volume, connector, **kwargs):
|
|
self.do_setup_status.wait()
|
|
ldev = self.common.get_ldev(volume)
|
|
if ldev is None:
|
|
LOG.warning(basic_lib.set_msg(302, volume_id=volume['id']))
|
|
return
|
|
|
|
if 'initiator' not in connector:
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(650, resource='HBA'))
|
|
|
|
hostgroups = []
|
|
self._get_hostgroup_info_iscsi(hostgroups,
|
|
connector['initiator'])
|
|
if not hostgroups:
|
|
raise exception.HBSDError(message=basic_lib.output_err(649))
|
|
|
|
self.common.add_volinfo(ldev, volume['id'])
|
|
with self.common.volume_info[ldev]['lock'],\
|
|
self.common.volume_info[ldev]['in_use']:
|
|
self._terminate_connection(ldev, connector, hostgroups)
|
|
|
|
def create_export(self, context, volume, connector):
|
|
pass
|
|
|
|
def ensure_export(self, context, volume):
|
|
pass
|
|
|
|
def remove_export(self, context, volume):
|
|
pass
|
|
|
|
def pair_initialize_connection(self, unused_ldev):
|
|
pass
|
|
|
|
def pair_terminate_connection(self, unused_ldev):
|
|
pass
|
|
|
|
def copy_volume_to_image(self, context, volume, image_service, image_meta):
|
|
self.do_setup_status.wait()
|
|
if volume['volume_attachment']:
|
|
desc = 'volume %s' % volume['id']
|
|
raise exception.HBSDError(
|
|
message=basic_lib.output_err(660, desc=desc))
|
|
super(HBSDISCSIDriver, self).copy_volume_to_image(context, volume,
|
|
image_service,
|
|
image_meta)
|
|
|
|
def manage_existing(self, volume, existing_ref):
|
|
return self.common.manage_existing(volume, existing_ref)
|
|
|
|
def manage_existing_get_size(self, volume, existing_ref):
|
|
self.do_setup_status.wait()
|
|
return self.common.manage_existing_get_size(volume, existing_ref)
|
|
|
|
def unmanage(self, volume):
|
|
self.do_setup_status.wait()
|
|
self.common.unmanage(volume)
|