--- /dev/null
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 Justin Santa Barbara
+# Copyright 2014 Red Hat, Inc.
+# 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.
+
+"""Utilities related to SSH connection management."""
+
+import os.path
+
+from eventlet import pools
+import paramiko
+
+from cinder import exception
+from cinder.openstack.common.gettextutils import _
+from cinder.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+class SSHPool(pools.Pool):
+ """A simple eventlet pool to hold ssh connections."""
+
+ def __init__(self, ip, port, conn_timeout, login, password=None,
+ privatekey=None, *args, **kwargs):
+ self.ip = ip
+ self.port = port
+ self.login = login
+ self.password = password
+ self.conn_timeout = conn_timeout if conn_timeout else None
+ self.privatekey = privatekey
+ if 'missing_key_policy' in kwargs.keys():
+ self.missing_key_policy = kwargs.pop('missing_key_policy')
+ else:
+ self.missing_key_policy = paramiko.AutoAddPolicy()
+ if 'hosts_key_file' in kwargs.keys():
+ self.hosts_key_file = kwargs.pop('hosts_key_file')
+ else:
+ self.hosts_key_file = None
+ super(SSHPool, self).__init__(*args, **kwargs)
+
+ def create(self):
+ try:
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(self.missing_key_policy)
+ if not self.hosts_key_file:
+ ssh.load_system_host_keys()
+ else:
+ ssh.load_host_keys(self.hosts_key_file)
+ if self.password:
+ ssh.connect(self.ip,
+ port=self.port,
+ username=self.login,
+ password=self.password,
+ timeout=self.conn_timeout)
+ elif self.privatekey:
+ pkfile = os.path.expanduser(self.privatekey)
+ privatekey = paramiko.RSAKey.from_private_key_file(pkfile)
+ ssh.connect(self.ip,
+ port=self.port,
+ username=self.login,
+ pkey=privatekey,
+ timeout=self.conn_timeout)
+ else:
+ msg = _("Specify a password or private_key")
+ raise exception.CinderException(msg)
+
+ # Paramiko by default sets the socket timeout to 0.1 seconds,
+ # ignoring what we set through the sshclient. This doesn't help for
+ # keeping long lived connections. Hence we have to bypass it, by
+ # overriding it after the transport is initialized. We are setting
+ # the sockettimeout to None and setting a keepalive packet so that,
+ # the server will keep the connection open. All that does is send
+ # a keepalive packet every ssh_conn_timeout seconds.
+ if self.conn_timeout:
+ transport = ssh.get_transport()
+ transport.sock.settimeout(None)
+ transport.set_keepalive(self.conn_timeout)
+ return ssh
+ except Exception as e:
+ msg = _("Error connecting via ssh: %s") % e
+ LOG.error(msg)
+ raise paramiko.SSHException(msg)
+
+ def get(self):
+ """Return an item from the pool, when one is available.
+
+ This may cause the calling greenthread to block. Check if a
+ connection is active before returning it.
+
+ For dead connections create and return a new connection.
+ """
+ conn = super(SSHPool, self).get()
+ if conn:
+ if conn.get_transport().is_active():
+ return conn
+ else:
+ conn.close()
+ return self.create()
+
+ def remove(self, ssh):
+ """Close an ssh client and remove it from free_items."""
+ ssh.close()
+ ssh = None
+ if ssh in self.free_items:
+ self.free_items.pop(ssh)
+ if self.current_size > 0:
+ self.current_size -= 1
from cinder import context
from cinder import exception
+from cinder import ssh_utils
from cinder import test
-from cinder import utils
from cinder.volume import configuration as conf
from cinder.volume.drivers.huawei import huawei_utils
from cinder.volume.drivers.huawei import HuaweiVolumeDriver
self.configuration.append_config_values(mox.IgnoreArg())
self.stubs.Set(time, 'sleep', Fake_sleep)
- self.stubs.Set(utils, 'SSHPool', FakeSSHPool)
+ self.stubs.Set(ssh_utils, 'SSHPool', FakeSSHPool)
self.stubs.Set(ssh_common.TseriesCommon, '_change_file_mode',
Fake_change_file_mode)
self._init_driver()
self.configuration.append_config_values(mox.IgnoreArg())
self.stubs.Set(time, 'sleep', Fake_sleep)
- self.stubs.Set(utils, 'SSHPool', FakeSSHPool)
+ self.stubs.Set(ssh_utils, 'SSHPool', FakeSSHPool)
self.stubs.Set(ssh_common.TseriesCommon, '_change_file_mode',
Fake_change_file_mode)
self._init_driver()
self.configuration.append_config_values(mox.IgnoreArg())
self.stubs.Set(time, 'sleep', Fake_sleep)
- self.stubs.Set(utils, 'SSHPool', FakeSSHPool)
+ self.stubs.Set(ssh_utils, 'SSHPool', FakeSSHPool)
self.stubs.Set(ssh_common.TseriesCommon, '_change_file_mode',
Fake_change_file_mode)
Curr_test[0] = 'T'
from cinder import exception
from cinder.openstack.common import processutils as putils
from cinder.openstack.common import timeutils
+from cinder import ssh_utils
from cinder import test
from cinder import utils
mock_sshclient.return_value = FakeSSHClient()
# create with customized setting
- sshpool = utils.SSHPool("127.0.0.1", 22, 10,
- "test",
- password="test",
- min_size=1,
- max_size=1,
- missing_key_policy=paramiko.RejectPolicy(),
- hosts_key_file='dummy_host_keyfile')
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=1,
+ missing_key_policy=paramiko.RejectPolicy(),
+ hosts_key_file='dummy_host_keyfile')
with sshpool.item() as ssh:
self.assertTrue(isinstance(ssh.get_policy(),
paramiko.RejectPolicy))
self.assertEqual(ssh.hosts_key_file, 'dummy_host_keyfile')
# create with default setting
- sshpool = utils.SSHPool("127.0.0.1", 22, 10,
- "test",
- password="test",
- min_size=1,
- max_size=1)
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=1)
with sshpool.item() as ssh:
self.assertTrue(isinstance(ssh.get_policy(),
paramiko.AutoAddPolicy))
mock_sshclient.return_value = FakeSSHClient()
# create with password
- sshpool = utils.SSHPool("127.0.0.1", 22, 10,
- "test",
- password="test",
- min_size=1,
- max_size=1)
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=1)
with sshpool.item() as ssh:
first_id = ssh.id
mock_sshclient.connect.assert_called_once()
# create with private key
- sshpool = utils.SSHPool("127.0.0.1", 22, 10,
- "test",
- privatekey="test",
- min_size=1,
- max_size=1)
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ privatekey="test",
+ min_size=1,
+ max_size=1)
mock_sshclient.connect.assert_called_once()
# attempt to create with no password or private key
self.assertRaises(paramiko.SSHException,
- utils.SSHPool,
+ ssh_utils.SSHPool,
"127.0.0.1", 22, 10,
"test",
min_size=1,
@mock.patch('paramiko.SSHClient')
def test_closed_reopend_ssh_connections(self, mock_sshclient):
mock_sshclient.return_value = eval('FakeSSHClient')()
- sshpool = utils.SSHPool("127.0.0.1", 22, 10,
- "test",
- password="test",
- min_size=1,
- max_size=4)
+ sshpool = ssh_utils.SSHPool("127.0.0.1", 22, 10,
+ "test",
+ password="test",
+ min_size=1,
+ max_size=4)
with sshpool.item() as ssh:
mock_sshclient.reset_mock()
first_id = ssh.id
import tempfile
from Crypto.Random import random
-from eventlet import pools
from oslo.config import cfg
-import paramiko
import six
from xml.dom import minidom
from xml.parsers import expat
return channel
-class SSHPool(pools.Pool):
- """A simple eventlet pool to hold ssh connections."""
-
- def __init__(self, ip, port, conn_timeout, login, password=None,
- privatekey=None, *args, **kwargs):
- self.ip = ip
- self.port = port
- self.login = login
- self.password = password
- self.conn_timeout = conn_timeout if conn_timeout else None
- self.privatekey = privatekey
- if 'missing_key_policy' in kwargs.keys():
- self.missing_key_policy = kwargs.pop('missing_key_policy')
- else:
- self.missing_key_policy = paramiko.AutoAddPolicy()
- if 'hosts_key_file' in kwargs.keys():
- self.hosts_key_file = kwargs.pop('hosts_key_file')
- else:
- self.hosts_key_file = None
- super(SSHPool, self).__init__(*args, **kwargs)
-
- def create(self):
- try:
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(self.missing_key_policy)
- if not self.hosts_key_file:
- ssh.load_system_host_keys()
- else:
- ssh.load_host_keys(self.hosts_key_file)
- if self.password:
- ssh.connect(self.ip,
- port=self.port,
- username=self.login,
- password=self.password,
- timeout=self.conn_timeout)
- elif self.privatekey:
- pkfile = os.path.expanduser(self.privatekey)
- privatekey = paramiko.RSAKey.from_private_key_file(pkfile)
- ssh.connect(self.ip,
- port=self.port,
- username=self.login,
- pkey=privatekey,
- timeout=self.conn_timeout)
- else:
- msg = _("Specify a password or private_key")
- raise exception.CinderException(msg)
-
- # Paramiko by default sets the socket timeout to 0.1 seconds,
- # ignoring what we set through the sshclient. This doesn't help for
- # keeping long lived connections. Hence we have to bypass it, by
- # overriding it after the transport is initialized. We are setting
- # the sockettimeout to None and setting a keepalive packet so that,
- # the server will keep the connection open. All that does is send
- # a keepalive packet every ssh_conn_timeout seconds.
- if self.conn_timeout:
- transport = ssh.get_transport()
- transport.sock.settimeout(None)
- transport.set_keepalive(self.conn_timeout)
- return ssh
- except Exception as e:
- msg = _("Error connecting via ssh: %s") % e
- LOG.error(msg)
- raise paramiko.SSHException(msg)
-
- def get(self):
- """Return an item from the pool, when one is available.
-
- This may cause the calling greenthread to block. Check if a
- connection is active before returning it.
-
- For dead connections create and return a new connection.
- """
- conn = super(SSHPool, self).get()
- if conn:
- if conn.get_transport().is_active():
- return conn
- else:
- conn.close()
- return self.create()
-
- def remove(self, ssh):
- """Close an ssh client and remove it from free_items."""
- ssh.close()
- ssh = None
- if ssh in self.free_items:
- self.free_items.pop(ssh)
- if self.current_size > 0:
- self.current_size -= 1
-
-
def cinderdir():
import cinder
return os.path.abspath(cinder.__file__).split('cinder/__init__.py')[0]
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
from cinder.openstack.common import processutils
+from cinder import ssh_utils
from cinder import utils
from cinder.volume.drivers.san import SanISCSIDriver
privatekey = self.configuration.san_private_key
min_size = self.configuration.ssh_min_pool_conn
max_size = self.configuration.ssh_max_pool_conn
- self.sshpool = utils.SSHPool(self.configuration.san_ip,
- self.configuration.san_ssh_port,
- self.configuration.ssh_conn_timeout,
- self.configuration.san_login,
- password=password,
- privatekey=privatekey,
- min_size=min_size,
- max_size=max_size)
+ self.sshpool = ssh_utils.SSHPool(
+ self.configuration.san_ip,
+ self.configuration.san_ssh_port,
+ self.configuration.ssh_conn_timeout,
+ self.configuration.san_login,
+ password=password,
+ privatekey=privatekey,
+ min_size=min_size,
+ max_size=max_size)
try:
total_attempts = attempts
with self.sshpool.item() as ssh:
from cinder.openstack.common import excutils
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
+from cinder import ssh_utils
from cinder import utils
from cinder.volume.drivers.huawei import huawei_utils
from cinder.volume import volume_types
user = self.login_info['UserName']
pwd = self.login_info['UserPassword']
if not self.ssh_pool:
- self.ssh_pool = utils.SSHPool(ip0, 22, 30, user, pwd, max_size=2)
+ self.ssh_pool = ssh_utils.SSHPool(ip0, 22, 30, user, pwd,
+ max_size=2)
ssh_client = None
while True:
try:
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
from cinder.openstack.common import processutils
+from cinder import ssh_utils
from cinder import utils
from cinder.volume import driver
privatekey = self.configuration.san_private_key
min_size = self.configuration.ssh_min_pool_conn
max_size = self.configuration.ssh_max_pool_conn
- self.sshpool = utils.SSHPool(self.configuration.san_ip,
- self.configuration.san_ssh_port,
- self.configuration.ssh_conn_timeout,
- self.configuration.san_login,
- password=password,
- privatekey=privatekey,
- min_size=min_size,
- max_size=max_size)
+ self.sshpool = ssh_utils.SSHPool(
+ self.configuration.san_ip,
+ self.configuration.san_ssh_port,
+ self.configuration.ssh_conn_timeout,
+ self.configuration.san_login,
+ password=password,
+ privatekey=privatekey,
+ min_size=min_size,
+ max_size=max_size)
last_exception = None
try:
with self.sshpool.item() as ssh:
from cinder.openstack.common.gettextutils import _
from cinder.openstack.common import log as logging
from cinder.openstack.common import processutils
+from cinder import ssh_utils
from cinder import utils
import cinder.zonemanager.drivers.brocade.fc_zone_constants as ZoneConstant
command = ' '. join(cmd_list)
if not self.sshpool:
- self.sshpool = utils.SSHPool(self.switch_ip,
- self.switch_port,
- None,
- self.switch_user,
- self.switch_pwd,
- min_size=1,
- max_size=5)
+ self.sshpool = ssh_utils.SSHPool(self.switch_ip,
+ self.switch_port,
+ None,
+ self.switch_user,
+ self.switch_pwd,
+ min_size=1,
+ max_size=5)
last_exception = None
try:
with self.sshpool.item() as ssh:
command = ' '. join(cmd_list)
if not self.sshpool:
- self.sshpool = utils.SSHPool(self.switch_ip,
- self.switch_port,
- None,
- self.switch_user,
- self.switch_pwd,
- min_size=1,
- max_size=5)
+ self.sshpool = ssh_utils.SSHPool(self.switch_ip,
+ self.switch_port,
+ None,
+ self.switch_user,
+ self.switch_pwd,
+ min_size=1,
+ max_size=5)
stdin, stdout, stderr = None, None, None
LOG.debug("Executing command via ssh: %s" % command)
last_exception = None
command = ' '. join(cmd)
stdout, stderr = None, None
if not self.sshpool:
- self.sshpool = utils.SSHPool(self.switch_ip,
- self.switch_port,
- None,
- self.switch_user,
- self.switch_pwd,
- min_size=1,
- max_size=5)
+ self.sshpool = ssh_utils.SSHPool(self.switch_ip,
+ self.switch_port,
+ None,
+ self.switch_user,
+ self.switch_pwd,
+ min_size=1,
+ max_size=5)
with self.sshpool.item() as ssh:
LOG.debug('Running cmd (SSH): %s' % command)
channel = ssh.invoke_shell()