I'm ultimately trying to create some basic functions to control my cisco test lab devices using Exscript. Exscript has done everything perfectly for me up to this point and I'm just pulling a few functions for example.
What I'm having trouble with is creating this reload_start() function that executes the reload command, rebooting my Cisco device and reverting any changes I've made in my test run. I've tried dozens of different combinations of character strings to execute but cannot get it to work around the additional prompts that come up when typing 'reload'
In contrast, my copy_to_running_config() function works just fine, simply by adding '\n' at the end of the string.
I've not yet jumped into Exscript's prompt functions(get_prompt(), expect_prompt(), waitfor(), etc), and I'm guessing this is the avenue I need to explore, but I cannot find examples of this that deal with my specific goal.
from Exscript import Account
from Exscript.protocols import Telnet
from Exscript.protocols.drivers import ios
def __init__(self, ip):
self.ip = ip
self.account = Account('admin', 'key')
self.conn = Telnet()
self.conn.set_driver('ios')
self.conn.connect(ip)
self.conn.login(self.account)
self.conn.execute('terminal length 0')
def enable(self):
self.conn.execute('enable')
def copy_to_running_config(self, config):
self.enable()
self.conn.execute('copy flash:{0} running-config \n'.format(config))
res = self.conn.response
self.conn.execute('exit')
return res
def reload_start(self):
self.enable()
self.conn.execute('reload \n no \n')
print self.conn.response
Any help or input would be greatly appreciated!
Your Function reload_start should look like this:
def reload_start(self):
self.enable()
self.conn.set_prompt(r'Save\? \[yes/no\]\:')
self.conn.execute('reload')
self.conn.set_prompt(r'Proceed with reload\? \[confirm\]')
self.conn.execute('no')
self.conn.set_prompt()
self.conn.execute('confirm')
print self.conn.response
You have to set the Regular Expression for the prompt before executing the command. Otherwise Exscrpt is not be able to determine when to send the next command.
Nevertheless, if the configuration wasn't changed and the router doesn't ask you to save, the script above would not work because it would wait for the save-question.
Related
I am trying to make a script to automate the login into Microsoft Teams and all of my code works except the part where the application has to be opened. The weird thing is that this is capable of opening any other application except MS Teams (Chrome, Notepad, Firefox, Edge etc.)
Here's the relevant code:
def openfile():
if os.stat("stor.txt").st_size == 0:
name = filedialog.askopenfilename()
newfile = open("stor.txt", "w")
newfile.write(name)
else:
name = (open("stor.txt", "r").read())
os.startfile(name)
sleep(5)
keyboard.write(open("user.txt", "r").read())
keyboard.press("enter")
sleep(3)
keyboard.write(open("pass.txt", "r").read())
keyboard.press("enter")
I tried this with os.startfile, os.system(start..) and every other method on the web. Doesn't work.
The value I'm passing in to os.startfile() when I try to run Teams is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe.
First of all, I don't recommend storing your password in plain text like that. It's not very secure, and if another program takes focus at the right time your code will even type your password somewhere else!
Teams should remember your credentials after the first time you log in. I suggest letting it handle that part.
In any case, running os.startfile("foo.exe") is like double-clicking on foo.exe. The file name that you're passing in is C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe, and Update.exe doesn't look like something that should launch Teams to me.
Inspecting the Teams shortcut in my own Start menu, I see that things are a bit more complicated. This shortcut runs Update.exe and passes it some arguments:
C:\...\Update.exe --processStart "Teams.exe"
There is no way to pass arguments to a program with os.startfile(). Try os.system() instead:
os.system('C:/Users/Raghav/AppData/Local/Microsoft/Teams/Update.exe --processStart "Teams.exe"')
There are lots of other ways to run external commands in Python, but this is likely simplest since you don't need Teams' output streams. This command should return 0 if it succeeds and some other value if it fails.
import os
os.system("C:\\Users\\Lenovo\\AppData\\Local\\Discord\\Update.exe --processStart Discord.exe")
For applications that have an address like above, there are also some tips:
Sometimes Discord.exe name of the file in the address have "Discord.exe" (with double-quotes). Remove it.
Instead of single \ use double \\ in the address.
It will definitely work GO AHEAD ✔
So i have a script from Python that connects to the client servers then get some data that i need.
Now it will work in this way, my bash script from the client side needs input like the one below and its working this way.
client.exec_command('/apps./tempo.sh' 2016 10 01 02 03))
Now im trying to get the user input from my python script then transfer it to my remotely called bash script and thats where i get my problem. This is what i tried below.
Below is the method i tried that i have no luck working.
import sys
client.exec_command('/apps./tempo.sh', str(sys.argv))
I believe you are using Paramiko - which you should tag or include that info in your question.
The basic problem I think you're having is that you need to include those arguments inside the string, i.e.
client.exec_command('/apps./tempo.sh %s' % str(sys.argv))
otherwise they get applied to the other arguments of exec_command. I think your original example is not quite accurate in how it works;
Just out of interest, have you looked at "fabric" (http://www.fabfile.org ) - this has lots of very handy funcitons like "run" which will run a command on a remote server (or lots of remote servers!) and return you the response.
It also gives you lots of protection by wrapping around popen and paramiko for hte ssh login etcs, so it can be much more secure then trying to make web services or other things.
You should always be wary of injection attacks - Im unclear how you are injecting your variables, but if a user calls your script with something like python runscript "; rm -rf /" that would have very bad problems for you It would instead be better to have 'options' on the command, which are programmed in, limiting the users input drastically, or at least a lot of protection around the input variables. Of course if this is only for you (or trained people), then its a little easier.
I recommend using paramiko for the ssh connection.
import paramiko
ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(server, username=user,password=password)
...
ssh_client.close()
And If you want to simulate a terminal, as if a user was typing:
chan=ssh_client.invoke_shell()
chan.send('PS1="python-ssh:"\n')
def exec_command(cmd):
"""Gets ssh command(s), execute them, and returns the output"""
prompt='python-ssh:' # the command line prompt in the ssh terminal
buff=''
chan.send(str(cmd)+'\n')
while not chan.recv_ready():
time.sleep(1)
while not buff.endswith(prompt):
buff+=ssh_client.chan.recv(1024)
return buff[:len(prompt)]
Example usage: exec_command('pwd')
And the result would even be returned to you via ssh
Assuming that you are using paramiko you need to send the command as a string. It seems that you want to pass the command line arguments passed to your Python script as arguments for the remote command, so try this:
import sys
command = '/apps./tempo.sh'
args = ' '.join(sys.argv[1:]) # all args except the script's name!
client.exec_command('{} {}'.format(command, args))
This will collect all the command line arguments passed to the Python script, except the first argument which is the script's file name, and build a space separated string. This argument string is them concatenated with the bash script command and executed remotely.
I am building an interactive shell using Python 3 and the cmd module. I have already written simple unit tests using py.test to test the individual functions, such as the do_* functions. I'd like to create more comprehensive tests that actually interact with the shell itself by simulating a user's input. For example, how could I test the following simulated session:
bash$ console-app.py
md:> show options
Available Options:
------------------
HOST The IP address or hostname of the machine to interact with
PORT The TCP port number of the server on the HOST
md:> set HOST localhost
HOST => 'localhost'
md:> set PORT 2222
PORT => '2222'
md:>
You can mock input or input stream passed to cmd to inject user input but I find more simple and flexible test it by onecmd() Cmd API method and trust how Cmd read input. In this way you cannot care how Cmd do the dirty work and test directly by users command: I use cmd both by console and socket and this I cannot care where the stream come from.
Moreover I use onecmd() to test even do_* (and occasionally help_*) methods and make my test less coupled to the code.
Follow a simple example of how I use it. create() and _last_write() are helper methods to build a MyCLI instance and take the last output lines respectively.
from mymodule import MyCLI
from unittest.mock import create_autospec
class TestMyCLI(unittest.TestCase):
def setUp(self):
self.mock_stdin = create_autospec(sys.stdin)
self.mock_stdout = create_autospec(sys.stdout)
def create(self, server=None):
return MyCLI(stdin=self.mock_stdin, stdout=self.mock_stdout)
def _last_write(self, nr=None):
""":return: last `n` output lines"""
if nr is None:
return self.mock_stdout.write.call_args[0][0]
return "".join(map(lambda c: c[0][0], self.mock_stdout.write.call_args_list[-nr:]))
def test_active(self):
"""Tesing `active` command"""
cli = self.create()
self.assertFalse(cli.onecmd("active"))
self.assertTrue(self.mock_stdout.flush.called)
self.assertEqual("Autogain active=False\n", self._last_write())
self.mock_stdout.reset_mock()
self.assertFalse(cli.onecmd("active TRue"))
self.assertTrue(self.mock_stdout.flush.called)
self.assertEqual("Autogain active=True\n", self._last_write())
self.assertFalse(cli.onecmd("active 0"))
self.assertTrue(self.mock_stdout.flush.called)
self.assertEqual("Autogain active=False\n", self._last_write())
def test_exit(self):
"""exit command"""
cli = self.create()
self.assertTrue(cli.onecmd("exit"))
self.assertEqual("Goodbay\n", self._last_write())
Take care that onecmd() return True if your cli should terminate, False otherwise.
Use python mock library to simulate user input. Here you will find similar problems with examples 1, 2.
I am a security analyst..and Python newbie that constantly needs to find the following 3 pieces of information on end users during incident investigations at work:
1.Their device hostname
2.The IP address associated with the device
3.Their login username
I don't even know how to begin creating a script that would provide this information, but I'm thinking that it would prompt me to input 1 of the 3 piece of info I mentioned above and then print out the other 2 pieces. Beyond the prompt part below, I'm stuck..
#!/usr/bin/python
print "Please paste in one of the following pieces of information.."
print "\n"
print "1. Device hostname"
print "2. IP address"
print "3. Username"
print "\n"
str = raw_input()
I've seen a few posts that detail how to pull various bits of info on a system locally, but not remotely. Does anyone know how I'd go about building this type of script in Python?
There are existing command line tools that you can use like: dig, the host command, and nslookup which will all do DNS lookups for hostnames and IP addresses. The request for "username" doesn't seem meaningful. More than one user can log in to a single machine, so I'm not sure how you plan on gathering that piece of information unless you allow for multiple return values.
Also here's a Perl one-liner that will do an IP to name resolution (reverse DNS lookup):
perl -e 'use Socket qw(getnameinfo inet_aton pack_sockaddr_in NI_NUMERICSERV); my $ip = inet_aton($ARGV[0]); my $addr = pack_sockaddr_in(80, $ip); my ($err, $hostname) = getnameinfo($addr, NI_NUMERICSERV); print "$hostname\n"'
The script assumes a single argument on the command line.
Here's a script that does the same thing in the forward DNS direction, printing all IPs:
perl -e 'use Socket qw(getaddrinfo getnameinfo NI_NUMERICSERV NI_NUMERICHOST); my ($err, #res) = getaddrinfo($ARGV[0], "www", {socktype => SOCK_STREAM}); for my $r (#res) { my ($err, $ip) = getnameinfo($r->{addr}, NI_NUMERICHOST | NI_NUMERICSERV); print "$ip\n";}'
It also assumes a single command line argument.
If you want a Python solution, this will get you started using the gevent library:
import gevent.resolver_ares
from gevent.socket import AF_INET, SOCK_STREAM
def resolve(fqdn):
resolver = gevent.resolver_ares.Resolver()
results = resolver.getaddrinfo(
fqdn, 0, family=AF_INET, socktype=SOCK_STREAM)
return results[0][-1][0]
This only does a forward resolution, but you should be able to modify it based on the Perl code to get a working reverse resolution as well. You can also use the built-in socket.getaddrinfo instead, but if you plan on doing this for a large number of machines, I'd recommend the gevent library.
This a project for the simulation of a Cisco switch interface. I basically want to create a command line interface which I can telnet to.
If anyone is familiar with the Cisco switched this is primarily how they are controlled. I want to generate the simulated outputs of the commands on these switches. I tried using the twisted framework and the cmd option of python.
But I just need something simple, basically a module that would telnet to the cli, then I can use the commands as i see fit in a different modules and then display the commands.
I would appreciate if someone would show me the right way to do this, or even what I could use.(The telnet option is not mandatory.)
This seems the ticket; simple but workable. Its a telnet server library written in Python. Its easily extendable; like so:
if __name__ == '__main__':
"Testing - Accept a single connection"
class TNS(SocketServer.TCPServer):
allow_reuse_address = True
class TNH(TelnetHandler):
def cmdECHO(self, params):
""" [<arg> ...]
Echo parameters
Echo command line parameters back to user, one per line.
"""
self.writeline("Parameters:")
for item in params:
self.writeline("\t%s" % item)
def cmdTIME(self, params):
"""
Print Time
Added by dilbert
"""
self.writeline(time.ctime())
logging.getLogger('').setLevel(logging.DEBUG)
tns = TNS(("0.0.0.0", 8023), TNH)
tns.serve_forever()