blob: 90c3e39786cf499336c6c2120bf657d57c0bfe61 [file] [log] [blame]
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -06001#!/usr/bin/python -u
2
3import gobject
4import dbus
5import dbus.service
6import dbus.mainloop.glib
Adriana Kobylak41a925e2016-01-28 16:44:27 -06007import os
8import os.path as path
Adriana Kobylak256be782016-08-24 15:43:16 -05009import sys
Brad Bishop5ef7fe62016-05-17 08:39:17 -040010from obmc.dbuslib.bindings import DbusProperties, get_dbus
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053011from IPy import IP
Adriana Kobylak256be782016-08-24 15:43:16 -050012
Brad Bishop966fcd52016-09-29 09:22:32 -040013settings_file_path = os.path.join(
14 sys.prefix,
15 'share',
16 'phosphor-settings')
Adriana Kobylak256be782016-08-24 15:43:16 -050017sys.path.insert(1, settings_file_path)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060018import settings_file as s
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053019import re
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060020
21DBUS_NAME = 'org.openbmc.settings.Host'
22OBJ_NAME = '/org/openbmc/settings/host0'
23CONTROL_INTF = 'org.openbmc.Settings'
24
Brad Bishop2a9fe662016-08-31 12:37:35 -040025
Brad Bishop5ef7fe62016-05-17 08:39:17 -040026class HostSettingsObject(DbusProperties):
Adriana Kobylak41a925e2016-01-28 16:44:27 -060027 def __init__(self, bus, name, settings, path):
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053028 super(HostSettingsObject, self).__init__(conn=bus, object_path=name,
29 validator=self.input_validator)
30 self.bus = bus
Adriana Kobylak41a925e2016-01-28 16:44:27 -060031 self.path = path
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053032 # Needed to ignore the validation on default networkconfig values as
33 # opposed to user giving the same.
34 self.adminmode = True
35
Adriana Kobylak41a925e2016-01-28 16:44:27 -060036 if not os.path.exists(path):
37 os.mkdir(path)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060038
39 # Listen to changes in the property values and sync them to the BMC
Brad Bishop2a9fe662016-08-31 12:37:35 -040040 bus.add_signal_receiver(
41 self.settings_signal_handler,
42 dbus_interface="org.freedesktop.DBus.Properties",
43 signal_name="PropertiesChanged",
44 path="/org/openbmc/settings/host0")
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060045
46 # Create the dbus properties
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053047 for i in settings[DBUS_NAME].iterkeys():
48 shk = settings[DBUS_NAME][i]
Adriana Kobylak41a925e2016-01-28 16:44:27 -060049 self.set_settings_property(shk['name'],
50 shk['type'],
51 shk['default'])
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053052 # Done with consuming factory settings.
53 self.adminmode = False
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060054
Adriana Kobylak41a925e2016-01-28 16:44:27 -060055 def get_bmc_value(self, name):
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060056 try:
Adriana Kobylak41a925e2016-01-28 16:44:27 -060057 with open(path.join(self.path, name), 'r') as f:
58 return f.read()
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060059 except (IOError):
60 pass
Adriana Kobylak41a925e2016-01-28 16:44:27 -060061 return None
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060062
Brad Bishop2a9fe662016-08-31 12:37:35 -040063 # Create dbus properties based on bmc value.
64 # This will be either a value previously set,
65 # or the default file value if the BMC value
66 # does not exist.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060067 def set_settings_property(self, name, type, value):
68 bmcv = self.get_bmc_value(name)
69 if bmcv:
70 value = bmcv
Brad Bishop2a9fe662016-08-31 12:37:35 -040071 if type == "i":
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053072 self.Set(DBUS_NAME, name, int(value))
Brad Bishop2a9fe662016-08-31 12:37:35 -040073 elif type == "s":
Adriana Kobylak41a925e2016-01-28 16:44:27 -060074 self.Set(DBUS_NAME, name, str(value))
Brad Bishop2a9fe662016-08-31 12:37:35 -040075 elif type == "b":
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053076 self.Set(DBUS_NAME, name, bool(value))
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060077
78 # Save the settings to the BMC. This will write the settings value in
79 # individual files named by the property name to the BMC.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060080 def set_system_settings(self, name, value):
81 bmcv = self.get_bmc_value(name)
82 if bmcv != value:
83 filepath = path.join(self.path, name)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060084 with open(filepath, 'w') as f:
Adriana Kobylak41a925e2016-01-28 16:44:27 -060085 f.write(str(value))
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060086
87 # Signal handler for when one ore more settings properties were updated.
88 # This will sync the changes to the BMC.
Brad Bishop2a9fe662016-08-31 12:37:35 -040089 def settings_signal_handler(
90 self, interface_name, changed_properties, invalidated_properties):
Adriana Kobylak41a925e2016-01-28 16:44:27 -060091 for name, value in changed_properties.items():
92 self.set_system_settings(name, value)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060093
94 # Placeholder signal. Needed to register the settings interface.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060095 @dbus.service.signal(DBUS_NAME, signature='s')
96 def SettingsUpdated(self, sname):
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060097 pass
98
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053099 def validate_regex(self, regex, value):
100 if not re.compile(regex).search(value):
101 raise ValueError, "Invalid input. Data does not satisfy regex"
102
103 def validate_range(self, min, max, value):
104 if value not in range(min, max):
105 raise ValueError, "Invalid input. Data not in allowed range"
106
107 def validate_list_ignore_case(self, lst, value):
108 if value.lower() not in map(lambda val: val.lower(), lst):
109 raise ValueError, "Invalid input. Data not in allowed values"
110
111 # validate host network configuration
112 # need "ipaddress=,prefix=,gateway=,mac=,addr_type="
113 # Must be able to handle any order
114 def validate_net_config(self, value):
115 if self.adminmode:
116 return
117
118 # Need all of these to be given by the user.
119 user_config = []
120 all_config = ['ipaddress', 'prefix', 'gateway', 'mac', 'addr_type']
121
122 # This has a hard data format mentioned above so no blanks allowed.
123 if value.count(" ") or value.count("=") != 5:
124 raise ValueError, "Invalid Network Data. No white spaces allowed"
125
126 config = value.split(',')
127 for key_value in config:
128 key , value = key_value.split('=')
129 if not key or not value:
130 raise ValueError, "Invalid key or Data"
131
132 # Add the current key seen so we can compare at the end to see
133 # if all values have been given
134 user_config.append(key.lower())
135
136 if key.lower() == 'ipaddress' or key.lower() == 'gateway':
137 IP(value)
138
139 elif key.lower() == 'mac':
140 regex = '([a-fA-F0-9]{2}[:|\-]?){6}'
141 self.validate_regex(regex, value)
142
143 elif key.lower() == 'prefix':
144 self.validate_range(0, 33, int(value))
145
146 elif key.lower() == 'addr_type':
147 allowed = ["STATIC", "DYNAMIC"]
148 self.validate_list_ignore_case(allowed, value)
149
150 # Did user pass everything ??
151 if set(all_config) - set(user_config):
152 raise ValueError, "Invalid Network Data. All information is mandatory"
153
154 # Validate to see if the changes are in order
155 def input_validator(self, iface, proprty, value):
156 settings = s.SETTINGS
157 shk = {}
158 for key in settings[iface].iterkeys():
159 if proprty == settings[iface][key]['name']:
160 shk = settings[iface][key]
161 break
162
163 # User entered key is not present
164 if not shk: raise KeyError, "Invalid Property"
165
166 if shk['validation'] == 'list':
167 self.validate_list_ignore_case(shk['allowed'], value)
168
169 elif shk['validation'] == 'range':
170 self.validate_range(shk['min'], shk['max']+1, value)
171
172 elif shk['validation'] == 'regex':
173 self.validate_regex(shk['regex'], value)
174
175 elif shk['validation'] == 'custom':
176 getattr(self, shk['method'])(value)
177
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600178if __name__ == '__main__':
179 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
180
Brad Bishop5ef7fe62016-05-17 08:39:17 -0400181 bus = get_dbus()
Adriana Kobylak41a925e2016-01-28 16:44:27 -0600182 obj = HostSettingsObject(bus, OBJ_NAME, s.SETTINGS, "/var/lib/obmc/")
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600183 mainloop = gobject.MainLoop()
184
Brad Bishop2cbef3d2016-08-31 12:40:13 -0400185 obj.unmask_signals()
186 name = dbus.service.BusName(DBUS_NAME, bus)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600187 print "Running HostSettingsService"
188 mainloop.run()