blob: 0a098260061c70b5e72b3474749fd29200fe01cf [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):
Brad Bishopc1e5e9f2016-09-29 09:40:01 -040028 super(HostSettingsObject, self).__init__(
29 conn=bus,
30 object_path=name,
31 validator=self.input_validator)
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053032 self.bus = bus
Adriana Kobylak41a925e2016-01-28 16:44:27 -060033 self.path = path
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053034 # Needed to ignore the validation on default networkconfig values as
35 # opposed to user giving the same.
36 self.adminmode = True
37
Adriana Kobylak41a925e2016-01-28 16:44:27 -060038 if not os.path.exists(path):
39 os.mkdir(path)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060040
41 # Listen to changes in the property values and sync them to the BMC
Brad Bishop2a9fe662016-08-31 12:37:35 -040042 bus.add_signal_receiver(
43 self.settings_signal_handler,
44 dbus_interface="org.freedesktop.DBus.Properties",
45 signal_name="PropertiesChanged",
46 path="/org/openbmc/settings/host0")
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060047
48 # Create the dbus properties
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053049 for i in settings[DBUS_NAME].iterkeys():
50 shk = settings[DBUS_NAME][i]
Adriana Kobylak41a925e2016-01-28 16:44:27 -060051 self.set_settings_property(shk['name'],
52 shk['type'],
53 shk['default'])
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053054 # Done with consuming factory settings.
55 self.adminmode = False
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060056
Adriana Kobylak41a925e2016-01-28 16:44:27 -060057 def get_bmc_value(self, name):
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060058 try:
Adriana Kobylak41a925e2016-01-28 16:44:27 -060059 with open(path.join(self.path, name), 'r') as f:
60 return f.read()
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060061 except (IOError):
62 pass
Adriana Kobylak41a925e2016-01-28 16:44:27 -060063 return None
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060064
Brad Bishop2a9fe662016-08-31 12:37:35 -040065 # Create dbus properties based on bmc value.
66 # This will be either a value previously set,
67 # or the default file value if the BMC value
68 # does not exist.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060069 def set_settings_property(self, name, type, value):
70 bmcv = self.get_bmc_value(name)
71 if bmcv:
72 value = bmcv
Brad Bishop2a9fe662016-08-31 12:37:35 -040073 if type == "i":
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053074 self.Set(DBUS_NAME, name, int(value))
Brad Bishop2a9fe662016-08-31 12:37:35 -040075 elif type == "s":
Adriana Kobylak41a925e2016-01-28 16:44:27 -060076 self.Set(DBUS_NAME, name, str(value))
Brad Bishop2a9fe662016-08-31 12:37:35 -040077 elif type == "b":
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +053078 self.Set(DBUS_NAME, name, bool(value))
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060079
80 # Save the settings to the BMC. This will write the settings value in
81 # individual files named by the property name to the BMC.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060082 def set_system_settings(self, name, value):
83 bmcv = self.get_bmc_value(name)
84 if bmcv != value:
85 filepath = path.join(self.path, name)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060086 with open(filepath, 'w') as f:
Adriana Kobylak41a925e2016-01-28 16:44:27 -060087 f.write(str(value))
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060088
89 # Signal handler for when one ore more settings properties were updated.
90 # This will sync the changes to the BMC.
Brad Bishop2a9fe662016-08-31 12:37:35 -040091 def settings_signal_handler(
92 self, interface_name, changed_properties, invalidated_properties):
Adriana Kobylak41a925e2016-01-28 16:44:27 -060093 for name, value in changed_properties.items():
94 self.set_system_settings(name, value)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060095
96 # Placeholder signal. Needed to register the settings interface.
Adriana Kobylak41a925e2016-01-28 16:44:27 -060097 @dbus.service.signal(DBUS_NAME, signature='s')
98 def SettingsUpdated(self, sname):
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -060099 pass
100
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530101 def validate_regex(self, regex, value):
102 if not re.compile(regex).search(value):
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400103 raise ValueError("Invalid input. Data does not satisfy regex")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530104
105 def validate_range(self, min, max, value):
106 if value not in range(min, max):
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400107 raise ValueError("Invalid input. Data not in allowed range")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530108
109 def validate_list_ignore_case(self, lst, value):
110 if value.lower() not in map(lambda val: val.lower(), lst):
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400111 raise ValueError("Invalid input. Data not in allowed values")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530112
113 # validate host network configuration
114 # need "ipaddress=,prefix=,gateway=,mac=,addr_type="
115 # Must be able to handle any order
116 def validate_net_config(self, value):
117 if self.adminmode:
118 return
119
120 # Need all of these to be given by the user.
121 user_config = []
122 all_config = ['ipaddress', 'prefix', 'gateway', 'mac', 'addr_type']
123
124 # This has a hard data format mentioned above so no blanks allowed.
125 if value.count(" ") or value.count("=") != 5:
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400126 raise ValueError("Invalid Network Data. No white spaces allowed")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530127
128 config = value.split(',')
129 for key_value in config:
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400130 key, value = key_value.split('=')
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530131 if not key or not value:
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400132 raise ValueError("Invalid key or Data")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530133
134 # Add the current key seen so we can compare at the end to see
135 # if all values have been given
136 user_config.append(key.lower())
137
138 if key.lower() == 'ipaddress' or key.lower() == 'gateway':
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400139 IP(value)
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530140
141 elif key.lower() == 'mac':
142 regex = '([a-fA-F0-9]{2}[:|\-]?){6}'
143 self.validate_regex(regex, value)
144
145 elif key.lower() == 'prefix':
146 self.validate_range(0, 33, int(value))
147
148 elif key.lower() == 'addr_type':
149 allowed = ["STATIC", "DYNAMIC"]
150 self.validate_list_ignore_case(allowed, value)
151
152 # Did user pass everything ??
153 if set(all_config) - set(user_config):
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400154 raise ValueError(
155 "Invalid Network Data. All information is mandatory")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530156
157 # Validate to see if the changes are in order
158 def input_validator(self, iface, proprty, value):
159 settings = s.SETTINGS
160 shk = {}
161 for key in settings[iface].iterkeys():
162 if proprty == settings[iface][key]['name']:
163 shk = settings[iface][key]
164 break
165
166 # User entered key is not present
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400167 if not shk:
168 raise KeyError("Invalid Property")
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530169
170 if shk['validation'] == 'list':
171 self.validate_list_ignore_case(shk['allowed'], value)
172
173 elif shk['validation'] == 'range':
174 self.validate_range(shk['min'], shk['max']+1, value)
175
176 elif shk['validation'] == 'regex':
177 self.validate_regex(shk['regex'], value)
178
179 elif shk['validation'] == 'custom':
Brad Bishopc1e5e9f2016-09-29 09:40:01 -0400180 getattr(self, shk['method'])(value)
Vishwanatha Subbanna5b090c62016-09-21 15:49:26 +0530181
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600182if __name__ == '__main__':
183 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
184
Brad Bishop5ef7fe62016-05-17 08:39:17 -0400185 bus = get_dbus()
Adriana Kobylak41a925e2016-01-28 16:44:27 -0600186 obj = HostSettingsObject(bus, OBJ_NAME, s.SETTINGS, "/var/lib/obmc/")
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600187 mainloop = gobject.MainLoop()
188
Brad Bishop2cbef3d2016-08-31 12:40:13 -0400189 obj.unmask_signals()
190 name = dbus.service.BusName(DBUS_NAME, bus)
Adriana Kobylak4c60e5e2016-01-10 15:22:45 -0600191 print "Running HostSettingsService"
192 mainloop.run()
Brad Bishop31c42f02016-09-29 09:35:32 -0400193
194# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4