You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by vm...@apache.org on 2018/07/11 18:24:30 UTC

[trafficserver] branch master updated: add a reason tag to traffic_control host subcommand.

This is an automated email from the ASF dual-hosted git repository.

vmamidi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new b3dbff1  add a reason tag to traffic_control host subcommand.
b3dbff1 is described below

commit b3dbff10a34bdb809914e3671922bffc508befd9
Author: John Rushford <jr...@apache.org>
AuthorDate: Thu Jun 21 17:21:58 2018 +0000

    add a reason tag to traffic_control host subcommand.
---
 doc/appendices/command-line/traffic_ctl.en.rst | 12 +++-
 mgmt/LocalManager.cc                           |  4 +-
 mgmt/LocalManager.h                            |  2 +-
 mgmt/api/CoreAPI.cc                            | 11 ++--
 mgmt/api/CoreAPI.h                             |  4 +-
 mgmt/api/CoreAPIRemote.cc                      | 12 ++--
 mgmt/api/INKMgmtAPI.cc                         |  8 +--
 mgmt/api/NetworkMessage.cc                     |  4 +-
 mgmt/api/TSControlMain.cc                      | 13 ++--
 mgmt/api/include/mgmtapi.h                     |  4 +-
 proxy/HostStatus.h                             | 31 +++++++--
 proxy/ParentSelection.cc                       | 44 ++++++-------
 src/traffic_ctl/Makefile.inc                   |  1 +
 src/traffic_ctl/host.cc                        | 49 ++++++++++++--
 src/traffic_server/HostStatus.cc               | 91 +++++++++++++++++++-------
 15 files changed, 203 insertions(+), 87 deletions(-)

diff --git a/doc/appendices/command-line/traffic_ctl.en.rst b/doc/appendices/command-line/traffic_ctl.en.rst
index 8a15290..0719e9c 100644
--- a/doc/appendices/command-line/traffic_ctl.en.rst
+++ b/doc/appendices/command-line/traffic_ctl.en.rst
@@ -258,17 +258,23 @@ traffic_ctl host
     Get the current status of the hosts used in parent.config as a next hop in a multi-tiered cache heirarchy.  The value 0 or 1 is returned indicating that the host is marked as down '0' or marked as up '1'.  If a host is marked as down, it will not be used as the next hop parent, another host marked as up will be chosen.
 
 .. program:: traffic_ctl host
-.. option:: down --time seconds HOSTNAME [HOSTNAME ...]
+.. option:: down --time seconds --reason 'manual|active|local' HOSTNAME [HOSTNAME ...]
 
     Marks the listed hosts as down so that they will not be chosen as a next hop parent.
     If the --time option is included, the host is marked down for the specified number of 
     seconds after which the host will automatically be marked up.  0 seconds marks the host 
-    down indefinately until marked up manually and is the default.
+    down indefinitely until marked up manually and is the default. A reason tag may be used
+    when marking a host down.  Valid values are 'manual', 'active', or 'local', 'manual' is 
+    used as the default.  The tags are used to indicate wehter the host was marked down
+    manually or by an 'active' or 'local' health check.  There are three reason tag 
+    metrics for each host that may be viewed to see the reason a host was marked down.
 
 .. program:: traffic_ctl host
-.. option:: up HOSTNAME [HOSTNAME ...]
+.. option:: up --reason 'manual|active|local' HOSTNAME [HOSTNAME ...]
 
     Marks the listed hosts as up so that they will be available for use as a next hop parent.
+    By default, the 'manual' reason tag is used when marking up a host.  Use the --reason
+    tag to mark the host reason stat as up using one of 'manual', 'active', or 'local'.
 
 Examples
 ========
diff --git a/mgmt/LocalManager.cc b/mgmt/LocalManager.cc
index b31d00f..33ed6cb 100644
--- a/mgmt/LocalManager.cc
+++ b/mgmt/LocalManager.cc
@@ -134,9 +134,9 @@ LocalManager::hostStatusSetDown(const char *marshalled_req, int len)
 }
 
 void
-LocalManager::hostStatusSetUp(const char *marshalled_req)
+LocalManager::hostStatusSetUp(const char *marshalled_req, int len)
 {
-  signalEvent(MGMT_EVENT_HOST_STATUS_UP, marshalled_req);
+  signalEvent(MGMT_EVENT_HOST_STATUS_UP, marshalled_req, len);
   return;
 }
 
diff --git a/mgmt/LocalManager.h b/mgmt/LocalManager.h
index 4ff3591..4dc34db 100644
--- a/mgmt/LocalManager.h
+++ b/mgmt/LocalManager.h
@@ -96,7 +96,7 @@ public:
   void rollLogFiles();
   void clearStats(const char *name = nullptr);
   void hostStatusSetDown(const char *marshalled_req, int len);
-  void hostStatusSetUp(const char *marshalled_req);
+  void hostStatusSetUp(const char *marshalled_req, int len);
 
   bool processRunning();
 
diff --git a/mgmt/api/CoreAPI.cc b/mgmt/api/CoreAPI.cc
index 69a4201..d92148c 100644
--- a/mgmt/api/CoreAPI.cc
+++ b/mgmt/api/CoreAPI.cc
@@ -885,11 +885,12 @@ EventSignalCbUnregister(const char *event_name, TSEventSignalFunc func)
  *-------------------------------------------------------------------------
  * Sets the HOST status to Down
  *
- * 'marshalled_req' is marshalled here, (host_name and down_time).
+ * 'marshalled_req' is marshalled here, (host_name and down_time, na).
  * 'len' is the length of the 'req' marshaled data.
+ * 'na' unused.
  */
 TSMgmtError
-HostStatusSetDown(const char *marshalled_req, int len)
+HostStatusSetDown(const char *marshalled_req, int len, const char *na)
 {
   lmgmt->hostStatusSetDown(marshalled_req, len);
   return TS_ERR_OKAY;
@@ -901,11 +902,13 @@ HostStatusSetDown(const char *marshalled_req, int len)
  * Sets the HOST status to Up
  *
  * 'marshalled_req' is marshalled here, host_name.
+ * 'len' is the length of 'req'
+ * 'na' unused.
  */
 TSMgmtError
-HostStatusSetUp(const char *marshalled_req)
+HostStatusSetUp(const char *marshalled_req, int len, const char *na)
 {
-  lmgmt->hostStatusSetUp(marshalled_req);
+  lmgmt->hostStatusSetUp(marshalled_req, len);
   return TS_ERR_OKAY;
 }
 
diff --git a/mgmt/api/CoreAPI.h b/mgmt/api/CoreAPI.h
index 621cfc1..139c0c4 100644
--- a/mgmt/api/CoreAPI.h
+++ b/mgmt/api/CoreAPI.h
@@ -82,6 +82,6 @@ TSMgmtError EventIsActive(const char *event_name, bool *is_current);
 TSMgmtError EventSignalCbRegister(const char *event_name, TSEventSignalFunc func, void *data);
 TSMgmtError EventSignalCbUnregister(const char *event_name, TSEventSignalFunc func);
 
-TSMgmtError HostStatusSetDown(const char *host_name, int down_time);
-TSMgmtError HostStatusSetUp(const char *host_name);
+TSMgmtError HostStatusSetDown(const char *host_name, int down_time, const char *reason);
+TSMgmtError HostStatusSetUp(const char *host_name, int down_time, const char *reason);
 TSMgmtError StatsReset(const char *name = nullptr);
diff --git a/mgmt/api/CoreAPIRemote.cc b/mgmt/api/CoreAPIRemote.cc
index e3a8743..10e3d03 100644
--- a/mgmt/api/CoreAPIRemote.cc
+++ b/mgmt/api/CoreAPIRemote.cc
@@ -1033,26 +1033,28 @@ EventSignalCbUnregister(const char *event_name, TSEventSignalFunc func)
 }
 
 TSMgmtError
-HostStatusSetDown(const char *host_name, int down_time)
+HostStatusSetDown(const char *host_name, int down_time, const char *reason)
 {
-  fprintf(stderr, "%s:%s:%d - host_name: %s, down_time: %d\n", __FILE__, __func__, __LINE__, host_name, down_time);
   TSMgmtError ret         = TS_ERR_PARAMS;
   OpType op               = OpType::HOST_STATUS_DOWN;
   MgmtMarshallString name = const_cast<MgmtMarshallString>(host_name);
+  MgmtMarshallString re   = const_cast<MgmtMarshallString>(reason);
   MgmtMarshallInt dtime   = down_time;
 
-  ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &op, &name, &dtime);
+  ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &op, &name, &re, &dtime);
   return (ret == TS_ERR_OKAY) ? parse_generic_response(op, main_socket_fd) : ret;
 }
 
 TSMgmtError
-HostStatusSetUp(const char *host_name)
+HostStatusSetUp(const char *host_name, int down_time, const char *reason)
 {
   TSMgmtError ret         = TS_ERR_PARAMS;
   OpType op               = OpType::HOST_STATUS_UP;
   MgmtMarshallString name = const_cast<MgmtMarshallString>(host_name);
+  MgmtMarshallString re   = const_cast<MgmtMarshallString>(reason);
+  MgmtMarshallInt dtime   = down_time;
 
-  ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &op, &name);
+  ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &op, &name, &re, &dtime);
   return (ret == TS_ERR_OKAY) ? parse_generic_response(op, main_socket_fd) : ret;
 }
 
diff --git a/mgmt/api/INKMgmtAPI.cc b/mgmt/api/INKMgmtAPI.cc
index 3dff0a0..898c448 100644
--- a/mgmt/api/INKMgmtAPI.cc
+++ b/mgmt/api/INKMgmtAPI.cc
@@ -416,15 +416,15 @@ TSRecordEleDestroy(TSRecordEle *ele)
 
 /*--- host status operations ----------------------------------------------- */
 tsapi TSMgmtError
-TSHostStatusSetUp(const char *host_name)
+TSHostStatusSetUp(const char *host_name, int down_time, const char *reason)
 {
-  return HostStatusSetUp(host_name);
+  return HostStatusSetUp(host_name, down_time, reason);
 }
 
 tsapi TSMgmtError
-TSHostStatusSetDown(const char *host_name, int down_time)
+TSHostStatusSetDown(const char *host_name, int down_time, const char *reason)
 {
-  return HostStatusSetDown(host_name, down_time);
+  return HostStatusSetDown(host_name, down_time, reason);
 }
 
 /*--- statistics operations ----------------------------------------------- */
diff --git a/mgmt/api/NetworkMessage.cc b/mgmt/api/NetworkMessage.cc
index 44aa6ee..945d448 100644
--- a/mgmt/api/NetworkMessage.cc
+++ b/mgmt/api/NetworkMessage.cc
@@ -61,8 +61,8 @@ static const struct NetCmdOperation requests[] = {
   /* SERVER_BACKTRACE           */ {2, {MGMT_MARSHALL_INT, MGMT_MARSHALL_INT}},
   /* RECORD_DESCRIBE_CONFIG     */ {3, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}},
   /* LIFECYCLE_MESSAGE          */ {3, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_DATA}},
-  /* HOST_STATUS_HOST_UP        */ {2, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING}},
-  /* HOST_STATUS_HOST_DOWN      */ {3, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}},
+  /* HOST_STATUS_HOST_UP        */ {4, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}},
+  /* HOST_STATUS_HOST_DOWN      */ {4, {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT}},
 };
 
 // Responses always begin with a TSMgmtError code, followed by additional fields.
diff --git a/mgmt/api/TSControlMain.cc b/mgmt/api/TSControlMain.cc
index deedc66..49179ca 100644
--- a/mgmt/api/TSControlMain.cc
+++ b/mgmt/api/TSControlMain.cc
@@ -808,12 +808,14 @@ static TSMgmtError
 handle_host_status_up(int fd, void *req, size_t reqlen)
 {
   OpType optype;
-  MgmtMarshallString name = nullptr;
+  MgmtMarshallString name   = nullptr;
+  MgmtMarshallString reason = nullptr;
   MgmtMarshallInt err;
+  MgmtMarshallInt down_time;
 
-  err = recv_mgmt_request(req, reqlen, OpType::HOST_STATUS_UP, &optype, &name);
+  err = recv_mgmt_request(req, reqlen, OpType::HOST_STATUS_UP, &optype, &name, &reason, &down_time);
   if (err == TS_ERR_OKAY) {
-    err = HostStatusSetUp(name);
+    lmgmt->signalEvent(MGMT_EVENT_HOST_STATUS_UP, static_cast<char *>(req), reqlen);
   }
 
   ats_free(name);
@@ -830,11 +832,12 @@ static TSMgmtError
 handle_host_status_down(int fd, void *req, size_t reqlen)
 {
   OpType optype;
-  MgmtMarshallString name = nullptr;
+  MgmtMarshallString name   = nullptr;
+  MgmtMarshallString reason = nullptr;
   MgmtMarshallInt err;
   MgmtMarshallInt down_time;
 
-  err = recv_mgmt_request(req, reqlen, OpType::HOST_STATUS_DOWN, &optype, &name, &down_time);
+  err = recv_mgmt_request(req, reqlen, OpType::HOST_STATUS_DOWN, &optype, &name, &reason, &down_time);
   if (err == TS_ERR_OKAY) {
     lmgmt->signalEvent(MGMT_EVENT_HOST_STATUS_DOWN, static_cast<char *>(req), reqlen);
   }
diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h
index b9d87be..be597ac 100644
--- a/mgmt/api/include/mgmtapi.h
+++ b/mgmt/api/include/mgmtapi.h
@@ -428,8 +428,8 @@ tsapi TSMgmtError TSReadFromUrl(char *url, char **header, int *headerSize, char
  * NOTE: header and headerSize can be NULL
  */
 tsapi TSMgmtError TSReadFromUrlEx(const char *url, char **header, int *headerSize, char **body, int *bodySize, int timeout);
-tsapi TSMgmtError TSHostStatusSetUp(const char *host_name);
-tsapi TSMgmtError TSHostStatusSetDown(const char *host_name, int down_time);
+tsapi TSMgmtError TSHostStatusSetUp(const char *host_name, int down_time, const char *reason);
+tsapi TSMgmtError TSHostStatusSetDown(const char *host_name, int down_time, const char *reason);
 /*--- statistics operations -----------------------------------------------*/
 /* TSStatsReset: sets all the statistics variables to their default values
  * Outpue: TSErrr
diff --git a/proxy/HostStatus.h b/proxy/HostStatus.h
index 6eddb21..49ccd20 100644
--- a/proxy/HostStatus.h
+++ b/proxy/HostStatus.h
@@ -23,15 +23,17 @@
 
 /*****************************************************************************
  *
- *  HostSelection.h - Interface to Host Selection System
+ *  HostStatus.h - Interface to Host Status System
  *
  *
  ****************************************************************************/
 
 #pragma once
 
-#include "ControlBase.h"
-#include "ControlMatcher.h"
+#include <time.h>
+#include <string>
+#include "ts/ink_hash_table.h"
+#include "ts/ink_rwlock.h"
 #include "P_RecProcess.h"
 
 enum HostStatus_t {
@@ -46,7 +48,26 @@ struct HostStatRec_t {
   unsigned int down_time; // number of seconds that the host should be down, 0 is indefinately
 };
 
-const std::string stat_prefix = "host_status.";
+struct Reasons {
+  static constexpr const char *ACTIVE = "active";
+  static constexpr const char *LOCAL  = "local";
+  static constexpr const char *MANUAL = "manual";
+
+  static constexpr const char *reasons[3] = {ACTIVE, LOCAL, MANUAL};
+
+  static bool
+  validReason(const char *reason)
+  {
+    for (const char *i : reasons) {
+      if (strcmp(i, reason) == 0) {
+        return true;
+      }
+    }
+    return false;
+  }
+};
+
+static const std::string stat_prefix = "proxy.process.host_status.";
 
 /**
  * Singleton placeholder for next hop status.
@@ -60,7 +81,7 @@ struct HostStatus {
     static HostStatus instance;
     return instance;
   }
-  void setHostStatus(const char *name, const HostStatus_t status, const unsigned int down_time);
+  void setHostStatus(const char *name, const HostStatus_t status, const unsigned int down_time, const char *reason);
   HostStatus_t getHostStatus(const char *name);
   void createHostStat(const char *name);
 
diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc
index 496146d..a7d3dc7 100644
--- a/proxy/ParentSelection.cc
+++ b/proxy/ParentSelection.cc
@@ -370,7 +370,7 @@ ParentRecord::PreProcessParents(const char *val, const int line_num, char *buf,
         } else {
           Debug("parent_select", "token: %s, matches this machine.  Marking down self from parent list at line %d", fqdn, line_num);
           hs.createHostStat(fqdn);
-          hs.setHostStatus(fqdn, HostStatus_t::HOST_STATUS_DOWN, 0);
+          hs.setHostStatus(fqdn, HostStatus_t::HOST_STATUS_DOWN, 0, Reasons::MANUAL);
         }
       }
     } else {
@@ -383,7 +383,7 @@ ParentRecord::PreProcessParents(const char *val, const int line_num, char *buf,
           Debug("parent_select", "token: %s, matches this machine.  Marking down self from parent list at line %d", token,
                 line_num);
           hs.createHostStat(token);
-          hs.setHostStatus(token, HostStatus_t::HOST_STATUS_DOWN, 0);
+          hs.setHostStatus(token, HostStatus_t::HOST_STATUS_DOWN, 0, Reasons::MANUAL);
         }
       }
     }
@@ -1429,7 +1429,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   // Test 184
   // mark fuzzy down with HostStatus API.
   HostStatus &_st = HostStatus::instance();
-  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
 
   ST(184);
   REINIT;
@@ -1440,7 +1440,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
 
   // Test 185
   // mark fluffy down and expect furry to be chosen
-  _st.setHostStatus("fluffy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fluffy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
 
   ST(185);
   REINIT;
@@ -1451,9 +1451,9 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
 
   // Test 186
   // mark furry and frisky down, fuzzy up and expect fuzzy to be chosen
-  _st.setHostStatus("furry", HOST_STATUS_DOWN, 0);
-  _st.setHostStatus("frisky", HOST_STATUS_DOWN, 0);
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
+  _st.setHostStatus("furry", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
+  _st.setHostStatus("frisky", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
 
   ST(186);
   REINIT;
@@ -1471,10 +1471,10 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   REBUILD;
 
   // mark all up.
-  _st.setHostStatus("furry", HOST_STATUS_UP, 0);
-  _st.setHostStatus("fluffy", HOST_STATUS_UP, 0);
-  _st.setHostStatus("frisky", HOST_STATUS_UP, 0);
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
+  _st.setHostStatus("furry", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("fluffy", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("frisky", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
 
   REINIT;
   br(request, "i.am.rabbit.net");
@@ -1484,7 +1484,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
 
   // Test 188
   // mark fuzzy down and expect fluffy.
-  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
 
   ST(188);
   REINIT;
@@ -1495,7 +1495,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
 
   // Test 189
   // mark fuzzy back up and expect fuzzy.
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
 
   ST(189);
   REINIT;
@@ -1511,7 +1511,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   // because the host status is set to down.
   params->markParentDown(result, fail_threshold, retry_time);
   // set host status down
-  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
   // sleep long enough so that fuzzy is retryable
   sleep(params->policy.ParentRetryTime + 1);
   ST(190);
@@ -1522,7 +1522,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
 
   // now set the host staus on fuzzy to up and it should now
   // be retried.
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
   ST(191);
   REINIT;
   br(request, "i.am.rabbit.net");
@@ -1535,10 +1535,10 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   T("dest_domain=rabbit.net parent=fuzzy:80,fluffy:80,furry:80,frisky:80 round_robin=false go_direct=true\n");
   REBUILD;
   // mark all up.
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
-  _st.setHostStatus("fluffy", HOST_STATUS_UP, 0);
-  _st.setHostStatus("furry", HOST_STATUS_UP, 0);
-  _st.setHostStatus("frisky", HOST_STATUS_UP, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("fluffy", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("furry", HOST_STATUS_UP, 0, Reasons::MANUAL);
+  _st.setHostStatus("frisky", HOST_STATUS_UP, 0, Reasons::MANUAL);
   // fuzzy should be chosen.
   sleep(1);
   REINIT;
@@ -1553,7 +1553,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   sleep(params->policy.ParentRetryTime + 1);
   // since the host status is down even though fuzzy is
   // retryable, fluffy should be chosen
-  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
   REINIT;
   br(request, "i.am.rabbit.net");
   FP;
@@ -1563,7 +1563,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   // set the host status for fuzzy  back up and since its
   // retryable fuzzy should be chosen
   ST(194);
-  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_UP, 0, Reasons::MANUAL);
   REINIT;
   br(request, "i.am.rabbit.net");
   FP;
@@ -1684,7 +1684,7 @@ EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION)(RegressionTest * /* t ATS_UNUSED */,
   T("dest_domain=rabbit.net parent=fuzzy:80|1.0;fluffy:80|1.0 secondary_parent=furry:80|1.0;frisky:80|1.0 "
     "round_robin=consistent_hash go_direct=false secondary_mode=3\n");
   REBUILD;
-  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0);
+  _st.setHostStatus("fuzzy", HOST_STATUS_DOWN, 0, Reasons::MANUAL);
   REINIT;
   br(request, "i.am.rabbit.net");
   FP;
diff --git a/src/traffic_ctl/Makefile.inc b/src/traffic_ctl/Makefile.inc
index 23dca97..998a4ce 100644
--- a/src/traffic_ctl/Makefile.inc
+++ b/src/traffic_ctl/Makefile.inc
@@ -26,6 +26,7 @@ traffic_ctl_traffic_ctl_CPPFLAGS = \
     -I$(abs_top_srcdir)/lib/records \
     -I$(abs_top_srcdir)/mgmt \
     -I$(abs_top_srcdir)/mgmt/api/include \
+    -I$(abs_top_srcdir)/proxy \
     $(TS_INCLUDES)
 
 traffic_ctl_traffic_ctl_SOURCES = \
diff --git a/src/traffic_ctl/host.cc b/src/traffic_ctl/host.cc
index 0041044..539fb8c 100644
--- a/src/traffic_ctl/host.cc
+++ b/src/traffic_ctl/host.cc
@@ -20,9 +20,11 @@
   See the License for the specific language governing permissions and
   limitations under the License.
  */
+
 #include "traffic_ctl.h"
+#include "HostStatus.h"
 #include <P_RecUtils.h>
-const std::string stat_prefix = "host_status.";
+
 static int
 status_get(unsigned argc, const char **argv)
 {
@@ -53,40 +55,75 @@ static int
 status_down(unsigned argc, const char **argv)
 {
   int down_time     = 0;
+  char *reason      = nullptr;
   const char *usage = "host down HOST [OPTIONS]";
 
   const ArgumentDescription opts[] = {
-    {"time", 'I', "number of seconds that a host is marked down", "I", &down_time, nullptr, nullptr}};
+    {"time", 'I', "number of seconds that a host is marked down", "I", &down_time, nullptr, nullptr},
+    // memory is allocated for 'reason', if this option is used
+    {"reason", '-', "reason for marking the host down, one of 'manual|active|local'", "S*", &reason, nullptr, nullptr},
+  };
 
   if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments < 1) {
     return CtrlCommandUsage(usage, opts, countof(opts));
   }
 
+  // if reason is not set, set it to manual (default)
+  if (reason == nullptr) {
+    reason = ats_strdup(Reasons::MANUAL);
+  }
+
+  if (!Reasons::validReason(reason)) {
+    fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason);
+    return CtrlCommandUsage(usage, opts, countof(opts));
+  }
+
   TSMgmtError error = TS_ERR_OKAY;
   for (unsigned i = 0; i < n_file_arguments; ++i) {
-    error = TSHostStatusSetDown(file_arguments[i], down_time);
+    error = TSHostStatusSetDown(file_arguments[i], down_time, reason);
     if (error != TS_ERR_OKAY) {
       CtrlMgmtError(error, "failed to set %s", file_arguments[i]);
       return CTRL_EX_ERROR;
     }
   }
+  ats_free(reason);
 
   return CTRL_EX_OK;
 }
 static int
 status_up(unsigned argc, const char **argv)
 {
-  if (!CtrlProcessArguments(argc, argv, nullptr, 0) || n_file_arguments < 1) {
-    return CtrlCommandUsage("host up METRIC value", nullptr, 0);
+  char *reason      = nullptr;
+  const char *usage = "host down HOST [OPTIONS]";
+
+  const ArgumentDescription opts[] = {
+    // memory is allocated for 'reason', if this option is used
+    {"reason", '-', "reason for marking the host down, one of 'manual|active|local'", "S*", &reason, nullptr, nullptr},
+  };
+
+  if (!CtrlProcessArguments(argc, argv, opts, countof(opts)) || n_file_arguments < 1) {
+    return CtrlCommandUsage(usage, nullptr, 0);
+  }
+
+  // if reason is not set, set it to manual (default)
+  if (reason == nullptr) {
+    reason = ats_strdup(Reasons::MANUAL);
   }
+
+  if (!Reasons::validReason(reason)) {
+    fprintf(stderr, "\nInvalid reason: '%s'\n\n", reason);
+    return CtrlCommandUsage(usage, opts, countof(opts));
+  }
+
   TSMgmtError error;
   for (unsigned i = 0; i < n_file_arguments; ++i) {
-    error = TSHostStatusSetUp(file_arguments[i]);
+    error = TSHostStatusSetUp(file_arguments[i], 0, reason);
     if (error != TS_ERR_OKAY) {
       CtrlMgmtError(error, "failed to set %s", file_arguments[i]);
       return CTRL_EX_ERROR;
     }
   }
+  ats_free(reason);
 
   return CTRL_EX_OK;
 }
diff --git a/src/traffic_server/HostStatus.cc b/src/traffic_server/HostStatus.cc
index 95e1b95..e69df7a 100644
--- a/src/traffic_server/HostStatus.cc
+++ b/src/traffic_server/HostStatus.cc
@@ -25,13 +25,37 @@
 
 static RecRawStatBlock *host_status_rsb = nullptr;
 
+static void
+getStatName(std::string &stat_name, const char *name, const char *reason)
+{
+  stat_name = stat_prefix + name + "_";
+
+  if (reason == nullptr) {
+    stat_name += Reasons::MANUAL;
+  } else {
+    stat_name += reason;
+  }
+}
+
 static void *
 mgmt_host_status_up_callback(void *x, char *data, int len)
 {
+  MgmtInt op;
+  MgmtMarshallString name;
+  MgmtMarshallInt down_time;
+  MgmtMarshallString reason;
+  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: %d\n", __FILE__, __func__, __LINE__, data, len);
+
+  if (mgmt_message_parse(data, len, fields, countof(fields), &op, &name, &reason, &down_time) == -1) {
+    Error("Plugin message - RPC parsing error - message discarded.");
+  }
+  Debug("host_statuses", "op: %ld, name: %s, down_time: %d, reason: %s", static_cast<long>(op), name, static_cast<int>(down_time),
+        reason);
   if (data != nullptr) {
     Debug("host_statuses", "marking up server %s", data);
     HostStatus &hs = HostStatus::instance();
-    hs.setHostStatus(data, HostStatus_t::HOST_STATUS_UP, 0);
+    hs.setHostStatus(name, HostStatus_t::HOST_STATUS_UP, down_time, reason);
   }
   return nullptr;
 }
@@ -42,18 +66,20 @@ mgmt_host_status_down_callback(void *x, char *data, int len)
   MgmtInt op;
   MgmtMarshallString name;
   MgmtMarshallInt down_time;
-  static const MgmtMarshallType fields[] = {MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_INT};
+  MgmtMarshallString reason;
+  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: %d\n", __FILE__, __func__, __LINE__, data, len);
 
-  if (mgmt_message_parse(data, len, fields, countof(fields), &op, &name, &down_time) == -1) {
+  if (mgmt_message_parse(data, len, fields, countof(fields), &op, &name, &reason, &down_time) == -1) {
     Error("Plugin message - RPC parsing error - message discarded.");
   }
-  Debug("host_statuses", "op: %ld, name: %s, down_time: %d", static_cast<long>(op), name, static_cast<int>(down_time));
+  Debug("host_statuses", "op: %ld, name: %s, down_time: %d, reason: %s", static_cast<long>(op), name, static_cast<int>(down_time),
+        reason);
 
   if (data != nullptr) {
     Debug("host_statuses", "marking down server %s", name);
     HostStatus &hs = HostStatus::instance();
-    hs.setHostStatus(name, HostStatus_t::HOST_STATUS_DOWN, down_time);
+    hs.setHostStatus(name, HostStatus_t::HOST_STATUS_DOWN, down_time, reason);
   }
   return nullptr;
 }
@@ -64,7 +90,6 @@ HostStatus::HostStatus()
   hosts_stats_ids = ink_hash_table_create(InkHashTableKeyType_String);
   ink_rwlock_init(&host_status_rwlock);
   ink_rwlock_init(&host_statids_rwlock);
-  Debug("host_statuses", "registering ostas");
   pmgmt->registerMgmtCallback(MGMT_EVENT_HOST_STATUS_UP, mgmt_host_status_up_callback, nullptr);
   pmgmt->registerMgmtCallback(MGMT_EVENT_HOST_STATUS_DOWN, mgmt_host_status_down_callback, nullptr);
   host_status_rsb = RecAllocateRawStatBlock((int)TS_MAX_API_STATS);
@@ -91,21 +116,28 @@ HostStatus::~HostStatus()
 }
 
 void
-HostStatus::setHostStatus(const char *name, HostStatus_t status, const unsigned int down_time)
+HostStatus::setHostStatus(const char *name, HostStatus_t status, const unsigned int down_time, const char *reason)
 {
-  int stat_id = getHostStatId(name);
+  std::string reason_stat;
+
+  getStatName(reason_stat, name, reason);
+
+  int stat_id = getHostStatId(reason_stat.c_str());
+
+  // update the stats
   if (stat_id != -1) {
     if (status == HostStatus_t::HOST_STATUS_UP) {
-      Debug("host_statuses", "set stat for :  name: %s, status: %d", name, status);
+      Debug("host_statuses", "set status up for :  name: %s, status: %d, reason_stat: %s", name, status, reason_stat.c_str());
       RecSetRawStatCount(host_status_rsb, stat_id, 1);
       RecSetRawStatSum(host_status_rsb, stat_id, 1);
     } else {
+      Debug("host_statuses", "set status down for :  name: %s, status: %d, reason_stat: %s", name, status, reason_stat.c_str());
       RecSetRawStatCount(host_status_rsb, stat_id, 0);
       RecSetRawStatSum(host_status_rsb, stat_id, 0);
-      Debug("host_statuses", "clear stat for :  name: %s, status: %d", name, status);
     }
   }
   Debug("host_statuses", "name: %s, status: %d", name, status);
+
   // update / insert status.
   // using the hash table pointer to store the HostStatus_t value.
   HostStatRec_t *host_stat = nullptr;
@@ -149,7 +181,7 @@ HostStatus::getHostStatus(const char *name)
     if ((_status->down_time + _status->marked_down) < now) {
       Debug("host_statuses", "name: %s, now: %ld, down_time: %d, marked_down: %ld", name, now, _status->down_time,
             _status->marked_down);
-      setHostStatus(name, HostStatus_t::HOST_STATUS_UP, 0);
+      setHostStatus(name, HostStatus_t::HOST_STATUS_UP, 0, nullptr);
       return HostStatus_t::HOST_STATUS_UP;
     }
   }
@@ -160,29 +192,40 @@ void
 HostStatus::createHostStat(const char *name)
 {
   InkHashTableEntry *entry;
-  entry = ink_hash_table_lookup_entry(hosts_stats_ids, name);
-  if (entry == nullptr) {
-    RecRegisterRawStat(host_status_rsb, RECT_PROCESS, (stat_prefix + name).c_str(), RECD_INT, RECP_NON_PERSISTENT,
-                       (int)next_stat_id, RecRawStatSyncSum);
-    Debug("host_statuses", "name: %s, id: %d", name, next_stat_id);
-    ink_rwlock_wrlock(&host_statids_rwlock);
-    ink_hash_table_insert(hosts_stats_ids, name, reinterpret_cast<void *>(next_stat_id));
-    ink_rwlock_unlock(&host_statids_rwlock);
-    setHostStatus(name, HostStatus_t::HOST_STATUS_UP, 0);
-    next_stat_id++;
+
+  ink_rwlock_wrlock(&host_statids_rwlock);
+  {
+    for (const char *i : Reasons::reasons) {
+      std::string reason_stat;
+      getStatName(reason_stat, name, i);
+      entry = ink_hash_table_lookup_entry(hosts_stats_ids, reason_stat.c_str());
+      if (entry == nullptr) {
+        RecRegisterRawStat(host_status_rsb, RECT_PROCESS, (reason_stat).c_str(), RECD_INT, RECP_NON_PERSISTENT, (int)next_stat_id,
+                           RecRawStatSyncSum);
+        RecSetRawStatCount(host_status_rsb, next_stat_id, 1);
+        RecSetRawStatSum(host_status_rsb, next_stat_id, 1);
+
+        ink_hash_table_insert(hosts_stats_ids, reason_stat.c_str(), reinterpret_cast<void *>(next_stat_id));
+
+        Debug("host_statuses", "stat name: %s, id: %d", reason_stat.c_str(), next_stat_id);
+        next_stat_id++;
+      }
+    }
   }
+  ink_rwlock_unlock(&host_statids_rwlock);
+  setHostStatus(name, HostStatus_t::HOST_STATUS_UP, 0, nullptr);
 }
 
 int
-HostStatus::getHostStatId(const char *name)
+HostStatus::getHostStatId(const char *stat_name)
 {
   int lookup   = 0;
   intptr_t _id = -1;
 
   ink_rwlock_rdlock(&host_statids_rwlock);
-  lookup = ink_hash_table_lookup(hosts_stats_ids, name, reinterpret_cast<void **>(&_id));
+  lookup = ink_hash_table_lookup(hosts_stats_ids, stat_name, reinterpret_cast<void **>(&_id));
   ink_rwlock_unlock(&host_statids_rwlock);
-  Debug("host_statuses", "name: %s, id: %d", name, static_cast<int>(_id));
+  Debug("host_statuses", "name: %s, id: %d", stat_name, static_cast<int>(_id));
 
   return lookup == 1 ? static_cast<int>(_id) : -1;
 }