Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VOQ][saidump] Enhance saidump with new option -r to parser the JSON file and displays/format the right output #1288

Merged
merged 17 commits into from
Sep 25, 2023
198 changes: 195 additions & 3 deletions saidump/saidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include <string>
#include <set>
#include <sstream>
#include <iostream>
#include <fstream>
#include <regex>

extern "C" {
#include <sai.h>
Expand All @@ -10,18 +13,25 @@ extern "C" {
#include "swss/table.h"
#include "meta/sai_serialize.h"
#include "sairediscommon.h"
#include "swss/json.h"
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
#include "swss/json.hpp"
kcudnik marked this conversation as resolved.
Show resolved Hide resolved

#include <getopt.h>

// TODO split to multiple cpp

using namespace swss;
using json = nlohmann::json;

// 100 MB
constexpr int64_t RDB_FILE_MAX_SIZE = 1024 * 1024 * 100;

struct CmdOptions
{
bool skipAttributes;
bool dumpTempView;
bool dumpGraph;
std::string rdbFile;
};

CmdOptions g_cmdOptions;
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -31,11 +41,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;
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
std::cout << " -h --help:" << std::endl;
std::cout << " Print out this message" << std::endl;
}
Expand All @@ -49,14 +61,15 @@ 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)
{
static struct option long_options[] =
{
{ "dumpGraph", no_argument, 0, 'g' },
{ "tempView", no_argument, 0, 't' },
{ "rdb", required_argument, 0, 'r' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
Expand All @@ -82,6 +95,11 @@ CmdOptions handleCmdLine(int argc, char **argv)
options.dumpTempView = true;
break;

case 'r':
SWSS_LOG_NOTICE("Dumping from dump.rdb");
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
options.rdbFile = std::string(optarg);
break;

case 'h':
printUsage();
exit(EXIT_SUCCESS);
Expand Down Expand Up @@ -399,7 +417,170 @@ void dumpGraph(const TableDump& td)
std::cout << "}" << std::endl;
}

int main(int argc, char ** argv)
/*
preprocess the input json file to make sure it's a valid json file.
*/
static int preProcessFile(std::string file_name)
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
std::ifstream input_file(file_name);

if (!input_file.is_open())
{
std::cerr << "Failed to open the input file " << file_name << std::endl;
SWSS_LOG_ERROR("Failed to open the input file %s.", file_name.c_str());
return SAI_STATUS_FAILURE;
}

input_file.seekg(0, std::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)
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
std::cerr << "Get " << file_name.c_str() << "'s size failure or its size " << file_size << " >= "<< RDB_FILE_MAX_SIZE / 1024 / 1024<<" MB." << std::endl;
SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.", file_name.c_str(), file_size, RDB_FILE_MAX_SIZE / 1024 / 1024);
// Close the input file
input_file.close();
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
return SAI_STATUS_FAILURE;
}

kcudnik marked this conversation as resolved.
Show resolved Hide resolved
input_file.seekg(0, std::ios::beg); // Move to the begin of the file

// Read the content of the input file into a string
std::string content((std::istreambuf_iterator<char>(input_file)),
std::istreambuf_iterator<char>());
input_file.close();

content = regex_replace(content, std::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);
}
kcudnik marked this conversation as resolved.
Show resolved Hide resolved

std::ofstream outputFile(file_name);
kcudnik marked this conversation as resolved.
Show resolved Hide resolved

if (!outputFile.is_open())
{
std::cerr << "Failed to open the output file " << file_name << std::endl;
SWSS_LOG_ERROR("Failed to open the output file %s.", file_name.c_str());
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
return SAI_STATUS_FAILURE;
}

outputFile << content;
outputFile.close();

return SAI_STATUS_SUCCESS;
}

int dump_from_redis_rdb_file(std::string file_name)
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
std::ifstream input_file(file_name);

if (!input_file.is_open())
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
std::cerr << "Failed to open the input file " << file_name << std::endl;
SWSS_LOG_ERROR("The file %s does not exist for dumping from redis dump.rdb file.", file_name.c_str());
return SAI_STATUS_FAILURE;
}

input_file.seekg(0, std::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)
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
std::cerr << "Get " << file_name.c_str() << "'s size failure or its size " << file_size << " >= "<< RDB_FILE_MAX_SIZE / 1024 / 1024<<" MB." << std::endl;
SWSS_LOG_ERROR("Get %s's size failure or its size %ld >= %ld MB.", 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, std::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("JSON file is valid.");

for (json::iterator it = jsonData.begin(); it != jsonData.end(); ++it)
{
json jj_key = it.key();

std::string keystr = jj_key;
std::string item_name = keystr;
size_t pos = keystr.find_first_of(":");

if (pos != std::string::npos)
{
if(ASIC_STATE_TABLE != keystr.substr(0, pos)) // filter out non ASIC_STATE
{
continue;
}
item_name = keystr.substr(pos + 1);
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
if (item_name.find(":") != std::string::npos)
{
item_name.replace(item_name.find_first_of(":"), 1, " ");
}
}
else
{
continue;
}

std::cout << item_name << " \r\n";
kcudnik marked this conversation as resolved.
Show resolved Hide resolved

json jj = it.value();

if (!it->is_object())
{
continue;
}

TableMap map;

for (json::iterator itt = jj.begin(); itt != jj.end(); ++itt)
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
{
if (itt.key() == "NULL")
{
continue;
}
map[itt.key()] = itt.value();
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
}

size_t indent = 4;
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
size_t max_len = get_max_attr_len(map);
std::string str_indent = pad_string("", indent);

for (const auto&field: map)
{
std::stringstream ss;
ss << str_indent << pad_string(field.first, max_len) << " : ";
ss << field.second;
std::cout << ss.str() << "\r\n";
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
}
std::cout << "\r\n";
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
}
return SAI_STATUS_SUCCESS;
JunhongMao marked this conversation as resolved.
Show resolved Hide resolved
}
catch (std::exception &ex)
{
input_file.close();
std::cerr << "JSON file:" << file_name << " is invalid." << std::endl;
std::cerr << "JSON parsing error: " << ex.what() << std::endl;
SWSS_LOG_ERROR("JSON file %s is invalid.", file_name.c_str());
SWSS_LOG_ERROR("JSON parsing error: %s.", ex.what());
}
return SAI_STATUS_FAILURE;
}

int main(int argc, char **argv)
{
swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG);

Expand All @@ -411,6 +592,17 @@ int main(int argc, char ** argv)

g_cmdOptions = handleCmdLine(argc, argv);

if (g_cmdOptions.rdbFile.size() > 0)
{
if (SAI_STATUS_FAILURE == preProcessFile(g_cmdOptions.rdbFile))
{
return EXIT_FAILURE;
}

dump_from_redis_rdb_file(g_cmdOptions.rdbFile);
kcudnik marked this conversation as resolved.
Show resolved Hide resolved
return EXIT_SUCCESS;
}

swss::DBConnector db("ASIC_DB", 0);

std::string table = ASIC_STATE_TABLE;
Expand Down