Skip to content
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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"
#include "swss/json.hpp"

#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;
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;
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");
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)
{
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)
{
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

// 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);
}

std::ofstream outputFile(file_name);

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());
return SAI_STATUS_FAILURE;
}

outputFile << content;
outputFile.close();

return SAI_STATUS_SUCCESS;
}

int dump_from_redis_rdb_file(std::string file_name)
{
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("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)
{
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);
if (item_name.find(":") != std::string::npos)
{
item_name.replace(item_name.find_first_of(":"), 1, " ");
}
}
else
{
continue;
}

std::cout << item_name << " \r\n";

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);
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";
}
std::cout << "\r\n";
}
return SAI_STATUS_SUCCESS;
}
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);
return EXIT_SUCCESS;
}

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

std::string table = ASIC_STATE_TABLE;
Expand Down