-import os
+# 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 xmlrpclib
-import urllib
-import pycurl
-from cStringIO import StringIO
+import signal
+import os
import logger
-# a pycurl-based replacement for the previous version that relied on forking curl
-
-def retrieve(url, cacert=None, postdata=None, timeout=90):
- curl= pycurl.Curl()
- curl.setopt(pycurl.URL,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)
+verbose=False
+#verbose=True
- # set timeout
- if timeout:
- curl.setopt(pycurl.CONNECTTIMEOUT, timeout)
- curl.setopt(pycurl.TIMEOUT, timeout)
+class Sopen(Popen):
+ def kill(self, signal = signal.SIGTERM):
+ os.kill(self.pid, signal)
- # set cacert
- if cacert:
- curl.setopt(pycurl.CAINFO, cacert)
- curl.setopt(pycurl.SSL_VERIFYPEER, 2)
- else:
- curl.setopt(pycurl.SSL_VERIFYPEER, 0)
-
- # set postdata
- if postdata:
- if isinstance(postdata,dict):
- postfields = urllib.urlencode(postdata)
- else:
- postfields=postdata
- curl.setopt(pycurl.POSTFIELDS, postfields)
-
- # go
- try:
- curl.perform()
-
- errcode = curl.getinfo(pycurl.HTTP_CODE)
- 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,errstr),postdata )
-
- return buffer.getvalue()
+def retrieve(url, cacert=None, postdata=None, timeout=90):
+# 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 xmlrpclib.ProtocolError(url, rc, err, postdata)
+ else:
+ return data