X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=source%2FBootServerRequest.py;h=599bea03ae025d72ca37908229677ea63d902dff;hb=d95e7f586c1e1636ddfec67184b7be1e2c9ca694;hp=75fad3c2d29a0df82d8164eb63156a926c1fdad8;hpb=bd85ea4bb68783a0a58a6ddc6c3cc1dd22715eb1;p=bootmanager.git diff --git a/source/BootServerRequest.py b/source/BootServerRequest.py index 75fad3c..599bea0 100644 --- a/source/BootServerRequest.py +++ b/source/BootServerRequest.py @@ -1,24 +1,20 @@ -#!/usr/bin/python2 - +#!/usr/bin/python +# # Copyright (c) 2003 Intel Corporation # All rights reserved. # # Copyright (c) 2004-2006 The Trustees of Princeton University # All rights reserved. +from __future__ import print_function + import os, sys import re import string import urllib import tempfile -# try to load pycurl -try: - import pycurl - PYCURL_LOADED= 1 -except: - PYCURL_LOADED= 0 - +import pycurl # if there is no cStringIO, fall back to the original try: @@ -30,52 +26,35 @@ except: class BootServerRequest: - VERBOSE = 0 - # all possible places to check the cdrom mount point. # /mnt/cdrom is typically after the machine has come up, # and /usr is when the boot cd is running - CDROM_MOUNT_PATH = ("/mnt/cdrom/","/usr/") - - # this is the server to contact if we don't have a bootcd - DEFAULT_BOOT_SERVER = "boot.planet-lab.org" - - BOOTCD_VERSION_FILE = "bootme/ID" - BOOTCD_SERVER_FILE = "bootme/BOOTSERVER" - BOOTCD_SERVER_CERT_DIR = "bootme/cacert" - CACERT_NAME = "cacert.pem" - - # location of file containing http/https proxy info, if needed - PROXY_FILE = '/etc/planetlab/http_proxy' + CDROM_MOUNT_PATH = ("/mnt/cdrom/", "/usr/") + BOOTSERVER_CERTS = {} + MONITORSERVER_CERTS = {} + BOOTCD_VERSION = "" + HTTP_SUCCESS = 200 + HAS_BOOTCD = 0 + USE_PROXY = 0 + PROXY = 0 + # in seconds, how maximum time allowed for connect + DEFAULT_CURL_CONNECT_TIMEOUT = 30 + # in seconds, maximum time allowed for any transfer + DEFAULT_CURL_MAX_TRANSFER_TIME = 3600 # location of curl executable, if pycurl isn't available # and the DownloadFile method is called (backup, only # really need for the boot cd environment where pycurl # doesn't exist CURL_CMD = 'curl' - # in seconds, how maximum time allowed for connect - DEFAULT_CURL_CONNECT_TIMEOUT = 30 - - # in seconds, maximum time allowed for any transfer - DEFAULT_CURL_MAX_TRANSFER_TIME = 3600 - - CURL_SSL_VERSION = 3 + # use TLSv1 and not SSLv3 anymore + CURL_SSL_VERSION = pycurl.SSLVERSION_TLSv1 - HTTP_SUCCESS = 200 + def __init__(self, vars, verbose=0): - # proxy variables - USE_PROXY = 0 - PROXY = 0 - - # bootcd variables - HAS_BOOTCD = 0 - BOOTCD_VERSION = "" - BOOTSERVER_CERTS= {} - - def __init__(self, verbose=0): - - self.VERBOSE= verbose + self.VERBOSE = verbose + self.VARS = vars # see if we have a boot cd mounted by checking for the version file # if HAS_BOOTCD == 0 then either the machine doesn't have @@ -83,107 +62,104 @@ class BootServerRequest: self.HAS_BOOTCD = 0 for path in self.CDROM_MOUNT_PATH: - self.Message( "Checking existance of boot cd on %s" % path ) + self.Message("Checking existance of boot cd on {}".format(path)) - os.system("/bin/mount %s > /dev/null 2>&1" % path ) + os.system("/bin/mount {} > /dev/null 2>&1".format(path)) - version_file= path + self.BOOTCD_VERSION_FILE - self.Message( "Looking for version file %s" % version_file ) + version_file = self.VARS['BOOTCD_VERSION_FILE'].format(path=path) + self.Message("Looking for version file {}".format(version_file)) if os.access(version_file, os.R_OK) == 0: - self.Message( "No boot cd found." ); + self.Message("No boot cd found."); else: - self.Message( "Found boot cd." ) - self.HAS_BOOTCD=1 + self.Message("Found boot cd.") + self.HAS_BOOTCD = 1 break - if self.HAS_BOOTCD: # check the version of the boot cd, and locate the certs - self.Message( "Getting boot cd version." ) + self.Message("Getting boot cd version.") - versionRegExp= re.compile(r"PlanetLab BootCD v(\S+)") + versionRegExp = re.compile(r"PlanetLab BootCD v(\S+)") - bootcd_version_f= file(version_file,"r") - line= string.strip(bootcd_version_f.readline()) + bootcd_version_f = file(version_file, "r") + line = string.strip(bootcd_version_f.readline()) bootcd_version_f.close() - match= versionRegExp.findall(line) + match = versionRegExp.findall(line) if match: - (self.BOOTCD_VERSION)= match[0] + (self.BOOTCD_VERSION) = match[0] # right now, all the versions of the bootcd are supported, # so no need to check it - # create a list of the servers we should - # attempt to contact, and the certs for each - server_list= path + self.BOOTCD_SERVER_FILE - self.Message( "Getting list of servers off of cd from %s." % - server_list ) - - bootservers_f= file(server_list,"r") - bootservers= bootservers_f.readlines() - bootservers_f.close() + self.Message("Getting server from configuration") + bootservers = [ self.VARS['BOOT_SERVER'] ] for bootserver in bootservers: bootserver = string.strip(bootserver) - cacert_path= "%s/%s/%s/%s" % \ - (path,self.BOOTCD_SERVER_CERT_DIR, - bootserver,self.CACERT_NAME) + cacert_path = "{}/{}/{}".format( + self.VARS['SERVER_CERT_DIR'].format(path=path), + bootserver, + self.VARS['CACERT_NAME']) if os.access(cacert_path, os.R_OK): - self.BOOTSERVER_CERTS[bootserver]= cacert_path + self.BOOTSERVER_CERTS[bootserver] = cacert_path + + monitorservers = [ self.VARS['MONITOR_SERVER'] ] + for monitorserver in monitorservers: + monitorserver = string.strip(monitorserver) + cacert_path = "{}/{}/{}".format( + self.VARS['SERVER_CERT_DIR'].format(path=path), + monitorserver, + self.VARS['CACERT_NAME']) + if os.access(cacert_path, os.R_OK): + self.MONITORSERVER_CERTS[monitorserver] = cacert_path - self.Message( "Set of servers to contact: %s" % - str(self.BOOTSERVER_CERTS) ) + self.Message("Set of servers to contact: {}".format(self.BOOTSERVER_CERTS)) + self.Message("Set of servers to upload to: {}".format(self.MONITORSERVER_CERTS)) else: - self.Message( "Using default boot server address." ) - self.BOOTSERVER_CERTS[self.DEFAULT_BOOT_SERVER]= "" + self.Message("Using default boot server address.") + self.BOOTSERVER_CERTS[self.VARS['DEFAULT_BOOT_SERVER']] = "" + self.MONITORSERVER_CERTS[self.VARS['DEFAULT_BOOT_SERVER']] = "" - def CheckProxy( self ): + def CheckProxy(self): # see if we have any proxy info from the machine - self.USE_PROXY= 0 - self.Message( "Checking existance of proxy config file..." ) + self.USE_PROXY = 0 + self.Message("Checking existance of proxy config file...") - if os.access(self.PROXY_FILE, os.R_OK) and \ - os.path.isfile(self.PROXY_FILE): - self.PROXY= string.strip(file(self.PROXY_FILE,'r').readline()) - self.USE_PROXY= 1 - self.Message( "Using proxy %s." % self.PROXY ) + if os.access(self.VARS['PROXY_FILE'], os.R_OK) and \ + os.path.isfile(self.VARS['PROXY_FILE']): + self.PROXY = string.strip(file(self.VARS['PROXY_FILE'], 'r').readline()) + self.USE_PROXY = 1 + self.Message("Using proxy {}.".format(self.PROXY)) else: - self.Message( "Not using any proxy." ) - - - - def Message( self, Msg ): - if( self.VERBOSE ): - print( Msg ) + self.Message("Not using any proxy.") - def Error( self, Msg ): - sys.stderr.write( Msg + "\n" ) + def Message(self, Msg): + if(self.VERBOSE): + print(Msg) + def Error(self, Msg): + sys.stderr.write(Msg + "\n") - - def Warning( self, Msg ): + def Warning(self, Msg): self.Error(Msg) + def MakeRequest(self, PartialPath, GetVars, + PostVars, DoSSL, DoCertCheck, + ConnectTimeout = DEFAULT_CURL_CONNECT_TIMEOUT, + MaxTransferTime = DEFAULT_CURL_MAX_TRANSFER_TIME, + FormData = None): + fd, buffer_name = tempfile.mkstemp("MakeRequest-XXXXXX") + os.close(fd) + buffer = open(buffer_name, "w+b") - def MakeRequest( self, PartialPath, GetVars, - PostVars, DoSSL, DoCertCheck, - ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT, - MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME, - FormData= None): - - if hasattr(tempfile, "NamedTemporaryFile"): - buffer = tempfile.NamedTemporaryFile() - buffer_name = buffer.name - else: - buffer_name = tempfile.mktemp("MakeRequest") - buffer = open(buffer_name, "w+") + # the file "buffer_name" will be deleted by DownloadFile() ok = self.DownloadFile(PartialPath, GetVars, PostVars, DoSSL, DoCertCheck, buffer_name, @@ -191,209 +167,152 @@ class BootServerRequest: MaxTransferTime, FormData) - # check the code, return the string only if it was successfull + # check the ok code, return the string only if it was successfull if ok: buffer.seek(0) - return buffer.read() + ret = buffer.read() else: - return None + ret = None + + buffer.close() + try: + # just in case it is not deleted by DownloadFile() + os.unlink(buffer_name) + except OSError: + pass + + return ret def DownloadFile(self, PartialPath, GetVars, PostVars, DoSSL, DoCertCheck, DestFilePath, - ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT, - MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME, - FormData= None): + ConnectTimeout = DEFAULT_CURL_CONNECT_TIMEOUT, + MaxTransferTime = DEFAULT_CURL_MAX_TRANSFER_TIME, + FormData = None): - self.Message( "Attempting to retrieve %s" % PartialPath ) + self.Message("Attempting to retrieve {}".format(PartialPath)) # we can't do ssl and check the cert if we don't have a bootcd if DoSSL and DoCertCheck and not self.HAS_BOOTCD: - self.Error( "No boot cd exists (needed to use -c and -s.\n" ) + self.Error("No boot cd exists (needed to use -c and -s.\n") return 0 - if DoSSL and not PYCURL_LOADED: - self.Warning( "Using SSL without pycurl will by default " \ - "check at least standard certs." ) - # ConnectTimeout has to be greater than 0 if ConnectTimeout <= 0: - self.Error( "Connect timeout must be greater than zero.\n" ) + self.Error("Connect timeout must be greater than zero.\n") return 0 self.CheckProxy() - dopostdata= 0 + dopostdata = 0 # setup the post and get vars for the request if PostVars: - dopostdata= 1 + dopostdata = 1 postdata = urllib.urlencode(PostVars) - self.Message( "Posting data:\n%s\n" % postdata ) + self.Message("Posting data:\n{}\n".format(postdata)) - getstr= "" + getstr = "" if GetVars: - getstr= "?" + urllib.urlencode(GetVars) - self.Message( "Get data:\n%s\n" % getstr ) + getstr = "?" + urllib.urlencode(GetVars) + self.Message("Get data:\n{}\n".format(getstr)) # now, attempt to make the request, starting at the first # server in the list + if FormData: + cert_list = self.MONITORSERVER_CERTS + else: + cert_list = self.BOOTSERVER_CERTS - for server in self.BOOTSERVER_CERTS: - self.Message( "Contacting server %s." % server ) + for server in cert_list: + self.Message("Contacting server {}.".format(server)) - certpath = self.BOOTSERVER_CERTS[server] + certpath = cert_list[server] # output what we are going to be doing - self.Message( "Connect timeout is %s seconds" % \ - ConnectTimeout ) - - self.Message( "Max transfer time is %s seconds" % \ - MaxTransferTime ) + self.Message("Connect timeout is {} seconds".format(ConnectTimeout)) + self.Message("Max transfer time is {} seconds".format(MaxTransferTime)) if DoSSL: - url = "https://%s/%s%s" % (server,PartialPath,getstr) + url = "https://{}/{}{}".format(server, PartialPath, getstr) - if DoCertCheck and PYCURL_LOADED: - self.Message( "Using SSL version %d and verifying peer." % - self.CURL_SSL_VERSION ) + if DoCertCheck: + self.Message("Using SSL version {} and verifying peer." + .format(self.CURL_SSL_VERSION)) else: - self.Message( "Using SSL version %d." % - self.CURL_SSL_VERSION ) + self.Message("Using SSL version {}." + .format(self.CURL_SSL_VERSION)) else: - url = "http://%s/%s%s" % (server,PartialPath,getstr) + url = "http://{}/{}{}".format(server, PartialPath, getstr) - self.Message( "URL: %s" % url ) - - # setup a new pycurl instance, or a curl command line string - # if we don't have pycurl + self.Message("URL: {}".format(url)) - if PYCURL_LOADED: - curl= pycurl.Curl() + # setup a new pycurl instance + curl = pycurl.Curl() - # don't want curl sending any signals - curl.setopt(pycurl.NOSIGNAL, 1) - - curl.setopt(pycurl.CONNECTTIMEOUT, ConnectTimeout) - curl.setopt(pycurl.TIMEOUT, MaxTransferTime) + # don't want curl sending any signals + curl.setopt(pycurl.NOSIGNAL, 1) + + curl.setopt(pycurl.CONNECTTIMEOUT, ConnectTimeout) + curl.setopt(pycurl.TIMEOUT, MaxTransferTime) - # do not follow location when attempting to download a file - curl.setopt(pycurl.FOLLOWLOCATION, 0) + # do not follow location when attempting to download a file + curl.setopt(pycurl.FOLLOWLOCATION, 0) - if self.USE_PROXY: - curl.setopt(pycurl.PROXY, self.PROXY ) + if self.USE_PROXY: + curl.setopt(pycurl.PROXY, self.PROXY) - if DoSSL: - curl.setopt(pycurl.SSLVERSION, self.CURL_SSL_VERSION) + if DoSSL: + curl.setopt(pycurl.SSLVERSION, self.CURL_SSL_VERSION) - if DoCertCheck: - curl.setopt(pycurl.CAINFO, certpath) - curl.setopt(pycurl.SSL_VERIFYPEER, 2) - - else: - curl.setopt(pycurl.SSL_VERIFYPEER, 0) + if DoCertCheck: + curl.setopt(pycurl.CAINFO, certpath) + curl.setopt(pycurl.SSL_VERIFYPEER, 2) + else: + curl.setopt(pycurl.SSL_VERIFYPEER, 0) - if dopostdata: - curl.setopt(pycurl.POSTFIELDS, postdata) - - # setup multipart/form-data upload - if FormData: - curl.setopt(pycurl.HTTPPOST, FormData) - - curl.setopt(pycurl.URL, url) - else: - - cmdline = "%s " \ - "--connect-timeout %d " \ - "--max-time %d " \ - "--header Pragma: " \ - "--output %s " \ - "--fail " % \ - (self.CURL_CMD, ConnectTimeout, - MaxTransferTime, DestFilePath) - - if dopostdata: - cmdline = cmdline + "--data '" + postdata + "' " - - if FormData: - cmdline = cmdline + "".join(["--form '" + field + "' " for field in FormData]) + if dopostdata: + curl.setopt(pycurl.POSTFIELDS, postdata) - if not self.VERBOSE: - cmdline = cmdline + "--silent " - - if self.USE_PROXY: - cmdline = cmdline + "--proxy %s " % self.PROXY + # setup multipart/form-data upload + if FormData: + curl.setopt(pycurl.HTTPPOST, FormData) - if DoSSL: - cmdline = cmdline + "--sslv%d " % self.CURL_SSL_VERSION + curl.setopt(pycurl.URL, url) - if DoCertCheck: - cmdline = cmdline + "--cacert %s " % certpath - - cmdline = cmdline + url - - self.Message( "curl command: %s" % cmdline ) - - - if PYCURL_LOADED: - try: - # setup the output file - outfile = open(DestFilePath,"wb") - - self.Message( "Opened output file %s" % DestFilePath ) + try: + # setup the output file + with open(DestFilePath,"wb") as outfile: + self.Message("Opened output file {}".format(DestFilePath)) + curl.setopt(pycurl.WRITEDATA, outfile) - - self.Message( "Fetching..." ) + + self.Message("Fetching...") curl.perform() - self.Message( "Done." ) - - http_result= curl.getinfo(pycurl.HTTP_CODE) + self.Message("Done.") + + http_result = curl.getinfo(pycurl.HTTP_CODE) curl.close() - - outfile.close() - self.Message( "Results saved in %s" % DestFilePath ) - - # check the code, return 1 if successfull - if http_result == self.HTTP_SUCCESS: - self.Message( "Successfull!" ) - return 1 - else: - self.Message( "Failure, resultant http code: %d" % \ - http_result ) - - except pycurl.error, err: - errno, errstr= err - self.Error( "connect to %s failed; curl error %d: '%s'\n" % - (server,errno,errstr) ) - - if not outfile.closed: - try: - os.unlink(DestFilePath) - outfile.close() - except OSError: - pass + + self.Message("Results saved in {}".format(DestFilePath)) - else: - self.Message( "Fetching..." ) - rc = os.system(cmdline) - self.Message( "Done." ) - - if rc != 0: - try: - os.unlink( DestFilePath ) - except OSError: - pass - self.Message( "Failure, resultant curl code: %d" % rc ) - self.Message( "Removed %s" % DestFilePath ) - else: - self.Message( "Successfull!" ) + # check the code, return 1 if successfull + if http_result == self.HTTP_SUCCESS: + self.Message("Successfull!") return 1 - - self.Error( "Unable to successfully contact any boot servers.\n" ) - return 0 + else: + self.Message("Failure, resultant http code: {}" + .format(http_result)) + except pycurl.error as err: + errno, errstr = err + self.Error("connect to {} failed; curl error {}: '{}'\n" + .format(server, errno, errstr)) + + self.Error("Unable to successfully contact any boot servers.\n") + return 0 @@ -421,10 +340,10 @@ if __name__ == "__main__": [ "output=", "verbose", \ "help","ssl","checkcert"]) - ssl= 0 - checkcert= 0 - output_file= None - verbose= 0 + ssl = 0 + checkcert = 0 + output_file = None + verbose = 0 for opt, arg in opt_list: if opt in ("-h","--help"): @@ -432,21 +351,21 @@ if __name__ == "__main__": sys.exit() if opt in ("-c","--checkcert"): - checkcert= 1 + checkcert = 1 if opt in ("-s","--ssl"): - ssl= 1 + ssl = 1 if opt in ("-o","--output"): - output_file= arg + output_file = arg if opt == "-v": - verbose= 1 + verbose = 1 if len(arg_list) != 1: raise Exception - partialpath= arg_list[0] + partialpath = arg_list[0] if string.lower(partialpath[:4]) == "http": raise Exception @@ -455,14 +374,14 @@ if __name__ == "__main__": sys.exit(2) # got the command line args straightened out - requestor= BootServerRequest(verbose) + requestor = BootServerRequest(verbose) if output_file: - requestor.DownloadFile( partialpath, None, None, ssl, + requestor.DownloadFile(partialpath, None, None, ssl, checkcert, output_file) else: - result= requestor.MakeRequest( partialpath, None, None, ssl, checkcert) + result = requestor.MakeRequest(partialpath, None, None, ssl, checkcert) if result: - print result + print(result) else: sys.exit(1)