Host class improvements

- Use the external hostname when connecting to remote hosts
- Make it possible to specify working directory for remote commands
- Move kinit calls to installation code
  This allows tests where installation is done later
- Log at error level when a remote command fails unexpectedly
- Clean up test directory before testing
- Break infinite recursion in mkdir_recursive if dir can't be created
This commit is contained in:
Petr Viktorin
2013-06-11 20:22:19 -04:00
parent 846ae2b3f4
commit a02890526e
3 changed files with 34 additions and 15 deletions

View File

@@ -62,7 +62,6 @@ class IntegrationTest(object):
try: try:
cls.install() cls.install()
cls.kinit_all()
except: except:
cls.uninstall() cls.uninstall()
raise raise
@@ -91,12 +90,6 @@ class IntegrationTest(object):
else: else:
raise ValueError('Unknown topology %s' % cls.topology) raise ValueError('Unknown topology %s' % cls.topology)
@classmethod
def kinit_all(cls):
for host in cls.get_all_hosts():
host.run_command(['kinit', 'admin'],
stdin_text=host.config.admin_password)
@classmethod @classmethod
def teardown_class(cls): def teardown_class(cls):
try: try:
@@ -117,7 +110,7 @@ class IntegrationTest(object):
@classmethod @classmethod
def collect_log(cls, host, filename): def collect_log(cls, host, filename):
cls.log.info('Adding %s:%s to list of logs to collect' % cls.log.info('Adding %s:%s to list of logs to collect' %
(host.hostname, filename)) (host.external_hostname, filename))
cls.logs_to_collect.setdefault(host, []).append(filename) cls.logs_to_collect.setdefault(host, []).append(filename)
IntegrationTest.log = log_mgr.get_logger(IntegrationTest()) IntegrationTest.log = log_mgr.get_logger(IntegrationTest())

View File

@@ -95,9 +95,11 @@ class RemoteCommand(object):
self._done = True self._done = True
self.log.info('Exit code: %s', self.returncode)
if raiseonerr and self.returncode: if raiseonerr and self.returncode:
self.log.error('Exit code: %s', self.returncode)
raise subprocess.CalledProcessError(self.returncode, self.argv) raise subprocess.CalledProcessError(self.returncode, self.argv)
else:
self.log.info('Exit code: %s', self.returncode)
return self.returncode return self.returncode
def _start_pipe_thread(self, result_list, stream, name, do_log=True): def _start_pipe_thread(self, result_list, stream, name, do_log=True):
@@ -187,7 +189,8 @@ class Host(object):
return env return env
def run_command(self, argv, set_env=True, stdin_text=None, def run_command(self, argv, set_env=True, stdin_text=None,
log_stdout=True, raiseonerr=True): log_stdout=True, raiseonerr=True,
cwd=None):
"""Run the given command on this host """Run the given command on this host
Returns a RemoteCommand instance. The command will have already run Returns a RemoteCommand instance. The command will have already run
@@ -208,8 +211,13 @@ class Host(object):
log_stdout=log_stdout) log_stdout=log_stdout)
self._command_index += 1 self._command_index += 1
if cwd is None:
cwd = self.config.test_dir
command.stdin.write('cd %s\n' % ipautil.shell_quote(cwd))
if set_env: if set_env:
command.stdin.write('. %s\n' % self.env_sh_path) command.stdin.write('. %s\n' %
ipautil.shell_quote(self.env_sh_path))
command.stdin.write('set -e\n') command.stdin.write('set -e\n')
if isinstance(argv, basestring): if isinstance(argv, basestring):
@@ -234,7 +242,8 @@ class Host(object):
try: try:
return self._transport return self._transport
except AttributeError: except AttributeError:
sock = socket.create_connection((self.hostname, self.ssh_port)) sock = socket.create_connection((self.external_hostname,
self.ssh_port))
self._transport = transport = paramiko.Transport(sock) self._transport = transport = paramiko.Transport(sock)
transport.connect(hostkey=self.host_key) transport.connect(hostkey=self.host_key)
if self.root_ssh_key_filename: if self.root_ssh_key_filename:
@@ -249,6 +258,8 @@ class Host(object):
else: else:
self.log.critical('No SSH credentials configured') self.log.critical('No SSH credentials configured')
raise RuntimeError('No SSH credentials configured') raise RuntimeError('No SSH credentials configured')
# Clean up the test directory
self.run_command(['rm', '-rvf', self.config.test_dir])
return transport return transport
@property @property
@@ -264,8 +275,10 @@ class Host(object):
def mkdir_recursive(self, path): def mkdir_recursive(self, path):
"""`mkdir -p` on the remote host""" """`mkdir -p` on the remote host"""
try: try:
self.sftp.chdir(path) self.sftp.chdir(path or '/')
except IOError: except IOError as e:
if not path or path == '/':
raise
self.mkdir_recursive(os.path.dirname(path)) self.mkdir_recursive(os.path.dirname(path))
self.sftp.mkdir(path) self.sftp.mkdir(path)
self.sftp.chdir(path) self.sftp.chdir(path)
@@ -280,7 +293,7 @@ class Host(object):
"""Write the given string to the named remote file""" """Write the given string to the named remote file"""
self.log.info('WRITE %s', filename) self.log.info('WRITE %s', filename)
with self.sftp.open(filename, 'w') as f: with self.sftp.open(filename, 'w') as f:
return f.write(contents) f.write(contents)
def file_exists(self, filename): def file_exists(self, filename):
"""Return true if the named remote file exists""" """Return true if the named remote file exists"""
@@ -293,3 +306,11 @@ class Host(object):
else: else:
raise raise
return True return True
def get_file(self, remotepath, localpath):
self.log.info('GET %s', remotepath)
self.sftp.get(remotepath, localpath)
def put_file(self, localpath, remotepath):
self.log.info('PUT %s', remotepath)
self.sftp.put(localpath, remotepath)

View File

@@ -148,6 +148,8 @@ def install_master(host, collect_log=None):
enable_replication_debugging(host) enable_replication_debugging(host)
host.run_command(['kinit', 'admin'],
stdin_text=host.config.admin_password)
def install_replica(master, replica, collect_log=None): def install_replica(master, replica, collect_log=None):
if collect_log: if collect_log:
@@ -173,6 +175,9 @@ def install_replica(master, replica, collect_log=None):
enable_replication_debugging(replica) enable_replication_debugging(replica)
replica.run_command(['kinit', 'admin'],
stdin_text=replica.config.admin_password)
def connect_replica(master, replica=None): def connect_replica(master, replica=None):
if replica is None: if replica is None: