Skip to content

Commit 0e8e5eb

Browse files
Add a "fboss2 config history" command.
1 parent 41072eb commit 0e8e5eb

File tree

9 files changed

+475
-0
lines changed

9 files changed

+475
-0
lines changed

cmake/CliFboss2.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ add_library(fboss2_lib
376376
fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.cpp
377377
fboss/cli/fboss2/commands/config/CmdConfigReload.h
378378
fboss/cli/fboss2/commands/config/CmdConfigReload.cpp
379+
fboss/cli/fboss2/commands/config/history/CmdConfigHistory.h
380+
fboss/cli/fboss2/commands/config/history/CmdConfigHistory.cpp
379381
fboss/cli/fboss2/commands/config/rollback/CmdConfigRollback.h
380382
fboss/cli/fboss2/commands/config/rollback/CmdConfigRollback.cpp
381383
fboss/cli/fboss2/commands/config/session/CmdConfigSessionCommit.h

cmake/CliFboss2Test.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
add_executable(fboss2_cmd_test
55
fboss/cli/fboss2/test/TestMain.cpp
66
fboss/cli/fboss2/test/CmdConfigAppliedInfoTest.cpp
7+
fboss/cli/fboss2/test/CmdConfigHistoryTest.cpp
78
fboss/cli/fboss2/test/CmdConfigReloadTest.cpp
89
fboss/cli/fboss2/test/CmdConfigSessionDiffTest.cpp
910
fboss/cli/fboss2/test/CmdConfigSessionTest.cpp

fboss/cli/fboss2/BUCK

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,8 @@ cpp_library(
342342
"commands/config/CmdConfigAppliedInfo.cpp",
343343
"commands/config/CmdConfigReload.h",
344344
"commands/config/CmdConfigReload.cpp",
345+
"commands/config/history/CmdConfigHistory.h",
346+
"commands/config/history/CmdConfigHistory.cpp",
345347
"commands/config/rollback/CmdConfigRollback.h",
346348
"commands/config/rollback/CmdConfigRollback.cpp",
347349
"commands/config/session/CmdConfigSessionCommit.h",

fboss/cli/fboss2/CmdHandlerImpl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "fboss/cli/fboss2/commands/clear/interface/prbs/stats/CmdClearInterfacePrbsStats.h"
2121
#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
2222
#include "fboss/cli/fboss2/commands/config/CmdConfigReload.h"
23+
#include "fboss/cli/fboss2/commands/config/history/CmdConfigHistory.h"
2324
#include "fboss/cli/fboss2/commands/config/rollback/CmdConfigRollback.h"
2425
#include "fboss/cli/fboss2/commands/config/session/CmdConfigSessionCommit.h"
2526
#include "fboss/cli/fboss2/commands/config/session/CmdConfigSessionDiff.h"
@@ -250,6 +251,7 @@ CmdHandler<CmdClearInterfaceCounters, CmdClearInterfaceCountersTraits>::run();
250251
template void
251252
CmdHandler<CmdConfigAppliedInfo, CmdConfigAppliedInfoTraits>::run();
252253
template void CmdHandler<CmdConfigReload, CmdConfigReloadTraits>::run();
254+
template void CmdHandler<CmdConfigHistory, CmdConfigHistoryTraits>::run();
253255
template void CmdHandler<CmdConfigRollback, CmdConfigRollbackTraits>::run();
254256
template void
255257
CmdHandler<CmdConfigSessionCommit, CmdConfigSessionCommitTraits>::run();

fboss/cli/fboss2/CmdList.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "fboss/cli/fboss2/commands/clear/interface/prbs/stats/CmdClearInterfacePrbsStats.h"
2323
#include "fboss/cli/fboss2/commands/config/CmdConfigAppliedInfo.h"
2424
#include "fboss/cli/fboss2/commands/config/CmdConfigReload.h"
25+
#include "fboss/cli/fboss2/commands/config/history/CmdConfigHistory.h"
2526
#include "fboss/cli/fboss2/commands/config/rollback/CmdConfigRollback.h"
2627
#include "fboss/cli/fboss2/commands/config/session/CmdConfigSessionCommit.h"
2728
#include "fboss/cli/fboss2/commands/config/session/CmdConfigSessionDiff.h"
@@ -534,6 +535,11 @@ const CommandTree& kCommandTree() {
534535
"Show config applied information",
535536
commandHandler<CmdConfigAppliedInfo>,
536537
argTypeHandler<CmdConfigAppliedInfoTraits>},
538+
{"config",
539+
"history",
540+
"Show history of committed config revisions",
541+
commandHandler<CmdConfigHistory>,
542+
argTypeHandler<CmdConfigHistoryTraits>},
537543

538544
{
539545
"config",
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright (c) 2004-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#include "fboss/cli/fboss2/commands/config/history/CmdConfigHistory.h"
12+
#include <fcntl.h>
13+
#include <pwd.h>
14+
#include <sys/stat.h>
15+
#include <cstdint>
16+
#include <ctime>
17+
#include <filesystem>
18+
#include <iomanip>
19+
#include <sstream>
20+
#include <vector>
21+
#include "fboss/cli/fboss2/session/ConfigSession.h"
22+
#include "fboss/cli/fboss2/utils/Table.h"
23+
24+
namespace fs = std::filesystem;
25+
26+
namespace facebook::fboss {
27+
28+
namespace {
29+
30+
struct RevisionInfo {
31+
int revisionNumber;
32+
std::string owner;
33+
int64_t commitTimeNsec; // Commit time in nanoseconds since epoch
34+
std::string filePath;
35+
};
36+
37+
// Get the username from a UID
38+
std::string getUsername(uid_t uid) {
39+
struct passwd* pw = getpwuid(uid);
40+
if (pw) {
41+
return std::string(pw->pw_name);
42+
}
43+
// If we can't resolve the username, return the UID as a string
44+
return "UID:" + std::to_string(uid);
45+
}
46+
47+
// Format time as a human-readable string with milliseconds
48+
std::string formatTime(int64_t timeNsec) {
49+
// Convert nanoseconds to seconds and remaining nanoseconds
50+
std::time_t timeSec = timeNsec / 1000000000;
51+
long nsec = timeNsec % 1000000000;
52+
53+
char buffer[100];
54+
struct tm* timeinfo = std::localtime(&timeSec);
55+
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
56+
57+
// Add milliseconds
58+
long milliseconds = nsec / 1000000;
59+
std::ostringstream oss;
60+
oss << buffer << '.' << std::setfill('0') << std::setw(3) << milliseconds;
61+
return oss.str();
62+
}
63+
64+
// Collect all revision files from the CLI config directory
65+
std::vector<RevisionInfo> collectRevisions(const std::string& cliConfigDir) {
66+
std::vector<RevisionInfo> revisions;
67+
68+
std::error_code ec;
69+
if (!fs::exists(cliConfigDir, ec) || !fs::is_directory(cliConfigDir, ec)) {
70+
// Directory doesn't exist or is not a directory
71+
return revisions;
72+
}
73+
74+
for (const auto& entry : fs::directory_iterator(cliConfigDir, ec)) {
75+
if (ec) {
76+
continue; // Skip entries we can't read
77+
}
78+
79+
if (!entry.is_regular_file(ec)) {
80+
continue; // Skip non-regular files
81+
}
82+
83+
std::string filename = entry.path().filename().string();
84+
int revNum = ConfigSession::extractRevisionNumber(filename);
85+
86+
if (revNum < 0) {
87+
continue; // Skip files that don't match our pattern
88+
}
89+
90+
// Get file metadata using statx to get birth time (creation time)
91+
struct statx stx;
92+
if (statx(
93+
AT_FDCWD, entry.path().c_str(), 0, STATX_BTIME | STATX_UID, &stx) !=
94+
0) {
95+
continue; // Skip if we can't get file stats
96+
}
97+
98+
RevisionInfo info;
99+
info.revisionNumber = revNum;
100+
info.owner = getUsername(stx.stx_uid);
101+
// Use birth time (creation time) if available, otherwise fall back to mtime
102+
if (stx.stx_mask & STATX_BTIME) {
103+
info.commitTimeNsec =
104+
static_cast<int64_t>(stx.stx_btime.tv_sec) * 1000000000 +
105+
stx.stx_btime.tv_nsec;
106+
} else {
107+
info.commitTimeNsec =
108+
static_cast<int64_t>(stx.stx_mtime.tv_sec) * 1000000000 +
109+
stx.stx_mtime.tv_nsec;
110+
}
111+
info.filePath = entry.path().string();
112+
113+
revisions.push_back(info);
114+
}
115+
116+
// Sort by revision number (ascending)
117+
std::sort(
118+
revisions.begin(),
119+
revisions.end(),
120+
[](const RevisionInfo& a, const RevisionInfo& b) {
121+
return a.revisionNumber < b.revisionNumber;
122+
});
123+
124+
return revisions;
125+
}
126+
127+
} // namespace
128+
129+
CmdConfigHistoryTraits::RetType CmdConfigHistory::queryClient(
130+
const HostInfo& hostInfo) {
131+
auto& session = ConfigSession::getInstance();
132+
const std::string cliConfigDir = session.getCliConfigDir();
133+
134+
auto revisions = collectRevisions(cliConfigDir);
135+
136+
if (revisions.empty()) {
137+
return "No config revisions found in " + cliConfigDir;
138+
}
139+
140+
// Build the table
141+
utils::Table table;
142+
table.setHeader({"Revision", "Owner", "Commit Time"});
143+
144+
for (const auto& rev : revisions) {
145+
table.addRow(
146+
{"r" + std::to_string(rev.revisionNumber),
147+
rev.owner,
148+
formatTime(rev.commitTimeNsec)});
149+
}
150+
151+
// Convert table to string
152+
std::ostringstream oss;
153+
oss << table;
154+
return oss.str();
155+
}
156+
157+
void CmdConfigHistory::printOutput(const RetType& tableOutput) {
158+
std::cout << tableOutput << std::endl;
159+
}
160+
161+
} // namespace facebook::fboss
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2004-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include "fboss/cli/fboss2/CmdHandler.h"
14+
#include "fboss/cli/fboss2/utils/CmdClientUtils.h"
15+
#include "fboss/cli/fboss2/utils/CmdUtils.h"
16+
17+
namespace facebook::fboss {
18+
19+
struct CmdConfigHistoryTraits : public WriteCommandTraits {
20+
static constexpr utils::ObjectArgTypeId ObjectArgTypeId =
21+
utils::ObjectArgTypeId::OBJECT_ARG_TYPE_ID_NONE;
22+
using ObjectArgType = std::monostate;
23+
using RetType = std::string;
24+
};
25+
26+
class CmdConfigHistory
27+
: public CmdHandler<CmdConfigHistory, CmdConfigHistoryTraits> {
28+
public:
29+
using ObjectArgType = CmdConfigHistoryTraits::ObjectArgType;
30+
using RetType = CmdConfigHistoryTraits::RetType;
31+
32+
RetType queryClient(const HostInfo& hostInfo);
33+
34+
void printOutput(const RetType& tableOutput);
35+
};
36+
37+
} // namespace facebook::fboss

fboss/cli/fboss2/test/BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ cpp_unittest(
5555
name = "cmd_test",
5656
srcs = [
5757
"CmdConfigAppliedInfoTest.cpp",
58+
"CmdConfigHistoryTest.cpp",
5859
"CmdConfigReloadTest.cpp",
5960
"CmdConfigSessionDiffTest.cpp",
6061
"CmdConfigSessionTest.cpp",

0 commit comments

Comments
 (0)