# License for the specific language governing permissions and limitations
# under the License.
+import random
import time
+import mock
import mox
from oslo_concurrency import processutils
import paramiko
from cinder import context
from cinder import exception
from cinder.openstack.common import log as logging
+from cinder import ssh_utils
from cinder import test
+from cinder import utils
from cinder.volume import configuration as conf
from cinder.volume.drivers import eqlx
-
LOG = logging.getLogger(__name__)
self.configuration.san_password = "bar"
self.configuration.san_ssh_port = 16022
self.configuration.san_thin_provision = True
+ self.configuration.san_private_key = 'foo'
+ self.configuration.ssh_min_pool_conn = 1
+ self.configuration.ssh_max_pool_conn = 5
+ self.configuration.ssh_conn_timeout = 30
self.configuration.eqlx_pool = 'non-default'
self.configuration.eqlx_use_chap = True
self.configuration.eqlx_group_name = 'group-0'
self.assertRaises(processutils.ProcessExecutionError,
self.driver._ssh_execute, ssh, cmd)
+ def test_ensure_retries(self):
+ num_attempts = random.randint(1, 5)
+ self.driver.configuration.eqlx_cli_max_retries = num_attempts
+
+ self.mock_object(self.driver, '_ssh_execute',
+ mock.Mock(side_effect=exception.
+ VolumeBackendAPIException("some error")))
+ # mocks for calls in _run_ssh
+ self.mock_object(utils, 'check_ssh_injection')
+ self.mock_object(ssh_utils, 'SSHPool')
+
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=1)
+ self.mock_object(sshpool.item(), 'close')
+ self.driver.sshpool = mock.Mock(return_value=sshpool)
+ # now call the execute
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver._eql_execute, "fake command")
+ self.assertEqual(num_attempts + 1,
+ self.driver._ssh_execute.call_count)
+
+ def test_ensure_retries_on_channel_timeout(self):
+
+ num_attempts = random.randint(1, 5)
+ self.driver.configuration.eqlx_cli_max_retries = num_attempts
+
+ # mocks for calls and objects in _run_ssh
+ self.mock_object(utils, 'check_ssh_injection')
+ self.mock_object(ssh_utils, 'SSHPool')
+
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=1)
+ self.mock_object(sshpool.item(), 'close')
+ self.driver.sshpool = mock.Mock(return_value=sshpool)
+ # mocks for _ssh_execute and _get_output
+ self.mock_object(self.driver, '_get_output',
+ mock.Mock(side_effect=exception.
+ VolumeBackendAPIException("some error")))
+ # now call the execute
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver._eql_execute, "fake command")
+ self.assertEqual(num_attempts + 1, self.driver._get_output.call_count)
+
def test_with_timeout(self):
@eqlx.with_timeout
def no_timeout(cmd, *args, **kwargs):
# has closed the connection.
msg = _("The EQL array has closed the connection.")
LOG.error(msg)
- raise processutils.ProcessExecutionError(description=msg)
+ raise exception.VolumeBackendAPIException(data=msg)
out += ret
LOG.debug("CLI output\n%s", out)
max_size=max_size)
try:
total_attempts = attempts
- with self.sshpool.item() as ssh:
- while attempts > 0:
- attempts -= 1
- try:
- LOG.info(_LI('EQL-driver: executing "%s".'), command)
- return self._ssh_execute(
- ssh, command,
- timeout=self.configuration.eqlx_cli_timeout)
- except processutils.ProcessExecutionError:
- raise
- except Exception as e:
- LOG.exception(e)
- greenthread.sleep(random.randint(20, 500) / 100.0)
- msg = (_("SSH Command failed after '%(total_attempts)r' "
- "attempts : '%(command)s'") %
- {'total_attempts': total_attempts, 'command': command})
- raise exception.VolumeBackendAPIException(data=msg)
+ ssh = self.sshpool.item()
+ while attempts > 0:
+ attempts -= 1
+ try:
+ LOG.info(_LI('EQL-driver: executing "%s".'), command)
+ return self._ssh_execute(
+ ssh, command,
+ timeout=self.configuration.eqlx_cli_timeout)
+ except processutils.ProcessExecutionError:
+ raise
+ except Exception as e:
+ LOG.exception(e)
+ greenthread.sleep(random.randint(20, 500) / 100.0)
+ msg = (_("SSH Command failed after '%(total_attempts)r' "
+ "attempts : '%(command)s'") %
+ {'total_attempts': total_attempts - attempts,
+ 'command': command})
+ ssh.close()
+ raise exception.VolumeBackendAPIException(data=msg)
except Exception:
with excutils.save_and_reraise_exception():