--- category: framework framework: ShutIt contributors: - ["Ian Miell", "http://ian.meirionconsulting.tk"] filename: learnshutit.py --- ## ShutIt ShutIt is an shell automation framework designed to be easy to use. It is a wrapper around a Python-based expect clone (pexpect). You can look at it as 'expect without the pain'. It is available as a pip install. ## Hello World Starting with the simplest example. Create a file called example.py: ```python import shutit session = shutit.create_session('bash') session.send('echo Hello World', echo=True) ``` Running this with: ```bash python example.py ``` outputs: ```bash $ python example.py echo "Hello World" echo "Hello World" Hello World Ians-MacBook-Air.local:ORIGIN_ENV:RhuebR2T# ``` The first argument to 'send' is the command you want to run. The 'echo' argument outputs the terminal interactions. By default ShutIt is silent. 'send' takes care of all the messing around with prompts and 'expects' that you might be familiar with from expect. ## Log Into a Server Let's say you want to log into a server and run a command. Change example.py to: ```python import shutit session = shutit.create_session('bash') session.login('ssh you@example.com', user='you', password='mypassword') session.send('hostname', echo=True) session.logout() ``` which will log you into your server (if you replace with your details) and output the hostname. ``` $ python example.py hostname hostname example.com example.com:cgoIsdVv:heDa77HB# ``` Obviously that's insecure! Instead you can run: ```python import shutit session = shutit.create_session('bash') password = session.get_input('', ispass=True) session.login('ssh you@example.com', user='you', password=password) session.send('hostname', echo=True) session.logout() ``` which forces you to input the password: ``` $ python example.py Input Secret: hostname hostname example.com example.com:cgoIsdVv:heDa77HB# ``` Again, the 'login' method handles the changing prompt from a login. You give ShutIt the login command, the user you expect to log in as, and a password (if needed), and ShutIt takes care of the rest. 'logout' handles the ending of a 'login', handling any changes to the prompt for you. ## Log Into Multiple Servers Let's say you have a server farm of two servers, and want to log onto both. Just create two sessions and run similar login and send commands: ```python import shutit session1 = shutit.create_session('bash') session2 = shutit.create_session('bash') password1 = session1.get_input('Password for server1', ispass=True) password2 = session2.get_input('Password for server2', ispass=True) session1.login('ssh you@one.example.com', user='you', password=password1) session2.login('ssh you@two.example.com', user='you', password=password2) session1.send('hostname', echo=True) session2.send('hostname', echo=True) session1.logout() session2.logout() ``` would output: ```bash $ python example.py Password for server1 Input Secret: Password for server2 Input Secret: hostname hostname one.example.com one.example.com:Fnh2pyFj:qkrsmUNs# hostname hostname two.example.com two.example.com:Gl2lldEo:D3FavQjA# ``` ## Example: Monitor Multiple Servers We can turn the above into a simple monitoring tool by adding some logic to examine the output of a command: ```python import shutit capacity_command="""df / | awk '{print $5}' | tail -1 | sed s/[^0-9]//""" session1 = shutit.create_session('bash') session2 = shutit.create_session('bash') password1 = session.get_input('Password for server1', ispass=True) password2 = session.get_input('Password for server2', ispass=True) session1.login('ssh you@one.example.com', user='you', password=password1) session2.login('ssh you@two.example.com', user='you', password=password2) capacity = session1.send_and_get_output(capacity_command) if int(capacity) < 10: print('RUNNING OUT OF SPACE ON server1!') capacity = session2.send_and_get_output(capacity_command) if int(capacity) < 10: print('RUNNING OUT OF SPACE ON server2!') session1.logout() session2.logout() ``` Here you use the 'send\_and\_get\_output' method to retrieve the output of the capacity command (df). There are much more elegant ways to do the above (e.g. have a dictionary of the servers to iterate over), but it's up to you how clever you need the Python to be. ## More Intricate IO - Expecting Let's say you have an interaction with an interactive command line application you want to automate. Here we will use telnet as a trivial example: ```python import shutit session = shutit.create_session('bash') session.send('telnet', expect='elnet>', echo=True) session.send('open google.com 80', expect='scape character', echo=True) session.send('GET /', echo=True, check_exit=False) session.logout() ``` Note the 'expect' argument. You only need to give a subset of telnet's prompt to match and continue. Note also the 'check\_exit' argument in the above, which is new. We'll come back to that. The output of the above is: ```bash $ python example.py telnet telnet> open google.com 80 Trying 216.58.214.14... Connected to google.com. Escape character is '^]'. GET / HTTP/1.0 302 Found Cache-Control: private Content-Type: text/html; charset=UTF-8 Referrer-Policy: no-referrer Location: http://www.google.co.uk/?gfe_rd=cr&ei=huczWcj3GfTW8gfq0paQDA Content-Length: 261 Date: Sun, 04 Jun 2017 10:57:10 GMT