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 as published by 
  8  # 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   
 35  # needed for pb/jelly 
 36  from Products.ZenHub.services.StatusConfig import ServiceConfig 
 37  unused(ServiceConfig) 
 38   
39 -class ZenTcpTest(protocol.Protocol):
40 """ 41 Twisted class to make a TCP/IP connection to a remote IP service 42 and report back the result. 43 """ 44 defer = None 45 data = "" 46
47 - def connectionMade(self):
48 """ 49 Connected successfully to the remote device, now test against any 50 regex that we might have and record the result. 51 """ 52 log.debug("Connected to %s" % self.transport.getPeer().host) 53 self.factory.msg = "pass" 54 self.cfg = self.factory.cfg 55 56 if self.cfg.sendString: 57 sendString = self.cfg.sendString.decode("string_escape") 58 log.debug("Sending: %s" % sendString) 59 self.transport.write(sendString) 60 61 if self.cfg.expectRegex: 62 log.debug("Waiting for results to check against regex '%s'" % ( 63 self.cfg.expectRegex )) 64 self.defer = reactor.callLater(self.cfg.timeout, self.expectTimeout) 65 else: 66 self.loseConnection()
67 68
69 - def dataReceived(self, data):
70 """ 71 Compare the data from the remote device to what we expect in the 72 regex. 73 74 @parameter data: output from remote service 75 @type data: string 76 """ 77 log.debug("%s %s received data: %s" % (self.cfg.device, 78 self.cfg.component, data)) 79 self.data += data 80 if self.cfg.expectRegex: 81 if re.search(self.cfg.expectRegex, data): 82 log.debug("Found %s in '%s' -- closing connection" % ( 83 self.cfg.expectRegex, data)) 84 self.loseConnection() 85 else: 86 log.debug("No match for %s in '%s' -- looking for more data" % ( 87 self.cfg.expectRegex, data))
88 89
90 - def expectTimeout(self):
91 """ 92 Called if we timeout waiting for the service to connect or for 93 receiving a response from the service that matches our regex. 94 """ 95 msg = "IP Service %s TIMEOUT waiting for '%s'" % ( 96 self.cfg.component, self.cfg.expectRegex) 97 log.debug( "%s %s" % (self.cfg.ip, msg) ) 98 self.factory.msg = msg 99 self.loseConnection()
100 101
102 - def loseConnection(self):
103 """ 104 Shut down the connection and cleanup. 105 """ 106 ip, port = self.transport.addr 107 log.debug("Closed connection to %s on port %s for %s" % ( 108 ip, port, self.cfg.component)) 109 self.data = "" 110 try: 111 self.defer.cancel() 112 except: 113 self.defer = None 114 self.transport.loseConnection()
115 116 117
118 -class ZenTcpClient(protocol.ClientFactory):
119 """ 120 Client class to run TCP tests. 121 """ 122 protocol = ZenTcpTest 123 msg = "pass" 124 deferred = None 125
126 - def __init__(self, svc, status):
127 self.cfg = svc 128 self.status = status
129
130 - def clientConnectionLost(self, connector, reason):
131 """ 132 Record why the connection to the remote device was dropped. 133 134 @parameter connector: Twisted protocol object 135 @type connector: Twisted protocol object 136 @parameter reason: explanation for the connection loss 137 @type reason: Twisted error object 138 """ 139 unused(connector) 140 log.debug("Lost connection to %s (%s) port %s : %s" % ( 141 self.cfg.device, self.cfg.ip, self.cfg.port, 142 reason.getErrorMessage() )) 143 if self.deferred: 144 self.deferred.callback(self) 145 self.deferred = None
146 147
148 - def clientConnectionFailed(self, connector, reason):
149 """ 150 Record why the connection to the remote device failed. 151 152 @parameter connector: Twisted protocol object 153 @type connector: Twisted protocol object 154 @parameter reason: explanation for the connection loss 155 @type reason: Twisted error object 156 """ 157 unused(connector) 158 log.debug("Connection to %s (%s) port %s failed: %s" % ( 159 self.cfg.device, self.cfg.ip, self.cfg.port, 160 reason.getErrorMessage() )) 161 log.debug(reason.type) 162 self.msg = "IP Service %s is down" % self.cfg.component 163 if self.deferred: 164 self.deferred.callback(self) 165 self.deferred = None
166 167
168 - def getEvent(self):
169 """ 170 Called by zenstatus to report status information about a service. 171 172 @return: event of what happened to our service test 173 @rtype: dictionary 174 """ 175 log.debug("status:%s msg:%s", self.status, self.msg) 176 if self.msg == "pass" and self.status > 0: 177 self.status = sev = 0 178 self.msg = "IP Service %s back up" % self.cfg.component 179 log.info(self.msg) 180 181 elif self.msg != "pass": 182 self.status += 1 183 sev = self.cfg.failSeverity 184 log.warn(self.msg) 185 186 else: 187 # Don't send an event as there's no problem and 188 # nothing to clear. 189 return None 190 191 return dict(device=self.cfg.device, 192 component=self.cfg.component, 193 ipAddress=self.cfg.ip, 194 summary=self.msg, 195 severity=sev, 196 eventClass=Status_IpService, 197 eventGroup="TCPTest", 198 agent="ZenStatus", 199 manager=hostname)
200
201 - def start(self):
202 """ 203 Called by zenstatus to make a connection attempt to the service. 204 205 @return: Twisted deferred 206 @rtype: Twisted deferred 207 """ 208 d = self.deferred = defer.Deferred() 209 reactor.connectTCP(self.cfg.ip, self.cfg.port, self, self.cfg.timeout) 210 return d
211