From b7024111fcfe3662e96f5e6ad51d680fa3607b51 Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Thu, 23 Oct 2014 16:37:14 +0200 Subject: [ABRT PATCH 73/75] a-a-g-machine-id: add systemd's machine id The dmidecode based algorithm may not work on all architectures. man machine-id Related to rhbz#1139552 Signed-off-by: Jakub Filak --- src/plugins/abrt-action-generate-machine-id | 162 +++++++++++++++++++++++++--- 1 file changed, 150 insertions(+), 12 deletions(-) diff --git a/src/plugins/abrt-action-generate-machine-id b/src/plugins/abrt-action-generate-machine-id index 0aea787..6f43258 100644 --- a/src/plugins/abrt-action-generate-machine-id +++ b/src/plugins/abrt-action-generate-machine-id @@ -1,14 +1,47 @@ #!/usr/bin/python + +## Copyright (C) 2014 ABRT team +## Copyright (C) 2014 Red Hat, Inc. + +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. + +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. + +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA + +"""This module provides algorithms for generating Machine IDs. +""" + +import sys from argparse import ArgumentParser +import logging -import dmidecode import hashlib +def generate_machine_id_dmidecode(): + """Generate a machine_id based off dmidecode fields -# Generate a machine_id based off dmidecode fields -def generate_machine_id(): - dmixml = dmidecode.dmidecodeXML() + The function generates the same result as sosreport-uploader + + Returns a machine ID as string or throws RuntimeException + + """ + try: + import dmidecode + except ImportError as ex: + raise RuntimeError("Could not import dmidecode module: {0}" + .format(str(ex))) + + dmixml = dmidecode.dmidecodeXML() # Fetch all DMI data into a libxml2.xmlDoc object dmixml.SetResultType(dmidecode.DMIXML_DOC) xmldoc = dmixml.QuerySection('all') @@ -38,20 +71,125 @@ def generate_machine_id(): return machine_id.hexdigest() -if __name__ == "__main__": - CMDARGS = ArgumentParser(description = "Generate a machine_id based off dmidecode fields") - CMDARGS.add_argument('-o', '--output', type=str, help='Output file') +def generate_machine_id_systemd(): + """Generate a machine_id equals to a one generated by systemd + + This function returns contents of /etc/machine-id + + Returns a machine ID as string or throws RuntimeException. + + """ + + try: + with open('/etc/machine-id', 'r') as midf: + return "".join((l.strip() for l in midf)) + except IOError as ex: + raise RuntimeError("Could not use systemd's machine-id: {0}" + .format(str(ex))) + + +GENERATORS = { 'sosreport_uploader-dmidecode' : generate_machine_id_dmidecode, + 'systemd' : generate_machine_id_systemd } + + +def generate_machine_id(generators): + """Generates all requested machine id with all required generators + + Keyword arguments: + generators -- a list of generator names + + Returns a dictionary where keys are generators and associated values are + products of those generators. + + """ + + ids = {} + workers = GENERATORS + for sd in generators: + try: + ids[sd] = workers[sd]() + except RuntimeError as ex: + logging.error("Machine-ID generator '{0}' failed: {1}" + .format(sd, ex.message)) + + return ids + + +def print_result(ids, outfile, prefixed): + """Writes a dictionary of machine ids to a file + + Each dictionary entry is written on a single line. The function does not + print trailing new-line if the dictionary contains only one item as it is + common format of one-liners placed in a dump directory. + + Keyword arguments: + ids -- a dictionary [generator name: machine ids] + outfile -- output file + prefixed -- use 'generator name=' prefix or not + """ + + fmt = '{0}={1}' if prefixed else '{1}' + + if len(ids) > 1: + fmt += '\n' + + for sd, mid in ids.iteritems(): + outfile.write(fmt.format(sd,mid)) + + +def print_generators(outfile=None): + """Prints requested generators + + Keyword arguments: + outfile -- output file (default: sys.stdout) + + """ + if outfile is None: + outfile = sys.stdout + + for sd in GENERATORS.iterkeys(): + outfile.write("{0}\n".format(sd)) + + +if __name__ == '__main__': + CMDARGS = ArgumentParser(description = "Generate a machine_id") + CMDARGS.add_argument('-o', '--output', type=str, + help="Output file") + CMDARGS.add_argument('-g', '--generators', nargs='+', type=str, + help="Use given generators only") + CMDARGS.add_argument('-l', '--list-generators', action='store_true', + default=False, help="Print out a list of usable generators") + CMDARGS.add_argument('-n', '--noprefix', action='store_true', + default=False, help="Do not use generator name as prefix for IDs") OPTIONS = CMDARGS.parse_args() ARGS = vars(OPTIONS) - machineid = generate_machine_id() + logging.basicConfig(format='%(message)s') + + if ARGS['list_generators']: + print_generators() + sys.exit(0) + + requested_generators = None + if ARGS['generators']: + requested_generators = ARGS['generators'] + else: + requested_generators = GENERATORS.keys() + + machineids = generate_machine_id(requested_generators) if ARGS['output']: try: - with open(ARGS['output'], 'w') as outfile: - outfile.write(machineid) + with open(ARGS['output'], 'w') as fout: + print_result(machineids, fout, not ARGS['noprefix']) except IOError as ex: - print ex + logging.error("Could not open output file: {0}".format(str(ex))) + sys.exit(1) else: - print machineid + print_result(machineids, sys.stdout, not ARGS['noprefix']) + # print_results() omits new-line for one-liners + if len(machineids) == 1: + sys.stdout.write('\n') + + sys.exit(len(requested_generators) - len(machineids.keys())) -- 1.8.3.1