X-Git-Url: http://git.onelab.eu/?p=nodemanager.git;a=blobdiff_plain;f=curlwrapper.py;h=a877b07516fe8ff82eee54447a54727298771d8c;hp=c1f59c312b19d56ee633015d1d2cd11f507a25c5;hb=HEAD;hpb=96cae689c8216d4d857896d285f7985adf5c2839 diff --git a/curlwrapper.py b/curlwrapper.py index c1f59c3..a877b07 100644 --- a/curlwrapper.py +++ b/curlwrapper.py @@ -1,72 +1,50 @@ +# Note +# in spring 2010, an attempt was made to use pycurl instead of forking curl +# it turned out, however, that after around 10 cycles of the nodemanager, +# attempts to call GetSlivers were failing with a curl error 60 +# we are thus reverting to the version from tag curlwrapper.py-NodeManager-2.0-8 +# the (broken) pycurl version can be found in tags 2.0-9 and 2.0-10 + +from subprocess import PIPE, Popen +from select import select +import xmlrpc.client +import signal import os -import xmlrpclib -import urllib -import pycurl -from cStringIO import StringIO import logger -# a pycurl-based replacement for the previous version that relied on forking curl +verbose=False +#verbose=True -debug=False +class Sopen(Popen): + def kill(self, signal = signal.SIGTERM): + os.kill(self.pid, signal) def retrieve(url, cacert=None, postdata=None, timeout=90): - curl= pycurl.Curl() - curl.setopt(pycurl.URL,url) - if debug: logger.verbose('curlwrapper: new instance %r -> %s'%(curl,url)) - - # reproduce --fail from the previous version - curl.setopt(pycurl.FAILONERROR,1) - # don't want curl sending any signals - curl.setopt(pycurl.NOSIGNAL, 1) - - # do not follow location when attempting to download a file - # curl.setopt(pycurl.FOLLOWLOCATION, 0) - - # store result on the fly - buffer=StringIO() - curl.setopt(pycurl.WRITEFUNCTION,buffer.write) - - # set timeout - if timeout: - curl.setopt(pycurl.CONNECTTIMEOUT, timeout) - curl.setopt(pycurl.TIMEOUT, timeout) - if debug: logger.verbose('curlwrapper: timeout set to %r'%timeout) - - # set cacert - if cacert: - curl.setopt(pycurl.CAINFO, cacert) - curl.setopt(pycurl.SSL_VERIFYPEER, 2) - if debug: logger.verbose('curlwrapper: using cacert %s'%cacert) - else: - curl.setopt(pycurl.SSL_VERIFYPEER, 0) - - # set postdata - if postdata: - if isinstance(postdata,dict): - postfields = urllib.urlencode(postdata) - if debug: logger.verbose('curlwrapper: using encoded postfields %s'%postfields) - else: - postfields=postdata - if debug: logger.verbose('curlwrapper: using raw postfields %s'%postfields) - curl.setopt(pycurl.POSTFIELDS, postfields) - - # go - try: - curl.perform() - errcode = curl.getinfo(pycurl.HTTP_CODE) - - if debug: logger.verbose('curlwrapper: closing pycurl object') - curl.close() - - # check the code, return 1 if successfull - if errcode == 60: - raise xmlrpclib.ProtocolError (url,errcode, "SSL certificate validation failed", postdata) - elif errcode != 200: - raise xmlrpclib.ProtocolError (url,errcode, "http error %d"%errcode, postdata) - - except pycurl.error, err: - errno, errstr = err - raise xmlrpclib.ProtocolError(url, errno, "curl error %d: '%s'\n" %(errno,curl.errstr()),postdata ) - - return buffer.getvalue() +# command = ('/usr/bin/curl', '--fail', '--silent') + command = ('/usr/bin/curl', '--fail', ) + if cacert: command += ('--cacert', cacert) + if postdata: command += ('--data', '@-') + if timeout: + command += ('--max-time', str(timeout)) + command += ('--connect-timeout', str(timeout)) + command += (url, ) + if verbose: + print('Invoking ', command) + if postdata: print('with postdata=', postdata) + p = Sopen(command , stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + if postdata: p.stdin.write(postdata) + p.stdin.close() + sout, sin, serr = select([p.stdout, p.stderr], [], [], timeout) + if len(sout) == 0 and len(sin) == 0 and len(serr) == 0: + logger.verbose("curlwrapper: timed out after %s" % timeout) + p.kill(signal.SIGKILL) + data = p.stdout.read() + err = p.stderr.read() + rc = p.wait() + if rc != 0: + # when this triggers, the error sometimes doesn't get printed + logger.log ("curlwrapper: retrieve, got stderr <%s>"%err) + raise xmlrpc.client.ProtocolError(url, rc, err, postdata) + else: + return data