class NotSupportedOperation(Invalid):
message = _("Operation not supported: %(operation)s.")
code = 405
+
+
+# Hitachi HNAS drivers
+class HNASConnError(CinderException):
+ message = _("%(message)s")
# License for the specific language governing permissions and limitations
# under the License.
#
+import time
import mock
-from oslo_concurrency import processutils
+from oslo_concurrency import processutils as putils
from oslo_config import cfg
+from cinder import exception
from cinder import test
from cinder import utils
from cinder.volume.drivers.hitachi import hnas_backend
HNAS_RESULT21 = "Target created successfully."
+HNAS_RESULT22 = "Failed to establish SSC connection"
+
HNAS_CMDS = {
('ssh', '0.0.0.0', 'supervisor', 'supervisor', 'evsfs', 'list'):
["%s" % HNAS_RESULT1, ""],
@mock.patch('os.path.isfile', return_value=True)
@mock.patch('paramiko.RSAKey.from_private_key_file')
@mock.patch('paramiko.SSHClient')
- @mock.patch.object(processutils, 'ssh_execute',
+ @mock.patch.object(putils, 'ssh_execute',
return_value=(HNAS_RESULT5, ''))
- def test_run_cmd(self, m_ssh_exec, m_ssh_cli, m_pvt_key, m_file, m_open):
+ @mock.patch.object(utils, 'execute')
+ @mock.patch.object(time, 'sleep')
+ def test_run_cmd(self, m_sleep, m_utl, m_ssh, m_ssh_cli,
+ m_pvt_key, m_file, m_open):
save_hkey_file = CONF.ssh_hosts_key_file
save_spath = CONF.state_path
CONF.ssh_hosts_key_file = '/var/lib/cinder/ssh_known_hosts'
CONF.state_path = '/var/lib/cinder'
+ # Test main flow
out, err = self.hnas_bend.run_cmd('ssh', '0.0.0.0',
'supervisor', 'supervisor',
'df', '-a')
self.assertIn('fs01-husvm', out)
self.assertIn('WFS-2,128 DSBs', out)
+ # Test exception throwing when not using SSH
+ m_utl.side_effect = putils.ProcessExecutionError(stdout='',
+ stderr=HNAS_RESULT22,
+ exit_code=255)
+ self.hnas_bend.drv_configs['ssh_enabled'] = 'False'
+ self.assertRaises(exception.HNASConnError, self.hnas_bend.run_cmd,
+ 'ssh', '0.0.0.0', 'supervisor', 'supervisor',
+ 'df', '-a')
+
+ # Test exception throwing when using SSH
+ m_ssh.side_effect = putils.ProcessExecutionError(stdout='',
+ stderr=HNAS_RESULT22,
+ exit_code=255)
+ self.hnas_bend.drv_configs['ssh_enabled'] = 'True'
+ self.assertRaises(exception.HNASConnError, self.hnas_bend.run_cmd,
+ 'ssh', '0.0.0.0', 'supervisor', 'supervisor',
+ 'df', '-a')
+
CONF.state_path = save_spath
CONF.ssh_hosts_key_file = save_hkey_file
import os
import tempfile
+import time
import mock
+from oslo_concurrency import processutils as putils
import six
from cinder import exception
self.backend.deleteVolumebyProvider(svol['provider_location'])
self.backend.deleteVolumebyProvider(vol['provider_location'])
+ @mock.patch.object(time, 'sleep')
@mock.patch.object(iscsi.HDSISCSIDriver, '_update_vol_location')
- def test_initialize_connection(self, m_update_vol_location):
+ def test_initialize_connection(self, m_update_vol_location, m_sleep):
connector = {}
connector['initiator'] = 'iqn.1993-08.org.debian:01:11f90746eb2'
connector['host'] = 'dut_1.lab.hds.com'
vol = self._create_volume()
conn = self.driver.initialize_connection(vol, connector)
self.assertTrue('3260' in conn['data']['target_portal'])
+
+ self.backend.add_iscsi_conn = mock.MagicMock()
+ self.backend.add_iscsi_conn.side_effect = putils.ProcessExecutionError
+ self.assertRaises(exception.ISCSITargetAttachFailed,
+ self.driver.initialize_connection, vol, connector)
+
# cleanup
self.backend.deleteVolumebyProvider(vol['provider_location'])
import re
-from oslo_concurrency import processutils
+from oslo_concurrency import processutils as putils
from oslo_log import log as logging
from oslo_utils import units
import six
-from cinder.i18n import _LE, _LW, _LI
+from cinder.i18n import _, _LW, _LI
+from cinder import exception
from cinder import ssh_utils
from cinder import utils
LOG = logging.getLogger("cinder.volume.driver")
+HNAS_SSC_RETRIES = 5
class HnasBackend(object):
self.drv_configs = drv_configs
self.sshpool = None
+ @utils.retry(exceptions=exception.HNASConnError, retries=HNAS_SSC_RETRIES)
def run_cmd(self, cmd, ip0, user, pw, *args, **kwargs):
"""Run a command on SMU or using SSH
if self.drv_configs['ssh_enabled'] != 'True':
# Direct connection via ssc
args = (cmd, '-u', user, '-p', pw, ip0) + args
- out, err = utils.execute(*args, **kwargs)
- LOG.debug("command %(cmd)s result: out = %(out)s - err = "
- "%(err)s", {'cmd': cmd, 'out': out, 'err': err})
- return out, err
+
+ try:
+ out, err = utils.execute(*args, **kwargs)
+ LOG.debug("command %(cmd)s result: out = %(out)s - err = "
+ "%(err)s", {'cmd': cmd, 'out': out, 'err': err})
+ return out, err
+ except putils.ProcessExecutionError as e:
+ if 'Failed to establish SSC connection' in e.stderr:
+ LOG.debug("SSC connection error!")
+ msg = _("Failed to establish SSC connection.")
+ raise exception.HNASConnError(msg)
+ else:
+ raise putils.ProcessExecutionError
+
else:
if self.drv_configs['cluster_admin_ip0'] is None:
# Connect to SMU through SSH and run ssc locally
privatekey=privatekey)
with self.sshpool.item() as ssh:
+
try:
- out, err = processutils.ssh_execute(ssh, command,
- check_exit_code=True)
- LOG.debug("command %(cmd)s result: out = %(out)s - err = "
- "%(err)s", {'cmd': cmd, 'out': out, 'err': err})
+ out, err = putils.ssh_execute(ssh, command,
+ check_exit_code=True)
+ LOG.debug("command %(cmd)s result: out = "
+ "%(out)s - err = %(err)s",
+ {'cmd': cmd, 'out': out, 'err': err})
return out, err
- except processutils.ProcessExecutionError:
- LOG.error(_LE("Error running SSH command."))
- raise
+ except putils.ProcessExecutionError as e:
+ if 'Failed to establish SSC connection' in e.stderr:
+ LOG.debug("SSC connection error!")
+ msg = _("Failed to establish SSC connection.")
+ raise exception.HNASConnError(msg)
+ else:
+ raise putils.ProcessExecutionError
def get_version(self, cmd, ver, ip0, user, pw):
"""Gets version information from the storage unit
LOG.debug('extend_vol: %s', out)
return out
+ @utils.retry(putils.ProcessExecutionError, retries=HNAS_SSC_RETRIES)
def add_iscsi_conn(self, cmd, ip0, user, pw, lun, hdp,
port, iqn, initiator):
"""Setup the lun on on the specified target port
import os
from xml.etree import ElementTree as ETree
+from oslo_concurrency import processutils
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, _LW
+from cinder import utils as cinder_utils
from cinder.volume import driver
from cinder.volume.drivers.hitachi import hnas_backend
from cinder.volume import utils
from cinder.volume import volume_types
-HDS_HNAS_ISCSI_VERSION = '3.0.1'
+HDS_HNAS_ISCSI_VERSION = '3.1.0'
LOG = logging.getLogger(__name__)
self.config['password'],
hdp, lun)
+ @cinder_utils.synchronized('volume_mapping')
def initialize_connection(self, volume, connector):
"""Map the created volume to connector['initiator'].
loc = arid + '.' + lun
# sps, use target if provided
iqn = target
- out = self.bend.add_iscsi_conn(self.config['hnas_cmd'],
- self.config['mgmt_ip0'],
- self.config['username'],
- self.config['password'],
- lun, _hdp, port, iqn,
- connector['initiator'])
+
+ try:
+ out = self.bend.add_iscsi_conn(self.config['hnas_cmd'],
+ self.config['mgmt_ip0'],
+ self.config['username'],
+ self.config['password'],
+ lun, _hdp, port, iqn,
+ connector['initiator'])
+ except processutils.ProcessExecutionError:
+ msg = _("Error attaching volume %s. "
+ "Target limit might be reached!") % volume['id']
+ raise exception.ISCSITargetAttachFailed(message=msg)
hnas_portal = ip + ':' + ipp
# sps need hlun, fulliqn
return {'driver_volume_type': 'iscsi', 'data': properties}
+ @cinder_utils.synchronized('volume_mapping')
def terminate_connection(self, volume, connector, **kwargs):
"""Terminate a connection to a volume.