blob: 997c56fc6d0ac8919434aa41f5bb5ce9073f465e [file] [log] [blame]
#!/usr/bin/python -u
import gobject
import dbus
import dbus.service
import dbus.mainloop.glib
import os
import os.path as path
import sys
from obmc.dbuslib.bindings import DbusProperties, get_dbus
from IPy import IP
settings_file_path = os.path.join(sys.prefix, 'share/obmc-phosphor-settings')
sys.path.insert(1, settings_file_path)
import settings_file as s
import re
DBUS_NAME = 'org.openbmc.settings.Host'
OBJ_NAME = '/org/openbmc/settings/host0'
CONTROL_INTF = 'org.openbmc.Settings'
class HostSettingsObject(DbusProperties):
def __init__(self, bus, name, settings, path):
super(HostSettingsObject, self).__init__(conn=bus, object_path=name,
validator=self.input_validator)
self.bus = bus
self.path = path
# Needed to ignore the validation on default networkconfig values as
# opposed to user giving the same.
self.adminmode = True
if not os.path.exists(path):
os.mkdir(path)
# Listen to changes in the property values and sync them to the BMC
bus.add_signal_receiver(
self.settings_signal_handler,
dbus_interface="org.freedesktop.DBus.Properties",
signal_name="PropertiesChanged",
path="/org/openbmc/settings/host0")
# 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'])
# Done with consuming factory settings.
self.adminmode = False
def get_bmc_value(self, name):
try:
with open(path.join(self.path, name), 'r') as f:
return f.read()
except (IOError):
pass
return None
# Create dbus properties based on bmc value.
# 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)
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))
# Save the settings to the BMC. This will write the settings value in
# individual files named by the property name to the BMC.
def set_system_settings(self, name, value):
bmcv = self.get_bmc_value(name)
if bmcv != value:
filepath = path.join(self.path, name)
with open(filepath, 'w') as f:
f.write(str(value))
# Signal handler for when one ore more settings properties were updated.
# This will sync the changes to the BMC.
def settings_signal_handler(
self, interface_name, changed_properties, invalidated_properties):
for name, value in changed_properties.items():
self.set_system_settings(name, value)
# Placeholder signal. Needed to register the settings interface.
@dbus.service.signal(DBUS_NAME, signature='s')
def SettingsUpdated(self, sname):
pass
def validate_regex(self, regex, value):
if not re.compile(regex).search(value):
raise ValueError, "Invalid input. Data does not satisfy regex"
def validate_range(self, min, max, value):
if value not in range(min, max):
raise ValueError, "Invalid input. Data not in allowed range"
def validate_list_ignore_case(self, lst, value):
if value.lower() not in map(lambda val: val.lower(), lst):
raise ValueError, "Invalid input. Data not in allowed values"
# validate host network configuration
# need "ipaddress=,prefix=,gateway=,mac=,addr_type="
# Must be able to handle any order
def validate_net_config(self, value):
if self.adminmode:
return
# Need all of these to be given by the user.
user_config = []
all_config = ['ipaddress', 'prefix', 'gateway', 'mac', 'addr_type']
# This has a hard data format mentioned above so no blanks allowed.
if value.count(" ") or value.count("=") != 5:
raise ValueError, "Invalid Network Data. No white spaces allowed"
config = value.split(',')
for key_value in config:
key , value = key_value.split('=')
if not key or not value:
raise ValueError, "Invalid key or Data"
# Add the current key seen so we can compare at the end to see
# if all values have been given
user_config.append(key.lower())
if key.lower() == 'ipaddress' or key.lower() == 'gateway':
IP(value)
elif key.lower() == 'mac':
regex = '([a-fA-F0-9]{2}[:|\-]?){6}'
self.validate_regex(regex, value)
elif key.lower() == 'prefix':
self.validate_range(0, 33, int(value))
elif key.lower() == 'addr_type':
allowed = ["STATIC", "DYNAMIC"]
self.validate_list_ignore_case(allowed, value)
# Did user pass everything ??
if set(all_config) - set(user_config):
raise ValueError, "Invalid Network Data. All information is mandatory"
# 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: raise KeyError, "Invalid Property"
if shk['validation'] == 'list':
self.validate_list_ignore_case(shk['allowed'], value)
elif shk['validation'] == 'range':
self.validate_range(shk['min'], shk['max']+1, value)
elif shk['validation'] == 'regex':
self.validate_regex(shk['regex'], value)
elif shk['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()
obj.unmask_signals()
name = dbus.service.BusName(DBUS_NAME, bus)
print "Running HostSettingsService"
mainloop.run()