Exemplo n.º 1
0
def get_user_input():
    user_input = {}

    # Ask the user for assorted identifiers.
    for field in ['label', 'pid', '_id']:
        if settings.getboolean('DEFAULT', field):
            value = raw_input("%s: " % field).strip()
            if value:
                user_input[field] = value

    def get_option_default(opt_name, opt_class):
        try:
            default_opt = settings.get('DEFAULT', opt_name)
            default_val = opt_class(default_opt)
        except (ConfigParser.NoOptionError, ValueError):
            default_val = None
        return default_val

    def choose_from_dict(val_to_desc, msg_template, allow_empty=False):
        entry_to_item = dict(enumerate(val_to_desc.items(), start=1))
        choice_msg = '\n' + msg_template.format(
            '\n'.join('%d. %s' % (idx, desc)
                      for (idx, (_, desc)) in entry_to_item.items()),
            ("1-%d, empty to skip" if allow_empty else "1-%d") % len(entry_to_item)
        )
        entry = None
        while entry not in entry_to_item:
            if entry is not None:
                print("Invalid choice, please try again.")
            input_ = raw_input(choice_msg)
            if not input_.strip() and allow_empty:
                return None
            try:
                entry = int(input_)
            except ValueError:
                entry = -1  # invalid and not none
        (val, desc) = entry_to_item[entry]
        return val
    
    # Ask the user for several choice questions.
    for (field, opt, cls, choices, allow_empty, msg) in _user_input_questions:
        val_dflt = get_option_default(opt, cls)
        val = val_dflt if val_dflt else choose_from_dict(choices, msg, allow_empty)
        if val:
            user_input[field] = val

    # Let the user provide other information not requested previously.
    # Do this last to save the user from entering info in the comment
    # that is to be asked next.
    if settings.getboolean('DEFAULT', 'comment'):
        value = raw_input("Additional comments (empty to skip): ").strip()
        if value:
            user_input['comment'] = value
    
    return user_input
Exemplo n.º 2
0
def main(argv=None):
    if not os.geteuid() == 0:
        sys.exit("Only root can run this script")
    
    # configure logging
    setup_logging()
    logger = logging.getLogger(__name__)
    
    parser = argparse.ArgumentParser()
    
    # allow enabling/disabling debug mode
    group = parser.add_mutually_exclusive_group()
    group.add_argument('--debug', action='store_true',
            help='enable debug mode (extended output file!)')
    group.add_argument('--no-debug', dest='debug', action='store_false',
            help='disable debug mode')
    parser.set_defaults(debug=None)
    
    parser.add_argument('--smart', choices=['none', 'short', 'long'])
    parser.add_argument('--erase', choices=['ask', 'yes', 'no'])
    parser.add_argument('--stress', metavar='MINUTES', type=int,
            help='run stress test for the given MINUTES (0 to disable, default)')
    parser.add_argument('--install', choices=['ask', 'yes', 'no'],
            help='install a system image ("yes" avoids confirmation)')
    parser.add_argument('--image-name', metavar='NAME',
            help='select the system image with the given NAME for installation')
    parser.add_argument('--settings',
            help='file to be loaded as config file')
    args = parser.parse_args()
    
    # try to get custom config file from PXE server
    server = settings.get('server', 'address')
    username = settings.get('server', 'username')
    password = settings.get('server', 'password')
    
    localpath = '/tmp/remote_custom_config.ini'
    remotepath = '/home/ereuse/config.ini'
    try:
        storage.get_file_from_server(remotepath, localpath, username, password, server)
    except Exception as e:  # TODO catch specific exceptions to avoid mask errors
        logging.error("Error retrieving config file '%s' from server '%s'",
                      remotepath, server)
        logging.debug(e)
    else:
        print("Loading configuration from '%s'" % localpath)
        settings.load_config(config_file=localpath)
    
    # load specified config file (if any)
    if args.settings:
        cfg = settings.load_config(config_file=args.settings)
    
    # override settings with command line args
    if args.smart:
        settings.set('DEFAULT', 'smart', args.smart)
    if args.erase:
        settings.set('eraser', 'erase', args.erase)
    if args.stress is not None:
        settings.set('DEFAULT', 'stress', str(args.stress))
    if args.install is not None:
        settings.set('installer', 'install', args.install)
    if args.image_name is not None:
        settings.set('installer', 'image_name', args.image_name)
    if args.debug is not None:
        settings.set('DEFAULT', 'debug', str(args.debug).lower())
    
    debug = settings.getboolean('DEFAULT', 'debug')
    
    user_input = get_user_input()
    kwargs = dict(type=user_input.pop('device_type'),
                  smart=args.smart)
    
    device = Computer(**kwargs)
    # TODO move smart call here!!!
    
    # call eraser for every hard disk!
    for hd in device.hard_disk:
        hd.erasure = eraser.do_erasure(hd.logical_name)
        hd.benchmark = benchmark_hdd(hd.logical_name)
        # FIXME hack to exclude logical_name from serialization
        # create serializer where you can exclude fields
        delattr(hd, 'logical_name')
    
    data = serializers.export_to_devicehub_schema(device, user_input, debug)
    # Add a temporary, meaningless unique identifier just to avoid uploading
    # the very same file twice (this doesn't cover the case of e.g. running
    # the inventory twice on the same machine with different labels).  See
    # issue #57.
    data['_uuid'] = str(uuid.uuid4())  # random UUID
    
    # TODO save on the home
    filebase = ((data.get('label') or device.verbose_name)
                .replace(':', '-')
                .replace(os.path.sep, '-'))
    filename = "{0}.json".format(filebase)  # get_option
    localpath = os.path.join("/tmp", filename)
    with open(localpath, "w") as outfile:
        json.dump(data, outfile, indent=4, sort_keys=True, cls=InvEncoder)
    
    # sign output
    if settings.getboolean('signature', 'sign_output'):
        signed_data = utils.sign_data(json.dumps(data, indent=4, sort_keys=True, cls=InvEncoder))
        filename = "{0}.json.asc".format(filebase)
        localpath = os.path.join("/tmp", filename)
        with open(localpath, "w") as outfile:
            outfile.write(signed_data)
    
    # send files to the PXE Server
    if settings.getboolean('DEFAULT', 'sendtoserver'):
        remotepath = os.path.join(settings.get('server', 'remotepath'), filename)
        username = settings.get('server', 'username')
        password = settings.get('server', 'password')
        server = settings.get('server', 'address')
        try:
            storage.copy_file_to_server(localpath, remotepath, username, password, server)
            print("The file `{0}` has been successfully sent to the server.".format(localpath))
        except Exception as e:
            logger.error("Error copying file '%s' to server '%s'", localpath, server)
            logger.debug(e, exc_info=True)
    
    # copy file to an USB drive
    if settings.getboolean('DEFAULT', 'copy_to_usb'):
        try:
            storage.copy_file_to_usb(localpath)
        except KeyboardInterrupt:
            print("Copy to USB cancelled by user!")
        except Exception as e:
            logger.error("Error copying file '%s' to USB", localpath)
            logger.debug(e, exc_info=True)

    # run stress test
    stress_mins = settings.getint('DEFAULT', 'stress')
    if stress_mins > 0:
        print("Performing stress test for %d minutes, press Ctrl+C at any time to cancel." % stress_mins)
        try:
            if stress(stress_mins):
                print("Stress test succeeded.")
            else:
                print("Stress test failed, please note this down.")
        except KeyboardInterrupt:
            print("Stress test cancelled by user!")
        except Exception as e:
            logger.error("Error running stress test")
            logger.debug(e, exc_info=True)
    else:
        print("Skipping stress test (not enabled in remote configuration file).")

    # install system image
    install_image = settings.get('installer', 'install')
    if install_image in ('yes', 'ask'):
        image_name = settings.get('installer', 'image_name')
        print("Starting installation of system image.")
        try:
            install(name=image_name, confirm=(install_image == 'ask'))
        except KeyboardInterrupt:
            print("System installation cancelled by user!")
        except Exception as e:
            logger.error("Error installing system image")
            logger.debug(e, exc_info=True)
    else:
        print("Skipping installation (not enabled in remote configuration file).")
    
    print("Device Inventory has finished properly: {0}".format(localpath))