Cannot close Paramiko connection - python

I am trying to execute some command on remote server using Paramiko and re-purposed some code from net. From Paramiko documents, it say that you have to close the connection. But I am getting errors while doing that.
class ssh:
paramiko.util.log_to_file("filename_new.log")
client = None
def __init__(self, address, username, password):
self.client=paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
self.client.connect(hostname=address, username=username, password=password)
def sendCommand(self, command):
if(self.client):
couldNotConnect = False
stdin, stdout, stderr = self.client.exec_command(command, get_pty=True)
stdout = stdout.readlines()
self.client.close()
else:
stdout = "Could Not Connect"
couldNotConnect = True
return stdout
connection = ssh(serverName, userName, passWord)
dfDetails = connection.sendCommand("df -hT")
upTime = connection.sendCommand("uptime")
I am getting the below error:
File "/home/amarc/development/djago/venv/lib/python3.6/site-packages/paramiko/client.py", line 508, in exec_command
chan = self._transport.open_session(timeout=timeout)
AttributeError: 'NoneType' object has no attribute 'open_session'
But when I remove the self.client.close(), it works fine. But I am worried if not closing the connection might cause problem if the program was run multiple times.
And is using __init__ the right way to create a connection since I might be supplying the function with different credentials every time.

I'd recommend you to go for either Fabric (http://www.fabfile.org/) or Ansible and not rely purely on Paramiko since you'll have to reimplement a lot of details. Those tools are already using it but behind the scenes.

The SSHClient.close call has to match with SSHClient.connect.
You call SSHClient.connect once, but SSHClient.close for every command.
Call SSHClient.close only once, after you execute all commands.

Related

Running database script with Paramiko fails with exit code

The output file is created before the database results are available.
Passing a simple os command works fine:
# command = "whoami > result.txt"
works fine. I would get my user name when I open the result.txt file. The problem is waiting for the database to return the result. It comes out empty even though there is data returned from the actual query
import paramiko
def get_report(command):
# reference: https://stackoverflow.com/questions/5193886/python-paramiko-issue-while-closing-the-connection.
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('server123', username='username', password='password')
stdin, stdout, stderr = client.exec_command(command)
exit_status = stdout.channel.recv_exit_status()
if exit_status == 0:
print("File processed")
else:
print("Error", exit_status)
client.close()
command = "sql_query.script > result.txt"
get_report(command=command)
I expect to received a data set of first_name, last_name, and location but instead I get Error 108.
If a command does not work, when executed using Paramiko, debug it by reading its error output.
Use stderr.readlines() for that.
If the same command works in regular shell, but not in Paramiko, the problem is usually related to a different environment used by the SSH "exec" channel, which is used by SSHClient.exec_command. See:
Some Unix commands fail with "<command> not found", when executed using Python Paramiko exec_command
Environment variable differences when using Paramiko

paramiko expect timing out

Thinking about making a move from Perl to Python running scripts to automate certain tasks on remote servers and devices. We need to be able to use Expect to check for certain results and get the data back. Taking a look at Paramiko-Expect and I like it, but it's timing out every time.
import paramiko
from paramikoe import SSHClientInteraction
HOSTNAME = "HOST IP"
PASSWORD = "PWORD"
USERNAME = "UNAME"
PROMPT = "(node name)#"
command = "show command"
print PROMPT
file = open("testlog.txt","w")
def main():
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOSTNAME, port=22, username=USERNAME, password=PASSWORD)
interact = SSHClientInteraction(client, timeout=10, display=True)
interact.send(command)
interact.expect(PROMPT)
file.write(interact.current_output_clean)
client.close()
return
main()
file.close()
This is the traceback I get:
Traceback (most recent call last):
File "python_test.py", line 40, in <module>
main()
File "python_test.py", line 28, in main
interact.expect(PROMPT)
File "/usr/local/lib/python2.7/site-packages/paramikoe.py", line 122, in expect
buffer = self.channel.recv(self.buffer_size)
File "/usr/local/lib/python2.7/site-packages/paramiko/channel.py", line 598, in recv
raise socket.timeout() socket.timeout
I've tried multiple versions of the PROMPT to expect, from directly putting in the text of the node I'm trying it on to full regex. Nothing works. It always times out when it gets to the client.expect. Paramiko-expect documentation does not help and the only other place I see this question is different enough that it doesn't help.
Any advice is appreciated.
Put prompt to something you expect, as... prompt. Here is paramiko interaction example. Please note lines 21, and 37 -
PROMPT = 'vagrant#paramiko-expect-dev:~\$\s+'
interact.expect(PROMPT)
So, when I've updated part of your code to:
interact = SSHClientInteraction(client, timeout=10, display=True)
interact.expect(PROMPT)
interact.send("ls")
interact.expect(".*Maildir.*")
file.write(interact.current_output_clean)
client.close()
I have testlog.txt filled with listing of the home directory, of remote host.
As a side note - switch to python 3. If you are starting, it is better to use tool that is not well known to be outdated soon. Also you can use ipython, or jupyter - code will be more interactive, faster to test. Maybe netmiko will be interested for you?

Paramiko does not connect

I try to upload a file to a server via sftp using paramiko.
def send_file(server_, port_, user_, passwd_, file_, dir_):
"""
:return:
"""
try:
transport = paramiko.Transport((server_, int(port_)))
transport.connect(username=user_, password=passwd_)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put(file_, dir_)
sftp.close()
except RuntimeError, err:
print(str(err))
If I execute this function it just hangs (no response, no error messages), until the socket times out.
The credentials are correct, I tried them with sftp and ssh clients from the same machine and the same network.
I also passed the Transport and connect values directly, no change.
The logs on the server_ don't show any connections when I use this function.
The host key is in my known_hosts file.
The first statement in the try-block succeeds (I passed a string instead of an int to port_, this throws an exception), the second line seems to have problems.
What's the problem here?
Thanks in advance!
UPDATE 1:
I tried this in ipython2 and it works. The function above is in a PyQt program and executed via
self.connect(self.b_upload, QtCore.SIGNAL("clicked()"), self.onUpload)
Function onUpload:
def onUpload(self):
file_, ok = QtGui.QInputDialog.getText(self, 'Input Dialog', 'Datei inklusive Pfad angeben: ')
server_, port_, user_, passwd_, dir_ = ftpmod.read_config()
ftpmod.send_file(server_, port_, user_, passwd_, file_, dir_)
You can send via sftp, using ssh.open_sftp:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
ssh.connect(host, username, password)
ftp = ssh.open_sftp()
ftp.put(localpath, remotepath)
ftp.close()

get_pty() via sshClient sometimes hangs forever with paramiko

In an automation script, i need to ssh into several servers to gather some data. Unfortunately, few of them seems to have intermittent issues where the connection hangs forever on get_pty().
Here's a snippet of my code. Is there something I can do to kill the connection? I'm using python of course, and unfortunately with python, there is no easy way to kill a thread either :(
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
connect(hostname, port=port, username=username, password=password, timeout=30)
self.__chan = self.__client.get_transport().open_session()
print self.__chan
print ' after'
print self.__chan.get_pty()
output
<paramiko.Channel 1 (open) window=0 -> <paramiko.Transport at 0xd49410L (cipher aes128-ctr, 128 bits) (active; 1 open channel(s))>>
after
I believe the issue has to do with a failed attempt to get_transport() or open_session() properly. If so, how can i detect if an issue occurred?
Per the documentation for paramiko regarding get_pty, "It isn’t necessary (or desirable) to call this method if you’re going to exectue a single command with exec_command." http://docs.paramiko.org/en/1.13/api/channel.html#paramiko.channel.Channel.get_pty
Do you have a specific reason for invoking the pseudo-terminal? If you use paramiko.client.SSHClient.exec_command you do not need to invoke one. Depending on your version of paramiko, exec_command also accepts a timeout parameter so that the command will only block for a certain amount of time. Should your version not allow this parameter, you can subclass the client to add it.
from paramiko import SSHClient
class SSHClient_with_Timeout(SSHClient):
## overload the exec_command method
def exec_command(self, command, bufsize=-1, timeout=None):
chan = self._transport.open_session()
chan.settimeout(timeout)
chan.exec_command(command)
stdin = chan.makefile('wb', bufsize)
stdout = chan.makefile('rb', bufsize)
stderr = chan.makefile_stderr('rb', bufsize)
return stdin, stdout, stderr
If that's not the solution you're looking for, you could also set up logging. paramiko logs to the logger "paramiko", so invoking logging.basicConfig(level=logging.DEBUG) will allow you to see what paramiko is up to right before the 'hang.'

Python paramiko module using multiple commands

I have a class that creates the connection. I can connect and execute 1 command before the channel is closed. On another system i have i can execute multiple commands and the channel does not close. Obviously its a config issue with the systems i am trying to connect to.
class connect:
newconnection = ''
def __init__(self,username,password):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('somehost', username=username,password=password,port=2222,timeout=5)
except:
print "Count not connect"
sys.exit()
self.newconnection = ssh
def con(self):
return self.newconnection
Then i use 'ls' command just to print some output
sshconnection = connect('someuser','somepassword').con()
stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")
print stdout.readlines()
print stdout
stdin, stdout, stderr = sshconnection.exec_command("ls -lsa")
print stdout.readlines()
print stdout
sshconnection.close()
sys.exit()
After the first exec_command runs it prints the expected output of the dir list. When i print stdout after the first exec_command it looks like the channel is closed
<paramiko.ChannelFile from <paramiko.Channel 1 (closed) -> <paramiko.Transport at 0x2400f10L (cipher aes128-ctr, 128 bits) (active; 0 open channel(s))>>>
Like i said on another system i am able to keep running commands and the connection doesn't close. Is there a way i can keep this open? or a better way i can see the reason why it closes?
edit: So it looks like you can only run 1 command per SSHClient.exec_command... so i decided to get_transport().open_session() and then run a command. The first one always works. The second one always fails and the scripts just hangs
With just paramiko after the exec_command executes the channel is closed and the ssh returns an auth prompt.
Seems its not possible with just paramiko, try fabric or another tool.
** fabric did not work out too.
Please see the following referece as it provides a way to do this in Paramiko:
How do you execute multiple commands in a single session in Paramiko? (Python)
it's possible with netmiko (tested on windows).
this example is written for connecting to cisco devices but the principle is adaptable for others as well.
import netmiko
from netmiko import ConnectHandler
import json
def connect_enable_silent(ip_address,ios_command):
with open ("credentials.txt") as line:
line_1 = json.load(line)
for k,v in line_1.items():
router=(k,v)
try:
ssh = ConnectHandler(**router[1],device_type="cisco_ios",ip=ip_address)
ssh.enable()
except netmiko.ssh_exception.NetMikoAuthenticationException:
#incorrect credentials
continue
except netmiko.ssh_exception.NetMikoTimeoutException:
#oddly enough if it can log in but not able to authenticate to enable mode the ssh.enable() command does not give an authentication error
#but a time-out error instead
try:
ssh = ConnectHandler(username = router[1]['username'],password = router[1]['password'],device_type="cisco_ios", ip=ip_address)
except netmiko.ssh_exception.NetMikoTimeoutException:
# connection timed out (ssh not enabled on device, try telnet)
continue
except Exception:
continue
else:
output = ssh.send_command(ios_command)
ssh.disconnect()
if "at '^' marker." in output:
#trying to run a command that requires enble mode but not authenticated to enable mode
continue
return output
except Exception:
continue
else:
output = ssh.send_command(ios_command)
ssh.disconnect()
return output
output = connect_enable_silent(ip_address,ios_command)
for line in output.split('\n'):
print(line)
Credentials text is meant to store different credentials in case you are planning to call this function to access multiple devices and not all of them using the same credentials. It is in the format:
{"credentials_1":{"username":"username_1","password":"password_1","secret":"secret_1"},
"credentials_2":{"username":"username_2","password":"password_2","secret":"secret_2"},
"credentials_3": {"username": "username_3", "password": "password_3"}
}
The exceptions can be changed to do different things, in my case i just needed it to not return an error and continue trying the next set, which is why most exceptions are silenced.

Categories

Resources