diff --git a/cinder/tests/unit/test_hds.py b/cinder/tests/unit/test_hds.py deleted file mode 100644 index 4e830f85e..000000000 --- a/cinder/tests/unit/test_hds.py +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright (c) 2013 Hitachi Data Systems, Inc. -# Copyright (c) 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. -# - -""" -Self test for Hitachi Unified Storage (HUS) platform. -""" - -import os -import tempfile - -from mox3 import mox - -from cinder import test -from cinder.volume import configuration as conf -from cinder.volume.drivers.hds import hds - - -CONF = """ - - 172.17.44.16 - 172.17.44.17 - system - manager - - default - 172.17.39.132 - 9 - - - silver - 172.17.39.133 - 9 - - - gold - 172.17.39.134 - 9 - - - platinum - 172.17.39.135 - 9 - - - 9 - - - 3300 - - -""" - - -class SimulatedHusBackend(object): - """Simulation Back end. Talks to HUS.""" - - alloc_lun = [] # allocated LUs - connections = [] # iSCSI connections - init_index = 0 # initiator index - target_index = 0 # target index - hlun = 0 # hlun index - out = '' - - def __init__(self): - self.start_lun = 0 - - def get_version(self, cmd, ver, ip0, ip1, user, pw): - out = ("Array_ID: 92210013 (HUS130) version: 0920/B-S LU: 4096" - " RG: 75 RG_LU: 1024 Utility_version: 1.0.0") - return out - - def get_iscsi_info(self, cmd, ver, ip0, ip1, user, pw): - out = """CTL: 0 Port: 4 IP: 172.17.39.132 Port: 3260 Link: Up - CTL: 0 Port: 5 IP: 172.17.39.133 Port: 3260 Link: Up - CTL: 1 Port: 4 IP: 172.17.39.134 Port: 3260 Link: Up - CTL: 1 Port: 5 IP: 172.17.39.135 Port: 3260 Link: Up""" - return out - - def get_hdp_info(self, cmd, ver, ip0, ip1, user, pw): - out = """HDP: 2 272384 MB 33792 MB 12 % LUs: 70 Normal Normal - HDP: 9 546816 MB 73728 MB 13 % LUs: 194 Normal Normal""" - return out - - def create_lu(self, cmd, ver, ip0, ip1, user, pw, id, hdp, start, - end, size): - if self.start_lun < int(start): # initialize first time - self.start_lun = int(start) - out = ("LUN: %d HDP: 9 size: %s MB, is successfully created" % - (self.start_lun, size)) - self.alloc_lun.append(str(self.start_lun)) - self.start_lun += 1 - return out - - def extend_vol(self, cmd, ver, ip0, ip1, user, pw, id, lu, size): - out = ("LUN: %s successfully extended to %s MB" % (lu, size)) - SimulatedHusBackend.out = out - return out - - def delete_lu(self, cmd, ver, ip0, ip1, user, pw, id, lun): - out = "" - if lun in self.alloc_lun: - out = "LUN: %s is successfully deleted" % (lun) - self.alloc_lun.remove(lun) - return out - - def create_dup(self, cmd, ver, ip0, ip1, user, pw, id, src_lun, - hdp, start, end, size): - out = ("LUN: %s HDP: 9 size: %s MB, is successfully created" % - (self.start_lun, size)) - self.alloc_lun.append(str(self.start_lun)) - self.start_lun += 1 - return out - - def add_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port, - iqn, initiator): - conn = (self.hlun, lun, initiator, self.init_index, iqn, - self.target_index, ctl, port) - out = ("H-LUN: %d mapped. LUN: %s, iSCSI Initiator: %s @ index: %d, \ - and Target: %s @ index %d is successfully paired @ CTL: %s, \ - Port: %s" % conn) - self.init_index += 1 - self.target_index += 1 - self.hlun += 1 - SimulatedHusBackend.connections.append(conn) - return out - - def del_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port, - iqn, initiator): - conn = () - for connection in SimulatedHusBackend.connections: - if (connection[1] == lun): - conn = connection - SimulatedHusBackend.connections.remove(connection) - if conn is None: - return - (hlun, lun, initiator, init_index, iqn, target_index, ctl, port) = conn - detail = (hlun, iqn) - out = ("H-LUN: %d successfully deleted from target %s" % detail) - return out - - -# The following information is passed on to tests, when creating a volume - -_VOLUME = {'volume_id': '1234567890', 'size': 128, - 'volume_type': None, 'provider_location': None, 'id': 'abcdefg'} - - -class HUSiSCSIDriverTest(test.TestCase): - """Test HUS iSCSI volume driver.""" - - def __init__(self, *args, **kwargs): - super(HUSiSCSIDriverTest, self).__init__(*args, **kwargs) - - def setUp(self): - super(HUSiSCSIDriverTest, self).setUp() - (handle, self.config_file) = tempfile.mkstemp('.xml') - self.addCleanup(os.remove, self.config_file) - os.write(handle, CONF) - os.close(handle) - SimulatedHusBackend.alloc_lun = [] - SimulatedHusBackend.connections = [] - SimulatedHusBackend.out = '' - self.mox.StubOutWithMock(hds, 'factory_bend') - hds.factory_bend().AndReturn(SimulatedHusBackend()) - self.mox.ReplayAll() - self.configuration = mox.MockObject(conf.Configuration) - self.configuration.hds_cinder_config_file = self.config_file - self.driver = hds.HUSDriver(configuration=self.configuration) - - def test_get_volume_stats(self): - stats = self.driver.get_volume_stats(True) - self.assertEqual(stats["vendor_name"], "HDS") - self.assertEqual(stats["storage_protocol"], "iSCSI") - self.assertGreater(stats["total_capacity_gb"], 0) - - def test_create_volume(self): - loc = self.driver.create_volume(_VOLUME) - self.assertIsNotNone(loc) - vol = _VOLUME.copy() - vol['provider_location'] = loc['provider_location'] - self.assertIsNotNone(loc['provider_location']) - return vol - - def test_delete_volume(self): - """Delete a volume (test). - - Note: this API call should not expect any exception: - This driver will silently accept a delete request, because - the DB can be out of sync, and Cinder manager will keep trying - to delete, even though the volume has been wiped out of the - Array. We don't want to have a dangling volume entry in the - customer dashboard. - """ - vol = self.test_create_volume() - self.assertTrue(SimulatedHusBackend.alloc_lun) - num_luns_before = len(SimulatedHusBackend.alloc_lun) - self.driver.delete_volume(vol) - num_luns_after = len(SimulatedHusBackend.alloc_lun) - self.assertGreater(num_luns_before, num_luns_after) - - def test_extend_volume(self): - vol = self.test_create_volume() - new_size = _VOLUME['size'] * 2 - self.driver.extend_volume(vol, new_size) - self.assertTrue(str(new_size * 1024) in - SimulatedHusBackend.out) - - def test_create_snapshot(self): - vol = self.test_create_volume() - self.mox.StubOutWithMock(self.driver, '_id_to_vol') - self.driver._id_to_vol(vol['volume_id']).AndReturn(vol) - self.mox.ReplayAll() - svol = vol.copy() - svol['volume_size'] = svol['size'] - loc = self.driver.create_snapshot(svol) - self.assertIsNotNone(loc) - svol['provider_location'] = loc['provider_location'] - return svol - - def test_create_clone(self): - vol = self.test_create_volume() - self.mox.StubOutWithMock(self.driver, '_id_to_vol') - self.driver._id_to_vol(vol['volume_id']).AndReturn(vol) - self.mox.ReplayAll() - svol = vol.copy() - svol['volume_size'] = svol['size'] - loc = self.driver.create_snapshot(svol) - self.assertIsNotNone(loc) - svol['provider_location'] = loc['provider_location'] - return svol - - def test_delete_snapshot(self): - """Delete a snapshot (test). - - Note: this API call should not expect any exception: - This driver will silently accept a delete request, because - the DB can be out of sync, and Cinder manager will keep trying - to delete, even though the snapshot has been wiped out of the - Array. We don't want to have a dangling snapshot entry in the - customer dashboard. - """ - svol = self.test_create_snapshot() - num_luns_before = len(SimulatedHusBackend.alloc_lun) - self.driver.delete_snapshot(svol) - num_luns_after = len(SimulatedHusBackend.alloc_lun) - self.assertGreater(num_luns_before, num_luns_after) - - def test_create_volume_from_snapshot(self): - svol = self.test_create_snapshot() - vol = self.driver.create_volume_from_snapshot(_VOLUME, svol) - self.assertIsNotNone(vol) - return vol - - def test_initialize_connection(self): - connector = {} - connector['initiator'] = 'iqn.1993-08.org.debian:01:11f90746eb2' - connector['host'] = 'dut_1.lab.hds.com' - vol = self.test_create_volume() - self.mox.StubOutWithMock(self.driver, '_update_vol_location') - self.driver._update_vol_location(vol['id'], mox.IgnoreArg()) - self.mox.ReplayAll() - conn = self.driver.initialize_connection(vol, connector) - self.assertIn('hitachi', conn['data']['target_iqn']) - self.assertIn('3260', conn['data']['target_portal']) - vol['provider_location'] = conn['data']['provider_location'] - return (vol, connector) - - def test_terminate_connection(self): - """Terminate a connection (test). - - Note: this API call should not expect any exception: - This driver will silently accept a terminate_connection request - because an error/exception return will only jeopardize the - connection tear down at a host. - """ - connector = {} - connector['initiator'] = 'iqn.1993-08.org.debian:01:11f90746eb2' - connector['host'] = 'dut_1.lab.hds.com' - vol = self.test_create_volume() - self.mox.StubOutWithMock(self.driver, '_update_vol_location') - self.driver._update_vol_location(vol['id'], mox.IgnoreArg()) - self.driver._update_vol_location(vol['id'], mox.IgnoreArg()) - - self.mox.ReplayAll() - - conn = self.driver.initialize_connection(vol, connector) - vol['provider_location'] = conn['data']['provider_location'] - num_conn_before = len(SimulatedHusBackend.connections) - self.driver.terminate_connection(vol, connector) - num_conn_after = len(SimulatedHusBackend.connections) - self.assertGreater(num_conn_before, num_conn_after) diff --git a/cinder/volume/drivers/hds/hds.py b/cinder/volume/drivers/hds/hds.py deleted file mode 100644 index 86681f9ce..000000000 --- a/cinder/volume/drivers/hds/hds.py +++ /dev/null @@ -1,523 +0,0 @@ -# Copyright (c) 2013 Hitachi Data Systems, Inc. -# Copyright (c) 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. -# - -""" -iSCSI Cinder Volume driver for Hitachi Unified Storage (HUS) platform. -""" - -from xml.etree import ElementTree as ETree - -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import excutils - -from cinder import exception -from cinder.i18n import _LE, _LI -from cinder import utils -from cinder.volume import driver -from cinder.volume.drivers.hds import hus_backend - -HDS_VERSION = '1.0.2' - -LOG = logging.getLogger(__name__) - -HUS_OPTS = [ - cfg.StrOpt('hds_cinder_config_file', - default='/opt/hds/hus/cinder_hus_conf.xml', - help='The configuration file for the Cinder HDS driver ' - 'for HUS'), ] - -CONF = cfg.CONF -CONF.register_opts(HUS_OPTS) - -HI_IQN = 'iqn.1994-04.jp.co.hitachi:' # fixed string, for now. - -HUS_DEFAULT_CONFIG = {'hus_cmd': 'hus-cmd', - 'lun_start': '0', - 'lun_end': '8192'} - - -def factory_bend(): - """Factory over-ride in self-tests.""" - return hus_backend.HusBackend() - - -def _loc_info(loc): - """Parse info from location string.""" - info = {} - tup = loc.split(',') - if len(tup) < 5: - info['id_lu'] = tup[0].split('.') - return info - info['id_lu'] = tup[2].split('.') - info['tgt'] = tup - return info - - -def _do_lu_range_check(start, end, maxlun): - """Validate array allocation range.""" - LOG.debug("Range: start LU: %(start)s, end LU: %(end)s", - {'start': start, 'end': end}) - if int(start) < 0: - msg = 'start LU limit too low: ' + start - raise exception.InvalidInput(reason=msg) - if int(start) >= int(maxlun): - msg = 'start LU limit high: ' + start + ' max: ' + maxlun - raise exception.InvalidInput(reason=msg) - if int(end) <= int(start): - msg = 'LU end limit too low: ' + end - raise exception.InvalidInput(reason=msg) - if int(end) > int(maxlun): - end = maxlun - LOG.debug("setting LU upper (end) limit to %s", maxlun) - return (start, end) - - -def _xml_read(root, element, check=None): - """Read an xml element.""" - try: - val = root.findtext(element) - LOG.info(_LI("%(element)s: %(val)s"), - {'element': element, 'val': val}) - if val: - return val.strip() - if check: - raise exception.ParameterNotFound(param=element) - return None - except ETree.ParseError: - if check: - with excutils.save_and_reraise_exception(): - LOG.error(_LE("XML exception reading parameter: %s"), element) - else: - LOG.info(_LI("XML exception reading parameter: %s"), element) - return None - - -def _read_config(xml_config_file): - """Read hds driver specific xml config file.""" - try: - root = ETree.parse(xml_config_file).getroot() - except Exception: - raise exception.NotFound(message='config file not found: ' - + xml_config_file) - config = {} - arg_prereqs = ['mgmt_ip0', 'mgmt_ip1', 'username', 'password'] - for req in arg_prereqs: - config[req] = _xml_read(root, req, 'check') - - config['hdp'] = {} - config['services'] = {} - for svc in ['svc_0', 'svc_1', 'svc_2', 'svc_3']: # min one needed - if _xml_read(root, svc) is None: - continue - service = {} - service['label'] = svc - for arg in ['volume_type', 'hdp', 'iscsi_ip']: # none optional - service[arg] = _xml_read(root, svc + '/' + arg, 'check') - config['services'][service['volume_type']] = service - config['hdp'][service['hdp']] = service['hdp'] - - if config['services'].keys() is None: # at least one service required! - raise exception.ParameterNotFound(param="No service found") - - config['snapshot_hdp'] = _xml_read(root, 'snapshot/hdp', 'check') - - for arg in ['hus_cmd', 'lun_start', 'lun_end']: # optional - config[arg] = _xml_read(root, arg) or HUS_DEFAULT_CONFIG[arg] - - return config - - -class HUSDriver(driver.ISCSIDriver): - """HDS HUS volume driver.""" - - VERSION = HDS_VERSION - - def _array_info_get(self): - """Get array parameters.""" - out = self.bend.get_version(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password']) - inf = out.split() - return(inf[1], 'hus_' + inf[1], inf[6]) - - def _get_iscsi_info(self): - """Validate array iscsi parameters.""" - out = self.bend.get_iscsi_info(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password']) - lines = out.split('\n') - conf = {} # dict based on iSCSI portal ip addresses - for line in lines: - if 'CTL' in line: - inf = line.split() - (ctl, port, ip, ipp) = (inf[1], inf[3], inf[5], inf[7]) - conf[ip] = {} - conf[ip]['ctl'] = ctl - conf[ip]['port'] = port - conf[ip]['iscsi_port'] = ipp # HUS default: 3260 - LOG.debug('portal: %(ip)s:%(ipp)s, CTL: %(ctl)s, port: ' - '%(port)s', {'ip': ip, 'ipp': ipp, - 'ctl': ctl, 'port': port}) - return conf - - def _get_service(self, volume): - """Get the available service parameters for a given volume type.""" - label = None - if volume['volume_type']: - label = volume['volume_type']['name'] - label = label or 'default' - if label in self.config['services'].keys(): - svc = self.config['services'][label] - service = (svc['iscsi_ip'], svc['iscsi_port'], svc['ctl'], - svc['port'], svc['hdp']) # ip, ipp, ctl, port, hdp - else: - LOG.error(_LE("No configuration found for service: %s"), label) - raise exception.ParameterNotFound(param=label) - return service - - def _get_stats(self): - """Get HDP stats from HUS.""" - total_cap = 0 - total_used = 0 - out = self.bend.get_hdp_info(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password']) - for line in out.split('\n'): - if 'HDP' in line: - (hdp, size, _ign, used) = line.split()[1:5] # in MB - if hdp in self.config['hdp'].keys(): - total_cap += int(size) - total_used += int(used) - hus_stat = {} - hus_stat['total_capacity_gb'] = int(total_cap / 1024) # in GB - hus_stat['free_capacity_gb'] = int((total_cap - total_used) / 1024) - be_name = self.configuration.safe_get('volume_backend_name') - hus_stat["volume_backend_name"] = be_name or 'HUSDriver' - hus_stat["vendor_name"] = 'HDS' - hus_stat["driver_version"] = HDS_VERSION - hus_stat["storage_protocol"] = 'iSCSI' - hus_stat['QoS_support'] = False - hus_stat['reserved_percentage'] = 0 - return hus_stat - - def _get_hdp_list(self): - """Get HDPs from HUS.""" - out = self.bend.get_hdp_info(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password']) - hdp_list = [] - for line in out.split('\n'): - if 'HDP' in line: - hdp_list.extend(line.split()[1:2]) - return hdp_list - - def _check_hdp_list(self): - """Verify all HDPs specified in the configuration exist.""" - hdpl = self._get_hdp_list() - lst = self.config['hdp'].keys() - lst.extend([self.config['snapshot_hdp'], ]) - for hdp in lst: - if hdp not in hdpl: - LOG.error(_LE("HDP not found: %s"), hdp) - err = "HDP not found: " + hdp - raise exception.ParameterNotFound(param=err) - - def _id_to_vol(self, idd): - """Given the volume id, retrieve the volume object from database.""" - vol = self.db.volume_get(self.context, idd) - return vol - - def _update_vol_location(self, id, loc): - """Update the provider location.""" - update = {} - update['provider_location'] = loc - self.db.volume_update(self.context, id, update) - - def __init__(self, *args, **kwargs): - """Initialize, read different config parameters.""" - super(HUSDriver, self).__init__(*args, **kwargs) - self.driver_stats = {} - self.context = {} - self.bend = factory_bend() - self.configuration.append_config_values(HUS_OPTS) - self.config = _read_config(self.configuration.hds_cinder_config_file) - (self.arid, self.hus_name, self.lumax) = self._array_info_get() - self._check_hdp_list() - start = self.config['lun_start'] - end = self.config['lun_end'] - maxlun = self.lumax - (self.start, self.end) = _do_lu_range_check(start, end, maxlun) - iscsi_info = self._get_iscsi_info() - for svc in self.config['services'].keys(): - svc_ip = self.config['services'][svc]['iscsi_ip'] - if svc_ip in iscsi_info.keys(): - self.config['services'][svc]['port'] = ( - iscsi_info[svc_ip]['port']) - self.config['services'][svc]['ctl'] = iscsi_info[svc_ip]['ctl'] - self.config['services'][svc]['iscsi_port'] = ( - iscsi_info[svc_ip]['iscsi_port']) - else: # config iscsi address not found on device! - LOG.error(_LE("iSCSI portal not found " - "for service: %s"), svc_ip) - raise exception.ParameterNotFound(param=svc_ip) - return - - def check_for_setup_error(self): - """Returns an error if prerequisites aren't met.""" - return - - def do_setup(self, context): - """do_setup. - - Setup and verify HDS HUS storage connection. But moved it to - __init__ as (setup/errors) could became an infinite loop. - """ - self.context = context - - def ensure_export(self, context, volume): - return - - def create_export(self, context, volume): - """Create an export. Moved to initialize_connection.""" - return - - @utils.synchronized('hds_hus', external=True) - def create_volume(self, volume): - """Create a LU on HUS.""" - service = self._get_service(volume) - (_ip, _ipp, _ctl, _port, hdp) = service - out = self.bend.create_lu(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - self.arid, hdp, self.start, self.end, - '%s' % (int(volume['size']) * 1024)) - lun = self.arid + '.' + out.split()[1] - sz = int(out.split()[5]) - LOG.debug("LUN %(lun)s of size %(sz)s MB is created.", - {'lun': lun, 'sz': sz}) - return {'provider_location': lun} - - @utils.synchronized('hds_hus', external=True) - def create_cloned_volume(self, dst, src): - """Create a clone of a volume.""" - if src['size'] != dst['size']: - msg = 'clone volume size mismatch' - raise exception.VolumeBackendAPIException(data=msg) - service = self._get_service(dst) - (_ip, _ipp, _ctl, _port, hdp) = service - size = int(src['size']) * 1024 - source_vol = self._id_to_vol(src['id']) - (arid, slun) = _loc_info(source_vol['provider_location'])['id_lu'] - out = self.bend.create_dup(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, slun, - hdp, - self.start, self.end, - '%s' % (size)) - lun = self.arid + '.' + out.split()[1] - size = int(out.split()[5]) - LOG.debug("LUN %(lun)s of size %(size)s MB is cloned.", - {'lun': lun, 'size': size}) - return {'provider_location': lun} - - @utils.synchronized('hds_hus', external=True) - def extend_volume(self, volume, new_size): - """Extend an existing volume.""" - (arid, lun) = _loc_info(volume['provider_location'])['id_lu'] - self.bend.extend_vol(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun, - '%s' % (new_size * 1024)) - LOG.debug("LUN %(lun)s extended to %(size)s GB.", - {'lun': lun, 'size': new_size}) - - @utils.synchronized('hds_hus', external=True) - def delete_volume(self, volume): - """Delete an LU on HUS.""" - prov_loc = volume['provider_location'] - if prov_loc is None: - return - info = _loc_info(prov_loc) - (arid, lun) = info['id_lu'] - if 'tgt' in info.keys(): # connected? - (_portal, iqn, _loc, ctl, port) = info['tgt'] - self.bend.del_iscsi_conn(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun, ctl, port, iqn, - '') - name = self.hus_name - LOG.debug("delete lun %(lun)s on %(name)s", - {'lun': lun, 'name': name}) - self.bend.delete_lu(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun) - - def remove_export(self, context, volume): - """Disconnect a volume from an attached instance.""" - return - - @utils.synchronized('hds_hus', external=True) - def initialize_connection(self, volume, connector): - """Map the created volume to connector['initiator'].""" - service = self._get_service(volume) - (ip, ipp, ctl, port, _hdp) = service - info = _loc_info(volume['provider_location']) - if 'tgt' in info.keys(): # spurious repeat connection - return - (arid, lun) = info['id_lu'] - loc = arid + '.' + lun - iqn = HI_IQN + connector['host'] - out = self.bend.add_iscsi_conn(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun, ctl, port, iqn, - connector['initiator']) - hus_portal = ip + ':' + ipp - tgt = hus_portal + ',' + iqn + ',' + loc + ',' + ctl + ',' + port - properties = {} - hlun = out.split()[1] - properties['provider_location'] = tgt - self._update_vol_location(volume['id'], tgt) - properties['target_discovered'] = False - properties['target_portal'] = hus_portal - properties['target_iqn'] = iqn - properties['target_lun'] = hlun - properties['volume_id'] = volume['id'] - return {'driver_volume_type': 'iscsi', 'data': properties} - - @utils.synchronized('hds_hus', external=True) - def terminate_connection(self, volume, connector, **kwargs): - """Terminate a connection to a volume.""" - info = _loc_info(volume['provider_location']) - if 'tgt' not in info.keys(): # spurious disconnection - return - (arid, lun) = info['id_lu'] - (_portal, iqn, loc, ctl, port) = info['tgt'] - - self.bend.del_iscsi_conn(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun, ctl, port, iqn, - connector['initiator']) - self._update_vol_location(volume['id'], loc) - return {'provider_location': loc} - - @utils.synchronized('hds_hus', external=True) - def create_volume_from_snapshot(self, volume, snapshot): - """Create a volume from a snapshot.""" - size = int(snapshot['volume_size']) * 1024 - (arid, slun) = _loc_info(snapshot['provider_location'])['id_lu'] - service = self._get_service(volume) - (_ip, _ipp, _ctl, _port, hdp) = service - out = self.bend.create_dup(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, slun, hdp, - self.start, self.end, - '%s' % (size)) - lun = self.arid + '.' + out.split()[1] - sz = int(out.split()[5]) - LOG.debug("LUN %(lun)s of size %(sz)s MB is created from snapshot.", - {'lun': lun, 'sz': sz}) - return {'provider_location': lun} - - @utils.synchronized('hds_hus', external=True) - def create_snapshot(self, snapshot): - """Create a snapshot.""" - source_vol = self._id_to_vol(snapshot['volume_id']) - size = int(snapshot['volume_size']) * 1024 - (arid, slun) = _loc_info(source_vol['provider_location'])['id_lu'] - out = self.bend.create_dup(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, slun, - self.config['snapshot_hdp'], - self.start, self.end, - '%s' % (size)) - lun = self.arid + '.' + out.split()[1] - size = int(out.split()[5]) - LOG.debug("LUN %(lun)s of size %(size)s MB is created as snapshot.", - {'lun': lun, 'size': size}) - return {'provider_location': lun} - - @utils.synchronized('hds_hus', external=True) - def delete_snapshot(self, snapshot): - """Delete a snapshot.""" - loc = snapshot['provider_location'] - if loc is None: # to take care of spurious input - return # which could cause exception. - (arid, lun) = loc.split('.') - self.bend.delete_lu(self.config['hus_cmd'], - HDS_VERSION, - self.config['mgmt_ip0'], - self.config['mgmt_ip1'], - self.config['username'], - self.config['password'], - arid, lun) - LOG.debug("LUN %s is deleted.", lun) - return - - @utils.synchronized('hds_hus', external=True) - def get_volume_stats(self, refresh=False): - """Get volume stats. If 'refresh', run update the stats first.""" - if refresh: - self.driver_stats = self._get_stats() - return self.driver_stats diff --git a/cinder/volume/drivers/hds/hus_backend.py b/cinder/volume/drivers/hds/hus_backend.py deleted file mode 100644 index be0fbece3..000000000 --- a/cinder/volume/drivers/hds/hus_backend.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) 2013 Hitachi Data Systems, Inc. -# Copyright (c) 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. -# - -""" -Hitachi Unified Storage (HUS) platform. Backend operations. -""" - -from oslo_log import log as logging - -from cinder import utils - -LOG = logging.getLogger("cinder.volume.driver") - - -class HusBackend(object): - """Back end. Talks to HUS.""" - def get_version(self, cmd, ver, ip0, ip1, user, pw): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--version', '1', - run_as_root=True, - check_exit_code=True) - LOG.debug('get_version: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def get_iscsi_info(self, cmd, ver, ip0, ip1, user, pw): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--iscsi', '1', - check_exit_code=True) - LOG.debug('get_iscsi_info: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def get_hdp_info(self, cmd, ver, ip0, ip1, user, pw): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--hdp', '1', - check_exit_code=True) - LOG.debug('get_hdp_info: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def create_lu(self, cmd, ver, ip0, ip1, user, pw, id, hdp, start, - end, size): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--create-lun', '1', - '--array-id', id, - '--hdp', hdp, - '--start', start, - '--end', end, - '--size', size, - check_exit_code=True) - LOG.debug('create_lu: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def delete_lu(self, cmd, ver, ip0, ip1, user, pw, id, lun): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--delete-lun', '1', - '--array-id', id, - '--lun', lun, - '--force', 1, - check_exit_code=True) - LOG.debug('delete_lu: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def create_dup(self, cmd, ver, ip0, ip1, user, pw, id, src_lun, - hdp, start, end, size): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--create-dup', '1', - '--array-id', id, - '--pvol', src_lun, - '--hdp', hdp, - '--start', start, - '--end', end, - '--size', size, - check_exit_code=True) - LOG.debug('create_dup: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def extend_vol(self, cmd, ver, ip0, ip1, user, pw, id, lun, new_size): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--extend-lun', '1', - '--array-id', id, - '--lun', lun, - '--size', new_size, - check_exit_code=True) - LOG.debug('extend_vol: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def add_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port, - iqn, initiator): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--add-iscsi-connection', '1', - '--array-id', id, - '--lun', lun, - '--ctl', ctl, - '--port', port, - '--target', iqn, - '--initiator', initiator, - check_exit_code=True) - LOG.debug('add_iscsi_conn: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out - - def del_iscsi_conn(self, cmd, ver, ip0, ip1, user, pw, id, lun, ctl, port, - iqn, initiator): - out, err = utils.execute(cmd, - '--driver-version', ver, - '--ip0', ip0, - '--ip1', ip1, - '--user', user, - '--password', pw, - '--delete-iscsi-connection', '1', - '--array-id', id, - '--lun', lun, - '--ctl', ctl, - '--port', port, - '--target', iqn, - '--initiator', initiator, - '--force', 1, - check_exit_code=True) - LOG.debug('del_iscsi_conn: %(out)s -- %(err)s', - {'out': out, 'err': err}) - return out