azkaban-uncached
Changes
src/java/azkaban/execapp/JMXHttpServlet.java 73(+73 -0)
src/java/azkaban/webapp/servlet/velocity/jmxpage.vm 100(+75 -25)
src/web/js/azkaban.jmx.view.js 263(+91 -172)
Details
diff --git a/src/java/azkaban/execapp/AzkabanExecutorServer.java b/src/java/azkaban/execapp/AzkabanExecutorServer.java
index 7c25028..4f5fd02 100644
--- a/src/java/azkaban/execapp/AzkabanExecutorServer.java
+++ b/src/java/azkaban/execapp/AzkabanExecutorServer.java
@@ -22,8 +22,10 @@ import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.TimeZone;
+import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
@@ -92,8 +94,8 @@ public class AzkabanExecutorServer {
Context root = new Context(server, "/", Context.SESSIONS);
root.setMaxFormContentSize(MAX_FORM_CONTENT_SIZE);
- ServletHolder executorHolder = new ServletHolder(new ExecutorServlet());
- root.addServlet(executorHolder, "/executor");
+ root.addServlet(new ServletHolder(new ExecutorServlet()), "/executor");
+ root.addServlet(new ServletHolder(new JMXHttpServlet()), "/jmx");
root.setAttribute(AzkabanServletContextListener.AZKABAN_SERVLET_CONTEXT_KEY, this);
@@ -322,4 +324,26 @@ public class AzkabanExecutorServer {
}
}
+
+ public List<ObjectName> getMbeanNames() {
+ return registeredMBeans;
+ }
+
+ public MBeanInfo getMBeanInfo(ObjectName name) {
+ try {
+ return mbeanServer.getMBeanInfo(name);
+ } catch (Exception e) {
+ logger.error(e);
+ return null;
+ }
+ }
+
+ public Object getMBeanAttribute(ObjectName name, String attribute) {
+ try {
+ return mbeanServer.getAttribute(name, attribute);
+ } catch (Exception e) {
+ logger.error(e);
+ return null;
+ }
+ }
}
\ No newline at end of file
src/java/azkaban/execapp/JMXHttpServlet.java 73(+73 -0)
diff --git a/src/java/azkaban/execapp/JMXHttpServlet.java b/src/java/azkaban/execapp/JMXHttpServlet.java
new file mode 100644
index 0000000..0ee2ebc
--- /dev/null
+++ b/src/java/azkaban/execapp/JMXHttpServlet.java
@@ -0,0 +1,73 @@
+package azkaban.execapp;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.ObjectName;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+
+import azkaban.executor.ConnectorParams;
+import azkaban.utils.JSONUtils;
+import azkaban.webapp.servlet.AzkabanServletContextListener;
+import azkaban.webapp.servlet.HttpRequestUtils;
+
+public class JMXHttpServlet extends HttpServlet implements ConnectorParams {
+ private static final long serialVersionUID = -3085603824826446270L;
+ private static final Logger logger = Logger.getLogger(JMXHttpServlet.class);
+ private AzkabanExecutorServer server;
+
+ public void init(ServletConfig config) throws ServletException {
+ server = (AzkabanExecutorServer) config.getServletContext().getAttribute(AzkabanServletContextListener.AZKABAN_SERVLET_CONTEXT_KEY);
+ }
+
+ public boolean hasParam(HttpServletRequest request, String param) {
+ return HttpRequestUtils.hasParam(request, param);
+ }
+
+ public String getParam(HttpServletRequest request, String name) throws ServletException {
+ return HttpRequestUtils.getParam(request, name);
+ }
+
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ HashMap<String,Object> ret = new HashMap<String,Object>();
+
+ if (hasParam(req, JMX_GET_MBEANS)) {
+ ret.put("mbeans", server.getMbeanNames());
+ }
+ else if (hasParam(req, JMX_GET_ALL_MBEAN_ATTRIBUTES)) {
+ if (!hasParam(req, JMX_MBEAN)) {
+ ret.put("error", "Parameters 'mbean' must be set");
+ }
+ else {
+ String mbeanName = getParam(req, JMX_MBEAN);
+ try {
+ ObjectName name = new ObjectName(mbeanName);
+ MBeanInfo info = server.getMBeanInfo(name);
+
+ MBeanAttributeInfo[] mbeanAttrs = info.getAttributes();
+ HashMap<String, Object> attributes = new HashMap<String,Object>();
+
+ for (MBeanAttributeInfo attrInfo: mbeanAttrs) {
+ Object obj = server.getMBeanAttribute(name, attrInfo.getName());
+ attributes.put(attrInfo.getName(), obj);
+ }
+
+ ret.put("attributes", attributes);
+ } catch (Exception e) {
+ logger.error(e);
+ ret.put("error", "'" + mbeanName + "' is not a valid mBean name");
+ }
+ }
+ }
+
+ JSONUtils.toJSON(ret, resp.getOutputStream(), true);
+ }
+}
diff --git a/src/java/azkaban/executor/ConnectorParams.java b/src/java/azkaban/executor/ConnectorParams.java
index 7bac5d1..8ee9250 100644
--- a/src/java/azkaban/executor/ConnectorParams.java
+++ b/src/java/azkaban/executor/ConnectorParams.java
@@ -72,4 +72,14 @@ public interface ConnectorParams {
public static final String UPDATE_MAP_START_TIME = "startTime";
public static final String UPDATE_MAP_END_TIME = "endTime";
public static final String UPDATE_MAP_NODES = "nodes";
+
+ public static final String JMX_GET_MBEANS = "getMBeans";
+ public static final String JMX_GET_MBEAN_INFO = "getMBeanInfo";
+ public static final String JMX_GET_MBEAN_ATTRIBUTE = "getAttribute";
+ public static final String JMX_GET_ALL_MBEAN_ATTRIBUTES = "getAllMBeanAttributes";
+ public static final String JMX_ATTRIBUTE = "attribute";
+ public static final String JMX_MBEAN = "mBean";
+
+ public static final String JMX_GET_ALL_EXECUTOR_ATTRIBUTES = "getAllExecutorAttributes";
+ public static final String JMX_HOSTPORT = "hostPort";
}
diff --git a/src/java/azkaban/executor/ExecutorManager.java b/src/java/azkaban/executor/ExecutorManager.java
index 76f76ec..c724792 100644
--- a/src/java/azkaban/executor/ExecutorManager.java
+++ b/src/java/azkaban/executor/ExecutorManager.java
@@ -23,8 +23,10 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang.StringUtils;
@@ -105,6 +107,25 @@ public class ExecutorManager {
return this.lastCleanerThreadCheckTime;
}
+ public Set<String> getPrimaryServerHosts() {
+ // Only one for now. More probably later.
+ HashSet<String> ports = new HashSet<String>();
+ ports.add(executorHost + ":" + executorPort);
+ return ports;
+ }
+
+ public Set<String> getAllActiveExecutorServerHosts() {
+ // Includes non primary server/hosts
+ HashSet<String> ports = new HashSet<String>();
+ ports.add(executorHost + ":" + executorPort);
+ for(Pair<ExecutionReference, ExecutableFlow> running: runningFlows.values()) {
+ ExecutionReference ref = running.getFirst();
+ ports.add(ref.getHost() + ":" + ref.getPort());
+ }
+
+ return ports;
+ }
+
private void loadRunningFlows() throws ExecutorManagerException {
runningFlows.putAll(executorLoader.fetchActiveFlows());
}
@@ -472,6 +493,51 @@ public class ExecutorManager {
return jsonResponse;
}
+ public Map<String, Object> callExecutorJMX(String hostPort, String action, String mBean) throws IOException {
+ URIBuilder builder = new URIBuilder();
+
+ String[] hostPortSplit = hostPort.split(":");
+ builder.setScheme("http")
+ .setHost(hostPortSplit[0])
+ .setPort(Integer.parseInt(hostPortSplit[1]))
+ .setPath("/jmx");
+
+ builder.setParameter(action, "");
+ if (mBean != null) {
+ builder.setParameter(ConnectorParams.JMX_MBEAN, mBean);
+ }
+
+ URI uri = null;
+ try {
+ uri = builder.build();
+ } catch (URISyntaxException e) {
+ throw new IOException(e);
+ }
+
+ ResponseHandler<String> responseHandler = new BasicResponseHandler();
+
+ HttpClient httpclient = new DefaultHttpClient();
+ HttpGet httpget = new HttpGet(uri);
+ String response = null;
+ try {
+ response = httpclient.execute(httpget, responseHandler);
+ } catch (IOException e) {
+ throw e;
+ }
+ finally {
+ httpclient.getConnectionManager().shutdown();
+ }
+
+ System.out.println(response);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> jsonResponse = (Map<String, Object>)JSONUtils.parseJSONFromString(response);
+ String error = (String)jsonResponse.get(ConnectorParams.RESPONSE_ERROR);
+ if (error != null) {
+ throw new IOException(error);
+ }
+ return jsonResponse;
+ }
+
public void shutdown() {
executingManager.shutdown();
}
diff --git a/src/java/azkaban/jmx/JmxExecutorManager.java b/src/java/azkaban/jmx/JmxExecutorManager.java
index 35b18a1..123340d 100644
--- a/src/java/azkaban/jmx/JmxExecutorManager.java
+++ b/src/java/azkaban/jmx/JmxExecutorManager.java
@@ -1,5 +1,8 @@
package azkaban.jmx;
+import java.util.ArrayList;
+import java.util.List;
+
import azkaban.executor.ExecutorManager;
public class JmxExecutorManager implements JmxExecutorManagerMBean {
@@ -28,4 +31,9 @@ public class JmxExecutorManager implements JmxExecutorManagerMBean {
public Long getLastThreadCheckTime() {
return manager.getLastThreadCheckTime();
}
+
+ @Override
+ public List<String> getPrimaryExecutorHostPorts() {
+ return new ArrayList<String>(manager.getPrimaryServerHosts());
+ }
}
diff --git a/src/java/azkaban/jmx/JmxExecutorManagerMBean.java b/src/java/azkaban/jmx/JmxExecutorManagerMBean.java
index d5649a4..b4a3888 100644
--- a/src/java/azkaban/jmx/JmxExecutorManagerMBean.java
+++ b/src/java/azkaban/jmx/JmxExecutorManagerMBean.java
@@ -1,5 +1,7 @@
package azkaban.jmx;
+import java.util.List;
+
public interface JmxExecutorManagerMBean {
@DisplayName("OPERATION: getNumRunningFlows")
public int getNumRunningFlows();
@@ -12,4 +14,7 @@ public interface JmxExecutorManagerMBean {
@DisplayName("OPERATION: getLastThreadCheckTime")
public Long getLastThreadCheckTime();
+
+ @DisplayName("OPERATION: getPrimaryExecutorHostPorts")
+ public List<String> getPrimaryExecutorHostPorts();
}
diff --git a/src/java/azkaban/webapp/servlet/JMXHttpServlet.java b/src/java/azkaban/webapp/servlet/JMXHttpServlet.java
index 6bd1e94..27bbb3f 100644
--- a/src/java/azkaban/webapp/servlet/JMXHttpServlet.java
+++ b/src/java/azkaban/webapp/servlet/JMXHttpServlet.java
@@ -1,10 +1,11 @@
package azkaban.webapp.servlet;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Comparator;
import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.ObjectName;
import javax.servlet.ServletConfig;
@@ -14,17 +15,20 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
+import azkaban.executor.ConnectorParams;
+import azkaban.executor.ExecutorManager;
import azkaban.user.Permission;
import azkaban.user.Role;
import azkaban.user.User;
import azkaban.user.UserManager;
+import azkaban.utils.Pair;
import azkaban.webapp.AzkabanWebServer;
import azkaban.webapp.session.Session;
/**
* Limited set of jmx calls for when you cannot attach to the jvm
*/
-public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
+public class JMXHttpServlet extends LoginAbstractAzkabanServlet implements ConnectorParams {
/**
*
*/
@@ -34,12 +38,7 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
private UserManager userManager;
private AzkabanWebServer server;
-
- private static final String GET_MBEANS = "getMBeans";
- private static final String GET_MBEAN_INFO = "getMBeanInfo";
- private static final String GET_MBEAN_ATTRIBUTE = "getAttribute";
- private static final String ATTRIBUTE = "attribute";
- private static final String MBEAN = "mBean";
+ private ExecutorManager executorManager;
@Override
public void init(ServletConfig config) throws ServletException {
@@ -47,23 +46,38 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
server = (AzkabanWebServer)getApplication();
userManager = server.getUserManager();
+ executorManager = server.getExecutorManager();
}
@Override
protected void handleGet(HttpServletRequest req, HttpServletResponse resp, Session session) throws ServletException, IOException {
if (hasParam(req, "ajax")){
- HashMap<String,Object> ret = new HashMap<String,Object>();
+ Map<String,Object> ret = new HashMap<String,Object>();
if(!hasAdminRole(session.getUser())) {
ret.put("error", "User " + session.getUser().getUserId() + " has no permission.");
+ this.writeJSON(resp, ret, true);
+ return;
}
String ajax = getParam(req, "ajax");
- if (GET_MBEANS.equals(ajax)) {
+ if (JMX_GET_ALL_EXECUTOR_ATTRIBUTES.equals(ajax)) {
+ if (!hasParam(req, JMX_MBEAN) || !hasParam(req, JMX_HOSTPORT)) {
+ ret.put("error", "Parameters '" + JMX_MBEAN + "' and '"+ JMX_HOSTPORT +"' must be set");
+ this.writeJSON(resp, ret, true);
+ return;
+ }
+
+ String hostPort = getParam(req, JMX_HOSTPORT);
+ String mbean = getParam(req, JMX_MBEAN);
+ Map<String, Object> result = executorManager.callExecutorJMX(hostPort, JMX_GET_ALL_MBEAN_ATTRIBUTES, mbean);
+ ret = result;
+ }
+ else if (JMX_GET_MBEANS.equals(ajax)) {
ret.put("mbeans", server.getMbeanNames());
}
- else if (GET_MBEAN_INFO.equals(ajax)) {
- if (hasParam(req, MBEAN)) {
- String mbeanName = getParam(req, MBEAN);
+ else if (JMX_GET_MBEAN_INFO.equals(ajax)) {
+ if (hasParam(req, JMX_MBEAN)) {
+ String mbeanName = getParam(req, JMX_MBEAN);
try {
ObjectName name = new ObjectName(mbeanName);
MBeanInfo info = server.getMBeanInfo(name);
@@ -78,13 +92,13 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
ret.put("error", "No 'mbean' name parameter specified" );
}
}
- else if (GET_MBEAN_ATTRIBUTE.equals(ajax)) {
- if (!hasParam(req, MBEAN) || !hasParam(req, ATTRIBUTE)) {
+ else if (JMX_GET_MBEAN_ATTRIBUTE.equals(ajax)) {
+ if (!hasParam(req, JMX_MBEAN) || !hasParam(req, JMX_ATTRIBUTE)) {
ret.put("error", "Parameters 'mbean' and 'attribute' must be set");
}
else {
- String mbeanName = getParam(req, MBEAN);
- String attribute = getParam(req, ATTRIBUTE);
+ String mbeanName = getParam(req, JMX_MBEAN);
+ String attribute = getParam(req, JMX_ATTRIBUTE);
try {
ObjectName name = new ObjectName(mbeanName);
@@ -96,11 +110,36 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
}
}
}
+ else if (JMX_GET_ALL_MBEAN_ATTRIBUTES.equals(ajax)) {
+ if (!hasParam(req, JMX_MBEAN)) {
+ ret.put("error", "Parameters 'mbean' must be set");
+ }
+ else {
+ String mbeanName = getParam(req, JMX_MBEAN);
+ try {
+ ObjectName name = new ObjectName(mbeanName);
+ MBeanInfo info = server.getMBeanInfo(name);
+
+ MBeanAttributeInfo[] mbeanAttrs = info.getAttributes();
+ HashMap<String, Object> attributes = new HashMap<String,Object>();
+
+ for (MBeanAttributeInfo attrInfo: mbeanAttrs) {
+ Object obj = server.getMBeanAttribute(name, attrInfo.getName());
+ attributes.put(attrInfo.getName(), obj);
+ }
+
+ ret.put("attributes", attributes);
+ } catch (Exception e) {
+ logger.error(e);
+ ret.put("error", "'" + mbeanName + "' is not a valid mBean name");
+ }
+ }
+ }
else {
ret.put("commands", new String[] {
- GET_MBEANS,
- GET_MBEAN_INFO+"&"+MBEAN+"=<name>",
- GET_MBEAN_ATTRIBUTE+"&"+MBEAN+"=<name>&"+ATTRIBUTE+"=<attributename>"}
+ JMX_GET_MBEANS,
+ JMX_GET_MBEAN_INFO+"&"+JMX_MBEAN+"=<name>",
+ JMX_GET_MBEAN_ATTRIBUTE+"&"+JMX_MBEAN+"=<name>&"+JMX_ATTRIBUTE+"=<attributename>"}
);
}
this.writeJSON(resp, ret, true);
@@ -110,7 +149,7 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
}
}
- private void handleJMXPage(HttpServletRequest req, HttpServletResponse resp, Session session) {
+ private void handleJMXPage(HttpServletRequest req, HttpServletResponse resp, Session session) throws IOException {
Page page = newPage(req, resp, session, "azkaban/webapp/servlet/velocity/jmxpage.vm");
if(!hasAdminRole(session.getUser())) {
@@ -120,7 +159,21 @@ public class JMXHttpServlet extends LoginAbstractAzkabanServlet {
}
page.add("mbeans", server.getMbeanNames());
+
+ Map<String, Object> executorMBeans = new HashMap<String,Object>();
+ Set<String> primaryServerHosts = executorManager.getPrimaryServerHosts();
+ for (String hostPort: executorManager.getAllActiveExecutorServerHosts()) {
+ Map<String, Object> mbeans = executorManager.callExecutorJMX(hostPort, JMX_GET_MBEANS, null);
+ if (primaryServerHosts.contains(hostPort)) {
+ executorMBeans.put(hostPort, mbeans.get("mbeans"));
+ }
+ else {
+ executorMBeans.put(hostPort, mbeans.get("mbeans"));
+ }
+ }
+
+ page.add("remoteMBeans", executorMBeans);
page.render();
}
diff --git a/src/java/azkaban/webapp/servlet/velocity/index.vm b/src/java/azkaban/webapp/servlet/velocity/index.vm
index d884bb7..46e2ed0 100644
--- a/src/java/azkaban/webapp/servlet/velocity/index.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/index.vm
@@ -92,7 +92,7 @@
<td class="tb-owner">$project.lastModifiedUser</td>
</tr>
<tr class="childrow" id="${project.name}-child" style="display: none;">
- <td class="expandedFlow">
+ <td class="expandedFlow" colspan="3">
<table class="innerTable">
<thead>
<tr><th class="tb-name">Flows</th></tr>
src/java/azkaban/webapp/servlet/velocity/jmxpage.vm 100(+75 -25)
diff --git a/src/java/azkaban/webapp/servlet/velocity/jmxpage.vm b/src/java/azkaban/webapp/servlet/velocity/jmxpage.vm
index 64fcc9c..2a0e945 100644
--- a/src/java/azkaban/webapp/servlet/velocity/jmxpage.vm
+++ b/src/java/azkaban/webapp/servlet/velocity/jmxpage.vm
@@ -23,6 +23,7 @@
<script type="text/javascript" src="${context}/js/underscore-1.4.4-min.js"></script>
<script type="text/javascript" src="${context}/js/backbone-0.9.10-min.js"></script>
<script type="text/javascript" src="${context}/js/azkaban.nav.js"></script>
+ <script type="text/javascript" src="${context}/js/azkaban.jmx.view.js"></script>
<script type="text/javascript">
var contextURL = "${context}";
var currentTime = ${currentTime};
@@ -33,6 +34,7 @@
</head>
<body>
#set($current_page="all")
+#set($counter=0)
#parse( "azkaban/webapp/servlet/velocity/nav.vm" )
#if($errorMsg)
<div class="box-error-message"><pre>$errorMsg</pre></div>
@@ -40,47 +42,95 @@
<div class="content">
<div id="all-jobs-content">
- <div class="section-hd flow-header">
+ <div class="section-hd">
<h2><a href="${context}/jmx">Admin JMX Http Page</span></a></h2>
</div>
</div>
-
- <div id="flow-tabs">
- <table id="all-jobs" class="all-jobs job-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>Domain</th>
- <th>Canonical Name</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
+ <h3 class="subhead">Web Client JMX</h3>
+
+ <table id="all-jobs" class="all-jobs job-table">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Domain</th>
+ <th>Canonical Name</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
#foreach($bean in $mbeans)
+ <tr>
+ <td>${bean.keyPropertyList.get("name")}</td>
+ <td>${bean.domain}</td>
+ <td>${bean.canonicalName}</td>
+ <td><div class="btn4 querybtn" id="expandBtn-$counter" domain="${bean.domain}" name="${bean.keyPropertyList.get("name")}">Query</div></td>
+ </tr>
+
+ <tr class="childrow" id="expandBtn-${counter}-child" style="display: none;">
+ <td class="expandedFlow" colspan="3">
+ <table class="innerTable">
+ <thead>
+ <tr>
+ <th>Attribute Name</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tbody id="expandBtn-${counter}-tbody">
+ </tbody>
+ </table>
+ </td>
+
+ <td>
+ <div class="btn4 collapse">Collapse</div>
+ </td>
+ </tr>
+#set($counter=$counter + 1)
+#end
+ </tbody>
+ </table>
+
+#foreach($executor in $remoteMBeans.entrySet())
+ <h3 class="subhead">Remote Executor JMX $executor.key</h3>
+ <table class="all-jobs job-table remoteJMX">
+ <thead>
<tr>
- <td>${bean.keyPropertyList.get("name")}</td>
- <td>${bean.domain}</td>
- <td>${bean.canonicalName}</td>
- <td><div class="btn4 querybtn" id="${bean.canonicalName}">Query</div></td>
+ <th>Name</th>
+ <th>Domain</th>
+ <th>Canonical Name</th>
+ <th></th>
</tr>
- <tr class="childrow" id="${bean.canonicalName}-child" style="display: none;">
- <td class="expandedFlow">
+ </thead>
+ <tbody>
+ #foreach($bean in $executor.value)
+ <tr>
+ <td>${bean.get("keyPropertyList").get("name")}</td>
+ <td>${bean.get("domain")}</td>
+ <td>${bean.get("canonicalName")}</td>
+ <td><div class="btn4 querybtn" id="expandBtn-$counter" domain="${bean.get("domain")}" name="${bean.get("keyPropertyList").get("name")}" hostport="$executor.key">Query</div></td>
+ </tr>
+ <tr class="childrow" id="expandBtn-${counter}-child" style="display: none;">
+ <td class="expandedFlow" colspan="3">
<table class="innerTable">
<thead>
<tr>
- <th class="tb-name">Attribute Name</th>
+ <th>Attribute Name</th>
<th>Value</th>
</tr>
</thead>
- <tbody id="${bean.canonicalName}-tbody">
+ <tbody id="expandBtn-${counter}-tbody">
</tbody>
</table>
</td>
- </tr>
+
+ <td>
+ <div class="btn4 collapse">Collapse</div>
+ </td>
+ </tr>
+ #set($counter=$counter + 1)
+ #end
+ </tbody>
+ </table>
#end
- </tbody>
- </table>
- </div>
</div>
</body>
</html>
src/web/js/azkaban.jmx.view.js 263(+91 -172)
diff --git a/src/web/js/azkaban.jmx.view.js b/src/web/js/azkaban.jmx.view.js
index 5c9193a..7309c07 100644
--- a/src/web/js/azkaban.jmx.view.js
+++ b/src/web/js/azkaban.jmx.view.js
@@ -1,189 +1,108 @@
$.namespace('azkaban');
-var projectTableView;
-azkaban.ProjectTableView= Backbone.View.extend({
+var jmxTableView;
+azkaban.JMXTableView= Backbone.View.extend({
events : {
- "click .project-expand": "expandProject"
+ "click .querybtn": "queryJMX",
+ "click .collapse": "collapseRow"
},
initialize : function(settings) {
},
- expandProject : function(evt) {
- if (evt.target.tagName!="SPAN") {
- return;
- }
-
- var target = evt.currentTarget;
- var targetId = target.id;
- var requestURL = contextURL + "/manager";
-
- var targetExpanded = $('#' + targetId + '-child');
- var targetTBody = $('#' + targetId + '-tbody');
-
- var createFlowListFunction = this.createFlowListTable;
-
- if (target.loading) {
- console.log("Still loading.");
- }
- else if (target.loaded) {
- if($(targetExpanded).is(':visible')) {
- $(target).addClass('expand').removeClass('collapse');
- $(targetExpanded).fadeOut("fast");
- }
- else {
- $(target).addClass('collapse').removeClass('expand');
- $(targetExpanded).fadeIn();
- }
- }
- else {
- // projectId is available
- $(target).addClass('wait').removeClass('collapse').removeClass('expand');
- target.loading = true;
-
- $.get(
- requestURL,
- {"project": targetId, "ajax":"fetchprojectflows"},
- function(data) {
- console.log("Success");
- target.loaded = true;
- target.loading = false;
-
- createFlowListFunction(data, targetTBody);
-
- $(target).addClass('collapse').removeClass('wait');
- $(targetExpanded).fadeIn("fast");
- },
- "json"
- );
- }
- },
- render: function() {
- },
- createFlowListTable : function(data, innerTable) {
- var flows = data.flows;
- flows.sort(function(a,b){return a.flowId.localeCompare(b.flowId);});
-
- var requestURL = contextURL + "/manager?project=" + data.project + "&flow=";
- for (var i = 0; i < flows.length; ++i) {
- var id = flows[i].flowId;
-
- var tr = document.createElement("tr");
- var idtd = document.createElement("td");
- $(idtd).addClass("tb-name");
-
- var ida = document.createElement("a");
- ida.project = data.project;
- $(ida).text(id);
- $(ida).attr("href", requestURL + id);
-
- $(idtd).append(ida);
- $(tr).append(idtd);
- $(innerTable).append(tr);
- }
- }
-});
-
-var projectHeaderView;
-azkaban.ProjectHeaderView= Backbone.View.extend({
- events : {
- "click #create-project-btn":"handleCreateProjectJob"
- },
- initialize : function(settings) {
- if (settings.errorMsg && settings.errorMsg != "null") {
- // Chrome bug in displaying placeholder text. Need to hide the box.
- $('#searchtextbox').hide();
- $('.messaging').addClass("error");
- $('.messaging').removeClass("success");
- $('.messaging').html(settings.errorMsg);
- }
- else if (settings.successMsg && settings.successMsg != "null") {
- $('#searchtextbox').hide();
- $('.messaging').addClass("success");
- $('.messaging').removeClass("error");
- $('#message').html(settings.successMsg);
- }
- else {
- $('#searchtextbox').show();
- $('.messaging').removeClass("success");
- $('.messaging').removeClass("error");
- }
-
- $('#messageClose').click(function() {
- $('#searchtextbox').show();
-
- $('.messaging').slideUp('fast', function() {
- $('.messaging').removeClass("success");
- $('.messaging').removeClass("error");
- });
- });
- },
- handleCreateProjectJob : function(evt) {
- console.log("click create project");
- $('#create-project').modal({
- closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>",
- position: ["20%",],
- containerId: 'confirm-container',
- containerCss: {
- 'height': '220px',
- 'width': '565px'
- },
- onShow: function (dialog) {
- var modal = this;
- $("#errorMsg").hide();
- }
- });
- },
- render: function() {
- }
-});
+ queryJMX : function(evt) {
+ var target = evt.currentTarget;
+ var id = target.id;
+
+ var childID = id + "-child";
+ var tbody = id + "-tbody";
+
+ var requestURL = contextURL + "/jmx";
+ var canonicalName=$(target).attr("domain") + ":name=" + $(target).attr("name");
-var createProjectView;
-azkaban.CreateProjectView= Backbone.View.extend({
- events : {
- "click #create-btn": "handleCreateProject"
+ var data = {"ajax":"getAllMBeanAttributes", "mBean":canonicalName};
+ if ($(target).attr("hostPort")) {
+ data.ajax = "getAllExecutorAttributes";
+ data.hostPort = $(target).attr("hostPort");
+ }
+ $.get(
+ requestURL,
+ data,
+ function(data) {
+ var table = $('#' + tbody);
+ $(table).empty();
+
+ for(var key in data.attributes) {
+ var value = data.attributes[key];
+
+ var tr = document.createElement("tr");
+ var tdName = document.createElement("td");
+ var tdVal = document.createElement("td");
+
+ $(tdName).text(key);
+ $(tdVal).text(value);
+
+ $(tr).append(tdName);
+ $(tr).append(tdVal);
+
+ $('#' + tbody).append(tr);
+ }
+
+ var child = $("#" + childID);
+ $(child).fadeIn();
+ }
+ );
},
- initialize : function(settings) {
- $("#errorMsg").hide();
+ queryRemote : function(evt) {
+ var target = evt.currentTarget;
+ var id = target.id;
+
+ var childID = id + "-child";
+ var tbody = id + "-tbody";
+
+ var requestURL = contextURL + "/jmx";
+ var canonicalName=$(target).attr("domain") + ":name=" + $(target).attr("name");
+ var hostPort = $(target).attr("hostport");
+ $.get(
+ requestURL,
+ {"ajax":"getAllExecutorAttributes", "mBean":canonicalName, "hostPort": hostPort},
+ function(data) {
+ var table = $('#' + tbody);
+ $(table).empty();
+
+ for(var key in data.attributes) {
+ var value = data.attributes[key];
+
+ var tr = document.createElement("tr");
+ var tdName = document.createElement("td");
+ var tdVal = document.createElement("td");
+
+ $(tdName).text(key);
+ $(tdVal).text(value);
+
+ $(tr).append(tdName);
+ $(tr).append(tdVal);
+
+ $('#' + tbody).append(tr);
+ }
+
+ var child = $("#" + childID);
+ $(child).fadeIn();
+ }
+ );
},
- handleCreateProject : function(evt) {
- // First make sure we can upload
- var projectName = $('#path').val();
- var description = $('#description').val();
-
- console.log("Creating");
- $.ajax({
- async: "false",
- url: "manager",
- dataType: "json",
- type: "POST",
- data: {action:"create", name:projectName, description:description},
- success: function(data) {
- if (data.status == "success") {
- if (data.action == "redirect") {
- window.location = data.path;
- }
- }
- else {
- if (data.action == "login") {
- window.location = "";
- }
- else {
- $("#errorMsg").text("ERROR: " + data.message);
- $("#errorMsg").slideDown("fast");
- }
- }
- }
- });
-
+ collapseRow: function(evt) {
+ $(evt.currentTarget).parent().parent().fadeOut();
},
render: function() {
}
});
-var tableSorterView;
+var remoteTables = new Array();
$(function() {
- projectHeaderView = new azkaban.ProjectHeaderView({el:$( '#all-jobs-content'), successMsg: successMessage, errorMsg: errorMessage });
- projectTableView = new azkaban.ProjectTableView({el:$('#all-jobs')});
- tableSorterView = new azkaban.TableSorter({el:$('#all-jobs'), initialSort: $('.tb-name')});
- uploadView = new azkaban.CreateProjectView({el:$('#create-project')});
+ jmxTableView = new azkaban.JMXTableView({el:$('#all-jobs')});
+
+ $(".remoteJMX").each(function(item) {
+ var newTableView = new azkaban.JMXTableView({el:$(this)});
+ remoteTables.push(newTables);
+ });
});