Threaded SSH executer in Python

In addition to my full time job I also do some consulting on the side. Recently, I’ve been working on auditing one of my clients’ infrastructure. The results of the audit will be in the form of recommendations for updates/upgrades of their operating systems, packages, patches and software. This involves gathering the same data for every host in their environment and then analyzing it to produce the results. To make the gathering easier and to try to increase my Python fu I wrote a script using the threading and paramiko python modules. The threading module is part of the python core and paramiko is a pure python SSH2 implementation. The script reads a list of hosts stored in a file and forks a thread for each. In each thread the script logs into a host and executes any arbitrary command on the host printing the results to STDOUT. Because the start() method in the threading module is non-blocking the for loop is appropriate, but it also means that the main script could exit before all the threads return. That is why each thread is appended to the threads list object and then joined. I think the script itself is fairly simple and I’m sure there is room for improvement, but this was my first foray into threaded programming and I’m still learning python. Comments are welcome.

#!/usr/bin/env python
"""
The MIT License

Copyright (c) 2009 seano 

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""

import paramiko, threading

# setup the threading class and routine
class SSHThread (threading.Thread):
    def run (self):
        # SSH connection settings
        hostname = self.hostname
        port = 22
        username = 'username'
        ssh_pkey = '/home/username/.ssh/id_dsa'

        # make the connection and run the commands
        key = paramiko.DSSKey.from_private_key_file(ssh_pkey)
        conn = paramiko.SSHClient()
        conn.load_system_host_keys()
        conn.connect(hostname, port, username=username, pkey=key)
        stdin, stdout, stderr = conn.exec_command("/bin/ls")
        print stdout.read().strip()
        conn.close()

    def __init__(self,hostname):
        threading.Thread.__init__(self)
        self.hostname = hostname

def main():
    hostlist = '/home/username/.machines'

    threads = []
    for host in open(hostlist, 'r').readlines():
        hostname = host.strip()
        current_thread = SSHThread(hostname)
        threads.append(current_thread)
        current.start()

    for t in threads:
        t.join()

if __name__ == "__main__":
    main()
Follow

Get every new post delivered to your Inbox.