Skip to content
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
2 changes: 2 additions & 0 deletions cmake/CliFboss2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,8 @@ install(TARGETS fboss2)

# Config commands library for fboss2-dev
add_library(fboss2_config_lib
fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h
fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.cpp
fboss/cli/fboss2/commands/config/CmdConfigReload.h
fboss/cli/fboss2/commands/config/CmdConfigReload.cpp
fboss/cli/fboss2/CmdListConfig.cpp
Expand Down
1 change: 1 addition & 0 deletions cmake/CliFboss2Test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# cmd_test - Command tests from BUCK file
add_executable(fboss2_cmd_test
fboss/cli/fboss2/test/TestMain.cpp
fboss/cli/fboss2/test/CmdConfigAppliedInfoTest.cpp
fboss/cli/fboss2/test/CmdConfigReloadTest.cpp
fboss/cli/fboss2/test/CmdSetPortStateTest.cpp
fboss/cli/fboss2/test/CmdShowAclTest.cpp
Expand Down
2 changes: 2 additions & 0 deletions fboss/cli/fboss2/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,11 @@ cpp_library(
srcs = [
"CmdHandlerImplConfig.cpp",
"CmdListConfig.cpp",
"commands/config/CmdConfigAppliedInfo.cpp",
"commands/config/CmdConfigReload.cpp",
],
headers = [
"commands/config/CmdConfigAppliedInfo.h",
"commands/config/CmdConfigReload.h",
],
exported_deps = [
Expand Down
3 changes: 3 additions & 0 deletions fboss/cli/fboss2/CmdHandlerImplConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@

#include "fboss/cli/fboss2/CmdHandler.cpp"

#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
#include "fboss/cli/fboss2/commands/config/CmdConfigReload.h"

namespace facebook::fboss {

template void
CmdHandler<CmdConfigAppliedInfo, CmdConfigAppliedInfoTraits>::run();
template void CmdHandler<CmdConfigReload, CmdConfigReloadTraits>::run();

} // namespace facebook::fboss
7 changes: 7 additions & 0 deletions fboss/cli/fboss2/CmdListConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@
#include "fboss/cli/fboss2/CmdList.h"

#include "fboss/cli/fboss2/CmdHandler.h"
#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
#include "fboss/cli/fboss2/commands/config/CmdConfigReload.h"

namespace facebook::fboss {

const CommandTree& kConfigCommandTree() {
static CommandTree root = {
{"config",
"applied-info",
"Show config applied information",
commandHandler<CmdConfigAppliedInfo>,
argTypeHandler<CmdConfigAppliedInfoTraits>},

{"config",
"reload",
"Reload agent configuration",
Expand Down
69 changes: 69 additions & 0 deletions fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/

#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
#include <folly/Conv.h>
#include <ctime>
#include <iomanip>
#include <sstream>

namespace facebook::fboss {

namespace {
std::string formatTimestamp(int64_t timestampMs) {
if (timestampMs == 0) {
return "Never";
}

// Convert milliseconds to seconds
std::time_t timeInSeconds = timestampMs / 1000;
int64_t milliseconds = timestampMs % 1000;

// Convert to local time
std::tm* localTime = std::localtime(&timeInSeconds);

// Format the timestamp
std::ostringstream oss;
oss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S");
oss << "." << std::setfill('0') << std::setw(3) << milliseconds;

return oss.str();
}
} // namespace

CmdConfigAppliedInfoTraits::RetType CmdConfigAppliedInfo::queryClient(
const HostInfo& hostInfo) {
auto client =
utils::createClient<facebook::fboss::FbossCtrlAsyncClient>(hostInfo);

ConfigAppliedInfo configAppliedInfo;
client->sync_getConfigAppliedInfo(configAppliedInfo);

return configAppliedInfo;
}

void CmdConfigAppliedInfo::printOutput(const RetType& configAppliedInfo) {
std::cout << "Config Applied Information:" << std::endl;
std::cout << "===========================" << std::endl;

std::cout << "Last Applied Time: "
<< formatTimestamp(*configAppliedInfo.lastAppliedInMs())
<< std::endl;

std::cout << "Last Coldboot Applied Time: ";
if (configAppliedInfo.lastColdbootAppliedInMs()) {
std::cout << formatTimestamp(*configAppliedInfo.lastColdbootAppliedInMs())
<< std::endl;
} else {
std::cout << "Not available (warmboot)" << std::endl;
}
}

} // namespace facebook::fboss
40 changes: 40 additions & 0 deletions fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2004-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/

#pragma once

#include <folly/Conv.h>
#include <iostream>
#include "fboss/agent/if/gen-cpp2/ctrl_types.h"
#include "fboss/cli/fboss2/CmdHandler.h"
#include "fboss/cli/fboss2/utils/CmdClientUtils.h"
#include "fboss/cli/fboss2/utils/CmdUtils.h"

namespace facebook::fboss {

struct CmdConfigAppliedInfoTraits : public BaseCommandTraits {
static constexpr utils::ObjectArgTypeId ObjectArgTypeId =
utils::ObjectArgTypeId::OBJECT_ARG_TYPE_ID_NONE;
using ObjectArgType = std::monostate;
using RetType = ConfigAppliedInfo;
};

class CmdConfigAppliedInfo
: public CmdHandler<CmdConfigAppliedInfo, CmdConfigAppliedInfoTraits> {
public:
using ObjectArgType = CmdConfigAppliedInfoTraits::ObjectArgType;
using RetType = CmdConfigAppliedInfoTraits::RetType;

RetType queryClient(const HostInfo& hostInfo);

void printOutput(const RetType& configAppliedInfo);
};

} // namespace facebook::fboss
1 change: 1 addition & 0 deletions fboss/cli/fboss2/test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cpp_unittest(
cpp_unittest(
name = "cmd_test",
srcs = [
"CmdConfigAppliedInfoTest.cpp",
"CmdConfigReloadTest.cpp",
"CmdGetPcapTest.cpp",
"CmdSetPortStateTest.cpp",
Expand Down
127 changes: 127 additions & 0 deletions fboss/cli/fboss2/test/CmdConfigAppliedInfoTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// (c) Facebook, Inc. and its affiliates. Confidential and proprietary.

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sstream>

#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
#include "fboss/cli/fboss2/test/CmdHandlerTestBase.h"

using namespace ::testing;

namespace facebook::fboss {

ConfigAppliedInfo createMockConfigAppliedInfoWarmboot() {
ConfigAppliedInfo configAppliedInfo;
configAppliedInfo.lastAppliedInMs() = 1609459200000;
return configAppliedInfo;
}

ConfigAppliedInfo createMockConfigAppliedInfo() {
auto configAppliedInfo = createMockConfigAppliedInfoWarmboot();
configAppliedInfo.lastColdbootAppliedInMs() = 1609459100000;
return configAppliedInfo;
}

class CmdConfigAppliedInfoTestFixture : public CmdHandlerTestBase {
public:
ConfigAppliedInfo mockConfigAppliedInfo;
ConfigAppliedInfo mockConfigAppliedInfoWarmboot;

void SetUp() override {
CmdHandlerTestBase::SetUp();
mockConfigAppliedInfo = createMockConfigAppliedInfo();
mockConfigAppliedInfoWarmboot = createMockConfigAppliedInfoWarmboot();
}
};

TEST_F(CmdConfigAppliedInfoTestFixture, queryClient) {
setupMockedAgentServer();
EXPECT_CALL(getMockAgent(), getConfigAppliedInfo(_))
.WillOnce(Invoke([&](auto& configAppliedInfo) {
configAppliedInfo = mockConfigAppliedInfo;
}));

auto cmd = CmdConfigAppliedInfo();
auto result = cmd.queryClient(localhost());

EXPECT_EQ(
*result.lastAppliedInMs(), *mockConfigAppliedInfo.lastAppliedInMs());
EXPECT_EQ(
*result.lastColdbootAppliedInMs(),
*mockConfigAppliedInfo.lastColdbootAppliedInMs());
}

TEST_F(CmdConfigAppliedInfoTestFixture, queryClientWarmboot) {
setupMockedAgentServer();
EXPECT_CALL(getMockAgent(), getConfigAppliedInfo(_))
.WillOnce(Invoke([&](auto& configAppliedInfo) {
configAppliedInfo = mockConfigAppliedInfoWarmboot;
}));

auto cmd = CmdConfigAppliedInfo();
auto result = cmd.queryClient(localhost());

EXPECT_EQ(
*result.lastAppliedInMs(),
*mockConfigAppliedInfoWarmboot.lastAppliedInMs());
EXPECT_FALSE(result.lastColdbootAppliedInMs().has_value());
}

TEST_F(CmdConfigAppliedInfoTestFixture, printOutputWithColdboot) {
auto cmd = CmdConfigAppliedInfo();

std::stringstream buffer;
std::streambuf* old = std::cout.rdbuf(buffer.rdbuf());

cmd.printOutput(mockConfigAppliedInfo);

std::cout.rdbuf(old);

std::string output = buffer.str();

EXPECT_NE(output.find("Config Applied Information:"), std::string::npos);
EXPECT_NE(output.find("==========================="), std::string::npos);
EXPECT_NE(output.find("Last Applied Time:"), std::string::npos);
EXPECT_NE(output.find("Last Coldboot Applied Time:"), std::string::npos);
EXPECT_EQ(output.find("Not available (warmboot)"), std::string::npos);
}

TEST_F(CmdConfigAppliedInfoTestFixture, printOutputWarmboot) {
auto cmd = CmdConfigAppliedInfo();

std::stringstream buffer;
std::streambuf* old = std::cout.rdbuf(buffer.rdbuf());

cmd.printOutput(mockConfigAppliedInfoWarmboot);

std::cout.rdbuf(old);

std::string output = buffer.str();

EXPECT_NE(output.find("Config Applied Information:"), std::string::npos);
EXPECT_NE(output.find("==========================="), std::string::npos);
EXPECT_NE(output.find("Last Applied Time:"), std::string::npos);
EXPECT_NE(output.find("Last Coldboot Applied Time:"), std::string::npos);
EXPECT_NE(output.find("Not available (warmboot)"), std::string::npos);
}

TEST_F(CmdConfigAppliedInfoTestFixture, printOutputZeroTimestamp) {
auto cmd = CmdConfigAppliedInfo();

std::stringstream buffer;
std::streambuf* old = std::cout.rdbuf(buffer.rdbuf());

cmd.printOutput(ConfigAppliedInfo()); // Zero value.

std::cout.rdbuf(old);

std::string output = buffer.str();

EXPECT_NE(output.find("Config Applied Information:"), std::string::npos);
EXPECT_NE(output.find("==========================="), std::string::npos);
EXPECT_NE(output.find("Last Applied Time:"), std::string::npos);
EXPECT_NE(output.find("Never"), std::string::npos);
}

} // namespace facebook::fboss
1 change: 1 addition & 0 deletions fboss/cli/fboss2/test/MockClients.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class MockFbossCtrlAgent : public FbossCtrlSvIf {
void,
getAllEcmpDetails,
(std::vector<facebook::fboss::EcmpDetails>&));
MOCK_METHOD(void, getConfigAppliedInfo, (ConfigAppliedInfo&));
};

class MockFbossQsfpService : public QsfpServiceSvIf {
Expand Down
Loading