X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=source%2FBootServerRequest.py;h=8cb29f3792462f0ae2ab5db47d55779ceb6a51c9;hb=6388c2e6e02491179b15a8247afb8ef4e1ec1d0e;hp=a81ca9beca61a10f8022e4212c1d0d77d4e9ade4;hpb=88cfdd881bbd5191eaaf6408e0b8d57bfdf51438;p=bootmanager.git diff --git a/source/BootServerRequest.py b/source/BootServerRequest.py index a81ca9b..8cb29f3 100644 --- a/source/BootServerRequest.py +++ b/source/BootServerRequest.py @@ -1,51 +1,19 @@ -#!/usr/bin/python2 - +#!/usr/bin/python +# +# $Id$ +# $URL$ +# # Copyright (c) 2003 Intel Corporation # All rights reserved. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: - -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. - -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. - -# * Neither the name of the Intel Corporation nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. - -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS OF -# YOUR JURISDICTION. It is licensee's responsibility to comply with any -# export regulations applicable in licensee's jurisdiction. Under -# CURRENT (May 2000) U.S. export regulations this software is eligible -# for export from the U.S. and can be downloaded by or otherwise -# exported or reexported worldwide EXCEPT to U.S. embargoed destinations -# which include Cuba, Iraq, Libya, North Korea, Iran, Syria, Sudan, -# Afghanistan and any other country to which the U.S. has embargoed -# goods and services. - +# +# Copyright (c) 2004-2006 The Trustees of Princeton University +# All rights reserved. import os, sys import re import string import urllib +import tempfile # try to load pycurl try: @@ -71,46 +39,29 @@ class BootServerRequest: # /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/") + BOOTSERVER_CERTS= {} + MONITORSERVER_CERTS= {} + BOOTCD_VERSION="" + HTTP_SUCCESS=200 + HAS_BOOTCD=0 + USE_PROXY=0 + PROXY=0 - # 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' - + # 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' + CURL_SSL_VERSION=3 - # 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 - - HTTP_SUCCESS = 200 - - # proxy variables - USE_PROXY = 0 - PROXY = 0 - - # bootcd variables - HAS_BOOTCD = 0 - BOOTCD_VERSION = "" - BOOTSERVER_CERTS= {} - - def __init__(self, verbose=0): + def __init__(self, vars, verbose=0): 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 @@ -122,7 +73,7 @@ class BootServerRequest: os.system("/bin/mount %s > /dev/null 2>&1" % path ) - version_file= path + self.BOOTCD_VERSION_FILE + version_file= self.VARS['BOOTCD_VERSION_FILE'] % {'path' : path} self.Message( "Looking for version file %s" % version_file ) if os.access(version_file, os.R_OK) == 0: @@ -132,7 +83,6 @@ class BootServerRequest: self.HAS_BOOTCD=1 break - if self.HAS_BOOTCD: # check the version of the boot cd, and locate the certs @@ -151,29 +101,34 @@ class BootServerRequest: # 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= "%s/%s/%s" % \ + (self.VARS['SERVER_CERT_DIR'] % {'path' : path}, + bootserver,self.VARS['CACERT_NAME']) if os.access(cacert_path, os.R_OK): self.BOOTSERVER_CERTS[bootserver]= cacert_path + monitorservers= [ self.VARS['MONITOR_SERVER'] ] + for monitorserver in monitorservers: + monitorserver = string.strip(monitorserver) + cacert_path= "%s/%s/%s" % \ + (self.VARS['SERVER_CERT_DIR'] % {'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 upload to: %s" % + str(self.MONITORSERVER_CERTS) ) else: self.Message( "Using default boot server address." ) - self.BOOTSERVER_CERTS[self.DEFAULT_BOOT_SERVER]= "" + self.BOOTSERVER_CERTS[self.VARS['DEFAULT_BOOT_SERVER']]= "" + self.MONITORSERVER_CERTS[self.VARS['DEFAULT_BOOT_SERVER']]= "" def CheckProxy( self ): @@ -181,11 +136,11 @@ class BootServerRequest: 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()) + 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 %s." % self.PROXY ) + self.Message( "Using proxy %s." % self.PROXY) else: self.Message( "Not using any proxy." ) @@ -213,128 +168,39 @@ class BootServerRequest: MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME, FormData= None): - if PYCURL_LOADED == 0: - self.Error( "MakeRequest method requires pycurl." ) - return None + (fd, buffer_name) = tempfile.mkstemp("MakeRequest-XXXXXX") + os.close(fd) + buffer = open(buffer_name, "w+b") - self.CheckProxy() - - self.Message( "Attempting to retrieve %s" % 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" ) - return None - - # didn't pass a path in? just get the root doc - if PartialPath == "": - PartialPath= "/" + # the file "buffer_name" will be deleted by DownloadFile() - # ConnectTimeout has to be greater than 0 - if ConnectTimeout <= 0: - self.Error( "Connect timeout must be greater than zero.\n" ) - return None + ok = self.DownloadFile(PartialPath, GetVars, PostVars, + DoSSL, DoCertCheck, buffer_name, + ConnectTimeout, + MaxTransferTime, + FormData) - # setup the post and get vars for the request - if PostVars: - dopostdata= 1 - postdata = urllib.urlencode(PostVars) - self.Message( "Posting data:\n%s\n" % postdata ) + # check the ok code, return the string only if it was successfull + if ok: + buffer.seek(0) + ret = buffer.read() else: - dopostdata= 0 - - getstr= "" - if GetVars: - getstr= "?" + urllib.urlencode(GetVars) - self.Message( "Get data:\n%s\n" % getstr ) - - # now, attempt to make the request, starting at the first - # server in the list - for server in self.BOOTSERVER_CERTS: - self.Message( "Contacting server %s." % server ) - - certpath = self.BOOTSERVER_CERTS[server] - - curl= pycurl.Curl() - - # don't want curl sending any signals - curl.setopt(pycurl.NOSIGNAL, 1) - - curl.setopt(pycurl.CONNECTTIMEOUT, ConnectTimeout) - self.Message( "Connect timeout is %s seconds" % \ - ConnectTimeout ) - - curl.setopt(pycurl.TIMEOUT, MaxTransferTime) - self.Message( "Max transfer time is %s seconds" % \ - MaxTransferTime ) - - curl.setopt(pycurl.FOLLOWLOCATION, 1) - curl.setopt(pycurl.MAXREDIRS, 2) - - if self.USE_PROXY: - curl.setopt(pycurl.PROXY, self.PROXY ) + ret = None + + buffer.close() + try: + # just in case it is not deleted by DownloadFile() + os.unlink(buffer_name) + except OSError: + pass - if DoSSL: - curl.setopt(pycurl.SSLVERSION, self.CURL_SSL_VERSION) - - url = "https://%s/%s%s" % (server,PartialPath,getstr) - if DoCertCheck: - curl.setopt(pycurl.CAINFO, certpath) - curl.setopt(pycurl.SSL_VERIFYPEER, 2) - self.Message( "Using SSL version %d and verifying peer." % \ - self.CURL_SSL_VERSION ) - else: - curl.setopt(pycurl.SSL_VERIFYPEER, 0) - self.Message( "Using SSL version %d" % \ - self.CURL_SSL_VERSION ) - else: - url = "http://%s/%s%s" % (server,PartialPath,getstr) - - if dopostdata: - curl.setopt(pycurl.POSTFIELDS, postdata) - - # setup multipart/form-data upload - if FormData: - curl.setopt(pycurl.HTTPPOST, FormData) - - curl.setopt(pycurl.URL, url) - self.Message( "URL: %s" % url ) - - # setup the output buffer - buffer = StringIO() - curl.setopt(pycurl.WRITEFUNCTION, buffer.write) - - try: - self.Message( "Fetching..." ) - curl.perform() - self.Message( "Done." ) - - http_result= curl.getinfo(pycurl.HTTP_CODE) - curl.close() - - # check the code, return the string only if it was successfull - if http_result == self.HTTP_SUCCESS: - self.Message( "Successfull!" ) - return buffer.getvalue() - else: - self.Message( "Failure, resultant http code: %d" % \ - http_result ) - return None - - except pycurl.error, err: - errno, errstr= err - self.Error( "connect to %s failed; curl error %d: '%s'\n" % - (server,errno,errstr) ) - - self.Error( "Unable to successfully contact any boot servers.\n" ) - return None - - + return ret def DownloadFile(self, PartialPath, GetVars, PostVars, DoSSL, DoCertCheck, DestFilePath, ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT, - MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME): + MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME, + FormData= None): self.Message( "Attempting to retrieve %s" % PartialPath ) @@ -370,11 +236,15 @@ class BootServerRequest: # 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: + for server in cert_list: self.Message( "Contacting server %s." % server ) - certpath = self.BOOTSERVER_CERTS[server] + certpath = cert_list[server] # output what we are going to be doing @@ -429,6 +299,10 @@ class BootServerRequest: 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: @@ -444,6 +318,9 @@ class BootServerRequest: if dopostdata: cmdline = cmdline + "--data '" + postdata + "' " + if FormData: + cmdline = cmdline + "".join(["--form '" + field + "' " for field in FormData]) + if not self.VERBOSE: cmdline = cmdline + "--silent " @@ -452,7 +329,6 @@ class BootServerRequest: if DoSSL: cmdline = cmdline + "--sslv%d " % self.CURL_SSL_VERSION - if DoCertCheck: cmdline = cmdline + "--cacert %s " % certpath @@ -496,7 +372,7 @@ class BootServerRequest: if not outfile.closed: try: os.unlink(DestFilePath) - outfile.close + outfile.close() except OSError: pass