Skip to content

Commit b863272

Browse files
committed
fix: move ownership of Variables from Application to Profile
Currently, there is one global Variables object, as member of the global Application. When loading profiles, variables are added to it, but never removed. So when switching profiles, there are still variables present from the previous profile. With this commit, the Variables object is now owned by the Profile. It is created by the profile loader, so that more complex laod scenarios (multiple profiles, potentially with includes) still only use one Variables object. Signed-off-by: Adriaan Schmidt <adriaan.schmidt@siemens.com>
1 parent 0eb28ac commit b863272

15 files changed

Lines changed: 97 additions & 78 deletions

File tree

tests/unit/plugins/test_base.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,11 @@ class PluginBaseTestCase(unittest.TestCase):
3030
def setUp(self):
3131
self._plugin = DummyPlugin(monitors_repository,storage_factory,\
3232
hardware_inventory,device_matcher,device_matcher_udev,\
33-
plugin_instance_factory,None,None)
33+
plugin_instance_factory,None)
3434

3535
self._commands_plugin = CommandsPlugin(monitors_repository,\
3636
storage_factory,hardware_inventory,device_matcher,\
37-
device_matcher_udev,plugin_instance_factory,None,\
38-
profiles.variables.Variables())
37+
device_matcher_udev,plugin_instance_factory,None)
3938

4039
def test_get_effective_options(self):
4140
self.assertEqual(self._plugin._get_effective_options(\
@@ -51,13 +50,13 @@ def test_option_bool(self):
5150
def test_create_instance(self):
5251
instance = self._plugin.create_instance(\
5352
'first_instance',0,'test','test','test','test',\
54-
{'default_option1':'default_value2'})
53+
{'default_option1':'default_value2'},None)
5554
self.assertIsNotNone(instance)
5655

5756
def test_destroy_instance(self):
5857
instance = self._plugin.create_instance(\
5958
'first_instance',0,'test','test','test','test',\
60-
{'default_option1':'default_value2'})
59+
{'default_option1':'default_value2'},None)
6160
instance.plugin.init_devices()
6261

6362
self._plugin.destroy_instance(instance)
@@ -67,7 +66,7 @@ def test_get_matching_devices(self):
6766
""" without udev regex """
6867
instance = self._plugin.create_instance(\
6968
'first_instance',0,'right_device*',None,'test','test',\
70-
{'default_option1':'default_value2'})
69+
{'default_option1':'default_value2'},None)
7170

7271
self.assertEqual(self._plugin._get_matching_devices(\
7372
instance,['bad_device','right_device1','right_device2']),\
@@ -76,7 +75,7 @@ def test_get_matching_devices(self):
7675
""" with udev regex """
7776
instance = self._plugin.create_instance(\
7877
'second_instance',0,'right_device*','device[1-2]','test','test',\
79-
{'default_option1':'default_value2'})
78+
{'default_option1':'default_value2'},None)
8079

8180
device1 = DummyDevice('device1',{'name':'device1'})
8281
device2 = DummyDevice('device2',{'name':'device2'})
@@ -105,15 +104,15 @@ def test_check_commands(self):
105104

106105
def test_execute_all_non_device_commands(self):
107106
instance = self._commands_plugin.create_instance('test_instance',0,'',\
108-
'','','',{'size':'XXL'})
107+
'','','',{'size':'XXL'},profiles.variables.Variables())
109108

110109
self._commands_plugin._execute_all_non_device_commands(instance)
111110

112111
self.assertEqual(self._commands_plugin._size,'XXL')
113112

114113
def test_execute_all_device_commands(self):
115114
instance = self._commands_plugin.create_instance('test_instance',0,'',\
116-
'','','',{'device_setting':'010'})
115+
'','','',{'device_setting':'010'},profiles.variables.Variables())
117116

118117
device1 = DummyDevice('device1',{})
119118
device2 = DummyDevice('device2',{})
@@ -134,7 +133,7 @@ def test_process_assignment_modifiers(self):
134133

135134
def test_get_current_value(self):
136135
instance = self._commands_plugin.create_instance('test_instance',0,'',\
137-
'','','',{})
136+
'','','',{},None)
138137

139138
command = [com for com in self._commands_plugin._commands.values()\
140139
if com['name'] == 'size'][0]

tests/unit/profiles/test_loader.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ def setUp(self):
5353
locator = profiles.Locator([self._profiles_dir])
5454
factory = profiles.Factory()
5555
merger = profiles.Merger()
56-
self._loader = profiles.Loader(locator,factory,merger,None,\
57-
profiles.variables.Variables())
56+
self._loader = profiles.Loader(locator,factory,merger,None)
5857

5958
def test_safe_name(self):
6059
self.assertFalse(self._loader.safe_name('*'))

tests/unit/profiles/test_merger.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import unittest
22
from tuned.profiles.merger import Merger
33
from tuned.profiles.profile import Profile
4+
from tuned.profiles.variables import Variables
45
from collections import OrderedDict
56

67
class MergerTestCase(unittest.TestCase):
78
def test_merge_without_replace(self):
89
merger = Merger()
10+
variables = Variables()
911
config1 = OrderedDict([
1012
("main", {"test_option" : "test_value1"}),
1113
("net", { "devices": "em0", "custom": "custom_value"}),
1214
])
13-
profile1 = Profile('test_profile1',config1)
15+
profile1 = Profile('test_profile1',config1,variables)
1416
config2 = OrderedDict([
1517
('main', {'test_option' : 'test_value2'}),
1618
('net', { 'devices': 'em1' }),
1719
])
18-
profile2 = Profile("test_profile2",config2)
20+
profile2 = Profile("test_profile2",config2,variables)
1921

2022
merged_profile = merger.merge([profile1, profile2])
2123

@@ -27,16 +29,17 @@ def test_merge_without_replace(self):
2729

2830
def test_merge_with_replace(self):
2931
merger = Merger()
32+
variables = Variables()
3033
config1 = OrderedDict([
3134
("main", {"test_option" : "test_value1"}),
3235
("net", { "devices": "em0", "custom": "option"}),
3336
])
34-
profile1 = Profile('test_profile1',config1)
37+
profile1 = Profile('test_profile1',config1,variables)
3538
config2 = OrderedDict([
3639
("main", {"test_option" : "test_value2"}),
3740
("net", { "devices": "em1", "replace": True }),
3841
])
39-
profile2 = Profile('test_profile2',config2)
42+
profile2 = Profile('test_profile2',config2,variables)
4043
merged_profile = merger.merge([profile1, profile2])
4144

4245
self.assertEqual(merged_profile.options["test_option"],"test_value2")
@@ -46,15 +49,16 @@ def test_merge_with_replace(self):
4649

4750
def test_merge_multiple_order(self):
4851
merger = Merger()
52+
variables = Variables()
4953
config1 = OrderedDict([ ("main", {"test_option" : "test_value1"}),\
5054
("net", { "devices": "em0" }) ])
51-
profile1 = Profile('test_profile1',config1)
55+
profile1 = Profile('test_profile1',config1,variables)
5256
config2 = OrderedDict([ ("main", {"test_option" : "test_value2"}),\
5357
("net", { "devices": "em1" }) ])
54-
profile2 = Profile('test_profile2',config2)
58+
profile2 = Profile('test_profile2',config2,variables)
5559
config3 = OrderedDict([ ("main", {"test_option" : "test_value3"}),\
5660
("net", { "devices": "em2" }) ])
57-
profile3 = Profile('test_profile3',config3)
61+
profile3 = Profile('test_profile3',config3,variables)
5862
merged_profile = merger.merge([profile1, profile2, profile3])
5963

6064
self.assertEqual(merged_profile.options["test_option"],"test_value3")

tests/unit/profiles/test_profile.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,33 @@ def _create_unit(self, name, config):
99
class ProfileTestCase(unittest.TestCase):
1010

1111
def test_init(self):
12-
MockProfile("test", {})
12+
MockProfile("test", {}, None)
1313

1414
def test_create_units(self):
1515
profile = MockProfile("test", {
1616
"main": { "anything": 10 },
1717
"network" : { "type": "net", "devices": "*" },
1818
"storage" : { "type": "disk" },
19-
})
19+
}, None)
2020

2121
self.assertIs(type(profile.units), collections.OrderedDict)
2222
self.assertEqual(len(profile.units), 2)
2323
self.assertListEqual(sorted([name_config for name_config in profile.units]), sorted(["network", "storage"]))
2424

2525
def test_create_units_empty(self):
26-
profile = MockProfile("test", {"main":{}})
26+
profile = MockProfile("test", {"main":{}}, None)
2727

2828
self.assertIs(type(profile.units), collections.OrderedDict)
2929
self.assertEqual(len(profile.units), 0)
3030

3131
def test_sets_name(self):
32-
profile1 = MockProfile("test_one", {})
33-
profile2 = MockProfile("test_two", {})
32+
profile1 = MockProfile("test_one", {}, None)
33+
profile2 = MockProfile("test_two", {}, None)
3434
self.assertEqual(profile1.name, "test_one")
3535
self.assertEqual(profile2.name, "test_two")
3636

3737
def test_change_name(self):
38-
profile = MockProfile("oldname", {})
38+
profile = MockProfile("oldname", {}, None)
3939
self.assertEqual(profile.name, "oldname")
4040
profile.name = "newname"
4141
self.assertEqual(profile.name, "newname")
@@ -44,15 +44,15 @@ def test_sets_options(self):
4444
profile = MockProfile("test", {
4545
"main": { "anything": 10 },
4646
"network" : { "type": "net", "devices": "*" },
47-
})
47+
}, None)
4848

4949
self.assertIs(type(profile.options), dict)
5050
self.assertEqual(profile.options["anything"], 10)
5151

5252
def test_sets_options_empty(self):
5353
profile = MockProfile("test", {
5454
"storage" : { "type": "disk" },
55-
})
55+
}, None)
5656

5757
self.assertIs(type(profile.options), dict)
5858
self.assertEqual(len(profile.options), 0)

tuned/daemon/application.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,9 @@ def __init__(self, profile_name = None, config = None):
3939
device_matcher = hardware.DeviceMatcher()
4040
device_matcher_udev = hardware.DeviceMatcherUdev()
4141
plugin_instance_factory = plugins.instance.Factory()
42-
self.variables = profiles.variables.Variables()
4342

4443
plugins_repository = plugins.Repository(monitors_repository, storage_factory, hardware_inventory,\
45-
device_matcher, device_matcher_udev, plugin_instance_factory, self.config, self.variables)
44+
device_matcher, device_matcher_udev, plugin_instance_factory, self.config)
4645
def_instance_priority = int(self.config.get(consts.CFG_DEFAULT_INSTANCE_PRIORITY, consts.CFG_DEF_DEFAULT_INSTANCE_PRIORITY))
4746
unit_manager = units.Manager(
4847
plugins_repository, monitors_repository,
@@ -51,7 +50,7 @@ def __init__(self, profile_name = None, config = None):
5150
profile_factory = profiles.Factory()
5251
profile_merger = profiles.Merger()
5352
profile_locator = profiles.Locator(self.config.get_list(consts.CFG_PROFILE_DIRS, consts.CFG_DEF_PROFILE_DIRS))
54-
profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config, self.variables)
53+
profile_loader = profiles.Loader(profile_locator, profile_factory, profile_merger, self.config)
5554

5655
self._daemon = daemon.Daemon(unit_manager, profile_loader, profile_name, self.config, self)
5756
self._controller = controller.Controller(self._daemon, self.config)

tuned/daemon/daemon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def _thread_code(self):
198198
if self._profile is None:
199199
raise TunedException("Cannot start the daemon without setting a profile.")
200200

201-
self._unit_manager.create(self._profile.units)
201+
self._unit_manager.create(self._profile.units, self._profile.variables)
202202
self._save_active_profile(" ".join(self._active_profiles),
203203
self._manual)
204204
self._save_post_loaded_profile(self._post_loaded_profile)

tuned/plugins/base.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class Plugin(object):
1919
Intentionally a lot of logic is included in the plugin to increase plugin flexibility.
2020
"""
2121

22-
def __init__(self, monitors_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, instance_factory, global_cfg, variables):
22+
def __init__(self, monitors_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, instance_factory, global_cfg):
2323
"""Plugin constructor."""
2424

2525
self._storage = storage_factory.create(self.__class__.__name__)
@@ -33,7 +33,6 @@ def __init__(self, monitors_repository, storage_factory, hardware_inventory, dev
3333
self._init_commands()
3434

3535
self._global_cfg = global_cfg
36-
self._variables = variables
3736
self._has_dynamic_options = False
3837
self._devices_inited = False
3938

@@ -93,14 +92,14 @@ def _option_bool(self, value):
9392
# Interface for manipulation with instances of the plugin.
9493
#
9594

96-
def create_instance(self, name, priority, devices_expression, devices_udev_regex, script_pre, script_post, options):
95+
def create_instance(self, name, priority, devices_expression, devices_udev_regex, script_pre, script_post, options, variables):
9796
"""Create new instance of the plugin and seize the devices."""
9897
if name in self._instances:
9998
raise Exception("Plugin instance with name '%s' already exists." % name)
10099

101100
effective_options = self._get_effective_options(options)
102101
instance = self._instance_factory.create(self, name, priority, devices_expression, devices_udev_regex, \
103-
script_pre, script_post, effective_options)
102+
script_pre, script_post, effective_options, variables)
104103
self._instances[name] = instance
105104
self._instances = collections.OrderedDict(sorted(self._instances.items(), key=lambda x: x[1].priority))
106105

@@ -249,8 +248,8 @@ def _call_device_script(self, instance, script, op, devices, rollback = consts.R
249248
dir_name = os.path.dirname(script)
250249
ret = True
251250
for dev in devices:
252-
environ = os.environ
253-
environ.update(self._variables.get_env())
251+
environ = os.environ.copy()
252+
environ.update(instance._variables.get_env())
254253
arguments = [op]
255254
if rollback == consts.ROLLBACK_FULL:
256255
arguments.append("full_rollback")
@@ -459,13 +458,13 @@ def _storage_unset(self, instance, command, device_name=None):
459458

460459
def _execute_all_non_device_commands(self, instance):
461460
for command in [command for command in list(self._commands.values()) if not command["per_device"]]:
462-
new_value = self._variables.expand(instance.options.get(command["name"], None))
461+
new_value = instance._variables.expand(instance.options.get(command["name"], None))
463462
if new_value is not None:
464463
self._execute_non_device_command(instance, command, new_value)
465464

466465
def _execute_all_device_commands(self, instance, devices):
467466
for command in [command for command in list(self._commands.values()) if command["per_device"]]:
468-
new_value = self._variables.expand(instance.options.get(command["name"], None))
467+
new_value = instance._variables.expand(instance.options.get(command["name"], None))
469468
if new_value is None:
470469
continue
471470
for device in devices:
@@ -474,7 +473,7 @@ def _execute_all_device_commands(self, instance, devices):
474473
def _verify_all_non_device_commands(self, instance, ignore_missing):
475474
ret = True
476475
for command in [command for command in list(self._commands.values()) if not command["per_device"]]:
477-
new_value = self._variables.expand(instance.options.get(command["name"], None))
476+
new_value = instance._variables.expand(instance.options.get(command["name"], None))
478477
if new_value is not None:
479478
if self._verify_non_device_command(instance, command, new_value, ignore_missing) == False:
480479
ret = False
@@ -483,7 +482,7 @@ def _verify_all_non_device_commands(self, instance, ignore_missing):
483482
def _verify_all_device_commands(self, instance, devices, ignore_missing):
484483
ret = True
485484
for command in [command for command in list(self._commands.values()) if command["per_device"]]:
486-
new_value = self._variables.expand(instance.options.get(command["name"], None))
485+
new_value = instance._variables.expand(instance.options.get(command["name"], None))
487486
if new_value is None:
488487
continue
489488
for device in devices:

tuned/plugins/instance/instance.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ class Instance(object):
44
"""
55
"""
66

7-
def __init__(self, plugin, name, priority, devices_expression, devices_udev_regex, script_pre, script_post, options):
7+
def __init__(self, plugin, name, priority, devices_expression, devices_udev_regex, script_pre, script_post, options, variables):
88
self._plugin = plugin
99
self._name = name
1010
self._devices_expression = devices_expression
1111
self._devices_udev_regex = devices_udev_regex
1212
self._script_pre = script_pre
1313
self._script_post = script_post
1414
self._options = options
15+
self._variables = variables
1516

1617
self._active = True
1718
self._priority = priority
@@ -71,6 +72,10 @@ def script_post(self):
7172
def options(self):
7273
return self._options
7374

75+
@property
76+
def variables(self):
77+
return self._variables
78+
7479
@property
7580
def has_static_tuning(self):
7681
return self._has_static_tuning

tuned/plugins/plugin_sysfs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def _instance_cleanup(self, instance):
5151

5252
def _instance_apply_static(self, instance):
5353
for key, value in list(instance._sysfs.items()):
54-
v = self._variables.expand(value)
54+
v = instance.variables.expand(value)
5555
for f in glob.iglob(key):
5656
if self._check_sysfs(f):
5757
instance._sysfs_original[f] = self._read_sysfs(f)
@@ -62,7 +62,7 @@ def _instance_apply_static(self, instance):
6262
def _instance_verify_static(self, instance, ignore_missing, devices):
6363
ret = True
6464
for key, value in list(instance._sysfs.items()):
65-
v = self._variables.expand(value)
65+
v = instance.variables.expand(value)
6666
for f in glob.iglob(key):
6767
if self._check_sysfs(f):
6868
curr_val = self._read_sysfs(f)

tuned/plugins/repository.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
class Repository(ClassLoader):
1010

11-
def __init__(self, monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg, variables):
11+
def __init__(self, monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg):
1212
super(Repository, self).__init__()
1313
self._plugins = set()
1414
self._monitor_repository = monitor_repository
@@ -18,7 +18,6 @@ def __init__(self, monitor_repository, storage_factory, hardware_inventory, devi
1818
self._device_matcher_udev = device_matcher_udev
1919
self._plugin_instance_factory = plugin_instance_factory
2020
self._global_cfg = global_cfg
21-
self._variables = variables
2221

2322
@property
2423
def plugins(self):
@@ -33,7 +32,7 @@ def create(self, plugin_name):
3332
log.debug("creating plugin %s" % plugin_name)
3433
plugin_cls = self.load_class(plugin_name)
3534
plugin_instance = plugin_cls(self._monitor_repository, self._storage_factory, self._hardware_inventory, self._device_matcher,\
36-
self._device_matcher_udev, self._plugin_instance_factory, self._global_cfg, self._variables)
35+
self._device_matcher_udev, self._plugin_instance_factory, self._global_cfg)
3736
self._plugins.add(plugin_instance)
3837
return plugin_instance
3938

0 commit comments

Comments
 (0)