ia64/xen-unstable
changeset 8089:c5ee3b6f25b3
Added xen-bugtool, an application that collects various system logs and can
save them as a tarball, or submit them to a pre-existing bugzilla bug.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
save them as a tarball, or submit them to a pre-existing bugzilla bug.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
author | emellor@leeni.uk.xensource.com |
---|---|
date | Mon Nov 28 01:47:28 2005 +0000 (2005-11-28) |
parents | eb1169f92d81 |
children | a20a9ec0e510 |
files | tools/misc/Makefile tools/misc/xen-bugtool tools/python/xen/util/bugtool.py |
line diff
1.1 --- a/tools/misc/Makefile Sun Nov 27 13:09:46 2005 +0000 1.2 +++ b/tools/misc/Makefile Mon Nov 28 01:47:28 2005 +0000 1.3 @@ -16,7 +16,7 @@ HDRS = $(wildcard *.h) 1.4 TARGETS = xenperf xc_shadow 1.5 1.6 INSTALL_BIN = $(TARGETS) xencons 1.7 -INSTALL_SBIN = netfix xm xend xenperf 1.8 +INSTALL_SBIN = netfix xm xen-bugtool xend xenperf 1.9 1.10 all: build 1.11 build: $(TARGETS)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/tools/misc/xen-bugtool Mon Nov 28 01:47:28 2005 +0000 2.3 @@ -0,0 +1,20 @@ 2.4 +#!/usr/bin/env python 2.5 + 2.6 +# -*- mode: python; -*- 2.7 + 2.8 +# Copyright (c) 2005, XenSource Ltd. 2.9 + 2.10 +import sys 2.11 + 2.12 +sys.path.append('/usr/lib/python') 2.13 +sys.path.append('/usr/lib64/python') 2.14 + 2.15 +from xen.util import bugtool 2.16 + 2.17 + 2.18 +if __name__ == "__main__": 2.19 + try: 2.20 + sys.exit(bugtool.main()) 2.21 + except KeyboardInterrupt: 2.22 + print "\nInterrupted." 2.23 + sys.exit(1)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/tools/python/xen/util/bugtool.py Mon Nov 28 01:47:28 2005 +0000 3.3 @@ -0,0 +1,242 @@ 3.4 +#!/usr/bin/env python 3.5 + 3.6 +# This library is free software; you can redistribute it and/or 3.7 +# modify it under the terms of version 2.1 of the GNU Lesser General Public 3.8 +# License as published by the Free Software Foundation. 3.9 +# 3.10 +# This library is distributed in the hope that it will be useful, 3.11 +# but WITHOUT ANY WARRANTY; without even the implied warranty of 3.12 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 3.13 +# Lesser General Public License for more details. 3.14 +# 3.15 +# You should have received a copy of the GNU Lesser General Public 3.16 +# License along with this library; if not, write to the Free Software 3.17 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 3.18 +# 3.19 +# Copyright (c) 2005, XenSource Ltd. 3.20 + 3.21 + 3.22 +import errno 3.23 +import getpass 3.24 +import httplib 3.25 +import re 3.26 +import os 3.27 +import os.path 3.28 +import sys 3.29 +import tarfile 3.30 +import tempfile 3.31 +import time 3.32 +import urllib 3.33 + 3.34 +import xen.lowlevel.xc 3.35 + 3.36 +from xen.xend import encode 3.37 + 3.38 + 3.39 +SERVER = 'bugzilla.xensource.com' 3.40 +SHOW_BUG_PATTERN = 'http://%s/bugzilla/show_bug.cgi?id=%%d' % SERVER 3.41 +ATTACH_PATTERN = \ 3.42 + 'http://%s/bugzilla/attachment.cgi?bugid=%%d&action=enter' % SERVER 3.43 + 3.44 +TITLE_RE = re.compile(r'<title>(.*)</title>') 3.45 + 3.46 +FILES_TO_SEND = [ '/var/log/syslog', '/var/log/messages', '/var/log/debug', 3.47 + '/var/log/xend.log', '/var/log/xend-debug.log', 3.48 + '/var/log/xenstored-trace.log' ] 3.49 +#FILES_TO_SEND = [ ] 3.50 + 3.51 + 3.52 +def main(argv = None): 3.53 + if argv is None: 3.54 + argv = sys.argv 3.55 + 3.56 + print ''' 3.57 +This application will collate the Xen dmesg output, details of the hardware 3.58 +configuration of your machine, information about the build of Xen that you are 3.59 +using, plus, if you allow it, various logs. These logs may contain private 3.60 +information, and if you are at all worried about that, you should exit now. 3.61 + 3.62 +The information collated can either be posted to a Xen Bugzilla bug (this bug 3.63 +must already exist in the system, and you must be a registered user there), or 3.64 +it can be saved as a .tar.bz2 for sending or archiving. 3.65 +''' 3.66 + 3.67 + bugball = [] 3.68 + 3.69 + xc = xen.lowlevel.xc.xc() 3.70 + bugball.append(string_iterator('xen-dmesg', xc.readconsolering())) 3.71 + bugball.append(string_iterator('physinfo', prettyDict(xc.physinfo()))) 3.72 + bugball.append(string_iterator('xeninfo', prettyDict(xc.xeninfo()))) 3.73 + del xc 3.74 + 3.75 + for filename in FILES_TO_SEND: 3.76 + if not os.path.exists(filename): 3.77 + continue 3.78 + 3.79 + if yes('Include %s? [Y/n] ' % filename): 3.80 + bugball.append(file(filename)) 3.81 + 3.82 + maybeAttach(bugball) 3.83 + 3.84 + if (yes(''' 3.85 +Do you wish to save these details as a tarball (.tar.bz2)? [Y/n] ''')): 3.86 + tar(bugball) 3.87 + 3.88 + return 0 3.89 + 3.90 + 3.91 +def maybeAttach(bugball): 3.92 + if not yes(''' 3.93 +Do you wish to attach these details to a Bugzilla bug? [Y/n] '''): 3.94 + return 3.95 + 3.96 + bug = int(raw_input('Bug number? ')) 3.97 + 3.98 + bug_title = getBugTitle(bug) 3.99 + 3.100 + if bug_title == 'Search by bug number' or bug_title == 'Invalid Bug ID': 3.101 + print >>sys.stderr, 'Bug %d does not exist!' % bug 3.102 + maybeAttach(bugball) 3.103 + elif yes('Are you sure that you want to attach to %s? [Y/n] ' % 3.104 + bug_title): 3.105 + attach(bug, bugball) 3.106 + else: 3.107 + maybeAttach(bugball) 3.108 + 3.109 + 3.110 +def attach(bug, bugball): 3.111 + username = raw_input('Bugzilla username: ') 3.112 + password = getpass.getpass('Bugzilla password: ') 3.113 + 3.114 + conn = httplib.HTTPConnection(SERVER) 3.115 + try: 3.116 + for f in bugball: 3.117 + send(bug, conn, f, f.name, username, password) 3.118 + finally: 3.119 + conn.close() 3.120 + 3.121 + 3.122 +def getBugTitle(bug): 3.123 + f = urllib.urlopen(SHOW_BUG_PATTERN % bug) 3.124 + 3.125 + try: 3.126 + for line in f: 3.127 + m = TITLE_RE.search(line) 3.128 + if m: 3.129 + return m.group(1) 3.130 + finally: 3.131 + f.close() 3.132 + 3.133 + raise "Could not find title of bug %d!" % bug 3.134 + 3.135 + 3.136 +def send(bug, conn, fd, filename, username, password): 3.137 + 3.138 + print "Attaching %s to bug %d." % (filename, bug) 3.139 + 3.140 + headers, data = encode.encode_data( 3.141 + { 'bugid' : str(bug), 3.142 + 'action' : 'insert', 3.143 + 'data' : fd, 3.144 + 'description' : '%s from %s' % (filename, username), 3.145 + 'contenttypeselection' : 'text/plain', 3.146 + 'contenttypemethod' : 'list', 3.147 + 'ispatch' : '0', 3.148 + 'GoAheadAndLogIn' : '1', 3.149 + 'Bugzilla_login' : username, 3.150 + 'Bugzilla_password' : password, 3.151 + }) 3.152 + 3.153 + conn.request('POST',ATTACH_PATTERN % bug, data, headers) 3.154 + response = conn.getresponse() 3.155 + try: 3.156 + body = response.read() 3.157 + m = TITLE_RE.search(body) 3.158 + 3.159 + if response.status != 200: 3.160 + print >>sys.stderr, ( 3.161 + 'Attach failed: %s %s.' % (response.status, response.reason)) 3.162 + elif not m or m.group(1) != 'Changes Submitted': 3.163 + print >>sys.syderr, ( 3.164 + 'Attach failed: got a page titled %s.' % m.group(1)) 3.165 + else: 3.166 + print "Attaching %s to bug %d succeeded." % (filename, bug) 3.167 + finally: 3.168 + response.close() 3.169 + 3.170 + 3.171 +def tar(bugball): 3.172 + filename = raw_input('Tarball destination filename? ') 3.173 + 3.174 + now = time.time() 3.175 + 3.176 + tf = tarfile.open(filename, 'w:bz2') 3.177 + 3.178 + try: 3.179 + for f in bugball: 3.180 + ti = tarfile.TarInfo(f.name.split('/')[-1]) 3.181 + if hasattr(f, 'size'): 3.182 + ti.size = f.size() 3.183 + else: 3.184 + ti.size = os.stat(f.name).st_size 3.185 + 3.186 + ti.mtime = now 3.187 + ti.type = tarfile.REGTYPE 3.188 + ti.uid = 0 3.189 + ti.gid = 0 3.190 + ti.uname = 'root' 3.191 + ti.gname = 'root' 3.192 + 3.193 + f.seek(0) # If we've added this file to a bug, it will have been 3.194 + # read once already, so reset it. 3.195 + tf.addfile(ti, f) 3.196 + finally: 3.197 + tf.close() 3.198 + 3.199 + print 'Writing tarball %s successful.' % filename 3.200 + 3.201 + 3.202 +def prettyDict(d): 3.203 + format = '%%-%ds: %%s' % max(map(len, [k for k, _ in d.items()])) 3.204 + return '\n'.join([format % i for i in d.items()]) + '\n' 3.205 + 3.206 + 3.207 +class string_iterator: 3.208 + def __init__(self, name, val): 3.209 + self.name = name 3.210 + self.val = val 3.211 + self.vallist = val.splitlines(True) 3.212 + self.line = 0 3.213 + 3.214 + def readlines(self): 3.215 + return self.vallist 3.216 + 3.217 + def readline(self): 3.218 + result = self.vallist[line] 3.219 + line += 1 3.220 + return result 3.221 + 3.222 + def read(self, n = None): 3.223 + if n is None: 3.224 + return self.val 3.225 + else: 3.226 + return self.val[0:n] 3.227 + 3.228 + def close(self): 3.229 + pass 3.230 + 3.231 + def size(self): 3.232 + return len(self.val) 3.233 + 3.234 + def seek(self, _1, _2 = None): 3.235 + pass 3.236 + 3.237 + 3.238 +def yes(prompt): 3.239 + yn = raw_input(prompt) 3.240 + 3.241 + return len(yn) == 0 or yn.lower()[0] == 'y' 3.242 + 3.243 + 3.244 +if __name__ == "__main__": 3.245 + sys.exit(main())