I am working on some python code to log into a whitebox device that houses a virtual application (VTA). There will be two different VTAs installed and the code will log into the physical device, then log into the VTA using a virsh console (Name of VTA).
The issue I am running into is exiting one VTA and then virsh console into another. The exit command simply brings me to a login prompt again but will not exit out of the console connection.
In order to do so, I must send a "control + ]" in order to break out of the console. I have been searching online to try and find a solution but the only option I have found is to send and "exit" followed by "\x1b". However, This does not actually break out of the console window. Rather, it ends the session which is not what I am looking for.
Is there a way to send a "Control + ]" in python?
Here is some of the code showing the steps:
from paramiko import SSHClient, AutoAddPolicy
import time
import re
import os
import sys
import progressbar
import stat
def create_connection(host):
username = ''
password = ''
port = 22
connection_info = {
'port': port,
'username': username,
'password': password
}
client = SSHClient()
client.set_missing_host_key_policy(AutoAddPolicy())
client.connect(host, timeout=10, auth_timeout=10, **connection_info)
ssh_session = client.invoke_shell()
ssh_session.settimeout(10.0)
return ssh_session
def send_commands(ssh_session, commands, sleep_time=1):
for command in commands:
ssh_session.send(command)
time.sleep(sleep_time)
output = ssh_session.recv(1048576)
decoded_output = output.decode()
return decoded_output
console_commands = [
'virsh console vw-vta\n',
'\n',
'\n', # Place the username of the VTA here
'\n' # Place the password of the VTA here
]
show_mgmt_commands = [
'ifconfig ens2 | grep Bcast\n'
]
exit_console = [
'exit\n'
'\x1b'
]
validate_commands = [
'virsh list\n'
]
def validation():
host = input('What is the IP address? ')
print('\n')
print(f'\033[1;33m--< Checking {host} for a valid VTA >------------\033[0m')
try:
ssh_session = create_connection(host)
except Exception as l:
print(f"\033[1;31mCannot connect to {host}!\033[0m")
return
validate = send_commands(ssh_session, validate_commands)
if 'y1564' in validate:
print(f"\033[1;32mThere is a Y1564 VTA running! Obtaining information...\033[0m")
ssh_session = create_connection(host)
console = send_commands(ssh_session, console_commands)
try:
show_mgmt = send_commands(ssh_session, show_mgmt_commands, sleep_time=2)
except Exception as e:
print(f"\033[1;31mCouldn't reach the console on " f"\033[1;33m{host}\033[0m"f"\033[1;31m. This VTA will need to be rebuilt.\033[0m")
if 'Login incorrect' in show_mgmt:
print(f"\033[1;31m--< Begin ERROR MESSAGE >------------\033[0m")
print(show_mgmt)
print(f"\033[1;31m--< End ERROR MESSAGE >------------\033[0m")
print(f"\033[1;31mThis VTA has the incorrect password!\033[0m")
print(f'{host},VTA Password Error', file=f)
exit = send_commands(ssh_session, exit_console)
return
else:
try:
mgmt = show_mgmt.split('addr:')[1].split(" ")[0]
except Exception as g:
print(f"\033[1;31mThis VTA is corrupt and will need to be rebuilt!\033[0m")
exit = send_commands(ssh_session, exit_console)
return
print("Y1564 VTA IP: ", mgmt)
exit = send_commands(ssh_session, exit_console)
else:
print("\033[1;33mThere is NOT a Y1564 VTA running on \033[0m"f"\033[1;34m {host}\033[0m")
ssh_session.close()
if __name__ == '__main__':
full_check()
When this function finishes, the second part of the code calls a similar function. However it fails because the previous function did not break out of the console connection. The code attempts to send the commands for the next function while it is still inside the previous VTA.
Here is an output showing what it is doing:
What is the IP address? 1.1.1.1
--< Checking 1.1.1.1 for a valid VTA >------------
There is a Y1564 VTA running! Obtaining information...
Y1564 VTA IP: 10.10.10.10
exit
logout
--< Checking 1.1.1.1 for a valid VTA >------------
Ubuntu 16.04.6 LTS y1564 ttyS0
y1564 login:
virsh list
Password:
There is NOT a VTA running on 1.1.1.1
The output above shows that when the exit command is run and followed by the \x1b, it does not properly exit out but attempts to send the "virsh list" command from the next part.
The hex character you're using to send the ctrl+] is wrong. Update your exit console commands to this:
exit_console = [ 'exit\n', '\x01D' ]
ASCII Reference: http://www.physics.udel.edu/~watson/scen103/ascii.html
It also looks like you're using the invoke_shell() method, you can use the close() method to exit out of that particular shell and establish a new one as needed.
Paramiko reference: http://docs.paramiko.org/en/stable/api/channel.html
Related
Django API Code:
def post(self,request)-> JsonResponse:
try:
self.email = request.data['email']
self.mobile = request.data['mobile']
self.password = request.data['password']
except Exception as e:
return JsonResponse(create_failure('400',f"invalid payload {e}","fail"))
try:
res = {}
jwt_token = ''
if self.email:
password = Customer.objects.get(email=self.email).password
username = Customer.objects.get(email=self.email).username
print(password)
if check_password(self.password,password) :
jwt_token = make_jwt_token({'username':username})
else:
return JsonResponse(create_failure('500',f"Invalid password","fail"))
elif self.mobile:
password = Customer.objects.get(mobile=self.mobile).password
username = Customer.objects.get(mobile=self.mobile).username
if check_password( password,self.password) :
jwt_token = make_jwt_token({'username':username})
else:
return JsonResponse(create_failure('500',f"Invalid password","fail"))
res['token'] = jwt_token
except Exception as e:
return JsonResponse(create_failure('400',f"error in verifying the password {e}","fail"))
return JsonResponse(create_success('User Verified',res))
Error while running it on the postman
{
"StatusCode": "400",
"Message": "error in verifying the password [Errno 5] Input/output error",
"ReplyCode": "fail",
"Data": []
}
Above code is working fine on the local machine, but it creates this error when I deploy it to the server. I am using cpanel for the hosting which uses CentOS
Resolved I just had to remove the print from the code.
This might happen if your server has nowhere to put the print statements.
For example, I was running a server in one terminal window, then somehow the window got closed but the server was still running. There are 2 options, depending on your situation:
Kill the process. Start a new server: sudo kill -9 $(sudo lsof -t -i:8000). (or search "find port and kill process [YOUR_OS]" to find OS-specific information. More details
Pipe your command output: python MY_SCRIPT.py >/dev/null More details
I hope everyone is good , i just work with one python code for check status for spawn status , but always shown me this error message , while When i went to the server and write the same command it is working without any error.
path of the spawn in my server is :
Server01:> which spawn
/st/ex/sap/spawn/bin/spawncmd
ksh: spawn: not found
import paramiko
hostname = "yyy.com"
user = "me"
password = 'hello'
commands = [ # "df -h",
# "pwd"
"spawn status"
]
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(hostname=hostname, username=user, password=password)
except:
print("can not do it ")
exit()
for command in commands:
print("command", command, "commands")
stdin, stdout, stderr = client.exec_command(command)
print(stdout.read().decode())
err = stderr.read().decode()
if err:
print(err)
Any creative idea to solve this
I'm using a python script to manage ssh fingerprint problems after a workstation(s) is reimaged.
I attempt to connect with ssh, and if I get a any warnings I deal with them.
However, if there are no errors, then I am asked for a password to connect. At this point I want to terminate the process. However, the script hangs on the password request.
Here's the method:
def ssh_fingerprint_changed(node):
"""
Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
It does this by attempting to connect via ssh and inspecting stdout for an error message.
:param node: the ip or hostname of the node
:return: True if the node's fingerprint doesn't match the client's records. Else False.
"""
changed = False
cmd = ["ssh", "-q", ADMIN_USER + "#" + node, "exit"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
print("Checking for fingerprint changes")
for line in proc.stdout: # loop on lines
print("in for loop") # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
if b"Offending key" in line:
print("Offending key found.")
proc.stdin.write(b"no\n") # don't connect
changed = True
elif b"REMOTE HOST IDENTIFICATION HAS CHANGED!" in line:
print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
changed = True
print(changed) # NEVER REACHES HERE IF NO ERRORS, WAITING FOR PASSWORD
if not changed: # then everything's good, but it will be waiting for a password to connect
print("Good to go, terminating ssh test.")
rc = proc.terminate()
else:
rc = proc.wait()
return changed
If I run this from the terminal ./my_python_script.py, I have the problems. Oddly, if I run in PyCharm, it doesn't hang on the password request and terminates shh, continuing with the script as expected.
The easy answer is simply to tell ssh that you don't want to support password authentication at all; you'll still get the messages you want if the host key is changed, but you won't ever have the process hanging waiting for a password to be entered.
cmd = ['ssh',
'-o', 'PasswordAuthentication no', ### <-- THIS LINE HERE
'-o', 'StrictHostKeyChecking yes', ### also, never modify known_hosts
'-q',
'%s#%s' % (ADMIN_USER, + node),
'exit']
If you did not want to process other prompts, I would suggest setting stdin=subprocess.DEVNULL (in Python 3) or passing the -n argument to ssh to prevent stdin from being passed to the process at all.
My goal is to connect to SSH with python and authenticate which i can do with Paramiko or Fabric. But i would like to keep the session open after each execution and read the input/output. With paramiko i can only run 1 command before the session is closed and i am asked to authenticate again and the session hangs. And since fabric is using the paramiko library its giving me the same issue. For example if my directory structure is like this
-home
--myfolder1
--myfolder2
I would like to execute the below commands without having to re-authenticate because the sessions closes.
(make connection)
run cmd: 'pwd'
output: /home
run cmd: 'cd myfolder2'
run cmd: 'pwd'
output: /home/myfolder2
Is this possible with any module that is out there right now? Could it be made from scratch with native python? And also is this just not possible...?
Edit Added code. Without the new open_session it closes and i cannot run any command. After running the first command with this i will be prompted again to authenticate and it creates an infinite loop.
Edit2 If it closes after each command then there is no way this will work at all correct?
edit3 If i run this on a different server and exec_command with the paramikio.SSHClient it wont ask me to reauthenticate but if i 'cd somedir' and then 'pwd' it will output that i am back in the root directory of where i created.
class connect:
newconnection = ''
def __init__(self,username,password):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect('someserver', username=username,password=password,port=22,timeout=5)
except:
print "Count not connect"
sys.exit()
self.newconnection = ssh
def con(self):
return self.newconnection
#This will create the connection
sshconnection = connect('someuser','somepassword').con()
while True:
cmd = raw_input("Command to run: ")
if cmd == "":
break
try:
transport = sshconnection.get_transport()
transport.set_keepalive(999999)
chan = transport.open_session()
chan.settimeout(3)
chan.setblocking(0)
except:
print "Failed to open a channel"
chan.get_exception()
sys.exit()
print "running '%s'" % cmd
stdout_data = []
stderr_data = []
pprint.pprint(chan)
nbytes = 4096
chan.settimeout(5)
chan.get_pty()
chan.exec_command(cmd)
while True:
print "Inside loop " , chan.exit_status_ready()
time.sleep(1.2)
if chan.recv_ready():
print "First if"
stdout_data.append(chan.recv(nbytes))
if chan.recv_stderr_ready():
print "Recv Ready"
stderr_data.append(chan.recv_stderr(nbytes))
if chan.exit_status_ready():
print "Breaking"
break
print 'exit status: ', chan.recv_exit_status()
print ''.join(stdout_data)
This is possible by using the normal modules when you can concatenate the commands into one. Try
pwd ; cd myfolder2 ; pwd
as command. This should work but quickly becomes tedious when you have more complex commands which need arguments and horrible when the arguments contain spaces. The next step then is to copy a script with all the commands to the remote side and tell ssh to execute said script.
Another problem of this approach is that SSH doesn't return until all commands have executed.
Alternatively, you could build a "command server", i.e. a simple TCP server that listens for incoming connections and executes commands sent to it. It's pretty simple to write but also pretty insecure. Again, the solution is to turn the server into a (Python) script which reads commands from stdin and start that script remotely via SSH and then send 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.