I have a cluster of machines, and I write a Python script to change the hostname; the code follows.
What puzzles me is that the source command only takes effect on some machines, not all. After I repeat several times, then all hostname take effect [BTW: I can change the hostname in /etc/hostname, but the hostname service do not take effect.]
import paramiko
import time
import threading
import os
cmd0 = "sudo source /root/.bashrc"
cmd1 = "sudo service hostname stop"
cmd2 = "sudo service hostname start"
def executeit(ip):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, 22, "root")
ssh.exec_command(cmd0)
stdin, stdout, stderr = ssh.exec_command(cmd1)
out = stdout.readlines()
for o in out:
print(o)
time.sleep(1)
ssh.exec_command(cmd2)
ssh.close()
print("=======")
def main():
fr = open("info.txt", "r")
contents = fr.read().splitlines()
fr.close()
for ip in contents:
t = threading.Thread(target=executeit, args=(ip,))
t.start()
main()
Related
I'm trying to use the spur library to launch a long-running command via ssh then read and process the output from it one line at a time. The documentation says you can pass a file object using stdout=f and run/spawn will call stdout.write for anything the subprocess writes to its stdout stream. I hit on the idea of creating an os.pipe() to make this work, but it doesn't. Can someone please suggest a fix.
NOTE: I've already got this working with paramiko.SSHClient.exec_command but the interface is a bit low-level for my needs, so I want to learn how to do it with spur. Thanks!
import spur
import os
HOST = "rocky.lan"
USER = "rocky"
CMD = "while sleep 1; do date; done"
r, w = os.pipe()
r = os.fdopen(r, 'rb')
w = os.fdopen(w, 'wb')
ssh = spur.SshShell(hostname=HOST, username=USER)
child = ssh.spawn(CMD, stdout=w)
for line in iter(r.readline, ""):
print(line, end="")
Since someone is bound to ask, the parakimo code looks like this:-
from paramiko import SSHClient
HOST = "rocky.lan"
USER = "rocky"
CMD = "while sleep 1; do date; done"
ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect(HOST, username=USER)
stdin, stdout, stderr = ssh.exec_command(CMD)
for line in iter(stdout.readline, ""):
print(line, end="")
I've discovered parallel-ssh which seems to have parted company from paramiko and gone for python-ssh/python-ssh2 instead. A 5-minute test suggests that it combines paramiko's power with spur's simplicity, but sadly still doesn't support ~/.ssh/config, so Perl's Net::OpenSSH is still my favourite :-) Here's the code I got working with pssh:-
from pssh.clients import SSHClient
HOST = "rocky.lan"
USER = "rocky"
CMD = "while sleep 1; do date; done"
ssh = SSHClient(host=HOST, user=USER)
cmd = ssh.run_command(CMD)
for line in cmd.stdout:
print(line)
So this is an alternative, but really I still need to know how to read the subprocess's stdout using spur.
This question already has an answer here:
Executing command using "su -l" in SSH using Python
(1 answer)
Closed 1 year ago.
I am trying to make script to ssh my device with r/o user and then super user and execute a command.Below are the steps i did on my putty
login as admin ( r/o user) and password.
sudo su and than password
execute a command
print output of executed command
i tried below code to make it working but i didn't get any output.
import paramiko
import pandas as pd
import openpyxl
from paramiko import AuthenticationException
from paramiko.ssh_exception import SSHException, NoValidConnectionsError
import socket
import time
import os
import inspect
import datetime
start = time.time()
print("Starting................................Please Wait")
df=pd.DataFrame(columns=["ip","Status","Remarks"])
ips = ['10.11.8.71']
root = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
#ips = open (root+ "/440_ip.txt")
for ipp in ips:
ip = ipp.strip()
port=22
username='admin'
#password='AeGEBUx66m_1ND'
#cmd='interface wireless set [ find default-name=wlan1 ] ampdu-priorities=0,1,2,3,4,5,6,7 rate-set=configured rx-chains=0,1 scan-list=5825-5875 security-profile=iB440 ssid=iBw supported-rates-a/g="" basic-rates-a/g=""'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip,port,username,timeout=5,password='HeWGEUx66m=_4!ND')
stdin, stdout, stderr = ssh.exec_command('sudo bash', get_pty = True)
time.sleep(0.1)
stdin.write('HeWGEUx66m=_4!ND\n')
stdin.flush()
stdin.write('whoami\n')
#time.sleep(1)
stdin.flush()
dd = stdout.readlines()
print(dd)
ssh.close()
After running the code there is no error, seems it stuck in some loop.,
Starting................................Please Wait
Using ssh with plink in single line command
C:\Users\Administrator\AppData\Local\Programs\Python\Python38>plink.exe -ssh -t admin#10.11.8.71 sudo bash admin#10.11.8.71's password: Access granted. Press Return to begin session. Password: bash-3.2# whoami root bash-3.2#```
To make it working properl i used channels from paramiko, and it worked like charm.
import paramiko
from paramiko import *
from paramiko.channel import Channel
import time
import os
import inspect
import datetime
from socket import *
import pandas as pd
df = pd.DataFrame(columns=["Ip","Status",'Remarks'])
root = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
#ips = ['10.23.0.30', '10.23.0.11','10.23.0.12','10.23.0.13']
ips = open(root+ "\\ahip.txt")
for ipp in ips:
ip = ipp.strip()
print(ip)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(ip, port=22,timeout = 5,username='op', password='C#Uj!AnX')
channel:Channel = ssh.invoke_shell()
#print(type(channel))
channel_data = str()
while True:
#channel.recv_ready():
#time.sleep(1)
channel_data += str(channel.recv(999))
channel.send("su -\n")
time.sleep(1)
#channel_data += str(channel.recv(999))
# if "Password" in channel_data:
channel.send("HeWGEUx\n")
time.sleep(3)
#channel_data += str(channel.recv(999))
channel.send("/bs/lteCli\n")
time.sleep(3)
channel.send("logger threshold set cli=6\n")
time.sleep(4)
channel.send("db set stackCfg [1] EnCLPC=0\n")
time.sleep(4)
channel.send("db get stackCfg EnCLPC\n")
time.sleep(3)
#channel.send("db get stackCfg EnCLPC\n")
time.sleep(.1)
channel_data += str(channel.recv(99999))
str2 = 'Done'
df.loc[ip]=[ip,str2,channel_data]
#print(channel_data)
channel.close()
ssh.close()
break
except (timeout ,AuthenticationException):
print(ip+'not done')
str1 = 'Not Done'
df.loc[ip]=[ip,'failed',str1]
I am working with remote machine. I had to ssh everytime i need verification of file update time and there are multiple scripts which will do ssh to the remote machine.
I look over internet but couldn't find according to my requirements.
I am trying to find a python script which uses ssh and the password is also in the script because my python scripts will check every 5 minutes the file modification times and i cannot enter password everytime the script execute.
I tried these codes from SO and internet but couldn't fulfil my need.
Establish ssh session by giving password using script in python
How to execute a process remotely using python
Also I enter into one remote machine through ssh simply.then I am trying to ssh but via python script to another remote machine cox this python script also include code to check the modification time of different files.. mean i already ssh to one remote machine and then i want to run some python scripts from there which checks file modification time of files on another remote machine.
Is there a simple way to ssh remote machine along with password in python script. .
I would be grateful.
If you want to try paramiko module. Here is a sample working python script.
import paramiko
def start_connection():
u_name = 'root'
pswd = ''
port = 22
r_ip = '198.x.x.x'
sec_key = '/mycert.ppk'
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
my_rsa_key = paramiko.RSAKey.from_private_key_file(sec_key)
session = myconn.connect(r_ip, username =u_name, password=pswd, port=port,pkey=my_rsa_key)
remote_cmd = 'ifconfig'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
print("{}".format(stdout.read()))
print("{}".format(type(myconn)))
print("Options available to deal with the connectios are many like\n{}".format(dir(myconn)))
myconn.close()
if __name__ == '__main__':
start_connection()
Adding my program as well here which relies on the user password and displays the status on different output files.
#!/bin/python3
import threading, time, paramiko, socket, getpass
from queue import Queue
locke1 = threading.Lock()
q = Queue()
#Check the login
def check_hostname(host_name, pw_r):
with locke1:
print ("Checking hostname :"+str(host_name)+" with " + threading.current_thread().name)
file_output = open('output_file','a')
file_success = open('success_file','a')
file_failed = open('failed_file','a')
file_error = open('error_file','a')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(host_name, username='root', password=pw_r, timeout=5)
#print ("Success")
file_success.write(str(host_name+"\n"))
file_success.close()
file_output.write("success: "+str(host_name+"\n"))
file_output.close()
# printing output if required from remote machine
#stdin,stdout,stderr = ssh.exec_command("hostname&&uptime")
#for line in stdout.readlines():
# print (line.strip())
except paramiko.SSHException:
# print ("error")
file_failed.write(str(host_name+"\n"))
file_failed.close()
file_output.write("failed: "+str(host_name+"\n"))
file_output.close()
#quit()
except paramiko.ssh_exception.NoValidConnectionsError:
#print ("might be windows------------")
file_output.write("failed: " + str(host_name + "\n"))
file_output.close()
file_failed.write(str(host_name+"\n"))
file_failed.close()
#quit()
except socket.gaierror:
#print ("wrong hostname/dns************")
file_output.write("error: "+str(host_name+"\n"))
file_output.close()
file_error.write(str(host_name + "\n"))
file_error.close()
except socket.timeout:
#print ("No Ping %%%%%%%%%%%%")
file_output.write("error: "+str(host_name+"\n"))
file_output.close()
file_error.write(str(host_name + "\n"))
file_error.close()
ssh.close()
def performer1():
while True:
hostname_value = q.get()
check_hostname(hostname_value,pw_sent)
q.task_done()
if __name__ == '__main__':
print ("This script checks all the hostnames in the input_file with your standard password and write the outputs in below files: \n1.file_output\n2.file_success \n3.file_failed \n4.file_error \n")
f = open('output_file', 'w')
f.write("-------Output of all hosts-------\n")
f.close()
f = open('success_file', 'w')
f.write("-------Success hosts-------\n")
f.close()
f = open('failed_file', 'w')
f.write("-------Failed hosts-------\n")
f.close()
f = open('error_file', 'w')
f.write("-------Hosts with error-------\n")
f.close()
with open("input_file") as f:
hostname1 = f.read().splitlines()
#Read the standard password from the user
pw_sent=getpass.getpass("Enter the Password:")
start_time1 = time.time()
for i in hostname1:
q.put(i)
#print ("all the hostname : "+str(list(q.queue)))
for no_of_threads in range(10):
t = threading.Thread(target=performer1)
t.daemon=True
t.start()
q.join()
print ("Check output files for results")
print ("completed task in" + str(time.time()-start_time1) + "seconds")
I have the following script which SSH's into a network server and executes some commands, for some reason the SSH connection opens but by the time the commands are executed it closes (I think), as a result the commands are failing with below error? Can anyone provide info how to make the SSH connection persistent?
#!/usr/bin/python
import os
import sys
import json
import fileinput
import pwd
from subprocess import Popen, PIPE, STDOUT
import re
import paramiko
import MySQLdb
resource = r'qca-cdit-01'
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(resource, username='username', password='passwordname')
#chan = ssh.get_transport().open_session()
chan = ssh.invoke_shell()
chan.get_pty()
commandstringlist = \
['/local/mnt/workspace/LA_host_builds/AU_LINUX_ANDROID_LA.BF64.1.2.1_RB2.05.01.01.081.031_msm8992',
'cd frameworks/base',
'git fetch ssh://cdit#review-android.company.com:29418/platform/frameworks/base refs/changes/21/1260821/2 && git cherry-pick FETCH_HEAD']
for cmd_val in commandstringlist:
#chan.exec_command(cmd_val)
chan.send(cmd_val)
print(chan.recv(1024))
error:
Traceback (most recent call last):
File "ssh_test.py", line 21, in <module>
chan.get_pty()
File "/usr/local/lib/python2.7/dist-packages/paramiko/channel.py", line 60, in _check
return func(self, *args, **kwds)
File "/usr/local/lib/python2.7/dist-packages/paramiko/channel.py", line 177, in get_pty
self._wait_for_event()
File "/usr/local/lib/python2.7/dist-packages/paramiko/channel.py", line 1086, in _wait_for_event
raise e
paramiko.ssh_exception.SSHException: Channel closed
Every command you execute using exec_command has a channel of its own and therefore a context of its own. That context includes the working directory. You change the working directory in one context and then try to use it in another. Instead, use the same channel for all the commands. You can either open a channel and use it, or just issue all the commands at once.
commandstringlist = ['cd /local/mnt/workspace/test2 && cd data/log && git fetch ssh://username#review-android.company.com:29418/platform/data/log refs/changes/21/1260821/2 && git cherry-pick FETCH_HEAD']
Here are a few other questions that should explain this in more detail.
https://unix.stackexchange.com/questions/80821/why-does-cd-command-not-work-via-ssh
https://superuser.com/questions/46851/keeping-working-directory-across-ssh
https://stackoverflow.com/a/6770272/492773
The trick is to change to the directory before executing the command. You can easily integrate it into your execute_command:
def execute_command (cmd, pwd=None):
if pwd:
cmd = 'cd "%s";%s' % (pwd, cmd)
print cmd
si,so,se = ssh.exec_command(cmd)
print os.getcwd()
print "printing so"
soreadList = so.readlines()
print soreadList
print "printing se"
errList = se.readlines()
print errList
The command is run by a shell on the remote machine, so any shell tricks like setting environment variables could be added also.
Simply do :
#!/usr/bin/python
import os
import sys
import json
import fileinput
import pwd
from subprocess import Popen, PIPE, STDOUT
import re
import paramiko
import MySQLdb
resource = r'qca-cdit-01'
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(resource, username='username', password='passwordname')
#chan = ssh.get_transport().open_session()
chan = ssh.invoke_shell()
commandstringlist = \
['\n/local/mnt/workspace/LA_host_builds/AU_LINUX_ANDROID_LA.BF64.1.2.1_RB2.05.01.01.081.031_msm8992\n',
'\ncd frameworks/base\n',
'\ngit fetch ssh://cdit#review-android.company.com:29418/platform/frameworks/base refs/changes/21/1260821/2 && git cherry-pick FETCH_HEAD\n']
for cmd_val in commandstringlist:
#chan.exec_command(cmd_val)
chan.send(cmd_val)
print(chan.recv(8192))
which worked for me. (You forgot .send() doesn’t add lines automatically)
Can anyone provide info how to make the SSH connection persistent?
The following is an example of how to make an SSH connection persistent by attempting to execute a command and then falling back on connecting then executing the command when errors occur.
import paramiko
class sshConnection:
def __init__( self, host, un, pw ):
self.host = host
self.un = un
self.pw = pw
def connect( self ):
self.ssh = paramiko.SSHClient()
self.ssh.load_system_host_keys()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect(self.host, username=self.un, password=self.pw)
def cmd ( self, cmd, tries=0 ):
self.si, self.so, self.se = None, None, None
try:
self.si, self.so, self.se= self.ssh.exec_command(cmd)
except Exception, e:
if tries > 3:
raise
self.connect( )
self.cmd( cmd, tries+1 )
return self.si, self.so, self.se
conn = sshConnection( "host","username","password" )
si, out, err = conn.cmd("ls -al")
print "\n".join(map ( lambda x: x.strip(), out.readlines()) )
import paramiko
import os
import sys
ssh = paramiko.SSHClient()
paramiko.util.log_to_file('U:\\Temp\\paramiko.log')
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('172.18.24.234','/TestBTEC/',22,'btectest','M3j0Stanf0rd')
stdin, stdout, stderr = ssh.exec_command("mkdir abc")
stdout.readlines()
This is obviously throwing back errors. What is the proper way to set the home directory on the remote server for user btectest
Instead of setting you can also specify parent directory as userprofile as below
import os
abc_dir = os.path.join('%UserProfile%','abc')
cmd = "mkdir %s" % abc_dir
stdin, stdout, stderr = ssh.exec_command(cmd)
The parameters you are passing to SSHCient.connect() are incorrect (at least for paramiko 1.6+). Your connect() call should look like this:
ssh.connect('172.18.24.234', username='btectest', password='...')
or if you explicitly include the port:
ssh.connect('172.18.24.234', 22, 'btectest', '...')
Once connected, you should already be in the home directory of the user "btectest", as can be seen with this:
stdin, stdout, stderr = ssh.exec_command("pwd")
stdout.readlines()