This is an automated email from the ASF dual-hosted git repository.
amc 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 e137c7d traffic_ctl: Refactor and convert traffic_ctl to use ArgParser
e137c7d is described below
commit e137c7d3941be638701a2a2b9427a3a2f9424be1
Author: Xavier Chi <[email protected]>
AuthorDate: Tue Nov 13 14:28:38 2018 -0600
traffic_ctl: Refactor and convert traffic_ctl to use ArgParser
---
include/tscore/runroot.h | 2 +-
src/traffic_ctl/alarm.cc | 67 +++---------
src/traffic_ctl/config.cc | 243 ++++++++++++++---------------------------
src/traffic_ctl/host.cc | 113 ++++++-------------
src/traffic_ctl/metric.cc | 83 +++++---------
src/traffic_ctl/plugin.cc | 28 ++---
src/traffic_ctl/server.cc | 151 ++++++-------------------
src/traffic_ctl/storage.cc | 31 ++----
src/traffic_ctl/traffic_ctl.cc | 231 ++++++++++++++++++++-------------------
src/traffic_ctl/traffic_ctl.h | 123 +++++++++++----------
10 files changed, 399 insertions(+), 673 deletions(-)
diff --git a/include/tscore/runroot.h b/include/tscore/runroot.h
index 0f2efa1..5d1b607 100644
--- a/include/tscore/runroot.h
+++ b/include/tscore/runroot.h
@@ -55,7 +55,7 @@ bool exists(const std::string &dir);
bool is_directory(const std::string &directory);
// argparser_runroot_handler should replace runroot_handler below when all
program use ArgParser.
-void argparser_runroot_handler(std::string const &value, const char
*executable, bool json);
+void argparser_runroot_handler(std::string const &value, const char
*executable, bool json = false);
void runroot_handler(const char **argv, bool json = false);
// get a map from default layout
diff --git a/src/traffic_ctl/alarm.cc b/src/traffic_ctl/alarm.cc
index d3229f3..d8df03a 100644
--- a/src/traffic_ctl/alarm.cc
+++ b/src/traffic_ctl/alarm.cc
@@ -41,46 +41,38 @@ struct AlarmListPolicy {
using CtrlAlarmList = CtrlMgmtList<AlarmListPolicy>;
-static int
-alarm_list(unsigned argc, const char **argv)
+void
+CtrlEngine::alarm_list()
{
TSMgmtError error;
CtrlAlarmList alarms;
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("alarm list", nullptr, 0);
- }
-
error = TSActiveEventGetMlt(alarms.list);
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to fetch active alarms");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
while (!alarms.empty()) {
char *a = alarms.next();
- printf("%s\n", a);
+ std::cout << a << std::endl;
TSfree(a);
}
-
- return CTRL_EX_OK;
}
-static int
-alarm_clear(unsigned argc, const char **argv)
+void
+CtrlEngine::alarm_clear()
{
TSMgmtError error;
CtrlAlarmList alarms;
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("alarm clear", nullptr, 0);
- }
-
// First get the active alarms ...
error = TSActiveEventGetMlt(alarms.list);
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to fetch active alarms");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
// Now resolve them all ...
@@ -91,49 +83,26 @@ alarm_clear(unsigned argc, const char **argv)
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to resolve %s", a);
TSfree(a);
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
TSfree(a);
}
-
- return CTRL_EX_OK;
}
-static int
-alarm_resolve(unsigned argc, const char **argv)
+void
+CtrlEngine::alarm_resolve()
{
TSMgmtError error;
CtrlAlarmList alarms;
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments == 0) {
- return CtrlCommandUsage("alarm resolve ALARM [ALARM ...]", nullptr, 0);
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
- error = TSEventResolve(file_arguments[i]);
+ for (const auto &it : arguments.get("resolve")) {
+ error = TSEventResolve(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to resolve %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to resolve %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_alarm(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {alarm_clear, "clear", "Clear all current alarms"},
- {alarm_list, "list", "List all current alarms"},
-
- // Note that we separate resolve one from resolve all for the same reasons
that
- // we have "metric zero" and "metric clear".
- {alarm_resolve, "resolve", "Resolve the listed alarms"},
- /* XXX describe a specific alarm? */
- /* XXX raise an alarm? */
- };
-
- return CtrlGenericSubcommand("alarm", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/config.cc b/src/traffic_ctl/config.cc
index 35c7303..378fb47 100644
--- a/src/traffic_ctl/config.cc
+++ b/src/traffic_ctl/config.cc
@@ -181,179 +181,143 @@ format_record(const CtrlMgmtRecord &record, bool recfmt)
CtrlMgmtRecordValue value(record);
if (recfmt) {
- printf("%s %s %s %s\n", rec_labelof(record.rclass()), record.name(),
rec_typeof(record.type()), value.c_str());
+ std::cout << rec_labelof(record.rclass()) << ' ' << record.name() << ' '
<< rec_typeof(record.type()) << ' ' << value.c_str()
+ << std::endl;
} else {
- printf("%s: %s\n", record.name(), value.c_str());
+ std::cout << record.name() << ": " << value.c_str() << std::endl;
}
}
-static int
-config_get(unsigned argc, const char **argv)
+void
+CtrlEngine::config_get()
{
- int recfmt = 0;
- const ArgumentDescription opts[] = {
- {"records", '-', "Emit output in records.config format", "F", &recfmt,
nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments < 1) {
- return CtrlCommandUsage("config get [OPTIONS] RECORD [RECORD ...]", opts,
countof(opts));
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("get")) {
CtrlMgmtRecord record;
TSMgmtError error;
- error = record.fetch(file_arguments[i]);
+ error = record.fetch(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to fetch %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
if (REC_TYPE_IS_CONFIG(record.rclass())) {
- format_record(record, recfmt);
+ format_record(record, arguments.get("records"));
}
}
-
- return CTRL_EX_OK;
}
-static int
-config_describe(unsigned argc, const char **argv)
+void
+CtrlEngine::config_describe()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
- return CtrlCommandUsage("config describe RECORD [RECORD ...]");
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("describe")) {
TSConfigRecordDescription desc;
TSMgmtError error;
ink_zero(desc);
- error = TSConfigRecordDescribe(file_arguments[i], 0 /* flags */, &desc);
+ error = TSConfigRecordDescribe(it.c_str(), 0 /* flags */, &desc);
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to describe %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to describe %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
- printf("%-16s: %s\n", "Name", desc.rec_name);
- printf("%-16s: %s\n", "Current Value", CtrlMgmtRecordValue(desc.rec_type,
desc.rec_value).c_str());
- printf("%-16s: %s\n", "Default Value", CtrlMgmtRecordValue(desc.rec_type,
desc.rec_default).c_str());
- printf("%-16s: %s\n", "Record Type", rec_classof(desc.rec_class));
- printf("%-16s: %s\n", "Data Type", rec_typeof(desc.rec_type));
- printf("%-16s: %s\n", "Access Control ", rec_accessof(desc.rec_access));
- printf("%-16s: %s\n", "Update Type", rec_updateof(desc.rec_updatetype));
- printf("%-16s: 0x%" PRIx64 "\n", "Update Status", desc.rec_update);
- printf("%-16s: %s\n", "Source", rec_sourceof(desc.rec_source));
+ std::cout << "Name: " << desc.rec_name << std::endl;
+ std::cout << "Current Value: " << CtrlMgmtRecordValue(desc.rec_type,
desc.rec_value).c_str() << std::endl;
+ std::cout << "Default Value: " << CtrlMgmtRecordValue(desc.rec_type,
desc.rec_default).c_str() << std::endl;
+ std::cout << "Record Type: " << rec_classof(desc.rec_class) << std::endl;
+ std::cout << "Data Type: " << rec_typeof(desc.rec_type) << std::endl;
+ std::cout << "Access Control: " << rec_accessof(desc.rec_access) <<
std::endl;
+ std::cout << "Update Type: " << rec_updateof(desc.rec_updatetype) <<
std::endl;
+ std::cout << "Update Status: " << desc.rec_update << std::endl;
+ std::cout << "Source: " << rec_sourceof(desc.rec_source) << std::endl;
if (strlen(desc.rec_checkexpr)) {
- printf("%-16s: %s, '%s'\n", "Syntax Check",
rec_checkof(desc.rec_checktype), desc.rec_checkexpr);
+ std::cout << "Syntax Check: " << rec_checkof(desc.rec_checktype) <<
desc.rec_checkexpr << std::endl;
} else {
- printf("%-16s: %s\n", "Syntax Check", rec_checkof(desc.rec_checktype));
+ std::cout << "Syntax Check: " << rec_checkof(desc.rec_checktype) <<
std::endl;
}
-
- printf("%-16s: %" PRId64 "\n", "Version", desc.rec_version);
- printf("%-16s: %" PRId64 "\n", "Order", desc.rec_order);
- printf("%-16s: %" PRId64 "\n", "Raw Stat Block", desc.rec_rsb);
+ std::cout << "Version: " << desc.rec_version << std::endl;
+ std::cout << "Order: " << desc.rec_order << std::endl;
+ std::cout << "Raw Stat Block: " << desc.rec_rsb << std::endl;
TSConfigRecordDescriptionFree(&desc);
}
-
- return CTRL_EX_OK;
}
-static int
-config_set(unsigned argc, const char **argv)
+void
+CtrlEngine::config_set()
{
TSMgmtError error;
TSActionNeedT action;
-
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 2) {
- return CtrlCommandUsage("config set RECORD VALUE");
- }
-
- error = TSRecordSet(file_arguments[0], file_arguments[1], &action);
+ auto set_data = arguments.get("set");
+ const char *rec_name = set_data[0].c_str();
+ const char *rec_val = set_data[1].c_str();
+ error = TSRecordSet(rec_name, rec_val, &action);
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to set %s", file_arguments[0]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to set %s", rec_name);
+ status_code = CTRL_EX_ERROR;
+ return;
}
switch (action) {
case TS_ACTION_SHUTDOWN:
- printf("set %s, full shutdown required\n", file_arguments[0]);
+ std::cout << "set " << rec_name << ", full shutdown required" << std::endl;
break;
case TS_ACTION_RESTART:
- printf("set %s, restart required\n", file_arguments[0]);
+ std::cout << "set " << rec_name << ", restart required" << std::endl;
break;
case TS_ACTION_RECONFIGURE:
- printf("set %s, please wait 10 seconds for traffic server to sync
configuration, restart is not required\n", file_arguments[0]);
+ std::cout << "set " << rec_name << ", please wait 10 seconds for traffic
server to sync configuration, restart is not required"
+ << std::endl;
break;
case TS_ACTION_DYNAMIC:
default:
- printf("set %s\n", file_arguments[0]);
+ printf("set %s\n", rec_name);
break;
}
-
- return CTRL_EX_OK;
}
-static int
-config_match(unsigned argc, const char **argv)
+void
+CtrlEngine::config_match()
{
- int recfmt = 0;
- const ArgumentDescription opts[] = {
- {"records", '-', "Emit output in records.config format", "F", &recfmt,
nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments < 1) {
- return CtrlCommandUsage("config match [OPTIONS] REGEX [REGEX ...]", opts,
countof(opts));
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("match")) {
CtrlMgmtRecordList reclist;
TSMgmtError error;
// XXX filter the results to only match configuration records.
- error = reclist.match(file_arguments[i]);
+ error = reclist.match(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to fetch %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
while (!reclist.empty()) {
CtrlMgmtRecord record(reclist.next());
if (REC_TYPE_IS_CONFIG(record.rclass())) {
- format_record(record, recfmt);
+ format_record(record, arguments.get("records"));
}
}
}
-
- return CTRL_EX_OK;
}
-static int
-config_reload(unsigned argc, const char **argv)
+void
+CtrlEngine::config_reload()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("config reload");
- }
-
TSMgmtError error = TSReconfigure();
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "configuration reload request failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
}
-static int
-config_status(unsigned argc, const char **argv)
+void
+CtrlEngine::config_status()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("config status");
- }
-
CtrlMgmtRecord version;
CtrlMgmtRecord configtime;
CtrlMgmtRecord starttime;
@@ -368,77 +332,57 @@ config_status(unsigned argc, const char **argv)
CTRL_MGMT_CHECK(proxy.fetch("proxy.node.config.restart_required.proxy"));
CTRL_MGMT_CHECK(manager.fetch("proxy.node.config.restart_required.manager"));
- printf("%s\n", CtrlMgmtRecordValue(version).c_str());
- printf("Started at %s", timestr((time_t)starttime.as_int()).c_str());
- printf("Last reconfiguration at %s",
timestr((time_t)configtime.as_int()).c_str());
- printf("%s\n", reconfig.as_int() ? "Reconfiguration required" :
"Configuration is current");
+ std::cout << CtrlMgmtRecordValue(version).c_str() << std::endl;
+ std::cout << "Started at " << timestr((time_t)starttime.as_int()).c_str();
+ std::cout << "Last reconfiguration at " <<
timestr((time_t)configtime.as_int()).c_str();
+ std::cout << (reconfig.as_int() ? "Reconfiguration required" :
"Configuration is current") << std::endl;
if (proxy.as_int()) {
- printf("traffic_server requires restarting\n");
+ std::cout << "traffic_server requires restarting" << std::endl;
}
if (manager.as_int()) {
- printf("traffic_manager requires restarting\n");
+ std::cout << "traffic_manager requires restarting\n" << std::endl;
}
-
- return CTRL_EX_OK;
}
-static int
-config_defaults(unsigned argc, const char **argv)
+void
+CtrlEngine::config_defaults()
{
- int recfmt = 0;
- const ArgumentDescription opts[] = {
- {"records", '-', "Emit output in records.config format", "F", &recfmt,
nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage("config diff [OPTIONS]");
- }
-
TSMgmtError error;
CtrlMgmtRecordDescriptionList descriptions;
error = descriptions.match(".*");
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to fetch record metadata");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
while (!descriptions.empty()) {
TSConfigRecordDescription *desc = descriptions.next();
CtrlMgmtRecordValue deflt(desc->rec_type, desc->rec_default);
- if (recfmt) {
- printf("%s %s %s %s\n", rec_labelof(desc->rec_class), desc->rec_name,
rec_typeof(desc->rec_type), deflt.c_str());
+ if (arguments.get("records")) {
+ std::cout << rec_labelof(desc->rec_class) << ' ' << desc->rec_name << '
' << rec_typeof(desc->rec_type) << ' '
+ << deflt.c_str() << std::endl;
} else {
- printf("%s: %s\n", desc->rec_name, deflt.c_str());
+ std::cout << desc->rec_name << ": " << deflt.c_str() << std::endl;
}
-
TSConfigRecordDescriptionDestroy(desc);
}
-
- return CTRL_EX_OK;
}
-static int
-config_diff(unsigned argc, const char **argv)
+void
+CtrlEngine::config_diff()
{
- int recfmt = 0;
- const ArgumentDescription opts[] = {
- {"records", '-', "Emit output in records.config format", "F", &recfmt,
nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage("config diff [OPTIONS]");
- }
-
TSMgmtError error;
CtrlMgmtRecordDescriptionList descriptions;
error = descriptions.match(".*");
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to fetch record metadata");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
while (!descriptions.empty()) {
@@ -468,35 +412,16 @@ config_diff(unsigned argc, const char **argv)
CtrlMgmtRecordValue current(desc->rec_type, desc->rec_value);
CtrlMgmtRecordValue deflt(desc->rec_type, desc->rec_default);
- if (recfmt) {
- printf("%s %s %s %s # default: %s\n", rec_labelof(desc->rec_class),
desc->rec_name, rec_typeof(desc->rec_type),
- current.c_str(), deflt.c_str());
+ if (arguments.get("records")) {
+ std::cout << rec_labelof(desc->rec_class) << ' ' << desc->rec_name <<
' ' << rec_typeof(desc->rec_type) << ' '
+ << current.c_str() << " # default: " << deflt.c_str() <<
std::endl;
} else {
- printf("%s has changed\n", desc->rec_name);
- printf("\t%-16s: %s\n", "Current Value", current.c_str());
- printf("\t%-16s: %s\n", "Default Value", deflt.c_str());
+ std::cout << desc->rec_name << "has changed" << std::endl;
+ std::cout << "\tCurrent Value: " << current.c_str() << std::endl;
+ std::cout << "\tDefault Value: " << deflt.c_str() << std::endl;
}
}
TSConfigRecordDescriptionDestroy(desc);
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_config(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {config_defaults, "defaults", "Show default information configuration
values"},
- {config_describe, "describe", "Show detailed information about
configuration values"},
- {config_diff, "diff", "Show non-default configuration values"},
- {config_get, "get", "Get one or more configuration values"},
- {config_match, "match", "Get configuration matching a regular expression"},
- {config_reload, "reload", "Request a configuration reload"},
- {config_set, "set", "Set a configuration value"},
- {config_status, "status", "Check the configuration status"},
- };
-
- return CtrlGenericSubcommand("config", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/host.cc b/src/traffic_ctl/host.cc
index 1c69fa3..2b23bc9 100644
--- a/src/traffic_ctl/host.cc
+++ b/src/traffic_ctl/host.cc
@@ -25,121 +25,78 @@
#include "HostStatus.h"
#include "records/P_RecUtils.h"
-static int
-status_get(unsigned argc, const char **argv)
+void
+CtrlEngine::status_get()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
- return CtrlCommandUsage("host status HOST [HOST ...]", nullptr, 0);
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("status")) {
CtrlMgmtRecord record;
TSMgmtError error;
- std::string str = stat_prefix + file_arguments[i];
+ std::string str = stat_prefix + it;
for (const char *_reason_tag : Reasons::reasons) {
std::string _stat = str + "_" + _reason_tag;
error = record.fetch(_stat.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to fetch %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
if (REC_TYPE_IS_STAT(record.rclass())) {
- printf("%s %s\n", record.name(), CtrlMgmtRecordValue(record).c_str());
+ std::cout << record.name() << ' ' <<
CtrlMgmtRecordValue(record).c_str() << std::endl;
}
}
}
-
- return CTRL_EX_OK;
}
-static int
-status_down(unsigned argc, const char **argv)
+void
+CtrlEngine::status_down()
{
- int down_time = 0;
- char *reason = nullptr;
- const char *usage = "host down HOST [OPTIONS]";
-
- const ArgumentDescription opts[] = {
- {"time", 'I', "number of seconds that a host is marked down", "I",
&down_time, nullptr, nullptr},
- // memory is allocated for 'reason', if this option is used
- {"reason", '-', "reason for marking the host down, one of
'manual|active|local'", "S*", &reason, nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments < 1) {
- return CtrlCommandUsage(usage, opts, countof(opts));
- }
+ int down_time = 0;
+ std::string reason = arguments.get("reason").value();
// if reason is not set, set it to manual (default)
- if (reason == nullptr) {
- reason = ats_strdup(Reasons::MANUAL);
+ if (reason.empty()) {
+ reason = Reasons::MANUAL;
}
- if (!Reasons::validReason(reason)) {
- fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason);
- return CtrlCommandUsage(usage, opts, countof(opts));
+ if (!Reasons::validReason(reason.c_str())) {
+ fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason.c_str());
+ parser.help_message();
}
TSMgmtError error = TS_ERR_OKAY;
- for (unsigned i = 0; i < n_file_arguments; ++i) {
- error = TSHostStatusSetDown(file_arguments[i], down_time, reason);
+ for (const auto &it : arguments.get("down")) {
+ error = TSHostStatusSetDown(it.c_str(), down_time, reason.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to set %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to set %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
}
- ats_free(reason);
-
- return CTRL_EX_OK;
}
-static int
-status_up(unsigned argc, const char **argv)
+void
+CtrlEngine::status_up()
{
- char *reason = nullptr;
- const char *usage = "host up HOST [OPTIONS]";
-
- const ArgumentDescription opts[] = {
- // memory is allocated for 'reason', if this option is used
- {"reason", '-', "reason for marking the host up, one of
'manual|active|local'", "S*", &reason, nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments < 1) {
- return CtrlCommandUsage(usage, nullptr, 0);
- }
+ std::string reason = arguments.get("reason").value();
// if reason is not set, set it to manual (default)
- if (reason == nullptr) {
- reason = ats_strdup(Reasons::MANUAL);
+ if (reason.empty()) {
+ reason = Reasons::MANUAL;
}
- if (!Reasons::validReason(reason)) {
- fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason);
- return CtrlCommandUsage(usage, opts, countof(opts));
+ if (!Reasons::validReason(reason.c_str())) {
+ fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason.c_str());
+ parser.help_message();
}
TSMgmtError error;
- for (unsigned i = 0; i < n_file_arguments; ++i) {
- error = TSHostStatusSetUp(file_arguments[i], 0, reason);
+ for (const auto &it : arguments.get("up")) {
+ error = TSHostStatusSetUp(it.c_str(), 0, reason.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to set %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to set %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
}
- ats_free(reason);
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_host(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {status_get, "status", "Get one or more host statuses"},
- {status_down, "down", "Set down one or more host(s) "},
- {status_up, "up", "Set up one or more host(s) "},
-
- };
-
- return CtrlGenericSubcommand("host", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/metric.cc b/src/traffic_ctl/metric.cc
index 68796b5..1076ace 100644
--- a/src/traffic_ctl/metric.cc
+++ b/src/traffic_ctl/metric.cc
@@ -24,103 +24,72 @@
#include "traffic_ctl.h"
#include "records/P_RecUtils.h"
-static int
-metric_get(unsigned argc, const char **argv)
+void
+CtrlEngine::metric_get()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
- return CtrlCommandUsage("metric get METRIC [METRIC ...]", nullptr, 0);
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("get")) {
CtrlMgmtRecord record;
TSMgmtError error;
- error = record.fetch(file_arguments[i]);
+ error = record.fetch(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to fetch %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
if (REC_TYPE_IS_STAT(record.rclass())) {
- printf("%s %s\n", record.name(), CtrlMgmtRecordValue(record).c_str());
+ std::cout << record.name() << ' ' << CtrlMgmtRecordValue(record).c_str()
<< std::endl;
}
}
-
- return CTRL_EX_OK;
}
-static int
-metric_match(unsigned argc, const char **argv)
+void
+CtrlEngine::metric_match()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
- return CtrlCommandUsage("metric match [OPTIONS] REGEX [REGEX ...]",
nullptr, 0);
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ for (const auto &it : arguments.get("match")) {
CtrlMgmtRecordList reclist;
TSMgmtError error;
- error = reclist.match(file_arguments[i]);
+ error = reclist.match(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to fetch %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
while (!reclist.empty()) {
CtrlMgmtRecord record(reclist.next());
if (REC_TYPE_IS_STAT(record.rclass())) {
- printf("%s %s\n", record.name(), CtrlMgmtRecordValue(record).c_str());
+ std::cout << record.name() << ' ' <<
CtrlMgmtRecordValue(record).c_str() << std::endl;
}
}
}
-
- return CTRL_EX_OK;
}
-static int
-metric_clear(unsigned argc, const char **argv)
+void
+CtrlEngine::metric_clear()
{
TSMgmtError error;
error = TSStatsReset(nullptr);
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "failed to clear metrics");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
}
-static int
-metric_zero(unsigned argc, const char **argv)
+void
+CtrlEngine::metric_zero()
{
TSMgmtError error;
- for (unsigned i = 0; i < n_file_arguments; ++i) {
- error = TSStatsReset(file_arguments[i]);
+ for (const auto &it : arguments.get("zero")) {
+ error = TSStatsReset(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to clear %s", file_arguments[i]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to clear %s", it.c_str());
+ status_code = CTRL_EX_ERROR;
}
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_metric(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {metric_get, "get", "Get one or more metric values"},
- {metric_clear, "clear", "Clear all metric values"},
- {CtrlUnimplementedCommand, "describe", "Show detailed information about
one or more metric values"},
- {metric_match, "match", "Get metrics matching a regular expression"},
- {CtrlUnimplementedCommand, "monitor", "Display the value of a metric over
time"},
-
- // We could allow clearing all the metrics in the "clear" subcommand, but
that seems error-prone. It
- // would be too easy to just expect a help message and accidentally nuke
all the metrics.
- {metric_zero, "zero", "Clear one or more metric values"},
- };
-
- return CtrlGenericSubcommand("metric", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/plugin.cc b/src/traffic_ctl/plugin.cc
index cec12fa..8935ee7 100644
--- a/src/traffic_ctl/plugin.cc
+++ b/src/traffic_ctl/plugin.cc
@@ -23,30 +23,16 @@
#include "traffic_ctl.h"
-static int
-plugin_msg(unsigned argc, const char **argv)
+void
+CtrlEngine::plugin_msg()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 2) {
- return CtrlCommandUsage("plugin msg TAG DATA");
- }
-
TSMgmtError error;
+ auto msg_data = arguments.get("msg");
- error = TSLifecycleMessage(file_arguments[0], file_arguments[1],
strlen(file_arguments[1]) + 1);
+ error = TSLifecycleMessage(msg_data[0].c_str(), msg_data[1].c_str(),
msg_data[1].size() + 1);
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "message '%s' not sent", file_arguments[0]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "message '%s' not sent", msg_data[0].c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_plugin(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {plugin_msg, "msg", "Send message to plugins - a TAG and the message
DATA"},
- };
-
- return CtrlGenericSubcommand("plugin", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/server.cc b/src/traffic_ctl/server.cc
index d41064f..58271ba 100644
--- a/src/traffic_ctl/server.cc
+++ b/src/traffic_ctl/server.cc
@@ -23,30 +23,17 @@
#include "traffic_ctl.h"
-static int drain = 0;
-static int manager = 0;
-
-static int
-restart(unsigned argc, const char **argv)
+void
+CtrlEngine::server_restart()
{
TSMgmtError error;
- const char *usage = "server restart [OPTIONS]";
- unsigned flags = TS_RESTART_OPT_NONE;
-
- const ArgumentDescription opts[] = {
- {"drain", '-', "Wait for client connections to drain before restarting",
"F", &drain, nullptr, nullptr},
- {"manager", '-', "Restart traffic_manager as well as traffic_server", "F",
&manager, nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage(usage, opts, countof(opts));
- }
+ unsigned flags = TS_RESTART_OPT_NONE;
- if (drain) {
+ if (arguments.get("drain")) {
flags |= TS_RESTART_OPT_DRAIN;
}
- if (manager) {
+ if (arguments.get("manager")) {
error = TSRestart(flags);
} else {
error = TSBounce(flags);
@@ -54,79 +41,51 @@ restart(unsigned argc, const char **argv)
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "server restart failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
-}
-
-static int
-server_restart(unsigned argc, const char **argv)
-{
- return restart(argc, argv);
}
-static int
-server_backtrace(unsigned argc, const char **argv)
+void
+CtrlEngine::server_backtrace()
{
TSMgmtError error;
TSString trace = nullptr;
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("server backtrace");
- }
-
error = TSProxyBacktraceGet(0, &trace);
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "server backtrace failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
- printf("%s\n", trace);
+ std::cout << trace << std::endl;
TSfree(trace);
- return CTRL_EX_OK;
}
-static int
-server_status(unsigned argc, const char **argv)
+void
+CtrlEngine::server_status()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments != 0) {
- return CtrlCommandUsage("server status");
- }
-
switch (TSProxyStateGet()) {
case TS_PROXY_ON:
- printf("Proxy -- on\n");
+ std::cout << "Proxy -- on" << std::endl;
break;
case TS_PROXY_OFF:
- printf("Proxy -- off\n");
+ std::cout << "Proxy -- off" << std::endl;
break;
case TS_PROXY_UNDEFINED:
- printf("Proxy status undefined\n");
+ std::cout << "Proxy status undefined" << std::endl;
break;
}
-
- // XXX Surely we can report more useful status that this !?!!
-
- return CTRL_EX_OK;
}
-static int
-server_stop(unsigned argc, const char **argv)
+void
+CtrlEngine::server_stop()
{
TSMgmtError error;
- const char *usage = "server stop [OPTIONS]";
- unsigned flags = TS_RESTART_OPT_NONE;
+ unsigned flags = TS_RESTART_OPT_NONE;
- const ArgumentDescription opts[] = {
- {"drain", '-', "Wait for client connections to drain before stopping",
"F", &drain, nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage(usage, opts, countof(opts));
- }
-
- if (drain) {
+ if (arguments.get("drain")) {
flags |= TS_STOP_OPT_DRAIN;
}
@@ -134,62 +93,36 @@ server_stop(unsigned argc, const char **argv)
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "server stop failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
}
-static int
-server_start(unsigned argc, const char **argv)
+void
+CtrlEngine::server_start()
{
TSMgmtError error;
- int cache = 0;
- int hostdb = 0;
unsigned clear = TS_CACHE_CLEAR_NONE;
- const ArgumentDescription opts[] = {
- {"clear-cache", '-', "Clear the disk cache on startup", "F", &cache,
nullptr, nullptr},
- {"clear-hostdb", '-', "Clear the DNS cache on startup", "F", &hostdb,
nullptr, nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage("server start [OPTIONS]", opts, countof(opts));
- }
-
- clear |= cache ? TS_CACHE_CLEAR_CACHE : TS_CACHE_CLEAR_NONE;
- clear |= hostdb ? TS_CACHE_CLEAR_HOSTDB : TS_CACHE_CLEAR_NONE;
+ clear |= arguments.get("clear-cache") ? TS_CACHE_CLEAR_CACHE :
TS_CACHE_CLEAR_NONE;
+ clear |= arguments.get("clear-hostdb") ? TS_CACHE_CLEAR_HOSTDB :
TS_CACHE_CLEAR_NONE;
error = TSProxyStateSet(TS_PROXY_ON, clear);
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "server start failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
}
-static int
-server_drain(unsigned argc, const char **argv)
+void
+CtrlEngine::server_drain()
{
TSMgmtError error;
- const char *usage = "server drain [OPTIONS]";
-
- int no_new_connection = 0;
- int undo = 0;
- const ArgumentDescription opts[] = {
- {"no-new-connection", 'N', "Wait for new connections down to threshold
before starting draining", "F", &no_new_connection,
- nullptr, nullptr},
- {"undo", 'U', "Recover server from the drain mode", "F", &undo, nullptr,
nullptr},
- };
-
- if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) ||
n_file_arguments != 0) {
- return CtrlCommandUsage(usage, opts, countof(opts));
- }
- if (undo) {
+ if (arguments.get("undo")) {
error = TSDrain(TS_DRAIN_OPT_UNDO);
- } else if (no_new_connection) {
+ } else if (arguments.get("no-new-connection")) {
error = TSDrain(TS_DRAIN_OPT_IDLE);
} else {
error = TSDrain(TS_DRAIN_OPT_NONE);
@@ -197,21 +130,7 @@ server_drain(unsigned argc, const char **argv)
if (error != TS_ERR_OKAY) {
CtrlMgmtError(error, "server drain failed");
- return CTRL_EX_ERROR;
+ status_code = CTRL_EX_ERROR;
+ return;
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_server(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {{server_backtrace, "backtrace", "Show a full
stack trace of the traffic_server process"},
- {server_restart, "restart", "Restart Traffic
Server"},
- {server_start, "start", "Start the proxy"},
- {server_status, "status", "Show the proxy
status"},
- {server_stop, "stop", "Stop the proxy"},
- {server_drain, "drain", "Drain the
requests"}};
-
- return CtrlGenericSubcommand("server", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/storage.cc b/src/traffic_ctl/storage.cc
index ebd9607..1e55bc9 100644
--- a/src/traffic_ctl/storage.cc
+++ b/src/traffic_ctl/storage.cc
@@ -23,33 +23,18 @@
#include "traffic_ctl.h"
-static int
-storage_offline(unsigned argc, const char **argv)
+void
+CtrlEngine::storage_offline()
{
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments == 0) {
- return CtrlCommandUsage("storage offline DEVICE [DEVICE ...]");
- }
-
- for (unsigned i = 0; i < n_file_arguments; ++i) {
+ auto offline_data = arguments.get("offline");
+ for (const auto &it : offline_data) {
TSMgmtError error;
- error = TSStorageDeviceCmdOffline(file_arguments[i]);
+ error = TSStorageDeviceCmdOffline(it.c_str());
if (error != TS_ERR_OKAY) {
- CtrlMgmtError(error, "failed to take %s offline", file_arguments[0]);
- return CTRL_EX_ERROR;
+ CtrlMgmtError(error, "failed to take %s offline",
offline_data[0].c_str());
+ status_code = CTRL_EX_ERROR;
+ return;
}
}
-
- return CTRL_EX_OK;
-}
-
-int
-subcommand_storage(unsigned argc, const char **argv)
-{
- const subcommand commands[] = {
- {storage_offline, "offline", "Take one or more storage volumes offline"},
- {CtrlUnimplementedCommand, "status", "Show the storage configuration"},
- };
-
- return CtrlGenericSubcommand("storage", commands, countof(commands), argc,
argv);
}
diff --git a/src/traffic_ctl/traffic_ctl.cc b/src/traffic_ctl/traffic_ctl.cc
index be61cf0..8efb92a 100644
--- a/src/traffic_ctl/traffic_ctl.cc
+++ b/src/traffic_ctl/traffic_ctl.cc
@@ -28,8 +28,6 @@
#include "tscore/I_Layout.h"
#include "tscore/runroot.h"
-AppVersionInfo CtrlVersionInfo;
-
const char *
CtrlMgmtRecord::name() const
{
@@ -145,120 +143,137 @@ CtrlMgmtError(TSMgmtError err, const char *fmt, ...)
}
}
-int
-CtrlSubcommandUsage(const char *name, const subcommand *cmds, unsigned ncmds,
const ArgumentDescription *desc, unsigned ndesc)
-{
- const char *opt = ndesc ? "[OPTIONS]" : "";
- const char *sep = (ndesc && name) ? " " : "";
-
- fprintf(stderr, "Usage: traffic_ctl %s%s%s CMD [ARGS
...]\n\nSubcommands:\n", name ? name : "", sep, opt);
-
- for (unsigned i = 0; i < ncmds; ++i) {
- fprintf(stderr, " %-16s%s\n", cmds[i].name, cmds[i].help);
- }
-
- if (ndesc) {
- usage(desc, ndesc, "\nOptions:");
- }
-
- return CTRL_EX_USAGE;
-}
-
-int
-CtrlCommandUsage(const char *msg, const ArgumentDescription *desc, unsigned
ndesc)
-{
- fprintf(stderr, "Usage: traffic_ctl %s\n", msg);
-
- if (ndesc) {
- usage(desc, ndesc, "\nOptions:");
- }
-
- return CTRL_EX_USAGE;
-}
-
-bool
-CtrlProcessArguments(int /* argc */, const char **argv, const
ArgumentDescription *desc, unsigned ndesc)
-{
- n_file_arguments = 0;
- return process_args_ex(&CtrlVersionInfo, desc, ndesc, argv);
-}
-
-int
-CtrlUnimplementedCommand(unsigned /* argc */, const char **argv)
+void
+CtrlEngine::CtrlUnimplementedCommand(std::string_view command)
{
- fprintf(stderr, "'%s' command is not implemented\n", *argv);
- return CTRL_EX_UNIMPLEMENTED;
+ fprintf(stderr, "'%s' command is not implemented\n", command.data());
+ status_code = CTRL_EX_UNIMPLEMENTED;
}
int
-CtrlGenericSubcommand(const char *name, const subcommand *cmds, unsigned
ncmds, unsigned argc, const char **argv)
-{
- CtrlCommandLine cmdline;
-
- // Process command line arguments and dump into variables
- if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
- return CtrlSubcommandUsage(name, cmds, ncmds, nullptr, 0);
- }
-
- cmdline.init(n_file_arguments, file_arguments);
-
- for (unsigned i = 0; i < ncmds; ++i) {
- if (strcmp(file_arguments[0], cmds[i].name) == 0) {
- return cmds[i].handler(cmdline.argc(), cmdline.argv());
- }
- }
-
- return CtrlSubcommandUsage(name, cmds, ncmds, nullptr, 0);
-}
-
-static const subcommand commands[] = {
- {subcommand_alarm, "alarm", "Manipulate alarms"},
- {subcommand_config, "config", "Manipulate configuration records"},
- {subcommand_metric, "metric", "Manipulate performance metrics"},
- {subcommand_server, "server", "Stop, restart and examine the server"},
- {subcommand_storage, "storage", "Manipulate cache storage"},
- {subcommand_plugin, "plugin", "Interact with plugins"},
- {subcommand_host, "host", "Interact with host status"},
-};
-
-int
main(int argc, const char **argv)
{
- CtrlCommandLine cmdline;
- int debug = false;
-
- CtrlVersionInfo.setup(PACKAGE_NAME, "traffic_ctl", PACKAGE_VERSION,
__DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, "");
- program_name = CtrlVersionInfo.AppStr;
-
- ArgumentDescription argument_descriptions[] = {
- {"debug", '-', "Enable debugging output", "F", &debug, nullptr, nullptr},
- {"help", 'h', "Print usage information", nullptr, nullptr, nullptr,
- [](const ArgumentDescription *args, unsigned nargs, const char
*arg_unused) {
- CtrlSubcommandUsage(nullptr, commands, countof(commands), args, nargs);
- }},
- VERSION_ARGUMENT_DESCRIPTION(),
- RUNROOT_ARGUMENT_DESCRIPTION(),
- };
+ CtrlEngine engine;
+
+ engine.parser.add_global_usage("traffic_ctl [OPTIONS] CMD [ARGS ...]");
+ engine.parser.require_commands();
+
+ engine.parser.add_option("--debug", "", "Enable debugging output")
+ .add_option("--version", "-V", "Print version string")
+ .add_option("--help", "-h", "Print usage information")
+ .add_option("--run-root", "", "using TS_RUNROOT as sandbox", "TS_RUNROOT",
1);
+
+ auto &alarm_command = engine.parser.add_command("alarm", "Manipulate
alarms").require_commands();
+ auto &config_command = engine.parser.add_command("config", "Manipulate
configuration records").require_commands();
+ auto &metric_command = engine.parser.add_command("metric", "Manipulate
performance metrics").require_commands();
+ auto &server_command = engine.parser.add_command("server", "Stop, restart
and examine the server").require_commands();
+ auto &storage_command = engine.parser.add_command("storage", "Manipulate
cache storage").require_commands();
+ auto &plugin_command = engine.parser.add_command("plugin", "Interact with
plugins").require_commands();
+ auto &host_command = engine.parser.add_command("host", "Interact with
host status").require_commands();
+
+ // alarm commands
+ alarm_command.add_command("clear", "Clear all current alarms", [&]() {
engine.alarm_clear(); })
+ .add_example_usage("traffic_ctl alarm clear");
+ alarm_command.add_command("list", "List all current alarms", [&]() {
engine.alarm_list(); })
+ .add_example_usage("traffic_ctl alarm list");
+ alarm_command.add_command("resolve", "Resolve the listed alarms", "",
MORE_THAN_ONE_ARG_N, [&]() { engine.alarm_resolve(); })
+ .add_example_usage("traffic_ctl alarm resolve ALARM [ALARM ...]");
+
+ // config commands
+ config_command.add_command("defaults", "Show default information
configuration values", [&]() { engine.config_defaults(); })
+ .add_example_usage("traffic_ctl config defaults [OPTIONS]")
+ .add_option("--records", "", "Emit output in records.config format");
+ config_command
+ .add_command("describe", "Show detailed information about configuration
values", "", MORE_THAN_ONE_ARG_N,
+ [&]() { engine.config_describe(); })
+ .add_example_usage("traffic_ctl config describe RECORD [RECORD ...]");
+ config_command.add_command("diff", "Show non-default configuration values",
[&]() { engine.config_diff(); })
+ .add_example_usage("traffic_ctl config diff [OPTIONS]")
+ .add_option("--records", "", "Emit output in records.config format");
+ config_command.add_command("get", "Get one or more configuration values",
"", MORE_THAN_ONE_ARG_N, [&]() { engine.config_get(); })
+ .add_example_usage("traffic_ctl config get [OPTIONS] RECORD [RECORD ...]")
+ .add_option("--records", "", "Emit output in records.config format");
+ config_command
+ .add_command("match", "Get configuration matching a regular expression",
"", MORE_THAN_ONE_ARG_N,
+ [&]() { engine.config_match(); })
+ .add_example_usage("traffic_ctl config match [OPTIONS] REGEX [REGEX ...]")
+ .add_option("--records", "", "Emit output in records.config format");
+ config_command.add_command("reload", "Request a configuration reload", [&]()
{ engine.config_reload(); })
+ .add_example_usage("traffic_ctl config reload");
+ config_command.add_command("status", "Check the configuration status", [&]()
{ engine.config_status(); })
+ .add_example_usage("traffic_ctl config status");
+ config_command.add_command("set", "Set a configuration value", "", 2, [&]()
{ engine.config_set(); })
+ .add_example_usage("traffic_ctl config set RECORD VALUE");
+
+ // host commands
+ host_command.add_command("status", "Get one or more host statuses", "",
MORE_THAN_ONE_ARG_N, [&]() { engine.status_get(); })
+ .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, [&]() { engine.status_down(); })
+ .add_example_usage("traffic_ctl host down HOST [OPTIONS]")
+ .add_option("--time", "-I", "number of seconds that a host is marked
down", "", 1)
+ .add_option("--reason", "", "reason for marking the host down, one of
'manual|active|local");
+ host_command.add_command("up", "Set up one or more host(s)", "",
MORE_THAN_ONE_ARG_N, [&]() { engine.status_up(); })
+ .add_example_usage("traffic_ctl host up METRIC value")
+ .add_option("--reason", "", "reason for marking the host up, one of
'manual|active|local");
+
+ // metric commands
+ metric_command.add_command("get", "Get one or more metric values", "",
MORE_THAN_ONE_ARG_N, [&]() { engine.metric_get(); })
+ .add_example_usage("traffic_ctl metric get METRIC [METRIC ...]");
+ metric_command.add_command("clear", "Clear all metric values", [&]() {
engine.metric_clear(); });
+ metric_command.add_command("describe", "Show detailed information about one
or more metric values", "", MORE_THAN_ONE_ARG_N,
+ [&]() {
engine.CtrlUnimplementedCommand("describe"); }); // not implemented
+ metric_command.add_command("match", "Get metrics matching a regular
expression", "", MORE_THAN_ZERO_ARG_N,
+ [&]() { engine.metric_match(); });
+ metric_command.add_command("monitor", "Display the value of a metric over
time", "", MORE_THAN_ZERO_ARG_N,
+ [&]() {
engine.CtrlUnimplementedCommand("monitor"); }); // not implemented
+ metric_command.add_command("zero", "Clear one or more metric values", "",
MORE_THAN_ONE_ARG_N, [&]() { engine.metric_zero(); });
+
+ // plugin command
+ plugin_command.add_command("msg", "Send message to plugins - a TAG and the
message DATA", "", 2, [&]() { engine.plugin_msg(); })
+ .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",
+ [&]() { engine.server_backtrace(); });
+ server_command.add_command("restart", "Restart Traffic Server", [&]() {
engine.server_backtrace(); })
+ .add_example_usage("traffic_ctl server restart [OPTIONS]")
+ .add_option("--drain", "", "Wait for client connections to drain before
restarting")
+ .add_option("--manager", "", "Restart traffic_manager as well as
traffic_server");
+ server_command.add_command("start", "Start the proxy", [&]() {
engine.server_start(); })
+ .add_example_usage("traffic_ctl server start [OPTIONS]")
+ .add_option("--clear-cache", "", "Clear the disk cache on startup")
+ .add_option("--clear-hostdb", "", "Clear the DNS cache on startup");
+ server_command.add_command("status", "Show the proxy status", [&]() {
engine.server_status(); })
+ .add_example_usage("traffic_ctl server status");
+ server_command.add_command("stop", "Stop the proxy", [&]() {
engine.server_stop(); })
+ .add_example_usage("traffic_ctl server stop [OPTIONS]")
+ .add_option("--drain", "", "Wait for client connections to drain before
stopping");
+ server_command.add_command("drain", "Drain the requests", [&]() {
engine.server_drain(); })
+ .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");
+
+ // storage commands
+ storage_command
+ .add_command("offline", "Take one or more storage volumes offline", "",
MORE_THAN_ONE_ARG_N,
+ [&]() { engine.storage_offline(); })
+ .add_example_usage("storage offline DEVICE [DEVICE ...]");
+ storage_command.add_command("status", "Show the storage configuration", "",
MORE_THAN_ZERO_ARG_N,
+ [&]() {
engine.CtrlUnimplementedCommand("status"); }); // not implemented
+
+ // parse the arguments
+ engine.arguments = engine.parser.parse(argv);
BaseLogFile *base_log_file = new BaseLogFile("stderr");
- diags = new Diags(program_name, "" /* tags */, "" /*
actions */, base_log_file);
+ diags = new Diags("traffic_ctl", "" /* tags */, "" /*
actions */, base_log_file);
- // Process command line arguments and dump into variables
- if (!CtrlProcessArguments(argc, argv, argument_descriptions,
countof(argument_descriptions))) {
- return CtrlSubcommandUsage(nullptr, commands, countof(commands),
argument_descriptions, countof(argument_descriptions));
- }
-
- if (debug) {
+ if (engine.arguments.get("debug")) {
diags->activate_taglist("traffic_ctl", DiagsTagType_Debug);
diags->config.enabled[DiagsTagType_Debug] = true;
diags->show_location = SHOW_LOCATION_DEBUG;
}
- if (n_file_arguments < 1) {
- return CtrlSubcommandUsage(nullptr, commands, countof(commands),
argument_descriptions, countof(argument_descriptions));
- }
-
- runroot_handler(argv);
+ argparser_runroot_handler(engine.arguments.get("--run-root").value(),
argv[0]);
Layout::create();
RecProcessInit(RECM_STAND_ALONE, diags);
LibRecordsConfigInit();
@@ -272,16 +287,10 @@ main(int argc, const char **argv)
// error.
TSInit(rundir, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS |
TS_MGMT_OPT_NO_SOCK_TESTS));
- for (unsigned i = 0; i < countof(commands); ++i) {
- if (strcmp(file_arguments[0], commands[i].name) == 0) {
- CtrlCommandLine cmdline;
-
- cmdline.init(n_file_arguments, file_arguments);
- return commands[i].handler(cmdline.argc(), cmdline.argv());
- }
- }
+ engine.arguments.invoke();
// Done with the mgmt API.
TSTerminate();
- return CtrlSubcommandUsage(nullptr, commands, countof(commands),
argument_descriptions, countof(argument_descriptions));
+
+ return engine.status_code;
}
diff --git a/src/traffic_ctl/traffic_ctl.h b/src/traffic_ctl/traffic_ctl.h
index 991c790..f02fe27 100644
--- a/src/traffic_ctl/traffic_ctl.h
+++ b/src/traffic_ctl/traffic_ctl.h
@@ -30,28 +30,22 @@
#include "tscore/ink_args.h"
#include "tscore/I_Version.h"
#include "tscore/BaseLogFile.h"
+#include "tscore/ArgParser.h"
#include <vector>
#include <string>
+#include <iostream>
-struct subcommand {
- int (*handler)(unsigned, const char **);
- const char *name;
- const char *help;
-};
-
-extern AppVersionInfo CtrlVersionInfo;
+// Exit status codes, following BSD's sysexits(3)
+constexpr int CTRL_EX_OK = 0;
+constexpr int CTRL_EX_ERROR = 2;
+constexpr int CTRL_EX_UNIMPLEMENTED = 3;
+constexpr int CTRL_EX_USAGE = EX_USAGE;
+constexpr int CTRL_EX_UNAVAILABLE = 69;
#define CtrlDebug(...) Debug("traffic_ctl", __VA_ARGS__)
void CtrlMgmtError(TSMgmtError err, const char *fmt, ...) TS_PRINTFLIKE(2, 3);
-int CtrlSubcommandUsage(const char *name, const subcommand *cmds, unsigned
ncmds, const ArgumentDescription *desc, unsigned ndesc);
-int CtrlCommandUsage(const char *msg, const ArgumentDescription *desc =
nullptr, unsigned ndesc = 0);
-
-bool CtrlProcessArguments(int argc, const char **argv, const
ArgumentDescription *desc, unsigned ndesc);
-int CtrlUnimplementedCommand(unsigned argc, const char **argv);
-
-int CtrlGenericSubcommand(const char *, const subcommand *cmds, unsigned
ncmds, unsigned argc, const char **argv);
#define CTRL_MGMT_CHECK(expr) \
do { \
@@ -59,7 +53,8 @@ int CtrlGenericSubcommand(const char *, const subcommand
*cmds, unsigned ncmds,
if (e != TS_ERR_OKAY) { \
CtrlDebug("%s failed with status %d", #expr, e); \
CtrlMgmtError(e, nullptr); \
- return CTRL_EX_ERROR; \
+ status_code = CTRL_EX_ERROR; \
+ return; \
} \
} while (0)
@@ -167,47 +162,59 @@ struct CtrlMgmtRecordList :
CtrlMgmtList<RecordListPolicy> {
TSMgmtError match(const char *);
};
-struct CtrlCommandLine {
- CtrlCommandLine() { this->args.push_back(nullptr); }
- void
- init(unsigned argc, const char **argv)
- {
- this->args.clear();
- for (unsigned i = 0; i < argc; ++i) {
- this->args.push_back(argv[i]);
- }
-
- // Always nullptr-terminate to keep ink_args happy. Note that we adjust
arg() accordingly.
- this->args.push_back(nullptr);
- }
-
- unsigned
- argc()
- {
- return args.size() - 1;
- }
-
- const char **
- argv()
- {
- return &args[0];
- }
-
-private:
- std::vector<const char *> args;
+// this is a engine for traffic_ctl containing the ArgParser and all the
methods
+// it also has a status code which can be set by these methods to return
+struct CtrlEngine {
+ // the parser for traffic_ctl
+ ts::ArgParser parser;
+ // parsed arguments
+ ts::Arguments arguments;
+ // the return status code from functions
+ // By default it is set to CTRL_EX_OK so we don't need to set it
+ // in each method when they finish successfully.
+ int status_code = CTRL_EX_OK;
+
+ // All traffic_ctl methods:
+ // umimplemented command
+ void CtrlUnimplementedCommand(std::string_view command);
+
+ // alarm methods
+ void alarm_list();
+ void alarm_clear();
+ void alarm_resolve();
+
+ // config methods
+ void config_defaults();
+ void config_diff();
+ void config_status();
+ void config_reload();
+ void config_match();
+ void config_get();
+ void config_set();
+ void config_describe();
+
+ // host methods
+ void status_get();
+ void status_down();
+ void status_up();
+
+ // metric methods
+ void metric_get();
+ void metric_match();
+ void metric_clear();
+ void metric_zero();
+
+ // metric methods
+ void plugin_msg();
+
+ // server methods
+ void server_restart();
+ void server_backtrace();
+ void server_status();
+ void server_stop();
+ void server_start();
+ void server_drain();
+
+ // storage methods
+ void storage_offline();
};
-
-int subcommand_alarm(unsigned argc, const char **argv);
-int subcommand_config(unsigned argc, const char **argv);
-int subcommand_metric(unsigned argc, const char **argv);
-int subcommand_server(unsigned argc, const char **argv);
-int subcommand_storage(unsigned argc, const char **argv);
-int subcommand_plugin(unsigned argc, const char **argv);
-int subcommand_host(unsigned argc, const char **argv);
-
-// Exit status codes, following BSD's sysexits(3)
-#define CTRL_EX_OK 0
-#define CTRL_EX_ERROR 2
-#define CTRL_EX_UNIMPLEMENTED 3
-#define CTRL_EX_USAGE EX_USAGE
-#define CTRL_EX_UNAVAILABLE 69