diff --git a/lib/ansible/connection.py b/lib/ansible/connection.py index 857d06efb14..ed7b2a13905 100755 --- a/lib/ansible/connection.py +++ b/lib/ansible/connection.py @@ -19,7 +19,9 @@ ################################################ import paramiko +import traceback import os +import time from ansible import errors ################################################ @@ -53,41 +55,50 @@ class ParamikoConnection(object): self.runner = runner self.host = host - def connect(self): - ''' connect to the remote host ''' - - self.ssh = paramiko.SSHClient() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + def _get_conn(self): + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: - self.ssh.connect( - self.host, username=self.runner.remote_user, - allow_agent=True, look_for_keys=True, password=self.runner.remote_pass, + ssh.connect( + self.host, username=self.runner.remote_user, + allow_agent=True, look_for_keys=True, password=self.runner.remote_pass, timeout=self.runner.timeout, port=self.runner.remote_port ) except Exception, e: if str(e).find("PID check failed") != -1: raise errors.AnsibleError("paramiko version issue, please upgrade paramiko on the machine running ansible") - else: + else: raise errors.AnsibleConnectionFailed(str(e)) + return ssh + + + def connect(self): + ''' connect to the remote host ''' + + self.ssh = self._get_conn() return self - def exec_command(self, cmd): + def exec_command(self, cmd, sudoable=True): + ''' run a command on the remote host ''' - #if not False: - stdin, stdout, stderr = self.ssh.exec_command(cmd) - return (stdin, stdout, stderr) - #else: - # sudo_chan = self.ssh.get_transport().open_session() - # sudo_chan = chan.get_pty() - # sudo_chan.exec_command("sudo %s" % cmd) - # output = channel.makefile('rb', -1).readlines() - # if not output: - # output = channel.makefile_stderr('rb', -1).readlines() - # print "DEBUG: output: %s" % output - # channel.close() - # return (None, '', output) + if not False: # if not self.runner.sudo or not sudoable: + stdin, stdout, stderr = self.ssh.exec_command(cmd) + return (stdin, stdout, stderr) + else: + # this code is a work in progress, so it's disabled... + self.ssh.close() + ssh_sudo = self._get_conn() + sudo_chan = ssh_sudo.invoke_shell() + sudo_chan.exec_command("sudo -s") + sudo_chan.recv(1024) + sudo_chan.send("%s\n" % cmd) + # TODO: wait for ready... + out = sudo_chan.recv(1024) + sudo_chan.close() + self.ssh = self._get_conn() + return (None, "\n".join(out), '') def put_file(self, in_path, out_path): @@ -98,6 +109,7 @@ class ParamikoConnection(object): try: sftp.put(in_path, out_path) except IOError: + traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path) sftp.close() diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index afedf204d8d..caa5c3cb26f 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -73,7 +73,8 @@ class Runner(object): forks=C.DEFAULT_FORKS, timeout=C.DEFAULT_TIMEOUT, pattern=C.DEFAULT_PATTERN, remote_user=C.DEFAULT_REMOTE_USER, remote_pass=C.DEFAULT_REMOTE_PASS, remote_port=C.DEFAULT_REMOTE_PORT, background=0, basedir=None, setup_cache=None, - transport='paramiko', conditional='True', groups={}, callbacks=None, verbose=False): + transport='paramiko', conditional='True', groups={}, callbacks=None, verbose=False, + sudo=True): # FIXME FIXME FIXME if setup_cache is None: setup_cache = {} @@ -106,7 +107,8 @@ class Runner(object): self.remote_pass = remote_pass self.remote_port = remote_port self.background = background - self.basedir = basedir + self.basedir = basedir + self.sudo = sudo self._tmp_paths = {} random.seed() @@ -243,13 +245,6 @@ class Runner(object): # ***************************************************** - def _transfer_file(self, conn, source, dest): - ''' transfers a remote file ''' - - conn.put_file(source, dest) - - # ***************************************************** - def _transfer_module(self, conn, tmp, module): ''' transfers a module file to the remote side to execute it, but does not execute it yet ''' @@ -269,7 +264,7 @@ class Runner(object): args_fo.close() args_remote = os.path.join(tmp, 'arguments') - self._transfer_file(conn, args_file, args_remote) + conn.put_file(args_file, args_remote) os.unlink(args_file) return args_remote @@ -435,7 +430,7 @@ class Runner(object): # transfer the file to a remote tmp location tmp_src = tmp + source.split('/')[-1] - self._transfer_file(conn, utils.path_dwim(self.basedir, source), tmp_src) + conn.put_file(utils.path_dwim(self.basedir, source), tmp_src) # install the copy module self.module_name = 'copy' @@ -487,7 +482,7 @@ class Runner(object): # first copy the source template over temppath = tmp + os.path.split(source)[-1] - self._transfer_file(conn, utils.path_dwim(self.basedir, source), temppath) + conn.put_file(utils.path_dwim(self.basedir, source), temppath) # install the template module template_module = self._transfer_module(conn, tmp, 'template') @@ -531,6 +526,7 @@ class Runner(object): tmp = self._get_tmp_path(conn) result = None + if self.module_name == 'copy': result = self._execute_copy(conn, host, tmp) elif self.module_name == 'template': @@ -559,23 +555,28 @@ class Runner(object): # ***************************************************** - def _exec_command(self, conn, cmd): + def _exec_command(self, conn, cmd, sudoable=False): ''' execute a command string over SSH, return the output ''' msg = '%s: %s' % (self.module_name, cmd) # log remote command execution conn.exec_command('/usr/bin/logger -t ansible -p auth.info "%s"' % msg) # now run actual command - stdin, stdout, stderr = conn.exec_command(cmd) - return "\n".join(stdout.readlines()) + stdin, stdout, stderr = conn.exec_command(cmd, sudoable=sudoable) + if type(stdout) != str: + return "\n".join(stdout.readlines()) + else: + return stdout # ***************************************************** def _get_tmp_path(self, conn): ''' gets a temporary path on a remote box ''' - result = self._exec_command(conn, "mktemp -d /tmp/ansible.XXXXXX") - return result.split("\n")[0] + '/' + result = self._exec_command(conn, "mktemp -d /tmp/ansible.XXXXXX", sudoable=False) + cleaned = result.split("\n")[0].strip() + '/' + return cleaned + # *****************************************************