diff --git a/com.redhat.tuned.policy b/com.redhat.tuned.policy index 8bee088b..f5c972a0 100644 --- a/com.redhat.tuned.policy +++ b/com.redhat.tuned.policy @@ -247,4 +247,24 @@ + + Create new plugin instance + Authentication is required to create a new plugin instance + + auth_admin + auth_admin + yes + + + + + Delete a plugin instance + Authentication is required to destroy the instance + + auth_admin + auth_admin + yes + + + diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py index f1d336fa..612e8d37 100644 --- a/tuned/daemon/controller.py +++ b/tuned/daemon/controller.py @@ -422,3 +422,100 @@ def instance_get_devices(self, instance_name, caller = None): rets = "Instance '%s' not found" % instance_name log.error(rets) return (False, rets, []) + + @exports.export("ssa{ss}", "(bs)") + def instance_create(self, plugin_name, instance_name, options, caller = None): + """Dynamically create a plugin instance + + Parameters: + plugin_name -- name of the plugin + instance_name -- name of the new instance + dict of string-string -- options for the new instance + + Return: + bool -- True on success + string -- error message or "OK" + """ + if caller == "": + return (False, "Unauthorized") + plugins = {p.name: p for p in self._daemon._unit_manager.plugins} + if not plugin_name in plugins.keys(): + rets = "Plugin '%s' not found" % plugin_name + log.error(rets) + return (False, rets) + plugin = plugins[plugin_name] + if not isinstance(plugin, hotplug.Plugin): + rets = "Plugin '%s' does not support hotplugging or dynamic instances." % plugin.name + log.error(rets) + return (False, rets) + devices = options.pop("devices", None) + devices_udev_regex = options.pop("devices_udev_regex", None) + script_pre = options.pop("script_pre", None) + script_post = options.pop("script_post", None) + priority = int(options.pop("priority", self._daemon._unit_manager._def_instance_priority)) + try: + instance = plugin.create_instance(instance_name, priority, devices, devices_udev_regex, script_pre, script_post, options) + plugin.initialize_instance(instance) + self._daemon._unit_manager.instances.append(instance) + except Exception as e: + rets = "Error creating instance '%s': %s" % (instance_name, str(e)) + log.error(rets) + return (False, rets) + log.info("Created dynamic instance '%s' of plugin '%s'" % (instance_name, plugin_name)) + + plugin.assign_free_devices(instance) + plugin.instance_apply_tuning(instance) + # transfer matching devices from other instances, if the priority of the new + # instance is equal or higher (equal or lower priority value) + for other_instance in self._daemon._unit_manager.instances: + if (other_instance == instance or + other_instance.plugin != plugin or + instance.priority > other_instance.priority): + continue + devs_moving = plugin._get_matching_devices(instance, other_instance.processed_devices) + if len(devs_moving): + log.info("Moving devices '%s' from instance '%s' to instance '%s'." % (str(devs_moving), + other_instance.name, instance.name)) + plugin._remove_devices_nocheck(other_instance, devs_moving) + plugin._add_devices_nocheck(instance, devs_moving) + return (True, "OK") + + @exports.export("s", "(bs)") + def instance_destroy(self, instance_name, caller = None): + """Destroy a dynamically created plugin instance + + Parameters: + instance_name -- name of the new instance + + Return: + bool -- True on success + string -- error message or "OK" + """ + if caller == "": + return (False, "Unauthorized") + try: + instance = [i for i in self._daemon._unit_manager.instances if i.name == instance_name][0] + except IndexError: + rets = "Instance '%s' not found" % instance_name + log.error(rets) + return (False, rets) + plugin = instance.plugin + if not isinstance(plugin, hotplug.Plugin): + rets = "Plugin '%s' does not support hotplugging or dynamic instances." % plugin.name + log.error(rets) + return (False, rets) + devices = instance.processed_devices.copy() + try: + plugin._remove_devices_nocheck(instance, devices) + self._daemon._unit_manager.instances.remove(instance) + plugin.instance_unapply_tuning(instance) + plugin.destroy_instance(instance) + except Exception as e: + rets = "Error deleting instance '%s': %s" % (instance_name, str(e)) + log.error(rets) + return (False, rets) + log.info("Deleted instance '%s'" % instance_name) + for device in devices: + # _add_device() will find a suitable plugin instance + plugin._add_device(device) + return (True, "OK")