| #!/usr/bin/env python |
| |
| """ This runs a sequence of commands on a remote host using SSH. It runs a |
| simple system checks such as uptime and free to monitor the state of the remote |
| host. |
| |
| ./monitor.py [-s server_hostname] [-u username] [-p password] |
| -s : hostname of the remote server to login to. |
| -u : username to user for login. |
| -p : Password to user for login. |
| |
| Example: |
| This will print information about the given host: |
| ./monitor.py -s www.example.com -u mylogin -p mypassword |
| |
| It works like this: |
| Login via SSH (This is the hardest part). |
| Run and parse 'uptime'. |
| Run 'iostat'. |
| Run 'vmstat'. |
| Run 'netstat' |
| Run 'free'. |
| Exit the remote host. |
| """ |
| |
| import os |
| import sys |
| import time |
| import re |
| import getopt |
| import getpass |
| import traceback |
| import pexpect |
| |
| # |
| # Some constants. |
| # |
| # This is way too simple for industrial use -- we will change is ASAP. |
| COMMAND_PROMPT = '[#$] ' |
| TERMINAL_PROMPT = '(?i)terminal type\?' |
| TERMINAL_TYPE = 'vt100' |
| # This is the prompt we get if SSH does not have the remote host's public |
| # key stored in the cache. |
| SSH_NEWKEY = '(?i)are you sure you want to continue connecting' |
| |
| |
| def exit_with_usage(): |
| |
| print globals()['__doc__'] |
| os._exit(1) |
| |
| |
| def main(): |
| |
| global COMMAND_PROMPT, TERMINAL_PROMPT, TERMINAL_TYPE, SSH_NEWKEY |
| ###################################################################### |
| # Parse the options, arguments, get ready, etc. |
| ###################################################################### |
| try: |
| optlist, args = getopt.getopt( |
| sys.argv[ |
| 1:], 'h?s:u:p:', [ |
| 'help', 'h', '?']) |
| except Exception as e: |
| print str(e) |
| exit_with_usage() |
| options = dict(optlist) |
| if len(args) > 1: |
| exit_with_usage() |
| |
| if [elem for elem in options if elem in [ |
| '-h', '--h', '-?', '--?', '--help']]: |
| print "Help:" |
| exit_with_usage() |
| |
| if '-s' in options: |
| host = options['-s'] |
| else: |
| host = raw_input('hostname: ') |
| if '-u' in options: |
| user = options['-u'] |
| else: |
| user = raw_input('username: ') |
| if '-p' in options: |
| password = options['-p'] |
| else: |
| password = getpass.getpass('password: ') |
| |
| # |
| # Login via SSH |
| # |
| child = pexpect.spawn('ssh -l %s %s' % (user, host)) |
| i = child.expect([pexpect.TIMEOUT, SSH_NEWKEY, |
| COMMAND_PROMPT, '(?i)password']) |
| if i == 0: # Timeout |
| print 'ERROR! could not login with SSH. Here is what SSH said:' |
| print child.before, child.after |
| print str(child) |
| sys.exit(1) |
| if i == 1: # In this case SSH does not have the public key cached. |
| child.sendline('yes') |
| child.expect('(?i)password') |
| if i == 2: |
| # This may happen if a public key was setup to automatically login. |
| # But beware, the COMMAND_PROMPT at this point is very trivial and |
| # could be fooled by some output in the MOTD or login message. |
| pass |
| if i == 3: |
| child.sendline(password) |
| # Now we are either at the command prompt or |
| # the login process is asking for our terminal type. |
| i = child.expect([COMMAND_PROMPT, TERMINAL_PROMPT]) |
| if i == 1: |
| child.sendline(TERMINAL_TYPE) |
| child.expect(COMMAND_PROMPT) |
| # |
| # Set command prompt to something more unique. |
| # |
| COMMAND_PROMPT = "\[PEXPECT\]\$ " |
| child.sendline("PS1='[PEXPECT]\$ '") # In case of sh-style |
| i = child.expect([pexpect.TIMEOUT, COMMAND_PROMPT], timeout=10) |
| if i == 0: |
| print "# Couldn't set sh-style prompt -- trying csh-style." |
| child.sendline("set prompt='[PEXPECT]\$ '") |
| i = child.expect([pexpect.TIMEOUT, COMMAND_PROMPT], timeout=10) |
| if i == 0: |
| print "Failed to set command prompt using sh or csh style." |
| print "Response was:" |
| print child.before |
| sys.exit(1) |
| |
| # Now we should be at the command prompt and ready to run some commands. |
| print '---------------------------------------' |
| print 'Report of commands run on remote host.' |
| print '---------------------------------------' |
| |
| # Run uname. |
| child.sendline('uname -a') |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| if 'linux' in child.before.lower(): |
| LINUX_MODE = 1 |
| else: |
| LINUX_MODE = 0 |
| |
| # Run and parse 'uptime'. |
| child.sendline('uptime') |
| child.expect( |
| 'up\s+(.*?),\s+([0-9]+) users?,\s+load averages?: ([0-9]+\.[0-9][0-9]),?\s+([0-9]+\.[0-9][0-9]),?\s+([0-9]+\.[0-9][0-9])') |
| duration, users, av1, av5, av15 = child.match.groups() |
| days = '0' |
| hours = '0' |
| mins = '0' |
| if 'day' in duration: |
| child.match = re.search('([0-9]+)\s+day', duration) |
| days = str(int(child.match.group(1))) |
| if ':' in duration: |
| child.match = re.search('([0-9]+):([0-9]+)', duration) |
| hours = str(int(child.match.group(1))) |
| mins = str(int(child.match.group(2))) |
| if 'min' in duration: |
| child.match = re.search('([0-9]+)\s+min', duration) |
| mins = str(int(child.match.group(1))) |
| print |
| print 'Uptime: %s days, %s users, %s (1 min), %s (5 min), %s (15 min)' % ( |
| duration, users, av1, av5, av15) |
| child.expect(COMMAND_PROMPT) |
| |
| # Run iostat. |
| child.sendline('iostat') |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| |
| # Run vmstat. |
| child.sendline('vmstat') |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| |
| # Run free. |
| if LINUX_MODE: |
| child.sendline('free') # Linux systems only. |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| |
| # Run df. |
| child.sendline('df') |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| |
| # Run lsof. |
| child.sendline('lsof') |
| child.expect(COMMAND_PROMPT) |
| print child.before |
| |
| # # Run netstat |
| # child.sendline ('netstat') |
| # child.expect (COMMAND_PROMPT) |
| # print child.before |
| |
| # # Run MySQL show status. |
| # child.sendline ('mysql -p -e "SHOW STATUS;"') |
| # child.expect (PASSWORD_PROMPT_MYSQL) |
| # child.sendline (password_mysql) |
| # child.expect (COMMAND_PROMPT) |
| # print |
| # print child.before |
| |
| # Now exit the remote host. |
| child.sendline('exit') |
| index = child.expect([pexpect.EOF, "(?i)there are stopped jobs"]) |
| if index == 1: |
| child.sendline("exit") |
| child.expect(EOF) |
| |
| if __name__ == "__main__": |
| |
| try: |
| main() |
| except Exception as e: |
| print str(e) |
| traceback.print_exc() |
| os._exit(1) |