Repository: trafficserver Updated Branches: refs/heads/master c6c910bc0 -> 857766c5c
TS-3408: add a "config describe" command to traffic_ctl Add a new management API TSConfigRecordDescribe() to publish all the information that we know about a configuration record. Plumb this through the messaging layer and expose it in traffic_ctl as the "config describe" subcommand. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/857766c5 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/857766c5 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/857766c5 Branch: refs/heads/master Commit: 857766c5caefd2c1b890e34e379cfcd7bbde475d Parents: c6c910b Author: James Peach <[email protected]> Authored: Wed Feb 11 16:27:00 2015 -0800 Committer: James Peach <[email protected]> Committed: Sun Mar 8 22:02:55 2015 -0700 ---------------------------------------------------------------------- CHANGES | 2 + cmd/traffic_ctl/Makefile.am | 1 + cmd/traffic_ctl/config.cc | 122 ++++++++++++++++++++++++++-- cmd/traffic_ctl/metric.cc | 4 +- cmd/traffic_ctl/traffic_ctl.cc | 69 +++++++++++----- cmd/traffic_ctl/traffic_ctl.h | 26 +++++- lib/records/I_RecCore.h | 6 +- lib/records/RecCore.cc | 25 ++++++ mgmt/api/CoreAPI.cc | 6 ++ mgmt/api/CoreAPI.h | 1 + mgmt/api/CoreAPIRemote.cc | 157 ++++++++++++++++++++++++++---------- mgmt/api/INKMgmtAPI.cc | 42 ++++++---- mgmt/api/NetworkMessage.cc | 18 ++++- mgmt/api/NetworkMessage.h | 3 + mgmt/api/TSControlMain.cc | 128 ++++++++++++++++++++++++++++- mgmt/api/include/mgmtapi.h | 50 ++++++++++-- 16 files changed, 559 insertions(+), 101 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index 320d0c6..17f59bc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ -*- coding: utf-8 -*- Changes with Apache Traffic Server 5.3.0 + *) [TS-3408] Add a "config describe" command to traffic_ctl. + *) [TS-3393] Fix records with missing validation expressions. *) [TS-3424] SSL Failed: decryption failed or bad record mac. http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/cmd/traffic_ctl/Makefile.am ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/Makefile.am b/cmd/traffic_ctl/Makefile.am index 51cc05c..d83fd19 100644 --- a/cmd/traffic_ctl/Makefile.am +++ b/cmd/traffic_ctl/Makefile.am @@ -21,6 +21,7 @@ AM_CPPFLAGS = \ $(iocore_include_dirs) \ -I$(top_srcdir)/lib \ -I$(top_srcdir)/lib/ts \ + -I$(top_srcdir)/lib/records \ -I$(top_srcdir)/mgmt/api/include bin_PROGRAMS = traffic_ctl http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/cmd/traffic_ctl/config.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/config.cc b/cmd/traffic_ctl/config.cc index 66e10de..f8b4886 100644 --- a/cmd/traffic_ctl/config.cc +++ b/cmd/traffic_ctl/config.cc @@ -23,6 +23,73 @@ #include "traffic_ctl.h" #include <time.h> +#include <I_RecDefs.h> + +// Record data type names, indexed by TSRecordT. +static const char * +rec_typeof(int rec_type) { + switch (rec_type) { + case TS_REC_INT: return "INT"; + case TS_REC_COUNTER: return "COUNTER"; + case TS_REC_FLOAT: return "FLOAT"; + case TS_REC_STRING: return "STRING"; + case TS_REC_UNDEFINED: /* fallthru */ + default: return "UNDEFINED"; + } +} + +// Record type name, indexed by RecT. +static const char * +rec_classof(int rec_class) { + switch (rec_class) { + case RECT_CONFIG: return "standard config"; + case RECT_LOCAL: return "local config"; + case RECT_PROCESS:return "process metric"; + case RECT_NODE: return "node metric"; + case RECT_CLUSTER:return "cluster metric"; + case RECT_PLUGIN: return "plugin metric"; + default: return "undefined"; + } +} + +// Record access control, indexed by RecAccessT. +static const char * +rec_accessof(int rec_access) +{ + switch (rec_access) { + case RECA_NO_ACCESS: return "no access"; + case RECA_READ_ONLY: return "read only"; + case RECA_NULL: /* fallthru */ + default: return "default"; + } +} + +// Record access control, indexed by RecUpdateT. +static const char * +rec_updateof(int rec_updatetype) +{ + switch (rec_updatetype) { + case RECU_DYNAMIC: return "dynamic, no restart"; + case RECU_RESTART_TS: return "static, restart traffic_server"; + case RECU_RESTART_TM: return "static, restart traffic_manager"; + case RECU_RESTART_TC: return "static, full restart"; + case RECU_NULL: /* fallthru */ + default: return "unknown"; + } +} + +// Record check type, indexed by RecCheckT. +static const char * +rec_checkof(int rec_checktype) +{ + switch (rec_checktype) { + case RECC_STR: return "string matching a regular expression"; + case RECC_INT: return "integer with a specified range"; + case RECC_IP: return "IP address"; + case RECC_NULL: /* fallthru */ + default: return "none"; + } +} static std::string timestr(time_t tm) @@ -34,15 +101,13 @@ timestr(time_t tm) static void format_record(const CtrlMgmtRecord& record, bool recfmt) { - const char * typestr[] = { - "INT", "COUNTER", "FLOAT", "STRING", "UNDEFINED" - }; + CtrlMgmtRecordValue value(record); if (recfmt) { // XXX Detect CONFIG or LOCAL ... - printf("CONFIG %s %s %s\n", record.name(), typestr[record.type()], record.c_str()); + printf("CONFIG %s %s %s\n", record.name(), rec_typeof(record.type()), value.c_str()); } else { - printf("%s: %s\n", record.name(), record.c_str()); + printf("%s: %s\n", record.name(), value.c_str()); } } @@ -75,6 +140,49 @@ config_get(unsigned argc, const char ** argv) } static int +config_describe(unsigned argc, const char ** argv) +{ + if (!CtrlProcessArguments(argc, argv, NULL, 0) || n_file_arguments < 1) { + return CtrlCommandUsage("config describe RECORD [RECORD ...]"); + } + + for (unsigned i = 0; i < n_file_arguments; ++i) { + TSConfigRecordDescription desc; + TSMgmtError error; + + ink_zero(desc); + error = TSConfigRecordDescribe(file_arguments[i], 0 /* flags */, &desc); + if (error != TS_ERR_OKAY) { + CtrlMgmtError(error, "failed to describe %s", file_arguments[i]); + return CTRL_EX_ERROR; + } + + printf("%-16s: %s\n", "Name", desc.rec_name); + printf("%-16s: %s\n", "Current Value", CtrlMgmtRecordValue(desc.rec_type, desc.rec_value).c_str()); + printf("%-16s: %s\n", "Default Value", CtrlMgmtRecordValue(desc.rec_type, desc.rec_default).c_str()); + printf("%-16s: %s\n", "Record Type", rec_classof(desc.rec_class)); + printf("%-16s: %s\n", "Data Type", rec_typeof(desc.rec_type)); + printf("%-16s: %s\n", "Access Control ", rec_accessof(desc.rec_access)); + printf("%-16s: %s\n", "Update Type", rec_updateof(desc.rec_updatetype)); + printf("%-16s: 0x%" PRIx64 "\n", "Update Status", desc.rec_update); + + if (strlen(desc.rec_checkexpr)) { + printf("%-16s: %s, '%s'\n", "Syntax Check", rec_checkof(desc.rec_checktype), desc.rec_checkexpr); + } else { + printf("%-16s: %s\n", "Syntax Check", rec_checkof(desc.rec_checktype)); + } + + printf("%-16s: %" PRId64 "\n", "Version", desc.rec_version); + printf("%-16s: %" PRId64 "\n", "Order", desc.rec_order); + printf("%-16s: %" PRId64 "\n", "Raw Stat Block", desc.rec_rsb); + + TSConfigRecordDescriptionFree(&desc); + } + + return CTRL_EX_OK; +} + +static int config_set(unsigned argc, const char ** argv) { TSMgmtError error; @@ -181,7 +289,7 @@ config_status(unsigned argc, const char ** argv) 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("%s\n", CtrlMgmtRecordValue(version).c_str()); printf("Started at %s", timestr((time_t)starttime.as_int()).c_str()); printf("Last reconfiguration at %s", timestr((time_t)configtime.as_int()).c_str()); printf("%s\n", reconfig.as_int() ? "Reconfiguration required" : "Configuration is current"); @@ -204,7 +312,7 @@ subcommand_config(unsigned argc, const char ** argv) { const subcommand commands[] = { - { CtrlUnimplementedCommand, "describe", "Show detailed information about configuration values" }, + { config_describe, "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" }, http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/cmd/traffic_ctl/metric.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/metric.cc b/cmd/traffic_ctl/metric.cc index fb4da30..4a90958 100644 --- a/cmd/traffic_ctl/metric.cc +++ b/cmd/traffic_ctl/metric.cc @@ -40,7 +40,7 @@ metric_get(unsigned argc, const char ** argv) return CTRL_EX_ERROR; } - printf("%s %s\n", record.name(), record.c_str()); + printf("%s %s\n", record.name(), CtrlMgmtRecordValue(record).c_str()); } return CTRL_EX_OK; @@ -67,7 +67,7 @@ metric_match(unsigned argc, const char ** argv) while (!reclist.empty()) { CtrlMgmtRecord record(reclist.next()); - printf("%s %s\n", record.name(), record.c_str()); + printf("%s %s\n", record.name(), CtrlMgmtRecordValue(record).c_str()); } } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/cmd/traffic_ctl/traffic_ctl.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/traffic_ctl.cc b/cmd/traffic_ctl/traffic_ctl.cc index 39b81fb..2b627f5 100644 --- a/cmd/traffic_ctl/traffic_ctl.cc +++ b/cmd/traffic_ctl/traffic_ctl.cc @@ -50,26 +50,6 @@ CtrlMgmtRecord::as_int() const } } -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) { @@ -82,6 +62,55 @@ CtrlMgmtRecordList::match(const char * name) return TSRecordGetMatchMlt(name, this->list); } +CtrlMgmtRecordValue::CtrlMgmtRecordValue(const CtrlMgmtRecord& rec) +{ + this->init(rec.ele->rec_type, rec.ele->valueT); +} + +CtrlMgmtRecordValue::CtrlMgmtRecordValue(const TSRecordEle * ele) +{ + this->init(ele->rec_type, ele->valueT); +} + +CtrlMgmtRecordValue::CtrlMgmtRecordValue(TSRecordT _t, TSRecordValueT _v) +{ + this->init(_t, _v); +} + +void +CtrlMgmtRecordValue::init(TSRecordT _t, TSRecordValueT _v) +{ + this->rec_type = _t; + switch (this->rec_type) { + case TS_REC_INT: + snprintf(this->fmt.nbuf, sizeof(this->fmt.nbuf), "%" PRId64, _v.int_val); + break; + case TS_REC_COUNTER: + snprintf(this->fmt.nbuf, sizeof(this->fmt.nbuf), "%" PRId64, _v.counter_val); + break; + case TS_REC_FLOAT: + snprintf(this->fmt.nbuf, sizeof(this->fmt.nbuf), "%f", _v.float_val); + break; + case TS_REC_STRING: + this->fmt.str = _v.string_val; + break; + default: + rec_type = TS_REC_STRING; + this->fmt.str = "(invalid)"; + } +} + +const char * +CtrlMgmtRecordValue::c_str() const +{ + switch (this->rec_type) { + case TS_REC_STRING: + return this->fmt.str; + default: + return this->fmt.nbuf; + } +} + void CtrlMgmtError(TSMgmtError err, const char * fmt, ...) { http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/cmd/traffic_ctl/traffic_ctl.h ---------------------------------------------------------------------- diff --git a/cmd/traffic_ctl/traffic_ctl.h b/cmd/traffic_ctl/traffic_ctl.h index 62d2c5e..17e7af3 100644 --- a/cmd/traffic_ctl/traffic_ctl.h +++ b/cmd/traffic_ctl/traffic_ctl.h @@ -75,10 +75,9 @@ struct CtrlMgmtRecord } TSMgmtError fetch(const char *); + const char * name() const; TSRecordT type() const; - const char * c_str() const; - int64_t as_int() const; private: @@ -86,7 +85,28 @@ private: CtrlMgmtRecord& operator=(const CtrlMgmtRecord&); // disabled TSRecordEle * ele; - mutable char nbuf[32]; + + friend struct CtrlMgmtRecordValue; +}; + +struct CtrlMgmtRecordValue +{ + explicit CtrlMgmtRecordValue(const TSRecordEle *); + explicit CtrlMgmtRecordValue(const CtrlMgmtRecord&); + + CtrlMgmtRecordValue(TSRecordT, TSRecordValueT); + const char * c_str() const; + +private: + CtrlMgmtRecordValue(const CtrlMgmtRecordValue&); // disabled + CtrlMgmtRecordValue& operator=(const CtrlMgmtRecordValue&); // disabled + void init(TSRecordT, TSRecordValueT); + + TSRecordT rec_type; + union { + const char * str; + char nbuf[32]; + } fmt; }; struct CtrlMgmtRecordList http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/lib/records/I_RecCore.h ---------------------------------------------------------------------- diff --git a/lib/records/I_RecCore.h b/lib/records/I_RecCore.h index 40bf46c..5b5ffe0 100644 --- a/lib/records/I_RecCore.h +++ b/lib/records/I_RecCore.h @@ -31,6 +31,7 @@ #include "I_RecSignals.h" #include "I_RecEvents.h" +struct RecRecord; //------------------------------------------------------------------------- // Diagnostic Output @@ -163,6 +164,9 @@ int RecGetRecordBool(const char *name, RecBool * rec_byte, bool lock = true); //------------------------------------------------------------------------ // Record Attributes Reading //------------------------------------------------------------------------ + +int RecLookupRecord(const char *name, void (*callback)(const RecRecord *, void *), void * data, bool lock = true); + int RecGetRecordType(const char *name, RecT * rec_type, bool lock = true); int RecGetRecordDataType(const char *name, RecDataT * data_type, bool lock = true); int RecGetRecordPersistenceType(const char *name, RecPersistT * persist_type, bool lock = true); @@ -301,6 +305,4 @@ int RecSetSyncRequired(char *name, bool lock = true); typedef void *(*RecManagerCb) (void *opaque_cb_data, char *data_raw, int data_len); int RecRegisterManagerCb(int _signal, RecManagerCb _fn, void *_data = NULL); -void RecResizeAdditional(int add); - #endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/lib/records/RecCore.cc ---------------------------------------------------------------------- diff --git a/lib/records/RecCore.cc b/lib/records/RecCore.cc index 848eed4..f24cd84 100644 --- a/lib/records/RecCore.cc +++ b/lib/records/RecCore.cc @@ -422,6 +422,31 @@ RecGetRecordBool(const char *name, RecBool *rec_bool, bool lock) //------------------------------------------------------------------------- // RecGetRec Attributes //------------------------------------------------------------------------- + +int +RecLookupRecord(const char *name, void (*callback)(const RecRecord *, void *), void * data, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + callback(r, data); + err = REC_ERR_OKAY; + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + int RecGetRecordType(const char *name, RecT * rec_type, bool lock) { http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/CoreAPI.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPI.cc b/mgmt/api/CoreAPI.cc index f48fd01..ded05d0 100644 --- a/mgmt/api/CoreAPI.cc +++ b/mgmt/api/CoreAPI.cc @@ -557,6 +557,12 @@ MgmtRecordGetMatching(const char * /* regex */, TSList /* rec_vals */) return TS_ERR_FAIL; } +TSMgmtError +MgmtConfigRecordDescribe(const char * /* rec_name */, unsigned /* flags */, TSConfigRecordDescription * /* val */) +{ + return TS_ERR_NOT_SUPPORTED; +} + /*------------------------------------------------------------------------- * reads the RecordsConfig info to determine which type of action is needed * when the record rec_name is changed; if the rec_name is invalid, http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/CoreAPI.h ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPI.h b/mgmt/api/CoreAPI.h index b7a434f..5c79843 100644 --- a/mgmt/api/CoreAPI.h +++ b/mgmt/api/CoreAPI.h @@ -66,6 +66,7 @@ TSMgmtError MgmtRecordSetFloat(const char * rec_name, MgmtFloat float_val, TSAct TSMgmtError MgmtRecordSetString(const char * rec_name, const char * string_val, TSActionNeedT * action_need); TSMgmtError MgmtRecordGetMatching(const char * regex, TSList rec_vals); +TSMgmtError MgmtConfigRecordDescribe(const char * rec_name, unsigned flags, TSConfigRecordDescription * val); /*************************************************************************** * File Operations http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/CoreAPIRemote.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPIRemote.cc b/mgmt/api/CoreAPIRemote.cc index cc462d8..24e3c0b 100644 --- a/mgmt/api/CoreAPIRemote.cc +++ b/mgmt/api/CoreAPIRemote.cc @@ -427,7 +427,6 @@ Restart(unsigned options) return ret; } - /*------------------------------------------------------------------------- * Bounce *------------------------------------------------------------------------- @@ -464,6 +463,35 @@ StorageDeviceCmdOffline(char const* dev) /*************************************************************************** * Record Operations ***************************************************************************/ + +static void +mgmt_record_convert_value(TSRecordT rec_type, const MgmtMarshallData& data, TSRecordValueT& value) +{ + // convert the record value to appropriate type + if (data.ptr) { + switch (rec_type) { + case TS_REC_INT: + ink_assert(data.len == sizeof(TSInt)); + value.int_val = *(TSInt *)data.ptr; + break; + case TS_REC_COUNTER: + ink_assert(data.len == sizeof(TSCounter)); + value.counter_val = *(TSCounter *)data.ptr; + break; + case TS_REC_FLOAT: + ink_assert(data.len == sizeof(TSFloat)); + value.float_val = *(TSFloat *)data.ptr; + break; + case TS_REC_STRING: + ink_assert(data.len == strlen((char *)data.ptr) + 1); + value.string_val = ats_strdup((char *)data.ptr); + break; + default: + ; // nothing ... shut up compiler! + } + } +} + static TSMgmtError mgmt_record_get_reply(OpType op, TSRecordEle * rec_ele) { @@ -472,8 +500,8 @@ mgmt_record_get_reply(OpType op, TSRecordEle * rec_ele) MgmtMarshallData reply = { NULL, 0 }; MgmtMarshallInt err; MgmtMarshallInt type; - MgmtMarshallString name; - MgmtMarshallData value; + MgmtMarshallString name = NULL; + MgmtMarshallData value = { NULL, 0 }; ink_zero(*rec_ele); rec_ele->rec_type = TS_REC_UNDEFINED; @@ -487,50 +515,22 @@ mgmt_record_get_reply(OpType op, TSRecordEle * rec_ele) ret = recv_mgmt_response(reply.ptr, reply.len, op, &err, &type, &name, &value); ats_free(reply.ptr); if (ret != TS_ERR_OKAY) { - return ret; + goto done; } if (err != TS_ERR_OKAY) { - ats_free(name); - ats_free(value.ptr); - return (TSMgmtError)err; + ret = (TSMgmtError)err; + goto done; } rec_ele->rec_type = (TSRecordT)type; + rec_ele->rec_name = ats_strdup(name); + mgmt_record_convert_value(rec_ele->rec_type, value, rec_ele->valueT); - // convert the record value to appropriate type - if (value.ptr) { - switch (rec_ele->rec_type) { - case TS_REC_INT: - ink_assert(value.len == sizeof(TSInt)); - rec_ele->valueT.int_val = *(TSInt *)value.ptr; - break; - case TS_REC_COUNTER: - ink_assert(value.len == sizeof(TSCounter)); - rec_ele->valueT.counter_val = *(TSCounter *)value.ptr; - break; - case TS_REC_FLOAT: - ink_assert(value.len == sizeof(TSFloat)); - rec_ele->valueT.float_val = *(TSFloat *)value.ptr; - break; - case TS_REC_STRING: - ink_assert(value.len == strlen((char *)value.ptr) + 1); - rec_ele->valueT.string_val = ats_strdup((char *)value.ptr); - break; - default: - ; // nothing ... shut up compiler! - } - } - - // The record takes ownership of the (non-empty) name. - if (strlen(name)) { - rec_ele->rec_name = name; - } else { - ats_free(name); - } - +done: + ats_free(name); ats_free(value.ptr); - return TS_ERR_OKAY; + return ret; } // note that the record value is being sent as chunk of memory, regardless of @@ -552,6 +552,82 @@ MgmtRecordGet(const char *rec_name, TSRecordEle * rec_ele) } TSMgmtError +MgmtConfigRecordDescribe(const char *rec_name, unsigned options, TSConfigRecordDescription * val) +{ + TSMgmtError ret; + MgmtMarshallInt optype = RECORD_DESCRIBE_CONFIG; + MgmtMarshallInt flags = options; + MgmtMarshallString record = const_cast<MgmtMarshallString>(rec_name); + + MgmtMarshallData reply = { NULL, 0 }; + + // create and send request + ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, RECORD_DESCRIBE_CONFIG, &optype, &record, &flags); + if (ret != TS_ERR_OKAY) { + return ret; + } + + ret = recv_mgmt_message(main_socket_fd, reply); + if (ret != TS_ERR_OKAY) { + return ret; + } else { + MgmtMarshallInt err; + MgmtMarshallString name = NULL; + MgmtMarshallString expr = NULL; + MgmtMarshallData value = { NULL, 0 }; + MgmtMarshallData deflt = { NULL, 0 }; + + MgmtMarshallInt rtype; + MgmtMarshallInt rclass; + MgmtMarshallInt version; + MgmtMarshallInt rsb; + MgmtMarshallInt order; + MgmtMarshallInt access; + MgmtMarshallInt update; + MgmtMarshallInt updatetype; + MgmtMarshallInt checktype; + + ret = recv_mgmt_response(reply.ptr, reply.len, RECORD_DESCRIBE_CONFIG, &err, &name, &value, &deflt, &rtype, + &rclass, &version, &rsb, &order, &access, &update, &updatetype, &checktype, &expr); + + ats_free(reply.ptr); + + if (ret != TS_ERR_OKAY) { + goto done; + } + + if (err != TS_ERR_OKAY) { + ret = (TSMgmtError)err; + goto done; + } + + // Everything is cool, populate the description ... + val->rec_name = ats_strdup(name); + val->rec_checkexpr = ats_strdup(expr); + val->rec_type = (TSRecordT)rtype; + val->rec_class = rclass; + val->rec_version = version; + val->rec_rsb = rsb; + val->rec_order = order; + val->rec_access = access; + val->rec_updatetype = updatetype; + val->rec_checktype = checktype; + + mgmt_record_convert_value(val->rec_type, value, val->rec_value); + mgmt_record_convert_value(val->rec_type, deflt, val->rec_default); + +done: + ats_free(name); + ats_free(expr); + ats_free(value.ptr); + ats_free(deflt.ptr); + return ret; + } + + return ret; +} + +TSMgmtError MgmtRecordGetMatching(const char * regex, TSList rec_vals) { TSMgmtError ret; @@ -661,7 +737,6 @@ MgmtRecordSetFloat(const char *rec_name, MgmtFloat float_val, TSActionNeedT * ac return ret; } - TSMgmtError MgmtRecordSetString(const char *rec_name, const char *string_val, TSActionNeedT * action_need) { @@ -674,7 +749,6 @@ MgmtRecordSetString(const char *rec_name, const char *string_val, TSActionNeedT return ret; } - /*************************************************************************** * File Operations ***************************************************************************/ @@ -981,4 +1055,3 @@ StatsReset(bool cluster, const char * stat_name) ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &optype, &name); return (ret == TS_ERR_OKAY) ? parse_generic_response(op, main_socket_fd) : ret; } - http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/INKMgmtAPI.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/INKMgmtAPI.cc b/mgmt/api/INKMgmtAPI.cc index c84d83f..c7e1bbe 100644 --- a/mgmt/api/INKMgmtAPI.cc +++ b/mgmt/api/INKMgmtAPI.cc @@ -45,7 +45,6 @@ // forward declarations void init_pdss_format(TSPdSsFormat& info); - /*************************************************************************** * API Memory Management ***************************************************************************/ @@ -73,7 +72,6 @@ _TSfree(void *ptr) ats_free(ptr); } - /*************************************************************************** * API Helper Functions for Data Carrier Structures ***************************************************************************/ @@ -212,7 +210,6 @@ TSIpAddrListEnqueue(TSIpAddrList ip_addrl, TSIpAddrEle * ip_addr) } } - /* The the TSIpAddrEle returned is actually removed from the end of list */ tsapi TSIpAddrEle * TSIpAddrListDequeue(TSIpAddrList ip_addrl) @@ -224,7 +221,6 @@ TSIpAddrListDequeue(TSIpAddrList ip_addrl) return (TSIpAddrEle *) dequeue((LLQ *) ip_addrl); } - tsapi int TSIpAddrListLen(TSIpAddrList ip_addrl) { @@ -370,7 +366,6 @@ TSPortListIsValid(TSPortList portl) return true; } - /*--- TSDomainList operations -----------------------------------------*/ tsapi TSDomainList TSDomainListCreate() @@ -657,7 +652,6 @@ TSIntListIsValid(TSIntList intl, int min, int max) return true; } - // helper fn that sets default values for the info passed in void init_pdss_format(TSPdSsFormat& info) @@ -948,7 +942,6 @@ TSCongestionEleDestroy(TSCongestionEle * ele) return; } - /*------------------------------------------------------------- * HostingObj *-------------------------------------------------------------*/ @@ -1043,7 +1036,6 @@ TSIpAllowEleDestroy(TSIpAllowEle * ele) } - /*------------------------------------------------------------- * TSLogFilterEle *-------------------------------------------------------------*/ @@ -1513,7 +1505,6 @@ END: return ret; } - /*------------------------------------------------------------------------- * TSRecordGetMlt *------------------------------------------------------------------------- @@ -1586,7 +1577,6 @@ TSRecordSet(const char *rec_name, const char *val, TSActionNeedT * action_need) return MgmtRecordSet(rec_name, val, action_need); } - tsapi TSMgmtError TSRecordSetInt(const char *rec_name, TSInt int_val, TSActionNeedT * action_need) { @@ -1611,7 +1601,6 @@ TSRecordSetString(const char *rec_name, const char *str_val, TSActionNeedT * act return MgmtRecordSetString(rec_name, str_val, action_need); } - /*------------------------------------------------------------------------- * TSRecordSetMlt *------------------------------------------------------------------------- @@ -1822,7 +1811,6 @@ TSStorageDeviceCmdOffline(char const* dev) return StorageDeviceCmdOffline(dev); } - /*--- diags output operations ---------------------------------------------*/ tsapi void TSDiags(TSDiagsT mode, const char *fmt, ...) @@ -1900,7 +1888,6 @@ TSGetErrorMessage(TSMgmtError err_id) return err_msg; } - /*--- password operations -------------------------------------------------*/ tsapi TSMgmtError TSEncryptPassword(char *passwd, char **e_passwd) @@ -1941,7 +1928,6 @@ TSConfigFileWrite(TSFileNameT file, char *text, int size, int version) return WriteFile(file, text, size, version); } - /* ReadFromUrl: reads a remotely located config file into a buffer * Input: url - remote location of the file * header - a buffer is allocated on the header char* pointer @@ -2376,7 +2362,6 @@ TSCfgContextMoveEleDown(TSCfgContext ctx, int index) return CfgContextMoveEleDown((CfgContext *) ctx, index); } - TSMgmtError TSCfgContextAppendEle(TSCfgContext ctx, TSCfgEle * ele) { @@ -2413,3 +2398,30 @@ TSIsValid(TSCfgEle * ele) ele_obj = create_ele_obj_from_ele(ele); return (ele_obj->isValid()); } + +void +TSConfigRecordDescriptionFree(TSConfigRecordDescription * val) +{ + if (val) { + ats_free(val->rec_name); + ats_free(val->rec_checkexpr); + + if (val->rec_type == TS_REC_STRING) { + ats_free(val->rec_value.string_val); + } + + ink_zero(*val); + val->rec_type = TS_REC_UNDEFINED; + } +} + +TSMgmtError +TSConfigRecordDescribe(const char * rec_name, unsigned flags, TSConfigRecordDescription * val) +{ + if (!rec_name || !val) { + return TS_ERR_PARAMS; + } + + TSConfigRecordDescriptionFree(val); + return MgmtConfigRecordDescribe(rec_name, flags, val); +} http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/NetworkMessage.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/NetworkMessage.cc b/mgmt/api/NetworkMessage.cc index 828be32..66c7e6f 100644 --- a/mgmt/api/NetworkMessage.cc +++ b/mgmt/api/NetworkMessage.cc @@ -29,7 +29,7 @@ #include "NetworkMessage.h" #define MAX_OPERATION_BUFSZ 1024 -#define MAX_OPERATION_FIELDS 10 +#define MAX_OPERATION_FIELDS 16 struct NetCmdOperation { @@ -65,6 +65,7 @@ static const struct NetCmdOperation requests[] = { /* RECORD_MATCH_GET */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING } }, /* API_PING */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT } }, /* SERVER_BACKTRACE */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT } }, + /* RECORD_DESCRIBE_CONFIG */ { 3, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT } }, }; // Responses always begin with a TSMgmtError code, followed by additional fields. @@ -95,6 +96,12 @@ static const struct NetCmdOperation responses[] = { /* RECORD_MATCH_GET */ { 4, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_DATA } }, /* API_PING */ { 0, {} }, // no reply /* SERVER_BACKTRACE */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING } }, + /* RECORD_DESCRIBE_CONFIG */ { 14, { MGMT_MARSHALL_INT /* status */, + MGMT_MARSHALL_STRING /* name */, MGMT_MARSHALL_DATA /* value */, MGMT_MARSHALL_DATA /* default */, + MGMT_MARSHALL_INT /* type */, MGMT_MARSHALL_INT /* class */, MGMT_MARSHALL_INT /* version */, + MGMT_MARSHALL_INT /* rsb */, MGMT_MARSHALL_INT /* order */, MGMT_MARSHALL_INT /* access */, + MGMT_MARSHALL_INT /* update */, MGMT_MARSHALL_INT /* updatetype */, MGMT_MARSHALL_INT /* checktype */, + MGMT_MARSHALL_STRING /* checkexpr */} }, }; #define GETCMD(ops, optype, cmd) do { \ @@ -221,6 +228,15 @@ send_mgmt_error(int fd, OpType optype, TSMgmtError error) ink_release_assert(responses[optype].nfields == 4); return send_mgmt_response(fd, optype, &ecode, &intval, &strval, &dataval); + case RECORD_DESCRIBE_CONFIG: + ink_release_assert(responses[optype].nfields == 14); + return send_mgmt_response(fd, optype, &ecode, + &strval /* name */, &dataval /* value */, &dataval /* default */, + &intval /* type */, &intval /* class */, &intval /* version */, + &intval /* rsb */, &intval /* order */, &intval /* access */, + &intval /* update */, &intval /* updatetype */, &intval /* checktype */, + &strval /* checkexpr */); + case EVENT_REG_CALLBACK: case EVENT_UNREG_CALLBACK: case EVENT_NOTIFY: http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/NetworkMessage.h ---------------------------------------------------------------------- diff --git a/mgmt/api/NetworkMessage.h b/mgmt/api/NetworkMessage.h index feb34cd..923fb7c 100644 --- a/mgmt/api/NetworkMessage.h +++ b/mgmt/api/NetworkMessage.h @@ -60,9 +60,12 @@ typedef enum RECORD_MATCH_GET, API_PING, SERVER_BACKTRACE, + RECORD_DESCRIBE_CONFIG, UNDEFINED_OP /* This must be last */ } OpType; +#define MGMT_OPERATION_TYPE_MAX (UNDEFINED_OP) + struct mgmt_message_sender { virtual TSMgmtError send(void * msg, size_t msglen) const = 0; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/TSControlMain.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/TSControlMain.cc b/mgmt/api/TSControlMain.cc index 9eff803..8f8633e 100644 --- a/mgmt/api/TSControlMain.cc +++ b/mgmt/api/TSControlMain.cc @@ -263,6 +263,39 @@ ts_ctrl_main(void *arg) */ static TSMgmtError +marshall_rec_data(RecDataT rec_type, const RecData& rec_data, MgmtMarshallData& data) +{ + switch (rec_type) { + case TS_REC_INT: + data.ptr = const_cast<RecInt *>(&rec_data.rec_int); + data.len = sizeof(TSInt); + break; + case TS_REC_COUNTER: + data.ptr = const_cast<RecCounter *>(&rec_data.rec_counter); + data.len = sizeof(TSCounter); + break; + case TS_REC_FLOAT: + data.ptr = const_cast<RecFloat *>(&rec_data.rec_float); + data.len = sizeof(TSFloat); + break; + case TS_REC_STRING: + // Make sure to send the NULL in the string value response. + if (rec_data.rec_string) { + data.ptr = rec_data.rec_string; + data.len = strlen(rec_data.rec_string) + 1; + } else { + data.ptr = (void *)"NULL"; + data.len = countof("NULL"); + } + break; + default: // invalid record type + return TS_ERR_FAIL; + } + + return TS_ERR_OKAY; +} + +static TSMgmtError send_record_get_response(int fd, TSRecordT rec_type, const char * rec_name, const void * rec_data, size_t data_len) { MgmtMarshallInt err = TS_ERR_OKAY; @@ -971,6 +1004,94 @@ handle_server_backtrace(int fd, void * req, size_t reqlen) return (TSMgmtError)err; } +static void +send_record_describe(const RecRecord * rec, void * ptr) +{ + MgmtMarshallString rec_name = const_cast<char *>(rec->name); + MgmtMarshallData rec_value = { NULL, 0 }; + MgmtMarshallData rec_default { NULL, 0 }; + MgmtMarshallInt rec_type = rec->data_type; + MgmtMarshallInt rec_class = rec->rec_type; + MgmtMarshallInt rec_version = rec->version; + MgmtMarshallInt rec_rsb = rec->rsb_id; + MgmtMarshallInt rec_order = rec->order; + MgmtMarshallInt rec_access = rec->config_meta.access_type; + MgmtMarshallInt rec_update = rec->config_meta.update_required; + MgmtMarshallInt rec_updatetype = rec->config_meta.update_type; + MgmtMarshallInt rec_checktype = rec->config_meta.check_type; + MgmtMarshallString rec_checkexpr = rec->config_meta.check_expr; + + MgmtMarshallInt err = TS_ERR_OKAY; + + int * fderr = (int *)ptr; + + // We only describe config variables (for now). + if (!REC_TYPE_IS_CONFIG(rec->rec_type)) { + *fderr = TS_ERR_PARAMS; + return; + } + + switch (rec_type) { + case RECD_INT: rec_type = TS_REC_INT; break; + case RECD_FLOAT: rec_type = TS_REC_FLOAT; break; + case RECD_STRING: rec_type = TS_REC_STRING; break; + case RECD_COUNTER: rec_type = TS_REC_COUNTER; break; + default: rec_type = TS_REC_UNDEFINED; + } + + err = marshall_rec_data(rec->data_type, rec->data, rec_value); + if (err != TS_ERR_OKAY) { + goto done; + } + + err = marshall_rec_data(rec->data_type, rec->data_default, rec_default); + if (err != TS_ERR_OKAY) { + goto done; + } + + err = send_mgmt_response(*fderr, RECORD_DESCRIBE_CONFIG, &err, + &rec_name, &rec_value, &rec_default, &rec_type, &rec_class, &rec_version, &rec_rsb, &rec_order, + &rec_access, &rec_update, &rec_updatetype, &rec_checktype, &rec_checkexpr); + +done: + *fderr = err; +} + +static TSMgmtError +handle_record_describe(int fd, void * req, size_t reqlen) +{ + TSMgmtError ret; + MgmtMarshallInt optype; + MgmtMarshallInt options; + MgmtMarshallString name; + + int fderr = fd; // [in,out] variable for the fd and error + + ret = recv_mgmt_request(req, reqlen, RECORD_DESCRIBE_CONFIG, &optype, &name, &options); + if (ret != TS_ERR_OKAY) { + return ret; + } + + if (strlen(name) == 0) { + ret = TS_ERR_PARAMS; + goto done; + } + + if (RecLookupRecord(name, send_record_describe, &fderr) != REC_ERR_OKAY) { + ret = TS_ERR_PARAMS; + goto done; + } + + // If the lookup succeeded, the final error is in "fderr". + if (ret == TS_ERR_OKAY) { + ret = (TSMgmtError)fderr; + } + +done: + ats_free(name); + return ret; +} + struct control_message_handler { unsigned flags; @@ -1003,9 +1124,14 @@ static const control_message_handler handlers[] = { /* STORAGE_DEVICE_CMD_OFFLINE */ { MGMT_API_PRIVILEGED, handle_storage_device_cmd_offline }, /* RECORD_MATCH_GET */ { 0, handle_record_match }, /* API_PING */ { 0, handle_api_ping }, - /* SERVER_BACKTRACE */ { MGMT_API_PRIVILEGED, handle_server_backtrace } + /* SERVER_BACKTRACE */ { MGMT_API_PRIVILEGED, handle_server_backtrace }, + /* RECORD_DESCRIBE_CONFIG */ { 0, handle_record_describe } }; +// This should use countof(), but we need a constexpr :-/ +#define NUM_OP_HANDLERS (sizeof(handlers)/sizeof(handlers[0])) +extern char __msg_handler_static_assert[NUM_OP_HANDLERS == MGMT_OPERATION_TYPE_MAX ? 0 : -1]; + static TSMgmtError handle_control_message(int fd, void * req, size_t reqlen) { http://git-wip-us.apache.org/repos/asf/trafficserver/blob/857766c5/mgmt/api/include/mgmtapi.h ---------------------------------------------------------------------- diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h index 156e5b2..47e4b06 100644 --- a/mgmt/api/include/mgmtapi.h +++ b/mgmt/api/include/mgmtapi.h @@ -110,6 +110,7 @@ extern "C" typedef int64_t TSInt; typedef int64_t TSCounter; typedef float TSFloat; + typedef bool TSBool; typedef char *TSString; typedef char *TSIpAddr; @@ -432,19 +433,44 @@ extern "C" /*--- records -------------------------------------------------------------*/ + typedef union + { /* record value */ + TSInt int_val; + TSCounter counter_val; + TSFloat float_val; + TSString string_val; + } TSRecordValueT; + typedef struct { - char *rec_name; /* record name */ + char *rec_name; /* record name */ TSRecordT rec_type; /* record type {TS_REC_INT...} */ - union - { /* record value */ - TSInt int_val; - TSCounter counter_val; - TSFloat float_val; - TSString string_val; - } valueT; + TSRecordValueT valueT; /* record value */ } TSRecordEle; + typedef struct + { + /* Common RecRecord fields ... */ + char * rec_name; + TSRecordValueT rec_value; + TSRecordValueT rec_default; + TSRecordT rec_type; /* data type (RecDataT) */ + TSInt rec_class; /* data class (RecT) */ + TSInt rec_version; + TSInt rec_rsb; /* Raw Stat Block ID */ + TSInt rec_order; + + /* RecConfigMeta fields ... */ + TSInt rec_access; /* access rights (RecAccessT) */ + TSInt rec_update; /* update_required bitmask */ + TSInt rec_updatetype; /* update type (RecUpdateT) */ + TSInt rec_checktype; /* syntax check type (RecCheckT) */ + char * rec_checkexpr; /* syntax check expression */ + } TSConfigRecordDescription; + + /* Free (the contents of) a TSConfigRecordDescription */ + tsapi void TSConfigRecordDescriptionFree(TSConfigRecordDescription * val); + /*--- events --------------------------------------------------------------*/ /* Note: Each event has a format String associated with it from which the @@ -1160,6 +1186,14 @@ extern "C" tsapi TSMgmtError TSRecordSetFloat(const char *rec_name, TSFloat float_val, TSActionNeedT * action_need); tsapi TSMgmtError TSRecordSetString(const char *rec_name, const char *string_val, TSActionNeedT * action_need); +/* TSConfigRecordDescribe: fetch a full description of a configuration record + * Input: rec_name - name of the record + * flags - (unused) fetch flags bitmask + * val - output value; + * Output: TSMgmtError + */ + tsapi TSMgmtError TSConfigRecordDescribe(const char * rec_name, unsigned flags, TSConfigRecordDescription * val); + /* TSRecordSetMlt: sets a set of records * Input: rec_list - list of record names the user wants to set; * if one set fails, transaction will be aborted
