X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=source%2FBootManager.py;h=c5e27f3f9114865c9c6e794b32fa8d845630f219;hb=27d9e3ef16bff9214074e88ce76eb686f53f3d81;hp=a118f662f28006e415e7cf0ba959b76f1b60c965;hpb=dc8d8c9e8ec6b53bacf62fd301bbf0b28e836e44;p=bootmanager.git diff --git a/source/BootManager.py b/source/BootManager.py index a118f66..c5e27f3 100755 --- a/source/BootManager.py +++ b/source/BootManager.py @@ -1,52 +1,10 @@ #!/usr/bin/python2 -u -# ------------------------------------------------------------------------ -# THIS file used to be named alpina.py, from the node installer. Since then -# the installer has been expanded to include all the functions of the boot -# manager as well, hence the new name for this file. -# ------------------------------------------------------------------------ - # 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 string import sys, os, traceback @@ -56,13 +14,11 @@ from gzip import GzipFile from steps import * from Exceptions import * import notify_messages - - +import BootServerRequest # all output is written to this file LOG_FILE= "/tmp/bm.log" -CURL_PATH= "curl" -UPLOAD_LOG_URL = "http://boot.planet-lab.org/alpina-logs/upload.php" +UPLOAD_LOG_PATH = "/alpina-logs/upload.php" # the new contents of PATH when the boot manager is running BIN_PATH= ('/usr/local/bin', @@ -74,6 +30,8 @@ BIN_PATH= ('/usr/local/bin', '/usr/local/planetlab/bin') +# the set of valid node run states +NodeRunStates = {} class log: @@ -119,15 +77,16 @@ class log: """ if self.OutputFile is not None: - self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_URL ) + self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_PATH ) self.OutputFile.close() self.OutputFile= None - - curl_cmd= "%s -s --connect-timeout 60 --max-time 600 " \ - "--form log=@%s %s" % \ - (CURL_PATH, self.OutputFilePath, UPLOAD_LOG_URL) - os.system( curl_cmd ) + + bs_request = BootServerRequest.BootServerRequest() + bs_request.MakeRequest(PartialPath = UPLOAD_LOG_PATH, + GetVars = None, PostVars = None, + FormData = ["log=@" + self.OutputFilePath], + DoSSL = True, DoCertCheck = True) @@ -140,10 +99,9 @@ class BootManager: VARS_FILE = "configuration" - def __init__(self, log): - # this contains a set of information used and updated - # by each step - self.VARS= {} + def __init__(self, log, forceState): + # override machine's current state from the command line + self.forceState = forceState # the main logging point self.LOG= log @@ -151,33 +109,13 @@ class BootManager: # set to 1 if we can run after initialization self.CAN_RUN = 0 - if not self.ReadBMConf(): - 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() - self.VARS['BM_SOURCE_DIR']= current_dir - - # 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,":") - - self.CAN_RUN= 1 - - def ReadBMConf(self): - """ - read in and store all variables in VARS_FILE into - self.VARS - - 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 - """ - + # 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) == "": @@ -186,15 +124,34 @@ class BootManager: parts= string.split(line,"=") if len(parts) != 2: self.LOG.LogEntry( "Invalid line in vars file: %s" % line ) - return 0 + 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 - self.VARS[name]= value + # 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 + + # 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 - return 1 - def Run(self): """ core boot manager logic. @@ -222,7 +179,27 @@ class BootManager: self.VARS['STATE_CHANGE_NOTIFY']= 1 self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \ notify_messages.MSG_NODE_NOT_INSTALLED - UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) + raise BootManagerException, \ + notify_messages.MSG_NODE_NOT_INSTALLED + + def _bootRun(): + # implements the boot logic, which consists of first + # double checking that the node was properly installed, + # checking whether someone added or changed disks, and + # then finally chain boots. + + InstallInit.Run( self.VARS, self.LOG ) + if ValidateNodeInstall.Run( self.VARS, self.LOG ): + WriteModprobeConfig.Run( self.VARS, self.LOG ) + MakeInitrd.Run( self.VARS, self.LOG ) + WriteNetworkConfig.Run( self.VARS, self.LOG ) + # the following step should be done by NM + UpdateNodeConfiguration.Run( self.VARS, self.LOG ) + CheckForNewDisks.Run( self.VARS, self.LOG ) + SendHardwareConfigToPLC.Run( self.VARS, self.LOG ) + ChainBootNode.Run( self.VARS, self.LOG ) + else: + _nodeNotInstalled() def _rinsRun(): # implements the reinstall logic, which will check whether @@ -231,17 +208,22 @@ class BootManager: # 'boot' state and chainboot into the production system if not CheckHardwareRequirements.Run( self.VARS, self.LOG ): self.VARS['BOOT_STATE']= 'dbg' - UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) raise BootManagerException, "Hardware requirements not met." - self.RunInstaller() - - if ValidateNodeInstall.Run( self.VARS, self.LOG ): - SendHardwareConfigToPLC.Run( self.VARS, self.LOG ) - ChainBootNode.Run( self.VARS, self.LOG ) - else: - self._nodeNotInstalled() - + # runinstaller + InstallInit.Run( self.VARS, self.LOG ) + InstallPartitionDisks.Run( self.VARS, self.LOG ) + InstallBootstrapRPM.Run( self.VARS, self.LOG ) + InstallWriteConfig.Run( self.VARS, self.LOG ) + InstallBuildVServer.Run( self.VARS, self.LOG ) + InstallUninitHardware.Run( self.VARS, self.LOG ) + self.VARS['BOOT_STATE']= 'boot' + self.VARS['STATE_CHANGE_NOTIFY']= 1 + self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \ + notify_messages.MSG_INSTALL_FINISHED + UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) + _bootRun() + def _newRun(): # implements the new install logic, which will first check # with the user whether it is ok to install on this @@ -252,89 +234,76 @@ class BootManager: return 0 self.VARS['BOOT_STATE']= 'rins' UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) - self._rins() - - def _bootRun(): - # implements the boot logic, which consists of first - # double checking that the node was properly installed, - # checking whether someone added or changed disks, and - # then finally chain boots. - - if ValidateNodeInstall.Run( self.VARS, self.LOG ): - UpdateNodeConfiguration.Run( self.VARS, self.LOG ) - CheckForNewDisks.Run( self.VARS, self.LOG ) - SendHardwareConfigToPLC.Run( self.VARS, self.LOG ) - ChainBootNode.Run( self.VARS, self.LOG ) - else: - self._nodeNotInstalled() - + _rinsRun() def _debugRun(): # implements debug logic, which just starts the sshd # and just waits around + self.VARS['BOOT_STATE']='dbg' + UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) StartDebug.Run( self.VARS, self.LOG ) def _badRun(): # should never happen; log event self.LOG.write( "\nInvalid BOOT_STATE = %s\n" % self.VARS['BOOT_STATE']) - self.VARS['BOOT_STATE']= 'dbg' - UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) - StartDebug.Run( self.VARS, self.LOG ) + _debugRun() + global NodeRunStates # setup state -> function hash table - states = {'new':_newRun, - 'inst':_newRun, - 'rins':_rinsRun, - 'boot':_bootRun, - 'dbg':_debugRun} + NodeRunStates['new'] = _newRun + NodeRunStates['inst'] = _newRun + NodeRunStates['rins'] = _rinsRun + NodeRunStates['boot'] = _bootRun + NodeRunStates['dbg'] = _debugRun + + success = 0 try: InitializeBootManager.Run( self.VARS, self.LOG ) ReadNodeConfiguration.Run( self.VARS, self.LOG ) AuthenticateWithPLC.Run( self.VARS, self.LOG ) GetAndUpdateNodeDetails.Run( self.VARS, self.LOG ) - stateRun = states.get(self.VARS['BOOT_STATE'],_badRun) + # override machine's current state from the command line + if self.forceState is not None: + self.VARS['BOOT_STATE']= self.forceState + UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) + + stateRun = NodeRunStates.get(self.VARS['BOOT_STATE'],_badRun) stateRun() + success = 1 except KeyError, e: self.LOG.write( "\n\nKeyError while running: %s\n" % str(e) ) except BootManagerException, e: self.LOG.write( "\n\nException while running: %s\n" % str(e) ) - - return 1 - + except: + self.LOG.write( "\n\nImplementation Error\n") + traceback.print_exc(file=self.LOG.OutputFile) + traceback.print_exc() - - def RunInstaller(self): - """ - since the installer can be invoked at more than one place - in the boot manager logic, seperate the steps necessary - to do it here - """ - - InstallInit.Run( self.VARS, self.LOG ) - InstallPartitionDisks.Run( self.VARS, self.LOG ) - InstallBootstrapRPM.Run( self.VARS, self.LOG ) - InstallBase.Run( self.VARS, self.LOG ) - InstallWriteConfig.Run( self.VARS, self.LOG ) - InstallBuildVServer.Run( self.VARS, self.LOG ) - InstallNodeInit.Run( self.VARS, self.LOG ) - InstallUninitHardware.Run( self.VARS, self.LOG ) - - self.VARS['BOOT_STATE']= 'boot' - self.VARS['STATE_CHANGE_NOTIFY']= 1 - self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \ - notify_messages.MSG_INSTALL_FINISHED - UpdateBootStateWithPLC.Run( self.VARS, self.LOG ) - - SendHardwareConfigToPLC.Run( self.VARS, self.LOG ) - - - -if __name__ == "__main__": + if not success: + try: + _debugRun() + except BootManagerException, e: + self.LOG.write( "\n\nException while running: %s\n" % str(e) ) + except: + self.LOG.write( "\n\nImplementation Error\n") + traceback.print_exc(file=self.LOG.OutputFile) + traceback.print_exc() - # set to 0 if no error occurred - error= 1 + return success + + +def main(argv): + global NodeRunStates + NodeRunStates = {'new':None, + 'inst':None, + 'rins':None, + 'boot':None, + 'dbg':None} + + # set to 1 if error occurred + error= 0 # all output goes through this class so we can save it and post # the data back to PlanetLab central @@ -344,7 +313,26 @@ if __name__ == "__main__": strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) ) try: - bm= BootManager(LOG) + forceState = None + if len(argv) == 2: + fState = argv[1] + if NodeRunStates.has_key(fState): + forceState = fState + else: + LOG.LogEntry("FATAL: cannot force node run state to=%s" % fState) + error = 1 + except: + traceback.print_exc(file=LOG.OutputFile) + traceback.print_exc() + + if error: + LOG.LogEntry( "BootManager finished at: %s" % \ + strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) ) + LOG.Upload() + return error + + try: + bm= BootManager(LOG,forceState) if bm.CAN_RUN == 0: LOG.LogEntry( "Unable to initialize BootManager." ) else: @@ -355,14 +343,18 @@ if __name__ == "__main__": LOG.LogEntry( "\nDone!" ); else: LOG.LogEntry( "\nError occurred!" ); - + error = 1 except: traceback.print_exc(file=LOG.OutputFile) traceback.print_exc() LOG.LogEntry( "BootManager finished at: %s" % \ strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) ) - LOG.Upload() + + return error + +if __name__ == "__main__": + error = main(sys.argv) sys.exit(error)