@command and @command_revert decorator
This commit is contained in:
parent
32d9a9d201
commit
2a3422fcd1
6 changed files with 239 additions and 151 deletions
|
|
@ -27,16 +27,45 @@ class Plugin(object):
|
|||
|
||||
def __init__(self, devices = None, options = None):
|
||||
self._devices = devices
|
||||
self._commands = {}
|
||||
self._options = self._get_default_options()
|
||||
self._options["_load_path"] = ""
|
||||
if options is not None:
|
||||
self._merge_options(options)
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.cleanup()
|
||||
except:
|
||||
pass
|
||||
#def __del__(self):
|
||||
#try:
|
||||
#self.cleanup()
|
||||
#except:
|
||||
#pass
|
||||
|
||||
def register_command(self, option, set_fnc, revert_fnc = None, is_per_dev = False):
|
||||
self._commands[option] = (is_per_dev, set_fnc, revert_fnc)
|
||||
|
||||
def execute_commands(self, devices = []):
|
||||
for option, (is_per_dev, set_fnc, revert_fnc) in self._commands.iteritems():
|
||||
if not self._options.has_key(option):
|
||||
continue
|
||||
|
||||
if is_per_dev:
|
||||
for dev in devices:
|
||||
set_fnc(dev, self._options[option])
|
||||
else:
|
||||
set_fnc(self._options[option])
|
||||
|
||||
def cleanup_commands(self, devices = []):
|
||||
for option, (is_per_dev, set_fnc, revert_fnc) in self._commands.iteritems():
|
||||
if not self._options.has_key(option):
|
||||
continue
|
||||
|
||||
if revert_fnc:
|
||||
set_fnc = revert_fnc
|
||||
|
||||
if is_per_dev:
|
||||
for dev in devices:
|
||||
set_fnc(dev, None)
|
||||
else:
|
||||
set_fnc(None)
|
||||
|
||||
def cleanup(self):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import tuned.plugins
|
||||
import tuned.logs
|
||||
import tuned.monitors
|
||||
import tuned.utils.commands
|
||||
from tuned.utils.commands import *
|
||||
import os
|
||||
import struct
|
||||
|
||||
|
|
@ -24,6 +24,13 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
|
|||
if not tuned.utils.storage.Storage.get_instance().data.has_key("cpu"):
|
||||
tuned.utils.storage.Storage.get_instance().data["cpu"] = {}
|
||||
|
||||
self.register_command("cpu_governor",
|
||||
self._set_cpu_governor,
|
||||
self._revert_cpu_governor)
|
||||
self.register_command("cpu_multicore_powersave",
|
||||
self._set_cpu_multicore_powersave,
|
||||
self._revert_cpu_multicore_powersave)
|
||||
|
||||
@classmethod
|
||||
def _get_default_options(cls):
|
||||
return {
|
||||
|
|
@ -35,16 +42,14 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
|
|||
}
|
||||
|
||||
def cleanup(self):
|
||||
self._revert_cpu_governor()
|
||||
self._revert_cpu_multicore_powersave()
|
||||
self.cleanup_commands()
|
||||
tuned.monitors.get_repository().delete(self._load_monitor)
|
||||
|
||||
os.close(self._cpu_latency_fd)
|
||||
|
||||
def update_tuning(self):
|
||||
if not self._commands_run:
|
||||
self._apply_cpu_governor()
|
||||
self._apply_cpu_multicore_powersave()
|
||||
self.execute_commands()
|
||||
self._commands_run = True
|
||||
|
||||
load = self._load_monitor.get_load()["system"]
|
||||
|
|
@ -61,65 +66,39 @@ class CPULatencyPlugin(tuned.plugins.Plugin):
|
|||
os.write(self._cpu_latency_fd, latency_bin)
|
||||
self._latency = latency
|
||||
|
||||
# COMMANDS:
|
||||
|
||||
def _apply_cpu_governor(self):
|
||||
self._revert_cpu_governor()
|
||||
|
||||
if len(self._options["cpu_governor"]) == 0:
|
||||
return False
|
||||
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
@command("cpu", "cpu_governor")
|
||||
def _set_cpu_governor(self, value):
|
||||
old_value = tuned.utils.commands.execute(["cpupower", "frequency-info", "-p"])
|
||||
if old_value.startswith("analyzing CPU"):
|
||||
try:
|
||||
old_value = old_value.split('\n')[1].split(' ')[2]
|
||||
storage.data["cpu"]["cpu_governor"] = old_value
|
||||
storage.save()
|
||||
except IndexError:
|
||||
old_value = ""
|
||||
pass
|
||||
|
||||
|
||||
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", self._options["cpu_governor"]])
|
||||
return True
|
||||
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", value])
|
||||
return old_value
|
||||
|
||||
def _revert_cpu_governor(self):
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if storage.data["cpu"].has_key("cpu_governor"):
|
||||
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", storage.data["cpu"]["cpu_governor"]])
|
||||
del storage.data["cpu"]["cpu_governor"]
|
||||
@command_revert("cpu", "cpu_governor")
|
||||
def _revert_cpu_governor(self, value):
|
||||
tuned.utils.commands.execute(["cpupower", "frequency-set", "-g", value])
|
||||
|
||||
def _apply_cpu_multicore_powersave(self):
|
||||
self._revert_cpu_multicore_powersave()
|
||||
|
||||
if len(self._options["cpu_multicore_powersave"]) == 0:
|
||||
return False
|
||||
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
@command("cpu", "cpu_multicore_powersave")
|
||||
def _set_cpu_multicore_powersave(self, value):
|
||||
old_value = tuned.utils.commands.execute(["cpupower", "info", "-m"])
|
||||
if old_value.find("not supported") != -1:
|
||||
log.info("cpu_multicore_powersave is not supported by this system")
|
||||
return False
|
||||
return ""
|
||||
|
||||
if old_value.startswith("System's multi core scheduler setting"):
|
||||
try:
|
||||
old_value = old_value.split(' ')[:-1][:-1] # get "2\n" and remove '\n'
|
||||
storage.data["cpu"]["cpu_multicore_powersave"] = old_value
|
||||
storage.save()
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
old_value = ""
|
||||
|
||||
tuned.utils.commands.execute(["cpupower", "set", "-m", storage.data["cpu"]["cpu_multicore_powersave"]])
|
||||
return True
|
||||
tuned.utils.commands.execute(["cpupower", "set", "-m", value])
|
||||
return old_value
|
||||
|
||||
def _revert_cpu_multicore_powersave(self):
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if storage.data["cpu"].has_key("cpu_multicore_powersave"):
|
||||
tuned.utils.commands.execute(["cpupower", "set", "-m", storage.data["cpu"]["cpu_multicore_powersave"]])
|
||||
del storage.data["cpu"]["cpu_multicore_powersave"]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@command_revert("cpu", "cpu_multicore_powersave")
|
||||
def _revert_cpu_multicore_powersave(self, value):
|
||||
tuned.utils.commands.execute(["cpupower", "set", "-m", value])
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import os, copy
|
|||
import tuned.plugins
|
||||
import tuned.logs
|
||||
import tuned.monitors
|
||||
import tuned.utils.commands
|
||||
from tuned.utils.commands import *
|
||||
import tuned.utils.storage
|
||||
import struct
|
||||
|
||||
|
|
@ -30,6 +30,25 @@ class DiskPlugin(tuned.plugins.Plugin):
|
|||
if not tuned.utils.storage.Storage.get_instance().data.has_key("disk"):
|
||||
tuned.utils.storage.Storage.get_instance().data["disk"] = {}
|
||||
|
||||
self.register_command("elevator",
|
||||
self._set_elevator,
|
||||
self._revert_elevator,
|
||||
is_per_dev = True)
|
||||
self.register_command("disk_readahead_multiplier",
|
||||
self._set_disk_readahead_multiplier,
|
||||
self._revert_disk_readahead_multiplier,
|
||||
is_per_dev = True)
|
||||
self.register_command("disk_alpm",
|
||||
self._set_disk_alpm,
|
||||
self._revert_disk_alpm)
|
||||
self.register_command("disk_apm",
|
||||
self._set_disk_apm,
|
||||
self._revert_disk_apm,
|
||||
is_per_dev = True)
|
||||
self.register_command("disk_spindown",
|
||||
self._set_disk_spindown,
|
||||
is_per_dev = True)
|
||||
|
||||
@classmethod
|
||||
def tunable_devices(cls):
|
||||
block_devices = os.listdir("/sys/block")
|
||||
|
|
@ -101,21 +120,12 @@ class DiskPlugin(tuned.plugins.Plugin):
|
|||
for dev in self.devidle.keys():
|
||||
if self.devidle[dev]["LEVEL"] > 0:
|
||||
os.system("hdparm -S0 -B255 /dev/"+dev+" > /dev/null 2>&1")
|
||||
self._revert_elevator(dev)
|
||||
self._revert_disk_apm(dev)
|
||||
self._revert_disk_readahead_multiplier(dev)
|
||||
|
||||
self._revert_disk_alpm()
|
||||
self.cleanup_commands(self.devidle.keys())
|
||||
|
||||
def update_tuning(self):
|
||||
load = self._load_monitor.get_load()
|
||||
for dev, devload in load.iteritems():
|
||||
if not self._elevator_set:
|
||||
self._apply_elevator(dev)
|
||||
self._apply_disk_apm(dev)
|
||||
self._apply_disk_spindown(dev)
|
||||
self._apply_disk_readahead_multiplier(dev)
|
||||
|
||||
self._init_stats(dev)
|
||||
self._update_stats(dev, devload)
|
||||
self._update_idle(dev)
|
||||
|
|
@ -142,32 +152,24 @@ class DiskPlugin(tuned.plugins.Plugin):
|
|||
log.debug("%s idle: read %d, write %d, level %d" % (dev, self.devidle[dev]["read"], self.devidle[dev]["write"], self.devidle[dev]["LEVEL"]))
|
||||
|
||||
if not self._elevator_set:
|
||||
self._apply_disk_alpm()
|
||||
|
||||
self._elevator_set = True
|
||||
|
||||
# Commands:
|
||||
|
||||
def _apply_elevator(self, dev):
|
||||
self._revert_elevator(dev)
|
||||
|
||||
if len(self._options["elevator"]) == 0:
|
||||
return False
|
||||
self.execute_commands(load.keys())
|
||||
self._elevator_set = True
|
||||
|
||||
@command("disk", "elevator")
|
||||
def _set_elevator(self, dev, value):
|
||||
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
|
||||
tuned.utils.commands.set_file("disk", "elevator_" + dev, sys_file, self._options["elevator"])
|
||||
return True
|
||||
old_value = tuned.utils.commands.read_file(sys_file)
|
||||
tuned.utils.commands.write_to_file(sys_file, value)
|
||||
return old_value
|
||||
|
||||
def _revert_elevator(self, dev):
|
||||
@command_revert("disk", "elevator")
|
||||
def _revert_elevator(self, dev, value):
|
||||
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
|
||||
tuned.utils.commands.revert_file("disk", "elevator_" + dev, sys_file)
|
||||
|
||||
def _apply_disk_alpm(self):
|
||||
self._revert_disk_alpm()
|
||||
|
||||
if len(self._options["disk_alpm"]) == 0:
|
||||
return False
|
||||
tuned.utils.commands.write_to_file(sys_file, value)
|
||||
|
||||
@command("disk", "disk_alpm")
|
||||
def _set_disk_alpm(self, value):
|
||||
old_value = ""
|
||||
for host in os.listdir("/sys/class/scsi_host/"):
|
||||
port_cmd_path = os.path.join("/sys/class/scsi_host/", host, "ahci_port_cmd")
|
||||
try:
|
||||
|
|
@ -186,57 +188,46 @@ class DiskPlugin(tuned.plugins.Plugin):
|
|||
policy = "max_performance"
|
||||
|
||||
sys_file = os.path.join("/sys/class/scsi_host/", host, "link_power_management_policy")
|
||||
tuned.utils.commands.set_file("disk", "disk_alpm", sys_file, policy)
|
||||
if len(old_value) == 0:
|
||||
old_value = tuned.utils.commands.read_file(sys_file)
|
||||
tuned.utils.commands.write_to_file(sys_file, policy)
|
||||
|
||||
return True
|
||||
return old_value
|
||||
|
||||
def _revert_disk_alpm(self):
|
||||
@command_revert("disk", "disk_alpm")
|
||||
def _revert_disk_alpm(self, value):
|
||||
for host in os.listdir("/sys/class/scsi_host/"):
|
||||
sys_file = os.path.join("/sys/class/scsi_host/", host, "link_power_management_policy")
|
||||
tuned.utils.commands.revert_file("disk", "disk_alpm", sys_file)
|
||||
|
||||
def _apply_disk_apm(self, dev):
|
||||
self._revert_disk_apm(dev)
|
||||
|
||||
if len(self._options["disk_apm"]) == 0:
|
||||
return False
|
||||
tuned.utils.commands.write_to_file(sys_file, value)
|
||||
|
||||
@command("disk", "disk_apm")
|
||||
def _set_disk_apm(self, dev, value):
|
||||
#TODO: get current value using hdparm -B. My disk does not support it...
|
||||
tuned.utils.commands.execute(["hdparm", "-B", self._options["disk_apm"], "/dev/" + dev])
|
||||
return True
|
||||
tuned.utils.commands.execute(["hdparm", "-B", value, "/dev/" + dev])
|
||||
return ""
|
||||
|
||||
def _revert_disk_apm(self, dev):
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if storage.data["disk"].has_key("disk_apm_" + dev):
|
||||
tuned.utils.commands.execute(["hdparm", "-B", storage.data["disk"]["disk_apm_" + dev], "/dev/" + dev])
|
||||
del storage.data["disk"]["disk_apm_" + dev]
|
||||
@command_revert("disk", "disk_apm")
|
||||
def _revert_disk_apm(self, dev, value):
|
||||
tuned.utils.commands.execute(["hdparm", "-B", value, "/dev/" + dev])
|
||||
|
||||
def _apply_disk_spindown(self, dev):
|
||||
if len(self._options["disk_spindown"]) == 0:
|
||||
return False
|
||||
|
||||
tuned.utils.commands.execute(["hdparm", "-S", self._options["disk_spindown"], "/dev/" + dev])
|
||||
return True
|
||||
|
||||
def _apply_disk_readahead_multiplier(self, dev):
|
||||
self._revert_elevator(dev)
|
||||
|
||||
if len(self._options["elevator"]) == 0:
|
||||
return False
|
||||
@command("disk", "disk_spindown")
|
||||
def _set_disk_spindown(self, dev, value):
|
||||
# There's no way how to get current/old spindown value...
|
||||
tuned.utils.commands.execute(["hdparm", "-S", value, "/dev/" + dev])
|
||||
|
||||
@command("disk", "disk_readahead_multiplier")
|
||||
def _set_disk_readahead_multiplier(self, dev, value):
|
||||
sys_file = os.path.join("/sys/block/", dev, "queue/read_ahead_kb")
|
||||
try:
|
||||
value = open(sys_file).read().strip()
|
||||
except (OSError,IOError) as e:
|
||||
log.error("Reading %s error: %s" % (sys_file, e))
|
||||
return
|
||||
|
||||
new_value = int(int(value) * float(self._options["disk_readahead_multiplier"]))
|
||||
old_value = tuned.utils.commands.read_file(sys_file).strip()
|
||||
if len(old_value) == 0:
|
||||
return ""
|
||||
new_value = int(int(old_value) * float(value))
|
||||
|
||||
tuned.utils.commands.set_file("disk", "disk_readahead_multiplier_" + dev, sys_file, str(new_value))
|
||||
return True
|
||||
tuned.utils.commands.write_to_file(sys_file, new_value)
|
||||
return old_value
|
||||
|
||||
def _revert_disk_readahead_multiplier(self, dev):
|
||||
@command_revert("disk", "disk_readahead_multiplier")
|
||||
def _revert_disk_readahead_multiplier(self, dev, value):
|
||||
sys_file = os.path.join("/sys/block/", dev, "queue/read_ahead_kb")
|
||||
tuned.utils.commands.revert_file("disk", "disk_readahead_multiplier_" + dev, sys_file)
|
||||
tuned.utils.commands.write_to_file(sys_file, value)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import tuned.plugins
|
||||
import tuned.logs
|
||||
import tuned.monitors
|
||||
import tuned.utils.commands
|
||||
from tuned.utils.commands import *
|
||||
import os
|
||||
import struct
|
||||
import glob
|
||||
|
|
@ -22,6 +22,8 @@ class WirelessPlugin(tuned.plugins.Plugin):
|
|||
if not tuned.utils.storage.Storage.get_instance().data.has_key("wireless"):
|
||||
tuned.utils.storage.Storage.get_instance().data["wireless"] = {}
|
||||
|
||||
self.register_command("wifi_power_level", self._set_wifi_power_level)
|
||||
|
||||
@classmethod
|
||||
def _get_default_options(cls):
|
||||
return {
|
||||
|
|
@ -29,21 +31,22 @@ class WirelessPlugin(tuned.plugins.Plugin):
|
|||
}
|
||||
|
||||
def cleanup(self):
|
||||
self._revert_wifi_power_level()
|
||||
self.cleanup_commands()
|
||||
|
||||
def update_tuning(self):
|
||||
if not self._commands_run:
|
||||
self._apply_wifi_power_level()
|
||||
self.execute_commands()
|
||||
self._commands_run = True
|
||||
|
||||
# COMMANDS:
|
||||
|
||||
@command("wireless", "wifi_power_level")
|
||||
def _set_wifi_power_level(self, power_level):
|
||||
try:
|
||||
lines = open("/proc/net/wireless").readlines()
|
||||
except (OSError,IOError) as e:
|
||||
log.error("Error reading wifi devices from /proc/net/wireless: %s" % (e))
|
||||
return None
|
||||
return ""
|
||||
|
||||
ifaces = []
|
||||
for line in lines:
|
||||
|
|
@ -56,7 +59,7 @@ class WirelessPlugin(tuned.plugins.Plugin):
|
|||
|
||||
if len(ifaces) == 0:
|
||||
log.info("No wifi interfaces found")
|
||||
return None
|
||||
return ""
|
||||
|
||||
# TODO: set old_value properly. Is there "get_power"? I don't have wifi here
|
||||
old_value = "5"
|
||||
|
|
@ -68,23 +71,3 @@ class WirelessPlugin(tuned.plugins.Plugin):
|
|||
tuned.utils.commands.write_to_file(sys_file, power_level)
|
||||
|
||||
return old_value
|
||||
|
||||
def _apply_wifi_power_level(self):
|
||||
self._revert_wifi_power_level()
|
||||
|
||||
if len(self._options["wifi_power_level"]) == 0:
|
||||
return False
|
||||
|
||||
old_value = self._set_wifi_power_level(self._options["wifi_power_level"])
|
||||
if old_value:
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
storage.data["wireless"]["wifi_power_level"] = old_value
|
||||
storage.save()
|
||||
|
||||
return True
|
||||
|
||||
def _revert_wifi_power_level(self):
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if storage.data["wireless"].has_key("wifi_power_level"):
|
||||
self._set_wifi_power_level(storage.data["wireless"]["wifi_power_level"])
|
||||
del storage.data["wireless"]["wifi_power_level"]
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class PluginRepository(tuned.patterns.Singleton):
|
|||
def delete(self, plugin):
|
||||
assert isinstance(plugin, self._loader.interface)
|
||||
log.debug("removing plugin %s" % plugin)
|
||||
plugin.cleanup()
|
||||
self._plugins.remove(plugin)
|
||||
|
||||
def update(self):
|
||||
|
|
|
|||
|
|
@ -22,15 +22,120 @@ import tuned.monitors
|
|||
import tuned.utils.storage
|
||||
import struct
|
||||
from subprocess import *
|
||||
from functools import wraps
|
||||
|
||||
log = tuned.logs.get()
|
||||
|
||||
# command decorator
|
||||
def command(plugin, key):
|
||||
"""
|
||||
This decorator makes adding new commands easier. The only thing you have to do is
|
||||
to implement method which handles the value of particular option from config file
|
||||
and returns previosly set value.
|
||||
|
||||
Here is example of method like that:
|
||||
@command("disk", "elevator")
|
||||
def _set_elevator(self, dev, value):
|
||||
sys_file = os.path.join("/sys/block/", dev, "queue/scheduler")
|
||||
old_value = tuned.utils.commands.read_file(sys_file)
|
||||
tuned.utils.commands.write_to_file(sys_file, value)
|
||||
return old_value
|
||||
|
||||
This decorator works then like this:
|
||||
1. Tries to revert to previously stored value in Storage class
|
||||
2. Tries to set the new value
|
||||
3. Stores old value returned by the original method into Storage
|
||||
"""
|
||||
def my_decorator(target):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
# Find out if the original method is def method(self, dev, value)
|
||||
# or just def method(self, value) and set the variables.
|
||||
dev = ""
|
||||
value = None
|
||||
if len(args) == 1:
|
||||
value = args[0]
|
||||
else:
|
||||
dev = "_" + args[0]
|
||||
value = args[1]
|
||||
|
||||
# Check if this plugin has key in Storage cache
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if not storage.data.has_key(plugin):
|
||||
log.error("Storage file does not contain item with key %s" % (plugin))
|
||||
return
|
||||
|
||||
# Revert to previous value if it exists
|
||||
if storage.data[plugin].has_key(key + dev):
|
||||
old_value = storage.data[plugin][key + dev]
|
||||
# Plugin could call Plugin.register_command with revert_fnc
|
||||
# set, so we should try to use specialized method for reverting.
|
||||
# However, if there's no method like that, use the original method
|
||||
# this decorator decorates.
|
||||
revert_fnc = self._commands[key][2]
|
||||
if not revert_fnc:
|
||||
if len(dev) == 0:
|
||||
target(self, old_value)
|
||||
else:
|
||||
target(self, dev[1:], old_value)
|
||||
del storage.data[plugin][key + dev]
|
||||
else:
|
||||
if len(dev) == 0:
|
||||
revert_fnc(old_value)
|
||||
else:
|
||||
revert_fnc(dev[1:], old_value)
|
||||
|
||||
# set it to new state and store old_value
|
||||
if not value or len(value) == 0:
|
||||
return False
|
||||
|
||||
old_value = target(self, *args, **kwargs)
|
||||
if len(old_value) != 0:
|
||||
storage.data[plugin][key + dev] = old_value
|
||||
storage.save()
|
||||
return True
|
||||
|
||||
# Fix the wrapper's call signature
|
||||
return wraps(target)(wrapper)
|
||||
|
||||
return my_decorator
|
||||
|
||||
# command_revert decorator
|
||||
def command_revert(plugin, key):
|
||||
def my_decorator(target):
|
||||
def wrapper(self, *args, **kwargs):
|
||||
dev = ""
|
||||
value = None
|
||||
if len(args) == 1:
|
||||
value = args[0]
|
||||
else:
|
||||
dev = "_" + args[0]
|
||||
value = args[1]
|
||||
|
||||
# revert to previous state
|
||||
storage = tuned.utils.storage.Storage.get_instance()
|
||||
if not storage.data.has_key(plugin):
|
||||
log.error("Storage file does not contain item with key %s" % (plugin))
|
||||
return
|
||||
|
||||
if storage.data[plugin].has_key(key + dev):
|
||||
old_value = storage.data[plugin][key + dev]
|
||||
if len(dev) == 0:
|
||||
target(self, old_value)
|
||||
else:
|
||||
target(self, dev[1:], old_value)
|
||||
del storage.data[plugin][key + dev]
|
||||
return True
|
||||
|
||||
# Fix the wrapper's call signature
|
||||
return wraps(target)(wrapper)
|
||||
|
||||
return my_decorator
|
||||
|
||||
def write_to_file(f, data):
|
||||
log.debug("Writing to file: %s < %s" % (f, data))
|
||||
try:
|
||||
fd = open(f, "w")
|
||||
fd.write(data)
|
||||
fd.write(str(data))
|
||||
fd.close()
|
||||
except (OSError,IOError) as e:
|
||||
log.error("Writing to file %s error: %s" % (f, e))
|
||||
|
|
|
|||
Loading…
Reference in a new issue