def _create_destinations(self): """Populate self.destinations with a list of list with them @param reset: Whether to kill existing destinations or not, defaults to false @type: bool """ dests = [] for info in self.dest_to_source_mapper.dests: # Dests should already include all destinations we want created # at this time. This method will make no assumptions of creating # defaults of any kind. source_keys = self.dest_to_source_mapper.dest_to_sources_map[info] info.name = "destination_%s" % hash(info) logger = log.getLogger(name=info.name) manager = Manager.fromInfo(logger, self.options, info) dest_class = info_to_destination_class[type(info)] dest = dest_class(config=info, logger=logger, source_keys=source_keys, options=self.options, source=self.datastore, dest=manager, terminate_event=self.terminate_event, interval=self.options[VW_GLOBAL]['interval'], oneshot=self.options[VW_GLOBAL]['oneshot']) dests.append(dest) return dests
def test_get_logger_no_config(self, open, getQueueLogger, isdir): open.return_value = None isdir.return_value = True queueLogger = log.QueueLogger('virtwho') queueLogger.logger.handlers = [] mockQueueLogger = Mock(wraps=queueLogger) getQueueLogger.return_value = mockQueueLogger conf_values = { 'global': { 'debug': False, 'background': True, 'log_file': log.DEFAULT_LOG_FILE, 'log_dir': log.DEFAULT_LOG_DIR, 'log_per_config': False } } config = StubEffectiveConfig(conf_values) log.init(config) main_logger = log.getLogger(name='main') self.assertTrue(main_logger.name == 'virtwho.main') self.assertTrue(len(main_logger.handlers) == 1) self.assertTrue(isinstance(main_logger.handlers[0], log.QueueHandler)) queue_handlers = queueLogger.logger.handlers self.assertTrue(len(queue_handlers) == 2) self.assertEqual(queue_handlers[0].baseFilename, '%s/%s' % (log.DEFAULT_LOG_DIR, log.DEFAULT_LOG_FILE))
def _create_destinations(self): """Populate self.destinations with a list of list with them @param reset: Whether to kill existing destinations or not, defaults to false @type: bool """ dests = [] for info in self.dest_to_source_mapper.dests: # Dests should already include all destinations we want created # at this time. This method will make no assumptions of creating # defaults of any kind. source_keys = self.dest_to_source_mapper.dest_to_sources_map[info] info.name = "destination_%s" % hash(info) logger = log.getLogger(name=info.name) manager = Manager.fromInfo(logger, self.options, info) dest_class = info_to_destination_class[type(info)] dest = dest_class(config=info, logger=logger, source_keys=source_keys, options=self.options, source=self.datastore, dest=manager, terminate_event=self.terminate_event, interval=self.options[VW_GLOBAL]['interval'], oneshot=self.options[VW_GLOBAL]['oneshot'], status=self.options[VW_GLOBAL]['status']) dests.append(dest) return dests
def association(self): # Apply filter logger = log.getLogger(name='virt', queue=False) assoc = [] for host in self._assoc['hypervisors']: if self.exclude_hosts is not None and self.exclude_hosts != NotSetSentinel: if self._filter(host.hypervisorId, self.exclude_hosts): logger.debug( "Skipping host '%s' because its ID was excluded by filter '%s'" % (host.hypervisorId, self.exclude_hosts)) continue else: logger.debug("Host %s passed filter %s" % (host.hypervisorId, self.exclude_hosts)) if self.filter_hosts is not None and self.filter_hosts != NotSetSentinel: if self._filter(host.hypervisorId, self.filter_hosts): logger.debug("Host %s passed filter %s" % (host.hypervisorId, self.filter_hosts)) else: logger.debug( "Skipping host '%s' because its ID was not included in filter '%s'" % (host.hypervisorId, self.filter_hosts)) continue assoc.append(host) return {'hypervisors': assoc}
def test_get_logger_different_log_file(self, getFileHandler, getQueueLogger): queueLogger = log.QueueLogger('virtwho') queueLogger.logger.handlers = [] mockQueueLogger = Mock(wraps=queueLogger) getQueueLogger.return_value = mockQueueLogger config = Mock() config.name = 'test' config.log_file = 'test.log' config.log_dir = '/test/' options = Mock() options.debug = False options.background = True options.log_per_config = True options.log_dir = '' options.log_file = '' log.init(options) test_logger = log.getLogger(name='test', config=config) self.assertTrue(test_logger.name == 'virtwho.test') self.assertTrue(len(test_logger.handlers) == 1) self.assertTrue(len(queueLogger.logger.handlers) == 1) getFileHandler.assert_called_with(name=test_logger.name, config=config)
def test_get_logger_no_config(self, open, getQueueLogger, isdir): open.return_value = None isdir.return_value = True queueLogger = log.QueueLogger('virtwho') queueLogger.logger.handlers = [] mockQueueLogger = Mock(wraps=queueLogger) getQueueLogger.return_value = mockQueueLogger options = Mock() options.debug = False options.background = True options.log_file = log.DEFAULT_LOG_FILE options.log_dir = log.DEFAULT_LOG_DIR options.log_per_config = False log.init(options) main_logger = log.getLogger(name='main') self.assertTrue(main_logger.name == 'virtwho.main') self.assertTrue(len(main_logger.handlers) == 1) self.assertTrue(isinstance(main_logger.handlers[0], log.QueueHandler)) queue_handlers = queueLogger.logger.handlers self.assertTrue(len(queue_handlers) == 1) self.assertEquals(queue_handlers[0].baseFilename, '%s/%s' % (log.DEFAULT_LOG_DIR, log.DEFAULT_LOG_FILE))
def test_get_logger_different_log_file(self, getFileHandler, getQueueLogger): queueLogger = log.QueueLogger('virtwho') queueLogger.logger.handlers = [] mockQueueLogger = Mock(wraps=queueLogger) getQueueLogger.return_value = mockQueueLogger options = { 'global': { 'debug': False, 'background': True, 'log_per_config': True, 'log_dir': '/test/', 'log_file': 'test.log', }, } log.init(options) test_logger = log.getLogger(config=options) self.assertTrue(test_logger.name == 'virtwho.test_log') self.assertTrue(len(test_logger.handlers) == 1) self.assertTrue(len(queueLogger.logger.handlers) == 2) getFileHandler.assert_called_with(name=test_logger.name, config=options)
def test_get_logger_no_config(self, open, getQueueLogger, isdir): open.return_value = None isdir.return_value = True queueLogger = log.QueueLogger('virtwho') queueLogger.logger.handlers = [] mockQueueLogger = Mock(wraps=queueLogger) getQueueLogger.return_value = mockQueueLogger options = Mock() options.debug = False options.background = True options.log_file = log.DEFAULT_LOG_FILE options.log_dir = log.DEFAULT_LOG_DIR options.log_per_config = False log.init(options) main_logger = log.getLogger(name='main') self.assertTrue(main_logger.name == 'virtwho.main') self.assertTrue(len(main_logger.handlers) == 1) self.assertTrue(isinstance(main_logger.handlers[0], log.QueueHandler)) queue_handlers = queueLogger.logger.handlers self.assertTrue(len(queue_handlers) == 1) self.assertEquals( queue_handlers[0].baseFilename, '%s/%s' % (log.DEFAULT_LOG_DIR, log.DEFAULT_LOG_FILE))
def association(self): # Apply filter logger = log.getLogger(name='virt', queue=False) assoc = [] for host in self._assoc['hypervisors']: if self.exclude_hosts is not None and self.exclude_hosts != NotSetSentinel: if self._filter(host.hypervisorId, self.exclude_hosts): logger.debug("Skipping host '%s' because its ID was excluded by filter '%s'" % (host.hypervisorId, self.exclude_hosts)) continue else: logger.debug("Host %s passed filter %s" % (host.hypervisorId, self.exclude_hosts)) if self.filter_hosts is not None and self.filter_hosts != NotSetSentinel: if self._filter(host.hypervisorId, self.filter_hosts): logger.debug("Host %s passed filter %s" % (host.hypervisorId, self.filter_hosts)) else: logger.debug("Skipping host '%s' because its ID was not included in filter '%s'" % (host.hypervisorId, self.filter_hosts)) continue assoc.append(host) return {'hypervisors': assoc}
def main(): logger = effective_config = None try: logger, effective_config = parse_options() # We now have the effective_config except OptionError as e: print(str(e), file=sys.stderr) exit(1, status="virt-who can't be started: %s" % str(e)) lock = PIDLock(PIDFILE) if lock.is_locked(): msg = "virt-who seems to be already running. If not, remove %s" % \ PIDFILE print(msg, file=sys.stderr) exit(1, status=msg) if not effective_config[VW_GLOBAL].is_valid(): message = "Required section 'global' is invalid:\n" message += "\n".join([ msg for (level, msg) in effective_config[VW_GLOBAL].validation_messages ]) message += "\n" exit(1, "virt-who can't be started: %s" % message) valid_virt_sections = [(name, section) for (name, section) in effective_config.virt_sections() if section.is_valid()] if not valid_virt_sections: err = "virt-who can't be started: no valid configuration found" logger.error(err) exit(1, err) global executor has_error = False try: executor = Executor(logger, effective_config) except (InvalidKeyFile, InvalidPasswordFormat) as e: logger.error(str(e)) exit(1, "virt-who can't be started: %s" % str(e)) if len(executor.dest_to_source_mapper.dests) == 0: if has_error: err = "virt-who can't be started: no valid destination found" logger.error(err) exit(1, err) if len(effective_config[VW_GLOBAL]['configs']) > 0: # When config file is provided using -c or --config, then other config # files in /etc/virt-who.d are ignored. When it is not possible to read # any configuration file, then virt-who should be terminated cli_config_file_readable = False for file_name in effective_config[VW_GLOBAL]['configs']: if os.path.isfile(file_name): cli_config_file_readable = True if cli_config_file_readable is False: err = 'No valid configuration file provided using -c/--config' logger.error(err) exit(1, "virt-who can't be started: %s" % str(err)) for name, config in executor.dest_to_source_mapper.configs: logger.info('Using configuration "%s" ("%s" mode)', name, config['type']) logger.info("Using reporter_id='%s'", effective_config[VW_GLOBAL]['reporter_id']) log.closeLogger(logger) with lock: signal.signal(signal.SIGHUP, reload) signal.signal(signal.SIGTERM, atexit_fn) executor.logger = logger = log.getLogger(name='main', queue=True) sd_notify("READY=1\nMAINPID=%d" % os.getpid()) while True: try: return _main(executor) except ReloadRequest: logger.info("Reloading") continue except ExitRequest as e: exit(e.code, status=e.message)
def parse_options(): """ This function parses all options from command line and environment variables :return: Tuple of logger and options """ # These options are deprecated DEPRECATED_OPTIONS = ['log_per_config', 'log_dir', 'log_file', 'reporter_id', 'virt_type', 'owner', 'env', 'server', 'username', 'password', 'sat_server', 'sat_username', 'sat_password', 'sm_type'] VIRT_TYPE_OPTIONS = ['owner', 'server', 'username', 'password'] SAT_OPTION_MAP = {'sat_server':'satellite-server', 'sat_username':'******', 'sat_password':'******'} # Read command line arguments first cli_options, errors, defaults = parse_cli_arguments() if 'version' in cli_options and cli_options['version']: print(get_version()) exit(os.EX_OK) # Read configuration env. variables env_options = read_config_env_variables() if six.PY2: # Read environments variables for virtualization backends env_options, env_errors = read_vm_backend_env_variables(env_options) errors.extend(env_errors) # Create the effective config that virt-who will use to run effective_config = init_config(env_options, cli_options) # Ensure validation errors during effective config creation are logged errors.extend(effective_config.validation_messages) logger = log.getLogger(config=effective_config, queue=False) used_deprecated_cli_options = [] for option in DEPRECATED_OPTIONS: display_option = option if option in cli_options and not cli_options[option] == defaults[option]: if option == 'virt_type' or option == 'sm_type': display_option = cli_options[option] elif any(option in s for s in VIRT_TYPE_OPTIONS): display_option = '%s-%s' % (cli_options['virt_type'], option) elif option in SAT_OPTION_MAP: display_option = SAT_OPTION_MAP[option] used_deprecated_cli_options.append(display_option) # These two flags set the value of sm_type to the default value ('sam'), so ArgumentParser will not # include them in the cli_options list, thus we have to manually check for and add them to # the deprecated list for them to be included in the warning: if '--satellite6' in _sys.argv: used_deprecated_cli_options.append('satellite6') if '--sam' in _sys.argv: used_deprecated_cli_options.append('sam') deprecated_options_msg = "The following cli options: %s are deprecated and will be removed " \ "in the next release. Please see 'man virt-who-config' for details on adding a configuration "\ "section." if used_deprecated_cli_options: logger.warning(deprecated_options_msg % ', '.join('--' + item for item in used_deprecated_cli_options)) # Log pending errors for err in errors: method = getattr(logger, err[0]) if method is not None and err[0] == 'error': method(err[1]) return logger, effective_config
def parse_options(): """ This function parses all options from command line and environment variables :return: Tuple of logger and options """ # These options are deprecated DEPRECATED_OPTIONS = ['log_per_config', 'log_dir', 'log_file', 'reporter_id', 'virt_type', 'owner', 'env', 'server', 'username', 'password', 'sat_server', 'sat_username', 'sat_password', 'sm_type'] VIRT_TYPE_OPTIONS = ['owner', 'server', 'username', 'password'] SAT_OPTION_MAP = {'sat_server': 'satellite-server', 'sat_username': '******', 'sat_password': '******'} # Read command line arguments first cli_options, errors, defaults = parse_cli_arguments() if 'version' in cli_options and cli_options['version']: print(get_version()) exit(os.EX_OK) if 'status' in cli_options and ('print' in cli_options or 'oneshot' in cli_options): print("You may not use the --print or --one-shot options with the --status option.") exit(os.EX_USAGE) if 'json' in cli_options and 'status' not in cli_options: print("The --json option must only be used with the --status option.") exit(os.EX_USAGE) # Create the effective config that virt-who will use to run effective_config = init_config(cli_options) # Ensure validation errors during effective config creation are logged errors.extend(effective_config.validation_messages) logger = log.getLogger(config=effective_config, queue=False) used_deprecated_cli_options = [] for option in DEPRECATED_OPTIONS: display_option = option if option in cli_options and not cli_options[option] == defaults[option]: if option == 'virt_type' or option == 'sm_type': display_option = cli_options[option] elif any(option in s for s in VIRT_TYPE_OPTIONS): display_option = '%s-%s' % (cli_options['virt_type'], option) elif option in SAT_OPTION_MAP: display_option = SAT_OPTION_MAP[option] used_deprecated_cli_options.append(display_option) # These two flags set the value of sm_type to the default value ('sam'), so ArgumentParser will not # include them in the cli_options list, thus we have to manually check for and add them to # the deprecated list for them to be included in the warning: if '--satellite6' in _sys.argv: used_deprecated_cli_options.append('satellite6') if '--sam' in _sys.argv: used_deprecated_cli_options.append('sam') deprecated_options_msg = ( "The following cli options: %s are deprecated and will be removed " "in the next release. Please see 'man virt-who-config' for details on adding " "a configuration section." ) if used_deprecated_cli_options: logger.warning(deprecated_options_msg % ', '.join('--' + item for item in used_deprecated_cli_options)) # Log pending errors for err in errors: method = getattr(logger, err[0]) if method is not None and err[0] == 'error': method(err[1]) return logger, effective_config
""" This module is used for parsing command line arguments and reading configuration from environment variables. """ import os import sys as _sys from argparse import ArgumentParser, Action from virtwho import log, SAT5, SAT6 from virtwho.config import NotSetSentinel, init_config, DEFAULTS, VW_ENV_CLI_SECTION_NAME from virtwho.virt.virt import Virt # Module-level logger logger = log.getLogger(name='parser', queue=False) # List of supported virtualization backends VIRT_BACKENDS = Virt.hypervisor_types() SAT5_VM_DISPATCHER = { 'libvirt': {'owner': False, 'server': False, 'username': False}, 'esx': {'owner': False, 'server': True, 'username': True}, 'rhevm': {'owner': False, 'server': True, 'username': True}, 'hyperv': {'owner': False, 'server': True, 'username': True}, 'kubevirt': {'owner': False, 'server': False, 'username': False, 'kubeconfig': True, 'kubeversion': False, 'insecure': False}, 'ahv': {'owner': False, 'server': False, 'username': False}, } SAT6_VM_DISPATCHER = { 'libvirt': {'owner': False, 'server': False, 'username': False},
def run(self): self.reloading = False if not self.options.oneshot: self.logger.debug("Starting infinite loop with %d seconds interval", self.options.interval) # Queue for getting events from virt backends if self.queue is None: self.queue = Queue() # Run the virtualization backends self.virts = [] for config in self.configManager.configs: try: logger = log.getLogger(config=config) virt = Virt.fromConfig(logger, config) except Exception as e: self.logger.error('Unable to use configuration "%s": %s', config.name, str(e)) continue # Run the process virt.start(self.queue, self.terminate_event, self.options.interval, self.options.oneshot) self.virts.append(virt) # This set is used both for oneshot mode and to bypass rate-limit # when virt-who is starting self.oneshot_remaining = set(virt.config.name for virt in self.virts) if len(self.virts) == 0: err = "virt-who can't be started: no suitable virt backend found" self.logger.error(err) exit(1, err) # queued reports depend on OrderedDict feature that if key exists # when setting an item, it will remain in the same order self.queued_reports.clear() # Clear last reports, we need to resend them when reloaded self.last_reports_hash.clear() # List of reports that are being processed by server self.reports_in_progress = [] # Send the first report immediately self.send_after = time.time() while not self.terminate_event.is_set(): if self.reports_in_progress: # Check sent report status regularly timeout = 1 elif time.time() > self.send_after: if self.queued_reports: # Reports are queued and we can send them right now, # don't wait in queue timeout = 0 else: # No reports in progress or queued and we can send report # immediately, we can wait for report as long as we want timeout = 3600 else: # We can't send report right now, wait till we can timeout = max(1, self.send_after - time.time()) # Wait for incoming report from virt backend or for timeout try: report = self.queue.get(block=True, timeout=timeout) except Empty: report = None except IOError: continue # Read rest of the reports from the queue in order to remove # obsoleted reports from same virt while True: if isinstance(report, ErrorReport): if self.options.oneshot: # Don't hang on the failed backend try: self.oneshot_remaining.remove(report.config.name) except KeyError: pass self.logger.warn('Unable to collect report for config "%s"', report.config.name) elif isinstance(report, AbstractVirtReport): if self.last_reports_hash.get(report.config.name, None) == report.hash: self.logger.info('Report for config "%s" hasn\'t changed, not sending', report.config.name) else: if report.config.name in self.oneshot_remaining: # Send the report immediately self.oneshot_remaining.remove(report.config.name) if not self.options.print_: self.send_report(report.config.name, report) else: self.queued_reports[report.config.name] = report else: self.queued_reports[report.config.name] = report elif report in ['exit', 'reload']: # Reload and exit reports takes priority, do not process # any other reports break # Get next report from queue try: report = self.queue.get(block=False) except Empty: break if report == 'exit': break elif report == 'reload': self.stop_virts() raise ReloadRequest() self.check_reports_state() if not self.reports_in_progress and self.queued_reports and time.time() > self.send_after: # No report is processed, send next one if not self.options.print_: self.send_current_report() if self.options.oneshot and not self.oneshot_remaining and not self.reports_in_progress: break self.queue = None self.stop_virts() self.virt = [] if self.options.print_: return self.queued_reports
def main(): logger = options = None try: logger, options = parse_options() # We now have the effective_config except OptionError as e: print(str(e), file=sys.stderr) exit(1, status="virt-who can't be started: %s" % str(e)) lock = PIDLock(PIDFILE) if lock.is_locked(): msg = "virt-who seems to be already running. If not, remove %s" % \ PIDFILE print(msg, file=sys.stderr) exit(1, status=msg) if not options[VW_GLOBAL].is_valid(): message = "Required section 'global' is invalid:\n" message += "\n".join([msg for (level, msg) in options[VW_GLOBAL].validation_messages]) message += "\n" exit(1, "virt-who can't be started: %s" % message) valid_virt_sections = [(name, section) for (name, section) in options.virt_sections() if section.is_valid()] if not valid_virt_sections: err = "virt-who can't be started: no valid configuration found" logger.error(err) exit(1, err) global executor has_error = False try: executor = Executor(logger, options) except (InvalidKeyFile, InvalidPasswordFormat) as e: logger.error(str(e)) exit(1, "virt-who can't be started: %s" % str(e)) if len(executor.dest_to_source_mapper.dests) == 0: if has_error: err = "virt-who can't be started: no valid destination found" logger.error(err) exit(1, err) for name, config in executor.dest_to_source_mapper.configs: logger.info('Using configuration "%s" ("%s" mode)', name, config['type']) logger.info("Using reporter_id='%s'", options[VW_GLOBAL]['reporter_id']) log.closeLogger(logger) with lock: signal.signal(signal.SIGHUP, reload) signal.signal(signal.SIGTERM, atexit_fn) executor.logger = logger = log.getLogger(name='main', queue=True) sd_notify("READY=1\nMAINPID=%d" % os.getpid()) while True: try: return _main(executor) except ReloadRequest: logger.info("Reloading") continue except ExitRequest as e: exit(e.code, status=e.message)
def main(): logger = options = None try: logger, options = parseOptions() except OptionError as e: print >>sys.stderr, str(e) exit(1, status="virt-who can't be started: %s" % str(e)) lock = PIDLock(PIDFILE) if lock.is_locked(): msg = "virt-who seems to be already running. If not, remove %s" % PIDFILE print >>sys.stderr, msg exit(1, status=msg) global executor try: executor = Executor(logger, options) except (InvalidKeyFile, InvalidPasswordFormat) as e: logger.error(str(e)) exit(1, "virt-who can't be started: %s" % str(e)) if options.virtType is not None: config = Config("env/cmdline", options.virtType, executor.configManager._defaults, **options) try: config.checkOptions(logger) except InvalidOption as e: err = "virt-who can't be started: %s" % str(e) logger.error(err) exit(1, err) executor.configManager.addConfig(config) has_error = False for conffile in options.configs: try: executor.configManager.readFile(conffile) except InvalidPasswordFormat as e: err = "virt-who can't be started: %s" % str(e) logger.error(err) exit(1, err) except Exception as e: logger.error('Config file "%s" skipped because of an error: %s', conffile, str(e)) has_error = True if len(executor.configManager.configs) == 0: if has_error: err = "virt-who can't be started: no valid configuration found" logger.error(err) exit(1, err) # In order to keep compatibility with older releases of virt-who, # fallback to using libvirt as default virt backend logger.info("No configurations found, using libvirt as backend") executor.configManager.addConfig(Config("env/cmdline", "libvirt")) for config in executor.configManager.configs: if config.name is None: logger.info('Using commandline or sysconfig configuration ("%s" mode)', config.type) else: logger.info('Using configuration "%s" ("%s" mode)', config.name, config.type) logger.info("Using reporter_id='%s'", options.reporter_id) log.closeLogger(logger) if options.background: locker = lambda: daemon.DaemonContext(pidfile=lock) # flake8: noqa else: locker = lambda: lock # flake8: noqa with locker(): signal.signal(signal.SIGHUP, reload) signal.signal(signal.SIGTERM, atexit_fn) executor.logger = logger = log.getLogger(name='main', config=None, queue=True) sd_notify("READY=1\nMAINPID=%d" % os.getpid()) while True: try: return _main(executor) except ReloadRequest: logger.info("Reloading") continue
def parseOptions(): parser = OptionParserEpilog( usage="virt-who [-d] [-i INTERVAL] [-o] [--sam|--satellite5|--satellite6] [--libvirt|--vdsm|--esx|--rhevm|--hyperv|--xen]", description="Agent for reporting virtual guest IDs to subscription manager", epilog="virt-who also reads environment variables. They have the same name as command line arguments but uppercased, with underscore instead of dash and prefixed with VIRTWHO_ (e.g. VIRTWHO_ONE_SHOT). Empty variables are considered as disabled, non-empty as enabled", ) parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Enable debugging output") parser.add_option( "-o", "--one-shot", action="store_true", dest="oneshot", default=False, help="Send the list of guest IDs and exit immediately", ) parser.add_option( "-i", "--interval", type="int", dest="interval", default=NotSetSentinel(), help="Acquire list of virtual guest each N seconds. Send if changes are detected.", ) parser.add_option( "-p", "--print", action="store_true", dest="print_", default=False, help="Print the host/guest association obtained from virtualization backend (implies oneshot)", ) parser.add_option( "-c", "--config", action="append", dest="configs", default=[], help="Configuration file that will be processed, can be used multiple times", ) parser.add_option( "-m", "--log-per-config", action="store_true", dest="log_per_config", default=NotSetSentinel(), help="Write one log file per configured virtualization backend.\nImplies a log_dir of %s/virtwho (Default: all messages are written to a single log file)" % log.DEFAULT_LOG_DIR, ) parser.add_option( "-l", "--log-dir", action="store", dest="log_dir", default=log.DEFAULT_LOG_DIR, help="The absolute path of the directory to log to. (Default '%s')" % log.DEFAULT_LOG_DIR, ) parser.add_option( "-f", "--log-file", action="store", dest="log_file", default=log.DEFAULT_LOG_FILE, help="The file name to write logs to. (Default '%s')" % log.DEFAULT_LOG_FILE, ) parser.add_option( "-r", "--reporter-id", action="store", dest="reporter_id", default=NotSetSentinel(), help="Label host/guest associations obtained by this instance of virt-who with the provided id.", ) virtGroup = OptionGroup( parser, "Virtualization backend", "Choose virtualization backend that should be used to gather host/guest associations", ) virtGroup.add_option( "--libvirt", action="store_const", dest="virtType", const="libvirt", default=None, help="Use libvirt to list virtual guests [default]", ) virtGroup.add_option( "--vdsm", action="store_const", dest="virtType", const="vdsm", help="Use vdsm to list virtual guests" ) virtGroup.add_option( "--esx", action="store_const", dest="virtType", const="esx", help="Register ESX machines using vCenter" ) virtGroup.add_option( "--xen", action="store_const", dest="virtType", const="xen", help="Register XEN machines using XenServer" ) virtGroup.add_option( "--rhevm", action="store_const", dest="virtType", const="rhevm", help="Register guests using RHEV-M" ) virtGroup.add_option( "--hyperv", action="store_const", dest="virtType", const="hyperv", help="Register guests using Hyper-V" ) parser.add_option_group(virtGroup) managerGroup = OptionGroup( parser, "Subscription manager", "Choose where the host/guest associations should be reported" ) managerGroup.add_option( "--sam", action="store_const", dest="smType", const=SAT6, default=SAT6, help="Report host/guest associations to the Subscription Asset Manager [default]", ) managerGroup.add_option( "--satellite6", action="store_const", dest="smType", const=SAT6, help="Report host/guest associations to the Satellite 6 server", ) managerGroup.add_option( "--satellite5", action="store_const", dest="smType", const=SAT5, help="Report host/guest associations to the Satellite 5 server", ) managerGroup.add_option("--satellite", action="store_const", dest="smType", const=SAT5, help=SUPPRESS_HELP) parser.add_option_group(managerGroup) libvirtGroup = OptionGroup(parser, "Libvirt options", "Use these options with --libvirt") libvirtGroup.add_option( "--libvirt-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products, default is owner of current system", ) libvirtGroup.add_option( "--libvirt-env", action="store", dest="env", default="", help="Environment where the server belongs to, default is environment of current system", ) libvirtGroup.add_option( "--libvirt-server", action="store", dest="server", default="", help="URL of the libvirt server to connect to, default is empty for libvirt on local computer", ) libvirtGroup.add_option( "--libvirt-username", action="store", dest="username", default="", help="Username for connecting to the libvirt daemon", ) libvirtGroup.add_option( "--libvirt-password", action="store", dest="password", default="", help="Password for connecting to the libvirt daemon", ) parser.add_option_group(libvirtGroup) esxGroup = OptionGroup(parser, "vCenter/ESX options", "Use these options with --esx") esxGroup.add_option( "--esx-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products", ) esxGroup.add_option( "--esx-env", action="store", dest="env", default="", help="Environment where the vCenter server belongs to" ) esxGroup.add_option( "--esx-server", action="store", dest="server", default="", help="URL of the vCenter server to connect to" ) esxGroup.add_option( "--esx-username", action="store", dest="username", default="", help="Username for connecting to vCenter" ) esxGroup.add_option( "--esx-password", action="store", dest="password", default="", help="Password for connecting to vCenter" ) parser.add_option_group(esxGroup) rhevmGroup = OptionGroup(parser, "RHEV-M options", "Use these options with --rhevm") rhevmGroup.add_option( "--rhevm-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products", ) rhevmGroup.add_option( "--rhevm-env", action="store", dest="env", default="", help="Environment where the RHEV-M belongs to" ) rhevmGroup.add_option( "--rhevm-server", action="store", dest="server", default="", help="URL of the RHEV-M server to connect to (preferable use secure connection - https://<ip or domain name>:<secure port, usually 8443>)", ) rhevmGroup.add_option( "--rhevm-username", action="store", dest="username", default="", help="Username for connecting to RHEV-M in the format username@domain", ) rhevmGroup.add_option( "--rhevm-password", action="store", dest="password", default="", help="Password for connecting to RHEV-M" ) parser.add_option_group(rhevmGroup) hypervGroup = OptionGroup(parser, "Hyper-V options", "Use these options with --hyperv") hypervGroup.add_option( "--hyperv-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products", ) hypervGroup.add_option( "--hyperv-env", action="store", dest="env", default="", help="Environment where the Hyper-V belongs to" ) hypervGroup.add_option( "--hyperv-server", action="store", dest="server", default="", help="URL of the Hyper-V server to connect to" ) hypervGroup.add_option( "--hyperv-username", action="store", dest="username", default="", help="Username for connecting to Hyper-V" ) hypervGroup.add_option( "--hyperv-password", action="store", dest="password", default="", help="Password for connecting to Hyper-V" ) parser.add_option_group(hypervGroup) xenGroup = OptionGroup(parser, "XenServer options", "Use these options with --xen") xenGroup.add_option( "--xen-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products", ) xenGroup.add_option( "--xen-env", action="store", dest="env", default="", help="Environment where the XenServer belongs to" ) xenGroup.add_option( "--xen-server", action="store", dest="server", default="", help="URL of the XenServer server to connect to" ) xenGroup.add_option( "--xen-username", action="store", dest="username", default="", help="Username for connecting to XenServer" ) xenGroup.add_option( "--xen-password", action="store", dest="password", default="", help="Password for connecting to XenServer" ) parser.add_option_group(xenGroup) satelliteGroup = OptionGroup(parser, "Satellite 5 options", "Use these options with --satellite5") satelliteGroup.add_option( "--satellite-server", action="store", dest="sat_server", default="", help="Satellite server URL" ) satelliteGroup.add_option( "--satellite-username", action="store", dest="sat_username", default="", help="Username for connecting to Satellite server", ) satelliteGroup.add_option( "--satellite-password", action="store", dest="sat_password", default="", help="Password for connecting to Satellite server", ) parser.add_option_group(satelliteGroup) (cli_options, args) = parser.parse_args() options = GlobalConfig.fromFile(VIRTWHO_GENERAL_CONF_PATH) # Handle defaults from the command line options parser options.update(**parser.defaults) # Handle environment variables env = os.getenv("VIRTWHO_LOG_PER_CONFIG", "0").strip().lower() if env in ["1", "true"]: options.log_per_config = True env = os.getenv("VIRTWHO_LOG_DIR", log.DEFAULT_LOG_DIR).strip() if env != log.DEFAULT_LOG_DIR: options.log_dir = env elif options.log_per_config: options.log_dir = os.path.join(log.DEFAULT_LOG_DIR, "virtwho") env = os.getenv("VIRTWHO_LOG_FILE", log.DEFAULT_LOG_FILE).strip() if env != log.DEFAULT_LOG_FILE: options.log_file = env env = os.getenv("VIRTWHO_REPORTER_ID", "").strip() if len(env) > 0: options.reporter_id = env env = os.getenv("VIRTWHO_DEBUG", "0").strip().lower() if env in ["1", "true"] or cli_options.debug is True: options.debug = True # Used only when starting as service (initscript sets it to 1, systemd to 0) env = os.getenv("VIRTWHO_BACKGROUND", "0").strip().lower() options.background = env in ["1", "true"] log.init(options) logger = log.getLogger(name="init", queue=False) env = os.getenv("VIRTWHO_ONE_SHOT", "0").strip().lower() if env in ["1", "true"]: options.oneshot = True env = os.getenv("VIRTWHO_INTERVAL") if env: try: env = int(env.strip().lower()) if env >= MinimumSendInterval: options.interval = env elif env < MinimumSendInterval: options.interval = MinimumSendInterval except ValueError: logger.warning("Interval is not number, ignoring") env = os.getenv("VIRTWHO_SAM", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT6 env = os.getenv("VIRTWHO_SATELLITE6", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT6 env = os.getenv("VIRTWHO_SATELLITE5", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT5 env = os.getenv("VIRTWHO_SATELLITE", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT5 env = os.getenv("VIRTWHO_LIBVIRT", "0").strip().lower() if env in ["1", "true"]: options.virtType = "libvirt" env = os.getenv("VIRTWHO_VDSM", "0").strip().lower() if env in ["1", "true"]: options.virtType = "vdsm" env = os.getenv("VIRTWHO_ESX", "0").strip().lower() if env in ["1", "true"]: options.virtType = "esx" env = os.getenv("VIRTWHO_XEN", "0").strip().lower() if env in ["1", "true"]: options.virtType = "xen" env = os.getenv("VIRTWHO_RHEVM", "0").strip().lower() if env in ["1", "true"]: options.virtType = "rhevm" env = os.getenv("VIRTWHO_HYPERV", "0").strip().lower() if env in ["1", "true"]: options.virtType = "hyperv" def getNonDefaultOptions(cli_options, defaults): return dict( (option, value) for option, value in cli_options.iteritems() if defaults.get(option, NotSetSentinel()) != value ) # Handle non-default command line options options.update(**getNonDefaultOptions(vars(cli_options), parser.defaults)) # Check Env def checkEnv(variable, option, name, required=True): """ If `option` is empty, check environment `variable` and return its value. Exit if it's still empty """ if not option or len(option) == 0: option = os.getenv(variable, "").strip() if required and (not option or len(option) == 0): raise OptionError("Required parameter '%s' is not set, exiting" % name) return option if options.smType == SAT5: options.sat_server = checkEnv("VIRTWHO_SATELLITE_SERVER", options.sat_server, "satellite-server") options.sat_username = checkEnv("VIRTWHO_SATELLITE_USERNAME", options.sat_username, "satellite-username") if len(options.sat_password) == 0: options.sat_password = os.getenv("VIRTWHO_SATELLITE_PASSWORD", "") if options.virtType == "libvirt": options.owner = checkEnv("VIRTWHO_LIBVIRT_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_LIBVIRT_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_LIBVIRT_SERVER", options.server, "server", required=False) options.username = checkEnv("VIRTWHO_LIBVIRT_USERNAME", options.username, "username", required=False) if len(options.password) == 0: options.password = os.getenv("VIRTWHO_LIBVIRT_PASSWORD", "") if options.virtType == "esx": options.owner = checkEnv("VIRTWHO_ESX_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_ESX_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_ESX_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_ESX_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_ESX_PASSWORD", "") if options.virtType == "xen": options.owner = checkEnv("VIRTWHO_XEN_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_XEN_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_XEN_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_XEN_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_XEN_PASSWORD", "") if options.virtType == "rhevm": options.owner = checkEnv("VIRTWHO_RHEVM_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_RHEVM_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_RHEVM_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_RHEVM_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_RHEVM_PASSWORD", "") if options.virtType == "hyperv": options.owner = checkEnv("VIRTWHO_HYPERV_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_HYPERV_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_HYPERV_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_HYPERV_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_HYPERV_PASSWORD", "") if options.smType == "sam" and options.virtType in ("esx", "rhevm", "hyperv", "xen"): if not options.owner: raise OptionError( "Option --%s-owner (or VIRTWHO_%s_OWNER environment variable) needs to be set" % (options.virtType, options.virtType.upper()) ) if not options.env: raise OptionError( "Option --%s-env (or VIRTWHO_%s_ENV environment variable) needs to be set" % (options.virtType, options.virtType.upper()) ) if not options.interval or options.interval == parser.defaults["interval"]: logger.info("Interval set to the default of %d seconds.", DefaultInterval) options.interval = DefaultInterval elif options.interval < MinimumSendInterval: logger.warning( "Interval value can't be lower than {min} seconds. Default value of {min} seconds will be used.".format( min=MinimumSendInterval ) ) options.interval = MinimumSendInterval if options.print_: options.oneshot = True return logger, options
def run(self): self.reloading = False if not self.options.oneshot: self.logger.debug( "Starting infinite loop with %d seconds interval", self.options.interval) # Queue for getting events from virt backends if self.queue is None: self.queue = Queue() # Run the virtualization backends self.virts = [] for config in self.configManager.configs: try: logger = log.getLogger(config=config) virt = Virt.fromConfig(logger, config) except Exception as e: self.logger.error('Unable to use configuration "%s": %s', config.name, str(e)) continue # Run the process virt.start(self.queue, self.terminate_event, self.options.interval, self.options.oneshot) self.virts.append(virt) # This set is used both for oneshot mode and to bypass rate-limit # when virt-who is starting self.oneshot_remaining = set(virt.config.name for virt in self.virts) if len(self.virts) == 0: err = "virt-who can't be started: no suitable virt backend found" self.logger.error(err) exit(1, err) # queued reports depend on OrderedDict feature that if key exists # when setting an item, it will remain in the same order self.queued_reports.clear() # Clear last reports, we need to resend them when reloaded self.last_reports_hash.clear() # List of reports that are being processed by server self.reports_in_progress = [] # Send the first report immediately self.send_after = time.time() while not self.terminate_event.is_set(): if self.reports_in_progress: # Check sent report status regularly timeout = 1 elif time.time() > self.send_after: if self.queued_reports: # Reports are queued and we can send them right now, # don't wait in queue timeout = 0 else: # No reports in progress or queued and we can send report # immediately, we can wait for report as long as we want timeout = 3600 else: # We can't send report right now, wait till we can timeout = max(1, self.send_after - time.time()) # Wait for incoming report from virt backend or for timeout try: report = self.queue.get(block=True, timeout=timeout) except Empty: report = None except IOError: continue # Read rest of the reports from the queue in order to remove # obsoleted reports from same virt while True: if isinstance(report, ErrorReport): if self.options.oneshot: # Don't hang on the failed backend try: self.oneshot_remaining.remove(report.config.name) except KeyError: pass self.logger.warn( 'Unable to collect report for config "%s"', report.config.name) elif isinstance(report, AbstractVirtReport): if self.last_reports_hash.get(report.config.name, None) == report.hash: self.logger.info( 'Report for config "%s" hasn\'t changed, not sending', report.config.name) else: if report.config.name in self.oneshot_remaining: # Send the report immediately self.oneshot_remaining.remove(report.config.name) if not self.options.print_: self.send_report(report.config.name, report) else: self.queued_reports[ report.config.name] = report else: self.queued_reports[report.config.name] = report elif report in ['exit', 'reload']: # Reload and exit reports takes priority, do not process # any other reports break # Get next report from queue try: report = self.queue.get(block=False) except Empty: break if report == 'exit': break elif report == 'reload': self.stop_virts() raise ReloadRequest() self.check_reports_state() if not self.reports_in_progress and self.queued_reports and time.time( ) > self.send_after: # No report is processed, send next one if not self.options.print_: self.send_current_report() if self.options.oneshot and not self.oneshot_remaining and not self.reports_in_progress: break self.queue = None self.stop_virts() self.virt = [] if self.options.print_: return self.queued_reports
def parseOptions(): parser = OptionParserEpilog( usage= "virt-who [-d] [-i INTERVAL] [-o] [--sam|--satellite5|--satellite6] [--libvirt|--vdsm|--esx|--rhevm|--hyperv|--xen]", description= "Agent for reporting virtual guest IDs to subscription manager", epilog= "virt-who also reads environment variables. They have the same name as command line arguments but uppercased, with underscore instead of dash and prefixed with VIRTWHO_ (e.g. VIRTWHO_ONE_SHOT). Empty variables are considered as disabled, non-empty as enabled" ) parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Enable debugging output") parser.add_option("-o", "--one-shot", action="store_true", dest="oneshot", default=False, help="Send the list of guest IDs and exit immediately") parser.add_option( "-i", "--interval", type="int", dest="interval", default=NotSetSentinel(), help= "Acquire list of virtual guest each N seconds. Send if changes are detected." ) parser.add_option( "-p", "--print", action="store_true", dest="print_", default=False, help= "Print the host/guest association obtained from virtualization backend (implies oneshot)" ) parser.add_option( "-c", "--config", action="append", dest="configs", default=[], help= "Configuration file that will be processed, can be used multiple times" ) parser.add_option( "-m", "--log-per-config", action="store_true", dest="log_per_config", default=NotSetSentinel(), help= "Write one log file per configured virtualization backend.\nImplies a log_dir of %s/virtwho (Default: all messages are written to a single log file)" % log.DEFAULT_LOG_DIR) parser.add_option( "-l", "--log-dir", action="store", dest="log_dir", default=log.DEFAULT_LOG_DIR, help="The absolute path of the directory to log to. (Default '%s')" % log.DEFAULT_LOG_DIR) parser.add_option("-f", "--log-file", action="store", dest="log_file", default=log.DEFAULT_LOG_FILE, help="The file name to write logs to. (Default '%s')" % log.DEFAULT_LOG_FILE) parser.add_option( "-r", "--reporter-id", action="store", dest="reporter_id", default=NotSetSentinel(), help= "Label host/guest associations obtained by this instance of virt-who with the provided id." ) virtGroup = OptionGroup( parser, "Virtualization backend", "Choose virtualization backend that should be used to gather host/guest associations" ) virtGroup.add_option("--libvirt", action="store_const", dest="virtType", const="libvirt", default=None, help="Use libvirt to list virtual guests [default]") virtGroup.add_option("--vdsm", action="store_const", dest="virtType", const="vdsm", help="Use vdsm to list virtual guests") virtGroup.add_option("--esx", action="store_const", dest="virtType", const="esx", help="Register ESX machines using vCenter") virtGroup.add_option("--xen", action="store_const", dest="virtType", const="xen", help="Register XEN machines using XenServer") virtGroup.add_option("--rhevm", action="store_const", dest="virtType", const="rhevm", help="Register guests using RHEV-M") virtGroup.add_option("--hyperv", action="store_const", dest="virtType", const="hyperv", help="Register guests using Hyper-V") parser.add_option_group(virtGroup) managerGroup = OptionGroup( parser, "Subscription manager", "Choose where the host/guest associations should be reported") managerGroup.add_option( "--sam", action="store_const", dest="smType", const=SAT6, default=SAT6, help= "Report host/guest associations to the Subscription Asset Manager [default]" ) managerGroup.add_option( "--satellite6", action="store_const", dest="smType", const=SAT6, help="Report host/guest associations to the Satellite 6 server") managerGroup.add_option( "--satellite5", action="store_const", dest="smType", const=SAT5, help="Report host/guest associations to the Satellite 5 server") managerGroup.add_option("--satellite", action="store_const", dest="smType", const=SAT5, help=SUPPRESS_HELP) parser.add_option_group(managerGroup) libvirtGroup = OptionGroup(parser, "Libvirt options", "Use these options with --libvirt") libvirtGroup.add_option( "--libvirt-owner", action="store", dest="owner", default="", help= "Organization who has purchased subscriptions of the products, default is owner of current system" ) libvirtGroup.add_option( "--libvirt-env", action="store", dest="env", default="", help= "Environment where the server belongs to, default is environment of current system" ) libvirtGroup.add_option( "--libvirt-server", action="store", dest="server", default="", help= "URL of the libvirt server to connect to, default is empty for libvirt on local computer" ) libvirtGroup.add_option( "--libvirt-username", action="store", dest="username", default="", help="Username for connecting to the libvirt daemon") libvirtGroup.add_option( "--libvirt-password", action="store", dest="password", default="", help="Password for connecting to the libvirt daemon") parser.add_option_group(libvirtGroup) esxGroup = OptionGroup(parser, "vCenter/ESX options", "Use these options with --esx") esxGroup.add_option( "--esx-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products") esxGroup.add_option("--esx-env", action="store", dest="env", default="", help="Environment where the vCenter server belongs to") esxGroup.add_option("--esx-server", action="store", dest="server", default="", help="URL of the vCenter server to connect to") esxGroup.add_option("--esx-username", action="store", dest="username", default="", help="Username for connecting to vCenter") esxGroup.add_option("--esx-password", action="store", dest="password", default="", help="Password for connecting to vCenter") parser.add_option_group(esxGroup) rhevmGroup = OptionGroup(parser, "RHEV-M options", "Use these options with --rhevm") rhevmGroup.add_option( "--rhevm-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products") rhevmGroup.add_option("--rhevm-env", action="store", dest="env", default="", help="Environment where the RHEV-M belongs to") rhevmGroup.add_option( "--rhevm-server", action="store", dest="server", default="", help= "URL of the RHEV-M server to connect to (preferable use secure connection - https://<ip or domain name>:<secure port, usually 8443>)" ) rhevmGroup.add_option( "--rhevm-username", action="store", dest="username", default="", help="Username for connecting to RHEV-M in the format username@domain") rhevmGroup.add_option("--rhevm-password", action="store", dest="password", default="", help="Password for connecting to RHEV-M") parser.add_option_group(rhevmGroup) hypervGroup = OptionGroup(parser, "Hyper-V options", "Use these options with --hyperv") hypervGroup.add_option( "--hyperv-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products") hypervGroup.add_option("--hyperv-env", action="store", dest="env", default="", help="Environment where the Hyper-V belongs to") hypervGroup.add_option("--hyperv-server", action="store", dest="server", default="", help="URL of the Hyper-V server to connect to") hypervGroup.add_option("--hyperv-username", action="store", dest="username", default="", help="Username for connecting to Hyper-V") hypervGroup.add_option("--hyperv-password", action="store", dest="password", default="", help="Password for connecting to Hyper-V") parser.add_option_group(hypervGroup) xenGroup = OptionGroup(parser, "XenServer options", "Use these options with --xen") xenGroup.add_option( "--xen-owner", action="store", dest="owner", default="", help="Organization who has purchased subscriptions of the products") xenGroup.add_option("--xen-env", action="store", dest="env", default="", help="Environment where the XenServer belongs to") xenGroup.add_option("--xen-server", action="store", dest="server", default="", help="URL of the XenServer server to connect to") xenGroup.add_option("--xen-username", action="store", dest="username", default="", help="Username for connecting to XenServer") xenGroup.add_option("--xen-password", action="store", dest="password", default="", help="Password for connecting to XenServer") parser.add_option_group(xenGroup) satelliteGroup = OptionGroup(parser, "Satellite 5 options", "Use these options with --satellite5") satelliteGroup.add_option("--satellite-server", action="store", dest="sat_server", default="", help="Satellite server URL") satelliteGroup.add_option( "--satellite-username", action="store", dest="sat_username", default="", help="Username for connecting to Satellite server") satelliteGroup.add_option( "--satellite-password", action="store", dest="sat_password", default="", help="Password for connecting to Satellite server") parser.add_option_group(satelliteGroup) (cli_options, args) = parser.parse_args() options = GlobalConfig.fromFile(VIRTWHO_GENERAL_CONF_PATH) # Handle defaults from the command line options parser options.update(**parser.defaults) # Handle environment variables env = os.getenv("VIRTWHO_LOG_PER_CONFIG", "0").strip().lower() if env in ["1", "true"]: options.log_per_config = True env = os.getenv("VIRTWHO_LOG_DIR", log.DEFAULT_LOG_DIR).strip() if env != log.DEFAULT_LOG_DIR: options.log_dir = env elif options.log_per_config: options.log_dir = os.path.join(log.DEFAULT_LOG_DIR, 'virtwho') env = os.getenv("VIRTWHO_LOG_FILE", log.DEFAULT_LOG_FILE).strip() if env != log.DEFAULT_LOG_FILE: options.log_file = env env = os.getenv("VIRTWHO_REPORTER_ID", "").strip() if len(env) > 0: options.reporter_id = env env = os.getenv("VIRTWHO_DEBUG", "0").strip().lower() if env in ["1", "true"] or cli_options.debug is True: options.debug = True # Used only when starting as service (initscript sets it to 1, systemd to 0) env = os.getenv("VIRTWHO_BACKGROUND", "0").strip().lower() options.background = env in ["1", "true"] log.init(options) logger = log.getLogger(name='init', queue=False) env = os.getenv("VIRTWHO_ONE_SHOT", "0").strip().lower() if env in ["1", "true"]: options.oneshot = True env = os.getenv("VIRTWHO_INTERVAL") if env: try: env = int(env.strip().lower()) if env >= MinimumSendInterval: options.interval = env elif env < MinimumSendInterval: options.interval = MinimumSendInterval except ValueError: logger.warning("Interval is not number, ignoring") env = os.getenv("VIRTWHO_SAM", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT6 env = os.getenv("VIRTWHO_SATELLITE6", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT6 env = os.getenv("VIRTWHO_SATELLITE5", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT5 env = os.getenv("VIRTWHO_SATELLITE", "0").strip().lower() if env in ["1", "true"]: options.smType = SAT5 env = os.getenv("VIRTWHO_LIBVIRT", "0").strip().lower() if env in ["1", "true"]: options.virtType = "libvirt" env = os.getenv("VIRTWHO_VDSM", "0").strip().lower() if env in ["1", "true"]: options.virtType = "vdsm" env = os.getenv("VIRTWHO_ESX", "0").strip().lower() if env in ["1", "true"]: options.virtType = "esx" env = os.getenv("VIRTWHO_XEN", "0").strip().lower() if env in ["1", "true"]: options.virtType = "xen" env = os.getenv("VIRTWHO_RHEVM", "0").strip().lower() if env in ["1", "true"]: options.virtType = "rhevm" env = os.getenv("VIRTWHO_HYPERV", "0").strip().lower() if env in ["1", "true"]: options.virtType = "hyperv" def getNonDefaultOptions(cli_options, defaults): return dict((option, value) for option, value in cli_options.iteritems() if defaults.get(option, NotSetSentinel()) != value) # Handle non-default command line options options.update(**getNonDefaultOptions(vars(cli_options), parser.defaults)) # Check Env def checkEnv(variable, option, name, required=True): """ If `option` is empty, check environment `variable` and return its value. Exit if it's still empty """ if not option or len(option) == 0: option = os.getenv(variable, "").strip() if required and (not option or len(option) == 0): raise OptionError("Required parameter '%s' is not set, exiting" % name) return option if options.smType == SAT5: options.sat_server = checkEnv("VIRTWHO_SATELLITE_SERVER", options.sat_server, "satellite-server") options.sat_username = checkEnv("VIRTWHO_SATELLITE_USERNAME", options.sat_username, "satellite-username") if len(options.sat_password) == 0: options.sat_password = os.getenv("VIRTWHO_SATELLITE_PASSWORD", "") if options.virtType == "libvirt": options.owner = checkEnv("VIRTWHO_LIBVIRT_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_LIBVIRT_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_LIBVIRT_SERVER", options.server, "server", required=False) options.username = checkEnv("VIRTWHO_LIBVIRT_USERNAME", options.username, "username", required=False) if len(options.password) == 0: options.password = os.getenv("VIRTWHO_LIBVIRT_PASSWORD", "") if options.virtType == "esx": options.owner = checkEnv("VIRTWHO_ESX_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_ESX_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_ESX_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_ESX_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_ESX_PASSWORD", "") if options.virtType == "xen": options.owner = checkEnv("VIRTWHO_XEN_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_XEN_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_XEN_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_XEN_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_XEN_PASSWORD", "") if options.virtType == "rhevm": options.owner = checkEnv("VIRTWHO_RHEVM_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_RHEVM_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_RHEVM_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_RHEVM_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_RHEVM_PASSWORD", "") if options.virtType == "hyperv": options.owner = checkEnv("VIRTWHO_HYPERV_OWNER", options.owner, "owner", required=False) options.env = checkEnv("VIRTWHO_HYPERV_ENV", options.env, "env", required=False) options.server = checkEnv("VIRTWHO_HYPERV_SERVER", options.server, "server") options.username = checkEnv("VIRTWHO_HYPERV_USERNAME", options.username, "username") if len(options.password) == 0: options.password = os.getenv("VIRTWHO_HYPERV_PASSWORD", "") if options.smType == 'sam' and options.virtType in ('esx', 'rhevm', 'hyperv', 'xen'): if not options.owner: raise OptionError( "Option --%s-owner (or VIRTWHO_%s_OWNER environment variable) needs to be set" % (options.virtType, options.virtType.upper())) if not options.env: raise OptionError( "Option --%s-env (or VIRTWHO_%s_ENV environment variable) needs to be set" % (options.virtType, options.virtType.upper())) if not options.interval or options.interval == parser.defaults['interval']: logger.info("Interval set to the default of %d seconds.", DefaultInterval) options.interval = DefaultInterval elif options.interval < MinimumSendInterval: logger.warning( "Interval value can't be lower than {min} seconds. Default value of {min} seconds will be used." .format(min=MinimumSendInterval)) options.interval = MinimumSendInterval if options.print_: options.oneshot = True return logger, options
def main(): logger = effective_config = None try: logger, effective_config = parse_options() # We now have the effective_config except OptionError as e: print(str(e), file=sys.stderr) exit(1, status="virt-who can't be started: %s" % str(e)) lock = PIDLock(PIDFILE) if lock.is_locked(): msg = "virt-who seems to be already running. If not, remove %s" % \ PIDFILE print(msg, file=sys.stderr) exit(1, status=msg) if not effective_config[VW_GLOBAL].is_valid(): message = "Required section 'global' is invalid:\n" message += "\n".join([msg for (level, msg) in effective_config[VW_GLOBAL].validation_messages]) message += "\n" exit(1, "virt-who can't be started: %s" % message) valid_virt_sections = [(name, section) for (name, section) in effective_config.virt_sections() if section.is_valid()] if not valid_virt_sections: err = "virt-who can't be started: no valid configuration found" logger.error(err) exit(1, err) global executor has_error = False try: executor = Executor(logger, effective_config) except (InvalidKeyFile, InvalidPasswordFormat) as e: logger.error(str(e)) exit(1, "virt-who can't be started: %s" % str(e)) if len(executor.dest_to_source_mapper.dests) == 0: if has_error: err = "virt-who can't be started: no valid destination found" logger.error(err) exit(1, err) for name, config in executor.dest_to_source_mapper.configs: logger.info('Using configuration "%s" ("%s" mode)', name, config['type']) logger.info("Using reporter_id='%s'", effective_config[VW_GLOBAL]['reporter_id']) log.closeLogger(logger) with lock: signal.signal(signal.SIGHUP, reload) signal.signal(signal.SIGTERM, atexit_fn) executor.logger = logger = log.getLogger(name='main', queue=True) sd_notify("READY=1\nMAINPID=%d" % os.getpid()) while True: try: return _main(executor) except ReloadRequest: logger.info("Reloading") continue except ExitRequest as e: exit(e.code, status=e.message)