Initial movement to new repo with cleanup
diff --git a/heat_tempest_plugin/common/remote_client.py b/heat_tempest_plugin/common/remote_client.py
new file mode 100644
index 0000000..f23622b
--- /dev/null
+++ b/heat_tempest_plugin/common/remote_client.py
@@ -0,0 +1,202 @@
+# 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.
+
+import re
+import select
+import socket
+import time
+
+from oslo_log import log as logging
+import paramiko
+import six
+
+from heat_tempest_plugin.common import exceptions
+
+LOG = logging.getLogger(__name__)
+
+
+class Client(object):
+
+ def __init__(self, host, username, password=None, timeout=300, pkey=None,
+ channel_timeout=10, look_for_keys=False, key_filename=None):
+ self.host = host
+ self.username = username
+ self.password = password
+ if isinstance(pkey, six.string_types):
+ pkey = paramiko.RSAKey.from_private_key(
+ six.moves.cStringIO(str(pkey)))
+ self.pkey = pkey
+ self.look_for_keys = look_for_keys
+ self.key_filename = key_filename
+ self.timeout = int(timeout)
+ self.channel_timeout = float(channel_timeout)
+ self.buf_size = 1024
+
+ def _get_ssh_connection(self, sleep=1.5, backoff=1):
+ """Returns an ssh connection to the specified host."""
+ bsleep = sleep
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(
+ paramiko.AutoAddPolicy())
+ _start_time = time.time()
+ if self.pkey is not None:
+ LOG.info("Creating ssh connection to '%s' as '%s'"
+ " with public key authentication",
+ self.host, self.username)
+ else:
+ LOG.info("Creating ssh connection to '%s' as '%s'"
+ " with password %s",
+ self.host, self.username, str(self.password))
+ attempts = 0
+ while True:
+ try:
+ ssh.connect(self.host, username=self.username,
+ password=self.password,
+ look_for_keys=self.look_for_keys,
+ key_filename=self.key_filename,
+ timeout=self.channel_timeout, pkey=self.pkey)
+ LOG.info("ssh connection to %s@%s successfuly created",
+ self.username, self.host)
+ return ssh
+ except (socket.error,
+ paramiko.SSHException) as e:
+ if self._is_timed_out(_start_time):
+ LOG.exception("Failed to establish authenticated ssh"
+ " connection to %s@%s after %d attempts",
+ self.username, self.host, attempts)
+ raise exceptions.SSHTimeout(host=self.host,
+ user=self.username,
+ password=self.password)
+ bsleep += backoff
+ attempts += 1
+ LOG.warning("Failed to establish authenticated ssh"
+ " connection to %s@%s (%s). Number attempts: %s."
+ " Retry after %d seconds.",
+ self.username, self.host, e, attempts, bsleep)
+ time.sleep(bsleep)
+
+ def _is_timed_out(self, start_time):
+ return (time.time() - self.timeout) > start_time
+
+ def exec_command(self, cmd):
+ """Execute the specified command on the server.
+
+ Note that this method is reading whole command outputs to memory, thus
+ shouldn't be used for large outputs.
+
+ :returns: data read from standard output of the command.
+ :raises: SSHExecCommandFailed if command returns nonzero
+ status. The exception contains command status stderr content.
+ """
+ ssh = self._get_ssh_connection()
+ transport = ssh.get_transport()
+ channel = transport.open_session()
+ channel.fileno() # Register event pipe
+ channel.exec_command(cmd)
+ channel.shutdown_write()
+ out_data = []
+ err_data = []
+ poll = select.poll()
+ poll.register(channel, select.POLLIN)
+ start_time = time.time()
+
+ while True:
+ ready = poll.poll(self.channel_timeout)
+ if not any(ready):
+ if not self._is_timed_out(start_time):
+ continue
+ raise exceptions.TimeoutException(
+ "Command: '{0}' executed on host '{1}'.".format(
+ cmd, self.host))
+ if not ready[0]: # If there is nothing to read.
+ continue
+ out_chunk = err_chunk = None
+ if channel.recv_ready():
+ out_chunk = channel.recv(self.buf_size)
+ out_data += out_chunk,
+ if channel.recv_stderr_ready():
+ err_chunk = channel.recv_stderr(self.buf_size)
+ err_data += err_chunk,
+ if channel.closed and not err_chunk and not out_chunk:
+ break
+ exit_status = channel.recv_exit_status()
+ if 0 != exit_status:
+ raise exceptions.SSHExecCommandFailed(
+ command=cmd, exit_status=exit_status,
+ strerror=''.join(err_data))
+ return ''.join(out_data)
+
+ def test_connection_auth(self):
+ """Raises an exception when we can not connect to server via ssh."""
+ connection = self._get_ssh_connection()
+ connection.close()
+
+
+class RemoteClient(object):
+
+ # NOTE(afazekas): It should always get an address instead of server
+ def __init__(self, server, username, password=None, pkey=None,
+ conf=None):
+ self.conf = conf
+ ssh_timeout = self.conf.ssh_timeout
+ network = self.conf.network_for_ssh
+ ip_version = self.conf.ip_version_for_ssh
+ ssh_channel_timeout = self.conf.ssh_channel_timeout
+ if isinstance(server, six.string_types):
+ ip_address = server
+ else:
+ addresses = server['addresses'][network]
+ for address in addresses:
+ if address['version'] == ip_version:
+ ip_address = address['addr']
+ break
+ else:
+ raise exceptions.ServerUnreachable()
+ self.ssh_client = Client(ip_address, username, password,
+ ssh_timeout, pkey=pkey,
+ channel_timeout=ssh_channel_timeout)
+
+ def exec_command(self, cmd):
+ return self.ssh_client.exec_command(cmd)
+
+ def validate_authentication(self):
+ """Validate ssh connection and authentication.
+
+ This method raises an Exception when the validation fails.
+ """
+ self.ssh_client.test_connection_auth()
+
+ def get_partitions(self):
+ # Return the contents of /proc/partitions
+ command = 'cat /proc/partitions'
+ output = self.exec_command(command)
+ return output
+
+ def get_boot_time(self):
+ cmd = 'cut -f1 -d. /proc/uptime'
+ boot_secs = self.exec_command(cmd)
+ boot_time = time.time() - int(boot_secs)
+ return time.localtime(boot_time)
+
+ def write_to_console(self, message):
+ message = re.sub("([$\\`])", "\\\\\\\\\\1", message)
+ # usually to /dev/ttyS0
+ cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
+ return self.exec_command(cmd)
+
+ def ping_host(self, host):
+ cmd = 'ping -c1 -w1 %s' % host
+ return self.exec_command(cmd)
+
+ def get_ip_list(self):
+ cmd = "/bin/ip address"
+ return self.exec_command(cmd)