Package Products :: Package ZenStatus :: Module ZenTcpClient
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenStatus.ZenTcpClient

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, 2009 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 or (at your 
  8  # option) any later version as published by the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13  __doc__ = """ZenTcpClient 
 14  Connect to the remote service and (optionally) test the output from 
 15  the service against what we expect. 
 16   
 17  Error types: 
 18   
 19      1. timeout (no connection) 
 20      2. connection refused - port not available on remote end 
 21      3. bad value - value returned did not match expectRegex 
 22   
 23  """ 
 24  import re 
 25  import logging 
 26  log = logging.getLogger("zen.ZenTcpClient") 
 27  from socket import getfqdn 
 28  hostname = getfqdn() 
 29   
 30  from twisted.internet import reactor, protocol, defer 
 31  from Products.ZenEvents.ZenEventClasses import Status_IpService 
 32  from Products.ZenUtils.Utils import unused 
 33   
34 -class ZenTcpTest(protocol.Protocol):
35 """ 36 Twisted class to make a TCP/IP connection to a remote IP service 37 and report back the result. 38 """ 39 defer = None 40 data = "" 41
42 - def connectionMade(self):
43 """ 44 Connected successfully to the remote device, now test against any 45 regex that we might have and record the result. 46 """ 47 log.debug("Connected to %s" % self.transport.getPeer().host) 48 self.factory.msg = "pass" 49 self.cfg = self.factory.cfg 50 51 if self.cfg.sendString: 52 sendString = self.cfg.sendString.decode("string_escape") 53 log.debug("Sending: %s", sendString) 54 self.transport.write(sendString) 55 56 if self.cfg.expectRegex: 57 log.debug("Waiting for results to check against regex '%s'", 58 self.cfg.expectRegex) 59 self.defer = reactor.callLater(self.cfg.timeout, self.expectTimeout) 60 else: 61 self.loseConnection()
62
63 - def dataReceived(self, data):
64 """ 65 Compare the data from the remote device to what we expect in the 66 regex. 67 68 @parameter data: output from remote service 69 @type data: string 70 """ 71 log.debug("%s %s received data: %s", self.cfg.device, 72 self.cfg.component, data) 73 self.data += data 74 if self.cfg.expectRegex: 75 if re.search(self.cfg.expectRegex, data): 76 log.debug("Found %s in '%s' -- closing connection", 77 self.cfg.expectRegex, data) 78 self.loseConnection() 79 else: 80 log.debug("No match for %s in '%s' -- looking for more data", 81 self.cfg.expectRegex, data)
82
83 - def expectTimeout(self):
84 """ 85 Called if we timeout waiting for the service to connect or for 86 receiving a response from the service that matches our regex. 87 """ 88 msg = "IP Service %s TIMEOUT waiting for '%s'" % ( 89 self.cfg.component, self.cfg.expectRegex) 90 log.debug("%s %s", self.cfg.ip, msg) 91 self.factory.msg = msg 92 self.loseConnection()
93
94 - def loseConnection(self):
95 """ 96 Shut down the connection and cleanup. 97 """ 98 ip, port = self.transport.addr 99 log.debug("Closed connection to %s on port %s for %s", 100 ip, port, self.cfg.component) 101 self.data = "" 102 try: 103 self.defer.cancel() 104 except: 105 self.defer = None 106 self.transport.loseConnection()
107 108
109 -class ZenTcpClient(protocol.ClientFactory):
110 """ 111 Client class to run TCP tests. 112 """ 113 protocol = ZenTcpTest 114 msg = "pass" 115 deferred = None 116
117 - def __init__(self, svc, status):
118 self.cfg = svc 119 self.status = status
120
121 - def clientConnectionLost(self, connector, reason):
122 """ 123 Record why the connection to the remote device was dropped. 124 125 @parameter connector: Twisted protocol object 126 @type connector: Twisted protocol object 127 @parameter reason: explanation for the connection loss 128 @type reason: Twisted error object 129 """ 130 unused(connector) 131 errorMsg = reason.getErrorMessage() 132 if errorMsg != 'Connection was closed cleanly.': 133 log.debug("Lost connection to %s (%s) port %s: %s", 134 self.cfg.device, self.cfg.ip, self.cfg.port, 135 reason.getErrorMessage() ) 136 if self.deferred: 137 self.deferred.callback(self) 138 self.deferred = None
139
140 - def clientConnectionFailed(self, connector, reason):
141 """ 142 Record why the connection to the remote device failed. 143 144 @parameter connector: Twisted protocol object 145 @type connector: Twisted protocol object 146 @parameter reason: explanation for the connection loss 147 @type reason: Twisted error object 148 """ 149 log.debug("Connection to %s (%s) port %s failed: %s", 150 self.cfg.device, connector.host, self.cfg.port, 151 reason.getErrorMessage() ) 152 self.msg = "IP Service %s is down" % self.cfg.component 153 if self.deferred: 154 self.deferred.callback(self) 155 self.deferred = None
156
157 - def getEvent(self):
158 """ 159 Called by zenstatus to report status information about a service. 160 161 @return: event of what happened to our service test 162 @rtype: dictionary 163 """ 164 if self.msg == "pass" and self.status > 0: 165 self.status = sev = 0 166 self.msg = "IP Service %s back up" % self.cfg.component 167 168 elif self.msg != "pass": 169 self.status += 1 170 sev = self.cfg.failSeverity 171 172 else: 173 # Send an event even though there's no problem and 174 # nothing to clear __internally__ to zenstatus. 175 # The event console might have an event that will 176 # otherwise never be cleared. 177 # Code higher up discards duplicate clears. 178 self.status = sev = 0 179 self.msg = "IP Service %s back up" % self.cfg.component 180 181 return dict(device=self.cfg.device, 182 component=self.cfg.component, 183 ipAddress=self.cfg.ip, 184 summary=self.msg, 185 severity=sev, 186 eventClass=Status_IpService, 187 eventGroup="TCPTest", 188 agent="ZenStatus", 189 manager=hostname)
190
191 - def start(self, ip_address):
192 """ 193 Called by zenstatus to make a connection attempt to the service. 194 195 @return: Twisted deferred 196 @rtype: Twisted deferred 197 """ 198 d = self.deferred = defer.Deferred() 199 reactor.connectTCP(ip_address, self.cfg.port, self, self.cfg.timeout) 200 return d
201