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