From: Stephen Soltesz Date: Tue, 1 Sep 2009 00:01:13 +0000 (+0000) Subject: add ssl certificate fields for Monitor in default_config.xml X-Git-Tag: BootManager-4.3-12~2 X-Git-Url: http://git.onelab.eu/?p=bootmanager.git;a=commitdiff_plain;h=373ed1b705da6b5eb52295d4215857ff923f0815 add ssl certificate fields for Monitor in default_config.xml add ssl certificate generation for Monitor in plc.d/ssl separate bootcd values from bootmanager configuration build.sh now collects all the certificates that it needs to authenticate the https sessions. As well, the BM configuration includes several new values that control how and where it uploads logs. BOOT_API_SERVER remains as the API server for all API calls BOOT_SERVER is the host from which the bootstrapfs and other files are fetched. MONITOR_SERVER is the host where logs are uploaded UPLOAD_LOG_SCRIPT is the path to the upload script or entry point. If the configuration value PLC_MONITOR_ENABLED=false, then MONITOR_SERVER=BOOT_SERVER It is now much easier to extend BM in the future to upload additional files such as for hardware information, SMART data, commands run by root users during the session, etc. --- diff --git a/build.sh b/build.sh index 5fa20a8..411111c 100755 --- a/build.sh +++ b/build.sh @@ -85,6 +85,19 @@ echo '($UUDECODE | /bin/tar -C /tmp -xj) << _EOF_' >> $DEST_SCRIPT sed -i -e "s@^BOOT_API_SERVER.*@BOOT_API_SERVER=https://$PLC_API_HOST:443/$PLC_API_PATH/@" \ $srcdir/source/configuration +sed -i -e "s@^BOOT_SERVER.*@BOOT_SERVER=$PLC_BOOT_HOST@" $srcdir/source/configuration +if [ "$PLC_MONITOR_ENABLED" = "1" ]; then + MONITOR_SERVER=$PLC_MONITOR_HOST +else + MONITOR_SERVER=$PLC_BOOT_HOST +fi +sed -i -e "s@^MONITOR_SERVER.*@MONITOR_SERVER=$MONITOR_SERVER@" $srcdir/source/configuration + +install -D -m 644 $PLC_BOOT_CA_SSL_CRT $srcdir/source/cacert/$PLC_BOOT_HOST/cacert.pem +if [ -f $PLC_MONITOR_CA_SSL_CRT ] ; then + install -D -m 644 $PLC_MONITOR_CA_SSL_CRT $srcdir/source/cacert/$PLC_MONITOR_HOST/cacert.pem +fi + # Replace the default debug SSH key if [ -f "$PLC_DEBUG_SSH_KEY_PUB" ] ; then install -D -m 644 "$PLC_DEBUG_SSH_KEY_PUB" $srcdir/source/debug_files/debug_root_ssh_key diff --git a/source/BootManager.py b/source/BootManager.py index 370044f..714aa15 100755 --- a/source/BootManager.py +++ b/source/BootManager.py @@ -18,7 +18,7 @@ import BootServerRequest # all output is written to this file BM_NODE_LOG= "/tmp/bm.log" -UPLOAD_LOG_SCRIPT = "/boot/upload-bmlog.php" +VARS_FILE = "configuration" # the new contents of PATH when the boot manager is running BIN_PATH= ('/usr/local/bin', @@ -27,7 +27,43 @@ BIN_PATH= ('/usr/local/bin', '/usr/sbin', '/bin', '/sbin') - + +def read_configuration_file(filename): + # read in and store all variables in VARS_FILE into each line + # is in the format name=val (any whitespace around the = is + # removed. everything after the = to the end of the line is + # the value + vars = {} + vars_file= file(filename,'r') + validConfFile = True + for line in vars_file: + # if its a comment or a whitespace line, ignore + if line[:1] == "#" or string.strip(line) == "": + continue + + parts= string.split(line,"=") + if len(parts) != 2: + validConfFile = False + raise Exception( "Invalid line in vars file: %s" % line ) + + name= string.strip(parts[0]) + value= string.strip(parts[1]) + value= value.replace("'", "") # remove quotes + value= value.replace('"', "") # remove quotes + vars[name]= value + + vars_file.close() + if not validConfFile: + raise Exception( "Unable to read configuration vars." ) + + # find out which directory we are running it, and set a variable + # for that. future steps may need to get files out of the bootmanager + # directory + current_dir= os.getcwd() + vars['BM_SOURCE_DIR']= current_dir + + return vars + ############################## class log: @@ -40,6 +76,14 @@ class log: except: print( "bootmanager log : Unable to open output file %r, continuing"%OutputFilePath ) self.OutputFile= None + + self.VARS = None + try: + vars = read_configuration_file(VARS_FILE) + self.VARS = vars + except Exception, e: + self.LogEntry( str(e) ) + return def LogEntry( self, str, inc_newline= 1, display_screen= 1 ): now=time.strftime(log.format, time.localtime()) @@ -72,22 +116,24 @@ class log: if self.OutputFile is not None: self.OutputFile.flush() - self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_SCRIPT ) + self.LogEntry( "Uploading logs to %s" % self.VARS['UPLOAD_LOG_SCRIPT'] ) self.OutputFile.close() self.OutputFile= None - bs_request = BootServerRequest.BootServerRequest() - bs_request.MakeRequest(PartialPath = UPLOAD_LOG_SCRIPT, + hostname= self.VARS['INTERFACE_SETTINGS']['hostname'] + "." + \ + self.VARS['INTERFACE_SETTINGS']['domainname'] + bs_request = BootServerRequest.BootServerRequest(self.VARS) + bs_request.MakeRequest(PartialPath = self.VARS['UPLOAD_LOG_SCRIPT'], GetVars = None, PostVars = None, - FormData = ["log=@" + self.OutputFilePath], + FormData = ["log=@" + self.OutputFilePath, + "hostname=" + hostname, "type=bm.log"], DoSSL = True, DoCertCheck = True) ############################## class BootManager: # file containing initial variables/constants - VARS_FILE = "configuration" # the set of valid node run states NodeRunStates = {'reinstall':None, @@ -105,46 +151,16 @@ class BootManager: # set to 1 if we can run after initialization self.CAN_RUN = 0 - - # read in and store all variables in VARS_FILE into each line - # is in the format name=val (any whitespace around the = is - # removed. everything after the = to the end of the line is - # the value - vars = {} - vars_file= file(self.VARS_FILE,'r') - validConfFile = True - for line in vars_file: - # if its a comment or a whitespace line, ignore - if line[:1] == "#" or string.strip(line) == "": - continue - - parts= string.split(line,"=") - if len(parts) != 2: - self.LOG.LogEntry( "Invalid line in vars file: %s" % line ) - validConfFile = False - break - - name= string.strip(parts[0]) - value= string.strip(parts[1]) - vars[name]= value - - vars_file.close() - if not validConfFile: - self.LOG.LogEntry( "Unable to read configuration vars." ) - return - - # find out which directory we are running it, and set a variable - # for that. future steps may need to get files out of the bootmanager - # directory - current_dir= os.getcwd() - vars['BM_SOURCE_DIR']= current_dir + if log.VARS: + # this contains a set of information used and updated by each step + self.VARS= log.VARS + else: + return + # not sure what the current PATH is set to, replace it with what # we know will work with all the boot cds os.environ['PATH']= string.join(BIN_PATH,":") - - # this contains a set of information used and updated by each step - self.VARS= vars self.CAN_RUN= 1 diff --git a/source/BootServerRequest.py b/source/BootServerRequest.py index 5313a23..4968ac6 100644 --- a/source/BootServerRequest.py +++ b/source/BootServerRequest.py @@ -36,46 +36,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 @@ -87,7 +70,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: @@ -97,7 +80,6 @@ class BootServerRequest: self.HAS_BOOTCD=1 break - if self.HAS_BOOTCD: # check the version of the boot cd, and locate the certs @@ -116,29 +98,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 ): @@ -146,11 +133,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." ) @@ -246,11 +233,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 @@ -335,7 +326,6 @@ class BootServerRequest: if DoSSL: cmdline = cmdline + "--sslv%d " % self.CURL_SSL_VERSION - if DoCertCheck: cmdline = cmdline + "--cacert %s " % certpath diff --git a/source/configuration b/source/configuration index 152cc75..e21933a 100644 --- a/source/configuration +++ b/source/configuration @@ -6,10 +6,24 @@ # the current version of the bootmanager VERSION=3.2 - +# this is the server to contact if we don't have a bootcd +DEFAULT_BOOT_SERVER=boot.planet-lab.org # full url to which api server to contact BOOT_API_SERVER=https://boot.planet-lab.org:443/PLCAPI/ +# keep redundant information to plc_config for simplicity +BOOT_SERVER=boot.planet-lab.org + +# hostname for MyOps server +MONITOR_SERVER=monitor.planet-lab.org +#UPLOAD_LOG_SCRIPT=/monitor/upload +UPLOAD_LOG_SCRIPT=/boot/upload-bmlog.php + +# bootcd variables : use %(path)s for path relative to bootcd +BOOTCD_VERSION_FILE='%(path)s/bootme/ID' +SERVER_CERT_DIR=/tmp/source/cacert +CACERT_NAME=cacert.pem + # path to store temporary files during the install, # do not include trailing slashes @@ -80,3 +94,7 @@ INSTALL_LANGS=en_US # number of auth failures before starting debug mode NUM_AUTH_FAILURES_BEFORE_DEBUG=2 + + +# location of file containing http/https proxy info, if needed +PROXY_FILE=/etc/planetlab/http_proxy diff --git a/source/steps/InstallBootstrapFS.py b/source/steps/InstallBootstrapFS.py index 72cfe16..2c49acc 100644 --- a/source/steps/InstallBootstrapFS.py +++ b/source/steps/InstallBootstrapFS.py @@ -73,7 +73,7 @@ def Run( vars, log ): log.write( "Missing partition in PARTITIONS: %s\n" % part ) return 0 - bs_request= BootServerRequest.BootServerRequest() + bs_request= BootServerRequest.BootServerRequest(vars) log.write( "turning on swap space\n" ) utils.sysexec( "swapon %s" % PARTITIONS["swap"], log ) diff --git a/source/steps/InstallPartitionDisks.py b/source/steps/InstallPartitionDisks.py index 0e65270..5bafb9f 100644 --- a/source/steps/InstallPartitionDisks.py +++ b/source/steps/InstallPartitionDisks.py @@ -67,7 +67,7 @@ def Run( vars, log ): except ValueError, var: raise BootManagerException, "Variable in vars, shouldn't be: %s\n" % var - bs_request= BootServerRequest.BootServerRequest() + bs_request= BootServerRequest.BootServerRequest(vars) # disable swap if its on diff --git a/source/steps/ReadNodeConfiguration.py b/source/steps/ReadNodeConfiguration.py index caef8fe..e51e9b0 100644 --- a/source/steps/ReadNodeConfiguration.py +++ b/source/steps/ReadNodeConfiguration.py @@ -473,7 +473,7 @@ def __parse_configuration_file( vars, log, file_contents ): log.write( "Configuration file does not contain the node_id value.\n" ) log.write( "Querying PLC for node_id.\n" ) - bs_request= BootServerRequest.BootServerRequest() + bs_request= BootServerRequest.BootServerRequest(vars) postVars= {"mac_addr" : INTERFACE_SETTINGS["mac"]} result= bs_request.DownloadFile( "%s/getnodeid.php" % diff --git a/source/steps/WriteNetworkConfig.py b/source/steps/WriteNetworkConfig.py index 6c3b2b8..cef1f08 100644 --- a/source/steps/WriteNetworkConfig.py +++ b/source/steps/WriteNetworkConfig.py @@ -132,7 +132,7 @@ def Run( vars, log ): except : log.write(" .. Failed. Using old method. -- stack trace follows\n") traceback.print_exc(file=log.OutputFile) - bs= BootServerRequest.BootServerRequest() + bs= BootServerRequest.BootServerRequest(vars) if bs.BOOTSERVER_CERTS: print >> plc_config, "PLC_BOOT_HOST='%s'" % bs.BOOTSERVER_CERTS.keys()[0] print >> plc_config, "PLC_API_HOST='%s'" % host