Cannot ssh to run a remote script using Python - python

I have the script below (test.py on 1.1.1.1) to run another remote script on another server (script.py on 2.2.2.2). I have set up the ssh keys so I don't get prompted for password.
import subprocess
USER="user"
SERVER_IP="2.2.2.2"
SCRIPT_PATH="/home/abc/script.py"
print ("ssh {0}#{1} '/usr/bin/python {2} aaa bbb'".format(USER, SERVER_IP, SCRIPT_PATH))
rc = subprocess.check_output("ssh {0}#{1} '/usr/bin/python {2} aaa bbb'".format(USER, SERVER_IP, SCRIPT_PATH))
script.py itself is on 1.2.3.4, and takes in 2 arguments.
If I copy the command that is printed out in the script, I can execute script.py successfully on 1.1.1.1. But running test.py on 1.1.1.1 gives me an error:
OSError: [Errno 2] No such file or directory
I don't understand why the script didn't work but the exact same command works on its own.

Use the additional argument:
shell=True
Your command will be:
rc = subprocess.check_output("ssh {0}#{1} '/usr/bin/python {2} aaa bbb'".format(USER, SERVER_IP, SCRIPT_PATH),shell=True)
I assume you need a shell to run a python script.

If your question is to address the need of executing a remote command and not making your script working - then if I could introduce Paramiko:
import paramiko
ssh_handle = paramiko.SSHClient()
ssh_handle.load_system_host_keys()
ssh_handle.connect(
hostname=address,
port=int(port),
username=login)
stdin, stdout, stderr = ssh_handle.exec_command("whoami")
IMO it's currently the most "usable" SSH library and works just fine in my projects.

Related

Pass arguments to a bash script stored locally and needs to be executed on a remote machine using Python Paramiko

I have a shell script stored on my local machine. The script needs arguments as below:
#!/bin/bash
echo $1
echo $2
I need to run this script on a remote machine (without copying the script on the remote machine). I am using Python's Paramiko module to run the script and can invoke on the remote server without any issue.
The problem is I am not able to pass the two arguments to the remote server. Here is the snippet from my python code to execute the local script on the remote server:
with open("test.sh", "r") as f:
mymodule = f.read()
c = paramiko.SSHClient()
k = paramiko.RSAKey.from_private_key(private_key_str)
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect( hostname = "hostname", username = "user", pkey = k )
stdin, stdout, stderr = c.exec_command("/bin/bash - <<EOF\n{s}\nEOF".format(s=mymodule))
With bash I can simply use the below command:
ssh -i key user#IP bash -s < test.sh "$var1" "$var2"
Can someone help me with how to pass the two arguments to the remote server using Python?
Do the same, what you are doing in the bash:
command = "/bin/bash -s {v1} {v2}".format(v1=var1, v2=var2)
stdin, stdout, stderr = c.exec_command(command)
stdin.write(mymodule)
stdin.close()
If you prefer the heredoc syntax, you need to use the single quotes, if you want the argument to be expanded:
command = "/bin/bash -s {v1} {v2} <<'EOF'\n{s}\nEOF".format(v1=var1,v2=var1,s=mymodule)
stdin, stdout, stderr = c.exec_command(command)
The same way as you would have to use the quotes in the bash:
ssh -i key user#IP bash -s "$var1" "$var2" <<'EOF'
echo $1
echo $2
EOF
Though as you have the script in a variable in your Python code, why don't you just modify the script itself? That would be way more straightforward, imo.
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".

Running a local python script with args on a remote host

I got a python script from which I use ssh to open a connection to a different host. During this session I’m trying to run another python script, with several arguments (the script is on my machine and not on the server) but the arguments are messing it up. It links the arguments to the python interpreter rather than my script.
My code looks like this:
ssh remotehost python2 < /path/to/script —-arg1 hello —-arg2 goodbye
And the error I’m getting is unknown option per each character in the argument’s name, for example:
Unknown option: —-
Unknown option:a
Unknown option:r
etc.. anyway I can pass arguments without getting this error? I tried using sys args but my arguments are sentences sometimes and it doesn’t parse it well..
To execute Scripts on a different server use paramiko to connect and to execute commands:
Import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(host,port,user,password)
stdin, stdout, stderr = client.exec_command('python2 /path/to/script hello goodbye')
client.close()
Full doc:
http://docs.paramiko.org/en/stable/api/client.html
to run a local script on a different server use:
ssh user#machine python < script.py - arg1 arg2
see Run local python script on remote server

Paramiko ssh connection to windows host. Empty stdout of "VBoxManage.exe guestcontrol run" command

I'm writing python script executing bash script inside virtualbox VM using paramiko python library. The code snippet below:
stdin, stdout, stderr = i[2].exec_command("\"\Program Files\Oracle\VirtualBox\VBoxManage.exe\" guestcontrol \"virtnet_proxy\" run --exe \"/home/username/show_ip.sh\" --username username --password password" )
exit_status = stdout.channel.recv_exit_status()
if exit_status == 0:
proxy_ip=stdout.readlines()
print ("got proxy ip from host ", i[0], proxy_ip, stderr.readlines())
Connects to windows host and
should print ip address of a VM's interface. If you run this command in cmd it works fine but using paramiko ssh client, stdout is empty. If you run similar code except you connect to linux virtualbox host (and run linux command) stdout.readlines() works fine and contains output of bash script. Stderr output:
VBoxManage.exe: warning: Error getting stdout handle: VERR_NOT_IMPLEMENTED\r\n', 'VBoxManage.exe: warning: Error getting stderr handle: VERR_NOT_IMPLEMENTED\r\n
Bash script:
ips=$(hostname --all-ip-addresses)
read -ra arr <<< "$ips"
echo"${arr[0]}"
As i said stdout is empty only if you connect to windows host and run vboxmanage command on guest machine.
Thank You in advance,
Wojtek
EDIT: I've changed ssh server on windows host from OpenSSH to FreeSSHd and the code worked !

Executing remote script locally using subprocess - Remote script uses vars from ~/.profile

I am executing a script that resides on the remote server.
This bash script makes use of a variable.
This variable is defined in ~/.profile.
For this purpose lets say it
$MYVAR=/a/b/c
So on remote server, or even ssh to remote and I execute
echo $MYVAR returns /a/b/c as you would expect.
But if I execute the remote script locally using python subprocess, the script fails. It fails as the script uses the $MYVAR which translates as soemthing incorrect.
This is because I am executing it via SSH, the ~./profile must not be getting loaded and instead it is using some other profile.
see here https://superuser.com/questions/207200/how-can-i-set-environment-variables-for-a-remote-rsync-process/207262#207262
Here is the command executed from a python script
ssh = subprocess.Popen(['ssh', '%s' % env.host, 'cd /script/dir | ./myscript arg1 arg2'],shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
My question is how can I run a script locally, that will ssh to remote, load the users ~/.profile then execute a bash script.
you can use paramiko module to run the scripts on remote server from locally.
http://www.paramiko.org/
Once installed , you can run the command as shown in example below
import paramiko
command=" 'ssh', '%s' % env.host, 'cd /script/dir | ./myscript arg1 arg2' "
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.18.1.26',port=22,username='root',password='defassult') #This will connect to remote server
stdin,stdout,stderr=ssh.exec_command(command) #This will execute the command on remote server
output=stdout.readlines()
print '\n'.join(output)
The easiest solution for this was to create a sort of wrapper script like so
#!/bin/bash
. /users/me/.profile
cd /dir/where/script/exists/
exec script LIVE "$#"
So now then create a method in the python script to scp the wrapper script to tmp dir
scp wrapper user#remote:/tmp
Now ssh command in the question becomes
subprocess.Popen(['ssh', '%s' % env.host, env.installPatch],shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
env.installPatch translates to:
cd /tmp; ./wrapper 'patch_name'
Now the .profile is loaded and the patch script has the correct variable vals.
With using exec I get all the output back from the patch o/p and can write to file.
This was the cleanest solution for my case.

Clustat command not found error in python script

Hi I am trying to create a script using python to log on to a server and to check the status of the cluster by running a clustat command. When I do this I get the following error:
/bin/sh: clustat: command not found
As I understand it, it's not able to run the command as this is a non standard bash command that is being used. I was hoping someone would have some ideas to get around this to get it work.
Below is the method used to run the command:(I have antoher method to ssh onto the system it works fine)
def run_cmd(command):
"""Function for running command on the system."""
proc = subprocess.Popen([command], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
return out
This is where it seems to go wrong. I know the run_cmd method works as I am able to use it with other commands:
run_cmd("clustat >> out.txt")
return ""
subprocess runs the commands locally.
You will have to use paramiko.SSHClient to run commands on the remote machine.
ssh_client = paramiko.SSHClient()
ssh_client.connect(host='some_host', username='username', password='password')
ssh_client.exec_command('clustat >> out.txt')

Categories

Resources