Browse Source

Fix gh-813 Add stylesheet on Thor Status

The existing code retrieves the tree branch from Status/servers/
for a thor cluster and convert the branch into XML for display.
This fix adds a ws_topology method and a stylesheet for viewing
thor status based on the tree branch. Major data items of the
tree branch are read and displayed inside a html form. From the
form, a user may click a link to view the XML; a user may click
a link to open thor log file; and, if a WU is running on that
thor process, a user may click a link to view WU Details page.

Signed-off-by: Kevin Wang <kevin.wang@lexisnexis.com>
Kevin Wang 13 years ago
parent
commit
41cef7b2ca

+ 1 - 1
esp/eclwatch/ws_XSLT/cluster_info.xslt

@@ -186,7 +186,7 @@
         </a>
       </td>
       <td>
-        <a href="/WsTopology/TpLogFile/{Name}?Name={Name}&amp;Type=xml">
+        <a href="/WsTopology/TpThorStatus?Name={Name}">
           <xsl:value-of select="Name"/>
         </a>
       </td>

+ 230 - 0
esp/eclwatch/ws_XSLT/thor_status.xslt

@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (C) 2011 HPCC Systems.
+
+    All rights reserved. This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as
+    published by the Free Software Foundation, either version 3 of the
+    License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+    <xsl:output method="html"/>
+    <xsl:variable name="autoRefresh" select="TpThorStatusResponse/AutoRefresh"/>
+    <xsl:variable name="thorName" select="TpThorStatusResponse/Name"/>
+    <xsl:template match="TpThorStatusResponse">
+        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+            <head>
+                <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+                <title>ThorStatus</title>
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/fonts/fonts-min.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/menu/assets/skins/sam/menu.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/button/assets/skins/sam/button.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/css/espdefault.css" />
+                <link rel="stylesheet" type="text/css" href="/esp/files/css/eclwatch.css" />
+                <link rel="StyleSheet" type="text/css" href="/esp/files/css/sortabletable.css"/>
+                <script type="text/javascript" src="/esp/files/scripts/espdefault.js">&#160;</script>
+                <script type="text/javascript">
+                    var thorName='<xsl:value-of select="$thorName"/>';
+                    var autoRefreshVal=<xsl:value-of select="$autoRefresh"/>;
+                    var doRefresh = true;
+                    <xsl:text disable-output-escaping="yes"><![CDATA[
+                        var reloadTimer = null;
+                        var reloadTimeout = 0;
+                        function SetAutoRefresh()
+                        {
+                            var refreshImg = document.getElementById('refresh');
+                            if (autoRefreshVal > 0)            
+                            {
+                                if (refreshImg)
+                                {
+                                    refreshImg.src = '/esp/files_/img/refreshenabled.png';
+                                }
+                                setReloadTimeout(autoRefreshVal); // Pass a default value
+                            }
+                            else
+                            {
+                                if (refreshImg)
+                                {
+                                    refreshImg.src = '/esp/files_/img/refreshdisabled.png';
+                                }
+                            }               
+                        }
+
+                        function TurnRefresh() 
+                        {
+                            if (doRefresh)
+                            {
+                                doRefresh = false;
+                                document.getElementById('refresh').src='/esp/files_/img/refreshdisabled.png';
+                                reloadTimeout = 0;
+                                if (reloadTimer) 
+                                {              
+                                    clearTimeout(reloadTimer);
+                                    reloadTimer = null;
+                                }               
+                            }
+                            else
+                            {
+                                doRefresh = true;
+                                document.getElementById('refresh').src='/esp/files_/img/refreshenabled.png';
+                                setReloadTimeout(autoRefreshVal); // Pass a default value
+                            }
+                        }
+
+                        function setReloadTimeout(mins) 
+                        {
+                            if (reloadTimeout == mins)
+                                return; 
+
+                            if (reloadTimer) 
+                            {              
+                                clearTimeout(reloadTimer);
+                                reloadTimer = null;
+                            }               
+                            if (mins > 0)
+                            {
+                                reloadTimer = setTimeout('reloadPage()', Math.ceil(parseFloat(mins) * 60 * 1000));
+                            }
+                            reloadTimeout = mins;
+                        }
+        
+                        function reloadPage() 
+                        {
+                            /*var globalframe = document.getElementById('GlobalFrame');
+                            if (globalframe)
+                            {
+                                globalframe.src = '/WsTopology/TpThorStatus?Name=' + thorName;
+                            }*/
+                            document.location.href = '/WsTopology/TpThorStatus?Name=' + thorName;
+                        }
+                    ]]></xsl:text>
+                </script>
+            </head>
+            <body class="yui-skin-sam" onload="nof5();SetAutoRefresh();">
+                <h3>Thor Status Details</h3>
+                <table style="text-align:left;" cellspacing="10">
+                    <colgroup style="vertical-align:top;padding-right:10px;" span="2">
+                    </colgroup>
+                    <tr>
+                        <th>Name:</th>
+                        <td>
+                            <a href="javascript:go('/WsTopology/TpLogFile/{Name}?Name={Name}&amp;Type=xml')">
+                                <xsl:value-of select="Name"/>
+                            </a>
+                            <img id="refresh" src="/esp/files/img/refresh.png" onclick="TurnRefresh()" title="Turn on/off Auto Refresh" />
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>Queue:</th>
+                        <td>
+                            <xsl:value-of select="Queue"/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>Node Group:</th>
+                        <td>
+                            <xsl:value-of select="Group"/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>ThorMaster Address:</th>
+                        <td>
+                            <xsl:value-of select="ThorMasterIPAddress"/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>Port:</th>
+                        <td>
+                            <xsl:value-of select="Port"/>
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>Started:</th>
+                        <td>
+                            <xsl:value-of select="StartTime"/>
+                        </td>
+                    </tr>
+                    <xsl:if test="string-length(Wuid)">
+                        <tr>
+                            <th>Workunit:</th>
+                            <td>
+                                <a href="javascript:go('/WsWorkunits/WUInfo?Wuid={Wuid}')">
+                                    <xsl:value-of select="Wuid"/>
+                                </a>
+                            </td>
+                        </tr>
+                        <tr>
+                            <th></th>
+                            <td>
+                                <table class="sort-table" id="resultsTable">
+                                    <colgroup>
+                                        <col />
+                                        <col />
+                                        <col />
+                                    </colgroup>
+                                    <thead>
+                                        <tr class="grey">
+                                            <th>
+                                                Graph
+                                            </th>
+                                            <th>
+                                                SubGraph
+                                            </th>
+                                            <th>
+                                                SubGraph Duration
+                                            </th>
+                                        </tr>
+                                    </thead>
+                                    <tbody>
+                                        <tr>
+                                            <td>
+                                                <xsl:if test="string-length(Graph)">
+                                                    <xsl:value-of select="Graph"/>
+                                                </xsl:if>
+                                            </td>
+                                            <td>
+                                                <xsl:if test="string-length(SubGraph)">
+                                                    <xsl:value-of select="SubGraph"/>
+                                                </xsl:if>
+                                            </td>
+                                            <td>
+                                                <xsl:if test="string-length(SubGraphDuration)">
+                                                    <xsl:value-of select="SubGraphDuration"/>
+                                                </xsl:if>
+                                            </td>
+                                        </tr>
+                                    </tbody>
+                                </table>
+                            </td>
+                        </tr>
+                    </xsl:if>
+                    <xsl:if test="string-length(LogFile)">
+                        <tr>
+                            <th>Log File:</th>
+                            <td>
+                                <a href="javascript:go('/WsTopology/TpLogFile/{Name}?Name={Name}&amp;Type=thormaster_log')">
+                                    <xsl:value-of select="LogFile"/>
+                                </a>
+                            </td>
+                        </tr>
+                    </xsl:if>
+                </table>
+                <xsl:text disable-output-escaping="yes"><![CDATA[
+                    <iframe id="GlobalFrame" name="GlobalFrame" style="display:none; visibility:hidden;"></iframe>
+                ]]></xsl:text>
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template match="text()|comment()"/>
+</xsl:stylesheet>

+ 22 - 0
esp/scm/ws_topology.ecm

@@ -522,6 +522,27 @@ ESPresponse [exceptions_inline] TpGetComponentFileResponse
     [http_content("application/octet-stream")] binary FileContents;
 };
 
+ESPrequest TpThorStatusRequest
+{
+    string Name;
+};
+
+ESPresponse [exceptions_inline,encode(0)] TpThorStatusResponse
+{
+    string Name;
+    string Queue;
+    string Group;
+    string ThorMasterIPAddress;
+    int Port;
+    string StartTime;
+    string LogFile;
+    string Wuid;
+    string Graph;
+    int SubGraph;
+    int SubGraphDuration;
+    int AutoRefresh;
+};
+
 ESPservice [noforms, version("1.17"), default_client_version("1.17"), exceptions_inline("./smc_xslt/exceptions.xslt")] WsTopology
 {
     ESPuses ESPStruct TpBinding;
@@ -551,6 +572,7 @@ ESPservice [noforms, version("1.17"), default_client_version("1.17"), exceptions
     ESPmethod TpGroupQuery(TpGroupQueryRequest, TpGroupQueryResponse);
     ESPmethod [resp_xsl_default("/esp/xslt/machines.xslt")] TpMachineQuery(TpMachineQueryRequest, TpMachineQueryResponse);
     ESPmethod [resp_xsl_default("/esp/xslt/cluster_info.xslt")] TpClusterInfo(TpClusterInfoRequest, TpClusterInfoResponse);
+    ESPmethod [resp_xsl_default("/esp/xslt/thor_status.xslt")] TpThorStatus(TpThorStatusRequest, TpThorStatusResponse);
 
     ESPmethod [resp_xsl_default("/esp/xslt/services.xslt")] TpServiceQuery(TpServiceQueryRequest, TpServiceQueryResponse);
     ESPmethod TpSetMachineStatus(TpSetMachineStatusRequest, TpSetMachineStatusResponse);

+ 61 - 6
esp/services/ws_topology/ws_topologyService.cpp

@@ -41,9 +41,8 @@
 static const char* FEATURE_URL = "ClusterTopologyAccess";
 static const char* MACHINE_URL = "MachineInfoAccess";
 
-//static const long LOGFILESIZELIMIT = 10000000; //In case of a huge file
+static const unsigned THORSTATUSDETAILS_REFRESH_MINS = 1;
 static const long LOGFILESIZELIMIT = 100000; //Limit page size to 100k
-//static const long LOGFILESIZELIMIT = 1000; //In case of a huge file
 static const long AVERAGELOGROWSIZE = 2000;
 const char* TEMPZIPDIR = "tempzipfiles";
 
@@ -558,13 +557,15 @@ bool CWsTopologyEx::onTpXMLFile(IEspContext &context,IEspTpXMLFileRequest  &req,
         if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
             throw MakeStringException(ECLWATCH_TOPOLOGY_ACCESS_DENIED, "Failed to get Configuration File. Permission denied.");
 
-        StringBuffer strBuff;
-        getThorXml(req.getName(),strBuff);
+        StringBuffer strBuff, xmlBuff;
+        strBuff.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><?xml-stylesheet href=\"../esp/xslt/xmlformatter.xsl\" type=\"text/xsl\"?>");
+        getThorXml(req.getName(),xmlBuff);
+        strBuff.append(xmlBuff);
         
         MemoryBuffer membuff;
         membuff.setBuffer(strBuff.length(), (void*)strBuff.toCharArray());
-        
-        resp.setThefile_mimetype("text/xml");
+
+        resp.setThefile_mimetype(HTTP_TYPE_TEXT_XML);
         resp.setThefile(membuff);
     }
     catch(IException* e)
@@ -1760,3 +1761,57 @@ bool CWsTopologyEx::onTpGetComponentFile(IEspContext &context,
     }
     return true;
 }
+
+bool CWsTopologyEx::onTpThorStatus(IEspContext &context, IEspTpThorStatusRequest &req, IEspTpThorStatusResponse &resp)
+{
+    try
+    {
+        if (!context.validateFeatureAccess(FEATURE_URL, SecAccess_Read, false))
+            throw MakeStringException(ECLWATCH_TOPOLOGY_ACCESS_DENIED, "Failed to access Thor status. Permission denied.");
+
+        const char* name   = req.getName();
+        if (!name || !*name)
+            throw MakeStringException(ECLWATCH_INVALID_INPUT, "Thor name not specified.");
+
+        CCluster conn(name);
+        IPropertyTree *root = conn->queryRoot();
+        if (!root)
+            throw MakeStringException(ECLWATCH_INVALID_INPUT, "Failed to access Thor status.");
+
+        resp.setName( name );
+        resp.setQueue( root->queryProp("@queue") );
+        resp.setGroup( root->queryProp("@nodeGroup") );
+        resp.setThorMasterIPAddress( root->queryProp("@node"));
+        resp.setPort( root->getPropInt("@mpport", -1));
+        resp.setStartTime( root->queryProp("@started") );
+        const char *LogFile = root->queryProp("LogFile");
+        if (LogFile && *LogFile)
+            resp.setLogFile( LogFile );
+        const char *wuid = root->queryProp("WorkUnit");
+        if (wuid && *wuid)
+        {
+            resp.setWuid( wuid );
+            const char *graph = root->queryProp("@graph");
+            if (graph && *graph)
+            {
+                resp.setGraph( graph );
+                int subgraph = root->getPropInt("@subgraph", -1);
+                if (subgraph > -1)
+                {
+                    resp.setSubGraph( subgraph );
+                }
+                int duration = root->getPropInt("@sg_duration", -1);
+                if (duration > -1)
+                {
+                    resp.setSubGraphDuration( duration );
+                }
+            }
+        }
+        resp.setAutoRefresh(THORSTATUSDETAILS_REFRESH_MINS);
+    }
+    catch(IException* e)
+    {
+        FORWARDEXCEPTION(context, e,  ECLWATCH_INTERNAL_ERROR);
+    }
+    return false;
+}

+ 2 - 0
esp/services/ws_topology/ws_topologyService.hpp

@@ -126,6 +126,8 @@ public:
     bool onTpServiceQuery(IEspContext &context, IEspTpServiceQueryRequest &req, IEspTpServiceQueryResponse &resp);
 
     bool onTpGetComponentFile(IEspContext &context, IEspTpGetComponentFileRequest &req, IEspTpGetComponentFileResponse &resp);
+
+    bool onTpThorStatus(IEspContext &context, IEspTpThorStatusRequest &req, IEspTpThorStatusResponse &resp);
 };