This is an automated email from the ASF dual-hosted git repository.
dmeden pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 07dd143859 traffic_ctl: Refactor command execution in traffic_ctl
(#12647)
07dd143859 is described below
commit 07dd1438594e4e9fc285236e02dbc954241a197a
Author: Damian Meden <[email protected]>
AuthorDate: Thu Nov 13 13:08:35 2025 +0100
traffic_ctl: Refactor command execution in traffic_ctl (#12647)
* traffic_ctl: Refactor command execution in traffic_ctl
Replace repeated inline lambdas with a reusable Command_Execute
lambda. This reduces code duplication.
---
src/traffic_ctl/traffic_ctl.cc | 123 ++++++++++++++++++++++-------------------
1 file changed, 65 insertions(+), 58 deletions(-)
diff --git a/src/traffic_ctl/traffic_ctl.cc b/src/traffic_ctl/traffic_ctl.cc
index 673b1906f7..5599bd64c9 100644
--- a/src/traffic_ctl/traffic_ctl.cc
+++ b/src/traffic_ctl/traffic_ctl.cc
@@ -63,7 +63,15 @@ main([[maybe_unused]] int argc, const char **argv)
{
ts::ArgParser parser;
- std::shared_ptr<CtrlCommand> command;
+ std::unique_ptr<CtrlCommand> command;
+
+ auto Command_Execute = [&command]() {
+ if (command) {
+ command->execute();
+ } else {
+ throw std::runtime_error("No command provided");
+ }
+ };
auto CtrlUnimplementedCommand = [](std::string_view cmd) {
std::cout << "Command " << cmd << " unimplemented.\n";
@@ -92,33 +100,31 @@ main([[maybe_unused]] int argc, const char **argv)
auto &direct_rpc_command = parser.add_command("rpc", "Interact with the rpc
api").require_commands();
// config commands
- config_command.add_command("defaults", "Show default information
configuration values", [&]() { command->execute(); })
+ config_command.add_command("defaults", "Show default information
configuration values", Command_Execute)
.add_example_usage("traffic_ctl config defaults [OPTIONS]")
.add_option("--records", "", "Emit output in YAML format");
config_command
- .add_command("describe", "Show detailed information about configuration
values", "", MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); })
+ .add_command("describe", "Show detailed information about configuration
values", "", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl config describe RECORD [RECORD ...]");
- config_command.add_command("diff", "Show non-default configuration values",
[&]() { command->execute(); })
+ config_command.add_command("diff", "Show non-default configuration values",
Command_Execute)
.add_example_usage("traffic_ctl config diff [OPTIONS]")
.add_option("--records", "", "Emit output in YAML format");
- config_command.add_command("get", "Get one or more configuration values",
"", MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ config_command.add_command("get", "Get one or more configuration values",
"", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl config get [OPTIONS] RECORD [RECORD ...]")
.add_option("--cold", "-c",
"Save the value in a configuration file. This does not save
the value in TS. Local file change only",
"TS_RECORD_YAML", MORE_THAN_ZERO_ARG_N)
.add_option("--records", "", "Emit output in YAML format")
.add_option("--default", "", "Include default value");
- config_command
- .add_command("match", "Get configuration matching a regular expression",
"", MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ config_command.add_command("match", "Get configuration matching a regular
expression", "", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl config match [OPTIONS] REGEX [REGEX ...]")
.add_option("--records", "", "Emit output in YAML format")
.add_option("--default", "", "Include the default value");
- config_command.add_command("reload", "Request a configuration reload", [&]()
{ command->execute(); })
+ config_command.add_command("reload", "Request a configuration reload",
Command_Execute)
.add_example_usage("traffic_ctl config reload");
- config_command.add_command("status", "Check the configuration status", [&]()
{ command->execute(); })
+ config_command.add_command("status", "Check the configuration status",
Command_Execute)
.add_example_usage("traffic_ctl config status");
- config_command.add_command("set", "Set a configuration value", "", 2, [&]()
{ command->execute(); })
+ config_command.add_command("set", "Set a configuration value", "", 2,
Command_Execute)
.add_option("--cold", "-c",
"Save the value in a configuration file. This does not save
the value in TS. Local file change only",
"TS_RECORD_YAML", MORE_THAN_ZERO_ARG_N)
@@ -129,31 +135,30 @@ main([[maybe_unused]] int argc, const char **argv)
"", 1)
.add_example_usage("traffic_ctl config set RECORD VALUE");
- config_command.add_command("registry", "Show configuration file registry",
[&]() { command->execute(); })
+ config_command.add_command("registry", "Show configuration file registry",
Command_Execute)
.add_example_usage("traffic_ctl config registry");
// host commands
- host_command.add_command("status", "Get one or more host statuses", "",
MORE_THAN_ZERO_ARG_N, [&]() { command->execute(); })
+ host_command.add_command("status", "Get one or more host statuses", "",
MORE_THAN_ZERO_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl host status HOST [HOST ...]");
- host_command.add_command("down", "Set down one or more host(s)", "",
MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ host_command.add_command("down", "Set down one or more host(s)", "",
MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl host down HOST [OPTIONS]")
.add_option("--time", "-I", "number of seconds that a host is marked
down", "", 1, "0")
.add_option("--reason", "", "reason for marking the host down, one of
'manual|active|local", "", 1, "manual");
- host_command.add_command("up", "Set up one or more host(s)", "",
MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ host_command.add_command("up", "Set up one or more host(s)", "",
MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl host up METRIC value")
.add_option("--reason", "", "reason for marking the host up, one of
'manual|active|local", "", 1, "manual");
// metric commands
- metric_command.add_command("get", "Get one or more metric values", "",
MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ metric_command.add_command("get", "Get one or more metric values", "",
MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl metric get METRIC [METRIC ...]");
metric_command.add_command("describe", "Show detailed information about one
or more metric values", "", MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); }); // not implemented
- metric_command.add_command("match", "Get metrics matching a regular
expression", "", MORE_THAN_ZERO_ARG_N,
- [&]() { command->execute(); });
+ Command_Execute); // not implemented
+ metric_command.add_command("match", "Get metrics matching a regular
expression", "", MORE_THAN_ZERO_ARG_N, Command_Execute);
metric_command
.add_command(
"monitor",
"Display the value of a metric(s) over time. Program stops after <count>
or with a SIGINT. A brief summary is displayed.", "",
- MORE_THAN_ZERO_ARG_N, [&]() { command->execute(); })
+ MORE_THAN_ZERO_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl metric monitor METRIC -i 3 -c 10")
.add_option("--count", "-c",
"Terminate execution after requesting <count> metrics. If 0 is
passed, program should be terminated by a SIGINT",
@@ -161,60 +166,81 @@ main([[maybe_unused]] int argc, const char **argv)
.add_option("--interval", "-i", "Wait interval seconds between sending
each metric request. Minimum value is 1s.", "", 1, "5");
// hostdb commands
- hostdb_command.add_command("status", "Get HostDB info", "",
MORE_THAN_ZERO_ARG_N, [&]() { command->execute(); })
+ hostdb_command.add_command("status", "Get HostDB info", "",
MORE_THAN_ZERO_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl hostdb status");
// plugin command
plugin_command
- .add_command("msg", "Send message to plugins - a TAG and the message
DATA(optional)", "", MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); })
+ .add_command("msg", "Send message to plugins - a TAG and the message
DATA(optional)", "", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("traffic_ctl plugin msg TAG DATA");
// server commands
server_command.add_command("backtrace", "Show a full stack trace of the
traffic_server process",
[&]() { CtrlUnimplementedCommand("backtrace"); });
- server_command.add_command("status", "Show the proxy status", [&]() {
command->execute(); })
- .add_example_usage("traffic_ctl server status");
- server_command.add_command("drain", "Drain the requests", [&]() {
command->execute(); })
+ server_command.add_command("status", "Show the proxy status",
Command_Execute).add_example_usage("traffic_ctl server status");
+ server_command.add_command("drain", "Drain the requests", Command_Execute)
.add_example_usage("traffic_ctl server drain [OPTIONS]")
.add_option("--no-new-connection", "-N", "Wait for new connections down to
threshold before starting draining")
.add_option("--undo", "-U", "Recover server from the drain mode");
auto &debug_command =
server_command.add_command("debug", "Enable/Disable ATS for diagnostic
messages at runtime").require_commands();
- debug_command.add_command("enable", "Enables logging for diagnostic messages
at runtime", [&]() { command->execute(); })
+ debug_command.add_command("enable", "Enables logging for diagnostic messages
at runtime", Command_Execute)
.add_option("--tags", "-t", "Debug tags", "TS_DEBUG_TAGS", 1)
.add_option("--client_ip", "-c", "Client's ip", "", 1, "")
.add_example_usage("traffic_ctl server debug enable -t my_tags -c
X.X.X.X");
- debug_command.add_command("disable", "Disables logging for diagnostic
messages at runtime", [&]() { command->execute(); })
+ debug_command.add_command("disable", "Disables logging for diagnostic
messages at runtime", Command_Execute)
.add_example_usage("traffic_ctl server debug disable");
// storage commands
- storage_command
- .add_command("offline", "Take one or more storage volumes offline", "",
MORE_THAN_ONE_ARG_N, [&]() { command->execute(); })
+ storage_command.add_command("offline", "Take one or more storage volumes
offline", "", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_example_usage("storage offline DEVICE [DEVICE ...]");
storage_command.add_command("status", "Show the storage configuration", "",
MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); }); // not
implemented
+ Command_Execute); // not implemented
// direct rpc commands, handy for debug and trouble shooting
direct_rpc_command
.add_command("file", "Send direct JSONRPC request to the server from a
passed file(s)", "", MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); })
+ Command_Execute)
.add_example_usage("traffic_ctl rpc file request.yaml");
- direct_rpc_command.add_command("get-api", "Request full API from server",
"", 0, [&]() { command->execute(); })
+ direct_rpc_command.add_command("get-api", "Request full API from server",
"", 0, Command_Execute)
.add_example_usage("traffic_ctl rpc get-api");
- direct_rpc_command
- .add_command("input", "Read from standard input. Ctrl-D to send the
request", "", 0, [&]() { command->execute(); })
+ direct_rpc_command.add_command("input", "Read from standard input. Ctrl-D to
send the request", "", 0, Command_Execute)
.add_option("--raw", "-r",
"No json/yaml parse validation will take place, the raw
content will be directly send to the server.", "", 0, "",
"raw")
.add_example_usage("traffic_ctl rpc input ");
direct_rpc_command
- .add_command("invoke", "Call a method by using the method name as input
parameter", "", MORE_THAN_ONE_ARG_N,
- [&]() { command->execute(); })
+ .add_command("invoke", "Call a method by using the method name as input
parameter", "", MORE_THAN_ONE_ARG_N, Command_Execute)
.add_option("--params", "-p", "Parameters to be passed in the request,
YAML or JSON format", "", MORE_THAN_ONE_ARG_N, "", "")
.add_example_usage("traffic_ctl rpc invoke foo_bar -p \"numbers: [1, 2,
3]\"");
+ auto create_command = [](ts::Arguments &args) ->
std::unique_ptr<CtrlCommand> {
+ if (args.get("config")) {
+ if (args.get("cold")) {
+ return std::make_unique<FileConfigCommand>(&args);
+ }
+ return std::make_unique<ConfigCommand>(&args);
+ }
+
+ static const std::map<std::string,
std::function<std::unique_ptr<CtrlCommand>(ts::Arguments *)>> factories = {
+ {"metric", [](ts::Arguments *a) { return
std::make_unique<MetricCommand>(a); } },
+ {"server", [](ts::Arguments *a) { return
std::make_unique<ServerCommand>(a); } },
+ {"storage", [](ts::Arguments *a) { return
std::make_unique<StorageCommand>(a); } },
+ {"plugin", [](ts::Arguments *a) { return
std::make_unique<PluginCommand>(a); } },
+ {"host", [](ts::Arguments *a) { return
std::make_unique<HostCommand>(a); } },
+ {"hostdb", [](ts::Arguments *a) { return
std::make_unique<HostDBCommand>(a); } },
+ {"rpc", [](ts::Arguments *a) { return
std::make_unique<DirectRPCCommand>(a); }},
+ };
+
+ for (const auto &[key, factory] : factories) {
+ if (args.get(key)) {
+ return factory(&args);
+ }
+ }
+ return nullptr;
+ };
+
try {
// for now we only care about SIGINT(SIGQUIT, ... ?)
signal_register_handler(SIGINT, handle_signal);
@@ -223,27 +249,8 @@ main([[maybe_unused]] int argc, const char **argv)
argparser_runroot_handler(args.get("run-root").value(), argv[0]);
Layout::create();
- if (args.get("config")) {
- if (args.get("cold")) {
- // We allow to just change a config file
- command = std::make_shared<FileConfigCommand>(&args);
- } else {
- command = std::make_shared<ConfigCommand>(&args);
- }
- } else if (args.get("metric")) {
- command = std::make_shared<MetricCommand>(&args);
- } else if (args.get("server")) {
- command = std::make_shared<ServerCommand>(&args);
- } else if (args.get("storage")) {
- command = std::make_shared<StorageCommand>(&args);
- } else if (args.get("plugin")) {
- command = std::make_shared<PluginCommand>(&args);
- } else if (args.get("host")) {
- command = std::make_shared<HostCommand>(&args);
- } else if (args.get("hostdb")) {
- command = std::make_shared<HostDBCommand>(&args);
- } else if (args.get("rpc")) {
- command = std::make_shared<DirectRPCCommand>(&args);
+ if (command = create_command(args); !command) {
+ throw std::runtime_error("No valid command provided");
}
// Execute
args.invoke();