diff --git a/saidump/saidump.cpp b/saidump/saidump.cpp index 6a3321e58..cf99f8dc0 100644 --- a/saidump/saidump.cpp +++ b/saidump/saidump.cpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include extern "C" { #include @@ -10,18 +13,26 @@ extern "C" { #include "swss/table.h" #include "meta/sai_serialize.h" #include "sairediscommon.h" +#include "swss/json.h" +#include "swss/json.hpp" #include // TODO split to multiple cpp using namespace swss; +using namespace std; +using json = nlohmann::json; + +// 100 MB +const int64_t RDB_FILE_MAX_SIZE = 1024 * 1024 * 100; struct CmdOptions { bool skipAttributes; bool dumpTempView; bool dumpGraph; + string rdb_file; }; CmdOptions g_cmdOptions; @@ -31,11 +42,13 @@ void printUsage() { SWSS_LOG_ENTER(); - std::cout << "Usage: saidump [-t] [-g] [-h]" << std::endl; + std::cout << "Usage: saidump [-t] [-g] [-r] [-h]" << std::endl; std::cout << " -t --tempView:" << std::endl; std::cout << " Dump temp view" << std::endl; std::cout << " -g --dumpGraph:" << std::endl; std::cout << " Dump current graph" << std::endl; + std::cout << " -r --rdb:" << std::endl; + std::cout << " Dump by parsing the Redis persistence file dump.rdb that is generated by SAVE command." << std::endl; std::cout << " -h --help:" << std::endl; std::cout << " Print out this message" << std::endl; } @@ -49,7 +62,7 @@ CmdOptions handleCmdLine(int argc, char **argv) options.dumpTempView = false; options.dumpGraph = false; - const char* const optstring = "gth"; + const char* const optstring = "gtr:h"; while (true) { @@ -57,6 +70,7 @@ CmdOptions handleCmdLine(int argc, char **argv) { { "dumpGraph", no_argument, 0, 'g' }, { "tempView", no_argument, 0, 't' }, + { "rdb", required_argument, 0, 'r' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; @@ -82,6 +96,11 @@ CmdOptions handleCmdLine(int argc, char **argv) options.dumpTempView = true; break; + case 'r': + SWSS_LOG_WARN("Dumping from dump.rdb"); + options.rdb_file = string(optarg); + break; + case 'h': printUsage(); exit(EXIT_SUCCESS); @@ -399,7 +418,159 @@ void dumpGraph(const TableDump& td) std::cout << "}" << std::endl; } -int main(int argc, char ** argv) +/* + preprocess the input json file to make make sure it's a valid json file. +*/ +int pre_process_file(string file_name) +{ + ifstream input_file(file_name); + + if (!input_file.is_open()) + { + cerr << "Failed to open the input file." << endl; + return SAI_STATUS_FAILURE; + } + + input_file.seekg(0, ios::end); // Move to the end of the file + int64_t file_size = input_file.tellg(); // Get the current position + + if (file_size >= RDB_FILE_MAX_SIZE) + { + SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.\n", file_name.c_str(), file_size, RDB_FILE_MAX_SIZE / 1024 / 1024); + + // Close the input file + input_file.close(); + return SAI_STATUS_FAILURE; + } + input_file.seekg(0, ios::beg); // Move to the begin of the file + + // Read the content of the input file into a string + string content((istreambuf_iterator(input_file)), + istreambuf_iterator()); + + + input_file.close(); + + content = regex_replace(content, regex("\\},\\{\\r"), ","); + + //erase the 1st and last char. + if (content.length() >= 2 && content[0] == '[' && content[content.length()-1] == ']') { + content.erase(0, 1); + content.erase(content.length() - 1); + } + + ofstream outputFile(file_name); + + if (!outputFile.is_open()) + { + cerr << "Failed to open the output file." << endl; + return SAI_STATUS_FAILURE; + } + + outputFile << content; + outputFile.close(); + + return SAI_STATUS_SUCCESS; +} + +int dump_from_redis_rdb_file(string file_name) +{ + ifstream input_file(file_name); + if (!input_file.is_open()) + { + SWSS_LOG_NOTICE("The file %s is not exsisted for dumping from redis dump.rdb file", file_name); + return SAI_STATUS_FAILURE; + } + + input_file.seekg(0, ios::end); // Move to the end of the file + int64_t file_size = input_file.tellg(); // Get the current position + if (file_size >= RDB_FILE_MAX_SIZE) + { + SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.\n", file_name.c_str(), file_size, RDB_FILE_MAX_SIZE / 1024 / 1024); + + // Close the input file + input_file.close(); + return SAI_STATUS_FAILURE; + } + input_file.seekg(0, ios::beg); // Move to the begin of the file + + try + { + // Parse the JSON data from the file (validation) + nlohmann::json jsonData; + input_file >> jsonData; + input_file.close(); + + SWSS_LOG_DEBUG("%s\n","JSON file is valid.\n"); + + for (json::iterator it = jsonData.begin(); it != jsonData.end(); ++it) + { + json jj_key = it.key(); + + string keystr = jj_key; + string item_name = keystr; + size_t pos = keystr.find_first_of(":"); + if (pos != string::npos) + { + if("ASIC_STATE" != keystr.substr(0, pos)) // filter out non ASIC_STATE + { + continue; + } + item_name = keystr.substr(pos + 1); + if (item_name.find(":") != string::npos) + { + item_name.replace(item_name.find_first_of(":"), 1, " "); + } + } + else + { + continue; + } + + cout << item_name << " " << endl; + + json jj = it.value(); + + if (!(*it).is_object()) + { + continue; + } + + TableMap map; + for (json::iterator itt = jj.begin(); itt != jj.end(); ++itt) + { + if (itt.key() == "NULL") + { + continue; + } + map[itt.key()] = itt.value(); + } + + size_t indent = 4; + size_t max_len = get_max_attr_len(map); + string str_indent = pad_string("", indent); + + for (const auto&field: map) + { + stringstream ss; + ss << str_indent << pad_string(field.first, max_len) << " : "; + ss << field.second; + cout << ss.str() << std::endl; + } + cout << endl; + } + return SAI_STATUS_SUCCESS; + } + catch (exception &ex) + { + input_file.close(); + cerr << "JSON file:" << file_name << " is invalid." << endl; + cerr << "JSON parsing error: " << ex.what() << endl; + } + return SAI_STATUS_FAILURE; +} + +int main(int argc, char **argv) { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); @@ -411,6 +582,16 @@ int main(int argc, char ** argv) g_cmdOptions = handleCmdLine(argc, argv); + if (g_cmdOptions.rdb_file.size() > 0) + { + if (SAI_STATUS_FAILURE == pre_process_file(g_cmdOptions.rdb_file)) + { + return EXIT_FAILURE; + } + dump_from_redis_rdb_file(g_cmdOptions.rdb_file); + return EXIT_SUCCESS; + } + swss::DBConnector db("ASIC_DB", 0); std::string table = ASIC_STATE_TABLE;