You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2015/02/23 22:37:12 UTC
trafficserver git commit: TS-3367: add traffic_ctl,
a new command-line interface to the management API
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 <jp...@apache.org>
Authored: Tue Feb 3 12:56:26 2015 -0800
Committer: James Peach <jp...@apache.org>
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,