def fetch_file(self, in_path, out_path): ''' save a remote file to the specified path ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) try: self.sftp = self._connect_sftp() except Exception, e: raise errors.AnsibleError("failed to open a SFTP connection (%s)", e)
def fetch_file(self, in_path, out_path): ''' fetch a file from zone to local ''' in_path = self._normalize_path(in_path, self.get_zone_path()) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.zone) self._copy_file(in_path, out_path)
def put_file(self, in_path, out_path): """ transfer a file from local to remote """ vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) cmd = self._password_cmd() host = self.host if self.ipv6: host = "[%s]" % host if C.DEFAULT_SCP_IF_SSH: cmd += ["scp"] + self.common_args cmd += [in_path, host + ":" + pipes.quote(out_path)] indata = None else: cmd += ["sftp"] + self.common_args + [host] indata = "put %s %s\n" % (pipes.quote(in_path), pipes.quote(out_path)) (p, stdin) = self._run(cmd, indata) self._send_password() (returncode, stdout, stderr) = self._communicate(p, stdin, indata) if returncode != 0: raise errors.AnsibleError("failed to transfer file to %s:\n%s\n%s" % (out_path, stdout, stderr))
def fetch_file(self, in_path, out_path): vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) cmd = self._password_cmd() host = self.host if self.ipv6: host = '[%s]' % host remote_cmd, prompt, success_key = self._su_sudo_cmd( self._lxc_cmd('cat %s' % pipes.quote(in_path)) ) cmd = self._password_cmd() cmd += ['ssh'] + self.common_args + [host, remote_cmd] (p, stdin) = self._run(cmd, True) self._send_password() if (self.runner.sudo and self.runner.sudo_pass) or \ (self.runner.su and self.runner.su_pass): (no_prompt_out, no_prompt_err) = self.send_su_sudo_password(p, stdin, success_key, True, prompt) try: outfile = open(out_path, 'w') except IOError as e: raise errors.AnsibleError('could not open destination file %s: %s' % (out_path, e)) com = self.FetchCommCB(self.runner, None, su=True, sudoable=True, prompt=prompt, outfile=outfile) returncode = self._communicate(p, stdin, callbacks=(com.stdin_cb, com.stdout_cb, com.stderr_cb)) outfile.close() if p.returncode != 0: raise errors.AnsibleError("failed to transfer file from %s:\n%s\n%s" % (in_path, com.stdout, com.stderr))
def put_file(self, in_path, out_path): ''' transfer a file from local to zone ''' out_path = self._normalize_path(out_path, self.get_zone_path()) vvv("PUT %s TO %s" % (in_path, out_path), host=self.zone) self._copy_file(in_path, out_path)
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, become=None, become_user=None): """ Run a command on the local host """ # Don't currently support su # if su or su_user: # raise errors.AnsibleError("Internal Error: this module does not " # "support running commands via su") if in_data: raise errors.AnsibleError("Internal Error: this module does not " "support optimized module pipelining") # if sudoable and sudo_user: # raise errors.AnsibleError("Internal Error: this module does not " # "support running commands via sudo") if executable: local_cmd = [self.docker_cmd, "exec", self.host, executable, '-c', cmd] else: local_cmd = '%s exec "%s" %s' % (self.docker_cmd, self.host, cmd) vvv("EXEC %s" % (local_cmd), host=self.host) p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() return (p.returncode, '', stdout, stderr)
def fetch_file(self, in_path, out_path): ''' fetch a file from VM to local ''' if not in_path.startswith(os.path.sep): in_path = os.path.join(os.path.sep, in_path) normpath = os.path.normpath(in_path) in_path = os.path.join("/", normpath[1:]) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot) f = pipes.quote(in_path) cmd = self.produce_command("test -f %s && cat %s || exit 7" % (f,f)) try: p = subprocess.Popen( cmd, stdout = subprocess.PIPE ) out, err = p.communicate("") retval = p.wait() if retval == 7: raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) elif retval != 0: raise subprocess.CalledProcessError(retval, cmd) file(out_path, "wb").write(out) except subprocess.CalledProcessError: traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path) except IOError: traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def put_file(self, in_path, out_path): ''' transfer a file from local to VM ''' if not out_path.startswith(os.path.sep): out_path = os.path.join(os.path.sep, out_path) normpath = os.path.normpath(out_path) out_path = os.path.join("/", normpath[1:]) vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) cmd = self.produce_command("cat > %s" % pipes.quote(out_path)) try: p = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) out, _ = p.communicate(file(in_path).read()) retval = p.wait() if retval != 0: raise QubesRPCError(retval, cmd, out) except subprocess.CalledProcessError: traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) cmd = self._password_cmd() host = self.host if self.ipv6: host = '[%s]' % host if C.DEFAULT_SCP_IF_SSH: cmd += ["scp"] + self.common_args cmd += [in_path,host + ":" + pipes.quote(out_path)] indata = None else: cmd += ["sftp"] + self.common_args + [host] indata = "put %s %s\n" % (pipes.quote(in_path), pipes.quote(out_path)) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self._send_password() stdout, stderr = p.communicate(indata) if p.returncode != 0: raise errors.AnsibleError("failed to transfer file to %s:\n%s\n%s" % (out_path, stdout, stderr))
def connect(self): ''' activates the connection object ''' if not HAVE_PARAMIKO: raise errors.AnsibleError("paramiko is not installed") user = self.runner.remote_user vvv("ESTABLISH CONNECTION FOR USER: %s" % user, host=self.host) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) allow_agent = True if self.runner.remote_pass is not None: allow_agent = False try: ssh.connect(self.host, username=user, allow_agent=allow_agent, look_for_keys=True, key_filename=self.runner.private_key_file, password=self.runner.remote_pass, timeout=self.runner.timeout, port=self.port) except Exception, e: msg = str(e) if "PID check failed" in msg: raise errors.AnsibleError("paramiko version issue, please upgrade paramiko on the machine running ansible") elif "Private key file is encrypted" in msg: msg = 'ssh %s@%s:%s : %s\nTo connect as a different user, use -u <username>.' % ( user, self.host, self.port, msg) raise errors.AnsibleConnectionFailed(msg) else: raise errors.AnsibleConnectionFailed(msg)
def put_file(self, in_path, out_path): ''' transfer a file from local to chroot ''' out_path = self._normalize_path(out_path, self.get_jail_path()) vvv("PUT %s TO %s" % (in_path, out_path), host=self.jail) self._copy_file(in_path, out_path)
def fetch_file(self, in_path, out_path): ''' fetch a file from chroot to local ''' in_path = self._normalize_path(in_path, self.get_jail_path()) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.jail) self._copy_file(in_path, out_path)
def _buffered_exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None, stdin=subprocess.PIPE): ''' run a command on the chroot. This is only needed for implementing put_file() get_file() so that we don't have to read the whole file into memory. compared to exec_command() it looses some niceties like being able to return the process's exit code immediately. ''' if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported: raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method) if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") # We enter zone as root so we ignore privilege escalation (probably need to fix in case we have to become a specific used [ex: postgres admin])? local_cmd = self._generate_cmd(executable, cmd) vvv("EXEC %s" % (local_cmd), host=self.chroot) p = subprocess.Popen(local_cmd, shell=False, cwd=self.runner.basedir, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE) return p
def put_file(self, in_path, out_path): vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) host = self.host if self.ipv6: host = '[%s]' % host remote_cmd, prompt, success_key = self._su_sudo_cmd( self._lxc_cmd('cat > %s; echo -n done' % pipes.quote(out_path)) ) cmd = self._password_cmd() cmd += ['ssh'] + self.common_args + [host, remote_cmd] (p, stdin) = self._run(cmd, True) self._send_password() if (self.runner.sudo and self.runner.sudo_pass) or \ (self.runner.su and self.runner.su_pass): (no_prompt_out, no_prompt_err) = self.send_su_sudo_password(p, stdin, success_key, True, prompt) com = self.CommunicateCallbacks(self.runner, open(in_path, 'r'), su=True, sudoable=True, prompt=prompt) returncode = self._communicate(p, stdin, callbacks=(com.stdin_cb, com.stdout_cb, com.stderr_cb)) if com.stdout[-4:] != 'done': raise errors.AnsibleError("failed to transfer file to %s" % out_path) if returncode != 0: raise errors.AnsibleError("failed to transfer file to %s:\n%s\n%s" % (out_path, stdout, stderr))
def fetch_file(self, in_path, out_path): if _winrm_hacks: in_path = _winrm_hacks.fix_slashes(in_path) out_path = out_path.replace('\\', '/') vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) buffer_size = 2**20 # 1MB chunks if not os.path.exists(os.path.dirname(out_path)): os.makedirs(os.path.dirname(out_path)) with open(out_path, 'wb') as out_file: offset = 0 while True: try: script = ''' $bufferSize = %d; $stream = [System.IO.File]::OpenRead("%s"); $stream.Seek(%d, [System.IO.SeekOrigin]::Begin) | Out-Null; $buffer = New-Object Byte[] $bufferSize; $bytesRead = $stream.Read($buffer, 0, $bufferSize); $bytes = $buffer[0..($bytesRead-1)]; [System.Convert]::ToBase64String($bytes); $stream.Close() | Out-Null; ''' % (buffer_size, self._winrm_escape(in_path), offset) cmd_parts = self._winrm_get_script_cmd(script) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:]) data = base64.b64decode(result.std_out.strip()) out_file.write(data) if len(data) < buffer_size: break offset += len(data) except Exception: # IOError? traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None): ''' run a command on the remote host ''' if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") vvv("EXEC COMMAND %s" % cmd) if self.runner.sudo and sudoable: raise errors.AnsibleError( "When using fireball, do not specify sudo to run your tasks. " + "Instead sudo the fireball action with sudo. " + "Task will communicate with the fireball already running in sudo mode." ) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) return (response.get('rc',None), '', response.get('stdout',''), response.get('stderr',''))
def connect(self): ''' connect to the remote host ''' vvv("ESTABLISH CONNECTION FOR USER: %s" % self.runner.remote_user, host=self.host) self.common_args = [] extra_args = C.ANSIBLE_SSH_ARGS if extra_args is not None: self.common_args += shlex.split(extra_args) else: self.common_args += ["-o", "ControlMaster=auto", "-o", "ControlPersist=60s", "-o", "ControlPath=/tmp/ansible-ssh-%h-%p-%r"] self.common_args += ["-o", "StrictHostKeyChecking=no"] if self.port is not None: self.common_args += ["-o", "Port=%d" % (self.port)] if self.runner.private_key_file is not None: self.common_args += ["-o", "IdentityFile="+os.path.expanduser(self.runner.private_key_file)] if self.runner.remote_pass: self.common_args += ["-o", "GSSAPIAuthentication=no", "-o", "PubkeyAuthentication=no"] else: self.common_args += ["-o", "KbdInteractiveAuthentication=no", "-o", "PasswordAuthentication=no"] self.common_args += ["-o", "User="+self.runner.remote_user] return self
def put_file(self, in_path, out_path): vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) with open(in_path, 'rb') as fp: r = self.session.put(self._build_url('/upload'), data={'dest': out_path}, files={'src': fp}) if r.status_code != 200: raise errors.AnsibleError("failed to transfer file from %s" % in_path)
def connect(self, allow_ssh=True): ''' activates the connection object ''' try: if not self.is_connected: tries = 3 self.conn = socket.socket() self.conn.settimeout(constants.ACCELERATE_CONNECT_TIMEOUT) vvvv("attempting connection to %s via the accelerated port %d" % (self.host,self.accport)) while tries > 0: try: self.conn.connect((self.host,self.accport)) break except: vvvv("failed, retrying...") time.sleep(0.1) tries -= 1 if tries == 0: vvv("Could not connect via the accelerated connection, exceeded # of tries") raise errors.AnsibleError("Failed to connect") self.conn.settimeout(constants.ACCELERATE_TIMEOUT) except: if allow_ssh: vvv("Falling back to ssh to startup accelerated mode") res = self._execute_accelerate_module() if not res.is_successful(): raise errors.AnsibleError("Failed to launch the accelerated daemon on %s (reason: %s)" % (self.host,res.result.get('msg'))) return self.connect(allow_ssh=False) else: raise errors.AnsibleError("Failed to connect to %s:%s" % (self.host,self.accport)) self.is_connected = True return self
def exec_command(self, cmd, tmp_path, become_user, **kwargs): executable = kwargs.get('executable', '/bin/sh') sudoable = kwargs.get('sudoable', False) if 'su' in kwargs or 'su_user' in kwargs: raise errors.AnsibleError("Internal Error: this module does not support running commands via su") if kwargs.get('in_data'): raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") if sudoable and getattr(self.runner, 'become', False) and self.runner.become_method not in self.become_methods_supported: raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method) become = getattr(self.runner, 'become', False) or getattr(self.runner, 'sudo', False) remote_cmd = [] if not become or not sudoable: if executable: remote_cmd.append(executable + ' -c ' + pipes.quote(cmd)) else: remote_cmd.append(cmd) else: if hasattr(self.runner, 'become_exe'): becomecmd, prompt, success_key = utils.make_become_cmd(cmd, become_user, executable, self.runner.become_method, '', self.runner.become_exe) elif hasattr(self.runner, 'sudo_exe'): becomecmd, prompt, success_key = utils.make_sudo_cmd(self.runner.sudo_exe, become_user, executable, cmd) else: becomecmd, prompt, success_key = utils.make_sudo_cmd(become_user, executable, cmd) remote_cmd.append(becomecmd) remote_cmd = ' '.join(remote_cmd) vvv("execnet exec_command %r" % remote_cmd) rc, stdout, stderr = self.rpc.exec_command(remote_cmd) return (rc, '', stdout, stderr)
def put_file(self, in_path, out_path): if _winrm_hacks: out_path = _winrm_hacks.fix_slashes(out_path) vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) buffer_size = 1024 # FIXME: Find max size or optimize. with open(in_path) as in_file: in_size = os.path.getsize(in_path) for offset in xrange(0, in_size, buffer_size): try: out_data = in_file.read(buffer_size) if offset == 0: if out_data.lower().startswith('#!powershell') and not out_path.lower().endswith('.ps1'): out_path = out_path + '.ps1' b64_data = base64.b64encode(out_data) script = ''' $bufferSize = %d; $stream = [System.IO.File]::OpenWrite("%s"); $stream.Seek(%d, [System.IO.SeekOrigin]::Begin) | Out-Null; $data = "%s"; $buffer = [System.Convert]::FromBase64String($data); $stream.Write($buffer, 0, $buffer.length) | Out-Null; $stream.SetLength(%d) | Out-Null; $stream.Close() | Out-Null; ''' % (buffer_size, self._winrm_escape(out_path), offset, b64_data, in_size) cmd_parts = self._winrm_get_script_cmd(script) result = self._winrm_exec(cmd_parts[0], cmd_parts[1:]) if result.status_code != 0: raise RuntimeError(result.std_err.encode('utf-8')) script = u'' except Exception: # IOError? traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None): ''' run a command on the local host ''' # su requires to be run from a terminal, and therefore isn't supported here (yet?) if sudoable and self.runner.become and self.runner.become_method not in self.become_methods_supported: raise errors.AnsibleError("Internal Error: this module does not support running commands via %s" % self.runner.become_method) if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") if self.runner.become and sudoable: local_cmd, prompt, success_key = utils.make_become_cmd(cmd, become_user, executable, self.runner.become_method, '-H', self.runner.become_exe) else: if executable: local_cmd = executable.split() + ['-c', cmd] else: local_cmd = cmd executable = executable.split()[0] if executable else None vvv("EXEC %s" % (local_cmd), host=self.host) p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), cwd=self.runner.basedir, executable=executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.envs) if self.runner.become and sudoable and self.runner.become_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) become_output = '' while success_key not in become_output: if prompt and become_output.endswith(prompt): break if utils.su_prompts.check_su_prompt(become_output): break rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], self.runner.timeout) if p.stdout in rfd: chunk = p.stdout.read() elif p.stderr in rfd: chunk = p.stderr.read() else: stdout, stderr = p.communicate() raise errors.AnsibleError('timeout waiting for %s password prompt:\n' % self.runner.become_method + become_output) if not chunk: stdout, stderr = p.communicate() raise errors.AnsibleError('%s output closed while waiting for password prompt:\n' % self.runner.become_method + become_output) become_output += chunk if success_key not in become_output: p.stdin.write(self.runner.become_pass + '\n') fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK) stdout, stderr = p.communicate() return (p.returncode, '', stdout, stderr)
def connect(self): vvv("ESTABLISH CONNECTION FOR USER: %s" % self.user, host=self.host) self.session = requests.Session() self.session.auth = (self.user, self.password) if CERTIFICATE: self.session.cert = os.path.expanduser(CERTIFICATE) self.session.verify = False return self
def fetch_file(self, in_path, out_path): ''' fetch a file from remote to local ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) sftp_cmd = ["sftp"] + self.common_args + [self.host] p = subprocess.Popen(sftp_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate("get %s %s\n" % (in_path, out_path)) if p.returncode != 0: raise errors.AnsibleError("failed to transfer file from %s:\n%s\n%s" % (in_path, stdout, stderr))
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) try: self.sftp = self.ssh.open_sftp() except Exception, e: raise errors.AnsibleError("failed to open a SFTP connection (%s)" % e)
def put_file(self, in_path, out_path): local_cmd = ['/usr/sbin/vzctl','exec',self.ctid,'/bin/sh','-c','"','cat > %s' % format(out_path),'"'] vvv("PUT CMD %s" % (local_cmd), host=self.host) vvv("PUT %s %s" % (in_path,out_path), host=self.host) p = subprocess.Popen(local_cmd, stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) p.stdin.write(open(in_path).read()) p.stdin.close() time.sleep(1) p.terminate()
def connect(self): """ connect to the remote host """ vvv("ESTABLISH CONNECTION FOR USER: %s" % self.user, host=self.host) self.common_args = [] extra_args = C.ANSIBLE_SSH_ARGS if extra_args is not None: # make sure there is no empty string added as this can produce weird errors self.common_args += [x.strip() for x in shlex.split(extra_args) if x.strip()] else: self.common_args += [ "-o", "ControlMaster=auto", "-o", "ControlPersist=60s", "-o", 'ControlPath="%s"' % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir)), ] cp_in_use = False cp_path_set = False for arg in self.common_args: if "ControlPersist" in arg: cp_in_use = True if "ControlPath" in arg: cp_path_set = True if cp_in_use and not cp_path_set: self.common_args += ["-o", 'ControlPath="%s"' % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir))] if not C.HOST_KEY_CHECKING: self.common_args += ["-o", "StrictHostKeyChecking=no"] if self.port is not None: self.common_args += ["-o", "Port=%d" % (self.port)] if self.private_key_file is not None: self.common_args += ["-o", 'IdentityFile="%s"' % os.path.expanduser(self.private_key_file)] elif self.runner.private_key_file is not None: self.common_args += ["-o", 'IdentityFile="%s"' % os.path.expanduser(self.runner.private_key_file)] if self.password: self.common_args += ["-o", "GSSAPIAuthentication=no", "-o", "PubkeyAuthentication=no"] else: self.common_args += [ "-o", "KbdInteractiveAuthentication=no", "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey", "-o", "PasswordAuthentication=no", ] if self.user != pwd.getpwuid(os.geteuid())[0]: self.common_args += ["-o", "User="******"-o", "ConnectTimeout=%d" % self.runner.timeout] return self
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh', in_data=None): ''' run a command on the remote minion ''' if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") vvv("EXEC %s" % (cmd), host=self.host) p = self.client.command.run(cmd)[self.host] return (p[0], '', p[1], p[2])
def exec_command(self, cmd, tmp_path, sudo_user,sudoable=False): ''' run a command on the remote host ''' ssh_cmd = ["ssh", "-tt", "-q"] + self.common_args + [self.host] if self.runner.sudo and sudoable: # Rather than detect if sudo wants a password this time, -k makes # sudo always ask for a password if one is required. # Passing a quoted compound command to sudo (or sudo -s) # directly doesn't work, so we shellquote it with pipes.quote() # and pass the quoted string to the user's shell. We loop reading # output until we see the randomly-generated sudo prompt set with # the -p option. randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) prompt = '[sudo via ansible, key=%s] password: '******'sudo -k && sudo -p "%s" -u %s "$SHELL" -c %s' % ( prompt, sudo_user, pipes.quote(cmd)) sudo_output = '' ssh_cmd.append(sudocmd) vvv("EXEC %s" % ssh_cmd, host=self.host) p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if self.runner.sudo_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) while not sudo_output.endswith(prompt): rfd, wfd, efd = select.select([p.stdout], [], [p.stdout], self.runner.timeout) if p.stdout in rfd: chunk = p.stdout.read() if not chunk: raise errors.AnsibleError('ssh connection closed waiting for sudo password prompt') sudo_output += chunk else: stdout = p.communicate() raise errors.AnsibleError('ssh connection error waiting for sudo password prompt') p.stdin.write(self.runner.sudo_pass + '\n') fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) else: ssh_cmd.append(cmd) vvv("EXEC %s" % ssh_cmd, host=self.host) p = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # We can't use p.communicate here because the ControlMaster may have stdout open as well stdout = '' while p.poll() is None: rfd, wfd, efd = select.select([p.stdout], [], [p.stdout], 1) if p.stdout in rfd: stdout += os.read(p.stdout.fileno(), 1024) p.stdin.close() # close stdin after we read from stdout (see also issue #848) if p.returncode != 0 and stdout.find('Bad configuration option: ControlPersist') != -1: raise errors.AnsibleError('using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in the config file) before running again') return ('', stdout, '')
def _connect_uncached(self): ''' activates the connection object ''' if not HAVE_PARAMIKO: raise errors.AnsibleError("paramiko is not installed") vvv("ESTABLISH CONNECTION FOR USER: %s on PORT %s TO %s" % (self.user, self.port, self.host), host=self.host) ssh = paramiko.SSHClient() self.keyfile = os.path.expanduser("~/.ssh/known_hosts") if C.HOST_KEY_CHECKING: ssh.load_system_host_keys() ssh.set_missing_host_key_policy(MyAddPolicy(self.runner)) allow_agent = True if self.password is not None: allow_agent = False try: if self.private_key_file: key_filename = os.path.expanduser(self.private_key_file) elif self.runner.private_key_file: key_filename = os.path.expanduser(self.runner.private_key_file) else: key_filename = None ssh.connect(self.host, username=self.user, allow_agent=allow_agent, look_for_keys=True, key_filename=key_filename, password=self.password, timeout=self.runner.timeout, port=self.port) except Exception, e: msg = str(e) if "PID check failed" in msg: raise errors.AnsibleError( "paramiko version issue, please upgrade paramiko on the machine running ansible" ) elif "Private key file is encrypted" in msg: msg = 'ssh %s@%s:%s : %s\nTo connect as a different user, use -u <username>.' % ( self.user, self.host, self.port, msg) raise errors.AnsibleConnectionFailed(msg) else: raise errors.AnsibleConnectionFailed(msg)
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % in_path) try: self.sftp = self.ssh.open_sftp() except Exception, e: raise errors.AnsibleError("failed to open a SFTP connection (%s)" % e)
def exec_command(self, cmd, tmp_path, become_user=None, sudoable=False, executable='/bin/sh', in_data=None): if in_data: raise errors.AnsibleError('Internal Error: this modules does not support optimized module pipelining') if executable: local_cmd = executable.split() + ['-c', cmd] else: local_cmd = cmd executable = executable.split()[0] if executable else None pipe_to_server = os.pipe() pipe_from_server = os.pipe() # os.environ is special, so we copy it into a dictionary and modify the dictionary instead env = dict() for key in os.environ.keys(): env[key] = os.environ[key] env['SNMP_PIPE_IN'] = str(pipe_from_server[0]) env['SNMP_PIPE_OUT'] = str(pipe_to_server[1]) if 'PYTHONPATH' in env: env['PYTHONPATH'] = os.path.dirname(__file__) + ':' + env['PYTHONPATH'] else: env['PYTHONPATH'] = os.path.dirname(__file__) vvv('EXEC %s' % (local_cmd), host=self.host) p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), cwd=self.runner.basedir, executable=executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) # pysnmp insist on using its own socket map, so we use that instead conn = self._get_snmp_connection() sock_map = conn.dispatcher.getSocketMap() stdout = _BufferedDispatcher(asyncore.file_wrapper(p.stdout.fileno()), map=sock_map) stderr = _BufferedDispatcher(asyncore.file_wrapper(p.stderr.fileno()), map=sock_map) server = _Server(conn, pipe_to_server[0], pipe_from_server[1], map=sock_map) while stdout.readable() or stderr.readable(): asyncore.poll(0.5, map=sock_map) conn.dispatcher.handleTimerTick(time.time()) p.wait() os.close(pipe_to_server[0]) os.close(pipe_to_server[1]) os.close(pipe_from_server[0]) os.close(pipe_from_server[1]) return (p.returncode, '', stdout.data, stderr.data)
def put_file(self, in_path, out_path): ''' transfer a file from local to local ''' out_path = os.path.join(self.chroot, out_path.lstrip('/')) vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % in_path) try: self._exec_command('cp {} {}'.format(in_path, out_path)) except Exception: traceback.print_exc() raise errors.AnsibleError("Some exceptions occurred.")
def fetch_file(self, in_path, out_path): ''' fetch a file from local to local -- for copatibility ''' in_path = os.path.join(self.chroot, in_path.lstrip('/')) vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(out_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % out_path) try: self._exec_command('cp {} {}'.format(in_path, out_path)) except Exception: traceback.print_exc() raise errors.AnsibleError("Some exceptions occurred.")
def fetch_file(self, in_path, out_path): ''' save a remote file to the specified path ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) try: sftp = self.ssh.open_sftp() except: raise errors.AnsibleError("failed to open a SFTP connection") try: sftp.get(in_path, out_path) except IOError: raise errors.AnsibleError("failed to transfer file from %s" % in_path) sftp.close()
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % in_path) fd = file(in_path, 'rb') fstat = os.stat(in_path) try: vvv("PUT file is %d bytes" % fstat.st_size) while fd.tell() < fstat.st_size: data = fd.read(CHUNK_SIZE) last = False if fd.tell() >= fstat.st_size: last = True data = dict(mode='put', data=base64.b64encode(data), out_path=out_path, last=last) if self.runner.sudo: data['user'] = self.runner.sudo_user data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("failed to send the file to %s" % self.host) response = self.recv_data() if not response: raise errors.AnsibleError( "Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if response.get('failed', False): raise errors.AnsibleError( "failed to put the file in the requested location") finally: fd.close() response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if response.get('failed', False): raise errors.AnsibleError( "failed to put the file in the requested location")
def fetch_file(self, in_path, out_path): ''' fetch a file from remote to local ''' in_path = self._normalize_path(in_path, '/') vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) # need to use a tmp dir due to difference of semantic for getfile # ( who take a # directory as destination) and fetch_file, who # take a file directly tmpdir = tempfile.mkdtemp(prefix="func_ansible") self.client.local.getfile.get(in_path, tmpdir) shutil.move(os.path.join(tmpdir, self.host, os.path.basename(in_path)), out_path) shutil.rmtree(tmpdir)
def fetch_file(self, in_path, out_path): ''' fetch a file from remote to local ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) sftp_cmd = ["sftp"] + self.common_args + [self.host] p = subprocess.Popen(sftp_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate("get %s %s\n" % (in_path, out_path)) if p.returncode != 0: raise errors.AnsibleError( "failed to transfer file from %s:\n%s\n%s" % (in_path, stdout, stderr))
def put_file(self, in_path, out_path): ''' transfer a file from local to lxc ''' out_path = self._normalize_path(out_path, '/') vvv("PUT %s TO %s" % (in_path, out_path), host=self.lxc) local_cmd = [self.cmd, '-q', '-c', 'lxc:///', 'lxc-enter-namespace', self.lxc, '--', '/bin/tee', out_path] vvv("EXEC %s" % (local_cmd), host=self.lxc) p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate(open(in_path,'rb').read())
def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable='/bin/sh', in_data=None, su=None, su_user=None): ''' run a command on the local host ''' # su requires to be run from a terminal, and therefore isn't supported here (yet?) if su or su_user: raise errors.AnsibleError("Internal Error: this module does not support running commands via su") if in_data: raise errors.AnsibleError("Internal Error: this module does not support optimized module pipelining") if not self.runner.sudo or not sudoable: if executable: local_cmd = [executable, '-c', cmd] else: local_cmd = cmd else: local_cmd, prompt, success_key = utils.make_sudo_cmd(sudo_user, executable, cmd) vvv("EXEC %s" % (local_cmd), host=self.host) p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), cwd=self.runner.basedir, executable=executable or None, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if self.runner.sudo and sudoable and self.runner.sudo_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) sudo_output = '' while not sudo_output.endswith(prompt) and success_key not in sudo_output: rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout, p.stderr], self.runner.timeout) if p.stdout in rfd: chunk = p.stdout.read() elif p.stderr in rfd: chunk = p.stderr.read() else: stdout, stderr = p.communicate() raise errors.AnsibleError('timeout waiting for sudo password prompt:\n' + sudo_output) if not chunk: stdout, stderr = p.communicate() raise errors.AnsibleError('sudo output closed while waiting for password prompt:\n' + sudo_output) sudo_output += chunk if success_key not in sudo_output: p.stdin.write(self.runner.sudo_pass + '\n') fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) & ~os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) & ~os.O_NONBLOCK) stdout, stderr = p.communicate() return (p.returncode, '', stdout, stderr)
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'): ''' run a command on the chroot ''' # We enter lxc as root so sudo stuff can be ignored local_cmd = self._generate_cmd(executable, cmd) vvv("EXEC %s" % (local_cmd), host=self.lxc) p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring), cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() return (p.returncode, '', stdout, stderr)
def fetch_file(self, in_path, out_path): ''' fetch a file from lxc to local ''' in_path = self._normalize_path(in_path, '/') vvv("FETCH %s TO %s" % (in_path, out_path), host=self.lxc) local_cmd = [self.cmd, '-q', '-c', 'lxc:///', 'lxc-enter-namespace', self.lxc, '--', '/bin/cat', in_path] vvv("EXEC %s" % (local_cmd), host=self.lxc) p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() open(out_path,'wb').write(stdout)
def _connect_uncached(self): ''' activates the connection object ''' if not HAVE_PARAMIKO: raise errors.AnsibleError("paramiko is not installed") user = self.runner.remote_user vvv("ESTABLISH CONNECTION FOR USER: %s on PORT %s TO %s" % (user, self.port, self.host), host=self.host) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) allow_agent = True if self.runner.remote_pass is not None: allow_agent = False try: private_key = None key_filename = None if self.runner.private_key: private_key = paramiko.RSAKey.from_private_key( StringIO.StringIO(self.runner.private_key)) if self.runner.private_key_file: key_filename = os.path.expanduser(self.runner.private_key_file) ssh.connect(self.host, username=user, allow_agent=allow_agent, look_for_keys=True, key_filename=key_filename, pkey=private_key, password=self.runner.remote_pass, timeout=self.runner.timeout, port=self.port) except Exception, e: msg = str(e) if "PID check failed" in msg: raise errors.AnsibleError( "paramiko version issue, please upgrade paramiko on the machine running ansible" ) elif "Private key file is encrypted" in msg: msg = 'ssh %s@%s:%s : %s\nTo connect as a different user, use -u <username>.' % ( user, self.host, self.port, msg) raise errors.AnsibleConnectionFailed(msg) else: raise errors.AnsibleConnectionFailed(msg)
def __init__(self, runner, host, port, *args, **kwargs): self.host = host self.runner = runner self.has_pipelining = False if os.geteuid() != 0: raise errors.AnsibleError( "openvz connection requires running as root") if not self.host in self.list_containers(): raise errors.AnsibleError("No such container: %s" % self.host) self.ctid = self.get_ctid() vvv("CTID: " + self.ctid, host=self.host) pass
def put_file(self, in_path, out_path): ''' transfer a file from local to local ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path) try: shutil.copyfile(in_path, out_path) except shutil.Error: traceback.print_exc() raise errors.AnsibleError("failed to copy: %s and %s are the same" % (in_path, out_path)) except IOError: traceback.print_exc() raise errors.AnsibleError("failed to transfer file to %s" % out_path)
def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'): ''' run a command on the remote host ''' if executable == "": executable = constants.DEFAULT_EXECUTABLE if self.runner.sudo and sudoable and sudo_user: cmd, prompt, success_key = utils.make_sudo_cmd( sudo_user, executable, cmd) vvv("EXEC COMMAND %s" % cmd) data = dict( mode='command', cmd=cmd, tmp_path=tmp_path, executable=executable, ) data = utils.jsonify(data) data = utils.encrypt(self.key, data) if self.send_data(data): raise errors.AnsibleError("Failed to send command to %s" % self.host) while True: # we loop here while waiting for the response, because a # long running command may cause us to receive keepalive packets # ({"pong":"true"}) rather than the response we want. response = self.recv_data() if not response: raise errors.AnsibleError("Failed to get a response from %s" % self.host) response = utils.decrypt(self.key, response) response = utils.parse_json(response) if "pong" in response: # it's a keepalive, go back to waiting vvvv("%s: received a keepalive packet" % self.host) continue else: vvvv("%s: received the response" % self.host) break return (response.get('rc', None), '', response.get('stdout', ''), response.get('stderr', ''))
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' port = self.port or 5986 vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self.user, port, self.host), host=self.host) netloc = '%s:%d' % (self.host, port) cache_key = '%s:%s@%s:%d' % (self.user, hashlib.md5( self.password).hexdigest(), self.host, port) if cache_key in _winrm_cache: vvvv('WINRM REUSE EXISTING CONNECTION: %s' % cache_key, host=self.host) return _winrm_cache[cache_key] transport_schemes = [('plaintext', 'https'), ('plaintext', 'http')] # FIXME: ssl/kerberos if port == 5985: transport_schemes = reversed(transport_schemes) exc = None for transport, scheme in transport_schemes: endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self.host) protocol = Protocol(endpoint, transport=transport, username=self.user, password=self.password) try: protocol.send_message('') _winrm_cache[cache_key] = protocol return protocol except WinRMTransportError, exc: err_msg = str(exc.args[0]) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise errors.AnsibleError( "the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise errors.AnsibleError( "the username/password specified for this server was incorrect" ) elif code == 411: _winrm_cache[cache_key] = protocol return protocol vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) continue
def fetch_file(self, in_path, out_path): ''' fetch a file from docker to local ''' in_path = self._normalize_path(in_path, '/') vvv("FETCH %s TO %s" % (in_path, out_path), host=self.docker_id) local_cmd = [self.cmd, 'cp', self.docker_id, ':', in_path, out_path] vvv("EXEC %s" % (local_cmd), host=self.docker_id) p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate()
def put_file(self, in_path, out_path): local_cmd = [ '/usr/sbin/vzctl', 'exec', self.ctid, '/bin/sh', '-c', '"', 'cat > %s' % format(out_path), '"' ] vvv("PUT CMD %s" % (local_cmd), host=self.host) vvv("PUT %s %s" % (in_path, out_path), host=self.host) p = subprocess.Popen(local_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.stdin.write(open(in_path).read()) p.stdin.close() time.sleep(1) p.terminate()
def handle_module_result(self, result, changed_if=None, failed_if=None): changed = result.get("changed", False) failed = result.get("failed", False) msg = result.get("msg", result.get("stderr", "")) vvv("result: failed={} changed={} msg={}".format( failed, changed, msg, )) if changed: self.changed = True if failed: raise ModuleError(msg) return result
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % in_path) sftp_cmd = ["sftp"] + self.common_args + [self.host] p = subprocess.Popen(sftp_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate("put %s %s\n" % (in_path, out_path)) if p.returncode != 0: raise errors.AnsibleError( "failed to transfer file to %s:\n%s\n%s" % (out_path, stdout, stderr))
def fetch_file(self, in_path, out_path): """ Fetch a file from container to local. """ # out_path is the final file path, but docker takes a directory, not a # file path out_dir = os.path.dirname(out_path) args = [self.docker_cmd, "cp", "%s:%s" % (self.host, in_path), out_dir] vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.communicate() # Rename if needed actual_out_path = os.path.join(out_dir, os.path.basename(in_path)) if actual_out_path != out_path: os.rename(actual_out_path, out_path)
def put_file(self, in_path, out_path): ''' transfer a file from local to the namespace ''' out_path = self._normalize_path(out_path, '/') vvv("PUT %s TO %s" % (in_path, out_path), host=self.docker_id) # cat localfile | docker exec -i data sh -c 'cat > containerfile' local_cmd = [self.cmd, 'exec', '-i', self.docker_id, 'tee', out_path] vvv("EXEC %s" % (local_cmd), host=self.docker_id) p = subprocess.Popen(local_cmd, cwd=self.runner.basedir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate(open(in_path, 'rb').read())
def connect(self): ''' activates the connection object ''' if not HAVE_PARAMIKO: raise errors.AnsibleError("paramiko is not installed") user = self.runner.remote_user vvv("ESTABLISH CONNECTION FOR USER: %s" % user, host=self.host) #SSHConfig() checks config = SSHConfig() home_directory = os.getenv('HOME') config.parse(open(os.path.join(home_directory, '.ssh/config'))) o = config.lookup(self.host) if o.has_key('port'): self.port = int(o['port']) if o.has_key('hostname'): self.host = o['hostname'] if o.has_key('user'): user = o['user'] #print user,self.host ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) allow_agent = True if self.runner.remote_pass is not None: allow_agent = False try: ssh.connect(self.host, username=user, allow_agent=allow_agent, look_for_keys=True, key_filename=self.runner.private_key_file, password=self.runner.remote_pass, timeout=self.runner.timeout, port=self.port) except Exception, e: msg = str(e) if "PID check failed" in msg: raise errors.AnsibleError("paramiko version issue, please upgrade paramiko on the machine running ansible") elif "Private key file is encrypted" in msg: msg = 'ssh %s@%s:%s : %s\nTo connect as a different user, use -u <username>.' % ( user, self.host, self.port, msg) raise errors.AnsibleConnectionFailed(msg) else: raise errors.AnsibleConnectionFailed(msg)
def connect(self): ''' connect to the remote host ''' vvv("ESTABLISH CONNECTION FOR USER: %s" % self.user, host=self.host) self.common_args = [] extra_args = C.ANSIBLE_SSH_ARGS if extra_args is not None: # make sure there is no empty string added as this can produce weird errors self.common_args += [x.strip() for x in shlex.split(extra_args) if x.strip()] else: self.common_args += ["-o", "ControlMaster=auto", "-o", "ControlPersist=60s", "-o", "ControlPath=\"%s\"" % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir))] cp_in_use = False cp_path_set = False for arg in self.common_args: if "ControlPersist" in arg: cp_in_use = True if "ControlPath" in arg: cp_path_set = True if cp_in_use and not cp_path_set: self.common_args += ["-o", "ControlPath=\"%s\"" % (C.ANSIBLE_SSH_CONTROL_PATH % dict(directory=self.cp_dir))] if not C.HOST_KEY_CHECKING: self.common_args += ["-o", "StrictHostKeyChecking=no"] if self.port is not None: self.common_args += ["-o", "Port=%d" % (self.port)] if self.private_key_file is not None: self.common_args += ["-o", "IdentityFile=\"%s\"" % os.path.expanduser(self.private_key_file)] elif self.runner.private_key_file is not None: self.common_args += ["-o", "IdentityFile=\"%s\"" % os.path.expanduser(self.runner.private_key_file)] if self.password: self.common_args += ["-o", "GSSAPIAuthentication=no", "-o", "PubkeyAuthentication=no"] else: self.common_args += ["-o", "KbdInteractiveAuthentication=no", "-o", "PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey", "-o", "PasswordAuthentication=no"] if self.user != pwd.getpwuid(os.geteuid())[0]: self.common_args += ["-o", "User="******"-o", "ConnectTimeout=%d" % self.runner.timeout] return self
def not_in_host_file(self, host): if 'USER' in os.environ: user_host_file = os.path.expandvars("~${USER}/.ssh/known_hosts") else: user_host_file = "~/.ssh/known_hosts" user_host_file = os.path.expanduser(user_host_file) host_file_list = [] host_file_list.append(user_host_file) host_file_list.append("/etc/ssh/ssh_known_hosts") host_file_list.append("/etc/ssh/ssh_known_hosts2") hfiles_not_found = 0 for hf in host_file_list: if not os.path.exists(hf): hfiles_not_found += 1 continue host_fh = open(hf) data = host_fh.read() host_fh.close() for line in data.split("\n"): if line is None or " " not in line: continue tokens = line.split() if tokens[0].find(self.HASHED_KEY_MAGIC) == 0: # this is a hashed known host entry try: (kn_salt, kn_host ) = tokens[0][len(self.HASHED_KEY_MAGIC):].split( "|", 2) hash = hmac.new(kn_salt.decode('base64'), digestmod=sha1) hash.update(host) if hash.digest() == kn_host.decode('base64'): return False except: # invalid hashed host key, skip it continue else: # standard host file entry if host in tokens[0]: return False if (hfiles_not_found == len(host_file_list)): vvv("EXEC previous known host file not found for %s" % host) return True
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' port = self.port or 5986 vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % \ (self.user, port, self.host), host=self.host) netloc = '%s:%d' % (self.host, port) exc = None for transport, scheme in self.transport_schemes['http' if port == 5985 else 'https']: if transport == 'kerberos' and (not HAVE_KERBEROS or not '@' in self.user): continue if transport == 'kerberos': realm = self.user.split('@', 1)[1].strip() or None else: realm = None endpoint = urlparse.urlunsplit((scheme, netloc, '/wsman', '', '')) vvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self.host) protocol = Protocol(endpoint, transport=transport, username=self.user, password=self.password, realm=realm) try: protocol.send_message('') return protocol except WinRMTransportError, exc: err_msg = str(exc) if re.search(r'Operation\s+?timed\s+?out', err_msg, re.I): raise errors.AnsibleError( "the connection attempt timed out") m = re.search(r'Code\s+?(\d{3})', err_msg) if m: code = int(m.groups()[0]) if code == 401: raise errors.AnsibleError( "the username/password specified for this server was incorrect" ) elif code == 411: return protocol vvvv('WINRM CONNECTION ERROR: %s' % err_msg, host=self.host) continue
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' vvv("PUT %s TO %s" % (in_path, out_path), host=self.host) if not os.path.exists(in_path): raise errors.AnsibleFileNotFound( "file or module does not exist: %s" % in_path) data = file(in_path).read() data = dict(mode='put', data=data, out_path=out_path) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response)
def fetch_file(self, in_path, out_path): ''' save a remote file to the specified path ''' vvv("FETCH %s TO %s" % (in_path, out_path), host=self.host) data = dict(mode='fetch', file=in_path) data = utils.jsonify(data) data = utils.encrypt(self.key, data) self.socket.send(data) response = self.socket.recv() response = utils.decrypt(self.key, response) response = utils.parse_json(response) response = response['data'] fh = open(out_path, "w") fh.write(response) fh.close()
def exec_command(self, cmd, become_user=None, sudoable=False, executable='/bin/sh', in_data=None): ''' run a command on the remote minion ''' if in_data: raise errors.AnsibleError( "Internal Error: this module does not support optimized module pipelining" ) # totally ignores privlege escalation vvv("EXEC %s" % (cmd), host=self.host) p = self.client.command.run(cmd)[self.host] return (p[0], p[1], p[2])