From 2816009d59ab5809109bd4b61e9c0d0b06d5a36a Mon Sep 17 00:00:00 2001 From: John Rushford Date: Fri, 18 Feb 2022 22:14:39 +0000 Subject: [PATCH 1/3] Update traffic_ctl to query HostStatus directly - Updates HostStatus to eliminate stats creation. - Updates traffic_ctl JSON-RPC to query HostStatus directly. - adds in a new persistance mechanism for HosStatus. --- .../command-line/traffic_ctl_jsonrpc.en.rst | 12 +- .../jsonrpc/jsonrpc-api.en.rst | 42 +-- include/shared/rpc/yaml_codecs.h | 2 +- include/tscore/Filenames.h | 1 + proxy/HostStatus.h | 49 ++- src/traffic_ctl_jsonrpc/CtrlCommands.cc | 7 +- src/traffic_ctl_jsonrpc/CtrlPrinters.cc | 15 +- .../jsonrpc/CtrlRPCRequests.h | 24 +- .../jsonrpc/ctrl_yaml_codecs.h | 22 +- src/traffic_ctl_jsonrpc/traffic_ctl.cc | 2 +- src/traffic_server/HostStatus.cc | 315 +++++++++--------- src/traffic_server/RpcAdminPubHandlers.cc | 2 +- src/traffic_server/traffic_server.cc | 2 +- 13 files changed, 271 insertions(+), 224 deletions(-) diff --git a/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst b/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst index e8b72a13926..5973a459b75 100644 --- a/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst +++ b/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst @@ -325,11 +325,10 @@ traffic_ctl host ---------------- .. program:: traffic_ctl host -A stat to track status is created for each host. The name is the host fqdn with a prefix of -"proxy.process.host_status". The value of the stat is a string which is the serialized -representation of the status. This contains the overall status and the status for each reason. The -stats may be viewed using the :program:`traffic_ctl metric` command or through the `stats_over_http` -endpoint. +A record to track status is created for each host. The name is the host fqdn. The value of the +record when retrieved, is a serialized string representation of the status. +This contains the overall status and the status for each reason. The +records may be viewed using the :program:`traffic_ctl host status` command. .. option:: --time count @@ -366,7 +365,8 @@ endpoint. :ref:`admin_lookup_records` Get the current status of the specified hosts with respect to their use as targets for parent - selection. This returns the same information as the per host stat. + selection. This returns the same information as the per host record. If the HOSTNAME arguments + are omitted, all host records available are returned. .. option:: down HOSTNAME [HOSTNAME ...] diff --git a/doc/developer-guide/jsonrpc/jsonrpc-api.en.rst b/doc/developer-guide/jsonrpc/jsonrpc-api.en.rst index b18cc4b532b..3391909fc05 100644 --- a/doc/developer-guide/jsonrpc/jsonrpc-api.en.rst +++ b/doc/developer-guide/jsonrpc/jsonrpc-api.en.rst @@ -1106,9 +1106,9 @@ admin_host_set_status Description ~~~~~~~~~~~ -A stat to track status is created for each host. The name is the host fqdn with a prefix of `proxy.process.host_status`. The value of -the stat is a string which is the serialized representation of the status. This contains the overall status and the status for each reason. -The stats may be viewed using the `admin_lookup_records`_ rpc api or through the ``stats_over_http`` endpoint. +A record to track status is created for each host. The name is the host fqdn. +This record contains the overall status and the status for each reason. +The records may be viewed using the `admin_host_get_status` rpc api. Parameters ~~~~~~~~~~ @@ -1204,11 +1204,8 @@ Response: Getting the host status ~~~~~~~~~~~~~~~~~~~~~~~ -Get the current status of the specified hosts with respect to their use as targets for parent selection. This returns the same -information as the per host stat. - -Although there is no specialized API that you can call to get a status from a particular host you can work away by pulling the right records. -For instance, the ``host1`` that we just set up can be easily fetch for a status: +Get the current status of the specified hosts with respect to their use as targets for parent selection. This returns the serialized +information for the host. Request: @@ -1218,11 +1215,10 @@ Request: { "id": "ded7018e-0720-11eb-abe2-001fc69cc946", "jsonrpc": "2.0", - "method": "admin_lookup_records", - "params": [{ - "record_name": "proxy.process.host_status.host1" - } - ] + "method": "admin_host_get_status", + "params": [ + "host1.mycdn.net" + ] } Response: @@ -1234,23 +1230,11 @@ Response: "jsonrpc": "2.0", "id": "ded7018e-0720-11eb-abe2-001fc69cc946", "result": { - "recordList": [{ - "record": { - "record_name": "proxy.process.host_status.host1", - "record_type": "3", - "version": "0", - "raw_stat_block": "0", - "order": "1134", - "stat_meta": { - "persist_type": "1" - }, - "record_class": "2", - "overridable": "false", - "data_type": "STRING", - "current_value": "HOST_STATUS_UP,ACTIVE:UP:0:0,LOCAL:UP:0:0,MANUAL:UP:0:0,SELF_DETECT:UP:0", - "default_value": "HOST_STATUS_UP,ACTIVE:UP:0:0,LOCAL:UP:0:0,MANUAL:UP:0:0,SELF_DETECT:UP:0" + "statusList": [{ + "hostname": "host1.mycdn.net", + "status": "HOST_STATUS_DOWN,ACTIVE:UP:0:0,LOCAL:UP:0:0,MANUAL:UP:0:0,SELF_DETECT:DOWN:1646248306" } - }] + ] ,"errorList":[] } } diff --git a/include/shared/rpc/yaml_codecs.h b/include/shared/rpc/yaml_codecs.h index 42610dde570..db230ee4ad8 100644 --- a/include/shared/rpc/yaml_codecs.h +++ b/include/shared/rpc/yaml_codecs.h @@ -240,4 +240,4 @@ class yamlcpp_json_emitter return resp; } -}; \ No newline at end of file +}; diff --git a/include/tscore/Filenames.h b/include/tscore/Filenames.h index f2f0718f9bb..24c3edf87e0 100644 --- a/include/tscore/Filenames.h +++ b/include/tscore/Filenames.h @@ -46,6 +46,7 @@ namespace filename /////////////////////////////////////////////////////////////////// // Various other file names constexpr const char *RECORDS_STATS = "records.snap"; + constexpr const char *HOST_RECORDS = "host_records.yaml"; } // namespace filename } // namespace ts diff --git a/proxy/HostStatus.h b/proxy/HostStatus.h index 8649fe97eb0..a04dda042b5 100644 --- a/proxy/HostStatus.h +++ b/proxy/HostStatus.h @@ -33,6 +33,8 @@ #include #include #include +#include "tscore/Filenames.h" +#include "tscore/I_Layout.h" #include "tscore/ink_rwlock.h" #include "records/P_RecProcess.h" @@ -89,6 +91,11 @@ struct Reason { } }; +struct HostStatuses { + std::string hostname; + std::string status; +}; + // host status POD struct HostStatRec { TSHostStatus status; @@ -168,6 +175,35 @@ struct HostStatRec { } }; +struct HostStatusSync; +typedef int (HostStatusSync::*HostStatusSyncHandler)(int, void *); +struct HostStatusSync : public Continuation { + std::string hostRecordsFile; + + void sync_task(); + void + getHostStatusPersistentFilePath() + { + std::string rundir(RecConfigReadRuntimeDir()); + hostRecordsFile = Layout::relative_to(rundir, ts::filename::HOST_RECORDS); + } + +public: + HostStatusSync() + { + getHostStatusPersistentFilePath(); + + SET_HANDLER((HostStatusSyncHandler)&HostStatusSync::mainEvent); + } + + int + mainEvent(int event, Event *e) + { + sync_task(); + return EVENT_DONE; + } +}; + /** * Singleton placeholder for next hop status. */ @@ -182,11 +218,16 @@ struct HostStatus { } void setHostStatus(const std::string_view name, const TSHostStatus status, const unsigned int down_time, const unsigned int reason); - HostStatRec *getHostStatus(const std::string_view name); - void createHostStat(const std::string_view name, const char *data = nullptr); - void loadHostStatusFromStats(); + void loadFromPersistentStore(); void loadRecord(std::string_view name, HostStatRec &h); - RecErrT getHostStat(std::string &stat_name, char *buf, unsigned int buf_len); + HostStatRec *getHostStatus(const std::string_view name); + void getAllHostStatuses(std::vector &hosts); + std::string + getHostStatusPersistentFilePath() + { + std::string rundir(RecConfigReadRuntimeDir()); + return Layout::relative_to(rundir, ts::filename::HOST_RECORDS); + } private: HostStatus(); diff --git a/src/traffic_ctl_jsonrpc/CtrlCommands.cc b/src/traffic_ctl_jsonrpc/CtrlCommands.cc index 96a0fab291c..35e8b4faea6 100644 --- a/src/traffic_ctl_jsonrpc/CtrlCommands.cc +++ b/src/traffic_ctl_jsonrpc/CtrlCommands.cc @@ -312,11 +312,8 @@ void HostCommand::status_get() { auto const &data = _arguments.get("status"); - HostGetStatusRequest request; - for (auto it : data) { - std::string name = std::string{HostGetStatusRequest::STATUS_PREFIX} + "." + it; - request.emplace_rec(name, shared::rpc::NOT_REGEX, shared::rpc::METRIC_REC_TYPES); - } + HostGetStatusRequest request{{std::begin(data), std::end(data)}}; + auto response = invoke_rpc(request); _printer->write_output(response); diff --git a/src/traffic_ctl_jsonrpc/CtrlPrinters.cc b/src/traffic_ctl_jsonrpc/CtrlPrinters.cc index 6351926a14c..25a40fd4cc5 100644 --- a/src/traffic_ctl_jsonrpc/CtrlPrinters.cc +++ b/src/traffic_ctl_jsonrpc/CtrlPrinters.cc @@ -282,12 +282,17 @@ RecordDescribePrinter::write_output_pretty(shared::rpc::RecordLookUpResponse con void GetHostStatusPrinter::write_output(YAML::Node const &result) { - auto response = result.as(); - for (auto &&recordInfo : response.recordList) { - std::cout << recordInfo.name << " " << recordInfo.currentValue << '\n'; + auto resp = result.as(); + + if (resp.statusList.size() > 0) { + for (auto &&host : resp.statusList) { + std::cout << host.hostName << " " << host.status << '\n'; + } + std::cout << '\n'; } - for (auto &&e : response.errorList) { - std::cout << "Failed to fetch " << e.recordName << '\n'; + + for (auto &&e : resp.errorList) { + std::cout << e << '\n'; } } diff --git a/src/traffic_ctl_jsonrpc/jsonrpc/CtrlRPCRequests.h b/src/traffic_ctl_jsonrpc/jsonrpc/CtrlRPCRequests.h index b4466ab5538..f16507045c8 100644 --- a/src/traffic_ctl_jsonrpc/jsonrpc/CtrlRPCRequests.h +++ b/src/traffic_ctl_jsonrpc/jsonrpc/CtrlRPCRequests.h @@ -108,6 +108,16 @@ struct ConfigSetRecordResponse { std::vector data; }; //------------------------------------------------------------------------------------------------------------------------------------ +struct HostStatusLookUpResponse { + struct HostStatusInfo { + std::string hostName; + std::string status; + }; + + std::vector statusList; + std::vector errorList; +}; +//------------------------------------------------------------------------------------------------------------------------------------ struct HostSetStatusRequest : shared::rpc::ClientRequest { using super = shared::rpc::ClientRequest; struct Params { @@ -129,10 +139,16 @@ struct HostSetStatusRequest : shared::rpc::ClientRequest { } }; -struct HostGetStatusRequest : shared::rpc::RecordLookupRequest { - static constexpr auto STATUS_PREFIX = "proxy.process.host_status"; - using super = shared::rpc::RecordLookupRequest; - HostGetStatusRequest() : super() {} +struct HostGetStatusRequest : shared::rpc::ClientRequest { + using super = shared::rpc::ClientRequest; + using Params = std::vector; + HostGetStatusRequest(Params p) { super::params = std::move(p); } + + std::string + get_method() const + { + return "admin_host_get_status"; + } }; //------------------------------------------------------------------------------------------------------------------------------------ struct BasicPluginMessageRequest : shared::rpc::ClientRequest { diff --git a/src/traffic_ctl_jsonrpc/jsonrpc/ctrl_yaml_codecs.h b/src/traffic_ctl_jsonrpc/jsonrpc/ctrl_yaml_codecs.h index 41f81874d27..e2684973318 100644 --- a/src/traffic_ctl_jsonrpc/jsonrpc/ctrl_yaml_codecs.h +++ b/src/traffic_ctl_jsonrpc/jsonrpc/ctrl_yaml_codecs.h @@ -157,5 +157,23 @@ template <> struct convert { return true; } }; -//------------------------------------------------------------------------------------------------------------------------------------ -} // namespace YAML \ No newline at end of file + +template <> struct convert { + static bool + decode(Node const &node, HostStatusLookUpResponse &info) + { + YAML::Node statusList = node["statusList"]; + YAML::Node errorList = node["errorList"]; + for (auto &&item : statusList) { + HostStatusLookUpResponse::HostStatusInfo hi; + hi.hostName = item["hostname"].Scalar(); + hi.status = item["status"].Scalar(); + info.statusList.push_back(hi); + } + for (auto &&item : errorList) { + info.errorList.push_back(item.Scalar()); + } + return true; + } +}; +} // namespace YAML diff --git a/src/traffic_ctl_jsonrpc/traffic_ctl.cc b/src/traffic_ctl_jsonrpc/traffic_ctl.cc index ae567444235..73298806b6c 100644 --- a/src/traffic_ctl_jsonrpc/traffic_ctl.cc +++ b/src/traffic_ctl_jsonrpc/traffic_ctl.cc @@ -93,7 +93,7 @@ main(int argc, const char **argv) config_command.add_command("registry", "Show configuration file registry", [&]() { command->execute(); }) .add_example_usage("traffic_ctl config registry"); // host commands - host_command.add_command("status", "Get one or more host statuses", "", MORE_THAN_ONE_ARG_N, [&]() { command->execute(); }) + host_command.add_command("status", "Get one or more host statuses", "", MORE_THAN_ZERO_ARG_N, [&]() { command->execute(); }) .add_example_usage("traffic_ctl host status HOST [HOST ...]"); host_command.add_command("down", "Set down one or more host(s)", "", MORE_THAN_ONE_ARG_N, [&]() { command->execute(); }) .add_example_usage("traffic_ctl host down HOST [OPTIONS]") diff --git a/src/traffic_server/HostStatus.cc b/src/traffic_server/HostStatus.cc index cb273137013..5d6f2e55c0a 100644 --- a/src/traffic_server/HostStatus.cc +++ b/src/traffic_server/HostStatus.cc @@ -20,85 +20,32 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include #include "HostStatus.h" #include "ProcessManager.h" #include "tscore/BufferWriter.h" #include "rpc/jsonrpc/JsonRPC.h" +#include "shared/rpc/RPCRequests.h" -ts::Rv server_set_status(std::string_view const &id, YAML::Node const ¶ms); - -inline void -getStatName(std::string &stat_name, const std::string_view name) -{ - stat_name.clear(); - stat_name.append(stat_prefix).append(name); -} - -static void -mgmt_host_status_up_callback(ts::MemSpan span) +namespace { - MgmtInt op; - MgmtMarshallString name; - MgmtMarshallInt down_time; - MgmtMarshallString reason_str; - std::string stat_name; - char buf[1024] = {0}; - char *data = static_cast(span.data()); - auto len = span.size(); - static const MgmtMarshallType fields[] = {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}; - Debug("host_statuses", "%s:%s:%d - data: %s, len: %ld\n", __FILE__, __func__, __LINE__, data, len); - - if (mgmt_message_parse(data, len, fields, countof(fields), &op, &name, &reason_str, &down_time) == -1) { - Error("Plugin message - RPC parsing error - message discarded."); - } - Debug("host_statuses", "op: %ld, name: %s, down_time: %d, reason_str: %s", static_cast(op), name, - static_cast(down_time), reason_str); +const std::string STATUS_LIST_KEY{"statusList"}; +const std::string ERROR_LIST_KEY{"errorList"}; +const std::string HOST_NAME_KEY{"hostname"}; +const std::string STATUS_KEY{"status"}; - unsigned int reason = Reason::getReason(reason_str); - - getStatName(stat_name, name); - if (data != nullptr) { - Debug("host_statuses", "marking up server %s", data); - HostStatus &hs = HostStatus::instance(); - if (hs.getHostStat(stat_name, buf, 1024) == REC_ERR_FAIL) { - hs.createHostStat(name); - } - hs.setHostStatus(name, TSHostStatus::TS_HOST_STATUS_UP, down_time, reason); - } -} - -static void -mgmt_host_status_down_callback(ts::MemSpan span) -{ - MgmtInt op; - MgmtMarshallString name; - MgmtMarshallInt down_time; - MgmtMarshallString reason_str; - std::string stat_name; - char *data = static_cast(span.data()); - char buf[1024] = {0}; - auto len = span.size(); - static const MgmtMarshallType fields[] = {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}; - Debug("host_statuses", "%s:%s:%d - data: %s, len: %ld\n", __FILE__, __func__, __LINE__, data, len); - - if (mgmt_message_parse(data, len, fields, countof(fields), &op, &name, &reason_str, &down_time) == -1) { - Error("Plugin message - RPC parsing error - message discarded."); - } - Debug("host_statuses", "op: %ld, name: %s, down_time: %d, reason_str: %s", static_cast(op), name, - static_cast(down_time), reason_str); +struct HostCmdInfo { + TSHostStatus type{TSHostStatus::TS_HOST_STATUS_INIT}; + unsigned int reasonType{0}; + std::vector hosts; + int time{0}; +}; - unsigned int reason = Reason::getReason(reason_str); +} // namespace - if (data != nullptr) { - Debug("host_statuses", "marking down server %s", name); - HostStatus &hs = HostStatus::instance(); - if (hs.getHostStat(stat_name, buf, 1024) == REC_ERR_FAIL) { - hs.createHostStat(name); - } - hs.setHostStatus(name, TSHostStatus::TS_HOST_STATUS_DOWN, down_time, reason); - } -} +ts::Rv server_get_status(std::string_view const &id, YAML::Node const ¶ms); +ts::Rv server_set_status(std::string_view const &id, YAML::Node const ¶ms); HostStatRec::HostStatRec() : status(TS_HOST_STATUS_UP), @@ -187,33 +134,13 @@ HostStatRec::HostStatRec(std::string str) } } -static void -handle_record_read(const RecRecord *rec, void *edata) -{ - HostStatus &hs = HostStatus::instance(); - std::string hostname; - - if (rec) { - Debug("host_statuses", "name: %s", rec->name); - - // parse the hostname from the stat name - char *s = const_cast(rec->name); - // 1st move the pointer past the stat prefix. - s += stat_prefix.length(); - hostname = s; - hs.createHostStat(hostname.c_str(), rec->data.rec_string); - HostStatRec h(rec->data.rec_string); - hs.loadRecord(hostname, h); - } -} - HostStatus::HostStatus() { ink_rwlock_init(&host_status_rwlock); - pmgmt->registerMgmtCallback(MGMT_EVENT_HOST_STATUS_UP, &mgmt_host_status_up_callback); - pmgmt->registerMgmtCallback(MGMT_EVENT_HOST_STATUS_DOWN, &mgmt_host_status_down_callback); + // register JSON-RPC methods. rpc::add_method_handler("admin_host_set_status", &server_set_status, &rpc::core_ats_rpc_service_provider_handle); + rpc::add_method_handler("admin_host_get_status", &server_get_status, &rpc::core_ats_rpc_service_provider_handle); } HostStatus::~HostStatus() @@ -225,14 +152,30 @@ HostStatus::~HostStatus() ink_rwlock_destroy(&host_status_rwlock); } +// loads host status persistent store file void -HostStatus::loadHostStatusFromStats() +HostStatus::loadFromPersistentStore() { - if (RecLookupMatchingRecords(RECT_PROCESS, stat_prefix.c_str(), handle_record_read, nullptr) != REC_ERR_OKAY) { - Error("[HostStatus] - While loading HostStatus stats, there was an Error reading HostStatus stats."); + YAML::Node records; + std::string fileStore = getHostStatusPersistentFilePath(); + if (access(fileStore.c_str(), R_OK) == 0) { + try { + records = YAML::LoadFile(fileStore.c_str()); + YAML::Node statusList = records["statuses"]; + for (YAML::const_iterator it = statusList.begin(); it != statusList.end(); ++it) { + const YAML::Node &host = *it; + std::string hostName = host[HOST_NAME_KEY].as(); + std::string status = host[STATUS_KEY].as(); + HostStatRec h(status); + loadRecord(hostName, h); + } + } catch (std::exception const &ex) { + Warning("Error loading and decoding %s : %s", fileStore.c_str(), ex.what()); + } } } +// loads in host status record. void HostStatus::loadRecord(std::string_view name, HostStatRec &h) { @@ -240,32 +183,20 @@ HostStatus::loadRecord(std::string_view name, HostStatRec &h) Debug("host_statuses", "loading host status record for %.*s", int(name.size()), name.data()); ink_rwlock_wrlock(&host_status_rwlock); { - if (auto it = hosts_statuses.find(std::string(name)); it != hosts_statuses.end()) { - host_stat = it->second; - } else { + auto it = hosts_statuses.find(std::string(name)); + if (it == hosts_statuses.end()) { host_stat = static_cast(ats_malloc(sizeof(HostStatRec))); *host_stat = h; hosts_statuses.emplace(name, host_stat); } } ink_rwlock_unlock(&host_status_rwlock); - - *host_stat = h; } void HostStatus::setHostStatus(const std::string_view name, TSHostStatus status, const unsigned int down_time, const unsigned int reason) { std::string stat_name; - char buf[1024] = {0}; - - getStatName(stat_name, name); - - if (getHostStat(stat_name, buf, 1024) == REC_ERR_FAIL) { - createHostStat(name); - } - - RecErrT result = getHostStat(stat_name, buf, 1024); // update / insert status. // using the hash table pointer to store the TSHostStatus value. @@ -346,21 +277,6 @@ HostStatus::setHostStatus(const std::string_view name, TSHostStatus status, cons } ink_rwlock_unlock(&host_status_rwlock); - // update the stats - if (result == REC_ERR_OKAY) { - std::stringstream status_rec; - status_rec << *host_stat; - RecSetRecordString(stat_name.c_str(), const_cast(status_rec.str().c_str()), REC_SOURCE_EXPLICIT, true); - if (status == TSHostStatus::TS_HOST_STATUS_UP) { - Debug("host_statuses", "set status up for name: %.*s, status: %d, stat_name: %s", int(name.size()), name.data(), status, - stat_name.c_str()); - } else { - Debug("host_statuses", "set status down for name: %.*s, status: %d, stat_name: %s", int(name.size()), name.data(), status, - stat_name.c_str()); - } - } - Debug("host_statuses", "name: %.*s, status: %d", int(name.size()), name.data(), status); - // log it. if (status == TSHostStatus::TS_HOST_STATUS_DOWN) { Note("Host %.*s has been marked down, down_time: %d - %s.", int(name.size()), name.data(), down_time, @@ -370,6 +286,29 @@ HostStatus::setHostStatus(const std::string_view name, TSHostStatus status, cons } } +// retrieve all host statuses. +void +HostStatus::getAllHostStatuses(std::vector &hosts) +{ + if (hosts_statuses.empty()) { + return; + } + + ink_rwlock_rdlock(&host_status_rwlock); + { + for (std::pair hsts : hosts_statuses) { + std::stringstream ss; + HostStatuses h; + h.hostname = hsts.first; + ss << *hsts.second; + h.status = ss.str(); + hosts.push_back(h); + } + } + ink_rwlock_unlock(&host_status_rwlock); +} + +// retrieve the named host status. HostStatRec * HostStatus::getHostStatus(const std::string_view name) { @@ -430,44 +369,6 @@ HostStatus::getHostStatus(const std::string_view name) return _status; } -void -HostStatus::createHostStat(const std::string_view name, const char *data) -{ - char buf[1024] = {0}; - HostStatRec r; - - std::string stat_name; - std::stringstream status_rec; - if (data != nullptr) { - HostStatRec h(data); - r = h; - } - status_rec << r; - getStatName(stat_name, name); - - if (getHostStat(stat_name, buf, 1024) == REC_ERR_FAIL) { - RecRegisterStatString(RECT_PROCESS, stat_name.c_str(), const_cast(status_rec.str().c_str()), RECP_PERSISTENT); - Debug("host_statuses", "stat name: %s, data: %s", stat_name.c_str(), status_rec.str().c_str()); - } -} - -RecErrT -HostStatus::getHostStat(std::string &stat_name, char *buf, unsigned int buf_len) -{ - return RecGetRecordString(stat_name.c_str(), buf, buf_len, true); -} - -namespace -{ -struct HostCmdInfo { - TSHostStatus type{TSHostStatus::TS_HOST_STATUS_INIT}; - unsigned int reasonType{0}; - std::vector hosts; - int time{0}; -}; - -} // namespace - namespace YAML { template <> struct convert { @@ -515,11 +416,65 @@ template <> struct convert { }; } // namespace YAML +// JSON-RPC method to retrieve host status information. +ts::Rv +server_get_status(std::string_view const &id, YAML::Node const ¶ms) +{ + namespace err = rpc::handlers::errors; + ts::Rv resp; + YAML::Node statusList{YAML::NodeType::Sequence}, errorList{YAML::NodeType::Sequence}; + + try { + if (!params.IsNull() && params.size() > 0) { // returns host statuses for just the ones asked for. + for (YAML::const_iterator it = params.begin(); it != params.end(); ++it) { + YAML::Node host{YAML::NodeType::Map}; + auto name = it->as(); + HostStatRec *host_rec = nullptr; + HostStatus &hs = HostStatus::instance(); + host_rec = hs.getHostStatus(name); + if (host_rec == nullptr) { + Debug("host_statuses", "no record for %s was found", name.c_str()); + errorList.push_back("no record for " + name + " was found"); + continue; + } else { + std::stringstream s; + s << *host_rec; + host[HOST_NAME_KEY] = name; + host[STATUS_KEY] = s.str(); + statusList.push_back(host); + Debug("host_statuses", "hostname: %s, status: %s", name.c_str(), s.str().c_str()); + } + } + } else { // return all host statuses. + std::vector hostInfo; + HostStatus &hs = HostStatus::instance(); + hs.getAllHostStatuses(hostInfo); + for (auto &h : hostInfo) { + YAML::Node host{YAML::NodeType::Map}; + host[HOST_NAME_KEY] = h.hostname; + host[STATUS_KEY] = h.status; + statusList.push_back(host); + } + } + } catch (std::exception const &ex) { + Debug("host_statuses", "Got an error decoding the parameters: %s", ex.what()); + errorList.push_back("Error decoding parameters : " + std::string(ex.what())); + } + + resp.result()[STATUS_LIST_KEY] = statusList; + resp.result()[ERROR_LIST_KEY] = errorList; + + return resp; +} + +// JSON-RPC method to mark up or down a host. ts::Rv server_set_status(std::string_view const &id, YAML::Node const ¶ms) { + Debug("host_statuses", "id=%s", id.data()); namespace err = rpc::handlers::errors; ts::Rv resp; + try { if (!params.IsNull()) { auto cmdInfo = params.as(); @@ -527,10 +482,6 @@ server_set_status(std::string_view const &id, YAML::Node const ¶ms) for (auto const &name : cmdInfo.hosts) { HostStatus &hs = HostStatus::instance(); std::string statName = stat_prefix + name; - char buf[1024] = {0}; - if (hs.getHostStat(statName, buf, 1024) == REC_ERR_FAIL) { - hs.createHostStat(name.c_str()); - } Debug("host_statuses", "marking server %s : %s", name.c_str(), (cmdInfo.type == TSHostStatus::TS_HOST_STATUS_UP ? "up" : "down")); hs.setHostStatus(name.c_str(), cmdInfo.type, cmdInfo.time, cmdInfo.reasonType); @@ -538,9 +489,43 @@ server_set_status(std::string_view const &id, YAML::Node const ¶ms) } else { resp.errata().push(err::make_errata(err::Codes::SERVER, "Invalid input parameters, null")); } + + // schedule a write to the persistent store. + Debug("host_statuses", "updating persistent store"); + eventProcessor.schedule_imm(new HostStatusSync, ET_TASK); } catch (std::exception const &ex) { Debug("host_statuses", "Got an error HostCmdInfo decoding: %s", ex.what()); resp.errata().push(err::make_errata(err::Codes::SERVER, "Error found during host status set: {}", ex.what())); } return resp; } + +// method to write host status records to the persistent store. +void +HostStatusSync::sync_task() +{ + YAML::Node records{YAML::NodeType::Map}; + + YAML::Node statusList{YAML::NodeType::Sequence}; + std::vector statuses; + HostStatus &hs = HostStatus::instance(); + hs.getAllHostStatuses(statuses); + + for (auto &&h : statuses) { + YAML::Node host{YAML::NodeType::Map}; + host[HOST_NAME_KEY] = h.hostname; + host[STATUS_KEY] = h.status; + statusList.push_back(host); + } + records["statuses"] = statusList; + + std::ofstream fout; + fout.open(hostRecordsFile.c_str(), std::ofstream::out | std::ofstream::trunc); + if (fout) { + fout << records; + fout << '\n'; + fout.close(); + } else { + Warning("failed to open %s for writing", hostRecordsFile.c_str()); + } +} diff --git a/src/traffic_server/RpcAdminPubHandlers.cc b/src/traffic_server/RpcAdminPubHandlers.cc index 32422ffed36..d97d668aa7e 100644 --- a/src/traffic_server/RpcAdminPubHandlers.cc +++ b/src/traffic_server/RpcAdminPubHandlers.cc @@ -60,4 +60,4 @@ register_admin_jsonrpc_handlers() rpc::add_method_handler("admin_storage_set_device_offline", &set_storage_offline, &core_ats_rpc_service_provider_handle); rpc::add_method_handler("admin_storage_get_device_status", &get_storage_status, &core_ats_rpc_service_provider_handle); } -} // namespace rpc::admin \ No newline at end of file +} // namespace rpc::admin diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc index 54289fadf8a..4b5cd77a120 100644 --- a/src/traffic_server/traffic_server.cc +++ b/src/traffic_server/traffic_server.cc @@ -2162,7 +2162,7 @@ main(int /* argc ATS_UNUSED */, const char **argv) RecProcessStart(); initCacheControl(); IpAllow::startup(); - HostStatus::instance().loadHostStatusFromStats(); + HostStatus::instance().loadFromPersistentStore(); netProcessor.init_socks(); ParentConfig::startup(); SplitDNSConfig::startup(); From 1332a662d91bd1754ad295a03c4fa0f8d09ae5dc Mon Sep 17 00:00:00 2001 From: John Rushford Date: Tue, 15 Mar 2022 20:42:18 +0000 Subject: [PATCH 2/3] Changes from review comments. --- doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst | 3 +-- proxy/HostStatus.h | 4 +--- src/traffic_server/HostStatus.cc | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst b/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst index 5973a459b75..acfe4f267c9 100644 --- a/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst +++ b/doc/appendices/command-line/traffic_ctl_jsonrpc.en.rst @@ -365,8 +365,7 @@ records may be viewed using the :program:`traffic_ctl host status` command. :ref:`admin_lookup_records` Get the current status of the specified hosts with respect to their use as targets for parent - selection. This returns the same information as the per host record. If the HOSTNAME arguments - are omitted, all host records available are returned. + selection. If the HOSTNAME arguments are omitted, all host records available are returned. .. option:: down HOSTNAME [HOSTNAME ...] diff --git a/proxy/HostStatus.h b/proxy/HostStatus.h index a04dda042b5..2a73dbca655 100644 --- a/proxy/HostStatus.h +++ b/proxy/HostStatus.h @@ -175,8 +175,6 @@ struct HostStatRec { } }; -struct HostStatusSync; -typedef int (HostStatusSync::*HostStatusSyncHandler)(int, void *); struct HostStatusSync : public Continuation { std::string hostRecordsFile; @@ -193,7 +191,7 @@ struct HostStatusSync : public Continuation { { getHostStatusPersistentFilePath(); - SET_HANDLER((HostStatusSyncHandler)&HostStatusSync::mainEvent); + SET_HANDLER(&HostStatusSync::mainEvent); } int diff --git a/src/traffic_server/HostStatus.cc b/src/traffic_server/HostStatus.cc index 5d6f2e55c0a..e56a6e24e6c 100644 --- a/src/traffic_server/HostStatus.cc +++ b/src/traffic_server/HostStatus.cc @@ -44,8 +44,8 @@ struct HostCmdInfo { } // namespace -ts::Rv server_get_status(std::string_view const &id, YAML::Node const ¶ms); -ts::Rv server_set_status(std::string_view const &id, YAML::Node const ¶ms); +ts::Rv server_get_status(std::string_view const id, YAML::Node const ¶ms); +ts::Rv server_set_status(std::string_view const id, YAML::Node const ¶ms); HostStatRec::HostStatRec() : status(TS_HOST_STATUS_UP), @@ -418,7 +418,7 @@ template <> struct convert { // JSON-RPC method to retrieve host status information. ts::Rv -server_get_status(std::string_view const &id, YAML::Node const ¶ms) +server_get_status(std::string_view const id, YAML::Node const ¶ms) { namespace err = rpc::handlers::errors; ts::Rv resp; @@ -469,7 +469,7 @@ server_get_status(std::string_view const &id, YAML::Node const ¶ms) // JSON-RPC method to mark up or down a host. ts::Rv -server_set_status(std::string_view const &id, YAML::Node const ¶ms) +server_set_status(std::string_view const id, YAML::Node const ¶ms) { Debug("host_statuses", "id=%s", id.data()); namespace err = rpc::handlers::errors; From b9dd022bcd3d846dadf9b343fa25d97bbd7a9eb0 Mon Sep 17 00:00:00 2001 From: John Rushford Date: Tue, 15 Mar 2022 20:59:42 +0000 Subject: [PATCH 3/3] remove redundant 'const'. --- src/traffic_server/HostStatus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traffic_server/HostStatus.cc b/src/traffic_server/HostStatus.cc index e56a6e24e6c..240f32ade6d 100644 --- a/src/traffic_server/HostStatus.cc +++ b/src/traffic_server/HostStatus.cc @@ -418,7 +418,7 @@ template <> struct convert { // JSON-RPC method to retrieve host status information. ts::Rv -server_get_status(std::string_view const id, YAML::Node const ¶ms) +server_get_status(std::string_view id, YAML::Node const ¶ms) { namespace err = rpc::handlers::errors; ts::Rv resp; @@ -469,7 +469,7 @@ server_get_status(std::string_view const id, YAML::Node const ¶ms) // JSON-RPC method to mark up or down a host. ts::Rv -server_set_status(std::string_view const id, YAML::Node const ¶ms) +server_set_status(std::string_view id, YAML::Node const ¶ms) { Debug("host_statuses", "id=%s", id.data()); namespace err = rpc::handlers::errors;