X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=source%2Futils.py;h=3c6c2251ad9066f48efed6390e2e3ebe56d2f45f;hb=819a7ca00b618108c382140e62395fb20b894607;hp=e3c966e34b6facfa56f596517720e8c51a82351c;hpb=4eb121c4478448b571786761325aea4d762f7f27;p=bootmanager.git diff --git a/source/utils.py b/source/utils.py index e3c966e..3c6c225 100644 --- a/source/utils.py +++ b/source/utils.py @@ -1,5 +1,5 @@ -#!/usr/bin/python2 - +#!/usr/bin/python +# # Copyright (c) 2003 Intel Corporation # All rights reserved. # @@ -8,7 +8,8 @@ # expected /proc/partitions format import os, sys, shutil -import popen2 +import subprocess +import shlex import socket import fcntl import string @@ -16,7 +17,69 @@ import exceptions from Exceptions import * +#################### +# the simplest way to debug is to let the node take off, +# ssh into it as root using the debug ssh key in /etc/planetlab +# then go to /tmp/source +# edit this file locally to turn on breakpoints if needed, then run +# ./BootManager.py +#################### + +### handling breakpoints in the startup process +import select, sys, string + +### global debugging settings + +# enabling this will cause the node to ask for breakpoint-mode at startup +# production code should read False/False +PROMPT_MODE=False +# default for when prompt is turned off, or it's on but the timeout triggers +BREAKPOINT_MODE=False + +# verbose mode is just fine +VERBOSE_MODE=True +# in seconds : if no input, proceed +PROMPT_TIMEOUT=5 + +def prompt_for_breakpoint_mode (): + global BREAKPOINT_MODE + if PROMPT_MODE: + default_answer=BREAKPOINT_MODE + answer='' + if BREAKPOINT_MODE: + display="[y]/n" + else: + display="y/[n]" + sys.stdout.write ("Want to run in breakpoint mode ? %s "%display) + sys.stdout.flush() + r,w,e = select.select ([sys.stdin],[],[],PROMPT_TIMEOUT) + if r: + answer = string.strip(sys.stdin.readline()) + else: + sys.stdout.write("\nTimed-out (%d s)"%PROMPT_TIMEOUT) + if answer: + BREAKPOINT_MODE = ( answer == "y" or answer == "Y") + else: + BREAKPOINT_MODE = default_answer + label="Off" + if BREAKPOINT_MODE: + label="On" + sys.stdout.write("\nCurrent BREAKPOINT_MODE is %s\n"%label) + +def breakpoint (message, cmd = None): + + if BREAKPOINT_MODE: + + if cmd is None: + cmd="/bin/sh" + message=message+" -- Entering bash - type ^D to proceed" + + print message + os.system(cmd) + + +######################################## def makedirs( path ): """ from python docs for os.makedirs: @@ -60,8 +123,7 @@ def removedir( path ): return 1 - -def sysexec( cmd, log= None ): +def sysexec( cmd, log=None, fsck=False, shell=False ): """ execute a system command, output the results to the logger if log <> None @@ -70,36 +132,96 @@ def sysexec( cmd, log= None ): 0 if failed. A BootManagerException is raised if the command was unable to execute or was interrupted by the user with Ctrl+C """ - if BREAKPOINT_MODE: - print ("sysexec >>> %s" % cmd) - prog= popen2.Popen4( cmd, 0 ) - if prog is None: + try: + # Thierry - Jan. 6 2011 + # would probably make sense to look for | here as well + # however this is fragile and hard to test thoroughly + # let the caller set 'shell' when that is desirable + if shell or cmd.__contains__(">"): + prog = subprocess.Popen(cmd, shell=True) + if log is not None: + log.write("sysexec (shell mode) >>> %s" % cmd) + if VERBOSE_MODE: + print "sysexec (shell mode) >>> %s" % cmd + else: + prog = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if log is not None: + log.write("sysexec >>> %s\n" % cmd) + if VERBOSE_MODE: + print "sysexec >>> %s" % cmd + except OSError: raise BootManagerException, \ - "Unable to create instance of popen2.Popen4 " \ + "Unable to create instance of subprocess.Popen " \ "for command: %s" % cmd + try: + (stdoutdata, stderrdata) = prog.communicate() + except KeyboardInterrupt: + raise BootManagerException, "Interrupted by user" + # log stdout & stderr if log is not None: - try: - for line in prog.fromchild: - log.write( line ) - except KeyboardInterrupt: - raise BootManagerException, "Interrupted by user" + if stdoutdata: + log.write("==========stdout\n"+stdoutdata) + if stderrdata: + log.write("==========stderr\n"+stderrdata) + + returncode = prog.wait() + + if fsck: + # The exit code returned by fsck is the sum of the following conditions: + # 0 - No errors + # 1 - File system errors corrected + # 2 - System should be rebooted + # 4 - File system errors left uncorrected + # 8 - Operational error + # 16 - Usage or syntax error + # 32 - Fsck canceled by user request + # 128 - Shared library error + if returncode != 0 and returncode != 1: + raise BootManagerException, "Running %s failed (rc=%d)" % (cmd,returncode) + else: + if returncode != 0: + raise BootManagerException, "Running %s failed (rc=%d)" % (cmd,returncode) + + prog = None + return 1 - returncode= prog.wait() - if returncode != 0: - raise BootManagerException, "Running %s failed (rc=%d)" % (cmd,returncode) - prog= None - return 1 +def sysexec_chroot( path, cmd, log=None, shell=False): + """ + same as sysexec, but inside a chroot + """ + preload = "" + release = os.uname()[2] + # 2.6.12 kernels need this + if release[:5] == "2.6.1": + library = "%s/lib/libc-opendir-hack.so" % path + if not os.path.exists(library): + shutil.copy("./libc-opendir-hack.so", library) + preload = "/bin/env LD_PRELOAD=/lib/libc-opendir-hack.so" + sysexec("chroot %s %s %s" % (path, preload, cmd), log, shell=shell) + + +def sysexec_chroot_noerr( path, cmd, log=None, shell=False ): + """ + same as sysexec_chroot, but capture boot manager exceptions + """ + try: + rc= 0 + rc= sysexec_chroot( cmd, log, shell=shell ) + except BootManagerException, e: + pass + + return rc -def sysexec_noerr( cmd, log= None ): +def sysexec_noerr( cmd, log=None, shell=False ): """ same as sysexec, but capture boot manager exceptions """ try: rc= 0 - rc= sysexec( cmd, log ) + rc= sysexec( cmd, log, shell=shell ) except BootManagerException, e: pass @@ -160,54 +282,33 @@ def get_mac_from_interface(ifname): return ret -### handling breakpoints in the startup process -import select, sys, string - -### global debug settings -# NOTE. when BREAKPOINT_MODE turns out enabled, -# you have to attend the boot phase, that would hang otherwise - -# enabling this will cause the node to ask for breakpoint-mode at startup -# production code should read False/False -PROMPT_MODE=True -# default for when prompt is turned off, or it's on but the timeout triggers -BREAKPOINT_MODE=True -# in seconds : if no input, proceed -PROMPT_TIMEOUT=5 - -def prompt_for_breakpoint_mode (): - - global BREAKPOINT_MODE - if PROMPT_MODE: - default_answer=BREAKPOINT_MODE - answer='' - if BREAKPOINT_MODE: - display="[y]/n" - else: - display="y/[n]" - sys.stdout.write ("Want to run in breakpoint mode ? %s "%display) - sys.stdout.flush() - r,w,e = select.select ([sys.stdin],[],[],PROMPT_TIMEOUT) - if r: - answer = string.strip(sys.stdin.readline()) - else: - sys.stdout.write("\nTimed-out (%d s)"%PROMPT_TIMEOUT) - if answer: - BREAKPOINT_MODE = ( answer == "y" or answer == "Y") - else: - BREAKPOINT_MODE = default_answer - label="Off" - if BREAKPOINT_MODE: - label="On" - sys.stdout.write("\nCurrent BREAKPOINT_MODE is %s\n"%label) - -def breakpoint (message, cmd = None): - - if BREAKPOINT_MODE: - - if cmd is None: - cmd="/bin/sh" - message=message+" -- Entering bash - type ^D to proceed" +def check_file_hash(filename, hash_filename): + """Check the file's integrity with a given hash.""" + return sha1_file(filename) == open(hash_filename).read().split()[0].strip() - print message - os.system(cmd) +def sha1_file(filename): + """Calculate sha1 hash of file.""" + try: + try: + import hashlib + m = hashlib.sha1() + except: + import sha + m=sha.new() + f = file(filename, 'rb') + while True: + # 256 KB seems ideal for speed/memory tradeoff + # It wont get much faster with bigger blocks, but + # heap peak grows + block = f.read(256 * 1024) + if len(block) == 0: + # end of file + break + m.update(block) + # Simple trick to keep total heap even lower + # Delete the previous block, so while next one is read + # we wont have two allocated blocks with same size + del block + return m.hexdigest() + except IOError: + raise BootManagerException, "Cannot calculate SHA1 hash of %s" % filename