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 <sergey.solomin@us.ibm.com>
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 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 @@
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 @@
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 @@
# 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 @@
# 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()