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

[sonic-db-cli]: SONiC DB CLI for DPU objects #837

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
12 changes: 12 additions & 0 deletions .azure-pipelines/build-docker-sonic-vs-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ jobs:
artifact: ${{ parameters.swss_artifact_name }}
path: $(Build.ArtifactStagingDirectory)/download
displayName: "Download pre-stage built ${{ parameters.swss_artifact_name }}"
- task: DownloadPipelineArtifact@2
inputs:
source: specific
project: build
pipeline: sonic-net.sonic-dash-api
artifact: sonic-dash-api
runVersion: 'latestFromBranch'
runBranch: 'refs/heads/$(BUILD_BRANCH)'
path: $(Build.ArtifactStagingDirectory)/download
patterns: |
libdashapi*.deb
displayName: "Download dash api"
- task: DownloadPipelineArtifact@2
inputs:
source: specific
Expand Down
17 changes: 17 additions & 0 deletions .azure-pipelines/build-sairedis-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,24 @@ jobs:
patterns: |
target/debs/${{ parameters.debian_version }}/libyang-*.deb
target/debs/${{ parameters.debian_version }}/libyang_*.deb
target/debs/${{ parameters.debian_version }}/libprotobuf*.deb
target/debs/${{ parameters.debian_version }}/libprotoc*.deb
target/debs/${{ parameters.debian_version }}/protobuf-compiler*.deb
displayName: "Download libyang from common lib"
- task: DownloadPipelineArtifact@2
inputs:
source: specific
project: build
pipeline: sonic-net.sonic-dash-api
${{ if eq(parameters.arch, 'amd64') }}:
artifact: sonic-dash-api
${{ else }}:
artifact: sonic-dash-api.${{ parameters.arch }}
runVersion: 'latestFromBranch'
runBranch: 'refs/heads/$(BUILD_BRANCH)'
path: $(Build.ArtifactStagingDirectory)/download
patterns: |
libdashapi*.deb
- script: |
set -ex
sudo dpkg -i $(find ./download -name *.deb)
Expand Down
15 changes: 14 additions & 1 deletion .azure-pipelines/build-swss-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,21 @@ jobs:
target/debs/${{ parameters.debian_version }}/libprotobuf*.deb
target/debs/${{ parameters.debian_version }}/libprotoc*.deb
target/debs/${{ parameters.debian_version }}/protobuf-compiler*.deb
target/debs/${{ parameters.debian_version }}/libdashapi*.deb
displayName: "Download common libs"
- task: DownloadPipelineArtifact@2
inputs:
source: specific
project: build
pipeline: sonic-net.sonic-dash-api
${{ if eq(parameters.arch, 'amd64') }}:
artifact: sonic-dash-api
${{ else }}:
artifact: sonic-dash-api.${{ parameters.arch }}
runVersion: 'latestFromBranch'
runBranch: 'refs/heads/$(BUILD_BRANCH)'
path: $(Build.ArtifactStagingDirectory)/download
patterns: |
libdashapi*.deb

- script: |
set -ex
Expand Down
21 changes: 19 additions & 2 deletions .azure-pipelines/build-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,29 @@ jobs:
patterns: |
target/debs/${{ parameters.debian_version }}/libyang-*.deb
target/debs/${{ parameters.debian_version }}/libyang_*.deb
displayName: "Download libyang from ${{ parameters.arch }} common lib"
target/debs/${{ parameters.debian_version }}/libprotobuf*.deb
target/debs/${{ parameters.debian_version }}/libprotoc*.deb
displayName: "Download ${{ parameters.arch }} common lib"
- task: DownloadPipelineArtifact@2
inputs:
source: specific
project: build
pipeline: sonic-net.sonic-dash-api
${{ if eq(parameters.arch, 'amd64') }}:
artifact: sonic-dash-api
${{ else }}:
artifact: sonic-dash-api.${{ parameters.arch }}
runVersion: 'latestFromBranch'
runBranch: 'refs/heads/$(BUILD_BRANCH)'
path: $(Build.ArtifactStagingDirectory)/download
patterns: |
libdashapi*.deb
displayName: "Download dash api"
- script: |
set -ex
sudo dpkg -i $(find ./download -name *.deb)
workingDirectory: $(Build.ArtifactStagingDirectory)
displayName: "Install libyang from common lib"
displayName: "Install common libs and dashapi from common lib"
- script: |
set -ex
rm ../*.deb || true
Expand Down
4 changes: 2 additions & 2 deletions .azure-pipelines/docker-sonic-vs/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ COPY ["debs", "/debs"]
# Remove existing packages first before installing the new/current packages. This is to overcome limitations with
# Docker's diff detection mechanism, where only the file size and the modification timestamp (which will remain the
# same, even though contents have changed) are checked between the previous and current layer.
RUN dpkg --purge libswsscommon python3-swsscommon sonic-db-cli libsaimetadata libsairedis libsaivs syncd-vs swss sonic-eventd
RUN dpkg -i /debs/libswsscommon_1.0.0_amd64.deb /debs/python3-swsscommon_1.0.0_amd64.deb /debs/sonic-db-cli_1.0.0_amd64.deb /debs/libsaimetadata_1.0.0_amd64.deb /debs/libsairedis_1.0.0_amd64.deb /debs/libsaivs_1.0.0_amd64.deb /debs/syncd-vs_1.0.0_amd64.deb /debs/swss_1.0.0_amd64.deb
RUN dpkg --purge libswsscommon python3-swsscommon sonic-db-cli libsaimetadata libsairedis libsaivs syncd-vs swss sonic-eventd libdashapi
RUN dpkg -i /debs/libdashapi_1.0.0_amd64.deb /debs/libswsscommon_1.0.0_amd64.deb /debs/python3-swsscommon_1.0.0_amd64.deb /debs/sonic-db-cli_1.0.0_amd64.deb /debs/libsaimetadata_1.0.0_amd64.deb /debs/libsairedis_1.0.0_amd64.deb /debs/libsaivs_1.0.0_amd64.deb /debs/syncd-vs_1.0.0_amd64.deb /debs/swss_1.0.0_amd64.deb
2 changes: 2 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ cc_library(
hdrs = glob([
"common/*.h",
"common/*.hpp",
"config.h"
]),
copts = [
"-std=c++14",
"-I/usr/include/libnl3", # Expected location in the SONiC build container"
"-I."
],
includes = [
"common",
Expand Down
70 changes: 65 additions & 5 deletions common/redisreply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@
#include <sstream>
#include <system_error>
#include <functional>
#include <memory>
#include <boost/algorithm/string.hpp>

#include <config.h>
#include "common/logger.h"
#include "common/redisreply.h"
#include "common/dbconnector.h"
#include "common/rediscommand.h"
#include "common/stringutility.h"

#ifdef DASH_API_INSTALLED
#include <dash_api/utils.h>
#endif

using namespace std;
using namespace boost;

Expand Down Expand Up @@ -276,7 +282,7 @@ string RedisReply::to_string()
return RedisReply::to_string(this->getContext());
}

string RedisReply::to_string(redisReply *reply, string command)
string RedisReply::to_string(redisReply *reply, const string &command)
{
/*
Response format need keep as same as redis-py, redis-py using a command to result type mapping to convert result:
Expand Down Expand Up @@ -308,7 +314,33 @@ string RedisReply::to_string(redisReply *reply, string command)
}
}

string RedisReply::formatReply(string command, long long integer)
string RedisReply::to_string(redisReply *reply,const vector<string> &commands)
{
if (commands.empty())
{
return to_string(reply);
}

auto command = boost::to_upper_copy<string>(commands[0]);

#ifdef DASH_API_INSTALLED
if (commands.size() > 1)
{
if (reply->type == REDIS_REPLY_ARRAY
&& command == "HGETALL"
&& reply->elements == 2
&& to_string(reply->element[0]) == PROTOBUF_TYPE_TAG
&& reply->element[1]->type == REDIS_REPLY_STRING)
{
return formatPbReply(reply->element, reply->elements, commands[1]);
}
}
#endif

return to_string(reply, command);
}

string RedisReply::formatReply(const string &command, long long integer)
{
if (g_intToBoolCommands.find(command) != g_intToBoolCommands.end())
{
Expand All @@ -332,7 +364,7 @@ string RedisReply::formatReply(string command, long long integer)
return std::to_string(integer);
}

string RedisReply::formatReply(string command, const char* str, size_t len)
string RedisReply::formatReply(const string &command, const char* str, size_t len)
{
string result = string(str, len);
if (g_strToBoolCommands.find(command) != g_strToBoolCommands.end()
Expand All @@ -357,7 +389,7 @@ string RedisReply::formatReply(string command, const char* str, size_t len)
return result;
}

string RedisReply::formatReply(string command, struct redisReply **element, size_t elements)
string RedisReply::formatReply(const string &command, struct redisReply **element, size_t elements)
{
if (command == "HGETALL")
{
Expand Down Expand Up @@ -475,7 +507,35 @@ string RedisReply::formatTupleReply(struct redisReply **element, size_t elements
return swss::join(", ", '(', ')', elementvector.begin(), elementvector.end());
}

string RedisReply::formatStringWithQuot(string str)
string RedisReply::formatPbReply(struct redisReply **element, size_t elements, const string &key)
{
#ifdef DASH_API_INSTALLED
if (
elements != 2
|| to_string(element[0]) != PROTOBUF_TYPE_TAG
|| element[1]->type != REDIS_REPLY_STRING)
{
throw system_error(make_error_code(errc::io_error),
"Invalid result");
}

std::string pb_buffer(element[1]->str, element[1]->len);

// Extract table name
std::string table_name(
key.begin(),
find_if(
key.begin(),
key.end(),
[](char c){ return c == ':' || c == '|';}));

return dash::PbBinaryToJsonString(table_name, pb_buffer);
#else
throw runtime_error("Dash API is not installed");
#endif
}

string RedisReply::formatStringWithQuot(const string &str)
{
if (str.find('\'') != std::string::npos)
{
Expand Down
12 changes: 7 additions & 5 deletions common/redisreply.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,24 @@ class RedisReply

std::string to_string();

static std::string to_string(redisReply *reply, std::string command = std::string());
static std::string to_string(redisReply *reply,const std::string &command = std::string());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const

Please add one blank before const.

static std::string to_string(redisReply *reply,const std::vector<std::string> &commands);

private:
void checkStatus(const char *status);
void checkReply();

static std::string formatReply(std::string command, struct redisReply **element, size_t elements);
static std::string formatReply(std::string command, long long integer);
static std::string formatReply(std::string command, const char* str, size_t len);
static std::string formatReply(const std::string &command, struct redisReply **element, size_t elements);
static std::string formatReply(const std::string &command, long long integer);
static std::string formatReply(const std::string &command, const char* str, size_t len);
static std::string formatSscanReply(struct redisReply **element, size_t elements);
static std::string formatHscanReply(struct redisReply **element, size_t elements);
static std::string formatDictReply(struct redisReply **element, size_t elements);
static std::string formatArrayReply(struct redisReply **element, size_t elements);
static std::string formatListReply(struct redisReply **element, size_t elements);
static std::string formatTupleReply(struct redisReply **element, size_t elements);
static std::string formatStringWithQuot(std::string str);
static std::string formatPbReply(struct redisReply **element, size_t elements, const std::string &key);
static std::string formatStringWithQuot(const std::string &str);

redisReply *m_reply;
};
Expand Down
2 changes: 2 additions & 0 deletions common/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,8 @@ namespace swss {
#define DEL_COMMAND "DEL"
#define EMPTY_PREFIX ""

#define PROTOBUF_TYPE_TAG "pb"

#define CFG_DTEL_TABLE_NAME "DTEL"
#define CFG_DTEL_REPORT_SESSION_TABLE_NAME "DTEL_REPORT_SESSION"
#define CFG_DTEL_INT_SESSION_TABLE_NAME "DTEL_INT_SESSION"
Expand Down
9 changes: 9 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ CFLAGS_COMMON+=" -fstack-protector-strong"

AC_SUBST(CFLAGS_COMMON)

AC_CHECK_LIB([dashapi], [PbBinaryToJsonString], [
AC_DEFINE(DASH_API_INSTALLED, 1, [Define if DASH API is installed])
LIBS="$LIBS -ldashapi"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ldashapi

swss-common is widely used, it is awkward to ask others to install dashapi.
I see below options:

  1. remove the dependency on dashapi, and make this PR a generic feature
  2. refactor sonic-db-cli to support plugin, and develop a new plugin with dashapi dependency
  3. develop another CLI like sonic-db-dash-cli (just random name).

],
[
CFLAGS_COMMON+=" -Wno-suggest-attribute=noreturn"
])


AC_CONFIG_FILES([
Makefile
])
Expand Down
13 changes: 1 addition & 12 deletions sonic-db-cli/sonic-db-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ int executeCommands(
based on our usage in SONiC, None and list type output from python API needs to be modified
with these changes, it is enough for us to mimic redis-cli in SONiC so far since no application uses tty mode redis-cli output
*/
auto commandName = getCommandName(commands);
cout << RedisReply::to_string(reply.getContext(), commandName) << endl;
cout << RedisReply::to_string(reply.getContext(), commands) << endl;
}
catch (const std::system_error& e)
{
Expand Down Expand Up @@ -371,13 +370,3 @@ int cli_exception_wrapper(
return 1;
}
}

string getCommandName(vector<string>& commands)
{
if (commands.size() == 0)
{
return string();
}

return boost::to_upper_copy<string>(commands[0]);
}
34 changes: 33 additions & 1 deletion tests/cli_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <string>
#include <ctime>
#include <getopt.h>
#include <stdlib.h>

#include "common/dbconnector.h"
#include "sonic-db-cli/sonic-db-cli.h"

Expand Down Expand Up @@ -539,4 +541,34 @@ TEST(sonic_db_cli, test_cli_not_throw_exception)
initializeConfig);

EXPECT_EQ(1, exit_code);
}
}

TEST(sonic_db_cli, test_cli_hgetall_pb)
{
char *args[6];
args[0] = "sonic-db-cli";
args[1] = "TEST_DB";

// clear database
args[2] = "FLUSHDB";
auto output = runCli(3, args);
EXPECT_EQ("True\n", output);

// restore binary pb message to TEST_DB
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pb_appliance.bin

Do you want to check-in this binary file with this PR? Better to prevent binary file in codebase, instead you can generate it.

EXPECT_EQ(system("cat ./tests/cli_test_data/pb_appliance.bin "
"| redis-cli -n 15 -x restore 'DASH_APPLIANCE_TABLE:123' 0"),
0);

string target_json =
"{\n"
" \"sip\": {\n"
" \"ipv4\": 16777482\n"
" },\n"
" \"vm_vni\": 4321\n"
"}\n\n";

args[2] = "hgetall";
args[3] = R"(DASH_APPLIANCE_TABLE:123)";
output = runCli(4, args);
EXPECT_EQ(target_json, output);
}
Loading