- MyPLC 0.4 RC2
[bootmanager.git] / source / BootManager.py
index fdda2a3..5519af4 100755 (executable)
@@ -56,13 +56,13 @@ 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 +74,8 @@ BIN_PATH= ('/usr/local/bin',
            '/usr/local/planetlab/bin')
            
 
+# the set of valid node run states
+NodeRunStates = {}
 
 class log:
 
@@ -119,15 +121,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,7 +143,10 @@ class BootManager:
     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= {}
@@ -166,9 +172,6 @@ class BootManager:
         os.environ['PATH']= string.join(BIN_PATH,":")
                    
         self.CAN_RUN= 1
-        
-
-
 
     def ReadBMConf(self):
         """
@@ -198,7 +201,6 @@ class BootManager:
 
         return 1
     
-
     def Run(self):
         """
         core boot manager logic.
@@ -219,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.
         """
-        
+
+        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 )
-            
-            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 )
-            
-                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) )
@@ -305,7 +328,6 @@ class BootManager:
         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 )
@@ -320,11 +342,16 @@ class BootManager:
         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
@@ -334,7 +361,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:
@@ -345,14 +391,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)