From 702312051b0c3fb82ddf1fc533dbcbdbf3f3e776 Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Sat, 2 Apr 2022 05:49:08 +0000 Subject: [PATCH 1/8] Add sonic-cli code --- rules/sonic-cli.dep | 8 ++ rules/sonic-cli.mk | 15 ++++ src/sonic-cli/Makefile.am | 24 ++++++ src/sonic-cli/configure.ac | 63 ++++++++++++++ src/sonic-cli/debian/changelog | 6 ++ src/sonic-cli/debian/compat | 1 + src/sonic-cli/debian/control | 12 +++ src/sonic-cli/debian/copyright | 1 + src/sonic-cli/debian/rules | 27 ++++++ src/sonic-cli/sonic-cli.cpp | 152 +++++++++++++++++++++++++++++++++ 10 files changed, 309 insertions(+) create mode 100755 rules/sonic-cli.dep create mode 100755 rules/sonic-cli.mk create mode 100755 src/sonic-cli/Makefile.am create mode 100755 src/sonic-cli/configure.ac create mode 100755 src/sonic-cli/debian/changelog create mode 100755 src/sonic-cli/debian/compat create mode 100755 src/sonic-cli/debian/control create mode 100755 src/sonic-cli/debian/copyright create mode 100755 src/sonic-cli/debian/rules create mode 100755 src/sonic-cli/sonic-cli.cpp diff --git a/rules/sonic-cli.dep b/rules/sonic-cli.dep new file mode 100755 index 00000000000..749870fb473 --- /dev/null +++ b/rules/sonic-cli.dep @@ -0,0 +1,8 @@ +SPATH := $($(SONIC_CLI)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-cli.mk rules/sonic-cli.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(SPATH)) + +$(BASH)_CACHE_MODE := GIT_CONTENT_SHA +$(BASH)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(BASH)_DEP_FILES := $(DEP_FILES) \ No newline at end of file diff --git a/rules/sonic-cli.mk b/rules/sonic-cli.mk new file mode 100755 index 00000000000..cbe48bcfd78 --- /dev/null +++ b/rules/sonic-cli.mk @@ -0,0 +1,15 @@ +# sonic-cli Debian package +SONIC_CLI_VERSION = 1.0.0 +export SONIC_CLI_VERSION + +SONIC_CLI = sonic-cli_$(SONIC_CLI_VERSION)_$(CONFIGURED_ARCH).deb +$(SONIC_CLI)_DEPENDS += $(LIBSWSSCOMMON_DEV) +$(SONIC_CLI)_RDEPENDS += $(LIBSWSSCOMMON) +$(SONIC_CLI)_SRC_PATH = $(SRC_PATH)/sonic-cli + +SONIC_MAKE_DEBS += $(SONIC_CLI) + +# The .c, .cpp, .h & .hpp files under src/{$DBG_SRC_ARCHIVE list} +# are archived into debug one image to facilitate debugging. +# +DBG_SRC_ARCHIVE += sonic-cli \ No newline at end of file diff --git a/src/sonic-cli/Makefile.am b/src/sonic-cli/Makefile.am new file mode 100755 index 00000000000..e8a445a2eb3 --- /dev/null +++ b/src/sonic-cli/Makefile.am @@ -0,0 +1,24 @@ +########################################################################### +## +## File: ./Makefile.am +## Versions: $Id: Makefile.am,v 1.0 2022/04/02 12:04:29 liuh@microsoft.com Exp $ +## Created: 2022/04/02 +## +########################################################################### + +ACLOCAL_AMFLAGS = -I config +AUTOMAKE_OPTIONS = subdir-objects + +bin_PROGRAMS = sonic-cli +sonic_cli_SOURCES = sonic-cli.h \ + sonic-cli.cpp +sonic_cli_CPPFLAGS = $(AM_CPPFLAGS) +sonic_cli_LDFLAGS = -lswsscommon + +EXTRA_DIST = sonic-cli.spec + +MAINTAINERCLEANFILES = Makefile.in config.h.in configure aclocal.m4 \ + config/config.guess config/config.sub config/depcomp \ + config/install-sh config/ltmain.sh config/missing + +pkgconfigdir = $(libdir)/pkgconfig diff --git a/src/sonic-cli/configure.ac b/src/sonic-cli/configure.ac new file mode 100755 index 00000000000..6226a2560f5 --- /dev/null +++ b/src/sonic-cli/configure.ac @@ -0,0 +1,63 @@ +dnl +dnl File: configure.in +dnl Revision: $Id: configure.ac,v 1.0 2022/04/02 12:04:29 liuh@microsoft.com Exp $ +dnl Created: 2022/04/02 +dnl Author: Liu Hua +dnl +dnl Process this file with autoconf to produce a configure script +dnl You need autoconf 2.59 or better! +dnl +dnl --------------------------------------------------------------------------- + +AC_PREREQ(2.59) +AC_COPYRIGHT([ +See the included file: COPYING for copyright information. +]) +AC_INIT(sonic-cli, 1.0.0, [liuh@microsoft.com]) + +AC_CONFIG_AUX_DIR(config) +AM_INIT_AUTOMAKE([foreign]) +AC_CONFIG_SRCDIR([sonic-cli.cpp]) +AC_CONFIG_HEADER([config.h]) +AC_CONFIG_MACRO_DIR([config]) + +dnl -------------------------------------------------------------------- +dnl Checks for programs. +AC_LANG_C +AC_LANG([C++]) +AC_PROG_CC +AC_PROG_CXX +AM_PROG_CC_C_O +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_ENABLE_SHARED +AC_DISABLE_STATIC +AM_PROG_LIBTOOL + +dnl -------------------------------------------------------------------- +dnl Checks for libraries. +AC_CHECK_LIB(swsscommon, conn) + +dnl -------------------------------------------------------------------- +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADER([swss/sonicv2connector.h], [], [AC_MSG_ERROR([swsscommon libraries missing. ])] ) + +dnl -------------------------------------------------------------------- +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_HEADER_TIME + +dnl -------------------------------------------------------------------- +dnl Checks for library functions. +AC_FUNC_REALLOC +AC_FUNC_SELECT_ARGTYPES +AC_TYPE_SIGNAL +AC_CHECK_FUNCS([bzero gethostbyname gettimeofday inet_ntoa select socket logwtmp getrandom]) + +dnl -------------------------------------------------------------------- +dnl Generate made files +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/src/sonic-cli/debian/changelog b/src/sonic-cli/debian/changelog new file mode 100755 index 00000000000..dfea23a8b4f --- /dev/null +++ b/src/sonic-cli/debian/changelog @@ -0,0 +1,6 @@ +sonic-cli (1.0.0) unstable; urgency=low + + * First version of sonic-cli debian package. + + -- Liu Hua Sat, 2 Apr 2022 16:00:00 +0000 + diff --git a/src/sonic-cli/debian/compat b/src/sonic-cli/debian/compat new file mode 100755 index 00000000000..f599e28b8ab --- /dev/null +++ b/src/sonic-cli/debian/compat @@ -0,0 +1 @@ +10 diff --git a/src/sonic-cli/debian/control b/src/sonic-cli/debian/control new file mode 100755 index 00000000000..637ab566186 --- /dev/null +++ b/src/sonic-cli/debian/control @@ -0,0 +1,12 @@ +Source: sonic-cli +Section: admin +Priority: extra +Maintainer: Liu Hua +Build-Depends: autoconf-archive +Description: SONiC CLI for SONiC database. + +Package: sonic-cli +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libswsscommon +Description: SONiC CLI debian package + SONiC CLI for manage SONiC database. diff --git a/src/sonic-cli/debian/copyright b/src/sonic-cli/debian/copyright new file mode 100755 index 00000000000..7cf565eff8d --- /dev/null +++ b/src/sonic-cli/debian/copyright @@ -0,0 +1 @@ +Copyright (C) 2022 Microsoft, Inc \ No newline at end of file diff --git a/src/sonic-cli/debian/rules b/src/sonic-cli/debian/rules new file mode 100755 index 00000000000..16f9dd09f59 --- /dev/null +++ b/src/sonic-cli/debian/rules @@ -0,0 +1,27 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +%: + dh $@ + + +override_dh_auto_configure: + dh_auto_configure -- --enable-manuals + +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + +override_dh_auto_test: \ No newline at end of file diff --git a/src/sonic-cli/sonic-cli.cpp b/src/sonic-cli/sonic-cli.cpp new file mode 100755 index 00000000000..1bacc69f7c7 --- /dev/null +++ b/src/sonic-cli/sonic-cli.cpp @@ -0,0 +1,152 @@ +#include + +#include +#include + +#include +#include +#include + +static std::string nameSpace; +static std::string dbOrOperation; +static std::vector commands; + +static int useUnixSocket; +static int helpRequested; + +void printUsage() +{ + std::cerr << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; +} + +void parseCliArguments(int argc, char** argv) +{ + for (int index = 1; index < argc; index++) + { + std::string opt{argv[index]}; + if (opt == "-h" || opt == "--help") + { + helpRequested = true; + } + else if (opt == "-n" || opt == "--namespace") + { + index++; + if (index == argc) + { + throw std::invalid_argument("namespace option requires argument"); + } + nameSpace = argv[index]; + } + else if (opt == "-s" || opt == "--unixsocket") + { + useUnixSocket = true; + } + else + { + if (dbOrOperation.empty()) + { + dbOrOperation = argv[index]; + } + else + { + commands.emplace_back(argv[index]); + } + } + } +} + +void printRedisReply(redisReply* reply) +{ + switch(reply->type) + { + case REDIS_REPLY_INTEGER: + std::cout << reply->integer; + break; + case REDIS_REPLY_STRING: + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_NIL: + std::cout << std::string(reply->str, reply->len); + break; + case REDIS_REPLY_ARRAY: + for (size_t i = 0; i < reply->elements; i++) + { + printRedisReply(reply->element[i]); + } + break; + default: + std::cerr << reply->type << std::endl; + throw std::runtime_error("Unexpected reply type"); + } + + std::cout << std::endl; +} + +void executeCommands(const std::string& dbname, std::vector& commands) +{ + swss::SonicV2Connector_Native conn(useUnixSocket, nameSpace.c_str()); + conn.connect(dbname); + auto& client = conn.get_redis_client(dbname); + + swss::RedisCommand r; + + size_t argc = commands.size(); + const char** argv = new const char*[argc]; + size_t* argvc = new size_t[argc]; + + for (size_t i = 0; i < argc; i++) + { + argv[i] = strdup(commands[i].c_str()); + argvc[i] = commands[i].size(); + } + + swss::RedisCommand c; + c.formatArgv(argc, argv, argvc); + swss::RedisReply reply(&client, c); + + auto redisReply = reply.getContext(); + printRedisReply(redisReply); +} + +void handleSingleOperation(const std::string& ns, const std::string& operation) +{ + swss::SonicV2Connector_Native conn(useUnixSocket, ns.c_str()); + conn.connect("APPL_DB"); + auto& client = conn.get_redis_client("APPL_DB"); + + swss::RedisReply reply(&client, operation); + auto redisReply = reply.getContext(); + printRedisReply(redisReply); +} + +void handleOperation() +{ + if (dbOrOperation == "PING" || dbOrOperation == "SAVE" || dbOrOperation == "FLUSHALL") + { + handleSingleOperation(nameSpace, dbOrOperation); + } + else if (!commands.empty()) + { + executeCommands(dbOrOperation, commands); + } + else + { + throw std::runtime_error("Invalid operation"); + } +} + +int main(int argc, char** argv) +{ + try + { + parseCliArguments(argc, argv); + handleOperation(); + } + catch (const std::exception& e) + { + std::cerr << e.what() << std::endl; + return -1; + } + + return 0; +} \ No newline at end of file From b0943a787ed62173a23e7b312d8529cde0ba4c0f Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Sat, 2 Apr 2022 09:16:57 +0000 Subject: [PATCH 2/8] Port code --- src/sonic-cli/Makefile.am | 8 +- src/sonic-cli/configure.ac | 6 +- src/sonic-cli/sonic-cli.cpp | 209 ++++++++++++++++++++++++------------ 3 files changed, 147 insertions(+), 76 deletions(-) diff --git a/src/sonic-cli/Makefile.am b/src/sonic-cli/Makefile.am index e8a445a2eb3..0c626c1b7f1 100755 --- a/src/sonic-cli/Makefile.am +++ b/src/sonic-cli/Makefile.am @@ -5,17 +5,17 @@ ## Created: 2022/04/02 ## ########################################################################### - +ACLOCAL_AMFLAGS = -I m4 --install ACLOCAL_AMFLAGS = -I config AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = sonic-cli sonic_cli_SOURCES = sonic-cli.h \ sonic-cli.cpp -sonic_cli_CPPFLAGS = $(AM_CPPFLAGS) -sonic_cli_LDFLAGS = -lswsscommon +sonic_cli_CPPFLAGS = $(AM_CPPFLAGS) -std=c++17 +sonic_cli_LDFLAGS = -lswsscommon $(BOOST_PROGRAM_OPTIONS_LIB) -EXTRA_DIST = sonic-cli.spec +EXTRA_DIST = bootstrap sonic-cli.spec MAINTAINERCLEANFILES = Makefile.in config.h.in configure aclocal.m4 \ config/config.guess config/config.sub config/depcomp \ diff --git a/src/sonic-cli/configure.ac b/src/sonic-cli/configure.ac index 6226a2560f5..8a293156b5a 100755 --- a/src/sonic-cli/configure.ac +++ b/src/sonic-cli/configure.ac @@ -20,6 +20,7 @@ AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_SRCDIR([sonic-cli.cpp]) AC_CONFIG_HEADER([config.h]) AC_CONFIG_MACRO_DIR([config]) +AC_CONFIG_MACRO_DIR([m4]) dnl -------------------------------------------------------------------- dnl Checks for programs. @@ -38,11 +39,14 @@ AM_PROG_LIBTOOL dnl -------------------------------------------------------------------- dnl Checks for libraries. AC_CHECK_LIB(swsscommon, conn) +dnl Check boost libs: https://www.gnu.org/software/autoconf-archive/The-Macros.html#The-Macros +AX_BOOST_BASE(,, [AC_MSG_ERROR([boost lib missing])]) +AX_BOOST_PROGRAM_OPTIONS dnl -------------------------------------------------------------------- dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADER([swss/sonicv2connector.h], [], [AC_MSG_ERROR([swsscommon libraries missing. ])] ) +AC_CHECK_HEADER([swss/sonicv2connector.h], [], [AC_MSG_ERROR([swsscommon lib missing. ])] ) dnl -------------------------------------------------------------------- dnl Checks for typedefs, structures, and compiler characteristics. diff --git a/src/sonic-cli/sonic-cli.cpp b/src/sonic-cli/sonic-cli.cpp index 1bacc69f7c7..64f2a8d4ddc 100755 --- a/src/sonic-cli/sonic-cli.cpp +++ b/src/sonic-cli/sonic-cli.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -6,53 +8,16 @@ #include #include #include +#include -static std::string nameSpace; -static std::string dbOrOperation; -static std::vector commands; +const char* emptyStr = ""; -static int useUnixSocket; -static int helpRequested; +namespace po = boost::program_options; -void printUsage() +void printUsage(const po::options_description &description) { - std::cerr << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; -} - -void parseCliArguments(int argc, char** argv) -{ - for (int index = 1; index < argc; index++) - { - std::string opt{argv[index]}; - if (opt == "-h" || opt == "--help") - { - helpRequested = true; - } - else if (opt == "-n" || opt == "--namespace") - { - index++; - if (index == argc) - { - throw std::invalid_argument("namespace option requires argument"); - } - nameSpace = argv[index]; - } - else if (opt == "-s" || opt == "--unixsocket") - { - useUnixSocket = true; - } - else - { - if (dbOrOperation.empty()) - { - dbOrOperation = argv[index]; - } - else - { - commands.emplace_back(argv[index]); - } - } - } + std::cout << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; + std::cout << description << std::endl; } void printRedisReply(redisReply* reply) @@ -82,70 +47,172 @@ void printRedisReply(redisReply* reply) std::cout << std::endl; } -void executeCommands(const std::string& dbname, std::vector& commands) +int executeCommands( + const std::string& dbName, + std::vector& commands, + const std::string& nameSpace, + bool useUnixSocket) { - swss::SonicV2Connector_Native conn(useUnixSocket, nameSpace.c_str()); - conn.connect(dbname); - auto& client = conn.get_redis_client(dbname); - - swss::RedisCommand r; + std::unique_ptr dbconn; + if (nameSpace.compare("None") == 0) { + dbconn = std::make_unique(useUnixSocket, emptyStr); + } + else { + dbconn = std::make_unique(true, nameSpace.c_str()); + } + + try { + dbconn->connect(dbName); + } + catch (const std::exception& e) + { + std::cerr << "Invalid database name input : " << dbName << std::endl; + return 1; + } + + auto& client = dbconn->get_redis_client(dbName); size_t argc = commands.size(); const char** argv = new const char*[argc]; size_t* argvc = new size_t[argc]; - for (size_t i = 0; i < argc; i++) { argv[i] = strdup(commands[i].c_str()); argvc[i] = commands[i].size(); } - swss::RedisCommand c; - c.formatArgv(argc, argv, argvc); - swss::RedisReply reply(&client, c); + swss::RedisCommand command; + command.formatArgv(argc, argv, argvc); + swss::RedisReply reply(&client, command); auto redisReply = reply.getContext(); printRedisReply(redisReply); + + return 0; } -void handleSingleOperation(const std::string& ns, const std::string& operation) +void handleSingleOperation( + const std::string& nameSpace, + const std::string& dbName, + const std::string& operation, + bool useUnixSocket) { - swss::SonicV2Connector_Native conn(useUnixSocket, ns.c_str()); - conn.connect("APPL_DB"); - auto& client = conn.get_redis_client("APPL_DB"); + swss::SonicV2Connector_Native conn(useUnixSocket, nameSpace.c_str()); + conn.connect(dbName); + auto& client = conn.get_redis_client(dbName); swss::RedisReply reply(&client, operation); auto redisReply = reply.getContext(); printRedisReply(redisReply); } -void handleOperation() +void handleAllInstances( + const std::string& nameSpace, + const std::string& operation, + bool useUnixSocket) { - if (dbOrOperation == "PING" || dbOrOperation == "SAVE" || dbOrOperation == "FLUSHALL") - { - handleSingleOperation(nameSpace, dbOrOperation); + // Use the tcp connectivity if namespace is local and unixsocket cmd_option is present. + if (nameSpace.compare("None") == 0) { + useUnixSocket = true; } - else if (!commands.empty()) - { - executeCommands(dbOrOperation, commands); + + auto dbNames = swss::SonicDBConfig::getDbList(nameSpace); + // Operate All Redis Instances in Parallel + // TODO: if one of the operations failed, it could fail quickly and not necessary to wait all other operations + std::for_each( + std::execution::par, + dbNames.begin(), + dbNames.end(), + [=](auto&& dbName) + { + handleSingleOperation(nameSpace, dbName, operation, useUnixSocket); + }); +} + +int handleOperation(const po::variables_map &variablesMap, const po::options_description &description) +{ + if (variablesMap.count("db_or_op")) { + auto dbOrOperation = variablesMap["db_or_op"].as(); + auto nameSpace = variablesMap["--namespace"].as(); + bool useUnixSocket = variablesMap.count("--unixsocket"); + if (nameSpace.compare("None") != 0) { + swss::SonicDBConfig::initializeGlobalConfig(nameSpace); + } + + if (variablesMap.count("cmd")) { + auto commands = variablesMap["cmd"].as< std::vector >(); + return executeCommands(dbOrOperation, commands, nameSpace, useUnixSocket); + } + else if (nameSpace.compare("PING") == 0 || nameSpace.compare("SAVE") == 0 || nameSpace.compare("FLUSHALL") == 0) { + // redis-cli doesn't depend on database_config.json which could raise some exceptions + // sonic-db-cli catch all possible exceptions and handle it as a failure case which not return 'OK' or 'PONG' + handleAllInstances(nameSpace, dbOrOperation, useUnixSocket); + } + else { + printUsage(description); + } } - else - { - throw std::runtime_error("Invalid operation"); + else { + printUsage(description); } + + return 0; +} + +void parseCliArguments( + int argc, + char** argv, + po::options_description &description, + po::variables_map &variablesMap) +{ + description.add_options() + ("--help,-h", "Help message") + ("--unixsocket,-s", "Override use of tcp_port and use unixsocket") + ("--namespace,-n", po::value(&nameSpace)->default_value("None"), "Namespace string to use asic0/asic1.../asicn") + ("db_or_op", po::value(&dbOrOperation)->default_value(emptyStr), "Database name Or Unary operation(only PING/SAVE/FLUSHALL supported)") + ("cmd", po::value< std::vector >(), "Command to execute in database") + ; + + po::store(po::parse_command_line(argc, argv, description), variablesMap); + po::notify(variablesMap); } int main(int argc, char** argv) { + po::options_description description("SONiC DB CLI"); + po::variables_map variablesMap; + + try { + parseCliArguments(argc, argv, description, variablesMap); + } + catch (po::error_with_option_name& e) { + std::cerr << "Command Line Syntax Error: " << e.what() << std::endl; + printUsage(description); + return -1; + } + catch (po::error& e) { + std::cerr << "Command Line Error: " << e.what() << std::endl; + printUsage(description); + return -1; + } + + if (variablesMap.count("--help")) { + printUsage(description); + return 0; + } + try { - parseCliArguments(argc, argv); - handleOperation(); + return handleOperation(variablesMap, description); } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; - return -1; + std::cerr << "An exception of type " << e.what() << " occurred. Arguments:" << std::endl; + for (int idx = 0; idx < argc; idx++) { + std::cerr << argv[idx] << " "; + } + std::cerr << std::endl; + return 1; } return 0; From c061404547b4defb219a4f02a71035f99fbadbc5 Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Sat, 2 Apr 2022 09:35:14 +0000 Subject: [PATCH 3/8] Port code --- src/sonic-cli/sonic-cli.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sonic-cli/sonic-cli.cpp b/src/sonic-cli/sonic-cli.cpp index 64f2a8d4ddc..1a507da5211 100755 --- a/src/sonic-cli/sonic-cli.cpp +++ b/src/sonic-cli/sonic-cli.cpp @@ -1,19 +1,18 @@ -#include -#include -#include - -#include -#include - +#include #include #include #include -#include -const char* emptyStr = ""; +#include +#include +#include namespace po = boost::program_options; +static std::string nameSpace; +static std::string dbOrOperation; +const char* emptyStr = ""; + void printUsage(const po::options_description &description) { std::cout << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; From 5660bae524d59b8dbca0ac20f557166537bbed5f Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Wed, 6 Apr 2022 09:42:12 +0000 Subject: [PATCH 4/8] Fix build issue --- rules/sonic-cli.mk | 2 +- src/sonic-cli/debian/changelog | 7 +++--- src/sonic-cli/debian/compat | 1 - src/sonic-cli/debian/control | 20 +++++++++------- src/sonic-cli/debian/copyright | 44 +++++++++++++++++++++++++++++++++- src/sonic-cli/debian/rules | 12 ++++------ 6 files changed, 64 insertions(+), 22 deletions(-) mode change 100755 => 100644 src/sonic-cli/debian/changelog delete mode 100755 src/sonic-cli/debian/compat mode change 100755 => 100644 src/sonic-cli/debian/control mode change 100755 => 100644 src/sonic-cli/debian/copyright diff --git a/rules/sonic-cli.mk b/rules/sonic-cli.mk index cbe48bcfd78..0d7ab918d27 100755 --- a/rules/sonic-cli.mk +++ b/rules/sonic-cli.mk @@ -7,7 +7,7 @@ $(SONIC_CLI)_DEPENDS += $(LIBSWSSCOMMON_DEV) $(SONIC_CLI)_RDEPENDS += $(LIBSWSSCOMMON) $(SONIC_CLI)_SRC_PATH = $(SRC_PATH)/sonic-cli -SONIC_MAKE_DEBS += $(SONIC_CLI) +SONIC_DPKG_DEBS += $(SONIC_CLI) # The .c, .cpp, .h & .hpp files under src/{$DBG_SRC_ARCHIVE list} # are archived into debug one image to facilitate debugging. diff --git a/src/sonic-cli/debian/changelog b/src/sonic-cli/debian/changelog old mode 100755 new mode 100644 index dfea23a8b4f..da24edb914d --- a/src/sonic-cli/debian/changelog +++ b/src/sonic-cli/debian/changelog @@ -1,6 +1,5 @@ -sonic-cli (1.0.0) unstable; urgency=low +sonic-cli (1.0.0-1) unstable; urgency=medium - * First version of sonic-cli debian package. - - -- Liu Hua Sat, 2 Apr 2022 16:00:00 +0000 + * Initial release (Closes: #nnnn) + -- unknown Wed, 06 Apr 2022 09:21:18 +0000 diff --git a/src/sonic-cli/debian/compat b/src/sonic-cli/debian/compat deleted file mode 100755 index f599e28b8ab..00000000000 --- a/src/sonic-cli/debian/compat +++ /dev/null @@ -1 +0,0 @@ -10 diff --git a/src/sonic-cli/debian/control b/src/sonic-cli/debian/control old mode 100755 new mode 100644 index 637ab566186..cbcbbf68f13 --- a/src/sonic-cli/debian/control +++ b/src/sonic-cli/debian/control @@ -1,12 +1,16 @@ Source: sonic-cli -Section: admin -Priority: extra -Maintainer: Liu Hua -Build-Depends: autoconf-archive -Description: SONiC CLI for SONiC database. +Section: unknown +Priority: optional +Maintainer: unknown +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.5.1 +Homepage: +#Vcs-Browser: https://salsa.debian.org/debian/sonic-cli +#Vcs-Git: https://salsa.debian.org/debian/sonic-cli.git +Rules-Requires-Root: no Package: sonic-cli Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libswsscommon -Description: SONiC CLI debian package - SONiC CLI for manage SONiC database. +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: + diff --git a/src/sonic-cli/debian/copyright b/src/sonic-cli/debian/copyright old mode 100755 new mode 100644 index 7cf565eff8d..e7eb1d9e6d2 --- a/src/sonic-cli/debian/copyright +++ b/src/sonic-cli/debian/copyright @@ -1 +1,43 @@ -Copyright (C) 2022 Microsoft, Inc \ No newline at end of file +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: sonic-cli +Upstream-Contact: +Source: + +Files: * +Copyright: + +License: + + + . + + +# If you want to use GPL v2 or later for the /debian/* files use +# the following clauses, or change it to suit. Delete these two lines +Files: debian/* +Copyright: 2022 unknown +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +# Please also look if there are files or directories which have a +# different copyright/license attached and list them here. +# Please avoid picking licenses with terms that are more restrictive than the +# packaged work, as it may make Debian's contributions unacceptable upstream. +# +# If you need, there are some extra license texts available in two places: +# /usr/share/debhelper/dh_make/licenses/ +# /usr/share/common-licenses/ diff --git a/src/sonic-cli/debian/rules b/src/sonic-cli/debian/rules index 16f9dd09f59..59ea751e676 100755 --- a/src/sonic-cli/debian/rules +++ b/src/sonic-cli/debian/rules @@ -18,10 +18,8 @@ dh $@ -override_dh_auto_configure: - dh_auto_configure -- --enable-manuals - -override_dh_shlibdeps: - dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info - -override_dh_auto_test: \ No newline at end of file +# dh_make generated override targets +# This is example for Cmake (See https://bugs.debian.org/641051 ) +#override_dh_auto_configure: +# dh_auto_configure -- \ +# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) From 3d4727086566452676d1b8623013c30dba80e42e Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Wed, 6 Apr 2022 10:05:34 +0000 Subject: [PATCH 5/8] Add UT project --- src/sonic-cli/Makefile.am | 1 + src/sonic-cli/configure.ac | 5 +- src/sonic-cli/tests/Makefile.am | 18 +++++++ src/sonic-cli/tests/main.cpp | 84 +++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/sonic-cli/tests/Makefile.am create mode 100644 src/sonic-cli/tests/main.cpp diff --git a/src/sonic-cli/Makefile.am b/src/sonic-cli/Makefile.am index 0c626c1b7f1..259231c9eda 100755 --- a/src/sonic-cli/Makefile.am +++ b/src/sonic-cli/Makefile.am @@ -8,6 +8,7 @@ ACLOCAL_AMFLAGS = -I m4 --install ACLOCAL_AMFLAGS = -I config AUTOMAKE_OPTIONS = subdir-objects +SUBDIRS = tests bin_PROGRAMS = sonic-cli sonic_cli_SOURCES = sonic-cli.h \ diff --git a/src/sonic-cli/configure.ac b/src/sonic-cli/configure.ac index 8a293156b5a..9becc64f46b 100755 --- a/src/sonic-cli/configure.ac +++ b/src/sonic-cli/configure.ac @@ -63,5 +63,8 @@ AC_CHECK_FUNCS([bzero gethostbyname gettimeofday inet_ntoa select socket logwtmp dnl -------------------------------------------------------------------- dnl Generate made files -AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([ + Makefile + tests/Makefile +]) AC_OUTPUT diff --git a/src/sonic-cli/tests/Makefile.am b/src/sonic-cli/tests/Makefile.am new file mode 100644 index 00000000000..8073830cc04 --- /dev/null +++ b/src/sonic-cli/tests/Makefile.am @@ -0,0 +1,18 @@ +INCLUDES = -I $(top_srcdir) + +bin_PROGRAMS = tests + +if DEBUG +DBGFLAGS = -ggdb -DDEBUG +else +DBGFLAGS = -g -DNDEBUG +endif + +CFLAGS_GTEST = +LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main -lgmock -lgmock_main + +tests_SOURCES = main.cpp + +tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) +tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) +tests_LDADD = $(LDADD_GTEST) -lswsscommon $(CODE_COVERAGE_LIBS) $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file diff --git a/src/sonic-cli/tests/main.cpp b/src/sonic-cli/tests/main.cpp new file mode 100644 index 00000000000..018824973f1 --- /dev/null +++ b/src/sonic-cli/tests/main.cpp @@ -0,0 +1,84 @@ +#include "gtest/gtest.h" +#include "common/dbconnector.h" +#include + +using namespace std; +using namespace swss; + +string existing_file = "./tests/redis_multi_db_ut_config/database_config.json"; +string nonexisting_file = "./tests/redis_multi_db_ut_config/database_config_nonexisting.json"; +string global_existing_file = "./tests/redis_multi_db_ut_config/database_global.json"; + +#define TEST_DB "APPL_DB" +#define TEST_NAMESPACE "asic0" +#define INVALID_NAMESPACE "invalid" + +class SwsscommonEnvironment : public ::testing::Environment { +public: + // Override this to define how to set up the environment. + void SetUp() override { + // by default , init should be false + cout<<"Default : isInit = "< Date: Thu, 7 Apr 2022 06:19:11 +0000 Subject: [PATCH 6/8] Fix build issue --- src/sonic-cli/debian/changelog | 4 +-- src/sonic-cli/debian/control | 4 +-- src/sonic-cli/debian/copyright | 44 +-------------------------------- src/sonic-cli/tests/Makefile.am | 9 ++----- src/sonic-cli/tests/main.cpp | 2 +- 5 files changed, 7 insertions(+), 56 deletions(-) diff --git a/src/sonic-cli/debian/changelog b/src/sonic-cli/debian/changelog index da24edb914d..e18bcf51bf9 100644 --- a/src/sonic-cli/debian/changelog +++ b/src/sonic-cli/debian/changelog @@ -1,5 +1,5 @@ -sonic-cli (1.0.0-1) unstable; urgency=medium +sonic-cli (1.0.0) unstable; urgency=medium * Initial release (Closes: #nnnn) - -- unknown Wed, 06 Apr 2022 09:21:18 +0000 + -- Liu Hua Wed, 06 Apr 2022 09:21:18 +0000 diff --git a/src/sonic-cli/debian/control b/src/sonic-cli/debian/control index cbcbbf68f13..841c5a6c4ad 100644 --- a/src/sonic-cli/debian/control +++ b/src/sonic-cli/debian/control @@ -1,12 +1,10 @@ Source: sonic-cli Section: unknown Priority: optional -Maintainer: unknown +Maintainer: Liu Hua (liuh@microsoft.com) Build-Depends: debhelper-compat (= 13) Standards-Version: 4.5.1 Homepage: -#Vcs-Browser: https://salsa.debian.org/debian/sonic-cli -#Vcs-Git: https://salsa.debian.org/debian/sonic-cli.git Rules-Requires-Root: no Package: sonic-cli diff --git a/src/sonic-cli/debian/copyright b/src/sonic-cli/debian/copyright index e7eb1d9e6d2..7cf565eff8d 100644 --- a/src/sonic-cli/debian/copyright +++ b/src/sonic-cli/debian/copyright @@ -1,43 +1 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: sonic-cli -Upstream-Contact: -Source: - -Files: * -Copyright: - -License: - - - . - - -# If you want to use GPL v2 or later for the /debian/* files use -# the following clauses, or change it to suit. Delete these two lines -Files: debian/* -Copyright: 2022 unknown -License: GPL-2+ - This package is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - . - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - . - You should have received a copy of the GNU General Public License - along with this program. If not, see - . - On Debian systems, the complete text of the GNU General - Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". - -# Please also look if there are files or directories which have a -# different copyright/license attached and list them here. -# Please avoid picking licenses with terms that are more restrictive than the -# packaged work, as it may make Debian's contributions unacceptable upstream. -# -# If you need, there are some extra license texts available in two places: -# /usr/share/debhelper/dh_make/licenses/ -# /usr/share/common-licenses/ +Copyright (C) 2022 Microsoft, Inc \ No newline at end of file diff --git a/src/sonic-cli/tests/Makefile.am b/src/sonic-cli/tests/Makefile.am index 8073830cc04..e4c0b8da85e 100644 --- a/src/sonic-cli/tests/Makefile.am +++ b/src/sonic-cli/tests/Makefile.am @@ -1,12 +1,7 @@ -INCLUDES = -I $(top_srcdir) +#INCLUDES = -I $(top_srcdir) bin_PROGRAMS = tests - -if DEBUG DBGFLAGS = -ggdb -DDEBUG -else -DBGFLAGS = -g -DNDEBUG -endif CFLAGS_GTEST = LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main -lgmock -lgmock_main @@ -15,4 +10,4 @@ tests_SOURCES = main.cpp tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) -tests_LDADD = $(LDADD_GTEST) -lswsscommon $(CODE_COVERAGE_LIBS) $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file +tests_LDADD = $(LDADD_GTEST) -lpthread -lswsscommon $(CODE_COVERAGE_LIBS) $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file diff --git a/src/sonic-cli/tests/main.cpp b/src/sonic-cli/tests/main.cpp index 018824973f1..2b38773297f 100644 --- a/src/sonic-cli/tests/main.cpp +++ b/src/sonic-cli/tests/main.cpp @@ -1,5 +1,5 @@ #include "gtest/gtest.h" -#include "common/dbconnector.h" +#include #include using namespace std; From f160a9c792fea6481dcefd7fb1755ad0c542f208 Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Thu, 7 Apr 2022 08:56:36 +0000 Subject: [PATCH 7/8] Add first UT --- rules/sonic-cli.mk | 15 -- rules/{sonic-cli.dep => sonic-db-cli.dep} | 4 +- rules/sonic-db-cli.mk | 15 ++ src/sonic-cli/sonic-cli.cpp | 218 ---------------- src/sonic-cli/tests/main.cpp | 84 ------ src/{sonic-cli => sonic-db-cli}/Makefile.am | 11 +- src/{sonic-cli => sonic-db-cli}/configure.ac | 4 +- .../debian/changelog | 2 +- .../debian/control | 6 +- .../debian/copyright | 0 src/{sonic-cli => sonic-db-cli}/debian/rules | 0 src/sonic-db-cli/sonic-db-cli.cpp | 239 ++++++++++++++++++ src/sonic-db-cli/sonic-db-cli.h | 42 +++ .../tests/Makefile.am | 8 +- src/sonic-db-cli/tests/database_config.json | 107 ++++++++ src/sonic-db-cli/tests/database_config0.json | 87 +++++++ src/sonic-db-cli/tests/database_config1.json | 87 +++++++ src/sonic-db-cli/tests/database_global.json | 16 ++ src/sonic-db-cli/tests/help_output.txt | 18 ++ src/sonic-db-cli/tests/main.cpp | 56 ++++ 20 files changed, 685 insertions(+), 334 deletions(-) delete mode 100755 rules/sonic-cli.mk rename rules/{sonic-cli.dep => sonic-db-cli.dep} (61%) create mode 100755 rules/sonic-db-cli.mk delete mode 100755 src/sonic-cli/sonic-cli.cpp delete mode 100644 src/sonic-cli/tests/main.cpp rename src/{sonic-cli => sonic-db-cli}/Makefile.am (73%) rename src/{sonic-cli => sonic-db-cli}/configure.ac (95%) rename src/{sonic-cli => sonic-db-cli}/debian/changelog (75%) rename src/{sonic-cli => sonic-db-cli}/debian/control (79%) rename src/{sonic-cli => sonic-db-cli}/debian/copyright (100%) rename src/{sonic-cli => sonic-db-cli}/debian/rules (100%) create mode 100755 src/sonic-db-cli/sonic-db-cli.cpp create mode 100755 src/sonic-db-cli/sonic-db-cli.h rename src/{sonic-cli => sonic-db-cli}/tests/Makefile.am (65%) create mode 100644 src/sonic-db-cli/tests/database_config.json create mode 100644 src/sonic-db-cli/tests/database_config0.json create mode 100644 src/sonic-db-cli/tests/database_config1.json create mode 100644 src/sonic-db-cli/tests/database_global.json create mode 100644 src/sonic-db-cli/tests/help_output.txt create mode 100644 src/sonic-db-cli/tests/main.cpp diff --git a/rules/sonic-cli.mk b/rules/sonic-cli.mk deleted file mode 100755 index 0d7ab918d27..00000000000 --- a/rules/sonic-cli.mk +++ /dev/null @@ -1,15 +0,0 @@ -# sonic-cli Debian package -SONIC_CLI_VERSION = 1.0.0 -export SONIC_CLI_VERSION - -SONIC_CLI = sonic-cli_$(SONIC_CLI_VERSION)_$(CONFIGURED_ARCH).deb -$(SONIC_CLI)_DEPENDS += $(LIBSWSSCOMMON_DEV) -$(SONIC_CLI)_RDEPENDS += $(LIBSWSSCOMMON) -$(SONIC_CLI)_SRC_PATH = $(SRC_PATH)/sonic-cli - -SONIC_DPKG_DEBS += $(SONIC_CLI) - -# The .c, .cpp, .h & .hpp files under src/{$DBG_SRC_ARCHIVE list} -# are archived into debug one image to facilitate debugging. -# -DBG_SRC_ARCHIVE += sonic-cli \ No newline at end of file diff --git a/rules/sonic-cli.dep b/rules/sonic-db-cli.dep similarity index 61% rename from rules/sonic-cli.dep rename to rules/sonic-db-cli.dep index 749870fb473..68f2dca68b3 100755 --- a/rules/sonic-cli.dep +++ b/rules/sonic-db-cli.dep @@ -1,5 +1,5 @@ -SPATH := $($(SONIC_CLI)_SRC_PATH) -DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-cli.mk rules/sonic-cli.dep +SPATH := $($(SONIC_DB_CLI)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-db-cli.mk rules/sonic-db-cli.dep DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) DEP_FILES += $(shell git ls-files $(SPATH)) diff --git a/rules/sonic-db-cli.mk b/rules/sonic-db-cli.mk new file mode 100755 index 00000000000..e08524825d5 --- /dev/null +++ b/rules/sonic-db-cli.mk @@ -0,0 +1,15 @@ +# sonic-cli Debian package +SONIC_DB_CLI_VERSION = 1.0.0 +export SONIC_DB_CLI_VERSION + +SONIC_DB_CLI = sonic-db-cli_$(SONIC_DB_CLI_VERSION)_$(CONFIGURED_ARCH).deb +$(SONIC_DB_CLI)_DEPENDS += $(LIBSWSSCOMMON_DEV) +$(SONIC_DB_CLI)_RDEPENDS += $(LIBSWSSCOMMON) +$(SONIC_DB_CLI)_SRC_PATH = $(SRC_PATH)/sonic-db-cli + +SONIC_DPKG_DEBS += $(SONIC_DB_CLI) + +# The .c, .cpp, .h & .hpp files under src/{$DBG_SRC_ARCHIVE list} +# are archived into debug one image to facilitate debugging. +# +DBG_SRC_ARCHIVE += sonic-db-cli \ No newline at end of file diff --git a/src/sonic-cli/sonic-cli.cpp b/src/sonic-cli/sonic-cli.cpp deleted file mode 100755 index 1a507da5211..00000000000 --- a/src/sonic-cli/sonic-cli.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -namespace po = boost::program_options; - -static std::string nameSpace; -static std::string dbOrOperation; -const char* emptyStr = ""; - -void printUsage(const po::options_description &description) -{ - std::cout << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; - std::cout << description << std::endl; -} - -void printRedisReply(redisReply* reply) -{ - switch(reply->type) - { - case REDIS_REPLY_INTEGER: - std::cout << reply->integer; - break; - case REDIS_REPLY_STRING: - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_NIL: - std::cout << std::string(reply->str, reply->len); - break; - case REDIS_REPLY_ARRAY: - for (size_t i = 0; i < reply->elements; i++) - { - printRedisReply(reply->element[i]); - } - break; - default: - std::cerr << reply->type << std::endl; - throw std::runtime_error("Unexpected reply type"); - } - - std::cout << std::endl; -} - -int executeCommands( - const std::string& dbName, - std::vector& commands, - const std::string& nameSpace, - bool useUnixSocket) -{ - std::unique_ptr dbconn; - if (nameSpace.compare("None") == 0) { - dbconn = std::make_unique(useUnixSocket, emptyStr); - } - else { - dbconn = std::make_unique(true, nameSpace.c_str()); - } - - try { - dbconn->connect(dbName); - } - catch (const std::exception& e) - { - std::cerr << "Invalid database name input : " << dbName << std::endl; - return 1; - } - - auto& client = dbconn->get_redis_client(dbName); - - size_t argc = commands.size(); - const char** argv = new const char*[argc]; - size_t* argvc = new size_t[argc]; - for (size_t i = 0; i < argc; i++) - { - argv[i] = strdup(commands[i].c_str()); - argvc[i] = commands[i].size(); - } - - swss::RedisCommand command; - command.formatArgv(argc, argv, argvc); - swss::RedisReply reply(&client, command); - - auto redisReply = reply.getContext(); - printRedisReply(redisReply); - - return 0; -} - -void handleSingleOperation( - const std::string& nameSpace, - const std::string& dbName, - const std::string& operation, - bool useUnixSocket) -{ - swss::SonicV2Connector_Native conn(useUnixSocket, nameSpace.c_str()); - conn.connect(dbName); - auto& client = conn.get_redis_client(dbName); - - swss::RedisReply reply(&client, operation); - auto redisReply = reply.getContext(); - printRedisReply(redisReply); -} - -void handleAllInstances( - const std::string& nameSpace, - const std::string& operation, - bool useUnixSocket) -{ - // Use the tcp connectivity if namespace is local and unixsocket cmd_option is present. - if (nameSpace.compare("None") == 0) { - useUnixSocket = true; - } - - auto dbNames = swss::SonicDBConfig::getDbList(nameSpace); - // Operate All Redis Instances in Parallel - // TODO: if one of the operations failed, it could fail quickly and not necessary to wait all other operations - std::for_each( - std::execution::par, - dbNames.begin(), - dbNames.end(), - [=](auto&& dbName) - { - handleSingleOperation(nameSpace, dbName, operation, useUnixSocket); - }); -} - -int handleOperation(const po::variables_map &variablesMap, const po::options_description &description) -{ - if (variablesMap.count("db_or_op")) { - auto dbOrOperation = variablesMap["db_or_op"].as(); - auto nameSpace = variablesMap["--namespace"].as(); - bool useUnixSocket = variablesMap.count("--unixsocket"); - if (nameSpace.compare("None") != 0) { - swss::SonicDBConfig::initializeGlobalConfig(nameSpace); - } - - if (variablesMap.count("cmd")) { - auto commands = variablesMap["cmd"].as< std::vector >(); - return executeCommands(dbOrOperation, commands, nameSpace, useUnixSocket); - } - else if (nameSpace.compare("PING") == 0 || nameSpace.compare("SAVE") == 0 || nameSpace.compare("FLUSHALL") == 0) { - // redis-cli doesn't depend on database_config.json which could raise some exceptions - // sonic-db-cli catch all possible exceptions and handle it as a failure case which not return 'OK' or 'PONG' - handleAllInstances(nameSpace, dbOrOperation, useUnixSocket); - } - else { - printUsage(description); - } - } - else { - printUsage(description); - } - - return 0; -} - -void parseCliArguments( - int argc, - char** argv, - po::options_description &description, - po::variables_map &variablesMap) -{ - description.add_options() - ("--help,-h", "Help message") - ("--unixsocket,-s", "Override use of tcp_port and use unixsocket") - ("--namespace,-n", po::value(&nameSpace)->default_value("None"), "Namespace string to use asic0/asic1.../asicn") - ("db_or_op", po::value(&dbOrOperation)->default_value(emptyStr), "Database name Or Unary operation(only PING/SAVE/FLUSHALL supported)") - ("cmd", po::value< std::vector >(), "Command to execute in database") - ; - - po::store(po::parse_command_line(argc, argv, description), variablesMap); - po::notify(variablesMap); -} - -int main(int argc, char** argv) -{ - po::options_description description("SONiC DB CLI"); - po::variables_map variablesMap; - - try { - parseCliArguments(argc, argv, description, variablesMap); - } - catch (po::error_with_option_name& e) { - std::cerr << "Command Line Syntax Error: " << e.what() << std::endl; - printUsage(description); - return -1; - } - catch (po::error& e) { - std::cerr << "Command Line Error: " << e.what() << std::endl; - printUsage(description); - return -1; - } - - if (variablesMap.count("--help")) { - printUsage(description); - return 0; - } - - try - { - return handleOperation(variablesMap, description); - } - catch (const std::exception& e) - { - std::cerr << "An exception of type " << e.what() << " occurred. Arguments:" << std::endl; - for (int idx = 0; idx < argc; idx++) { - std::cerr << argv[idx] << " "; - } - std::cerr << std::endl; - return 1; - } - - return 0; -} \ No newline at end of file diff --git a/src/sonic-cli/tests/main.cpp b/src/sonic-cli/tests/main.cpp deleted file mode 100644 index 2b38773297f..00000000000 --- a/src/sonic-cli/tests/main.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "gtest/gtest.h" -#include -#include - -using namespace std; -using namespace swss; - -string existing_file = "./tests/redis_multi_db_ut_config/database_config.json"; -string nonexisting_file = "./tests/redis_multi_db_ut_config/database_config_nonexisting.json"; -string global_existing_file = "./tests/redis_multi_db_ut_config/database_global.json"; - -#define TEST_DB "APPL_DB" -#define TEST_NAMESPACE "asic0" -#define INVALID_NAMESPACE "invalid" - -class SwsscommonEnvironment : public ::testing::Environment { -public: - // Override this to define how to set up the environment. - void SetUp() override { - // by default , init should be false - cout<<"Default : isInit = "< diff --git a/src/sonic-cli/debian/control b/src/sonic-db-cli/debian/control similarity index 79% rename from src/sonic-cli/debian/control rename to src/sonic-db-cli/debian/control index 841c5a6c4ad..6a526bedbcf 100644 --- a/src/sonic-cli/debian/control +++ b/src/sonic-db-cli/debian/control @@ -1,13 +1,13 @@ -Source: sonic-cli +Source: sonic-db-cli Section: unknown Priority: optional -Maintainer: Liu Hua (liuh@microsoft.com) +Maintainer: Liu Hua Build-Depends: debhelper-compat (= 13) Standards-Version: 4.5.1 Homepage: Rules-Requires-Root: no -Package: sonic-cli +Package: sonic-db-cli Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: diff --git a/src/sonic-cli/debian/copyright b/src/sonic-db-cli/debian/copyright similarity index 100% rename from src/sonic-cli/debian/copyright rename to src/sonic-db-cli/debian/copyright diff --git a/src/sonic-cli/debian/rules b/src/sonic-db-cli/debian/rules similarity index 100% rename from src/sonic-cli/debian/rules rename to src/sonic-db-cli/debian/rules diff --git a/src/sonic-db-cli/sonic-db-cli.cpp b/src/sonic-db-cli/sonic-db-cli.cpp new file mode 100755 index 00000000000..6fac176cecc --- /dev/null +++ b/src/sonic-db-cli/sonic-db-cli.cpp @@ -0,0 +1,239 @@ +#include +#include + +#include +#include + +#include "sonic-db-cli.h" + +static std::string name_space; +static std::string db_or_operation; +const char* empty_str = ""; + +void printUsage(const po::options_description &all_options) +{ + std::cout << "usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...]" << std::endl; + std::cout << all_options << std::endl; + + std::cout << "**sudo** needed for commands accesing a different namespace [-n], or using unixsocket connection [-s]" << std::endl; + std::cout << "" << std::endl; + std::cout << "Example 1: sonic-db-cli -n asic0 CONFIG_DB keys \\*" << std::endl; + std::cout << "Example 2: sonic-db-cli -n asic2 APPL_DB HGETALL VLAN_TABLE:Vlan10" << std::endl; + std::cout << "Example 3: sonic-db-cli APPL_DB HGET VLAN_TABLE:Vlan10 mtu" << std::endl; + std::cout << "Example 4: sonic-db-cli -n asic3 APPL_DB EVAL \"return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}\" 2 k1 k2 v1 v2" << std::endl; + std::cout << "Example 5: sonic-db-cli PING | sonic-db-cli -s PING" << std::endl; + std::cout << "Example 6: sonic-db-cli SAVE | sonic-db-cli -s SAVE" << std::endl; + std::cout << "Example 7: sonic-db-cli FLUSHALL | sonic-db-cli -s FLUSHALL" << std::endl; +} + +void printRedisReply(redisReply* reply) +{ + switch(reply->type) + { + case REDIS_REPLY_INTEGER: + std::cout << reply->integer; + break; + case REDIS_REPLY_STRING: + case REDIS_REPLY_ERROR: + case REDIS_REPLY_STATUS: + case REDIS_REPLY_NIL: + std::cout << std::string(reply->str, reply->len); + break; + case REDIS_REPLY_ARRAY: + for (size_t i = 0; i < reply->elements; i++) + { + printRedisReply(reply->element[i]); + } + break; + default: + std::cerr << reply->type << std::endl; + throw std::runtime_error("Unexpected reply type"); + } + + std::cout << std::endl; +} + +int executeCommands( + const std::string& db_name, + std::vector& commands, + const std::string& name_space, + bool use_unix_socket) +{ + std::unique_ptr dbconn; + if (name_space.compare("None") == 0) { + dbconn = std::make_unique(use_unix_socket, empty_str); + } + else { + dbconn = std::make_unique(true, name_space.c_str()); + } + + try { + dbconn->connect(db_name); + } + catch (const std::exception& e) + { + std::cerr << "Invalid database name input : " << db_name << std::endl; + return 1; + } + + auto& client = dbconn->get_redis_client(db_name); + + size_t argc = commands.size(); + const char** argv = new const char*[argc]; + size_t* argvc = new size_t[argc]; + for (size_t i = 0; i < argc; i++) + { + argv[i] = strdup(commands[i].c_str()); + argvc[i] = commands[i].size(); + } + + swss::RedisCommand command; + command.formatArgv(argc, argv, argvc); + swss::RedisReply reply(&client, command); + + auto redisReply = reply.getContext(); + printRedisReply(redisReply); + + return 0; +} + +void handleSingleOperation( + const std::string& name_space, + const std::string& db_name, + const std::string& operation, + bool use_unix_socket) +{ + swss::SonicV2Connector_Native conn(use_unix_socket, name_space.c_str()); + conn.connect(db_name); + auto& client = conn.get_redis_client(db_name); + + swss::RedisReply reply(&client, operation); + auto redisReply = reply.getContext(); + printRedisReply(redisReply); +} + +void handleAllInstances( + const std::string& name_space, + const std::string& operation, + bool use_unix_socket) +{ + // Use the tcp connectivity if namespace is local and unixsocket cmd_option is present. + if (name_space.compare("None") == 0) { + use_unix_socket = true; + } + + auto dbNames = swss::SonicDBConfig::getDbList(name_space); + // Operate All Redis Instances in Parallel + // TODO: if one of the operations failed, it could fail quickly and not necessary to wait all other operations + std::for_each( + std::execution::par, + dbNames.begin(), + dbNames.end(), + [=](auto&& db_name) + { + handleSingleOperation(name_space, db_name, operation, use_unix_socket); + }); +} + +int handleOperation( + const po::options_description &all_options, + const po::variables_map &variables_map) +{ + if (variables_map.count("db_or_op")) { + auto db_or_operation = variables_map["db_or_op"].as(); + auto name_space = variables_map["--namespace"].as(); + bool useUnixSocket = variables_map.count("--unixsocket"); + if (name_space.compare("None") != 0) { + swss::SonicDBConfig::initializeGlobalConfig(name_space); + } + + if (variables_map.count("cmd")) { + auto commands = variables_map["cmd"].as< std::vector >(); + return executeCommands(db_or_operation, commands, name_space, useUnixSocket); + } + else if (name_space.compare("PING") == 0 || name_space.compare("SAVE") == 0 || name_space.compare("FLUSHALL") == 0) { + // redis-cli doesn't depend on database_config.json which could raise some exceptions + // sonic-db-cli catch all possible exceptions and handle it as a failure case which not return 'OK' or 'PONG' + handleAllInstances(name_space, db_or_operation, useUnixSocket); + } + else { + printUsage(all_options); + } + } + else { + printUsage(all_options); + } + + return 0; +} + +void parseCliArguments( + int argc, + char** argv, + po::options_description &all_options, + po::variables_map &variables_map) +{ + all_options.add_options() + ("--help,-h", "Help message") + ("--unixsocket,-s", "Override use of tcp_port and use unixsocket") + ("--namespace,-n", po::value(&name_space)->default_value("None"), "Namespace string to use asic0/asic1.../asicn") + ("db_or_op", po::value(&db_or_operation)->default_value(empty_str), "Database name Or Unary operation(only PING/SAVE/FLUSHALL supported)") + ("cmd", po::value< std::vector >(), "Command to execute in database") + ; + + po::positional_options_description positional_opts; + positional_opts.add("db_or_op", 1); + positional_opts.add("cmd", -1); + + po::store(po::command_line_parser(argc, argv) + .options(all_options) + .positional(positional_opts) + .run(), + variables_map); + po::notify(variables_map); +} + +#ifdef TESTING +int sonic_db_cli(int argc, char** argv) +#else +int main(int argc, char** argv) +#endif +{ + po::options_description all_options("SONiC DB CLI"); + po::variables_map variables_map; + + try { + parseCliArguments(argc, argv, all_options, variables_map); + } + catch (po::error_with_option_name& e) { + std::cerr << "Command Line Syntax Error: " << e.what() << std::endl; + printUsage(all_options); + return -1; + } + catch (po::error& e) { + std::cerr << "Command Line Error: " << e.what() << std::endl; + printUsage(all_options); + return -1; + } + + if (variables_map.count("--help")) { + printUsage(all_options); + return 0; + } + + try + { + return handleOperation(all_options, variables_map); + } + catch (const std::exception& e) + { + std::cerr << "An exception of type " << e.what() << " occurred. Arguments:" << std::endl; + for (int idx = 0; idx < argc; idx++) { + std::cerr << argv[idx] << " "; + } + std::cerr << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/src/sonic-db-cli/sonic-db-cli.h b/src/sonic-db-cli/sonic-db-cli.h new file mode 100755 index 00000000000..effda9507ae --- /dev/null +++ b/src/sonic-db-cli/sonic-db-cli.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +namespace po = boost::program_options; + +void printUsage(const po::options_description &all_options); + +void printRedisReply(redisReply* reply); + +int executeCommands( + const std::string& db_name, + std::vector& commands, + const std::string& name_space, + bool use_unix_socket); + +void handleSingleOperation( + const std::string& name_space, + const std::string& db_name, + const std::string& operation, + bool use_unix_socket); + +void handleAllInstances( + const std::string& name_space, + const std::string& operation, + bool use_unix_socket); + +int handleOperation( + const po::options_description &all_options, + const po::variables_map &variables_map); + +void parseCliArguments( + int argc, + char** argv, + po::options_description &all_options, + po::variables_map &variables_map); + +#ifdef TESTING +int sonic_db_cli(int argc, char** argv); +#endif \ No newline at end of file diff --git a/src/sonic-cli/tests/Makefile.am b/src/sonic-db-cli/tests/Makefile.am similarity index 65% rename from src/sonic-cli/tests/Makefile.am rename to src/sonic-db-cli/tests/Makefile.am index e4c0b8da85e..4425e2378d0 100644 --- a/src/sonic-cli/tests/Makefile.am +++ b/src/sonic-db-cli/tests/Makefile.am @@ -6,8 +6,10 @@ DBGFLAGS = -ggdb -DDEBUG CFLAGS_GTEST = LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main -lgmock -lgmock_main -tests_SOURCES = main.cpp +tests_SOURCES = main.cpp \ + ../sonic-db-cli.cpp \ + ../sonic-db-cli.h -tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) -tests_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) +tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) -DTESTING +tests_CPPFLAGS = $(tests_CFLAGS) -std=c++17 tests_LDADD = $(LDADD_GTEST) -lpthread -lswsscommon $(CODE_COVERAGE_LIBS) $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file diff --git a/src/sonic-db-cli/tests/database_config.json b/src/sonic-db-cli/tests/database_config.json new file mode 100644 index 00000000000..feea811bce6 --- /dev/null +++ b/src/sonic-db-cli/tests/database_config.json @@ -0,0 +1,107 @@ +{ + "INSTANCES": { + "redis":{ + "hostname" : "127.0.0.1", + "port": 6379, + "unix_socket_path": "/var/run/redis/redis.sock" + }, + "redis1":{ + "hostname" : "127.0.0.1", + "port": 6380, + "unix_socket_path": "/var/run/redis/redis1.sock" + }, + "redis2":{ + "hostname" : "127.0.0.1", + "port": 6381, + "unix_socket_path": "/var/run/redis/redis2.sock" + }, + "redis3":{ + "hostname" : "127.0.0.1", + "port": 6382, + "unix_socket_path": "/var/run/redis/redis3.sock" + }, + "redis4":{ + "hostname" : "127.0.0.1", + "port": 6383, + "unix_socket_path": "/var/run/redis/redis4.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "separator": ":", + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "separator": ":", + "instance" : "redis" + }, + "LOGLEVEL_DB" : { + "id" : 3, + "separator": ":", + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "separator": "|", + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "separator": "|", + "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "separator": "|", + "instance" : "redis" + }, + "ASIC_DB2" : { + "id" : 10, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB2" : { + "id" : 11, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB2" : { + "id" : 12, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB2" : { + "id" : 13, + "separator": "|", + "instance" : "redis" + }, + "APPL_STATE_DB" : { + "id" : 14, + "separator": ":", + "instance" : "redis" + }, + "TEST_DB" : { + "id" : 15, + "separator": ":", + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} \ No newline at end of file diff --git a/src/sonic-db-cli/tests/database_config0.json b/src/sonic-db-cli/tests/database_config0.json new file mode 100644 index 00000000000..e51f6f59e1a --- /dev/null +++ b/src/sonic-db-cli/tests/database_config0.json @@ -0,0 +1,87 @@ +{ + "INSTANCES": { + "redis":{ + "hostname" : "127.0.0.1", + "port": 6379, + "unix_socket_path": "/var/run/redis0/redis.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "separator": ":", + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "separator": ":", + "instance" : "redis" + }, + "LOGLEVEL_DB" : { + "id" : 3, + "separator": ":", + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "separator": "|", + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "separator": "|", + "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "separator": "|", + "instance" : "redis" + }, + "ASIC_DB2" : { + "id" : 10, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB2" : { + "id" : 11, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB2" : { + "id" : 12, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB2" : { + "id" : 13, + "separator": "|", + "instance" : "redis" + }, + "APPL_STATE_DB" : { + "id" : 14, + "separator": ":", + "instance" : "redis" + }, + "TEST_DB" : { + "id" : 15, + "separator": ":", + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} \ No newline at end of file diff --git a/src/sonic-db-cli/tests/database_config1.json b/src/sonic-db-cli/tests/database_config1.json new file mode 100644 index 00000000000..568df3cc6d3 --- /dev/null +++ b/src/sonic-db-cli/tests/database_config1.json @@ -0,0 +1,87 @@ +{ + "INSTANCES": { + "redis":{ + "hostname" : "127.0.0.1", + "port": 6379, + "unix_socket_path": "/var/run/redis1/redis.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "separator": ":", + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "separator": ":", + "instance" : "redis" + }, + "LOGLEVEL_DB" : { + "id" : 3, + "separator": ":", + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "separator": "|", + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "separator": "|", + "instance" : "redis" + }, + "SNMP_OVERLAY_DB" : { + "id" : 7, + "separator": "|", + "instance" : "redis" + }, + "ASIC_DB2" : { + "id" : 10, + "separator": ":", + "instance" : "redis" + }, + "COUNTERS_DB2" : { + "id" : 11, + "separator": ":", + "instance" : "redis" + }, + "FLEX_COUNTER_DB2" : { + "id" : 12, + "separator": ":", + "instance" : "redis" + }, + "STATE_DB2" : { + "id" : 13, + "separator": "|", + "instance" : "redis" + }, + "APPL_STATE_DB" : { + "id" : 14, + "separator": ":", + "instance" : "redis" + }, + "TEST_DB" : { + "id" : 15, + "separator": ":", + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} \ No newline at end of file diff --git a/src/sonic-db-cli/tests/database_global.json b/src/sonic-db-cli/tests/database_global.json new file mode 100644 index 00000000000..fe33bb6de98 --- /dev/null +++ b/src/sonic-db-cli/tests/database_global.json @@ -0,0 +1,16 @@ +{ + "INCLUDES" : [ + { + "include" : "database_config.json" + }, + { + "namespace" : "asic0", + "include" : "database_config0.json" + }, + { + "namespace" : "asic1", + "include" : "database_config1.json" + } + ], + "VERSION" : "1.0" +} \ No newline at end of file diff --git a/src/sonic-db-cli/tests/help_output.txt b/src/sonic-db-cli/tests/help_output.txt new file mode 100644 index 00000000000..ff2ea28266c --- /dev/null +++ b/src/sonic-db-cli/tests/help_output.txt @@ -0,0 +1,18 @@ +usage: sonic-db-cli [-h] [-s] [-n NAMESPACE] db_or_op [cmd ...] +SONiC DB CLI: + ----help Help message + ----unixsocket Override use of tcp_port and use unixsocket + ----namespace arg (=None) Namespace string to use asic0/asic1.../asicn + --db_or_op arg Database name Or Unary operation(only + PING/SAVE/FLUSHALL supported) + --cmd arg Command to execute in database + +**sudo** needed for commands accesing a different namespace [-n], or using unixsocket connection [-s] + +Example 1: sonic-db-cli -n asic0 CONFIG_DB keys \* +Example 2: sonic-db-cli -n asic2 APPL_DB HGETALL VLAN_TABLE:Vlan10 +Example 3: sonic-db-cli APPL_DB HGET VLAN_TABLE:Vlan10 mtu +Example 4: sonic-db-cli -n asic3 APPL_DB EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 k1 k2 v1 v2 +Example 5: sonic-db-cli PING | sonic-db-cli -s PING +Example 6: sonic-db-cli SAVE | sonic-db-cli -s SAVE +Example 7: sonic-db-cli FLUSHALL | sonic-db-cli -s FLUSHALL diff --git a/src/sonic-db-cli/tests/main.cpp b/src/sonic-db-cli/tests/main.cpp new file mode 100644 index 00000000000..c04ec409be8 --- /dev/null +++ b/src/sonic-db-cli/tests/main.cpp @@ -0,0 +1,56 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include +#include "sonic-db-cli.h" + +std::string db_file = "./database_config.json"; +std::string global_db_file = "./database_global.json"; + +#define TEST_DB "APPL_DB" +#define TEST_NAMESPACE "asic0" +#define INVALID_NAMESPACE "invalid" + +class SwsscommonEnvironment : public ::testing::Environment { +public: + void SetUp() override { + // load local config file + //SonicDBConfig::initialize(db_file); + //EXPECT_TRUE(SonicDBConfig::isInit()); + + // load local global file + swss::SonicDBConfig::initializeGlobalConfig(global_db_file); + EXPECT_TRUE(swss::SonicDBConfig::isGlobalInit()); + } +}; + +std::string readFileContent(std::string file_name) { + std::ifstream help_output_file(file_name); + std::stringstream buffer; + buffer << help_output_file.rdbuf(); + return buffer.str(); +} + +TEST(sonic_db_cli, test_cli_help) { + char *args[1]; + args[0] = "-h"; + + testing::internal::CaptureStdout(); + EXPECT_EQ(0, sonic_db_cli(1, args)); + auto output = testing::internal::GetCapturedStdout(); + std::cout << output << std::endl; + + auto expected_output = readFileContent("help_output.txt"); + EXPECT_EQ(expected_output, output); +} + +int main(int argc, char* argv[]) +{ + testing::InitGoogleTest(&argc, argv); + // Registers a global test environment, and verifies that the + // registration function returns its argument. + SwsscommonEnvironment* const env = new SwsscommonEnvironment; + testing::AddGlobalTestEnvironment(env); + return RUN_ALL_TESTS(); +} \ No newline at end of file From 696dfcab2e8818f7c342a492d8dab5edc118f3cd Mon Sep 17 00:00:00 2001 From: liuh-80 Date: Tue, 12 Apr 2022 07:33:16 +0000 Subject: [PATCH 8/8] Improve code --- src/sonic-db-cli/sonic-db-cli.cpp | 3 ++- src/sonic-db-cli/tests/Makefile.am | 4 ++-- src/sonic-db-cli/tests/main.cpp | 21 ++++++++++++++++++--- src/sonic-db-cli/tests/mock_connector.h | 0 4 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 src/sonic-db-cli/tests/mock_connector.h diff --git a/src/sonic-db-cli/sonic-db-cli.cpp b/src/sonic-db-cli/sonic-db-cli.cpp index 6fac176cecc..3ba7e56eef4 100755 --- a/src/sonic-db-cli/sonic-db-cli.cpp +++ b/src/sonic-db-cli/sonic-db-cli.cpp @@ -72,7 +72,8 @@ int executeCommands( } catch (const std::exception& e) { - std::cerr << "Invalid database name input : " << db_name << std::endl; + std::cerr << "Invalid database name input: " << db_name << std::endl; + std::cerr << e.what() << std::endl; return 1; } diff --git a/src/sonic-db-cli/tests/Makefile.am b/src/sonic-db-cli/tests/Makefile.am index 4425e2378d0..428aeeb1a11 100644 --- a/src/sonic-db-cli/tests/Makefile.am +++ b/src/sonic-db-cli/tests/Makefile.am @@ -3,13 +3,13 @@ bin_PROGRAMS = tests DBGFLAGS = -ggdb -DDEBUG -CFLAGS_GTEST = +CFLAGS_GTEST = -DTESTING -Wno-write-strings LDADD_GTEST = -L/usr/src/gtest -lgtest -lgtest_main -lgmock -lgmock_main tests_SOURCES = main.cpp \ ../sonic-db-cli.cpp \ ../sonic-db-cli.h -tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) -DTESTING +tests_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_GTEST) tests_CPPFLAGS = $(tests_CFLAGS) -std=c++17 tests_LDADD = $(LDADD_GTEST) -lpthread -lswsscommon $(CODE_COVERAGE_LIBS) $(BOOST_PROGRAM_OPTIONS_LIB) \ No newline at end of file diff --git a/src/sonic-db-cli/tests/main.cpp b/src/sonic-db-cli/tests/main.cpp index c04ec409be8..a70f482cb04 100644 --- a/src/sonic-db-cli/tests/main.cpp +++ b/src/sonic-db-cli/tests/main.cpp @@ -33,14 +33,29 @@ std::string readFileContent(std::string file_name) { } TEST(sonic_db_cli, test_cli_help) { - char *args[1]; - args[0] = "-h"; + char *args[2]; + args[0] = "sonic-db-cli"; + args[1] = "-h"; testing::internal::CaptureStdout(); EXPECT_EQ(0, sonic_db_cli(1, args)); auto output = testing::internal::GetCapturedStdout(); - std::cout << output << std::endl; + auto expected_output = readFileContent("help_output.txt"); + EXPECT_EQ(expected_output, output); +} + +TEST(sonic_db_cli, test_cli_default_ns_run_cmd) { + char *args[5]; + args[0] = "sonic-db-cli"; + args[1] = "APPL_DB"; + args[2] = "HGET"; + args[3] = "VLAN_TABLE:Vlan10"; + args[4] = "mtu"; + testing::internal::CaptureStdout(); + EXPECT_EQ(0, sonic_db_cli(4, args)); + auto output = testing::internal::GetCapturedStdout(); + std::cout << output <