From 5dc626fd898ea59855e93d778834ab64144b2fdf Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Tue, 20 Jan 2009 14:20:24 +0000 Subject: [PATCH] Fix burnin problems when using http checks The urllib2 module has very bad error handling. This patch changes to urllib which is simpler, and we derive a custom class from the FancyURLopener. Burning is no longer keeping sockets in CLOSE_WAIT state with this patch. Reviewed-by: ultrotter --- tools/burnin | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/tools/burnin b/tools/burnin index 84b506bde..fa8776284 100755 --- a/tools/burnin +++ b/tools/burnin @@ -28,7 +28,7 @@ import sys import optparse import time import socket -import urllib2 +import urllib import errno from itertools import izip, islice, cycle from cStringIO import StringIO @@ -77,12 +77,31 @@ def Err(msg, exit_code=1): sys.stderr.flush() sys.exit(exit_code) + +class SimpleOpener(urllib.FancyURLopener): + """A simple url opener""" + + def prompt_user_passwd(self, host, realm, clear_cache = 0): + """No-interaction version of prompt_user_passwd.""" + return None, None + + def http_error_default(self, url, fp, errcode, errmsg, headers): + """Custom error handling""" + # make sure sockets are not left in CLOSE_WAIT, this is similar + # but with a different exception to the BasicURLOpener class + _ = fp.read() # throw away data + fp.close() + raise InstanceDown("HTTP error returned: code %s, msg %s" % + (errcode, errmsg)) + + class Burner(object): """Burner class.""" def __init__(self): """Constructor.""" utils.SetupLogging(constants.LOG_BURNIN, debug=False, stderr_logging=True) + self.url_opener = SimpleOpener() self._feed_buf = StringIO() self.nodes = [] self.instances = [] @@ -646,18 +665,18 @@ class Burner(object): """ if not self.opts.http_check: return - try: - for retries in range(self.opts.net_timeout): - try: - url = urllib2.urlopen("http://%s/hostname.txt" % instance) - except urllib2.URLError, err: - if err.args[0][0] == errno.ECONNREFUSED: - time.sleep(1) - continue - raise - except urllib2.URLError, err: - raise InstanceDown(instance, str(err)) + end_time = time.time() + self.opts.net_timeout + url = None + while time.time() < end_time and url is None: + try: + url = self.url_opener.open("http://%s/hostname.txt" % instance) + except IOError, err: + # here we can have connection refused, no route to host, etc. + time.sleep(1) + if url is None: + raise InstanceDown(instance, "Cannot contact instance") hostname = url.read().strip() + url.close() if hostname != instance: raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" % (instance, hostname))) -- GitLab