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
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))