diff --git a/qvm-tools/qubes-bug-report b/qvm-tools/qubes-bug-report index 3bbab112..5dcb12ce 100755 --- a/qvm-tools/qubes-bug-report +++ b/qvm-tools/qubes-bug-report @@ -11,216 +11,217 @@ from os.path import expanduser #the term qube refers to a qubes vm def is_program_installed_in_qube( program, qube_name ): - is_installed = True + is_installed = True - try: - command = 'command -v ' + program - subprocess.check_call([ 'qvm-run', qube_name, '--pass-io', '--no-color-output', command ], stdout = open( os.devnull, 'w' ) ) + try: + command = 'command -v ' + program + subprocess.check_call([ 'qvm-run', qube_name, '--pass-io', '--no-color-output', command ], stdout = open( os.devnull, 'w' ) ) - except subprocess.CalledProcessError: - is_installed = False + except subprocess.CalledProcessError: + is_installed = False - return is_installed + return is_installed #this function requires virsh #domstate only works for Xen domU (guests) def is_qube_running( qube_name ): - runs = False + runs = False - out = subprocess.check_output([ "virsh", "-c", "xen:///", "domstate", qube_name ]) - out = out.decode('utf-8').replace('\n', '') + out = subprocess.check_output([ "virsh", "-c", "xen:///", "domstate", qube_name ]) + out = out.decode('utf-8').replace('\n', '') - if 'running' == out: - runs = True + if 'running' == out: + runs = True - return runs + return runs def get_qube_packages( qube_name ): - content = "## Qubes Packages\n\n" + content = "## Qubes Packages\n\n" - #a qube can have more than one package manager installed (only one is functional) - pkg_cmd = { 'dpkg' : 'dpkg -l qubes-*', 'pacman' : 'pacman -Qs qubes', 'rpm' : 'rpm -qa qubes-*' } + #a qube can have more than one package manager installed (only one is functional) + pkg_cmd = { 'dpkg' : 'dpkg -l qubes-*', 'pacman' : 'pacman -Qs qubes', 'rpm' : 'rpm -qa qubes-*' } - if is_qube_running( qube_name ): + if is_qube_running( qube_name ): - for package_manager in pkg_cmd.keys(): - if is_program_installed_in_qube( package_manager, qube_name ): - pkg_list_cmd = pkg_cmd[package_manager] + for package_manager in pkg_cmd.keys(): + if is_program_installed_in_qube( package_manager, qube_name ): + pkg_list_cmd = pkg_cmd[package_manager] - try: - out = subprocess.check_output([ 'qvm-run', qube_name, '--pass-io', '--no-color-output', pkg_list_cmd ], stderr = open( os.devnull, 'w' ) ) - out = out.decode('utf-8') - content = content + create_heading( ( "Package Manager: " + package_manager ), 3 ) - content = content + wrap_code( out ) - except subprocess.CalledProcessError: - pass #do nothing + try: + out = subprocess.check_output([ 'qvm-run', qube_name, '--pass-io', '--no-color-output', pkg_list_cmd ], stderr = open( os.devnull, 'w' ) ) + out = out.decode('utf-8') + content += create_heading( ( "Package Manager: " + package_manager ), 3 ) + content += wrap_code( out ) + except subprocess.CalledProcessError: + pass #do nothing - else: - content = content + "**No packages listed, because Qube " + qube_name + " was not running**\n\n" + else: + content += "**No packages listed, because Qube " + qube_name + " was not running**\n\n" - return content - + return content + def get_dom0_packages(): - content = create_heading( "Dom0 Packages", 2 ) - out = subprocess.check_output([ "rpm", "-qa", "qubes-*" ]) - out = out.decode('utf-8') - content = content + wrap_code( out ) - - return content + content = create_heading( "Dom0 Packages", 2 ) + out = subprocess.check_output([ "rpm", "-qa", "qubes-*" ]) + out = out.decode('utf-8') + content += wrap_code( out ) + + return content def wrap_code( text ): - code = "~~~\n" + text + "~~~\n\n" - - return code + code = "~~~\n" + text + "~~~\n\n" + + return code def create_heading( heading, level ): - heading = heading + "\n\n" - - if 1 == level: - heading = "# " + heading - elif 2 == level: - heading = "## " + heading - else: - heading = "### " + heading + heading = heading + "\n\n" + + if 1 == level: + heading = "# " + heading + elif 2 == level: + heading = "## " + heading + else: + heading = "### " + heading - return heading - + return heading + def get_log_file_content( qube_name ): - content = "## Log Files\n\n" - qubes_os_log = "/var/log/qubes/" - ext = ".log" + content = "## Log Files\n\n" + qubes_os_log = "/var/log/qubes/" + ext = ".log" - log_prefix = [ "guid", "pacat", "qubesdb", "qrexec" ] + log_prefix = [ "guid", "pacat", "qubesdb", "qrexec" ] - for prefix in log_prefix: - log_file = prefix + "." + qube_name + ext - content = content + create_heading( ( "Log File: " + log_file ), 3 ) - content = content + wrap_code( get_log_file( qubes_os_log + log_file ) ) + #constructs for each log file prefix the full path and reads the log file + for prefix in log_prefix: + log_file = prefix + "." + qube_name + ext + content += create_heading( ( "Log File: " + log_file ), 3 ) + content += wrap_code( get_log_file( qubes_os_log + log_file ) ) - return content + return content def get_qube_prefs( qube_name ): - qube_prefs = subprocess.check_output([ "qvm-prefs", qube_name ]) - qube_prefs = qube_prefs.decode('utf-8') - - content = create_heading( "Qube Prefs", 2 ) - content = content + wrap_code( qube_prefs ) - - return content + qube_prefs = subprocess.check_output([ "qvm-prefs", qube_name ]) + qube_prefs = qube_prefs.decode('utf-8') + + content = create_heading( "Qube Prefs", 2 ) + content += wrap_code( qube_prefs ) + + return content def report( qube_name ): - template = '''{title} + template = '''{title} {content} ''' - title_text = create_heading( "Bug report: " + qube_name, 1 ) + title_text = create_heading( "Bug report: " + qube_name, 1 ) - content_text = get_qube_prefs( qube_name ) - content_text = content_text + get_dom0_packages() - content_text = content_text + get_log_file_content( qube_name ) - content_text = content_text + get_qube_packages( qube_name ) - + content_text = get_qube_prefs( qube_name ) + content_text += get_dom0_packages() + content_text += get_log_file_content( qube_name ) + content_text += get_qube_packages( qube_name ) + - report = template.format( title=title_text, content=content_text ) + report = template.format( title=title_text, content=content_text ) - return report + return report def write_report( report_content, file_path ): - with open( file_path, 'w' ) as report_file: - report_file.write( report_content ) + with open( file_path, 'w' ) as report_file: + report_file.write( report_content ) def send_report( dest_qube, file_path): - #if dest_qube is not running -> start dest_qube - if not is_qube_running( dest_qube ): - try: - subprocess.check_call([ "qvm-start", dest_qube ]) - except subprocess.CalledProcessError: - print( "Error while starting: " + dest_qube, file = sys.stderr ) + #if dest_qube is not running -> start dest_qube + if not is_qube_running( dest_qube ): + try: + subprocess.check_call([ "qvm-start", dest_qube ]) + except subprocess.CalledProcessError: + print( "Error while starting: " + dest_qube, file = sys.stderr ) - try: - subprocess.check_call([ "qvm-move-to-vm", dest_qube, file_path ]) - except subprocess.calledProcessError: - print( "Moving file bug-report failed", file = sys.stderr ) + try: + subprocess.check_call([ "qvm-move-to-vm", dest_qube, file_path ]) + except subprocess.calledProcessError: + print( "Moving file bug-report failed", file = sys.stderr ) def get_log_file( log_file ): - data = "" + data = "" - #open and close the file - with open( log_file ) as log: - data = log.read() + #open and close the file + with open( log_file ) as log: + data = log.read() - return data + return data def qube_exist( qube_name ): - exists = True - - try: - #calls: qvm-check --quiet vmanme - subprocess.check_call([ "qvm-check", "--quiet", qube_name ]) + exists = True + + try: + #calls: qvm-check --quiet vmanme + subprocess.check_call([ "qvm-check", "--quiet", qube_name ]) - except subprocess.CalledProcessError: - exists = False + except subprocess.CalledProcessError: + exists = False - return exists + return exists def get_report_file_path( qube_name ): - #exapanduser -> works corss platform - home_dir = expanduser("~") - date = time.strftime("%H%M%S") - file_path = home_dir + "/" + qube_name + "_bug-report_" + date + ".md" + #exapanduser -> works corss platform + home_dir = expanduser("~") + date = time.strftime("%H%M%S") + file_path = home_dir + "/" + qube_name + "_bug-report_" + date + ".md" - return file_path + return file_path def main(): - parser = argparse.ArgumentParser( description = 'Generates a bug report for a specific qube (Qubes VM)' ) - parser.add_argument( 'vmname', metavar = '', type = str ) - parser.add_argument( '-d', '--dest-vm', metavar = '', dest = "destvm", type = str, default = 'dom0', help = "send the report to the destination VM" ) - parser.add_argument( '-p', '--print-report', action = 'store_const', const = "print_report", required = False, help = "prints the report without writing it or sending it to a destination VM" ) - args = parser.parse_args() + parser = argparse.ArgumentParser( description = 'Generates a bug report for a specific qube (Qubes VM)' ) + parser.add_argument( 'vmname', metavar = '', type = str ) + parser.add_argument( '-d', '--dest-vm', metavar = '', dest = "destvm", type = str, default = 'dom0', help = "send the report to the destination VM" ) + parser.add_argument( '-p', '--print-report', action = 'store_const', const = "print_report", required = False, help = "prints the report without writing it or sending it to a destination VM" ) + args = parser.parse_args() - if qube_exist( args.vmname ): + if qube_exist( args.vmname ): - if qube_exist( args.destvm ): - #get the report - report_content = report( args.vmname ) + if qube_exist( args.destvm ): + #get the report + report_content = report( args.vmname ) - #if -p or --print-report is an argument print the report - if args.print_report: - print( report_content ) + #if -p or --print-report is an argument print the report + if args.print_report: + print( report_content ) - #write and send the report - else: - file_path = get_report_file_path( args.vmname ) - write_report( report_content, file_path ) - print( "Report written to: " + file_path ) + #write and send the report + else: + file_path = get_report_file_path( args.vmname ) + write_report( report_content, file_path ) + print( "Report written to: " + file_path ) - if 'dom0' != args.destvm: - send_report( args.destvm, file_path ) - print( "Report send to VM: " + args.destvm ) + if 'dom0' != args.destvm: + send_report( args.destvm, file_path ) + print( "Report send to VM: " + args.destvm ) - exit(0) + exit(0) - else: - print ( "Destination VM does not exist" ) - exit(1) + else: + print ( "Destination VM does not exist" ) + exit(1) - else: - print( "VM does not exist" ) - exit(1) + else: + print( "VM does not exist" ) + exit(1) #calls the main function -> program start point