I'm trying to open a file which got created as part of the Paramiko exec_command. The file gets created, but when I check if the file exists, it always returns false. How do I check if the file exists and then open the file for reading?
The code written is:
ip = '10.30.2.104'
username = 'root'
password = 'docker'
def checkSSH(ip, username, password, retries=1):
ssh = SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
for x in range(retries):
try:
ssh.connect(ip, username=username, password=password, timeout=10)
return ssh
except (
paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
print('Exception occured.. {0}'.format(e))
return False
hdl = checkSSH(ip, username, password)
cmd = 'ls > test.log'
hdl.exec_command(cmd)
a = os.path.exists('/root/test.log')
print(a) >>> if the file exists, this returns true as per the documentation but in this case, it always returns false.
First, you are not waiting for the command to complete.
For that see:
Wait to finish command executed with Python Paramiko
Once the command completes, you can retrieve its exit code using Channel.recv_exit_status():
How can you get the SSH return code using Paramiko?
If it returns 0, you know that everything went fine and no additional check is needed.
Anyway, if you want to check, use SFTP (SFTPClient.stat):
sftp = hdl.open_sftp()
try:
sftp.stat('/root/test.log')
print("exists")
except Exception as e:
print("something is wrong: " + e)
Though the execution of ls command seems strange to me.
If you want to retrieve the directory listing, use SFTP: SFTPClient.listdir_attr
Related
So I built a program that prints out the login logs of my ubuntu server using tail -f.
The program uses Paramiko to connect via ssh and runs the command to tail the logs.
The program works but it prints out the motd from the server which is unnecessary.
I've tried splicing using itertools.
Tried using next().
Still doesn't work.
Here's my code:
import yaml, paramiko, getpass, traceback, time, itertools
from paramiko_expect import SSHClientInteraction
with open("config.yaml", "r") as yamlfile:
cfg = yaml.load(yamlfile, Loader=yaml.FullLoader)
def main():
command = "sudo tail -f /var/log/auth.log"
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
server_pw = getpass.getpass("Enter the password for your account %s on %s:" % (cfg['ssh_config']['username'], cfg['ssh_config']['host']))
sudo_pw = getpass.getpass("Enter the sudo password for %s on %s: " % (cfg['ssh_config']['username'], cfg['ssh_config']['host']))
ssh.connect(hostname = cfg['ssh_config']['host'], username = cfg['ssh_config']['username'], port = cfg['ssh_config']['port'], password = server_pw)
interact = SSHClientInteraction(ssh, timeout=10, display=False)
interact.send(command)
interact.send(sudo_pw + "\n")
with open(interact.tail(line_prefix=cfg['ssh_config']['servername']+': ')) as tail:
for line in itertools.islice(tail, 17, None):
print(line)
except KeyboardInterrupt:
print('Ctrl+C interruption detected, stopping tail')
except Exception:
traceback.print_exc()
finally:
try:
ssh.close()
except:
pass
if __name__ == '__main__':
main()
You get MOTD because you are opening an interactive shell session. I do not think you need that, quite on the contrary.
Use SSHClient.exec_command instead:
stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)
stdin.write(sudo_pw + "\n")
stdin.flush()
for line in iter(stdout.readline, ""):
print(line, end="")
Related questions:
Get output from a Paramiko SSH exec_command continuously
Pass input/variables to command/script over SSH using Python Paramiko
What is the difference between exec_command and send with invoke_shell() on Paramiko?
Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
I am trying to fix a segment of code originally developed in Python 2.X. I have to use all standard libraries, , remove paramiko, and need to keep the functionality the same. As you can see, there is a port number configuration, username, password, etc. Any suggestions?
I have tried other SSH options, but none have worked. It returns an error.
def grab_and_post_inventory_data(machine_name):
try:
if not USEKEYFILE?: ssh.connect(str(machine_name), port=PORT, username=USER, password=PASSWORD, timeout=TIMEOUT)
else: ssh.connect(str(machine_name), port=PORT, username=USER, key_filename=KEY_FILE, timeout=TIMEOUT)
except paramiko.AuthenticationException:
print(machine_name + ': authentication failed')
return None
except Exception as err:
print(machine_name + ":" + err)
return None
devargs = {}
The output is an error, saying ssh not defined. There is no ssh library. I have tried other solutions, but no avail. Any ideas? Again, I need to use only the standard library and remove paramiko.
subprocess.Popen()
It is to control a local ssh session using subprocess.Popen() if no libraries are available. This is a super primative way to do things, and not recommended if you can avoid it.
import subprocess
import sys
HOST="www.example.org"
# Ports are handled in ~/.ssh/config since we use OpenSSH
COMMAND="uname -a"
ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = ssh.stdout.readlines()
if result == []:
error = ssh.stderr.readlines()
print >>sys.stderr, "ERROR: %s" % error
else:
print result
but recommended way is to use paramiko for ssh client and server. it will handle all low level operations. it is very simple to use.
I have a directory containing some files and sub-directories on my local machine that is generated by a daily Python script running. And then I want to copy all those generated files in a directory to the server and then run some series of commands on it by ssh using python package paramiko.
I want to add little code to securely copy that entire directory and files and sub-directories inside it to to my server over SSH/SCP using the paramiko package of python. I can send the individual files using the same but unable to send the entire directory and its content using paramiko. It gives me IOError saying it's a directory.
IOError: [Errno 21] Is a directory: 'temp'
Here is the my code:
from paramiko import SSHClient, AutoAddPolicy
from scp import SCPClient
class SSh(object):
def __init__(self, address, username, password, port=22):
print "Connecting to server."
self._address = address
self._username = username
self._password = password
self._port = port
self.sshObj = None
self.connect()
self.scp = SCPClient(self.sshObj.get_transport())
def sendCommand(self, command):
if(self.sshObj):
stdin, stdout, stderr = self.sshObj.exec_command(command)
while not stdout.channel.exit_status_ready():
# Print data when available
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print str(alldata)
else:
print "Connection not opened."
def connect(self):
try:
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect(self._address, port=self._port, username=self._username, password=self._password, timeout=20, look_for_keys=False)
print 'Connected to {} over SSh'.format(self._address)
return True
except Exception as e:
ssh = None
print "Unable to connect to {} over ssh: {}".format(self._address, e)
return False
finally:
self.sshObj = ssh
if __name__ == "__main__":
# Parse and check the arguments
ssh = SSh('10.24.143.190', 'username', 'password')
ssh.scp.put("Valigrind_BB.py") # This works perfectly fine
ssh.scp.put("temp") # IOError over here Is a directory
ssh.sendCommand('ls')
Thank you in advance.
Looking at the source code for SCP, it appears you can pass the parameter "recursive" as a bool to the put() method to specify transferring the contents of a directory recursively. Here is a link to the source code I am talking about. Try changing last part of your code to the following:
if __name__ == "__main__":
# Parse and check the arguments
ssh = SSh('10.24.143.190', 'username', 'password')
ssh.scp.put("Valigrind_BB.py") # This works perfectly fine
ssh.scp.put("temp", recursive=True) # IOError over here Is a directory
ssh.sendCommand('ls')
Also, if you just want to transfer files, you can try rsync as an alternative. The modification to your code above should work though. I hope this helps.
im connecting a linux server with sshclient .And then, im connecting cisco routers via telnet on this server. I'm connecting server and execute telnet command perfectly but in second or third telnet command code get stucked and doesnt throw error.Here is part of my code:
def __init__(self):
self.pre_client=paramiko.SSHClient()
self.pre_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sellf.pre_client.connect("server",username="user",password="password")
self.client=self.pre_client.invoke_shell()
def connect(self,ip):
o=self.client.recv(1024)
print o
self.client.exec_command("telnet %s\n"%(ip))
while True:
o=self.client.recv(1024)
print o
#EXECUTE COMMAND ON ROUTER
self.client.exec_command("exit\n")
if 'exit' in o:
break
Why it get stuck on this command? How can i handle it?
I think I'd need to see more code to find what's wrong. If you don't have a specific reason for needing to use a Paramiko Channel, life will probably be a lot easier for you if you just use a Paramiko Client. This is a rough snippet from an old script of mine:
def ssh_connect(usr, pswds, host):
# Open Connection - auto add policy
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Retry with multiple passwords
for pswd in pswds:
try:
ssh.connect(host, username=usr, password=pswd)
return ssh
except:
pass
else:
print("Could not login to: " + host)
return None
def send_command(conn, command):
try:
stdin, stdout, stderr = conn.exec_command(command)
if stdout:
for str in stdout:
sys.stdout.write("\t%s" % str)
return True
if stderr:
for str in stderr:
sys.stderr.write("\t%s" % str)
return False
else:
print("\n")
return True
except paramiko.ssh_exception.SSHException as e:
print(e.message)
return False
And of course, call them with:
conn = ssh_connect(login, passwords, host)
send_command(conn, command)
I have the following code in python:
import pxssh
s = pxssh.pxssh()
try:
if not s.login ('x.x.x.x', 'root', 'password'):
print "SSH session failed on login."
print str(s)
else:
print "SSH session login successful"
s.sendline ('uptime')
s.prompt() # match the prompt
print s.before # print everything before the prompt.
s.logout()
except pxssh.ExceptionPxssh, e:
print "SSH conection failed"
print str(e)
and I success to do ssh connection.
Now, I want to append a key to a file which already exists in my system (in /root/.ssh/authorized_keys)
I don't find any way to do it with the pxssh API. How can I do it.
In the following code I'll assume that you have successfully connected to the remote machine via ssh. I have used this method for a similar purpose but with different data.
file_data = open("/root/.ssh/authorized_keys").read()
"""manipulate the contents of the file such that the variable new_key contains
the data you want to append to the file via ssh"""
#I'll assume the data to be abcd
new_key = "abcd"
#Constructing the command to pass via ssh
cmd = 'echo "' + new_key + '">>/root/.ssh/authorized_keys'
#note that I've used >> and not >, the former will append while the later will overwrite the file
#also the path given in the above command is the one on the remote ssh server and not your local machine
s.sendline(cmd)
s.prompt()
print s.before
#voilà your key is appended to the file on the remote server
#you can check that
s.sendline("cat /root/.ssh/authorized_keys")
s.prompt()
print s.before
Hope this helps.