def __init__(self, unit_manager, profile_loader, profile_names=None, config=None, application=None): log.debug("initializing daemon") self._daemon = consts.CFG_DEF_DAEMON self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) self._update_interval = int(consts.CFG_DEF_UPDATE_INTERVAL) self._dynamic_tuning = consts.CFG_DEF_DYNAMIC_TUNING self._recommend_command = True if config is not None: self._daemon = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) self._sleep_interval = int(config.get(consts.CFG_SLEEP_INTERVAL, consts.CFG_DEF_SLEEP_INTERVAL)) self._update_interval = int(config.get(consts.CFG_UPDATE_INTERVAL, consts.CFG_DEF_UPDATE_INTERVAL)) self._dynamic_tuning = config.get_bool(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING) self._recommend_command = config.get_bool(consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND) self._application = application if self._sleep_interval <= 0: self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) if self._update_interval == 0: self._dynamic_tuning = False elif self._update_interval < self._sleep_interval: self._update_interval = self._sleep_interval self._sleep_cycles = self._update_interval // self._sleep_interval log.info("using sleep interval of %d second(s)" % self._sleep_interval) if self._dynamic_tuning: log.info("dynamic tuning is enabled (can be overridden by plugins)") log.info("using update interval of %d second(s) (%d times of the sleep interval)" % (self._sleep_cycles * self._sleep_interval, self._sleep_cycles)) self._profile_recommender = ProfileRecommender(is_hardcoded = not self._recommend_command) self._unit_manager = unit_manager self._profile_loader = profile_loader self._init_threads() self._cmd = commands() try: self._init_profile(profile_names) except TunedException as e: log.error("Cannot set initial profile. No tunings will be enabled: %s" % e)
def __init__(self, dbus=True, debug=False, asynco=False, timeout=consts.ADMIN_TIMEOUT, log_level=logging.ERROR): self._dbus = dbus self._debug = debug self._async = asynco self._timeout = timeout self._cmd = commands(debug) self._profiles_locator = profiles_locator(consts.LOAD_DIRECTORIES) self._daemon_action_finished = threading.Event() self._daemon_action_profile = "" self._daemon_action_result = True self._daemon_action_errstr = "" self._controller = None self._log_token = None self._log_level = log_level self._profile_recommender = ProfileRecommender() if self._dbus: self._controller = tuned.admin.DBusController( consts.DBUS_BUS, consts.DBUS_INTERFACE, consts.DBUS_OBJECT, debug) try: self._controller.set_signal_handler( consts.DBUS_SIGNAL_PROFILE_CHANGED, self._signal_profile_changed_cb) except TunedAdminDBusException as e: self._error(e) self._dbus = False
def _get_recommended_profile(self): log.info( "Running in automatic mode, checking what profile is recommended for your configuration." ) profile = ProfileRecommender().recommend( hardcoded=not self._recommend_command) log.info("Using '%s' profile" % profile) return profile
def recommend_profile(self, caller=None): if caller == "": return "" return ProfileRecommender( ).recommend(hardcoded=not self._global_config.get_bool( consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND))
class Daemon(object): def __init__(self, unit_manager, profile_loader, profile_names=None, config=None, application=None): log.debug("initializing daemon") self._daemon = consts.CFG_DEF_DAEMON self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) self._update_interval = int(consts.CFG_DEF_UPDATE_INTERVAL) self._dynamic_tuning = consts.CFG_DEF_DYNAMIC_TUNING self._recommend_command = True if config is not None: self._daemon = config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) self._sleep_interval = int(config.get(consts.CFG_SLEEP_INTERVAL, consts.CFG_DEF_SLEEP_INTERVAL)) self._update_interval = int(config.get(consts.CFG_UPDATE_INTERVAL, consts.CFG_DEF_UPDATE_INTERVAL)) self._dynamic_tuning = config.get_bool(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING) self._recommend_command = config.get_bool(consts.CFG_RECOMMEND_COMMAND, consts.CFG_DEF_RECOMMEND_COMMAND) self._application = application if self._sleep_interval <= 0: self._sleep_interval = int(consts.CFG_DEF_SLEEP_INTERVAL) if self._update_interval == 0: self._dynamic_tuning = False elif self._update_interval < self._sleep_interval: self._update_interval = self._sleep_interval self._sleep_cycles = self._update_interval // self._sleep_interval log.info("using sleep interval of %d second(s)" % self._sleep_interval) if self._dynamic_tuning: log.info("dynamic tuning is enabled (can be overridden by plugins)") log.info("using update interval of %d second(s) (%d times of the sleep interval)" % (self._sleep_cycles * self._sleep_interval, self._sleep_cycles)) self._profile_recommender = ProfileRecommender(is_hardcoded = not self._recommend_command) self._unit_manager = unit_manager self._profile_loader = profile_loader self._init_threads() self._cmd = commands() try: self._init_profile(profile_names) except TunedException as e: log.error("Cannot set initial profile. No tunings will be enabled: %s" % e) def _init_threads(self): self._thread = None self._terminate = threading.Event() # Flag which is set if terminating due to profile_switch self._terminate_profile_switch = threading.Event() # Flag which is set if there is no operation in progress self._not_used = threading.Event() self._not_used.set() self._profile_applied = threading.Event() def reload_profile_config(self): """Read configuration files again and load profile according to them""" self._init_profile(None) def _init_profile(self, profile_names): manual = True post_loaded_profile = self._cmd.get_post_loaded_profile() if profile_names is None: (profile_names, manual) = self._get_startup_profile() if profile_names is None: msg = "No profile is preset, running in manual mode. " if post_loaded_profile: msg += "Only post-loaded profile will be enabled" else: msg += "No profile will be enabled." log.info(msg) # Passed through '-p' cmdline option elif profile_names == "": if post_loaded_profile: log.info("Only post-loaded profile will be enabled") else: log.info("No profile will be enabled.") self._profile = None self._manual = None self._active_profiles = [] self._post_loaded_profile = None self.set_all_profiles(profile_names, manual, post_loaded_profile) def _load_profiles(self): profile_list = self._active_profiles if self._post_loaded_profile: log.info("Using post-loaded profile '%s'" % self._post_loaded_profile) profile_list = profile_list + [self._post_loaded_profile] for profile in profile_list: if profile not in self.profile_loader.profile_locator.get_known_names(): errstr = "Requested profile '%s' doesn't exist." % profile profile_names = " ".join(self._active_profiles) self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) try: if profile_list: self._profile = self._profile_loader.load(profile_list) else: self._profile = None except InvalidProfileException as e: errstr = "Cannot load profile(s) '%s': %s" % (" ".join(profile_list), e) profile_names = " ".join(self._active_profiles) self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) def _set_profile(self, profile_names, manual): self._manual = manual if profile_names: self._active_profiles = profile_names.split() else: self._active_profiles = [] def set_profile(self, profile_names, manual): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(profile_names, False, errstr) raise TunedException(errstr) self._set_profile(profile_names, manual) self._load_profiles() def _set_post_loaded_profile(self, profile_name): if not profile_name: self._post_loaded_profile = None elif len(profile_name.split()) > 1: errstr = "Whitespace is not allowed in profile names; only a single post-loaded profile is allowed." raise TunedException(errstr) else: self._post_loaded_profile = profile_name def set_all_profiles(self, active_profiles, manual, post_loaded_profile, save_instantly=False): if self.is_running(): errstr = "Cannot set profile while the daemon is running." self._notify_profile_changed(active_profiles, False, errstr) raise TunedException(errstr) self._set_profile(active_profiles, manual) self._set_post_loaded_profile(post_loaded_profile) self._load_profiles() if save_instantly: self._save_active_profile(active_profiles, manual) self._save_post_loaded_profile(post_loaded_profile) @property def profile(self): return self._profile @property def manual(self): return self._manual @property def post_loaded_profile(self): # Return the profile name only if the profile is active. If # the profile is not active, then the value is meaningless. return self._post_loaded_profile if self._profile else None @property def profile_recommender(self): return self._profile_recommender @property def profile_loader(self): return self._profile_loader # send notification when profile is changed (everything is setup) or if error occured # result: True - OK, False - error occured def _notify_profile_changed(self, profile_names, result, errstr): if self._application is not None and self._application._dbus_exporter is not None: self._application._dbus_exporter.send_signal(consts.DBUS_SIGNAL_PROFILE_CHANGED, profile_names, result, errstr) return errstr def _full_rollback_required(self): retcode, out = self._cmd.execute(["systemctl", "is-system-running"], no_errors = [0]) if retcode < 0: return False if out[:8] == "stopping": return False retcode, out = self._cmd.execute(["systemctl", "list-jobs"], no_errors = [0]) return re.search(r"\b(shutdown|reboot|halt|poweroff)\.target.*start", out) is None def _thread_code(self): if self._profile is None: raise TunedException("Cannot start the daemon without setting a profile.") self._unit_manager.create(self._profile.units) self._save_active_profile(" ".join(self._active_profiles), self._manual) self._save_post_loaded_profile(self._post_loaded_profile) self._unit_manager.start_tuning() self._profile_applied.set() log.info("static tuning from profile '%s' applied" % self._profile.name) if self._daemon: exports.start() profile_names = " ".join(self._active_profiles) self._notify_profile_changed(profile_names, True, "OK") if self._daemon: # In python 2 interpreter with applied patch for rhbz#917709 we need to periodically # poll, otherwise the python will not have chance to update events / locks (due to GIL) # and e.g. DBus control will not work. The polling interval of 1 seconds (which is # the default) is still much better than 50 ms polling with unpatched interpreter. # For more details see tuned rhbz#917587. _sleep_cnt = self._sleep_cycles while not self._cmd.wait(self._terminate, self._sleep_interval): if self._dynamic_tuning: _sleep_cnt -= 1 if _sleep_cnt <= 0: _sleep_cnt = self._sleep_cycles log.debug("updating monitors") self._unit_manager.update_monitors() log.debug("performing tunings") self._unit_manager.update_tuning() self._profile_applied.clear() # wait for others to complete their tasks, use timeout 3 x sleep_interval to prevent # deadlocks i = 0 while not self._cmd.wait(self._not_used, self._sleep_interval) and i < 3: i += 1 # if terminating due to profile switch if self._terminate_profile_switch.is_set(): full_rollback = True else: # with systemd it detects system shutdown and in such case it doesn't perform # full cleanup, if not shutting down it means that Tuned was explicitly # stopped by user and in such case do full cleanup, without systemd never # do full cleanup full_rollback = False if self._full_rollback_required(): if self._daemon: log.info("terminating Tuned, rolling back all changes") full_rollback = True else: log.info("terminating Tuned in one-shot mode") else: log.info("terminating Tuned due to system shutdown / reboot") if self._daemon: self._unit_manager.stop_tuning(full_rollback) self._unit_manager.destroy_all() def _save_active_profile(self, profile_names, manual): try: self._cmd.save_active_profile(profile_names, manual) except TunedException as e: log.error(str(e)) def _save_post_loaded_profile(self, profile_name): try: self._cmd.save_post_loaded_profile(profile_name) except TunedException as e: log.error(str(e)) def _get_recommended_profile(self): log.info("Running in automatic mode, checking what profile is recommended for your configuration.") profile = self._profile_recommender.recommend() log.info("Using '%s' profile" % profile) return profile def _get_startup_profile(self): profile, manual = self._cmd.get_active_profile() if manual is None: manual = profile is not None if not manual: profile = self._get_recommended_profile() return profile, manual def get_all_plugins(self): """Return all accessible plugin classes""" return self._unit_manager.plugins_repository.load_all_plugins() def get_plugin_documentation(self, plugin_name): """Return plugin class docstring""" try: plugin_class = self._unit_manager.plugins_repository.load_plugin( plugin_name ) except ImportError: return "" return plugin_class.__doc__ def get_plugin_hints(self, plugin_name): """Return plugin's parameters and their hints Parameters: plugin_name -- plugins name Return: dictionary -- {parameter_name: hint} """ try: plugin_class = self._unit_manager.plugins_repository.load_plugin( plugin_name ) except ImportError: return {} return plugin_class.get_config_options_hints() def is_enabled(self): return self._profile is not None def is_running(self): return self._thread is not None and self._thread.is_alive() def start(self): if self.is_running(): return False if self._profile is None: return False log.info("starting tuning") self._not_used.set() self._thread = threading.Thread(target=self._thread_code) self._terminate_profile_switch.clear() self._terminate.clear() self._thread.start() return True def verify_profile(self, ignore_missing): if not self.is_running(): log.error("tuned is not running") return False if self._profile is None: log.error("no profile is set") return False if not self._profile_applied.is_set(): log.error("profile is not applied") return False # using deamon, the main loop mustn't exit before our completion self._not_used.clear() log.info("verifying profile(s): %s" % self._profile.name) ret = self._unit_manager.verify_tuning(ignore_missing) # main loop is allowed to exit self._not_used.set() return ret # profile_switch is helper telling plugins whether the stop is due to profile switch def stop(self, profile_switch = False): if not self.is_running(): return False log.info("stopping tuning") if profile_switch: self._terminate_profile_switch.set() self._terminate.set() self._thread.join() self._thread = None return True
class Admin(object): def __init__(self, dbus=True, debug=False, asynco=False, timeout=consts.ADMIN_TIMEOUT, log_level=logging.ERROR): self._dbus = dbus self._debug = debug self._async = asynco self._timeout = timeout self._cmd = commands(debug) self._profiles_locator = profiles_locator(consts.LOAD_DIRECTORIES) self._daemon_action_finished = threading.Event() self._daemon_action_profile = "" self._daemon_action_result = True self._daemon_action_errstr = "" self._controller = None self._log_token = None self._log_level = log_level self._profile_recommender = ProfileRecommender() if self._dbus: self._controller = tuned.admin.DBusController( consts.DBUS_BUS, consts.DBUS_INTERFACE, consts.DBUS_OBJECT, debug) try: self._controller.set_signal_handler( consts.DBUS_SIGNAL_PROFILE_CHANGED, self._signal_profile_changed_cb) except TunedAdminDBusException as e: self._error(e) self._dbus = False def _error(self, message): print(message, file=sys.stderr) def _signal_profile_changed_cb(self, profile_name, result, errstr): # ignore successive signals if the signal is not yet processed if not self._daemon_action_finished.is_set(): self._daemon_action_profile = profile_name self._daemon_action_result = result self._daemon_action_errstr = errstr self._daemon_action_finished.set() def _tuned_is_running(self): try: os.kill(int(self._cmd.read_file(consts.PID_FILE)), 0) except OSError as e: return e.errno == errno.EPERM except (ValueError, IOError) as e: return False return True # run the action specified by the action_name with args def action(self, action_name, *args, **kwargs): if action_name is None or action_name == "": return False action = None action_dbus = None res = False try: action_dbus = getattr(self, "_action_dbus_" + action_name) except AttributeError as e: self._dbus = False try: action = getattr(self, "_action_" + action_name) except AttributeError as e: if not self._dbus: self._error( str(e) + ", action '%s' is not implemented" % action_name) return False if self._dbus: try: self._controller.set_on_exit_action(self._log_capture_finish) self._controller.set_action(action_dbus, *args, **kwargs) res = self._controller.run() except TunedAdminDBusException as e: self._error(e) self._dbus = False if not self._dbus: res = action(*args, **kwargs) return res def _print_profiles(self, profile_names): print("Available profiles:") for profile in profile_names: if profile[1] is not None and profile[1] != "": print( self._cmd.align_str("- %s" % profile[0], 30, "- %s" % profile[1])) else: print("- %s" % profile[0]) def _action_dbus_list_profiles(self): try: profile_names = self._controller.profiles2() except TunedAdminDBusException as e: # fallback to older API profile_names = [(profile, "") for profile in self._controller.profiles()] self._print_profiles(profile_names) self._action_dbus_active() return self._controller.exit(True) def _action_list_profiles(self): self._print_profiles(self._profiles_locator.get_known_names_summary()) self._action_active() return True def _dbus_get_active_profile(self): profile_name = self._controller.active_profile() if profile_name == "": profile_name = None self._controller.exit(True) return profile_name def _get_active_profile(self): profile_name, manual = self._cmd.get_active_profile() return profile_name def _get_profile_mode(self): (profile, manual) = self._cmd.get_active_profile() if manual is None: manual = profile is not None return consts.ACTIVE_PROFILE_MANUAL if manual else consts.ACTIVE_PROFILE_AUTO def _dbus_get_post_loaded_profile(self): profile_name = self._controller.post_loaded_profile() if profile_name == "": profile_name = None return profile_name def _get_post_loaded_profile(self): profile_name = self._cmd.get_post_loaded_profile() return profile_name def _print_profile_info(self, profile, profile_info): if profile_info[0] == True: print("Profile name:") print(profile_info[1]) print() print("Profile summary:") print(profile_info[2]) print() print("Profile description:") print(profile_info[3]) return True else: print("Unable to get information about profile '%s'" % profile) return False def _action_dbus_profile_info(self, profile=""): if profile == "": profile = self._dbus_get_active_profile() if profile: res = self._print_profile_info( profile, self._controller.profile_info(profile)) else: print("No current active profile.") res = False return self._controller.exit(res) def _action_profile_info(self, profile=""): if profile == "": try: profile = self._get_active_profile() if profile is None: print("No current active profile.") return False except TunedException as e: self._error(str(e)) return False return self._print_profile_info( profile, self._profiles_locator.get_profile_attrs( profile, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], ["", ""])) def _print_profile_name(self, profile_name): if profile_name is None: print("No current active profile.") return False else: print("Current active profile: %s" % profile_name) return True def _print_post_loaded_profile(self, profile_name): if profile_name: print("Current post-loaded profile: %s" % profile_name) def _action_dbus_active(self): active_profile = self._dbus_get_active_profile() res = self._print_profile_name(active_profile) if res: post_loaded_profile = self._dbus_get_post_loaded_profile() self._print_post_loaded_profile(post_loaded_profile) return self._controller.exit(res) def _action_active(self): try: profile_name = self._get_active_profile() post_loaded_profile = self._get_post_loaded_profile() # The result of the DBus call active_profile includes # the post-loaded profile, so add it here as well if post_loaded_profile: if profile_name: profile_name += " " else: profile_name = "" profile_name += post_loaded_profile except TunedException as e: self._error(str(e)) return False if profile_name is not None and not self._tuned_is_running(): print( "It seems that tuned daemon is not running, preset profile is not activated." ) print("Preset profile: %s" % profile_name) if post_loaded_profile: print("Preset post-loaded profile: %s" % post_loaded_profile) return True res = self._print_profile_name(profile_name) self._print_post_loaded_profile(post_loaded_profile) return res def _print_profile_mode(self, mode): print("Profile selection mode: " + mode) def _action_dbus_profile_mode(self): mode, error = self._controller.profile_mode() self._print_profile_mode(mode) if error != "": self._error(error) return self._controller.exit(False) return self._controller.exit(True) def _action_profile_mode(self): try: mode = self._get_profile_mode() self._print_profile_mode(mode) return True except TunedException as e: self._error(str(e)) return False def _profile_print_status(self, ret, msg): if ret: if not self._controller.is_running( ) and not self._controller.start(): self._error("Cannot enable the tuning.") ret = False else: self._error(msg) return ret def _action_dbus_wait_profile(self, profile_name): if time.time() >= self._timestamp + self._timeout: print( "Operation timed out after waiting %d seconds(s), you may try to increase timeout by using --timeout command line option or using --async." % self._timeout) return self._controller.exit(False) if self._daemon_action_finished.isSet(): if self._daemon_action_profile == profile_name: if not self._daemon_action_result: print("Error changing profile: %s" % self._daemon_action_errstr) return self._controller.exit(False) return self._controller.exit(True) return False def _log_capture_finish(self): if self._log_token is None or self._log_token == "": return try: log_msgs = self._controller.log_capture_finish(self._log_token) self._log_token = None print(log_msgs, end="", file=sys.stderr) sys.stderr.flush() except TunedAdminDBusException as e: self._error( "Error: Failed to stop log capture. Restart the Tuned daemon to prevent a memory leak." ) def _action_dbus_profile(self, profiles): if len(profiles) == 0: return self._action_dbus_list() profile_name = " ".join(profiles) if profile_name == "": return self._controller.exit(False) self._daemon_action_finished.clear() if not self._async and self._log_level is not None: # 25 seconds default DBus timeout + 5 secs safety margin timeout = self._timeout + 25 + 5 self._log_token = self._controller.log_capture_start( self._log_level, timeout) (ret, msg) = self._controller.switch_profile(profile_name) if self._async or not ret: return self._controller.exit(self._profile_print_status(ret, msg)) else: self._timestamp = time.time() self._controller.set_action(self._action_dbus_wait_profile, profile_name) return self._profile_print_status(ret, msg) def _restart_tuned(self): print("Trying to (re)start tuned...") (ret, msg) = self._cmd.execute(["service", "tuned", "restart"]) if ret == 0: print("Tuned (re)started, changes applied.") else: print( "Tuned (re)start failed, you need to (re)start tuned by hand for changes to apply." ) def _set_profile(self, profile_name, manual): if profile_name in self._profiles_locator.get_known_names(): try: self._cmd.save_active_profile(profile_name, manual) self._restart_tuned() return True except TunedException as e: self._error(str(e)) self._error("Unable to switch profile.") return False else: self._error("Requested profile '%s' doesn't exist." % profile_name) return False def _action_profile(self, profiles): if len(profiles) == 0: return self._action_list_profiles() profile_name = " ".join(profiles) if profile_name == "": return False return self._set_profile(profile_name, True) def _action_dbus_auto_profile(self): profile_name = self._controller.recommend_profile() self._daemon_action_finished.clear() if not self._async and self._log_level is not None: # 25 seconds default DBus timeout + 5 secs safety margin timeout = self._timeout + 25 + 5 self._log_token = self._controller.log_capture_start( self._log_level, timeout) (ret, msg) = self._controller.auto_profile() if self._async or not ret: return self._controller.exit(self._profile_print_status(ret, msg)) else: self._timestamp = time.time() self._controller.set_action(self._action_dbus_wait_profile, profile_name) return self._profile_print_status(ret, msg) def _action_auto_profile(self): profile_name = self._profile_recommender.recommend() return self._set_profile(profile_name, False) def _action_dbus_recommend_profile(self): print(self._controller.recommend_profile()) return self._controller.exit(True) def _action_recommend_profile(self): print(self._profile_recommender.recommend()) return True def _action_dbus_verify_profile(self, ignore_missing): if ignore_missing: ret = self._controller.verify_profile_ignore_missing() else: ret = self._controller.verify_profile() if ret: print( "Verfication succeeded, current system settings match the preset profile." ) else: print( "Verification failed, current system settings differ from the preset profile." ) print( "You can mostly fix this by restarting the Tuned daemon, e.g.:" ) print(" systemctl restart tuned") print("or") print(" service tuned restart") print( "Sometimes (if some plugins like bootloader are used) a reboot may be required." ) print("See tuned log file ('%s') for details." % consts.LOG_FILE) return self._controller.exit(ret) def _action_verify_profile(self, ignore_missing): print("Not supported in no_daemon mode.") return False def _action_dbus_off(self): # 25 seconds default DBus timeout + 5 secs safety margin timeout = 25 + 5 self._log_token = self._controller.log_capture_start( self._log_level, timeout) ret = self._controller.off() if not ret: self._error("Cannot disable active profile.") return self._controller.exit(ret) def _action_off(self): print("Not supported in no_daemon mode.") return False def _action_dbus_list(self, list_choice="profiles", verbose=False): """Print accessible profiles or plugins got from tuned dbus api Keyword arguments: list_choice -- argument from command line deciding what will be listed verbose -- if True then list plugin's config options and their hints if possible. Functional only with plugin listing, with profiles this argument is omitted """ if list_choice == "profiles": return self._action_dbus_list_profiles() elif list_choice == "plugins": return self._action_dbus_list_plugins(verbose=verbose) def _action_list(self, list_choice="profiles", verbose=False): """Print accessible profiles or plugins with no daemon mode Keyword arguments: list_choice -- argument from command line deciding what will be listed verbose -- Plugins cannot be listed in this mode, so verbose argument is here only because argparse module always supplies verbose option and if verbose was not here it would result in error """ if list_choice == "profiles": return self._action_list_profiles() elif list_choice == "plugins": return self._action_list_plugins(verbose=verbose) def _action_dbus_list_plugins(self, verbose=False): """Print accessible plugins Keyword arguments: verbose -- if is set to True then parameters and hints are printed """ plugins = self._controller.get_plugins() for plugin in plugins.keys(): print(plugin) if not verbose or len(plugins[plugin]) == 0: continue hints = self._controller.get_plugin_hints(plugin) for parameter in plugins[plugin]: print("\t%s" % (parameter)) hint = hints.get(parameter, None) if hint: print("\t\t%s" % (hint)) return self._controller.exit(True) def _action_list_plugins(self, verbose=False): print("Not supported in no_daemon mode.") return False