Setting tag nodeupdate-0.5-8
[nodeupdate.git] / NodeUpdate.py
index b0cd6d8..c6be451 100644 (file)
@@ -3,6 +3,10 @@
 import sys, os
 from random import Random
 import string
+from types import StringTypes
+
+from time import strftime
+TIMEFORMAT="%Y-%m-%d %H:%M:%S"
 
 NODEUPDATE_PID_FILE= "/var/run/NodeUpdate.pid"
 
@@ -19,7 +23,6 @@ RPM_PATH = "/bin/rpm"
 
 RPM_GPG_PATH = "/etc/pki/rpm-gpg"
 
-
 # location of file containing http/https proxy info, if needed
 PROXY_FILE = '/etc/planetlab/http_proxy'
 
@@ -31,25 +34,41 @@ REBOOT_FLAG = '/etc/planetlab/update-reboot'
 # location of directory containing boot server ssl certs
 SSL_CERT_DIR='/mnt/cdrom/bootme/cacert/'
 
-# file containing list of extra groups to attempt to update,
-# if necessary.
-EXTRA_GROUPS_FILE= '/etc/planetlab/extra-node-groups'
+# file containing the list of extensions this node has, each
+# correspond to a package group in yum repository.
+# this is expected to be updated from the 'extensions tag' 
+# through the 'extensions.php' nodeconfig script
+EXTENSIONS_FILE='/etc/planetlab/extensions'
 
 # file containing a list of rpms that we should attempt to delete
-# before we updating everything else. this list is not
-# removed with 'yum remove', because that could accidently remove
-# dependency rpms that were not intended to be deleted.
+# before updating everything else. This list is not removed with 
+# 'yum remove', because that could accidently remove dependency rpms
+# that were not intended to be deleted.
 DELETE_RPM_LIST_FILE= '/etc/planetlab/delete-rpm-list'
 
+# ok, so the logic should be simple, just yum update the world
+# however there are many cases in the real life where this 
+# just does not work, because of a glitch somewhere
+# so, we force the update of crucial pkgs independently, as 
+# the whole group is sometimes too much to swallow 
+# this one is builtin
+UPDATE_PACKAGES_BUILTIN=[ 'NodeManager' ]
+# and operations can also try to push a list through a conf_file
+UPDATE_PACKAGES_OPTIONAL_PATH='/etc/planetlab/NodeUpdate.packages'
+
 
 # print out a message only if we are displaying output
-def Message(Str):
+def Message(message):
     if displayOutput:
-        print Str
+        if isinstance(message,StringTypes) and len(message) >=2 and message[0]=="\n":
+            print "\n",
+            message=message[1:]
+        print strftime(TIMEFORMAT),
+        print message
 
-
-# print out a message only if we are displaying output
+# always print errors
 def Error(Str):
+    print strftime(TIMEFORMAT),
     print Str
 
 
@@ -64,6 +83,7 @@ def UpdateCronFile():
         
         f = open( CRON_FILE, 'w' );
         f.write( "# %s\n" % (TARGET_DESC) );
+        ### xxx is root aliased to the support mailing list ?
         f.write( "MAILTO=%s\n" % (TARGET_USER) );
         f.write( "SHELL=%s\n" % (TARGET_SHELL) );
         f.write( "%s %s,%s * * * %s %s\n\n" %
@@ -97,7 +117,7 @@ class NodeUpdate:
     
 
     def CheckProxy( self ):
-        Message( "Checking existance of proxy config file..." )
+        Message( "Checking existence of proxy config file..." )
         
         if os.access(PROXY_FILE, os.R_OK) and os.path.isfile(PROXY_FILE):
             self.HTTP_PROXY= string.strip(file(PROXY_FILE,'r').readline())
@@ -130,34 +150,57 @@ class NodeUpdate:
 
         Message( "\nChecking if yum supports SSL certificate checks" )
         if os.system( "%s --help | grep -q sslcertdir" % YUM_PATH ) == 0:
-            Message( "Yes, using --sslcertdir option" )
+            Message( "It does, using --sslcertdir option" )
             sslcertdir = "--sslcertdir=" + SSL_CERT_DIR
         else:
-            Message( "No, not using --sslcertdir option" )
+            Message( "Unsupported, not using --sslcertdir option" )
             sslcertdir = ""
                     
+        yum_options=""
+        Message( "\nChecking if yum supports --verbose" )
+        if os.system( "%s --help | grep -q verbose" % YUM_PATH ) == 0:
+            Message( "It does, using --verbose option" )
+            yum_options += " --verbose"
+        else:
+            Message( "Unsupported, not using --verbose option" )
+        
+        # a configurable list of packages to try and update independently
+        # cautious..
+        try:
+            crucial_packages = []
+            for package in UPDATE_PACKAGES_BUILTIN: crucial_packages.append(package)
+            try: crucial_packages += file(UPDATE_PACKAGES_OPTIONAL_PATH).read().split()
+            except: pass
+            for package in crucial_packages:
+                Message( "\nUpdating crucial package %s" % package)
+                os.system( "%s %s -y update %s" %(YUM_PATH, yum_options, package))
+        except:
+            pass
+
         Message( "\nUpdating PlanetLab group" )
-        os.system( "%s %s -y groupupdate \"PlanetLab\"" %
-                   (YUM_PATH, sslcertdir) )
+        os.system( "%s %s %s -y groupinstall \"PlanetLab\"" %
+                   (YUM_PATH, yum_options, sslcertdir) )
 
         Message( "\nUpdating rest of system" )
-        os.system( "%s %s -y update" %
-                   (YUM_PATH, sslcertdir) )
-
-        Message( "\nChecking for extra groups to update" )
-        if os.access(EXTRA_GROUPS_FILE, os.R_OK) and \
-           os.path.isfile(EXTRA_GROUPS_FILE):
-            extra_groups_contents= file(EXTRA_GROUPS_FILE).read()
-            extra_groups_contents= string.strip(extra_groups_contents)
-            if extra_groups_contents == "":
+        os.system( "%s %s %s -y update" %
+                   (YUM_PATH, yum_options, sslcertdir) )
+
+        Message( "\nChecking for extra groups (extensions) to update" )
+        if os.access(EXTENSIONS_FILE, os.R_OK) and \
+           os.path.isfile(EXTENSIONS_FILE):
+            extensions_contents= file(EXTENSIONS_FILE).read()
+            extensions_contents= string.strip(extensions_contents)
+            if extensions_contents == "":
                 Message( "No extra groups found in file." )
             else:
-                for group in string.split(extra_groups_contents,"\n"):
+                extensions_contents.strip()
+                for extension in extensions_contents.split():
+                    group = "extension%s" % extension
                     Message( "\nUpdating %s group" % group )
-                    os.system( "%s %s -y groupupdate \"%s\"" %
-                               (YUM_PATH, sslcertdir, group) )
+                    os.system( "%s %s %s -y groupinstall \"%s\"" %
+                               (YUM_PATH, yum_options, sslcertdir, group) )
         else:
-            Message( "No extra groups file found" )
+            Message( "No extensions file found" )
             
         if os.access(REBOOT_FLAG, os.R_OK) and os.path.isfile(REBOOT_FLAG) and self.doReboot:
             Message( "\nAt least one update requested the system be rebooted" )
@@ -171,6 +214,13 @@ class NodeUpdate:
         try: os.system( "%s --rebuilddb" % RPM_PATH )
         except Exception, err: print "RebuildRPMdb: %s" % err
 
+    def YumCleanAll ( self ):
+        Message ("\nCleaning all yum cache (yum clean all)")
+        try:
+            os.system( "yum clean all")
+        except:
+            pass
+
     def RemoveRPMS( self ):
 
         Message( "\nLooking for RPMs to be deleted." )
@@ -202,9 +252,10 @@ class NodeUpdate:
 
 if __name__ == "__main__":
 
-    # if we are invoked with 'start', display the output. this
-    # is usefull for running something under cron and as a service
-    # (at startup), so the cron only outputs errors and doesn't
+    # if we are invoked with 'start', display the output. 
+    # this is useful for running something silently 
+    # under cron and as a service (at startup), 
+    # so the cron only outputs errors and doesn't
     # generate mail when it works correctly
 
     displayOutput= 0
@@ -215,8 +266,9 @@ if __name__ == "__main__":
     
     doReboot= 1
 
-    if "start" in sys.argv:
+    if "start" in sys.argv or "display" in sys.argv:
         displayOutput= 1
+        Message ("\nTurning on messages")
 
     if "noreboot" in sys.argv:
         doReboot= 0
@@ -256,6 +308,7 @@ if __name__ == "__main__":
         nodeupdate.RebuildRPMdb()
         nodeupdate.RemoveRPMS()
         nodeupdate.InstallKeys()
+        nodeupdate.YumCleanAll()
         nodeupdate.CheckForUpdates()
         Message( "\nUpdate complete." )