Blame src/plugins/abrt-action-generate-machine-id

Packit 8ea169
#!/usr/bin/python3
Packit 8ea169
Packit 8ea169
## Copyright (C) 2014 ABRT team <abrt-devel-list@redhat.com>
Packit 8ea169
## Copyright (C) 2014 Red Hat, Inc.
Packit 8ea169
Packit 8ea169
## This program is free software; you can redistribute it and/or modify
Packit 8ea169
## it under the terms of the GNU General Public License as published by
Packit 8ea169
## the Free Software Foundation; either version 2 of the License, or
Packit 8ea169
## (at your option) any later version.
Packit 8ea169
Packit 8ea169
## This program is distributed in the hope that it will be useful,
Packit 8ea169
## but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8ea169
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8ea169
## GNU General Public License for more details.
Packit 8ea169
Packit 8ea169
## You should have received a copy of the GNU General Public License
Packit 8ea169
## along with this program; if not, write to the Free Software
Packit 8ea169
## Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
Packit 8ea169
Packit 8ea169
"""This module provides algorithms for generating Machine IDs.
Packit 8ea169
"""
Packit 8ea169
Packit 8ea169
import os
Packit 8ea169
import sys
Packit 8ea169
from argparse import ArgumentParser
Packit 8ea169
from subprocess import check_output
Packit 8ea169
import logging
Packit 8ea169
Packit 8ea169
import hashlib
Packit 8ea169
Packit 8ea169
def generate_machine_id_dmidecode():
Packit 8ea169
    """Generate a machine_id based off dmidecode fields
Packit 8ea169
Packit 8ea169
    The function generates the same result as sosreport-uploader
Packit 8ea169
Packit 8ea169
    Returns a machine ID as string or throws RuntimeException
Packit 8ea169
Packit 8ea169
    """
Packit 8ea169
Packit 8ea169
    if not os.path.isfile("/usr/sbin/dmidecode"):
Packit 8ea169
        raise RuntimeError("Could not find dmidecode. It might not be available for this " \
Packit 8ea169
                           "architecture.")
Packit 8ea169
Packit 8ea169
    # What to look for
Packit 8ea169
    keys = ['system-manufacturer',
Packit 8ea169
            'system-product-name',
Packit 8ea169
            'system-serial-number',
Packit 8ea169
            'system-uuid']
Packit 8ea169
Packit 8ea169
    # Create a sha256 of ^ for machine_id
Packit 8ea169
    machine_id = hashlib.sha256()
Packit 8ea169
Packit 8ea169
    # Run dmidecode command
Packit 8ea169
    for k in keys:
Packit 8ea169
        data = check_output(["dmidecode", "-s", k]).strip()
Packit 8ea169
Packit 8ea169
        # Update the hash as we find the fields we are looking for
Packit 8ea169
        machine_id.update(data)
Packit 8ea169
Packit 8ea169
    # Create sha256 digest
Packit 8ea169
    return machine_id.hexdigest()
Packit 8ea169
Packit 8ea169
Packit 8ea169
def generate_machine_id_systemd():
Packit 8ea169
    """Generate a machine_id equals to a one generated by systemd
Packit 8ea169
Packit 8ea169
    This function returns contents of /etc/machine-id
Packit 8ea169
Packit 8ea169
    Returns a machine ID as string or throws RuntimeException.
Packit 8ea169
Packit 8ea169
    """
Packit 8ea169
Packit 8ea169
    try:
Packit 8ea169
        with open('/etc/machine-id', 'r') as midf:
Packit 8ea169
            return "".join((l.strip() for l in midf))
Packit 8ea169
    except IOError as ex:
Packit 8ea169
        raise RuntimeError("Could not use systemd's machine-id: {0}"
Packit 8ea169
                .format(str(ex)))
Packit 8ea169
Packit 8ea169
Packit 8ea169
GENERATORS = { 'sosreport_uploader-dmidecode' : generate_machine_id_dmidecode,
Packit 8ea169
               'systemd'                      : generate_machine_id_systemd }
Packit 8ea169
Packit 8ea169
Packit 8ea169
def generate_machine_id(generators):
Packit 8ea169
    """Generates all requested machine id with all required generators
Packit 8ea169
Packit 8ea169
    Keyword arguments:
Packit 8ea169
    generators -- a list of generator names
Packit 8ea169
Packit 8ea169
    Returns a dictionary where keys are generators and associated values are
Packit 8ea169
    products of those generators.
Packit 8ea169
Packit 8ea169
    """
Packit 8ea169
Packit 8ea169
    ids = {}
Packit 8ea169
    workers = GENERATORS
Packit 8ea169
    for sd in generators:
Packit 8ea169
        try:
Packit 8ea169
            ids[sd] = workers[sd]()
Packit 8ea169
        except RuntimeError as ex:
Packit 8ea169
            logging.error("Machine-ID generator '{0}' failed: {1}"
Packit 8ea169
                        .format(sd, str(ex)))
Packit 8ea169
Packit 8ea169
    return ids
Packit 8ea169
Packit 8ea169
Packit 8ea169
def print_result(ids, outfile, prefixed):
Packit 8ea169
    """Writes a dictionary of machine ids to a file
Packit 8ea169
Packit 8ea169
    Each dictionary entry is written on a single line. The function does not
Packit 8ea169
    print trailing new-line if the dictionary contains only one item as it is
Packit 8ea169
    common format of one-liners placed in a dump directory.
Packit 8ea169
Packit 8ea169
    Keyword arguments:
Packit 8ea169
    ids -- a dictionary [generator name: machine ids]
Packit 8ea169
    outfile -- output file
Packit 8ea169
    prefixed -- use 'generator name=' prefix or not
Packit 8ea169
    """
Packit 8ea169
Packit 8ea169
    fmt = '{0}={1}' if prefixed else '{1}'
Packit 8ea169
Packit 8ea169
    if len(ids) > 1:
Packit 8ea169
        fmt += '\n'
Packit 8ea169
Packit 8ea169
    for sd, mid in ids.items():
Packit 8ea169
        outfile.write(fmt.format(sd,mid))
Packit 8ea169
Packit 8ea169
Packit 8ea169
def print_generators(outfile=None):
Packit 8ea169
    """Prints requested generators
Packit 8ea169
Packit 8ea169
    Keyword arguments:
Packit 8ea169
    outfile -- output file (default: sys.stdout)
Packit 8ea169
Packit 8ea169
    """
Packit 8ea169
    if outfile is None:
Packit 8ea169
        outfile = sys.stdout
Packit 8ea169
Packit 8ea169
    for sd in GENERATORS.keys():
Packit 8ea169
        outfile.write("{0}\n".format(sd))
Packit 8ea169
Packit 8ea169
Packit 8ea169
if __name__ == '__main__':
Packit 8ea169
    CMDARGS = ArgumentParser(description = "Generate a machine_id")
Packit 8ea169
    CMDARGS.add_argument('-o', '--output', type=str,
Packit 8ea169
            help="Output file")
Packit 8ea169
    CMDARGS.add_argument('-g', '--generators', nargs='+', type=str,
Packit 8ea169
            help="Use given generators only")
Packit 8ea169
    CMDARGS.add_argument('-l', '--list-generators', action='store_true',
Packit 8ea169
            default=False, help="Print out a list of usable generators")
Packit 8ea169
    CMDARGS.add_argument('-n', '--noprefix', action='store_true',
Packit 8ea169
            default=False, help="Do not use generator name as prefix for IDs")
Packit 8ea169
Packit 8ea169
    OPTIONS = CMDARGS.parse_args()
Packit 8ea169
    ARGS = vars(OPTIONS)
Packit 8ea169
Packit 8ea169
    logging.basicConfig(format='%(message)s')
Packit 8ea169
Packit 8ea169
    if ARGS['list_generators']:
Packit 8ea169
        print_generators()
Packit 8ea169
        sys.exit(0)
Packit 8ea169
Packit 8ea169
    requested_generators = None
Packit 8ea169
    if ARGS['generators']:
Packit 8ea169
        requested_generators = ARGS['generators']
Packit 8ea169
    else:
Packit 8ea169
        requested_generators = list(GENERATORS.keys())
Packit 8ea169
Packit 8ea169
    machineids = generate_machine_id(requested_generators)
Packit 8ea169
Packit 8ea169
    if ARGS['output']:
Packit 8ea169
        try:
Packit 8ea169
            with open(ARGS['output'], 'w') as fout:
Packit 8ea169
                print_result(machineids, fout, not ARGS['noprefix'])
Packit 8ea169
        except IOError as ex:
Packit 8ea169
            logging.error("Could not open output file: {0}".format(str(ex)))
Packit 8ea169
            sys.exit(1)
Packit 8ea169
    else:
Packit 8ea169
        print_result(machineids, sys.stdout, not ARGS['noprefix'])
Packit 8ea169
        # print_results() omits new-line for one-liners
Packit 8ea169
        if len(machineids) == 1:
Packit 8ea169
            sys.stdout.write('\n')
Packit 8ea169
Packit 8ea169
    sys.exit(len(requested_generators) - len(machineids))