Browse Source

Merge pull request #7521 from wangkx/h12691b

HPCC-12691 Add ESP method to report Component Status

Reviewed-By: Gleb Aronsky <gleb.aronsky@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 10 years ago
parent
commit
93f36f6405

+ 60 - 0
esp/scm/ws_machine.ecm

@@ -309,6 +309,64 @@ ESPresponse [encode(0), exceptions_inline] GetTargetClusterInfoResponse
     string TimeStamp;
     [min_ver("1.12")] string AcceptLanguage;
 };
+
+ESPstruct [nil_remove] StatusReport
+{
+    int StatusID;
+    string Status;
+    string StatusDetails;
+    string Reporter;
+    int64 TimeReported;
+    string TimeReportedStr;
+    string TimeCached;
+    string URL;
+};
+
+ESPstruct [nil_remove] ComponentStatus
+{
+    int ComponentTypeID;
+    string ComponentType;
+    string EndPoint;
+    int StatusID;
+    string Status;
+    int64 TimeReported;
+    string TimeReportedStr;
+    string Reporter;
+    ESParray<ESPstruct StatusReport> StatusReports;
+};
+
+ESPrequest [nil_remove] GetComponentStatusRequest
+{
+};
+
+ESPresponse [encode(0), nil_remove, exceptions_inline] GetComponentStatusResponse 
+{
+    int StatusCode;
+    string Status;
+
+    string ComponentType;
+    string EndPoint;
+    int ComponentStatusID;
+    string ComponentStatus;
+    int64 TimeReported;
+    string TimeReportedStr;
+    string Reporter;
+    ESPstruct StatusReport StatusReport;
+    ESParray<ESPstruct ComponentStatus, ComponentStatus> ComponentStatusList;
+};
+
+ESPrequest [nil_remove] UpdateComponentStatusRequest
+{
+    string Reporter;
+    ESParray<ESPstruct ComponentStatus, ComponentStatus> ComponentStatusList;
+};
+
+ESPresponse [encode(0), nil_remove, exceptions_inline] UpdateComponentStatusResponse 
+{
+    int StatusCode;
+    string Status;
+};
+
 //-------- service ---------
 ESPservice [version("1.13")] ws_machine
 {
@@ -330,6 +388,8 @@ ESPservice [version("1.13")] ws_machine
     ESPmethod [resp_xsl_default("./smc_xslt/ws_machine/machines.xslt"), exceptions_inline("./smc_xslt/exceptions.xslt")] 
        GetMachineInfoEx(GetMachineInfoRequestEx, GetMachineInfoResponseEx);
 
+    ESPmethod GetComponentStatus(GetComponentStatusRequest, GetComponentStatusResponse);
+    ESPmethod UpdateComponentStatus(UpdateComponentStatusRequest, UpdateComponentStatusResponse);
 
     ESPmethod [resp_xsl_default("./smc_xslt/ws_machine/metrics.xslt"), exceptions_inline("./smc_xslt/exceptions.xslt")] 
        GetMetrics(MetricsRequest, MetricsResponse);

+ 1 - 0
esp/services/ws_machine/CMakeLists.txt

@@ -33,6 +33,7 @@ set (    SRCS
          ws_machineService.cpp 
          ws_machineServiceMetrics.cpp 
          ws_machineServiceRexec.cpp 
+         componentstatus.cpp
     )
 
 include_directories ( 

+ 342 - 0
esp/services/ws_machine/componentstatus.cpp

@@ -0,0 +1,342 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "jiface.hpp"
+#include "componentstatus.hpp"
+#include "jlib.hpp"
+#include "esp.hpp"
+#include "ws_machine_esp.ipp"
+#include "ws_machine.hpp"
+
+static unsigned csCacheMinutes = 30; //30 minutes as default
+static MapStringTo<int> componentTypeMap;
+static MapStringTo<int> componentStatusTypeMap;
+static unsigned componentTypeIDCount;
+
+const char* formatTimeStamp(time_t tNow, StringAttr& out)
+{
+    char timeStr[32];
+#ifdef _WIN32
+    struct tm *ltNow;
+    ltNow = localtime(&tNow);
+    strftime(timeStr, 32, "%Y-%m-%d %H:%M:%S", ltNow);
+#else
+    struct tm ltNow;
+    localtime_r(&tNow, &ltNow);
+    strftime(timeStr, 32, "%Y-%m-%d %H:%M:%S", &ltNow);
+#endif
+    out.set(timeStr);
+    return out.get();
+}
+
+CESPComponentStatusInfo::CESPComponentStatusInfo(const char* _reporter)
+{
+    componentStatusID = -1;
+    addToCache = _reporter? true : false;
+    if (_reporter && *_reporter)
+        reporter.set(_reporter);
+
+    expireTimeStamp = 0;
+    if (csCacheMinutes > 0)
+    { //A status report should be expired if it was reported >csCacheMinutes ago.
+        CDateTime timeNow;
+        timeNow.setNow();
+        timeNow.adjustTime(-csCacheMinutes);
+        expireTimeStamp = timeNow.getSimple();
+    }
+}
+
+void CESPComponentStatusInfo::init(IPropertyTree* cfg)
+{
+    StringArray statusTypeMap;
+    Owned<IPropertyTreeIterator> statusTypes = cfg->getElements("StatusType");
+    ForEach(*statusTypes)
+    {
+        IPropertyTree& statusType = statusTypes->query();
+        const char* name = statusType.queryProp("@name");
+        if (name && *name)
+            componentStatusTypeMap.setValue(name, statusType.getPropInt("@id"));
+    }
+
+    if (componentStatusTypeMap.count() < 1)
+    {
+        componentStatusTypeMap.setValue("normal", 1);
+        componentStatusTypeMap.setValue("warning", 2);
+        componentStatusTypeMap.setValue("error", 3);
+    }
+    componentTypeIDCount = 0;
+
+    cfg->getPropInt("CSCacheMinutes", csCacheMinutes);
+}
+
+bool CESPComponentStatusInfo::isSameComponent(const char* ep, int componentTypeID, IConstComponentStatus& status)
+{
+    const char* ep1 = status.getEndPoint();
+    if (!ep1 || !*ep1 || !ep || !*ep)
+        return false;
+    bool hasPort = strchr(ep, ':');
+    if (hasPort)
+        return streq(ep1, ep);
+    //If no port, for now, only one componentType is reported per IP.
+    return ((componentTypeID == status.getComponentTypeID()) && streq(ep1, ep));
+}
+
+void CESPComponentStatusInfo::addStatusReport(const char* reporterIn, const char* timeCachedIn, IConstComponentStatus& csIn, IEspComponentStatus& csOut, bool firstReport)
+{
+    IArrayOf<IConstStatusReport>& statusReports = csOut.getStatusReports();
+    IArrayOf<IConstStatusReport>& reportsIn = csIn.getStatusReports();
+    ForEachItemIn(i, reportsIn)
+    {
+        IConstStatusReport& report = reportsIn.item(i);
+        const char* status = report.getStatus();
+        if (!status || !*status)
+            continue;
+
+        if ((expireTimeStamp > 0) && (report.getTimeReported() < expireTimeStamp))
+            continue;
+
+        int statusID;
+        if (addToCache) //from the update status request
+            statusID = queryComponentStatusID(status);
+        else //from a cache report which StatusID has been set.
+            statusID = report.getStatusID();
+
+        Owned<IEspStatusReport> statusReport = createStatusReport();
+        statusReport->setStatusID(statusID);
+        statusReport->setStatus(status);
+
+        const char* details = report.getStatusDetails();
+        if (details && *details)
+            statusReport->setStatusDetails(details);
+
+        const char* url = report.getURL();
+        if (url && *url)
+            statusReport->setURL(url);
+
+        statusReport->setReporter(reporterIn);
+        statusReport->setTimeCached(timeCachedIn);
+        statusReport->setTimeReported(report.getTimeReported());
+
+        if (!addToCache)
+        {//We need to add more info for a user-friendly output
+            StringAttr timeStr;
+            statusReport->setTimeReportedStr(formatTimeStamp(report.getTimeReported(), timeStr));
+
+            if (firstReport || (statusID > csOut.getStatusID())) //worst case for component
+            {
+                csOut.setStatusID(statusID);
+                csOut.setStatus(status);
+                csOut.setTimeReportedStr(timeStr.get());
+                csOut.setReporter(reporterIn);
+            }
+            if (statusID > componentStatusID) //worst case for whole system
+            {
+                componentStatusID = statusID;
+                componentStatus.set(status);
+                timeReported = report.getTimeReported();
+                timeReportedStr.set(timeStr.get());
+                reporter.set(reporterIn);
+                componentTypeID = csIn.getComponentTypeID();
+                componentType.set(csIn.getComponentType());
+                endPoint.set(csIn.getEndPoint());
+                componentStatusReport.setown(statusReport.getLink());
+            }
+        }
+        statusReports.append(*statusReport.getClear());
+    }
+}
+
+void CESPComponentStatusInfo::addComponentStatus(const char* reporterIn, const char* timeCachedIn, IConstComponentStatus& st)
+{
+    Owned<IEspComponentStatus> cs = createComponentStatus();
+    cs->setEndPoint(st.getEndPoint());
+    cs->setComponentType(st.getComponentType());
+
+    int componentTypeID;
+    if (addToCache) //from the update status request
+        componentTypeID = queryComponentTypeID(st.getComponentType());
+    else
+        componentTypeID = st.getComponentTypeID();
+    cs->setComponentTypeID(componentTypeID);
+
+    IArrayOf<IConstStatusReport> statusReports;
+    cs->setStatusReports(statusReports);
+    addStatusReport(reporterIn, timeCachedIn, st, *cs, true);
+
+    statusList.append(*cs.getClear());
+}
+
+void CESPComponentStatusInfo::appendUnchangedComponentStatus(IEspComponentStatus& statusOld)
+{
+    bool componentFound = false;
+    const char* ep = statusOld.getEndPoint();
+    int componentTypeID = statusOld.getComponentTypeID();
+    ForEachItemIn(i, statusList)
+    {
+        if (isSameComponent(ep, componentTypeID, statusList.item(i)))
+        {
+            componentFound =  true;
+            break;
+        }
+    }
+    if (!componentFound)
+        addComponentStatus(reporter.get(), timeCached, statusOld);
+}
+
+bool CESPComponentStatusInfo::cleanExpiredStatusReports(IArrayOf<IConstStatusReport>& reports)
+{
+    bool expired = true;
+    ForEachItemInRev(i, reports)
+    {
+        IConstStatusReport& report = reports.item(i);
+        if ((expireTimeStamp > 0) && (report.getTimeReported() < expireTimeStamp))
+            reports.remove(i);
+        else
+            expired = false;
+    }
+    return expired;
+}
+
+int CESPComponentStatusInfo::queryComponentTypeID(const char *key)
+{
+    int* id = componentTypeMap.getValue(key);
+    if (id)
+        return *id;
+
+    componentTypeMap.setValue(key, ++componentTypeIDCount);
+    return componentTypeIDCount;
+}
+
+int CESPComponentStatusInfo::queryComponentStatusID(const char *key)
+{
+    StringBuffer buf(key);
+    int* value = componentStatusTypeMap.getValue(buf.toLowerCase().str());
+    if (!value)
+        return 0;
+    return *value;
+}
+
+bool CESPComponentStatusInfo::cleanExpiredComponentReports(IESPComponentStatusInfo& statusInfo)
+{
+    bool expired = true;
+    IArrayOf<IEspComponentStatus>& statusList = statusInfo.getComponentStatusList();
+    ForEachItemInRev(i, statusList)
+    {
+        IEspComponentStatus& status = statusList.item(i);
+        if (cleanExpiredStatusReports(status.getStatusReports()))
+            statusList.remove(i);
+        else
+            expired = false;
+    }
+    return expired;
+}
+
+void CESPComponentStatusInfo::mergeComponentStatusInfoFromReports(IESPComponentStatusInfo& statusInfo)
+{
+    const char* reporterIn = statusInfo.getReporter();
+    const char* timeCachedIn = statusInfo.getTimeCached();
+    IArrayOf<IEspComponentStatus>& statusListIn = statusInfo.getComponentStatusList();
+    ForEachItemIn(i, statusListIn)
+    {
+        IEspComponentStatus& statusIn = statusListIn.item(i);
+
+        bool newCompoment = true;
+        const char* ep = statusIn.getEndPoint();
+        int componentTypeID = statusIn.getComponentTypeID();
+        ForEachItemIn(ii, statusList)
+        {
+            IEspComponentStatus& statusOut = statusList.item(ii);
+            if (isSameComponent(ep, componentTypeID, statusOut))
+            {// multiple reports from different reporters.
+                addStatusReport(reporterIn, timeCachedIn, statusIn, statusOut, false);
+                newCompoment =  false;
+                break;
+            }
+        }
+        if (newCompoment)
+            addComponentStatus(reporterIn, timeCachedIn, statusIn);
+    }
+}
+
+void CESPComponentStatusInfo::setComponentStatus(IArrayOf<IConstComponentStatus>& statusListIn)
+{
+    time_t tNow;
+    time(&tNow);
+    formatTimeStamp(tNow, timeCached);
+
+    statusList.kill();
+    ForEachItemIn(i, statusListIn)
+        addComponentStatus(reporter, timeCached, statusListIn.item(i));
+}
+
+void CESPComponentStatusInfo::mergeCachedComponentStatus(IESPComponentStatusInfo& statusInfo)
+{
+    IArrayOf<IEspComponentStatus>& csList = statusInfo.getComponentStatusList();
+    ForEachItemIn(i, csList)
+        appendUnchangedComponentStatus(csList.item(i));
+}
+
+static CriticalSection componentStatusSect;
+
+IESPComponentStatusInfo* CComponentStatusFactory::getComponentStatus()
+{
+    CriticalBlock block(componentStatusSect);
+    Owned<IESPComponentStatusInfo> status = new CESPComponentStatusInfo(NULL);
+    ForEachItemInRev(i, cache)
+    {
+        IESPComponentStatusInfo& statusInfo = cache.item(i);
+        if (status->cleanExpiredComponentReports(statusInfo))
+            cache.remove(i);
+        else
+            status->mergeComponentStatusInfoFromReports(statusInfo);
+    }
+    return status.getClear();
+}
+
+void CComponentStatusFactory::updateComponentStatus(const char* reporter, IArrayOf<IConstComponentStatus>& statusList)
+{
+    CriticalBlock block(componentStatusSect);
+
+    Owned<IESPComponentStatusInfo> status = new CESPComponentStatusInfo(reporter);
+    status->setComponentStatus(statusList);
+
+    ForEachItemIn(i, cache)
+    {
+        IESPComponentStatusInfo& cachedStatus = cache.item(i);
+        if (strieq(reporter, cachedStatus.getReporter()))
+        {
+            status->mergeCachedComponentStatus(cachedStatus);
+            cache.remove(i);
+            break;
+        }
+    }
+    cache.append(*status.getClear());
+}
+
+static CComponentStatusFactory *csFactory = NULL;
+
+static CriticalSection getComponentStatusSect;
+
+extern COMPONENTSTATUS_API IComponentStatusFactory* getComponentStatusFactory()
+{
+    CriticalBlock block(getComponentStatusSect);
+
+    if (!csFactory)
+        csFactory = new CComponentStatusFactory();
+
+    return LINK(csFactory);
+}

+ 97 - 0
esp/services/ws_machine/componentstatus.hpp

@@ -0,0 +1,97 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "jiface.hpp"
+#include "jlib.hpp"
+#include "esp.hpp"
+#include "componentstatus.ipp"
+#include "ws_machine_esp.ipp"
+
+class CESPComponentStatusInfo : public CInterface, implements IESPComponentStatusInfo
+{
+    StringAttr reporter;
+    StringAttr timeCached;
+    IArrayOf<IEspComponentStatus> statusList;
+
+    bool addToCache; //this CESPComponentStatusInfo object is created by ws_machine.UpdateComponentStatus
+    __int64 expireTimeStamp;
+    int componentStatusID; //the worst component status in the system
+    int componentTypeID; //the worst component status in the system
+    StringAttr componentStatus; //the worst component status in the system
+    StringAttr componentType; //the worst component status in the system
+    StringAttr endPoint; //the worst component status in the system
+    StringAttr timeReportedStr; //the worst component status in the system
+    __int64 timeReported; //the worst component status in the system
+    Owned<IEspStatusReport> componentStatusReport; //the worst component status in the system
+
+    bool isSameComponent(const char* ep, int componentTypeID, IConstComponentStatus& status);
+    void addStatusReport(const char* reporterIn, const char* timeCachedIn, IConstComponentStatus& csIn,
+        IEspComponentStatus& csOut, bool firstReport);
+    void addComponentStatus(const char* reporterIn, const char* timeCachedIn, IConstComponentStatus& st);
+    void appendUnchangedComponentStatus(IEspComponentStatus& statusOld);
+    bool cleanExpiredStatusReports(IArrayOf<IConstStatusReport>& reports);
+
+public:
+    IMPLEMENT_IINTERFACE;
+
+    CESPComponentStatusInfo(const char* _reporter);
+
+    static void init(IPropertyTree* cfg);
+
+    inline const char* getReporter() { return reporter.get(); };
+    inline const char* getTimeCached() { return timeCached.get(); };
+    inline int getComponentStatusID() { return componentStatusID; };
+    inline const char* getComponentStatus() { return componentStatus.get(); };
+    inline const char* getTimeReportedStr() { return timeReportedStr.get(); };
+    inline __int64 getTimeReported() { return timeReported; };
+    inline const int getComponentTypeID() { return componentTypeID; };
+    inline const char* getComponentType() { return componentType.get(); };
+    inline const char* getEndPoint() { return endPoint.get(); };
+    inline IEspStatusReport* getStatusReport() { return componentStatusReport; };
+    inline IArrayOf<IEspComponentStatus>& getComponentStatusList() { return statusList; };
+
+    int queryComponentTypeID(const char *key);
+    int queryComponentStatusID(const char *key);
+    virtual bool cleanExpiredComponentReports(IESPComponentStatusInfo& statusInfo);
+    virtual void mergeComponentStatusInfoFromReports(IESPComponentStatusInfo& statusInfo);
+    virtual void setComponentStatus(IArrayOf<IConstComponentStatus>& statusListIn);
+    void mergeCachedComponentStatus(IESPComponentStatusInfo& statusInfo);
+};
+
+class CComponentStatusFactory : public CInterface, implements IComponentStatusFactory
+{
+    IArrayOf<IESPComponentStatusInfo> cache; //multiple caches from different reporter
+public:
+    IMPLEMENT_IINTERFACE;
+
+    CComponentStatusFactory() { };
+
+    virtual ~CComponentStatusFactory()
+    {
+        cache.kill();
+    };
+
+    virtual void init(IPropertyTree* cfg)
+    {
+        CESPComponentStatusInfo::init(cfg);
+    };
+
+    virtual IESPComponentStatusInfo* getComponentStatus();
+    virtual void updateComponentStatus(const char* reporter, IArrayOf<IConstComponentStatus>& statusList);
+};
+
+extern "C" COMPONENTSTATUS_API IComponentStatusFactory* getComponentStatusFactory();

+ 76 - 0
esp/services/ws_machine/componentstatus.ipp

@@ -0,0 +1,76 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#pragma warning (disable : 4786)
+
+#ifndef _COMPONENTSTATUS_HPP__
+#define _COMPONENTSTATUS_HPP__
+
+#include "jiface.hpp"
+
+class StringBuffer;
+class IPropertyTree;
+class IPropertyTreeIterator;
+
+class IEspStatusReport;
+class IEspComponentStatus;
+class IConstComponentStatus;
+template<class IEspComponentStatus> class IArrayOf;
+
+
+#ifdef WIN32
+    #ifdef SMCLIB_EXPORTS
+        #define COMPONENTSTATUS_API __declspec(dllexport)
+    #else
+        #define COMPONENTSTATUS_API __declspec(dllimport)
+    #endif
+#else
+    #define COMPONENTSTATUS_API
+#endif
+
+class IESPComponentStatusInfo : public IInterface
+{
+public:
+    virtual int queryComponentTypeID(const char *key) = 0;
+    virtual int queryComponentStatusID(const char *key) = 0;
+
+    virtual const char* getReporter() = 0;
+    virtual const char* getTimeCached() = 0;
+    virtual const char* getComponentStatus() = 0;
+    virtual int getComponentStatusID() = 0;
+    virtual const char* getTimeReportedStr() = 0;
+    virtual __int64 getTimeReported() = 0;
+    virtual const char* getEndPoint() = 0;
+    virtual const char* getComponentType() = 0;
+    virtual const int getComponentTypeID() = 0;
+    virtual IEspStatusReport* getStatusReport() = 0;
+    virtual IArrayOf<IEspComponentStatus>& getComponentStatusList() = 0;
+    virtual void setComponentStatus(IArrayOf<IConstComponentStatus>& StatusList) = 0;
+    virtual void mergeCachedComponentStatus(IESPComponentStatusInfo& statusInfo) = 0;
+    virtual void mergeComponentStatusInfoFromReports(IESPComponentStatusInfo& statusInfo) = 0;
+    virtual bool cleanExpiredComponentReports(IESPComponentStatusInfo& statusInfo) = 0;
+};
+
+class IComponentStatusFactory : public IInterface
+{
+public:
+    virtual void init(IPropertyTree* cfg) = 0;
+    virtual IESPComponentStatusInfo* getComponentStatus() = 0;
+    virtual void updateComponentStatus(const char* reporter, IArrayOf<IConstComponentStatus>& StatusList) = 0;
+};
+
+#endif  //_COMPONENTSTATUS_HPP__

+ 70 - 0
esp/services/ws_machine/ws_machineService.cpp

@@ -21,6 +21,7 @@
 #include "exception_util.hpp"
 #include "workunit.hpp"
 #include "roxiecommlibscm.hpp"
+#include "componentstatus.hpp"
 
 #ifndef eqHoleCluster
 #define eqHoleCluster  "HoleCluster"
@@ -198,6 +199,9 @@ void Cws_machineEx::init(IPropertyTree *cfg, const char *process, const char *se
         NULL, m_threadPoolSize, 10000, m_threadPoolStackSize)); //10 sec timeout for available thread; use stack size of 2MB
 
     setupLegacyFilters();
+
+    Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
+    factory->init(pServiceNode);
 }
 
 StringBuffer& Cws_machineEx::getAcceptLanguage(IEspContext& context, StringBuffer& acceptLanguage)
@@ -2255,3 +2259,69 @@ void Cws_machineEx::getAccountAndPlatformInfo(const char* address, StringBuffer&
 
     bLinux = machine->getOS() == MachineOsLinux;
 }
+
+bool Cws_machineEx::onGetComponentStatus(IEspContext &context, IEspGetComponentStatusRequest &req, IEspGetComponentStatusResponse &resp)
+{
+    try
+    {
+        if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
+            throw MakeStringException(ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Get Component Status. Permission denied.");
+
+        Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
+        Owned<IESPComponentStatusInfo> status = factory->getComponentStatus();
+        if (!status) //Should never happen
+            return false;
+
+        int statusID = status->getComponentStatusID();
+        if (statusID < 0)
+        {
+            resp.setStatus("Not reported");
+        }
+        else
+        {
+            resp.setComponentType(status->getComponentType());
+            resp.setEndPoint(status->getEndPoint());
+            resp.setReporter(status->getReporter());
+            resp.setComponentStatus(status->getComponentStatus());
+            resp.setTimeReportedStr(status->getTimeReportedStr());
+
+            IConstStatusReport* componentStatus = status->getStatusReport();
+            if (componentStatus)
+                resp.setStatusReport(*componentStatus);
+
+            resp.setComponentStatusList(status->getComponentStatusList());
+        }
+        resp.setComponentStatusID(statusID);
+        resp.setStatusCode(0);
+    }
+    catch(IException* e)
+    {
+        FORWARDEXCEPTION(context, e,  ECLWATCH_INTERNAL_ERROR);
+    }
+
+    return true;
+}
+
+bool Cws_machineEx::onUpdateComponentStatus(IEspContext &context, IEspUpdateComponentStatusRequest &req, IEspUpdateComponentStatusResponse &resp)
+{
+    try
+    {
+        if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Write, false))
+            throw MakeStringException(ECLWATCH_MACHINE_INFO_ACCESS_DENIED, "Failed to Update Component Status. Permission denied.");
+
+        const char* reporter = req.getReporter();
+        if (!reporter || !*reporter)
+            throw MakeStringException(ECLWATCH_INVALID_INPUT, "Report not specified.");
+        
+        Owned<IComponentStatusFactory> factory = getComponentStatusFactory();
+        factory->updateComponentStatus(reporter, req.getComponentStatusList());
+        resp.setStatusCode(0);
+    }
+    catch(IException* e)
+    {
+        FORWARDEXCEPTION(context, e,  ECLWATCH_INTERNAL_ERROR);
+    }
+
+    return true;
+}
+

+ 2 - 0
esp/services/ws_machine/ws_machineService.hpp

@@ -732,6 +732,8 @@ public:
     bool onGetMachineInfo(IEspContext &context, IEspGetMachineInfoRequest &req, IEspGetMachineInfoResponse &resp);
     bool onGetTargetClusterInfo(IEspContext &context, IEspGetTargetClusterInfoRequest &req, IEspGetTargetClusterInfoResponse &resp);
     bool onGetMachineInfoEx(IEspContext &context, IEspGetMachineInfoRequestEx &req, IEspGetMachineInfoResponseEx &resp);
+    bool onGetComponentStatus(IEspContext &context, IEspGetComponentStatusRequest &req, IEspGetComponentStatusResponse &resp);
+    bool onUpdateComponentStatus(IEspContext &context, IEspUpdateComponentStatusRequest &req, IEspUpdateComponentStatusResponse &resp);
 
     bool onGetMetrics(IEspContext &context, IEspMetricsRequest &req, IEspMetricsResponse &resp);
     bool onStartStop( IEspContext &context, IEspStartStopRequest &req,  IEspStartStopResponse &resp);