Serialize the config objects

This commit serializes the config object into cereal
path and restores the config object when the phosphor-ldap-conf
restarts.

TestedBy: Unit tested
          Serialize the object
          Restart the phosphor-ldap-conf restores the object.
          Ldap/Local authentication works fine.

Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
Change-Id: Ie6e940ddd6851085dc4213677dfb20e3afa0964f
diff --git a/phosphor-ldap-config/ldap_config.cpp b/phosphor-ldap-config/ldap_config.cpp
index 746f324..126cc46 100644
--- a/phosphor-ldap-config/ldap_config.cpp
+++ b/phosphor-ldap-config/ldap_config.cpp
@@ -1,11 +1,19 @@
 #include "ldap_config_mgr.hpp"
 #include "ldap_config.hpp"
-#include "ldap_config_serialize.hpp"
 #include "utils.hpp"
+
+#include <cereal/types/string.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/archives/binary.hpp>
 #include <filesystem>
 #include <fstream>
 #include <sstream>
 
+// Register class version
+// From cereal documentation;
+// "This macro should be placed at global scope"
+CEREAL_CLASS_VERSION(phosphor::ldap::Config, CLASS_VERSION);
+
 namespace phosphor
 {
 namespace ldap
@@ -38,8 +46,8 @@
                ConfigMgr& parent) :
     Ifaces(bus, path, true),
     secureLDAP(secureLDAP), lDAPBindPassword(std::move(lDAPBindDNPassword)),
-    configFilePath(filePath), tlsCacertFile(caCertFile), bus(bus),
-    parent(parent)
+    tlsCacertFile(caCertFile), configFilePath(filePath), objectPath(path),
+    bus(bus), parent(parent)
 {
     ConfigIface::lDAPServerURI(lDAPServerURI);
     ConfigIface::lDAPBindDN(lDAPBindDN);
@@ -49,16 +57,57 @@
     EnableIface::enabled(lDAPServiceEnabled);
     ConfigIface::userNameAttribute(userNameAttr);
     ConfigIface::groupNameAttribute(groupNameAttr);
-    // Don't update the bindDN password under ConfigIface::
+    // NOTE: Don't update the bindDN password under ConfigIface
     if (enabled())
     {
         writeConfig();
     }
+    // save the config.
+    configPersistPath = parent.dbusPersistentPath;
+    configPersistPath += objectPath;
+
+    // create the persistent directory
+    fs::create_directories(configPersistPath);
+
+    configPersistPath += "/config";
+
+    std::ofstream os(configPersistPath, std::ios::binary | std::ios::out);
+    // remove the read permission from others
+    auto permission =
+        fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read;
+    fs::permissions(configPersistPath, permission);
+
+    serialize();
+
     // Emit deferred signal.
     this->emit_object_added();
     parent.startOrStopService(nslcdService, enabled());
 }
 
+Config::Config(sdbusplus::bus::bus& bus, const char* path, const char* filePath,
+               const char* caCertFile, ConfigIface::Type lDAPType,
+               ConfigMgr& parent) :
+    Ifaces(bus, path, true),
+    tlsCacertFile(caCertFile), configFilePath(filePath), objectPath(path),
+    bus(bus), parent(parent)
+{
+    ConfigIface::lDAPType(lDAPType);
+
+    configPersistPath = parent.dbusPersistentPath;
+    configPersistPath += objectPath;
+
+    // create the persistent directory
+    fs::create_directories(configPersistPath);
+
+    configPersistPath += "/config";
+
+    std::ofstream os(configPersistPath, std::ios::binary | std::ios::out);
+    // remove the read permission from others
+    auto permission =
+        fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read;
+    fs::permissions(configPersistPath, permission);
+}
+
 void Config::writeConfig()
 {
     std::stringstream confData;
@@ -195,6 +244,7 @@
             writeConfig();
             parent.startOrStopService(nslcdService, enabled());
         }
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -245,6 +295,8 @@
             writeConfig();
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -290,6 +342,8 @@
             writeConfig();
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -331,6 +385,8 @@
             writeConfig();
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -365,6 +421,8 @@
 
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -401,8 +459,8 @@
         // TODO in later commit, one of the config would be active
         // at any moment of time.
         parent.startOrStopService(nslcdService, value);
-        // save the enabled property.
-        serialize(*this, parent.dbusPersistentPath);
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -433,6 +491,8 @@
 
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -463,6 +523,8 @@
 
             parent.startOrStopService(nslcdService, enabled());
         }
+        // save the object.
+        serialize();
     }
     catch (const InternalFailure& e)
     {
@@ -476,5 +538,86 @@
     return val;
 }
 
+template <class Archive>
+void Config::save(Archive& archive, const std::uint32_t version) const
+{
+    archive(this->enabled());
+    archive(lDAPServerURI());
+    archive(lDAPBindDN());
+    archive(lDAPBaseDN());
+    archive(lDAPSearchScope());
+    archive(lDAPBindPassword);
+    archive(userNameAttribute());
+    archive(groupNameAttribute());
+}
+
+template <class Archive>
+void Config::load(Archive& archive, const std::uint32_t version)
+{
+
+    bool bVal;
+    archive(bVal);
+    EnableIface::enabled(bVal);
+
+    std::string str;
+    archive(str);
+    ConfigIface::lDAPServerURI(str);
+
+    archive(str);
+    ConfigIface::lDAPBindDN(str);
+
+    archive(str);
+    ConfigIface::lDAPBaseDN(str);
+
+    ConfigIface::SearchScope scope;
+    archive(scope);
+    ConfigIface::lDAPSearchScope(scope);
+
+    archive(str);
+    lDAPBindPassword = str;
+
+    archive(str);
+    ConfigIface::userNameAttribute(str);
+
+    archive(str);
+    ConfigIface::groupNameAttribute(str);
+}
+
+void Config::serialize()
+{
+    std::ofstream os(configPersistPath.string(),
+                     std::ios::binary | std::ios::out);
+    cereal::BinaryOutputArchive oarchive(os);
+    oarchive(*this);
+    return;
+}
+
+bool Config::deserialize()
+{
+    try
+    {
+        if (fs::exists(configPersistPath))
+        {
+            std::ifstream is(configPersistPath.c_str(),
+                             std::ios::in | std::ios::binary);
+            cereal::BinaryInputArchive iarchive(is);
+            iarchive(*this);
+            return true;
+        }
+        return false;
+    }
+    catch (cereal::Exception& e)
+    {
+        log<level::ERR>(e.what());
+        std::error_code ec;
+        fs::remove(configPersistPath, ec);
+        return false;
+    }
+    catch (const fs::filesystem_error& e)
+    {
+        return false;
+    }
+}
+
 } // namespace ldap
 } // namespace phosphor