Package DataCollector :: Module SshClient
[hide private]
[frames] | no frames]

Source Code for Module DataCollector.SshClient

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  __doc__="""SshClient 
 15   
 16  SshClient runs commands on a remote box using ssh  
 17  and returns their results 
 18   
 19  $Id: SshClient.py,v 1.5 2004/04/05 02:05:30 edahl Exp $""" 
 20   
 21  __version__ = "$Revision: 1.5 $"[11:-2] 
 22   
 23  import os, getpass 
 24  import logging 
 25  log = logging.getLogger("zen.SshClient") 
 26   
 27  import Globals 
 28   
 29  from twisted.conch.ssh import transport, userauth, connection 
 30  from twisted.conch.ssh import common, keys, channel 
 31  from twisted.internet import defer, reactor 
 32   
 33  from Exceptions import * 
 34   
 35  import CollectorClient 
 36   
37 -class SshClientTransport(transport.SSHClientTransport):
38
39 - def verifyHostKey(self, hostKey, fingerprint):
40 #blowing off host key right now, should store and check 41 log.debug('%s host key: %s' % (self.factory.hostname, fingerprint)) 42 return defer.succeed(1)
43
44 - def connectionMade(self):
45 self.factory.transport = self.transport 46 transport.SSHClientTransport.connectionMade(self)
47
48 - def connectionSecure(self):
49 sshconn = SshConnection(self.factory) 50 sshauth = SshUserAuth(self.factory.username, sshconn, self.factory) 51 self.requestService(sshauth)
52 53
54 -class SshUserAuth(userauth.SSHUserAuthClient):
55 lastPublicKey = False
56 - def __init__(self, user, instance, factory):
57 user = str(user) # damn unicode 58 if user == '': 59 user = os.getlogin() 60 log.debug('attempting to authenticate using username: %s' % user) 61 userauth.SSHUserAuthClient.__init__(self, user, instance) 62 self.user = user 63 self.factory = factory
64
65 - def getPassword(self):
66 if not self.factory.password or self.factory.loginTries <= 0: 67 self.factory.clientFinished() 68 return 69 else: 70 self.factory.loginTries -= 1 71 return defer.succeed(self.factory.password)
72
73 - def getPublicKey(self):
74 log.debug('Getting Public Key from %s' % self.factory.keyPath) 75 keyPath = os.path.expanduser(self.factory.keyPath) 76 # this works with rsa too 77 # just change the name here and in getPrivateKey 78 path = None 79 if os.path.exists(keyPath): 80 path = keyPath 81 if not path or self.lastPublicKey: 82 # the file doesn't exist, or we've tried a public key 83 return 84 return keys.getPublicKeyString(path+'.pub')
85
86 - def getPrivateKey(self):
87 log.debug('Getting Private Key from %s' % self.factory.keyPath) 88 keyPath = os.path.expanduser(self.factory.keyPath) 89 path = None 90 if os.path.exists(keyPath): 91 path = keyPath 92 return defer.succeed(keys.getPrivateKeyObject(path, 93 passphrase=self.factory.password))
94
95 -class SshConnection(connection.SSHConnection):
96
97 - def __init__(self, factory):
98 log.debug("creating new ssh connection") 99 connection.SSHConnection.__init__(self) 100 self.factory = factory
101 102
103 - def serviceStarted(self):
104 self.factory.serviceStarted(self)
105
106 - def addCommand(self, cmd):
107 """open a new command channel for each command in queue""" 108 ch = CommandChannel(cmd, conn=self) 109 self.openChannel(ch)
110
111 - def channelClosed(self, channel):
112 # grr.. patch SSH inherited method to deal with partially 113 # configured channels 114 self.localToRemoteChannel[channel.id] = None 115 self.channelsToRemoteChannel[channel] = None 116 connection.SSHConnection.channelClosed(self, channel)
117 118
119 -class CommandChannel(channel.SSHChannel):
120 name = 'session' 121
122 - def __init__(self, command, conn=None):
123 channel.SSHChannel.__init__(self, conn=conn) 124 self.command = command 125 self.exitCode = None
126
127 - def openFailed(self, reason):
128 log.warn('open of %s failed: %s' % (self.command, reason))
129
130 - def channelOpen(self, ignoredData):
131 log.debug('opening command channel for %s' % self.command) 132 self.data = '' 133 log.debug('running command remotely: exec %s' % common.NS(self.command)) 134 d = self.conn.sendRequest(self, 'exec', common.NS(self.command), 135 wantReply = 1)
136
137 - def request_exit_status(self, data):
138 import struct 139 self.exitCode = struct.unpack('>L', data)[0]
140
141 - def dataReceived(self, data):
142 self.data += data
143
144 - def closed(self):
145 log.debug('command %s data: %s' % (self.command, repr(self.data))) 146 self.conn.factory.addResult(self.command, self.data, self.exitCode) 147 self.loseConnection() 148 if self.conn.factory.commandsFinished(): 149 self.conn.factory.clientFinished()
150 151
152 -class SshClient(CollectorClient.CollectorClient):
153
154 - def __init__(self, hostname, ip, port=22, commands=[], options=None, 155 device=None, datacollector=None):
156 CollectorClient.CollectorClient.__init__(self, hostname, ip, port, 157 commands, options, device, datacollector) 158 self.protocol = SshClientTransport 159 self.connection = None 160 self.transport = None
161 162
163 - def run(self):
164 """Start ssh collection. 165 """ 166 reactor.connectTCP(self.ip, self.port, self, self.loginTimeout)
167 168
169 - def serviceStarted(self, sshconn):
170 """run commands that are in the command queue""" 171 log.info("connected to device %s" % self.hostname) 172 self.connection = sshconn 173 for cmd in self.getCommands(): 174 sshconn.addCommand(cmd)
175 176
177 - def addCommand(self, commands):
178 """add command to queue and open a command channel for a command""" 179 CollectorClient.CollectorClient.addCommand(self, commands) 180 if type(commands) == type(''): commands = (commands,) 181 if self.connection: 182 for cmd in commands: 183 self.connection.addCommand(cmd)
184
185 - def loseConnection(self):
186 pass
187 #self.connection.loseConnection() 188 189
190 -def main():
191 import socket 192 parser = CollectorClient.buildOptions() 193 options = CollectorClient.parseOptions(parser,22) 194 client = SshClient(options.hostname, 195 socket.gethostbyname(options.hostname), 196 options.port, 197 commands=options.commands, options=options) 198 def stop(): 199 if client.commandsFinished(): 200 reactor.stop() 201 else: 202 reactor.callLater(1, stop)
203 stop() 204 client.run() 205 reactor.run() 206 import pprint 207 pprint.pprint(client.getResults()) 208 209 if __name__ == '__main__': 210 main() 211