Fix for adding new disks to system:
[bootmanager.git] / source / BootManager.py
index 478c714..5519af4 100755 (executable)
@@ -56,13 +56,13 @@ from gzip import GzipFile
 from steps import *
 from Exceptions import *
 import notify_messages
 from steps import *
 from Exceptions import *
 import notify_messages
+import BootServerRequest
 
 
 
 # all output is written to this file
 LOG_FILE= "/tmp/bm.log"
 
 
 
 # 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',
 
 # the new contents of PATH when the boot manager is running
 BIN_PATH= ('/usr/local/bin',
@@ -74,6 +74,8 @@ BIN_PATH= ('/usr/local/bin',
            '/usr/local/planetlab/bin')
            
 
            '/usr/local/planetlab/bin')
            
 
+# the set of valid node run states
+NodeRunStates = {}
 
 class log:
 
 
 class log:
 
@@ -86,9 +88,6 @@ class log:
                 print( "Unable to open output file for log, continuing" )
                 self.OutputFile= None
 
                 print( "Unable to open output file for log, continuing" )
                 self.OutputFile= None
 
-        # for upload
-        os.system( "ifconfig eth0 > /tmp/ifconfig" )
-
     
     def LogEntry( self, str, inc_newline= 1, display_screen= 1 ):
         if self.OutputFile:
     
     def LogEntry( self, str, inc_newline= 1, display_screen= 1 ):
         if self.OutputFile:
@@ -120,16 +119,18 @@ class log:
         """
         upload the contents of the log to the server
         """
         """
         upload the contents of the log to the server
         """
-    
-        self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_URL )
-        
-        self.OutputFile.close()
-        self.OutputFile= None
-                
-        curl_cmd= "%s -s --connect-timeout 60 --max-time 600 " \
-                  "--form log=@%s --form ifconfig=\</tmp/ifconfig %s" % \
-                  (CURL_PATH, self.OutputFilePath, UPLOAD_LOG_URL)
-        os.system( curl_cmd )
+
+        if self.OutputFile is not None:
+            self.LogEntry( "Uploading logs to %s" % UPLOAD_LOG_PATH )
+            
+            self.OutputFile.close()
+            self.OutputFile= None
+
+            bs_request = BootServerRequest.BootServerRequest()
+            bs_request.MakeRequest(PartialPath = UPLOAD_LOG_PATH,
+                                   GetVars = None, PostVars = None,
+                                   FormData = ["log=@" + self.OutputFilePath],
+                                   DoSSL = True, DoCertCheck = True)
         
     
 
         
     
 
@@ -142,7 +143,10 @@ class BootManager:
     VARS_FILE = "configuration"
 
     
     VARS_FILE = "configuration"
 
     
-    def __init__(self, log):
+    def __init__(self, log, forceState):
+        # override machine's current state from the command line
+        self.forceState = forceState
+
         # this contains a set of information used and updated
         # by each step
         self.VARS= {}
         # this contains a set of information used and updated
         # by each step
         self.VARS= {}
@@ -168,9 +172,6 @@ class BootManager:
         os.environ['PATH']= string.join(BIN_PATH,":")
                    
         self.CAN_RUN= 1
         os.environ['PATH']= string.join(BIN_PATH,":")
                    
         self.CAN_RUN= 1
-        
-
-
 
     def ReadBMConf(self):
         """
 
     def ReadBMConf(self):
         """
@@ -200,7 +201,6 @@ class BootManager:
 
         return 1
     
 
         return 1
     
-
     def Run(self):
         """
         core boot manager logic.
     def Run(self):
         """
         core boot manager logic.
@@ -221,72 +221,93 @@ class BootManager:
         For exact return values and expected operations, see the comments
         at the top of each of the invididual step functions.
         """
         For exact return values and expected operations, see the comments
         at the top of each of the invididual step functions.
         """
-        
+
+        def _nodeNotInstalled():
+            # called by the _xxxState() functions below upon failure
+            self.VARS['BOOT_STATE']= 'dbg'
+            self.VARS['STATE_CHANGE_NOTIFY']= 1
+            self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
+                      notify_messages.MSG_NODE_NOT_INSTALLED
+            UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+
+        def _rinsRun():
+            # implements the reinstall logic, which will check whether
+            # the min. hardware requirements are met, install the
+            # software, and upon correct installation will switch too
+            # '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:
+                _nodeNotInstalled()
+
+        def _newRun():
+            # implements the new install logic, which will first check
+            # with the user whether it is ok to install on this
+            # machine, switch to 'rins' state and then invoke the rins
+            # logic.  See rinsState logic comments for further
+            # details.
+            if not ConfirmInstallWithUser.Run( self.VARS, self.LOG ):
+                return 0
+            self.VARS['BOOT_STATE']= 'rins'
+            UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
+            _rinsRun()
+
+        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:
+                _nodeNotInstalled()
+
+
+        def _debugRun():
+            # implements debug logic, which just starts the sshd
+            # and just waits around
+            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 )            
+
+        global NodeRunStates
+        # setup state -> function hash table
+        NodeRunStates['new']  = _newRun
+        NodeRunStates['inst'] = _newRun
+        NodeRunStates['rins'] = _rinsRun
+        NodeRunStates['boot'] = _bootRun
+        NodeRunStates['dbg']  = _debugRun
+
         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 )
         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 )
-            
-            if self.VARS['BOOT_STATE'] == 'new' or \
-                   self.VARS['BOOT_STATE'] == 'inst':
-                if not ConfirmInstallWithUser.Run( self.VARS, self.LOG ):
-                    return 0
-                
-                self.VARS['BOOT_STATE']= 'rins'
+
+            # 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 )
                 UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
-            
-                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.VARS['BOOT_STATE']= 'dbg'
-                    self.VARS['STATE_CHANGE_NOTIFY']= 1
-                    self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
-                              notify_messages.MSG_NODE_NOT_INSTALLED
-                    UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
-                    
-
-            elif self.VARS['BOOT_STATE'] == 'rins':
-                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.VARS['BOOT_STATE']= 'dbg'
-                    self.VARS['STATE_CHANGE_NOTIFY']= 1
-                    self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
-                              notify_messages.MSG_NODE_NOT_INSTALLED
-                    UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
-
-            elif self.VARS['BOOT_STATE'] == 'boot':
-                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.VARS['BOOT_STATE']= 'dbg'
-                    self.VARS['STATE_CHANGE_NOTIFY']= 1
-                    self.VARS['STATE_CHANGE_NOTIFY_MESSAGE']= \
-                              notify_messages.MSG_NODE_NOT_INSTALLED
-                    UpdateBootStateWithPLC.Run( self.VARS, self.LOG )
-                    
-            elif self.VARS['BOOT_STATE'] == 'dbg':
-                StartDebug.Run( self.VARS, self.LOG )
+
+            stateRun = NodeRunStates.get(self.VARS['BOOT_STATE'],_badRun)
+            stateRun()
 
         except KeyError, e:
             self.LOG.write( "\n\nKeyError while running: %s\n" % str(e) )
 
         except KeyError, e:
             self.LOG.write( "\n\nKeyError while running: %s\n" % str(e) )
@@ -307,7 +328,6 @@ class BootManager:
         InstallInit.Run( self.VARS, self.LOG )                    
         InstallPartitionDisks.Run( self.VARS, self.LOG )            
         InstallBootstrapRPM.Run( self.VARS, self.LOG )            
         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 )
         InstallWriteConfig.Run( self.VARS, self.LOG )
         InstallBuildVServer.Run( self.VARS, self.LOG )
         InstallNodeInit.Run( self.VARS, self.LOG )
@@ -322,11 +342,16 @@ class BootManager:
         SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
 
     
         SendHardwareConfigToPLC.Run( self.VARS, self.LOG )
 
     
-    
-if __name__ == "__main__":
-
-    # set to 0 if no error occurred
-    error= 1
+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
     
     # all output goes through this class so we can save it and post
     # the data back to PlanetLab central
@@ -336,7 +361,26 @@ if __name__ == "__main__":
                   strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) )
 
     try:
                   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:
         if bm.CAN_RUN == 0:
             LOG.LogEntry( "Unable to initialize BootManager." )
         else:
@@ -347,14 +391,18 @@ if __name__ == "__main__":
                 LOG.LogEntry( "\nDone!" );
             else:
                 LOG.LogEntry( "\nError occurred!" );
                 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()) )
     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()
     LOG.Upload()
+
+    return error
+
     
     
+if __name__ == "__main__":
+    error = main(sys.argv)
     sys.exit(error)
     sys.exit(error)