[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] pygrub: add syslog support to pygrub



# HG changeset patch
# User Zhigang Wang <zhigang.x.wang@xxxxxxxxxx>
# Date 1342720736 14400
# Node ID ec9655b30a5fa5b5abb3e05505f681f9be559613
# Parent  43e21ce7f22151524b800a6cf0ac4ba1233b34a7
pygrub: add syslog support to pygrub

Currently, when pygrub failed, we don't know the reason because xend/xl will
not capture the stderr message.

This patch will log the error message to syslog.

We choosing syslog because pygrub could be called concurrently. If we want
dedicated log file for pygrub, we need a log server. Using syslog is simple.

Example /var/log/messages log:

  Jul 19 11:59:53 ovs030 [2012-07-19 11:59:53,504 7112] ERROR (pygrub:848) 
[Errno 95] Operation not supported Traceback (most recent call last):   File 
"/share/repos/xen-unstable/tools/pygrub/src/pygrub", line 828, in ?     fs = 
fsimage.open(file, offset, bootfsoptions) IOError: [Errno 95] Operation not 
supported
  Jul 19 11:59:53 ovs030 [2012-07-19 11:59:53,508 7112] ERROR (pygrub:892) 
Unable to find partition containing kernel

'7112' is the pygrub PID, so we can distinguish each process.

Also in this patch:

1). Fix indentation for some lines.
2). Removed some trailing spaces.
3). Mark 'isconfig' a duplicate option of 'debug' and remove the currently 
broken code:

      if isconfig:
          chosencfg = run_grub(file, entry, fs, incfg["args"])

    'fs' is not defined yet here, so it will raise an exception.

Signed-off-by: Zhigang Wang <zhigang.x.wang@xxxxxxxxxx>

diff -r 43e21ce7f221 -r ec9655b30a5f tools/pygrub/src/pygrub
--- a/tools/pygrub/src/pygrub   Tue Jul 17 17:33:31 2012 +0100
+++ b/tools/pygrub/src/pygrub   Thu Jul 19 13:58:56 2012 -0400
@@ -13,9 +13,10 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
-import os, sys, string, struct, tempfile, re, traceback
+import os, sys, string, struct, tempfile, re
 import copy
 import logging
+import logging.handlers
 import platform
 import xen.lowlevel.xc
 
@@ -35,7 +36,7 @@ def enable_cursor(ison):
         val = 2
     else:
         val = 0
-        
+
     try:
         curses.curs_set(val)
     except _curses.error:
@@ -79,7 +80,7 @@ def get_solaris_slice(file, offset):
         if slicetag == V_ROOT:
             return slicesect * SECTOR_SIZE
 
-    raise RuntimeError, "No root slice found"      
+    raise RuntimeError, "No root slice found"
 
 def get_fs_offset_gpt(file):
     fd = os.open(file, os.O_RDONLY)
@@ -102,7 +103,7 @@ FDISK_PART_GPT=0xee
 def get_partition_offsets(file):
     image_type = identify_disk_image(file)
     if image_type == DISK_TYPE_RAW:
-        # No MBR: assume whole disk filesystem, which is like a 
+        # No MBR: assume whole disk filesystem, which is like a
         # single partition starting at 0
         return [0]
     elif image_type == DISK_TYPE_HYBRIDISO:
@@ -122,7 +123,7 @@ def get_partition_offsets(file):
         partbuf = buf[poff:poff+16]
         offset  = struct.unpack("<L", partbuf[8:12])[0] * SECTOR_SIZE
         type    = struct.unpack("<B", partbuf[4:5])[0]
-        
+
         # offset == 0 implies this partition is not enabled
         if offset == 0:
             continue
@@ -153,7 +154,7 @@ class GrubLineEditor(curses.textpad.Text
         screen.noutrefresh()
         win = curses.newwin(1, 74, startx, starty + 2)
         curses.textpad.Textbox.__init__(self, win)
-        
+
         self.line = list(line)
         self.pos = len(line)
         self.cancelled = False
@@ -219,7 +220,7 @@ class GrubLineEditor(curses.textpad.Text
         if self.cancelled:
             return None
         return string.join(self.line, "")
-        
+
 
 class Grub:
     ENTRY_WIN_LINES = 8
@@ -243,7 +244,7 @@ class Grub:
             self.entry_win = curses.newwin(Grub.ENTRY_WIN_LINES + 2, 74, 2, 1)
             self.text_win = curses.newwin(10, 70, 12, 5)
             curses.def_prog_mode()
-        
+
         curses.reset_prog_mode()
         self.screen.erase()
 
@@ -261,7 +262,7 @@ class Grub:
             self.start_image = self.selected_image
         if self.selected_image < self.start_image:
             self.start_image = self.selected_image
-        
+
         for y in range(self.start_image, len(self.cf.images)):
             i = self.cf.images[y]
             if y > self.start_image + maxy:
@@ -311,7 +312,7 @@ class Grub:
                 l = img.lines[idx].expandtabs().ljust(70)
                 if len(l) > 70:
                     l = l[:69] + ">"
-                    
+
                 self.entry_win.addstr(idp, 2, l)
                 if idx == curline:
                     self.entry_win.attroff(curses.A_REVERSE)
@@ -349,7 +350,7 @@ class Grub:
                 self.command_line_mode()
                 if self.isdone:
                     return
-                
+
             # bound at the top and bottom
             if curline < 0:
                 curline = 0
@@ -357,11 +358,11 @@ class Grub:
                 curline = len(img.lines) - 1
 
         if self.isdone:
-           # Fix to allow pygrub command-line editing in Lilo bootloader (used 
by IA64)
-           if platform.machine() == 'ia64':
-              origimg.reset(img.lines, img.path)
-           else:
-              origimg.reset(img.lines)
+            # Fix to allow pygrub command-line editing in Lilo bootloader 
(used by IA64)
+            if platform.machine() == 'ia64':
+                origimg.reset(img.lines, img.path)
+            else:
+                origimg.reset(img.lines)
 
     def edit_line(self, line):
         self.screen.erase()
@@ -386,7 +387,7 @@ class Grub:
         lines = []
         while 1:
             t = GrubLineEditor(self.screen, y, 2)
-            enable_cursor(True)            
+            enable_cursor(True)
             ret = t.edit()
             if ret:
                 if ret in ("quit", "return"):
@@ -396,7 +397,7 @@ class Grub:
                     lines.append(ret)
                     continue
 
-                # if we got boot, then we want to boot the entered image 
+                # if we got boot, then we want to boot the entered image
                 img = self.cf.new_image("entered", lines)
                 self.cf.add_image(img)
                 self.selected_image = len(self.cf.images) - 1
@@ -409,16 +410,16 @@ class Grub:
     def read_config(self, fn, fs = None):
         """Read the given file to parse the config.  If fs = None, then
         we're being given a raw config file rather than a disk image."""
-        
+
         if not os.access(fn, os.R_OK):
             raise RuntimeError, "Unable to access %s" %(fn,)
 
         if platform.machine() == 'ia64':
-            cfg_list = map(lambda x: (x,grub.LiloConf.LiloConfigFile), 
+            cfg_list = map(lambda x: (x,grub.LiloConf.LiloConfigFile),
                            # common distributions
-                           ["/efi/debian/elilo.conf", 
"/efi/gentoo/elilo.conf", 
-                            "/efi/redflag/elilo.conf", 
"/efi/redhat/elilo.conf", 
-                            "/efi/SuSE/elilo.conf",] + 
+                           ["/efi/debian/elilo.conf", "/efi/gentoo/elilo.conf",
+                            "/efi/redflag/elilo.conf", 
"/efi/redhat/elilo.conf",
+                            "/efi/SuSE/elilo.conf",] +
                            # fallbacks
                            ["/efi/boot/elilo.conf", "/elilo.conf",])
         else:
@@ -442,7 +443,8 @@ class Grub:
 
         for f,parser in cfg_list:
             if fs.file_exists(f):
-                print >>sys.stderr, "Using %s to parse %s" % (parser,f)
+                if debug:
+                    print >> sys.stderr, "Using %s to parse %s" % (parser,f)
                 self.cf = parser()
                 self.cf.filename = f
                 break
@@ -465,7 +467,7 @@ class Grub:
         while not self.isdone:
             self.run_main(timeout)
             timeout = -1
-            
+
         return self.selected_image
 
     def run_main(self, timeout = -1):
@@ -495,7 +497,7 @@ class Grub:
         self.start_image = 0
         while (timeout == -1 or mytime < int(timeout)):
             draw()
-            if timeout != -1 and mytime != -1: 
+            if timeout != -1 and mytime != -1:
                 self.screen.addstr(20, 5, "Will boot selected entry in %2d 
seconds"
                                    %(int(timeout) - mytime))
             else:
@@ -566,7 +568,7 @@ class Grub:
                 self.selected_image = 0
             elif self.selected_image >= len(self.cf.images):
                 self.selected_image = len(self.cf.images) - 1
-        
+
 def get_entry_idx(cf, entry):
     # first, see if the given entry is numeric
     try:
@@ -601,7 +603,7 @@ def run_grub(file, entry, fs, arg):
     if entry is not None:
         idx = get_entry_idx(g.cf, entry)
         if idx is not None and idx > 0 and idx < len(g.cf.images):
-           sel = idx
+            sel = idx
 
     if sel == -1:
         print "No kernel image selected!"
@@ -651,10 +653,10 @@ def sniff_solaris(fs, cfg):
     # Unpleasant. Typically we'll have 'root=foo -k' or 'root=foo /kernel -k',
     # and we need to maintain Xen properties (root= and ip=) and the kernel
     # before any user args.
-    
+
     xenargs = ""
     userargs = ""
-    
+
     if not cfg["args"]:
         cfg["args"] = cfg["kernel"]
     else:
@@ -666,7 +668,7 @@ def sniff_solaris(fs, cfg):
         cfg["args"] = xenargs + " " + cfg["kernel"] + " " + userargs
 
     return cfg
- 
+
 def sniff_netware(fs, cfg):
     if not fs.file_exists("/nwserver/xnloader.sys"):
         return cfg
@@ -683,7 +685,7 @@ def format_sxp(kernel, ramdisk, args):
     if args:
         s += "(args \"%s\")" % args
     return s
-                
+
 def format_simple(kernel, ramdisk, args, sep):
     s = ("kernel %s" % kernel) + sep
     if ramdisk:
@@ -693,9 +695,19 @@ def format_simple(kernel, ramdisk, args,
     s += sep
     return s
 
+def init_log():
+    logger = logging.getLogger()
+    handler = logging.handlers.SysLogHandler(address='/dev/log')
+    file_format = ('[%(asctime)s %(process)d] %(levelname)s '
+                   '(%(module)s:%(lineno)d) %(message)s')
+    handler.setFormatter(logging.Formatter(file_format))
+    logger.addHandler(handler)
+    logger.setLevel(logging.DEBUG)
+
 if __name__ == "__main__":
+    init_log()
     sel = None
-    
+
     def usage():
         print >> sys.stderr, "Usage: %s [-q|--quiet] [-i|--interactive] 
[-n|--not-really] [--output=] [--kernel=] [--ramdisk=] [--args=] [--entry=] 
[--output-directory=] [--output-format=sxp|simple|simple0] <image>" 
%(sys.argv[0],)
 
@@ -732,9 +744,9 @@ if __name__ == "__main__":
 
     try:
         opts, args = getopt.gnu_getopt(sys.argv[1:], 'qinh::',
-                                   ["quiet", "interactive", "not-really", 
"help", 
+                                   ["quiet", "interactive", "not-really", 
"help",
                                     "output=", "output-format=", 
"output-directory=",
-                                    "entry=", "kernel=", 
+                                    "entry=", "kernel=",
                                     "ramdisk=", "args=", "isconfig", "debug"])
     except getopt.GetoptError:
         usage()
@@ -744,7 +756,7 @@ if __name__ == "__main__":
         usage()
         sys.exit(1)
     file = args[0]
-        
+
     output = None
     entry = None
     interactive = True
@@ -783,9 +795,7 @@ if __name__ == "__main__":
             entry = a
             # specifying the entry to boot implies non-interactive
             interactive = False
-        elif o in ("--isconfig",):
-            isconfig = True
-        elif o in ("--debug",):
+        elif o in ("--debug", "--isconfig"):
             debug = True
         elif o in ("--output-format",):
             if a not in ["sxp", "simple", "simple0"]:
@@ -796,96 +806,88 @@ if __name__ == "__main__":
         elif o in ("--output-directory",):
             output_directory = a
 
-    if debug:
-       logging.basicConfig(level=logging.DEBUG)
+    try:
+        if output is None or output == "-":
+            fd = sys.stdout.fileno()
+        else:
+            fd = os.open(output, os.O_WRONLY)
 
-    if output is None or output == "-":
-        fd = sys.stdout.fileno()
-    else:
-        fd = os.open(output, os.O_WRONLY)
+        # if boot filesystem is set then pass to fsimage.open
+        bootfsargs = '"%s"' % incfg["args"]
+        bootfsgroup = re.findall('zfs-bootfs=(.*?)[\s\,\"]', bootfsargs)
+        if bootfsgroup:
+            bootfsoptions = bootfsgroup[0]
+        else:
+            bootfsoptions = ""
 
-    # debug
-    if isconfig:
-        chosencfg = run_grub(file, entry, fs, incfg["args"])
-        print "  kernel: %s" % chosencfg["kernel"]
+        # get list of offsets into file which start partitions
+        part_offs = get_partition_offsets(file)
+
+        for offset in part_offs:
+            try:
+                fs = fsimage.open(file, offset, bootfsoptions)
+
+                chosencfg = sniff_solaris(fs, incfg)
+
+                if not chosencfg["kernel"]:
+                    chosencfg = sniff_netware(fs, incfg)
+
+                if not chosencfg["kernel"]:
+                    chosencfg = run_grub(file, entry, fs, incfg["args"])
+
+                # Break as soon as we've found the kernel so that we continue
+                # to use this fsimage object
+                if chosencfg["kernel"]:
+                    break
+                fs = None
+
+            except Exception, err:
+                # IOErrors raised by fsimage.open
+                # RuntimeErrors raised by run_grub if no menu.lst present
+                if debug:
+                    logging.exception(err)
+                fs = None
+                continue
+
+        # Did looping through partitions find us a kernel?
+        if not fs:
+            raise RuntimeError, "Unable to find partition containing kernel"
+
+        bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel",
+                                            output_directory, not_really)
+
         if chosencfg["ramdisk"]:
-            print "  initrd: %s" % chosencfg["ramdisk"]
-        print "  args: %s" % chosencfg["args"]
-        sys.exit(0)
+            try:
+                bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"],
+                                                     "ramdisk", 
output_directory,
+                                                     not_really)
+            except:
+                if not not_really:
+                    os.unlink(bootcfg["kernel"])
+                raise
+        else:
+            initrd = None
 
-    # if boot filesystem is set then pass to fsimage.open
-    bootfsargs = '"%s"' % incfg["args"]
-    bootfsgroup = re.findall('zfs-bootfs=(.*?)[\s\,\"]', bootfsargs)
-    if bootfsgroup:
-        bootfsoptions = bootfsgroup[0]
-    else:
-        bootfsoptions = ""
+        args = None
+        if chosencfg["args"]:
+            zfsinfo = fsimage.getbootstring(fs)
+            if zfsinfo is not None:
+                e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" )
+                (chosencfg["args"],count) = e.subn(zfsinfo, chosencfg["args"])
+                if count == 0:
+                    chosencfg["args"] += " -B %s" % zfsinfo
+            args = chosencfg["args"]
 
-    # get list of offsets into file which start partitions
-    part_offs = get_partition_offsets(file)
+        if output_format == "sxp":
+            ostring = format_sxp(bootcfg["kernel"], bootcfg["ramdisk"], args)
+        elif output_format == "simple":
+            ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], 
args, "\n")
+        elif output_format == "simple0":
+            ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], 
args, "\0")
 
-    for offset in part_offs:
-        try:
-            fs = fsimage.open(file, offset, bootfsoptions)
-
-            chosencfg = sniff_solaris(fs, incfg)
-
-            if not chosencfg["kernel"]:
-                chosencfg = sniff_netware(fs, incfg)
-
-            if not chosencfg["kernel"]:
-                chosencfg = run_grub(file, entry, fs, incfg["args"])
-
-            # Break as soon as we've found the kernel so that we continue
-            # to use this fsimage object
-            if chosencfg["kernel"]:
-                break
-            fs = None
-
-        except:
-            # IOErrors raised by fsimage.open
-            # RuntimeErrors raised by run_grub if no menu.lst present
-            if debug:
-               traceback.print_exc()
-            fs = None
-            continue
-
-    # Did looping through partitions find us a kernel?
-    if not fs:
-        raise RuntimeError, "Unable to find partition containing kernel"
-
-    bootcfg["kernel"] = copy_from_image(fs, chosencfg["kernel"], "kernel",
-                                        output_directory, not_really)
-
-    if chosencfg["ramdisk"]:
-        try:
-            bootcfg["ramdisk"] = copy_from_image(fs, chosencfg["ramdisk"],
-                                                 "ramdisk", output_directory,
-                                                 not_really)
-        except:
-            if not not_really:
-                os.unlink(bootcfg["kernel"])
-            raise
-    else:
-        initrd = None
-
-    args = None
-    if chosencfg["args"]:
-        zfsinfo = fsimage.getbootstring(fs)
-        if zfsinfo is not None:
-            e = re.compile("zfs-bootfs=[\w\-\.\:@/]+" )
-            (chosencfg["args"],count) = e.subn(zfsinfo, chosencfg["args"])
-            if count == 0:
-               chosencfg["args"] += " -B %s" % zfsinfo
-        args = chosencfg["args"]
-
-    if output_format == "sxp":
-        ostring = format_sxp(bootcfg["kernel"], bootcfg["ramdisk"], args)
-    elif output_format == "simple":
-        ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], args, 
"\n")
-    elif output_format == "simple0":
-        ostring = format_simple(bootcfg["kernel"], bootcfg["ramdisk"], args, 
"\0")
-
-    sys.stdout.flush()
-    os.write(fd, ostring)
-    
+        sys.stdout.flush()
+        os.write(fd, ostring)
+    except Exception, err:
+        print >> sys.stderr, str(err)
+        logging.error(err)
+        sys.exit(1)

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.