diff options
author | Deepak Kodihalli <dkodihal@in.ibm.com> | 2017-06-23 23:05:47 -0500 |
---|---|---|
committer | Deepak Kodihalli <dkodihal@in.ibm.com> | 2017-07-03 09:33:52 -0500 |
commit | 7a6f2526fd46badb145baa4309f88036af1bee9c (patch) | |
tree | 48a5a3a94dfeb040aefdd0396beeb177da978b00 | |
parent | 9711211cb53df56fb5bdf84e3882672ac7ec8a50 (diff) | |
download | phosphor-settingsd-7a6f2526fd46badb145baa4309f88036af1bee9c.tar.gz phosphor-settingsd-7a6f2526fd46badb145baa4309f88036af1bee9c.zip |
Persist changes to settings
Persist changes made to settings, if any, such that those changes can be
restored upon a reboot.
Use Cereal for serialization of the settings' properties. Since the
settings code is generated based on a system specific settings policy,
generate the serialization code as well such that only relevant settings
are serialized.
Resolves openbmc/openbmc#1764.
Change-Id: Id8bd84a9455cf4348b22f255d038b050d004eb7c
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
-rwxr-xr-x | Makefile.am | 3 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | settings_main.cpp | 3 | ||||
-rw-r--r-- | settings_manager.mako.hpp | 156 |
4 files changed, 146 insertions, 23 deletions
diff --git a/Makefile.am b/Makefile.am index 65f95cb..55ea2d6 100755 --- a/Makefile.am +++ b/Makefile.am @@ -30,4 +30,5 @@ phosphor_settings_manager_CXXFLAGS = \ phosphor_settings_manager_LDADD = \ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ - $(SDBUSPLUS_LIBS) + $(SDBUSPLUS_LIBS) \ + -lstdc++fs diff --git a/configure.ac b/configure.ac index 3ee9c6b..083d623 100644 --- a/configure.ac +++ b/configure.ac @@ -32,5 +32,12 @@ AS_IF([test "x$SETTINGS_YAML" == "x"], [SETTINGS_YAML="settings_example.yaml"]) SETTINGSGEN="$PYTHON $srcdir/settings.py -i $SETTINGS_YAML" AC_SUBST(SETTINGSGEN) +AC_ARG_VAR(SETTINGS_PERSIST_PATH, \ + [Path of directory housing persisted settings.]) +AS_IF([test "x$SETTINGS_PERSIST_PATH" == "x"], \ + [SETTINGS_PERSIST_PATH="/var/lib/phosphor-settings-manager/settings"]) +AC_DEFINE_UNQUOTED([SETTINGS_PERSIST_PATH], ["$SETTINGS_PERSIST_PATH"], \ + [Path of directory housing persisted settings]) + AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/settings_main.cpp b/settings_main.cpp index 0d775e2..fbb9a0d 100644 --- a/settings_main.cpp +++ b/settings_main.cpp @@ -11,11 +11,10 @@ int main(int argc, char *argv[]) // the object namespace and are not under a (settings) root. Hence register // "/" as the path. sdbusplus::server::manager::manager objManager(bus, "/"); + bus.request_name(SETTINGS_BUSNAME); phosphor::settings::Manager mgr(bus); - bus.request_name(SETTINGS_BUSNAME); - while(true) { bus.process_discard(); diff --git a/settings_manager.mako.hpp b/settings_manager.mako.hpp index acdf66d..6a4f1bf 100644 --- a/settings_manager.mako.hpp +++ b/settings_manager.mako.hpp @@ -1,17 +1,23 @@ ## This file is a template. The comment below is emitted ## into the rendered file; feel free to edit this file. // WARNING: Generated header. Do not edit! - <% +from collections import defaultdict objects = list(settingsDict.viewkeys()) -ns_list = [] -includes = [] +sdbusplus_namespaces = [] +sdbusplus_includes = [] +interfaces = [] +props = defaultdict(list) -def get_setting_type(setting_intf): +def get_setting_sdbusplus_type(setting_intf): setting = "sdbusplus::" + setting_intf.replace('.', '::') i = setting.rfind('::') setting = setting[:i] + '::server::' + setting[i+2:] return setting + +def get_setting_type(setting_intf): + setting = setting_intf.replace('.', '::') + return setting %>\ #pragma once @@ -20,30 +26,130 @@ def get_setting_type(setting_intf): include = settingsDict[object]['Interface'] include = include.replace('.', '/') include = include + "/server.hpp" - includes.append(include) + sdbusplus_includes.append(include) %>\ % endfor -% for i in set(includes): +#include <cereal/archives/json.hpp> +#include <fstream> +#include <utility> +#include <experimental/filesystem> +#include "config.h" + +% for i in set(sdbusplus_includes): #include "${i}" % endfor % for object in objects: <% - ns = get_setting_type(settingsDict[object]['Interface']) + ns = get_setting_sdbusplus_type(settingsDict[object]['Interface']) i = ns.rfind('::') ns = ns[:i] - ns_list.append(ns) + sdbusplus_namespaces.append(ns) %>\ % endfor -% for n in set(ns_list): -using namespace ${n}; -% endfor namespace phosphor { namespace settings { +namespace fs = std::experimental::filesystem; + +% for n in set(sdbusplus_namespaces): +using namespace ${n}; +% endfor + +% for object in objects: +<% + intf = settingsDict[object]['Interface'] + interfaces.append(intf) + if intf not in props: + for property, value in settingsDict[object]['Defaults'].items(): + props[intf].append(property) +%>\ +% endfor +% for intf in set(interfaces): +<% + ns = intf.split(".") + sdbusplus_type = get_setting_sdbusplus_type(intf) +%>\ +% for n in ns: +namespace ${n} +{ +% endfor + +using Base = ${sdbusplus_type}; +<% parent = "sdbusplus::server::object::object" + "<" + sdbusplus_type + ">" %>\ +using Parent = ${parent}; + +class Impl : public Parent +{ + public: + Impl(sdbusplus::bus::bus& bus, const char* path): + Parent(bus, path, true), + path(path) + { + } + virtual ~Impl() = default; + +% for arg in props[intf]: +<% t = arg[:1].lower() + arg[1:] %>\ + decltype(std::declval<Base>().${t}()) ${t}(decltype(std::declval<Base>().${t}()) value) override + { + auto result = Base::${t}(); + if (value != result) + { + fs::path p(SETTINGS_PERSIST_PATH); + p /= path; + fs::create_directories(p.parent_path()); + std::ofstream os(p.c_str(), std::ios::binary); + cereal::JSONOutputArchive oarchive(os); + result = Base::${t}(value); + oarchive(*this); + } + return result; + } + using Base::${t}; + + private: + fs::path path; +% endfor +}; + +template<class Archive> +void save(Archive& a, + const Impl& setting) +{ +<% + args = ["setting." + p[:1].lower() + p[1:] + "()" for p in props[intf]] + args = ','.join(args) +%>\ + a(${args}); +} + +template<class Archive> +void load(Archive& a, + Impl& setting) +{ +% for arg in props[intf]: +<% t = "setting." + arg[:1].lower() + arg[1:] + "()" %>\ + decltype(${t}) ${arg}{}; +% endfor +<% + args = ','.join(props[intf]) +%>\ + a(${args}); +% for arg in props[intf]: +<% t = "setting." + arg[:1].lower() + arg[1:] + "(" + arg + ")" %>\ + ${t}; +% endfor +} + +% for n in reversed(ns): +} // namespace ${n} +% endfor +% endfor + /** @class Manager * * @brief Compose settings objects and put them on the bus. @@ -63,10 +169,11 @@ class Manager */ Manager(sdbusplus::bus::bus& bus) { + fs::path path{}; settings = std::make_tuple( % for index, object in enumerate(objects): -<% type = get_setting_type(settingsDict[object]['Interface']) %>\ +<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\ std::make_unique<${type}>( bus, % if index < len(settingsDict) - 1: @@ -77,13 +184,22 @@ class Manager % endfor % for index, object in enumerate(objects): - % if 'Defaults' in settingsDict[object].viewkeys(): - % for property, value in settingsDict[object]['Defaults'].items(): - std::get<${index}>(settings)-> - setPropertyByName("${property}", ${value}); - % endfor - % endif - bus.emit_object_added("${object}"); + % for property, value in settingsDict[object]['Defaults'].items(): +<% p = property[:1].lower() + property[1:] %>\ + path = fs::path(SETTINGS_PERSIST_PATH) / "${object}"; + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in); + cereal::JSONInputArchive iarchive(is); + iarchive(*std::get<${index}>(settings)); + } + else + { + std::get<${index}>(settings)-> + ${get_setting_sdbusplus_type(settingsDict[object]['Interface'])}::${p}(${value}); + } + % endfor + std::get<${index}>(settings)->emit_object_added(); % endfor } @@ -92,7 +208,7 @@ class Manager /* @brief Composition of settings objects. */ std::tuple< % for index, object in enumerate(objects): -<% type = get_setting_type(settingsDict[object]['Interface']) %>\ +<% type = get_setting_type(settingsDict[object]['Interface']) + "::Impl" %>\ % if index < len(settingsDict) - 1: std::unique_ptr<${type}>, % else: |