diff options
Diffstat (limited to 'src/lib/Bcfg2/Proxy.py')
-rw-r--r-- | src/lib/Bcfg2/Proxy.py | 121 |
1 files changed, 65 insertions, 56 deletions
diff --git a/src/lib/Bcfg2/Proxy.py b/src/lib/Bcfg2/Proxy.py index 422d642db..220b89b5f 100644 --- a/src/lib/Bcfg2/Proxy.py +++ b/src/lib/Bcfg2/Proxy.py @@ -1,13 +1,3 @@ -"""RPC client access to cobalt components. - -Classes: -ComponentProxy -- an RPC client proxy to Cobalt components - -Functions: -load_config -- read configuration files - -""" - import logging import re import socket @@ -34,7 +24,6 @@ import time from Bcfg2.Bcfg2Py3k import httplib, xmlrpclib, urlparse version = sys.version_info[:2] -has_py23 = version >= (2, 3) has_py26 = version >= (2, 6) __all__ = ["ComponentProxy", @@ -70,50 +59,58 @@ class CertificateError(Exception): return ("Got unallowed commonName %s from server" % self.commonName) +_orig_Method = xmlrpclib._Method class RetryMethod(xmlrpclib._Method): """Method with error handling and retries built in.""" log = logging.getLogger('xmlrpc') - max_retries = 4 + max_retries = 3 + retry_delay = 1 def __call__(self, *args): for retry in range(self.max_retries): + if retry >= self.max_retries - 1: + final = True + else: + final = False + msg = None try: - return xmlrpclib._Method.__call__(self, *args) + return _orig_Method.__call__(self, *args) except xmlrpclib.ProtocolError: err = sys.exc_info()[1] - self.log.error("Server failure: Protocol Error: %s %s" % \ - (err.errcode, err.errmsg)) - raise xmlrpclib.Fault(20, "Server Failure") + msg = "Server failure: Protocol Error: %s %s" % \ + (err.errcode, err.errmsg) except xmlrpclib.Fault: - raise + msg = sys.exc_info()[1] except socket.error: err = sys.exc_info()[1] if hasattr(err, 'errno') and err.errno == 336265218: - self.log.error("SSL Key error") - break - if hasattr(err, 'errno') and err.errno == 185090050: - self.log.error("SSL CA error") - break - if retry == 3: - self.log.error("Server failure: %s" % err) - raise xmlrpclib.Fault(20, err) + msg = "SSL Key error: %s" % err + elif hasattr(err, 'errno') and err.errno == 185090050: + msg = "SSL CA error: %s" % err + elif final: + msg = "Server failure: %s" % err except CertificateError: - ce = sys.exc_info()[1] - self.log.error("Got unallowed commonName %s from server" \ - % ce.commonName) - break + err = sys.exc_info()[1] + msg = "Got unallowed commonName %s from server" % err.commonName except KeyError: - self.log.error("Server disallowed connection") - break + err = sys.exc_info()[1] + msg = "Server disallowed connection: %s" % err + except ProxyError: + err = sys.exc_info()[1] + msg = err except: - self.log.error("Unknown failure", exc_info=1) - break - time.sleep(0.5) - raise xmlrpclib.Fault(20, "Server Failure") + err = sys.exc_info()[1] + msg = "Unknown failure: %s" % err + if msg: + if final: + self.log.error(msg) + raise ProxyError(msg) + else: + self.log.info(msg) + time.sleep(self.retry_delay) -# sorry jon -_Method = RetryMethod +xmlrpclib._Method = RetryMethod class SSLHTTPConnection(httplib.HTTPConnection): @@ -192,7 +189,15 @@ class SSLHTTPConnection(httplib.HTTPConnection): def _connect_py26ssl(self): """Initiates a connection using the ssl module.""" - rawsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + # check for IPv6 + hostip = socket.getaddrinfo(self.host, + self.port, + socket.AF_UNSPEC, + socket.SOCK_STREAM)[0][4][0] + if ':' in hostip: + rawsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) + else: + rawsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if self.protocol == 'xmlrpc/ssl': ssl_protocol_ver = ssl.PROTOCOL_SSLv23 elif self.protocol == 'xmlrpc/tlsv1': @@ -212,8 +217,7 @@ class SSLHTTPConnection(httplib.HTTPConnection): self.logger.warning("SSL key specfied, but no cert. Cannot authenticate this client with SSL.") self.key = None - if has_py23: - rawsock.settimeout(self.timeout) + rawsock.settimeout(self.timeout) self.sock = ssl.SSLSocket(rawsock, cert_reqs=other_side_required, ca_certs=self.ca, suppress_ragged_eofs=True, keyfile=self.key, certfile=self.cert, @@ -286,26 +290,21 @@ class XMLRPCTransport(xmlrpclib.Transport): def make_connection(self, host): host, self._extra_headers = self.get_host_info(host)[0:2] - http = SSLHTTPConnection(host, + return SSLHTTPConnection(host, key=self.key, cert=self.cert, ca=self.ca, scns=self.scns, timeout=self.timeout) - https = httplib.HTTP() - https._setup(http) - return https def request(self, host, handler, request_body, verbose=0): """Send request to server and return response.""" - h = self.make_connection(host) - try: - self.send_request(h, handler, request_body) - self.send_host(h, host) - self.send_user_agent(h) - self.send_content(h, request_body) - errcode, errmsg, headers = h.getreply() + conn = self.send_request(host, handler, request_body, False) + response = conn.getresponse() + errcode = response.status + errmsg = response.reason + headers = response.msg except (socket.error, SSL_ERROR): err = sys.exc_info()[1] raise ProxyError(xmlrpclib.ProtocolError(host + handler, @@ -320,8 +319,17 @@ class XMLRPCTransport(xmlrpclib.Transport): headers)) self.verbose = verbose - msglen = int(headers.dict['content-length']) - return self._get_response(h.getfile(), msglen) + return self.parse_response(response) + + if sys.hexversion < 0x03000000: + def send_request(self, host, handler, request_body, debug): + """ send_request() changed significantly in py3k.""" + conn = self.make_connection(host) + xmlrpclib.Transport.send_request(self, conn, handler, request_body) + self.send_host(conn, host) + self.send_user_agent(conn) + self.send_content(conn, request_body) + return conn def _get_response(self, fd, length): # read response from input file/socket, and parse it @@ -345,9 +353,8 @@ class XMLRPCTransport(xmlrpclib.Transport): return u.close() -def ComponentProxy(url, user=None, password=None, - key=None, cert=None, ca=None, - allowedServerCNs=None, timeout=90): +def ComponentProxy(url, user=None, password=None, key=None, cert=None, ca=None, + allowedServerCNs=None, timeout=90, retries=3, delay=1): """Constructs proxies to components. @@ -357,6 +364,8 @@ def ComponentProxy(url, user=None, password=None, Additional arguments are passed to the ServerProxy constructor. """ + xmlrpclib._Method.max_retries = retries + xmlrpclib._Method.retry_delay = delay if user and password: method, path = urlparse(url)[:2] |