From 4a2433fdb0628871795c563f056c6d3f37560078 Mon Sep 17 00:00:00 2001 From: Sergey Solomin Date: Mon, 3 Oct 2016 10:22:57 -0500 Subject: phosphor-settingsd - Support YAML categories and sub-categories Currently phosphor-settingsd only supports a single category of 'host0', but the YAML format supports categories and sub-categories. This enhancement supports categories and sub-categories and automatically creates corresponding dbus objects to represent. Resolves openbmc/openbmc#551 Change-Id: I42bf246881ca08e8429771666415321fa997f0dc Signed-off-by: Sergey Solomin --- settings_manager.py | 102 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 30 deletions(-) (limited to 'settings_manager.py') diff --git a/settings_manager.py b/settings_manager.py index 0a09826..3e09ce5 100644 --- a/settings_manager.py +++ b/settings_manager.py @@ -19,9 +19,45 @@ import settings_file as s import re DBUS_NAME = 'org.openbmc.settings.Host' -OBJ_NAME = '/org/openbmc/settings/host0' CONTROL_INTF = 'org.openbmc.Settings' +def walk_nest(d, keys =()): + """Arrange dictionary keys and values. + + Walk the dictionary and establish every possible path + returned to and processed by 'create_object' below + """ + if isinstance(d, dict): + for k, v in d.iteritems(): + for rv in walk_nest(v, keys + (k, )): + yield rv + else: + yield keys, d + +def create_object(settings): + """Create and format objects. + + Parse dictionary file and return all objects and main properties + (name, type, default) for each attribute in the following format: + [obj_name, attr_ name, attr_ type, default] + """ + allobjects = {} + for compound_key, val in walk_nest(settings): + obj_name = compound_key[0].lower() + obj_name = obj_name.replace(".","/") + obj_name = "/" + obj_name + "0" + + for i in compound_key[1:len(compound_key)-2]: + obj_name = obj_name + "/" + i + + setting = compound_key[len(compound_key) - 2] + attribute = compound_key[len(compound_key) - 1] + + o = allobjects.setdefault(obj_name, {}) + s = o.setdefault(setting, {'name': None, 'type': None, 'default': None}) + s[attribute] = val + + return allobjects class HostSettingsObject(DbusProperties): def __init__(self, bus, name, settings, path): @@ -31,6 +67,9 @@ class HostSettingsObject(DbusProperties): validator=self.input_validator) self.bus = bus self.path = path + self.name = name + self.settings = settings + # Needed to ignore the validation on default networkconfig values as # opposed to user giving the same. self.adminmode = True @@ -43,14 +82,13 @@ class HostSettingsObject(DbusProperties): self.settings_signal_handler, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", - path="/org/openbmc/settings/host0") + path=name) # Create the dbus properties - for i in settings[DBUS_NAME].iterkeys(): - shk = settings[DBUS_NAME][i] - self.set_settings_property(shk['name'], - shk['type'], - shk['default']) + for setting in settings.itervalues(): + self.set_settings_property(setting['name'], + setting['type'], + setting['default']) # Done with consuming factory settings. self.adminmode = False @@ -66,16 +104,16 @@ class HostSettingsObject(DbusProperties): # This will be either a value previously set, # or the default file value if the BMC value # does not exist. - def set_settings_property(self, name, type, value): - bmcv = self.get_bmc_value(name) + def set_settings_property(self, attr_name, attr_type, value): + bmcv = self.get_bmc_value(attr_name) if bmcv: value = bmcv - if type == "i": - self.Set(DBUS_NAME, name, int(value)) - elif type == "s": - self.Set(DBUS_NAME, name, str(value)) - elif type == "b": - self.Set(DBUS_NAME, name, bool(value)) + if attr_type == "i": + self.Set(DBUS_NAME, attr_name, int(value)) + elif attr_type == "s": + self.Set(DBUS_NAME, attr_name, str(value)) + elif attr_type == "b": + self.Set(DBUS_NAME, attr_name, bool(value)) # Save the settings to the BMC. This will write the settings value in # individual files named by the property name to the BMC. @@ -156,37 +194,41 @@ class HostSettingsObject(DbusProperties): # Validate to see if the changes are in order def input_validator(self, iface, proprty, value): - settings = s.SETTINGS - shk = {} - for key in settings[iface].iterkeys(): - if proprty == settings[iface][key]['name']: - shk = settings[iface][key] - break - # User entered key is not present - if not shk: + shk = None + for attr in self.settings.itervalues(): + if attr['name'] == proprty: + shk = attr + + if shk is None: raise KeyError("Invalid Property") - if shk['validation'] == 'list': + validation = shk.get('validation', None) + + if validation == 'list': self.validate_list_ignore_case(shk['allowed'], value) - elif shk['validation'] == 'range': + elif validation == 'range': self.validate_range(shk['min'], shk['max']+1, value) - elif shk['validation'] == 'regex': + elif validation == 'regex': self.validate_regex(shk['regex'], value) - elif shk['validation'] == 'custom': + elif validation == 'custom': getattr(self, shk['method'])(value) if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = get_dbus() - obj = HostSettingsObject(bus, OBJ_NAME, s.SETTINGS, "/var/lib/obmc/") - mainloop = gobject.MainLoop() + allobjects = create_object(s.SETTINGS) + lastobject = None + objs = [] + for o, settings in allobjects.iteritems(): + objs.append(HostSettingsObject(bus, o, settings, "/var/lib/obmc/")) + objs[-1].unmask_signals() - obj.unmask_signals() + mainloop = gobject.MainLoop() name = dbus.service.BusName(DBUS_NAME, bus) print "Running HostSettingsService" mainloop.run() -- cgit v1.2.1