Repository: trafficserver Updated Branches: refs/heads/master 1d6f7d156 -> 683a377d1
TS-3367: add traffic_ctl, a new command-line interface to the management API traffic_ctl is a new commanline to administer Traffic Server using the management API. It uses the subcommand pattern, making the syntax more regular and extensible than traffic_line. This first implementation is feature-equivalent to traffic_line. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/683a377d Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/683a377d Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/683a377d Branch: refs/heads/master Commit: 683a377d199bddb41b1b5497bb894778df44ff90 Parents: 1d6f7d1 Author: James Peach <[email protected]> Authored: Tue Feb 3 12:56:26 2015 -0800 Committer: James Peach <[email protected]> Committed: Mon Feb 23 13:36:06 2015 -0800 ---------------------------------------------------------------------- .gitignore | 1 + CHANGES | 2 + cmd/Makefile.am | 5 +- cmd/traffic_ctl/Makefile.am | 40 +++++++ cmd/traffic_ctl/alarm.cc | 137 +++++++++++++++++++++ cmd/traffic_ctl/config.cc | 216 +++++++++++++++++++++++++++++++++ cmd/traffic_ctl/metric.cc | 142 ++++++++++++++++++++++ cmd/traffic_ctl/server.cc | 174 +++++++++++++++++++++++++++ cmd/traffic_ctl/storage.cc | 56 +++++++++ cmd/traffic_ctl/traffic_ctl.cc | 233 ++++++++++++++++++++++++++++++++++++ cmd/traffic_ctl/traffic_ctl.h | 201 +++++++++++++++++++++++++++++++ configure.ac | 2 + lib/ts/ink_args.cc | 49 +++++--- lib/ts/ink_args.h | 11 ++ lib/ts/ink_llqueue.h | 2 +- lib/ts/llqueue.cc | 7 +- mgmt/api/INKMgmtAPI.cc | 13 +- mgmt/api/include/mgmtapi.h | 4 +- 18 files changed, 1261 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index 5728268..044b972 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ pm_to_blib cmd/traffic_line/traffic_line cmd/traffic_shell/traffic_shell cmd/traffic_cop/traffic_cop +cmd/traffic_ctl/traffic_ctl cmd/traffic_crashlog/traffic_crashlog cmd/traffic_top/traffic_top cmd/traffic_manager/traffic_manager http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index 9511ce1..b3ba2ba 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ -*- coding: utf-8 -*- Changes with Apache Traffic Server 5.3.0 + *) [TS-3376] Add traffic_ctl, a new command line management tool. + *) [TS-3403] Stop parsing command-line options at the first non-option. *) [TS-3402] Rationalize lock debugging infrastructure. http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/Makefile.am ---------------------------------------------------------------------- diff --git a/cmd/Makefile.am b/cmd/Makefile.am index 3636cfe..b482056 100644 --- a/cmd/Makefile.am +++ b/cmd/Makefile.am @@ -17,14 +17,15 @@ SUBDIRS = \ traffic_cop \ + traffic_ctl \ traffic_crashlog \ traffic_layout \ traffic_line \ traffic_manager \ traffic_top \ - traffic_via + traffic_via -if BUILD_WCCP +if BUILD_WCCP SUBDIRS += traffic_wccp http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/Makefile.am ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/Makefile.am b/cmd/traffic_ctl/Makefile.am new file mode 100644 index 0000000..51cc05c --- /dev/null +++ b/cmd/traffic_ctl/Makefile.am @@ -0,0 +1,40 @@ +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/ts \ + -I$(top_srcdir)/mgmt/api/include + +bin_PROGRAMS = traffic_ctl + +traffic_ctl_SOURCES = \ + alarm.cc \ + config.cc \ + metric.cc \ + server.cc \ + storage.cc \ + traffic_ctl.cc + +traffic_ctl_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +traffic_ctl_LDADD = \ + $(top_builddir)/mgmt/api/libtsmgmt.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBRESOLV@ @LIBTCL@ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/alarm.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/alarm.cc b/cmd/traffic_ctl/alarm.cc new file mode 100644 index 0000000..404069c --- /dev/null +++ b/cmd/traffic_ctl/alarm.cc @@ -0,0 +1,137 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" + +struct AlarmListPolicy +{ + typedef char * entry_type; + + static void free(entry_type e) { + TSfree(e); + } + + static entry_type cast(void * ptr) { + return (entry_type)ptr; + } +}; + +typedef CtrlMgmtList<AlarmListPolicy> CtrlAlarmList; + +static int +alarm_list(unsigned argc, const char ** argv) +{ + TSMgmtError error; + CtrlAlarmList alarms; + + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) { + return CtrlCommandUsage("alarm list", NULL, 0); + } + + error = TSActiveEventGetMlt(alarms.list); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to fetch active alarms"); + return CTRL_EX_ERROR; + } + + while (!alarms.empty()) { + char * a = alarms.next(); + printf("%s\n", a); + TSfree(a); + } + + return CTRL_EX_OK; +} + +static int +alarm_clear(unsigned argc, const char ** argv) +{ + TSMgmtError error; + CtrlAlarmList alarms; + + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) { + return CtrlCommandUsage("alarm clear", NULL, 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; + } + + // Now resolve them all ... + while (!alarms.empty()) { + char * a = alarms.next(); + + error = TSEventResolve(a); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to resolve %s", a); + TSfree(a); + return CTRL_EX_ERROR; + } + + TSfree(a); + } + + return CTRL_EX_OK; +} + +static int +alarm_resolve(unsigned argc, const char ** argv) +{ + TSMgmtError error; + CtrlAlarmList alarms; + + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments == 0) { + return CtrlCommandUsage("alarm resolve ALARM [ALARM ...]", NULL, 0); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + error = TSEventResolve(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to resolve %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + } + + 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); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/config.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/config.cc b/cmd/traffic_ctl/config.cc new file mode 100644 index 0000000..66e10de --- /dev/null +++ b/cmd/traffic_ctl/config.cc @@ -0,0 +1,216 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" +#include <time.h> + +static std::string +timestr(time_t tm) +{ + char buf[32]; + return std::string(ctime_r(&tm, buf)); +} + +static void +format_record(const CtrlMgmtRecord& record, bool recfmt) +{ + const char * typestr[] = { + "INT", "COUNTER", "FLOAT", "STRING", "UNDEFINED" + }; + + if (recfmt) { + // XXX Detect CONFIG or LOCAL ... + printf("CONFIG %s %s %s\n", record.name(), typestr[record.type()], record.c_str()); + } else { + printf("%s: %s\n", record.name(), record.c_str()); + } +} + +static int +config_get(unsigned argc, const char ** argv) +{ + int recfmt = 0; + const ArgumentDescription opts[] = { + { "records", '-', "Emit output in records.config format", "F", &recfmt, NULL, NULL }, + }; + + 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) { + CtrlMgmtRecord record; + TSMgmtError error; + + error = record.fetch(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + + format_record(record, recfmt); + } + + return CTRL_EX_OK; +} + +static int +config_set(unsigned argc, const char ** argv) +{ + TSMgmtError error; + TSActionNeedT action; + + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 2) { + return CtrlCommandUsage("config set RECORD VALUE"); + } + + error = TSRecordSet(file_arguments[0], file_arguments[1], &action); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to set %s", file_arguments[0]); + return CTRL_EX_ERROR; + } + + switch (action) { + case TS_ACTION_SHUTDOWN: + printf("set %s, full shutdown required\n", file_arguments[0]); + break; + case TS_ACTION_RESTART: + printf("set %s, restart required\n", file_arguments[0]); + break; + case TS_ACTION_RECONFIGURE: + // printf("Set %s, reconfiguration required\n", file_arguments[0]); + break; + case TS_ACTION_DYNAMIC: + default: + printf("set %s\n", file_arguments[0]); + break; + } + + return CTRL_EX_OK; +} + +static int +config_match(unsigned argc, const char ** argv) +{ + int recfmt = 0; + const ArgumentDescription opts[] = { + { "records", '-', "Emit output in records.config format", "F", &recfmt, NULL, NULL }, + }; + + 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) { + CtrlMgmtRecordList reclist; + TSMgmtError error; + + // XXX filter the results to only match configuration records. + + error = reclist.match(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + + while (!reclist.empty()) { + CtrlMgmtRecord record(reclist.next()); + format_record(record, recfmt); + } + } + + return CTRL_EX_OK; +} + +static int +config_reload(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 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; + } + + return CTRL_EX_OK; +} + +static int +config_status(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) { + return CtrlCommandUsage("config status"); + } + + CtrlMgmtRecord version; + CtrlMgmtRecord configtime; + CtrlMgmtRecord starttime; + CtrlMgmtRecord reconfig; + CtrlMgmtRecord proxy; + CtrlMgmtRecord manager; + CtrlMgmtRecord cop; + + CTRL_MGMT_CHECK(version.fetch("proxy.process.version.server.long")); + CTRL_MGMT_CHECK(starttime.fetch("proxy.node.restarts.proxy.start_time")); + CTRL_MGMT_CHECK(configtime.fetch("proxy.node.config.reconfigure_time")); + CTRL_MGMT_CHECK(reconfig.fetch("proxy.node.config.reconfigure_required")); + CTRL_MGMT_CHECK(proxy.fetch("proxy.node.config.restart_required.proxy")); + CTRL_MGMT_CHECK(manager.fetch("proxy.node.config.restart_required.manager")); + CTRL_MGMT_CHECK(cop.fetch("proxy.node.config.restart_required.cop")); + + printf("%s\n", 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"); + + if (proxy.as_int()) { + printf("traffic_server requires restarting\n"); + } + if (manager.as_int()) { + printf("traffic_manager requires restarting\n"); + } + if (cop.as_int()) { + printf("traffic_cop requires restarting\n"); + } + + return CTRL_EX_OK; +} + +int +subcommand_config(unsigned argc, const char ** argv) +{ + const subcommand commands[] = + { + { CtrlUnimplementedCommand, "describe", "Show detailed information about 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); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/metric.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/metric.cc b/cmd/traffic_ctl/metric.cc new file mode 100644 index 0000000..5cfdbc3 --- /dev/null +++ b/cmd/traffic_ctl/metric.cc @@ -0,0 +1,142 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" + +static int +metric_get(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) { + return CtrlCommandUsage("metric get RECORD [RECORD ...]", NULL, 0); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + CtrlMgmtRecord record; + TSMgmtError error; + + error = record.fetch(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + + printf("%s %s\n", record.name(), record.c_str()); + } + + return CTRL_EX_OK; +} + +static int +metric_match(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) { + return CtrlCommandUsage("metric match [OPTIONS] REGEX [REGEX ...]", NULL, 0); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + CtrlMgmtRecordList reclist; + TSMgmtError error; + + // XXX filter the results to only match metric records. + + error = reclist.match(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to fetch %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + + while (!reclist.empty()) { + CtrlMgmtRecord record(reclist.next()); + printf("%s %s\n", record.name(), record.c_str()); + } + } + + return CTRL_EX_OK; +} + +static int +metric_clear(unsigned argc, const char ** argv) +{ + int cluster = 0; + TSMgmtError error; + + const ArgumentDescription opts[] = { + { "cluster", '-', "Clear cluster metrics", "F", &cluster, NULL, NULL }, + }; + + if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments != 0) { + return CtrlCommandUsage("config clear [OPTIONS]", opts, countof(opts)); + } + + error = TSStatsReset(cluster, NULL); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : ""); + return CTRL_EX_ERROR; + } + + return CTRL_EX_OK; +} + +static int +metric_zero(unsigned argc, const char ** argv) +{ + int cluster = 0; + TSMgmtError error; + + const ArgumentDescription opts[] = { + { "cluster", '-', "Zero cluster metrics", "F", &cluster, NULL, NULL }, + }; + + if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments == 0) { + return CtrlCommandUsage("config zero [OPTIONS]", opts, countof(opts)); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + error = TSStatsReset(cluster, NULL); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to clear %smetrics", cluster ? "cluster " : ""); + return 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); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/server.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/server.cc b/cmd/traffic_ctl/server.cc new file mode 100644 index 0000000..3b0e387 --- /dev/null +++ b/cmd/traffic_ctl/server.cc @@ -0,0 +1,174 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" + +static int drain = 0; + +const ArgumentDescription opts[] = { + { "drain", '-', "Wait for client connections to drain before restarting", "F", &drain, NULL, NULL }, +}; + +static int +bounce(unsigned argc, const char ** argv, unsigned flags) +{ + TSMgmtError error; + const char * usage = (flags & TS_RESTART_OPT_CLUSTER) ? "cluster bounce [OPTIONS]" : "server bounce [OPTIONS]"; + + if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments != 0) { + return CtrlCommandUsage(usage, opts, countof(opts)); + } + + if (drain) { + flags |= TS_RESTART_OPT_DRAIN; + } + + error = TSBounce(flags); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "%s bounce failed", (flags & TS_RESTART_OPT_CLUSTER) ? "cluster" : "server"); + return CTRL_EX_ERROR; + } + + return CTRL_EX_OK; +} + +static int +restart(unsigned argc, const char ** argv, unsigned flags) +{ + TSMgmtError error; + const char * usage = (flags & TS_RESTART_OPT_CLUSTER) ? "cluster restart [OPTIONS]" : "server restart [OPTIONS]"; + + if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments != 0) { + return CtrlCommandUsage(usage, opts, countof(opts)); + } + + if (drain) { + flags |= TS_RESTART_OPT_DRAIN; + } + + error = TSRestart(flags); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "%s restart failed", (flags & TS_RESTART_OPT_CLUSTER) ? "cluster" : "server"); + return CTRL_EX_ERROR; + } + + return CTRL_EX_OK; +} + +static int +cluster_bounce(unsigned argc, const char ** argv) +{ + return bounce(argc, argv, TS_RESTART_OPT_CLUSTER); +} + +static int +server_bounce(unsigned argc, const char ** argv) +{ + return bounce(argc, argv, TS_RESTART_OPT_NONE); +} + +static int +cluster_restart(unsigned argc, const char ** argv) +{ + return restart(argc, argv, TS_RESTART_OPT_CLUSTER); +} + +static int +server_restart(unsigned argc, const char ** argv) +{ + return restart(argc, argv, TS_RESTART_OPT_NONE); +} + +static int +server_backtrace(unsigned argc, const char ** argv) +{ + TSMgmtError error; + TSString trace = NULL; + + if (!CtrlProcessArguments(argc, argv, NULL, 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; + } + + printf("%s\n", trace); + TSfree(trace); + return CTRL_EX_OK; +} + +static int +server_status(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments != 0) { + return CtrlCommandUsage("server status"); + } + + switch (TSProxyStateGet()) { + case TS_PROXY_ON: + printf("Proxy -- on\n"); + break; + case TS_PROXY_OFF: + printf("Proxy -- off\n"); + break; + case TS_PROXY_UNDEFINED: + printf("Proxy status undefined\n"); + break; + } + + // XXX Surely we can report more useful status that this !?!! + + return CTRL_EX_OK; +} + +int +subcommand_cluster(unsigned argc, const char ** argv) +{ + const subcommand commands[] = + { + { cluster_bounce, "bounce", "Restart traffic_server across the cluster" }, + { cluster_restart, "restart", "Restart traffic_server and traffic_server across the cluster" }, + { CtrlUnimplementedCommand, "status", "Show the cluster status" }, + }; + + return CtrlGenericSubcommand("cluster", commands, countof(commands), argc, argv); +} + +int +subcommand_server(unsigned argc, const char ** argv) +{ + const subcommand commands[] = + { + { server_bounce, "bounce", "Restart traffic_server" }, + { server_restart, "restart", "Restart traffic_server and traffic_server" }, + { server_backtrace, "backtrace", "Show a full stack trace of the traffic_server process" }, + { server_status, "status", "Show the proxy status" }, + + /* XXX do the 'shutdown' and 'startup' commands make sense? */ + }; + + return CtrlGenericSubcommand("server", commands, countof(commands), argc, argv); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/storage.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/storage.cc b/cmd/traffic_ctl/storage.cc new file mode 100644 index 0000000..fbd6720 --- /dev/null +++ b/cmd/traffic_ctl/storage.cc @@ -0,0 +1,56 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" + +static int +storage_offline(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments == 0) { + return CtrlCommandUsage("storage offline DEVICE [DEVICE ...]"); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + TSMgmtError error; + + error = TSStorageDeviceCmdOffline(file_arguments[i]); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to take %s offline", file_arguments[0]); + return CTRL_EX_ERROR; + } + } + + 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); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/traffic_ctl.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/traffic_ctl.cc b/cmd/traffic_ctl/traffic_ctl.cc new file mode 100644 index 0000000..39b81fb --- /dev/null +++ b/cmd/traffic_ctl/traffic_ctl.cc @@ -0,0 +1,233 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "traffic_ctl.h" + +AppVersionInfo CtrlVersionInfo; + +const char * +CtrlMgmtRecord::name() const +{ + return this->ele->rec_name; +} + +TSRecordT +CtrlMgmtRecord::type() const +{ + return this->ele->rec_type; +} + +int64_t +CtrlMgmtRecord::as_int() const +{ + switch (this->ele->rec_type) { + case TS_REC_INT: + return this->ele->valueT.int_val; + case TS_REC_COUNTER: + return this->ele->valueT.counter_val; + default: + return 0; + } +} + +const char * +CtrlMgmtRecord::c_str() const +{ + switch (this->ele->rec_type) { + case TS_REC_INT: + snprintf(this->nbuf, sizeof(this->nbuf), "%" PRId64, this->ele->valueT.int_val); + return this->nbuf; + case TS_REC_COUNTER: + snprintf(this->nbuf, sizeof(this->nbuf), "%" PRId64, this->ele->valueT.counter_val); + return this->nbuf; + case TS_REC_FLOAT: + snprintf(this->nbuf, sizeof(this->nbuf), "%f", this->ele->valueT.float_val); + return this->nbuf; + case TS_REC_STRING: + return this->ele->valueT.string_val; + default: + return "(invalid)"; + } +} + +TSMgmtError +CtrlMgmtRecord::fetch(const char * name) +{ + return TSRecordGet(name, this->ele); +} + +TSMgmtError +CtrlMgmtRecordList::match(const char * name) +{ + return TSRecordGetMatchMlt(name, this->list); +} + +void +CtrlMgmtError(TSMgmtError err, const char * fmt, ...) +{ + ats_scoped_str msg(TSGetErrorMessage(err)); + + if (fmt) { + va_list ap; + + fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, ": %s\n", (const char *)msg); + } else { + fprintf(stderr, "%s: %s\n", program_name, (const char *)msg); + } + +} + +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) +{ + CtrlDebug("the '%s' command is not implemented", *argv); + return 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, NULL, 0) || n_file_arguments < 1) { + return CtrlSubcommandUsage(name, cmds, ncmds, NULL, 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, NULL, 0); +} + +int +main(int argc, const char **argv) +{ + TSMgmtError status; + 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, NULL, NULL }, + HELP_ARGUMENT_DESCRIPTION(), + VERSION_ARGUMENT_DESCRIPTION() + }; + + const subcommand commands[] = { + { subcommand_alarm, "alarm", "Manipulate alarms" }, + { subcommand_cluster, "cluster", "Stop, restart and examine the cluster" }, + { 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" }, + }; + + diags = new Diags("" /* tags */, "" /* actions */, stderr); + + // Process command line arguments and dump into variables + if (!CtrlProcessArguments(argc, argv, argument_descriptions, countof(argument_descriptions))) { + return CtrlSubcommandUsage(NULL, commands, countof(commands), argument_descriptions, countof(argument_descriptions)); + } + + if (debug) { + diags->activate_taglist("traffic_ctl", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = true; + } + + CtrlDebug("debug logging active"); + + if (n_file_arguments < 1) { + return CtrlSubcommandUsage(NULL, commands, countof(commands), argument_descriptions, countof(argument_descriptions)); + } + + status = TSInit(NULL, static_cast<TSInitOptionT>(TS_MGMT_OPT_NO_EVENTS | TS_MGMT_OPT_NO_SOCK_TESTS)); + if (status != TS_ERR_OKAY) { + CtrlMgmtError(status, "failed to attach to the API server"); + return CTRL_EX_UNAVAILABLE; + } + + 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()); + } + } + + // Done with the mgmt API. + TSTerminate(); + return CtrlSubcommandUsage(NULL, commands, countof(commands), argument_descriptions, countof(argument_descriptions)); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/cmd/traffic_ctl/traffic_ctl.h ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/traffic_ctl.h b/cmd/traffic_ctl/traffic_ctl.h new file mode 100644 index 0000000..62d2c5e --- /dev/null +++ b/cmd/traffic_ctl/traffic_ctl.h @@ -0,0 +1,201 @@ +/** @file + + traffic_ctl + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _TRAFFIC_CTRL_H_ +#define _TRAFFIC_CTRL_H_ + +#include "libts.h" +#include "mgmtapi.h" +#include "ink_args.h" +#include "I_Version.h" + +#include <vector> + +struct subcommand +{ + int (*handler) (unsigned, const char **); + const char * name; + const char * help; +}; + +extern AppVersionInfo CtrlVersionInfo; + +#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 = NULL, 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 { \ + TSMgmtError e = (expr); \ + if (e != TS_ERR_OKAY) { \ + CtrlDebug("%s failed with status %d", #expr, e);\ + CtrlMgmtError(e, NULL); \ + return CTRL_EX_ERROR; \ + } \ +} while (0) + +struct CtrlMgmtRecord +{ + explicit CtrlMgmtRecord(TSRecordEle * e) : ele(e) { + } + + CtrlMgmtRecord() : ele(TSRecordEleCreate()) { + } + + ~CtrlMgmtRecord() { + if (this->ele) { + TSRecordEleDestroy(this->ele); + } + } + + TSMgmtError fetch(const char *); + const char * name() const; + TSRecordT type() const; + const char * c_str() const; + + int64_t as_int() const; + +private: + CtrlMgmtRecord(const CtrlMgmtRecord&); // disabled + CtrlMgmtRecord& operator=(const CtrlMgmtRecord&); // disabled + + TSRecordEle * ele; + mutable char nbuf[32]; +}; + +struct CtrlMgmtRecordList +{ + CtrlMgmtRecordList() : list(TSListCreate()) { + } + + ~CtrlMgmtRecordList() { + this->clear(); + TSListDestroy(this->list); + } + + bool empty() const { + return TSListIsEmpty(this->list); + } + + void clear() const { + while (!this->empty()) { + TSRecordEleDestroy((TSRecordEle *)TSListDequeue(this->list)); + } + } + + // Return (ownership of) the next list entry. + TSRecordEle * next() { + return (TSRecordEle *)TSListDequeue(this->list); + } + + TSMgmtError match(const char *); + +private: + CtrlMgmtRecordList(const CtrlMgmtRecordList&); // disabled + CtrlMgmtRecordList& operator=(const CtrlMgmtRecordList&); // disabled + + TSList list; +}; + +template<typename T> +struct CtrlMgmtList +{ + CtrlMgmtList() : list(TSListCreate()) { + } + + ~CtrlMgmtList() { + this->clear(); + TSListDestroy(this->list); + } + + bool empty() const { + return TSListIsEmpty(this->list); + } + + void clear() const { + while (!this->empty()) { + T::free(T::cast(TSListDequeue(this->list))); + } + } + + // Return (ownership of) the next list entry. + typename T::entry_type next() { + return T::cast(TSListDequeue(this->list)); + } + + TSList list; + +private: + CtrlMgmtList(const CtrlMgmtList&); // disabled + CtrlMgmtList& operator=(const CtrlMgmtList&); // disabled +}; + +struct CtrlCommandLine +{ + CtrlCommandLine() { + this->args.push_back(NULL); + } + + void init(unsigned argc, const char ** argv) { + this->args.clear(); + for (unsigned i = 0; i < argc; ++i) { + this->args.push_back(argv[i]); + } + + // Always NULL-terminate to keep ink_args happy. Note that we adjust arg() accordingly. + this->args.push_back(NULL); + } + + unsigned argc() { + return args.size() - 1; + } + + const char ** argv() { + return &args[0]; + } + +private: + std::vector<const char *> args; +}; + +int subcommand_alarm(unsigned argc, const char ** argv); +int subcommand_cluster(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); + +// 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 + +#endif /* _TRAFFIC_CTRL_H_ */ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/configure.ac ---------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 11cadf1..0442407 100644 --- a/configure.ac +++ b/configure.ac @@ -1492,6 +1492,7 @@ AC_CHECK_HEADERS([sys/types.h \ math.h \ stdint.h \ stdbool.h \ + sysexits.h \ net/ppp_defs.h \ ifaddrs.h\ readline/readline.h \ @@ -1860,6 +1861,7 @@ AC_CONFIG_FILES([ cmd/Makefile cmd/traffic_cop/Makefile cmd/traffic_crashlog/Makefile + cmd/traffic_ctl/Makefile cmd/traffic_layout/Makefile cmd/traffic_line/Makefile cmd/traffic_manager/Makefile http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_args.cc ---------------------------------------------------------------------- diff --git a/lib/ts/ink_args.cc b/lib/ts/ink_args.cc index de4fb5d..c121813 100644 --- a/lib/ts/ink_args.cc +++ b/lib/ts/ink_args.cc @@ -72,9 +72,9 @@ append_file_argument(const char * arg) file_arguments[n_file_arguments++] = arg; } -static void +static bool process_arg(const AppVersionInfo * appinfo, const ArgumentDescription * argument_descriptions, - unsigned n_argument_descriptions, int i, const char ***argv, const char *usage_string) + unsigned n_argument_descriptions, int i, const char ***argv) { const char *arg = NULL; @@ -85,14 +85,15 @@ process_arg(const AppVersionInfo * appinfo, const ArgumentDescription * argument if (argument_descriptions[i].type) { char type = argument_descriptions[i].type[0]; - if (type == 'F' || type == 'f') + if (type == 'F' || type == 'f') { *(int *) argument_descriptions[i].location = type == 'F' ? 1 : 0; - else if (type == 'T') + } else if (type == 'T') { *(int *) argument_descriptions[i].location = !*(int *) argument_descriptions[i].location; - else { + } else { arg = *++(**argv) ? **argv : *++(*argv); - if (!arg) - usage(argument_descriptions, n_argument_descriptions, usage_string); + if (!arg) { + return false; + } switch (type) { case 'I': *(int *) argument_descriptions[i].location = atoi(arg); @@ -118,8 +119,12 @@ process_arg(const AppVersionInfo * appinfo, const ArgumentDescription * argument **argv += strlen(**argv) - 1; } } - if (argument_descriptions[i].pfn) + + if (argument_descriptions[i].pfn) { argument_descriptions[i].pfn(argument_descriptions, n_argument_descriptions, arg); + } + + return true; } @@ -160,6 +165,15 @@ show_argument_configuration(const ArgumentDescription * argument_descriptions, u void process_args(const AppVersionInfo * appinfo, const ArgumentDescription * argument_descriptions, unsigned n_argument_descriptions, const char **argv, const char *usage_string) { + if (!process_args_ex(appinfo, argument_descriptions, n_argument_descriptions, argv)) { + usage(argument_descriptions, n_argument_descriptions, usage_string); + } +} + +bool +process_args_ex(const AppVersionInfo * appinfo, const ArgumentDescription * argument_descriptions, + unsigned n_argument_descriptions, const char **argv) +{ unsigned i = 0; // // Grab Environment Variables @@ -210,23 +224,28 @@ process_args(const AppVersionInfo * appinfo, const ArgumentDescription * argumen for (i = 0; i < n_argument_descriptions; i++) if (!strcmp(argument_descriptions[i].name, (*argv) + 2)) { *argv += strlen(*argv) - 1; - process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv, usage_string); + if (!process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv)) { + return false; + } break; } - if (i >= n_argument_descriptions) - usage(argument_descriptions, n_argument_descriptions, usage_string); + if (i >= n_argument_descriptions) { + return false; + } } else { // Deal with (possibly combined) short options ... while (*++(*argv)) { for (i = 0; i < n_argument_descriptions; i++) { if (argument_descriptions[i].key == **argv) { - process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv, usage_string); + if (!process_arg(appinfo, argument_descriptions, n_argument_descriptions, i, &argv)) { + return false; + } break; } } if (i >= n_argument_descriptions) { - usage(argument_descriptions, n_argument_descriptions, usage_string); + return false; } } } @@ -239,6 +258,8 @@ process_args(const AppVersionInfo * appinfo, const ArgumentDescription * argumen append_file_argument(*argv); } } + + return true; } void @@ -312,5 +333,5 @@ usage(const ArgumentDescription * argument_descriptions, unsigned n_argument_des } fprintf(stderr, " %s\n", argument_descriptions[i].description); } - _exit(1); + exit(EX_USAGE); } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_args.h ---------------------------------------------------------------------- diff --git a/lib/ts/ink_args.h b/lib/ts/ink_args.h index aedd0f8..824f919 100644 --- a/lib/ts/ink_args.h +++ b/lib/ts/ink_args.h @@ -31,6 +31,14 @@ Process arguments #include "ink_defs.h" #include "ink_apidefs.h" +#if HAVE_SYSEXITS_H +#include <sysexits.h> +#endif + +#ifndef EX_USAGE +#define EX_USAGE 64 +#endif + #define MAX_FILE_ARGUMENTS 100 struct ArgumentDescription; @@ -80,4 +88,7 @@ void usage(const ArgumentDescription * argument_descriptions, unsigned n_argumen void process_args(const AppVersionInfo * appinfo, const ArgumentDescription * argument_descriptions, unsigned n_argument_descriptions, const char **argv, const char *usage_string = 0); +bool process_args_ex(const AppVersionInfo * appinfo, const ArgumentDescription * argument_descriptions, + unsigned n_argument_descriptions, const char **argv); + #endif /*_INK_ARGS_H*/ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/ink_llqueue.h ---------------------------------------------------------------------- diff --git a/lib/ts/ink_llqueue.h b/lib/ts/ink_llqueue.h index 670ec2d..67df59d 100644 --- a/lib/ts/ink_llqueue.h +++ b/lib/ts/ink_llqueue.h @@ -49,7 +49,7 @@ typedef struct llq_s LLQ *create_queue(void); int enqueue(LLQ * q, void *data); void *dequeue(LLQ * q); -int queue_is_empty(LLQ * q); +bool queue_is_empty(LLQ * q); uint64_t queue_len(LLQ * Q); uint64_t queue_highwater(LLQ * Q); void delete_queue(LLQ * Q); /* only deletes an empty queue but http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/lib/ts/llqueue.cc ---------------------------------------------------------------------- diff --git a/lib/ts/llqueue.cc b/lib/ts/llqueue.cc index 38f08d8..81125e2 100644 --- a/lib/ts/llqueue.cc +++ b/lib/ts/llqueue.cc @@ -169,17 +169,14 @@ queue_highwater(LLQ * Q) * *--------------------------------------------------------------------------- */ -int +bool queue_is_empty(LLQ * Q) { uint64_t len; len = queue_len(Q); - if (len) - return 0; - else - return 1; + return len == 0; } void * http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/mgmt/api/INKMgmtAPI.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/INKMgmtAPI.cc b/mgmt/api/INKMgmtAPI.cc index 55a2e41..c84d83f 100644 --- a/mgmt/api/INKMgmtAPI.cc +++ b/mgmt/api/INKMgmtAPI.cc @@ -126,18 +126,11 @@ TSListDequeue(TSList l) tsapi bool TSListIsEmpty(TSList l) { - int ret; - ink_assert(l); if (!l) return true; // list doesn't exist, so it's empty - ret = queue_is_empty((LLQ *) l); /* returns 0 if empty, non-zero if not empty */ - if (ret == 0) { /* empty */ - return true; - } else { - return false; - } + return queue_is_empty((LLQ *) l); } tsapi int @@ -1449,7 +1442,7 @@ TSStatsReset(bool cluster, const char *name) /* Call the CfgFileIO variable operations */ tsapi TSMgmtError -TSRecordGet(char *rec_name, TSRecordEle * rec_val) +TSRecordGet(const char *rec_name, TSRecordEle * rec_val) { return MgmtRecordGet(rec_name, rec_val); } @@ -2282,7 +2275,7 @@ TSEventSignal(char *event_name, ...) } tsapi TSMgmtError -TSEventResolve(char *event_name) +TSEventResolve(const char *event_name) { return EventResolve(event_name); } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/683a377d/mgmt/api/include/mgmtapi.h ---------------------------------------------------------------------- diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h index 2b78693..a04bb11 100644 --- a/mgmt/api/include/mgmtapi.h +++ b/mgmt/api/include/mgmtapi.h @@ -1117,7 +1117,7 @@ extern "C" * rec_val - allocated TSRecordEle structure, value stored inside * Output: TSMgmtError (if the rec_name does not exist, returns TS_ERR_FAIL) */ - tsapi TSMgmtError TSRecordGet(char *rec_name, TSRecordEle * rec_val); + tsapi TSMgmtError TSRecordGet(const char *rec_name, TSRecordEle * rec_val); /* TSRecordGet*: gets a record w/ a known type * Input: rec_name - the name of the record (proxy.config.record_name) @@ -1187,7 +1187,7 @@ extern "C" * Input: event_name - event to resolve * Output: TSMgmtError */ - tsapi TSMgmtError TSEventResolve(char *event_name); + tsapi TSMgmtError TSEventResolve(const char *event_name); /* TSActiveEventGetMlt: query for a list of all the currently active events * Input: active_events - an empty TSList; if function call is successful,
