pexpect not executing command by steps - python

I have this Python3 code which use Pexpect.
import pexpect
import getpass
import sys
def ssh(username,password,host,port,command,writeline):
child = pexpect.spawn("ssh -p {} {}#{} '{}'".format(port,username,host,command))
child.expect("password: ")
child.sendline(password)
if(writeline):
print(child.read())
def scp(username,password,host,port,file,dest):
child = pexpect.spawn("scp -P {} {} {}#{}:{}".format(port,file,username,host,dest))
child.expect("password: ")
child.sendline(password)
try:
filename = sys.argv[1]
print("=== sendhw remote commander ===")
username = input("Username: ")
password = getpass.getpass("Password: ")
ssh(username,password,"some.host.net","22","mkdir ~/srakrnSRV",False)
scp(username,password,"some.host.net","22",filename,"~/srakrnSRV")
ssh(username,password,"some.host.net","22","cd srakrnSRV && sendhw {}".format(filename),True)
except IndexError:
print("No homework name specified.")
My aim is to:
SSH into the host with the ssh function, create the directory srakrnSRV, then
upload a file into the srakrnSRV directory, which is previously created
cd into srakrnSRV, and execute the sendhw <filename> command. The filename variable is defined by command line parameteres, and print the result out.
After running the entire code, Python prints out
b'\r\nbash: line 0: cd: srakrnSRV: No such file or directory\r\n'
which is not expected, as the directory should be previously created.
Also, I tried manually creating the srakrnSRV folder in my remote host. After running the command again, it appears that scp function is also not running. The only runnning pexpect coomand was the last ssh function.
How to make it execute in order? Thanks in advance!

You may lack permission for executing commands through ssh. Also there is possibility that your program sends scp before prompt occurs.

Related

How to execute a Python program without any interruption when we change the shell or switch the Linux users inside the program?

Scenario: I made one program where I am taking the input file and execute the shell commands inside the file line by line using Python. But I noticed when we change the shell or switch the user, the execution stops on the go.
Input File:
# cat commands.txt
free -m
touch hi
ls -lrt
su - user
Code:
# cat mylinux.py
# This program is to interact with Linux
try:
import os
import subprocess
import shlex
print("This is an interactive linux session using Python! \nHere if you want to exit the session, type exit as the input command")
print("Your RHEL OS version is "+subprocess.run(shlex.split("cat /etc/redhat-release"),stdout=subprocess.PIPE).stdout.decode())
i = input("Enter the file name: ")
inputfile = open(i,"r")
for line in inputfile:
o=subprocess.run(shlex.split(line), stdout=subprocess.PIPE).stdout.decode()
print(o)
except FileNotFoundError:
if i != "exit":
print("Please re-run the script and make sure to give some valid commands.")
print("Thank you for using your PyShell!")
except IndexError:
print("Bye! Next time, type some valid commands")
How would I make sure this works even when the shell or user changes?

how to interact with Paramiko's interactive shell session?

I have some Paramiko code where I use the invoke_shell method to request an interactive ssh shell session on a remote server. Method is outlined here: invoke_shell()
Here's a summary of the pertinent code:
sshClient = paramiko.SSHClient()
sshClient.connect('127.0.0.1', username='matt', password='password')
channel = sshClient.get_transport().open_session()
channel.get_pty()
channel.invoke_shell()
while True:
command = raw_input('$ ')
if command == 'exit':
break
channel.send(command + "\n")
while True:
if channel.recv_ready():
output = channel.recv(1024)
print output
else:
time.sleep(0.5)
if not(channel.recv_ready()):
break
sshClient.close()
My question is: is there a better way to interact with the shell? The above works, but it's ugly with the two prompts (the matt#kali:~$ and the $ from raw_input), as shown in the screenshot of a test run with the interactive shell. I guess I need help writing to the stdin for the shell? Sorry, I don't code much. Thanks in advance!
I imported a file, interactive.py, found on Paramiko's GitHub. After importing it, I just had to change my code to this:
try:
import interactive
except ImportError:
from . import interactive
...
...
channel.invoke_shell()
interactive.interactive_shell(channel)
sshClient.close()
You can try disabling echo after invoking the remote shell:
channel.invoke_shell()
channel.send("stty -echo\n")
while True:
command = raw_input() # no need for `$ ' anymore
... ...

installing software on remote machine via python script

this is for work... so i will share as much as i can, I'm trying to install "environment" on a remote machine via python script, this "environment" require to pass to it user name and password, I tried a lot of things, nothing seems to work... the closest thing is this script, yet after it passes the user name a GUI popup and ask for the password... what i'm doing wrong ?! or what can i do to make it work?!... here is a part of the script that deal with pexpect
import os
import pexpect
cmd = 'ssh -X groupName#machineName cd ~/theLocationOfTheInstallation/ && pwd && theFullPathOfTheFileToInstall'
child = pexpect.spawn(cmd)
cmd_show_data = ''
usr = 'userName'
pas = 'myPassword'
while not child.eof() :
index = child.expect(['Please enter your.*','pass.*', pexpect.EOF, pexpect.TIMEOUT])
cmd_show_data += child.before
child.delaybeforesend = 1
if index == 0 :
print 'user name required, "'+usr+'" is passed'
child.sendline(usr)
elif index == 1 :
print 'password required, "'+pas+'" is passed'
child.sendline(pas)
elif index == 2 :
print 'EOF'
elif index == 3 :
print 'TIMEOUT'
cmd_show_data += child.before
cmd_show_data = cmd_show_data.split('\r\n')
for s in cmd_show_data :
print s
this is the GUI that popup :
if i enter the password manually (which i'm trying to avoid), i get output like this :
user name required, "userName" is passed
TIMEOUT
TIMEOUT (a lot of times out)
user name required, "userName" is passed
TIMEOUT
TIMEOUT (a lot of times out)
password required, "myPassword" is passed
TIMEOUT
TIMEOUT (a lot of times out).... till the installation is complete.
so.. any ideas?
If you really want to do this job with only Python, why can't you use Ansible instead?
Ansible solution:
If you have a script which installs software locally, then run that script in remote servers with the Ansible script module
# Example from Ansible Playbooks
- script: /some/local/script.py 1234
Python file example :
#!/usr/bin/python
import sys
print 'Number of arguments:', len(sys.argv), 'arguments.'
print '1st Argument :', str(sys.argv[1])
Here are some documentation links:
http://docs.ansible.com/ansible/script_module.html
http://docs.ansible.com/ansible/intro_adhoc.html

Script to capture everything on screen

So I have this python3 script that does a lot of automated testing for me, it takes roughly 20 minutes to run, and some user interaction is required. It also uses paramiko to ssh to a remote host for a separate test.
Eventually, I would like to hand this script over to the rest of my team however, it has one feature missing: evidence collection!
I need to capture everything that appears on the terminal to a file. I have been experimenting with the Linux command 'script'. However, I cannot find an automated method of starting script, and executing the script.
I have a command in /usr/bin/
script log_name;python3.5 /home/centos/scripts/test.py
When I run my command, it just stalls. Any help would be greatly appreciated!
Thanks :)
Is a redirection of the output to a file what you need ?
python3.5 /home/centos/scripts/test.py > output.log 2>&1
Or if you want to keep the output on the terminal AND save it into a file:
python3.5 /home/centos/scripts/test.py 2>&1 | tee output.log
I needed to do this, and ended up with a solution that combined pexpect and ttyrec.
ttyrec produces output files that can be played back with a few different player applications - I use TermTV and IPBT.
If memory serves, I had to use pexpect to launch ttyrec (as well as my test's other commands) because I was using Jenkins to schedule the execution of my test, and pexpect seemed to be the easiest way to get a working interactive shell in a Jenkins job.
In your situation you might be able to get away with using just ttyrec, and skip the pexpect step - try running ttyrec -e command as mentioned in the ttyrec docs.
Finally, on the topic of interactive shells, there's an alternative to pexpect named "empty" that I've had some success with too - see http://empty.sourceforge.net/. If you're running Ubuntu or Debian you can install empty with apt-get install empty-expect
I actually managed to do it in python3, took a lot of work, but here is the python solution:
def record_log(output):
try:
with open(LOG_RUN_OUTPUT, 'a') as file:
file.write(output)
except:
with open(LOG_RUN_OUTPUT, 'w') as file:
file.write(output)
def execute(cmd, store=True):
proc = Popen(cmd.encode("utf8"), shell=True, stdout=PIPE, stderr=PIPE)
output = "\n".join((out.decode()for out in proc.communicate()))
template = '''Command:\n====================\n%s\nResult:\n====================\n%s'''
output = template % (cmd, output)
print(output)
if store:
record_log(output)
return output
# SSH function
def ssh_connect(start_message, host_id, user_name, key, stage_commands):
print(start_message)
try:
ssh.connect(hostname=host_id, username=user_name, key_filename=key, timeout=120)
except:
print("Failed to connect to " + host_id)
for command in stage_commands:
try:
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(command)
except:
input("Paused, because " + command + " failed to run.\n Please verify and press enter to continue.")
else:
template = '''Command:\n====================\n%s\nResult:\n====================\n%s'''
output = ssh_stderr.read() + ssh_stdout.read()
output = template % (command, output)
record_log(output)
print(output)

How to modify rc.local in shell script?

I want to add a line(such as '*/data/mod/myservice start some_parameter*'.) to /etc/rc.d/rc.local file in shell script. If there exists a line start with '*/data/mod/myservice start*', then replace it by new one.
In my script, it execute the next python method.
def excuteCmd(cmd):
import commands
output = commands.getoutput(cmd)
def setTask(cmd, installFlag):
print cmd, installFlag
excuteCmd('cat /etc/rc.d/rc.local > oldTask')
input = open('oldTask','r')
emptyFile = False
lines = input.readlines()
input.close()
taskNum = len(lines)
output = open('newTask', 'w')
if (taskNum == 0):
if (installFlag):
output.write(cmd + '\n')
else:
for i in range(taskNum):
if (lines[i].find(cmd) == -1):
output.write(lines[i])
if (installFlag):
output.write(cmd + '\n')
output.close()
excuteCmd('sudo cat newTask > /etc/rc.d/rc.local')
excuteCmd('rm -f oldTask')
excuteCmd('rm -f newTask')
But when i execute sudo cat newTask > /etc/rc.d/rc.local, it raise the following error.
-bash: /etc/rc.d/rc.local: Permission denied
This means that you don't have permission to either write to or delete the file. Also, you won't be able to run the sudo command like that without typing in a password, so ideally the script itself would be run using sudo python scriptname.
sudo command > filename executes command using sudo (with root privileges), but writes into the filename with user's privileges (insufficient to write to /etc). Imagine it like this:
(sudo command) > filename
The sudo applies to the bracketed part only.
You could run your whole script using sudo.

Categories

Resources