views:

421

answers:

6

I've just become the system admin for my research group's cluster and, in this respect, am a novice. I'm trying to make a few tools to monitor the network and need help getting started implementing them with python (my native tongue).

For example, I would like to view who is logged onto remote machines. By hand, I'd ssh and who, but how would I get this info into a script for manipulation? Something like,

import remote_info as ri
ri.open("foo05.bar.edu")
ri.who()

Out[1]: 
hutchinson tty7         2009-08-19 13:32 (:0)
hutchinson pts/1        2009-08-19 13:33 (:0.0)

Similarly for things like cat /proc/cpuinfo to get the processor information of a node. A starting point would be really great. Thanks.

+2  A: 

Here's a simple, cheap solution to get you started

from subprocess import *
p = Popen('ssh servername who', shell=True, stdout=PIPE)
p.wait()
print p.stdout.readlines()

returns (eg)

['usr      pts/0        2009-08-19 16:03 (kakapo)\n',
 'usr      pts/1        2009-08-17 15:51 (kakapo)\n',
 'usr      pts/5        2009-08-17 17:00 (kakapo)\n']

and for cpuinfo:

p = Popen('ssh servername cat /proc/cpuinfo', shell=True, stdout=PIPE)
Peter
Nice. This was the first code I got to work. Question: Do you know when the ssh connection is terminated?
vgm64
right after running the command.
Peter
@Peter: if I need an interaction with a remote host (answer on prompts, etc) should I use Pexpect or there is a built-in library with such functionality
yeah, I think you'd have to go with Pexpect. I can't think of any built-in way.
Peter
+2  A: 

I've been using Pexpect, which let's you ssh into machines, send commands, read the output, and react to it, with success. I even started an open-source project around it, Proxpect - which haven't been updated in ages, but I digress...

inerte
A: 

This covers the bases. Notice the use of sudo for things that needed more privileges. We configured sudo to allow those commands for that user without needing a password typed.

Also, keep in mind that you should run ssh-agent to make this "make sense". But all in all, it works really well. Running deploy-control httpd configtest will check the apache configuration on all the remote servers.

#!/usr/local/bin/python

import subprocess
import sys

# The user@host: for the SourceURLs (NO TRAILING SLASH)
RemoteUsers = [
        "[email protected]",
        "[email protected]",
        ]

###################################################################################################
# Global Variables
Arg                             = None


# Implicitly verified below in if/else
Command = tuple(sys.argv[1:])

ResultList = []
###################################################################################################
for UH in RemoteUsers:
        print "-"*80
        print "Running %s command on: %s" % (Command, UH)

        #----------------------------------------------------------------------------------------------
        if Command == ('httpd', 'configtest'):
                CommandResult = subprocess.call(('ssh', UH, 'sudo /sbin/service httpd configtest'))

        #----------------------------------------------------------------------------------------------
        elif Command == ('httpd', 'graceful'):
                CommandResult = subprocess.call(('ssh', UH, 'sudo /sbin/service httpd graceful'))

        #----------------------------------------------------------------------------------------------
        elif Command == ('httpd', 'status'):
                CommandResult = subprocess.call(('ssh', UH, 'sudo /sbin/service httpd status'))

        #----------------------------------------------------------------------------------------------
        elif Command == ('disk', 'usage'):
                CommandResult = subprocess.call(('ssh', UH, 'df -h'))

        #----------------------------------------------------------------------------------------------
        elif Command == ('uptime',):
                CommandResult = subprocess.call(('ssh', UH, 'uptime'))

        #----------------------------------------------------------------------------------------------
        else:
                print
                print "#"*80
                print
                print "Error: invalid command"
                print
                HelpAndExit()

        #----------------------------------------------------------------------------------------------
        ResultList.append(CommandResult)
        print


###################################################################################################
if any(ResultList):
        print "#"*80
        print "#"*80
        print "#"*80
        print
        print "ERRORS FOUND.  SEE ABOVE"
        print
        sys.exit(0)

else:
        print "-"*80
        print
        print "Looks OK!"
        print
        sys.exit(1)
gahooa
+1  A: 

The pexpect module can help you interface with ssh. More or less, here is what your example would look like.

child = pexpect.spawn('ssh servername')
child.expect('Password:')
child.sendline('ABCDEF')
(output,status) = child.sendline('who')
ACoolie
This is fine for example, but please note, that authenticating like this is generally considered a Bad Idea. Public key-based SSH authentication is more secure... And at least you don't have to make sure your script is not world-readable after every accidental edit.
drdaeman
The output of `child.sendline('who')` seems to be the number 4... What am I missing?
vgm64
I got the same with pexpect, what gives with it?
Jon
A: 

Fabric is a simple way to automate some simple tasks like this, the version I'm currently using allows you to wrap up commands like so:

run('whoami', fail='ignore')

you can specify config options (config.fab_user, config.fab_password) for each machine you need (if you want to automate username password handling).

More info on Fabric here:

http://www.nongnu.org/fab/

There is a new version which is more Pythonic - I'm not sure whether that is going to be better for you int his case... works fine for me at present...

Jon
+1  A: 

If your needs overgrow simple "ssh remote-host.example.org who" then there is an awesome python library, called RPyC. It has so called "classic" mode which allows to almost transparently execute Python code over the network with several lines of code. Very useful tool for trusted environments.

Here's an example from Wikipedia:

import rpyc
# assuming a classic server is running on 'hostname'
conn = rpyc.classic.connect("hostname")

# runs os.listdir() and os.stat() remotely, printing results locally
def remote_ls(path):
    ros = conn.modules.os
    for filename in ros.listdir(path):
        stats = ros.stat(ros.path.join(path, filename))
        print "%d\t%d\t%s" % (stats.st_size, stats.st_uid, filename)

remote_ls("/usr/bin")

If you're interested, there's a good tutorial on their wiki.

But, of course, if you're perfectly fine with ssh calls using Popen or just don't want to run separate "RPyC" daemon, then this is definitely an overkill.

drdaeman