summaryrefslogtreecommitdiffstats
path: root/exception.py
diff options
context:
space:
mode:
authorChris Lumens <clumens@redhat.com>2008-07-22 12:59:27 -0400
committerChris Lumens <clumens@redhat.com>2008-07-22 15:58:24 -0400
commit1b632ee2e4c64148a942db567f4e4ef6de6af571 (patch)
tree2156deece62ca7bf17f44d9c0409a54813a1bbae /exception.py
parentb7ce023c6c33ad8974df25e72f1c99c3b0e75dcf (diff)
downloadanaconda-1b632ee2e4c64148a942db567f4e4ef6de6af571.tar.gz
anaconda-1b632ee2e4c64148a942db567f4e4ef6de6af571.tar.xz
anaconda-1b632ee2e4c64148a942db567f4e4ef6de6af571.zip
Add support for filing tracebacks directly into bugzilla.
This patch adds support for save to bugzilla, using the python-bugzilla module. We get the bugzilla URL from product.bugUrl and require the user to already have a valid account with that bugzilla instance. That should cut down on potential abuse. To cut down on the number of possible duplicates, we hash the file name, function name, and line of each frame in the traceback and store that hash in the bug itself. Before filing a new bug, we query for any bugs containing that hash value. If found, we simply add the traceback as a new attachment and put the user on the CC list. If not found, we create a new bug. Either way, the user is encouraged to visit their bug and make a more meaningful comment.
Diffstat (limited to 'exception.py')
-rw-r--r--exception.py136
1 files changed, 108 insertions, 28 deletions
diff --git a/exception.py b/exception.py
index ab01ecdf7..4572eefb7 100644
--- a/exception.py
+++ b/exception.py
@@ -51,6 +51,8 @@ class AnacondaExceptionDump:
self.value = value
self.tb = tb
+ self.tbFile = None
+
self._dumpHash = {}
# Reverse the order that tracebacks are printed so people will hopefully quit
@@ -219,6 +221,12 @@ class AnacondaExceptionDump:
return hashlib.sha256(s).hexdigest()
+ def write(self, anaconda):
+ self.tbFile = "/tmp/anacdump.txt"
+ fd = open(self.tbFile, "w")
+ self.dump(fd, anaconda)
+ fd.close()
+
# Save the traceback to a removable storage device, such as a floppy disk
# or a usb/firewire drive. If there's no filesystem on the disk/partition,
# write a vfat one.
@@ -273,8 +281,99 @@ def copyExceptionToDisk(anaconda, device):
isys.umount("/tmp/crash")
return True
-def runSaveDialog(anaconda, longTracebackFile):
- saveWin = anaconda.intf.saveExceptionWindow(anaconda, longTracebackFile)
+def saveToBugzilla(anaconda, exn, dest):
+ import bugzilla, xmlrpclib
+ import product, rpmUtils
+
+ if dest[0].strip() == "" or dest[1].strip() == "" or dest[2].strip() == "":
+ anaconda.intf.messageWindow(_("Invalid Bug Information"),
+ _("Please provide a valid username, "
+ "password, and short bug description."))
+ return False
+
+ hash = exn.hash()
+
+ if product.bugUrl.startswith("http://"):
+ bugUrl = "https://" + product.bugUrl[7:]
+ elif product.bugUrl.startswith("https://"):
+ bugUrl = product.bugUrl
+ else:
+ anaconda.intf.messageWindow(_("No bugzilla URL"),
+ _("Your distribution does not provide a "
+ "bug reporting URL, so you cannot save "
+ "your exception to a remote bug tracking "
+ "system."))
+ return False
+
+ if not exn.tbFile:
+ exn.write(anaconda)
+
+ bz = bugzilla.Bugzilla(url = "%s/xmlrpc.cgi" % bugUrl)
+
+ if not bz.login(dest[0], dest[1]):
+ anaconda.intf.messageWindow(_("Unable To Login"),
+ _("There was an error logging into %s "
+ "using the provided username and "
+ "password.") % product.bugUrl)
+ return False
+
+ # Are there any existing bugs with this hash value? If so we will just
+ # add this traceback to the bug report and put the reporter on the CC
+ # list. Otherwise, we need to create a new bug.
+ try:
+ buglist = bz.query({'status_whiteboard': hash})
+ except xmlrpclib.ProtocolError, e:
+ anaconda.intf.messageWindow(_("Unable To File Bug"),
+ _("Your bug could not be filed due to the "
+ "following error when communicating with "
+ "bugzilla:\n\n%s" % str(e)))
+ return False
+
+ # FIXME: need to handle all kinds of errors here
+ if len(buglist) == 0:
+ bug = bz.createbug(product=product.productName,
+ component="anaconda",
+ version=product.productVersion,
+ rep_platform=rpmUtils.arch.getBaseArch(),
+ bug_severity="medium",
+ priority="medium",
+ op_sys="Linux",
+ bug_file_loc="http://",
+ short_desc=dest[2],
+ comment="This bug was filed automatically by anaconda.")
+ bug.setwhiteboard("anaconda_trace_hash:%s" % hash, which="status")
+ bz.attachfile(bug.bug_id, exn.tbFile, "Attached traceback automatically from anaconda.",
+ contenttype="text/plain")
+
+ # Tell the user we created a new bug for them and that they should
+ # go add a descriptive comment.
+ anaconda.intf.messageWindow(_("Bug Created"),
+ _("A new bug has been created with your traceback attached. "
+ "Please add additional information such as what you were doing "
+ "when you encountered the bug, screenshots, and whatever else "
+ "is appropriate to the following bug:\n\n%s/%s") % (bugUrl, bug.bug_id),
+ type="custom", custom_icon="info",
+ custom_buttons=[_("_Exit installer")])
+ sys.exit(0)
+ else:
+ id = buglist[0].bug_id
+ bz.attachfile(id, exn.tbFile, "Attached traceback automatically from anaconda.",
+ contenttype="text/plain")
+ bz._updatecc(id, [dest[0]], "add")
+
+ # Tell the user which bug they've been CC'd on and that they should
+ # go add a descriptive comment.
+ anaconda.intf.messageWindow(_("Bug Updated"),
+ _("A bug with your information already exists. Your account has "
+ "been added to the CC list and your traceback added as a "
+ "comment. Please add additional descriptive information to the "
+ "following bug:\n\n%s/%s") % (bugUrl, id),
+ type="custom", custom_icon="info",
+ custom_buttons=[_("_Exit installer")])
+ sys.exit(0)
+
+def runSaveDialog(anaconda, exn):
+ saveWin = anaconda.intf.saveExceptionWindow(anaconda, exn.tbFile)
if not saveWin:
anaconda.intf.__del__()
os.kill(os.getpid(), signal.SIGKILL)
@@ -303,7 +402,7 @@ def runSaveDialog(anaconda, longTracebackFile):
elif saveWin.saveToLocal():
dest = saveWin.getDest()
try:
- shutil.copyfile("/tmp/anacdump.txt", "%s/InstallError.txt" %(dest,))
+ shutil.copyfile(exn.tbFile, "%s/InstallError.txt" %(dest,))
anaconda.intf.messageWindow(_("Dump Written"),
_("Your system's state has been successfully written to "
"the disk. The installer will now exit."),
@@ -311,30 +410,14 @@ def runSaveDialog(anaconda, longTracebackFile):
custom_buttons=[_("_Exit installer")])
sys.exit(0)
except Exception, e:
- log.error("Failed to copy anacdump.txt to %s/anacdump.txt: %s" %(dest, e))
+ log.error("Failed to copy %s to %s/anacdump.txt: %s" %(exn.tbFile, dest, e))
else:
anaconda.intf.messageWindow(_("Dump Not Written"),
_("There was a problem writing the system state to the "
"disk."))
continue
else:
- if not hasActiveNetDev() and not anaconda.intf.enableNetwork(anaconda):
- scpSucceeded = False
- else:
- scpInfo = saveWin.getDest()
- scpSucceeded = copyExceptionToRemote(anaconda.intf, scpInfo)
-
- if scpSucceeded:
- anaconda.intf.messageWindow(_("Dump Written"),
- _("Your system's state has been successfully written to "
- "the remote host. The installer will now exit."),
- type="custom", custom_icon="info",
- custom_buttons=[_("_Exit installer")])
- sys.exit(0)
- else:
- anaconda.intf.messageWindow(_("Dump Not Written"),
- _("There was a problem writing the system state to the "
- "remote host."))
+ if not saveToBugzilla(anaconda, exn, saveWin.getDest()):
continue
elif rc == EXN_CANCEL:
break
@@ -348,14 +431,11 @@ def handleException(anaconda, (type, value, tb)):
# restore original exception handler
sys.excepthook = sys.__excepthook__
+ # Save the exception file to local storage first.
exn = AnacondaExceptionDump(type, value, tb)
+ exn.write(anaconda)
text = str(exn)
- # save to local storage first
- out = open("/tmp/anacdump.txt", "w")
- exn.dump(out, anaconda)
- out.close()
-
# see if /mnt/sysimage is present and put exception there as well
if os.access("/mnt/sysimage/root", os.X_OK):
try:
@@ -371,7 +451,7 @@ def handleException(anaconda, (type, value, tb)):
except:
pass
- mainWin = anaconda.intf.mainExceptionWindow(text, "/tmp/anacdump.txt")
+ mainWin = anaconda.intf.mainExceptionWindow(text, exn.tbFile)
if not mainWin:
anaconda.intf.__del__()
os.kill(os.getpid(), signal.SIGKILL)
@@ -415,4 +495,4 @@ def handleException(anaconda, (type, value, tb)):
pdb.post_mortem (tb)
os.kill(os.getpid(), signal.SIGKILL)
elif rc == EXN_SAVE:
- runSaveDialog(anaconda, "/tmp/anacdump.txt")
+ runSaveDialog(anaconda, exn)