-#!/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:
# /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
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:
self.HAS_BOOTCD=1
break
-
if self.HAS_BOOTCD:
# check the version of the boot cd, and locate the certs
# 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 ):
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." )
def MakeRequest( self, PartialPath, GetVars,
PostVars, DoSSL, DoCertCheck,
ConnectTimeout= DEFAULT_CURL_CONNECT_TIMEOUT,
- MaxTransferTime= DEFAULT_CURL_MAX_TRANSFER_TIME):
+ 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
+ # the file "buffer_name" will be deleted by DownloadFile()
- # didn't pass a path in? just get the root doc
- if PartialPath == "":
- PartialPath= "/"
+ ok = self.DownloadFile(PartialPath, GetVars, PostVars,
+ DoSSL, DoCertCheck, buffer_name,
+ ConnectTimeout,
+ MaxTransferTime,
+ FormData)
- # ConnectTimeout has to be greater than 0
- if ConnectTimeout <= 0:
- self.Error( "Connect timeout must be greater than zero.\n" )
- return None
-
- # 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 )
-
- 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)
-
- curl.setopt(pycurl.URL, url)
- self.Message( "URL: %s" % url )
+ ret = None
+
+ buffer.close()
+ try:
+ # just in case it is not deleted by DownloadFile()
+ os.unlink(buffer_name)
+ except OSError:
+ pass
- # 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 )
# 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
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:
if dopostdata:
cmdline = cmdline + "--data '" + postdata + "' "
+ if FormData:
+ cmdline = cmdline + "".join(["--form '" + field + "' " for field in FormData])
+
if not self.VERBOSE:
cmdline = cmdline + "--silent "
if DoSSL:
cmdline = cmdline + "--sslv%d " % self.CURL_SSL_VERSION
-
if DoCertCheck:
cmdline = cmdline + "--cacert %s " % certpath
if not outfile.closed:
try:
os.unlink(DestFilePath)
- outfile.close
+ outfile.close()
except OSError:
pass