diff options
| author | Ratan Gupta <ratagupt@in.ibm.com> | 2017-06-15 09:07:31 +0530 |
|---|---|---|
| committer | Ratan Gupta <ratagupt@in.ibm.com> | 2017-06-21 15:34:32 +0530 |
| commit | ed123a3a3363144b24c444be5527a3d7b56a72a4 (patch) | |
| tree | 539b01aa88ff52e55f1e40dbb509450729c9d289 | |
| parent | ef85eb9c0e1859f8c420e753341a18ddaa2f8cbb (diff) | |
| download | phosphor-networkd-ed123a3a3363144b24c444be5527a3d7b56a72a4.tar.gz phosphor-networkd-ed123a3a3363144b24c444be5527a3d7b56a72a4.zip | |
Implement the INI config parser
Parse the systemd.network file
to get the configuration parameter.
Change-Id: Ic9c15a46158d2f1c0948e6eca729663e87051491
Signed-off-by: Ratan Gupta <ratagupt@in.ibm.com>
| -rw-r--r-- | Makefile.am | 4 | ||||
| -rw-r--r-- | config_parser.cpp | 165 | ||||
| -rw-r--r-- | config_parser.hpp | 89 | ||||
| -rw-r--r-- | test/Makefile.am | 4 | ||||
| -rw-r--r-- | test/test_config_parser.cpp | 98 |
5 files changed, 358 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 02ba4c2..6903a75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,6 +18,7 @@ noinst_HEADERS = \ types.hpp \ util.hpp \ routing_table.hpp \ + config_parser.hpp \ system_configuration.hpp phosphor_network_manager_SOURCES = \ @@ -30,7 +31,8 @@ phosphor_network_manager_SOURCES = \ xyz/openbmc_project/Network/VLAN/Create/server.cpp \ xyz/openbmc_project/Network/IP/Create/server.cpp \ util.cpp \ - routing_table.cpp + routing_table.cpp \ + config_parser.cpp CLEANFILES = \ xyz/openbmc_project/Network/VLAN/Create/server.cpp \ diff --git a/config_parser.cpp b/config_parser.cpp new file mode 100644 index 0000000..51ef55b --- /dev/null +++ b/config_parser.cpp @@ -0,0 +1,165 @@ +#include "config_parser.hpp" +#include "xyz/openbmc_project/Common/error.hpp" +#include <phosphor-logging/log.hpp> +#include <phosphor-logging/elog-errors.hpp> + +#include <fstream> +#include <string> +#include <algorithm> +#include <unordered_map> +#include <regex> +#include <list> + +namespace phosphor +{ +namespace network +{ +namespace config +{ + +using namespace phosphor::logging; +using namespace sdbusplus::xyz::openbmc_project::Common::Error; + +Parser::Parser(const fs::path& filePath) +{ + setFile(filePath); +} + + +KeyValues Parser::getSection(const std::string& section) +{ + auto it = sections.find(section); + if (it == sections.end()) + { + log<level::ERR>("ConfigParser: Section not found", + entry("SECTION=%s",section)); + elog<InternalFailure>(); + } + return it->second; +} + +std::vector<std::string> Parser::getValues(const std::string& section, + const std::string& key) +{ + std::vector<std::string> values; + auto keyValues = getSection(section); + auto it = keyValues.find(key); + if (it == keyValues.end()) + { + log<level::ERR>("ConfigParser: Key not found", + entry("KEY=%s",key)); + elog<InternalFailure>(); + } + for (; it != keyValues.end() && key == it->first; it++) + { + values.push_back(it->second); + } + return values; +} + + +bool Parser::isValueExist(const std::string& section, const std::string& key, + const std::string& value) +{ + try + { + auto values = getValues(section, key); + auto it = std::find(values.begin(), values.end(), value); + return it != std::end(values) ? true : false; + } + catch (InternalFailure& e) + { + commit<InternalFailure>(); + } + return false; +} + +void Parser::setValue(const std::string& section, const std::string& key, + const std::string& value) +{ + KeyValues values; + try + { + values = getSection(section); + } + catch (InternalFailure& e) + { + // don't commit the error. + + } + values.emplace(key, value); + sections.emplace(section, values); +} + +#if 0 +void Parser::print() +{ + for (auto section : sections) + { + std::cout << "[" << section.first << "]\n\n"; + for (auto keyValue : section.second) + { + std::cout << keyValue.first << "=" << keyValue.second << "\n"; + } + } +} +#endif + +void Parser::setFile(const fs::path& filePath) +{ + this->filePath = filePath; + std::fstream stream; + stream.open(filePath.string(), std::fstream::in); + + if (!stream.is_open()) + { + return; + } + //clear all the section data. + sections.clear(); + parse(stream); + stream.close(); + } + +void Parser::parse(std::istream& in) +{ + static const std::regex commentRegex + { + R"x(\s*[;#])x" + }; + static const std::regex sectionRegex + { + R"x(\s*\[([^\]]+)\])x" + }; + static const std::regex valueRegex + { + R"x(\s*(\S[^ \t=]*)\s*=\s*(\S+)\s*$)x" + }; + std::string section; + std::smatch pieces; + for (std::string line; std::getline(in, line);) + { + if (line.empty() || std::regex_match(line, pieces, commentRegex)) + { + // skip comment lines and blank lines + } + else if (std::regex_match(line, pieces, sectionRegex)) + { + if (pieces.size() == 2) + { + section = pieces[1].str(); + } + } + else if (std::regex_match(line, pieces, valueRegex)) + { + if (pieces.size() == 3) + { + setValue(section, pieces[1].str(), pieces[2].str()); + } + } + } +} + +}//namespace config +}//namespace network +}//namespace phosphor diff --git a/config_parser.hpp b/config_parser.hpp new file mode 100644 index 0000000..bf5cb2d --- /dev/null +++ b/config_parser.hpp @@ -0,0 +1,89 @@ +#pragma once + +#include <string> +#include <map> +#include <unordered_map> +#include <vector> +#include <experimental/filesystem> + +namespace phosphor +{ +namespace network +{ +namespace config +{ + +using Section = std::string; +using KeyValues = std::multimap<std::string, std::string>; +namespace fs = std::experimental::filesystem; + +class Parser +{ + public: + + Parser() = default; + + /** @brief Constructor + * @param[in] fileName - Absolute path of the file which will be parsed. + */ + + Parser(const fs::path& fileName); + + /** @brief Get the values of the given key and section. + * @param[in] section - section name. + * @param[in] key - key to look for. + * @returns the values associated with the key. + */ + + std::vector<std::string> getValues(const std::string& section, + const std::string& key); + + /** @brief Set the value of the given key and section. + * @param[in] section - section name. + * @param[in] key - key name. + * @param[in] value - value. + */ + + void setValue(const std::string& section, const std::string& key, + const std::string& value); + + + /** @brief Set the file name and parse it. + * @param[in] fileName - Absolute path of the file. + */ + + void setFile(const fs::path& fileName); + + private: + + /** @brief Parses the given file and fills the data. + * @param[in] stream - inputstream. + */ + + void parse(std::istream& stream); + + /** @brief Get all the key values of the given section. + * @param[in] section - section name. + * @returns the map of the key and value. + */ + + KeyValues getSection(const std::string& section); + + /** @brief checks that whether the value exist in the + * given section. + * @param[in] section - section name. + * @param[in] key - key name. + * @param[in] value - value. + * @returns true if exist otherwise false. + */ + + bool isValueExist(const std::string& section, const std::string& key, + const std::string& value); + + std::unordered_map<Section, KeyValues> sections; + fs::path filePath; +}; + +}//namespace config +}//namespce network +}//namespace phosphor diff --git a/test/Makefile.am b/test/Makefile.am index 8f951bf..bf1a935 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,7 +8,8 @@ test_SOURCES = \ test_util.cpp \ mock_syscall.cpp \ test_network_manager.cpp \ - test_ethernet_interface.cpp + test_ethernet_interface.cpp \ + test_config_parser.cpp test_CPPFLAGS = -Igtest $(GTEST_CPPFLAGS) $(AM_CPPFLAGS) @@ -32,5 +33,6 @@ test_LDADD = $(top_builddir)/ethernet_interface.cpp \ $(top_builddir)/routing_table.cpp \ $(top_builddir)/util.cpp \ $(top_builddir)/system_configuration.cpp \ + $(top_builddir)/config_parser.cpp \ $(top_builddir)/xyz/openbmc_project/Network/VLAN/Create/phosphor_network_manager-server.o \ $(top_builddir)/xyz/openbmc_project/Network/IP/Create/phosphor_network_manager-server.o diff --git a/test/test_config_parser.cpp b/test/test_config_parser.cpp new file mode 100644 index 0000000..a07390b --- /dev/null +++ b/test/test_config_parser.cpp @@ -0,0 +1,98 @@ +#include <gtest/gtest.h> + +#include "config_parser.hpp" + +#include "xyz/openbmc_project/Common/error.hpp" +#include <phosphor-logging/elog-errors.hpp> + +#include "config.h" +#include <exception> +#include <stdexcept> +#include <fstream> + +namespace phosphor +{ +namespace network +{ + +class TestConfigParser : public testing::Test +{ + public: + config::Parser parser; + TestConfigParser() + { + remove("/tmp/eth0.network"); + std::ofstream filestream("/tmp/eth0.network"); + + filestream << "[Match]\nName=eth0\n" << + "[Network]\nDHCP=true\n[DHCP]\nClientIdentifier= mac\n"; + filestream.close(); + parser.setFile("/tmp/eth0.network"); + } + + bool isValueFound(const std::vector<std::string>& values, + const std::string& expectedValue) + { + for (const auto& value : values) + { + if (expectedValue == value) + { + return true; + } + } + return false; + } +}; + +TEST_F(TestConfigParser, ReadConfigDataFromFile) +{ + auto values = parser.getValues("Network", "DHCP"); + std::string expectedValue = "true"; + bool found = isValueFound(values, expectedValue); + EXPECT_EQ(found, true); + + values = parser.getValues("DHCP", "ClientIdentifier"); + expectedValue = "mac"; + found = isValueFound(values, expectedValue); + EXPECT_EQ(found, true); + + values = parser.getValues("Match", "Name"); + expectedValue = "eth0"; + found = isValueFound(values, expectedValue); + EXPECT_EQ(found, true); +} + +TEST_F(TestConfigParser, SectionNotExist) +{ + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + bool caughtException = false; + try + { + parser.getValues("abc", "ipaddress"); + } + catch (const std::exception& e) + { + caughtException = true; + } + EXPECT_EQ(true, caughtException); +} + +TEST_F(TestConfigParser, KeyNotFound) +{ + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + bool caughtException = false; + try + { + parser.getValues("Network", "abc"); + } + catch (const std::exception& e) + { + caughtException = true; + } + EXPECT_EQ(true, caughtException); + remove("/tmp/eth0.network"); +} + +}//namespace network +}//namespace phosphor + |

