YARN-4515. [YARN-3368] Support hosting web UI framework inside YARN RM. (Sunil G via wangda)
YARN-5000. [YARN-3368] App attempt page is not loading when timeline server is not started (Sunil G via wangda) YARN-5038. [YARN-3368] Application and Container pages shows wrong values when RM is stopped. (Sunil G via wangda)
This commit is contained in:
parent
2c4f164e16
commit
c85cc3b56e
|
@ -2328,6 +2328,7 @@ The Apache Hadoop YARN Web UI component bundles the following files under the MI
|
||||||
- datatables v1.10.8 (https://datatables.net/)
|
- datatables v1.10.8 (https://datatables.net/)
|
||||||
- moment v2.10.6 (http://momentjs.com/) - Copyright (c) 2011-2015 Tim Wood, Iskren Chernev, Moment.js contributors
|
- moment v2.10.6 (http://momentjs.com/) - Copyright (c) 2011-2015 Tim Wood, Iskren Chernev, Moment.js contributors
|
||||||
- em-helpers v0.5.8 (https://github.com/sreenaths/em-helpers)
|
- em-helpers v0.5.8 (https://github.com/sreenaths/em-helpers)
|
||||||
|
- ember-array-contains-helper v1.0.2 (https://github.com/bmeurant/ember-array-contains-helper)
|
||||||
- ember-cli-app-version v0.5.8 (https://github.com/EmberSherpa/ember-cli-app-version) - Authored by Taras Mankovski <tarasm@gmail.com>
|
- ember-cli-app-version v0.5.8 (https://github.com/EmberSherpa/ember-cli-app-version) - Authored by Taras Mankovski <tarasm@gmail.com>
|
||||||
- ember-cli-babel v5.1.6 (https://github.com/babel/ember-cli-babel) - Authored by Stefan Penner <stefan.penner@gmail.com>
|
- ember-cli-babel v5.1.6 (https://github.com/babel/ember-cli-babel) - Authored by Stefan Penner <stefan.penner@gmail.com>
|
||||||
- ember-cli-content-security-policy v0.4.0 (https://github.com/rwjblue/ember-cli-content-security-policy)
|
- ember-cli-content-security-policy v0.4.0 (https://github.com/rwjblue/ember-cli-content-security-policy)
|
||||||
|
@ -2341,6 +2342,7 @@ The Apache Hadoop YARN Web UI component bundles the following files under the MI
|
||||||
- ember-cli-sri v1.2.1 (https://github.com/jonathanKingston/ember-cli-sri) - Authored by Jonathan Kingston
|
- ember-cli-sri v1.2.1 (https://github.com/jonathanKingston/ember-cli-sri) - Authored by Jonathan Kingston
|
||||||
- ember-cli-uglify v1.2.0 (github.com/ember-cli/ember-cli-uglify) - Authored by Robert Jackson <me@rwjblue.com>
|
- ember-cli-uglify v1.2.0 (github.com/ember-cli/ember-cli-uglify) - Authored by Robert Jackson <me@rwjblue.com>
|
||||||
- ember-d3 v0.1.0 (https://github.com/brzpegasus/ember-d3) - Authored by Estelle DeBlois
|
- ember-d3 v0.1.0 (https://github.com/brzpegasus/ember-d3) - Authored by Estelle DeBlois
|
||||||
|
- ember-truth-helpers v1.2.0 (https://github.com/jmurphyau/ember-truth-helpers)
|
||||||
- select2 v4.0.0 (https://select2.github.io/)
|
- select2 v4.0.0 (https://select2.github.io/)
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
|
@ -192,6 +192,13 @@
|
||||||
<directory>${project.build.directory}/site</directory>
|
<directory>${project.build.directory}/site</directory>
|
||||||
<outputDirectory>/share/doc/hadoop/${hadoop.component}</outputDirectory>
|
<outputDirectory>/share/doc/hadoop/${hadoop.component}</outputDirectory>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>hadoop-yarn/hadoop-yarn-ui/target/hadoop-yarn-ui-${project.version}</directory>
|
||||||
|
<outputDirectory>/share/hadoop/${hadoop.component}/webapps/rm</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>**/*</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
</fileSets>
|
</fileSets>
|
||||||
<moduleSets>
|
<moduleSets>
|
||||||
<moduleSet>
|
<moduleSet>
|
||||||
|
|
|
@ -262,7 +262,30 @@ public class YarnConfiguration extends Configuration {
|
||||||
public static final int DEFAULT_RM_WEBAPP_HTTPS_PORT = 8090;
|
public static final int DEFAULT_RM_WEBAPP_HTTPS_PORT = 8090;
|
||||||
public static final String DEFAULT_RM_WEBAPP_HTTPS_ADDRESS = "0.0.0.0:"
|
public static final String DEFAULT_RM_WEBAPP_HTTPS_ADDRESS = "0.0.0.0:"
|
||||||
+ DEFAULT_RM_WEBAPP_HTTPS_PORT;
|
+ DEFAULT_RM_WEBAPP_HTTPS_PORT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable YARN WebApp V2.
|
||||||
|
*/
|
||||||
|
public static final String RM_WEBAPP_UI2_ENABLE = RM_PREFIX
|
||||||
|
+ "webapp.ui2.enable";
|
||||||
|
public static final boolean DEFAULT_RM_WEBAPP_UI2_ENABLE = false;
|
||||||
|
|
||||||
|
/** The address of the RM web ui2 application. */
|
||||||
|
public static final String RM_WEBAPP_UI2_ADDRESS = RM_PREFIX
|
||||||
|
+ "webapp.ui2.address";
|
||||||
|
|
||||||
|
public static final int DEFAULT_RM_WEBAPP_UI2_PORT = 8288;
|
||||||
|
public static final String DEFAULT_RM_WEBAPP_UI2_ADDRESS = "0.0.0.0:" +
|
||||||
|
DEFAULT_RM_WEBAPP_UI2_PORT;
|
||||||
|
|
||||||
|
/** The https address of the RM web ui2 application.*/
|
||||||
|
public static final String RM_WEBAPP_UI2_HTTPS_ADDRESS =
|
||||||
|
RM_PREFIX + "webapp.ui2.https.address";
|
||||||
|
|
||||||
|
public static final int DEFAULT_RM_WEBAPP_UI2_HTTPS_PORT = 8290;
|
||||||
|
public static final String DEFAULT_RM_WEBAPP_UI2_HTTPS_ADDRESS = "0.0.0.0:"
|
||||||
|
+ DEFAULT_RM_WEBAPP_UI2_HTTPS_PORT;
|
||||||
|
|
||||||
public static final String RM_RESOURCE_TRACKER_ADDRESS =
|
public static final String RM_RESOURCE_TRACKER_ADDRESS =
|
||||||
RM_PREFIX + "resource-tracker.address";
|
RM_PREFIX + "resource-tracker.address";
|
||||||
public static final int DEFAULT_RM_RESOURCE_TRACKER_PORT = 8031;
|
public static final int DEFAULT_RM_RESOURCE_TRACKER_PORT = 8031;
|
||||||
|
|
|
@ -179,6 +179,32 @@
|
||||||
<value>true</value>
|
<value>true</value>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<description>To enable RM web ui2 application.</description>
|
||||||
|
<name>yarn.resourcemanager.webapp.ui2.enable</name>
|
||||||
|
<value>false</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<description>
|
||||||
|
The http address of the RM web ui2 application.
|
||||||
|
If only a host is provided as the value,
|
||||||
|
the webapp will be served on a random port.
|
||||||
|
</description>
|
||||||
|
<name>yarn.resourcemanager.webapp.ui2.address</name>
|
||||||
|
<value>${yarn.resourcemanager.hostname}:8288</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
|
<description>
|
||||||
|
The https address of the RM web ui2 application.
|
||||||
|
If only a host is provided as the value,
|
||||||
|
the webapp will be served on a random port.
|
||||||
|
</description>
|
||||||
|
<name>yarn.resourcemanager.webapp.ui2.https.address</name>
|
||||||
|
<value>${yarn.resourcemanager.hostname}:8290</value>
|
||||||
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>yarn.resourcemanager.resource-tracker.address</name>
|
<name>yarn.resourcemanager.resource-tracker.address</name>
|
||||||
<value>${yarn.resourcemanager.hostname}:8031</value>
|
<value>${yarn.resourcemanager.hostname}:8031</value>
|
||||||
|
|
|
@ -18,16 +18,6 @@
|
||||||
|
|
||||||
package org.apache.hadoop.yarn.server.resourcemanager;
|
package org.apache.hadoop.yarn.server.resourcemanager;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.security.PrivilegedExceptionAction;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.curator.framework.AuthInfo;
|
import org.apache.curator.framework.AuthInfo;
|
||||||
|
@ -38,10 +28,12 @@ import org.apache.hadoop.classification.InterfaceAudience.Private;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.ha.HAServiceProtocol;
|
import org.apache.hadoop.ha.HAServiceProtocol;
|
||||||
import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
|
import org.apache.hadoop.ha.HAServiceProtocol.HAServiceState;
|
||||||
|
import org.apache.hadoop.http.HttpServer2;
|
||||||
import org.apache.hadoop.http.lib.StaticUserWebFilter;
|
import org.apache.hadoop.http.lib.StaticUserWebFilter;
|
||||||
import org.apache.hadoop.metrics2.MetricsSystem;
|
import org.apache.hadoop.metrics2.MetricsSystem;
|
||||||
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
|
||||||
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
import org.apache.hadoop.metrics2.source.JvmMetrics;
|
||||||
|
import org.apache.hadoop.net.NetUtils;
|
||||||
import org.apache.hadoop.security.AuthenticationFilterInitializer;
|
import org.apache.hadoop.security.AuthenticationFilterInitializer;
|
||||||
import org.apache.hadoop.security.Groups;
|
import org.apache.hadoop.security.Groups;
|
||||||
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
import org.apache.hadoop.security.HttpCrossOriginFilterInitializer;
|
||||||
|
@ -124,6 +116,16 @@ import org.apache.hadoop.yarn.webapp.util.WebAppUtils;
|
||||||
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
|
import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ResourceManager is the main class that is a set of components.
|
* The ResourceManager is the main class that is a set of components.
|
||||||
|
@ -909,7 +911,49 @@ public class ResourceManager extends CompositeService implements Recoverable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a HttpServer.Builder that the journalnode / namenode / secondary
|
||||||
|
* namenode can use to initialize their HTTP / HTTPS server.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static HttpServer2.Builder httpServerTemplateForRM(Configuration conf,
|
||||||
|
final InetSocketAddress httpAddr, final InetSocketAddress httpsAddr,
|
||||||
|
String name) throws IOException {
|
||||||
|
HttpServer2.Builder builder = new HttpServer2.Builder().setName(name)
|
||||||
|
.setConf(conf).setSecurityEnabled(false);
|
||||||
|
|
||||||
|
if (httpAddr.getPort() == 0) {
|
||||||
|
builder.setFindPort(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uri = URI.create("http://" + NetUtils.getHostPortString(httpAddr));
|
||||||
|
builder.addEndpoint(uri);
|
||||||
|
LOG.info("Starting Web-server for " + name + " at: " + uri);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startWebAppV2() throws IOException {
|
||||||
|
Configuration config = getConfig();
|
||||||
|
final InetSocketAddress httpAddr = config.getSocketAddr(
|
||||||
|
YarnConfiguration.RM_WEBAPP_UI2_ADDRESS,
|
||||||
|
YarnConfiguration.DEFAULT_RM_WEBAPP_UI2_ADDRESS,
|
||||||
|
YarnConfiguration.DEFAULT_RM_WEBAPP_UI2_PORT);
|
||||||
|
final InetSocketAddress httpsAddr = config.getSocketAddr(
|
||||||
|
YarnConfiguration.RM_WEBAPP_UI2_HTTPS_ADDRESS,
|
||||||
|
YarnConfiguration.DEFAULT_RM_WEBAPP_UI2_HTTPS_ADDRESS,
|
||||||
|
YarnConfiguration.DEFAULT_RM_WEBAPP_UI2_HTTPS_PORT);
|
||||||
|
|
||||||
|
HttpServer2.Builder builder = httpServerTemplateForRM(config, httpAddr,
|
||||||
|
httpsAddr, "rm");
|
||||||
|
|
||||||
|
HttpServer2 infoServer = builder.build();
|
||||||
|
infoServer.start();
|
||||||
|
|
||||||
|
LOG.info("Web server init done");
|
||||||
|
}
|
||||||
|
|
||||||
protected void startWepApp() {
|
protected void startWepApp() {
|
||||||
|
|
||||||
// Use the customized yarn filter instead of the standard kerberos filter to
|
// Use the customized yarn filter instead of the standard kerberos filter to
|
||||||
|
@ -1128,6 +1172,16 @@ public class ResourceManager extends CompositeService implements Recoverable {
|
||||||
transitionToActive();
|
transitionToActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getConfig().getBoolean(YarnConfiguration.RM_WEBAPP_UI2_ENABLE,
|
||||||
|
YarnConfiguration.DEFAULT_RM_WEBAPP_UI2_ENABLE)) {
|
||||||
|
try {
|
||||||
|
startWebAppV2();
|
||||||
|
LOG.info("Yarn WebApp UI 2 is started");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Failed to start Yarn web app v2:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
startWepApp();
|
startWepApp();
|
||||||
if (getConfig().getBoolean(YarnConfiguration.IS_MINI_YARN_CLUSTER,
|
if (getConfig().getBoolean(YarnConfiguration.IS_MINI_YARN_CLUSTER,
|
||||||
false)) {
|
false)) {
|
||||||
|
|
|
@ -20,12 +20,12 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hadoop-yarn</artifactId>
|
<artifactId>hadoop-yarn</artifactId>
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<version>3.0.0-SNAPSHOT</version>
|
<version>3.0.0-alpha1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<artifactId>hadoop-yarn-ui</artifactId>
|
<artifactId>hadoop-yarn-ui</artifactId>
|
||||||
<version>3.0.0-SNAPSHOT</version>
|
<version>3.0.0-alpha1-SNAPSHOT</version>
|
||||||
<name>Apache Hadoop YARN UI</name>
|
<name>Apache Hadoop YARN UI</name>
|
||||||
<packaging>${packaging.type}</packaging>
|
<packaging>${packaging.type}</packaging>
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,8 @@ export default AbstractAdapter.extend({
|
||||||
|
|
||||||
urlForFindRecord(id, modelName, snapshot) {
|
urlForFindRecord(id, modelName, snapshot) {
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
var url = url + '/apps/' +
|
return url + '/apps/' +
|
||||||
Converter.attemptIdToAppId(id) + "/appattempts/" + id;
|
Converter.attemptIdToAppId(id) + "/appattempts/" + id;
|
||||||
console.log('app-attempt url:',url);
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default DS.RESTAdapter.extend({
|
||||||
var nodeHttpAddr = splits[0];
|
var nodeHttpAddr = splits[0];
|
||||||
var containerId = splits[1];
|
var containerId = splits[1];
|
||||||
var filename = splits[2];
|
var filename = splits[2];
|
||||||
this.host = this.host + nodeHttpAddr;
|
this.host = this.get('host') + nodeHttpAddr;
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
url = url + "/containerlogs/" + containerId + "/" + filename;
|
url = url + "/containerlogs/" + containerId + "/" + filename;
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -25,14 +25,20 @@ export default AbstractAdapter.extend({
|
||||||
serverName: "NM",
|
serverName: "NM",
|
||||||
|
|
||||||
urlForQuery(query) {
|
urlForQuery(query) {
|
||||||
this.host = this.get("host") + query.nodeAddr;
|
var extension = this.get("host").split('/').pop();
|
||||||
|
if (extension != query.nodeAddr) {
|
||||||
|
this.host = this.get("host") + query.nodeAddr;
|
||||||
|
}
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
url = url + "/apps";
|
url = url + "/apps";
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
urlForQueryRecord: function (query) {
|
urlForQueryRecord: function (query) {
|
||||||
this.host = this.get("host") + query.nodeAddr;
|
var extension = this.get("host").split('/').pop();
|
||||||
|
if (extension != query.nodeAddr) {
|
||||||
|
this.host = this.get("host") + query.nodeAddr;
|
||||||
|
}
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
url = url + "/apps/" + query.appId;
|
url = url + "/apps/" + query.appId;
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -25,14 +25,20 @@ export default AbstractAdapter.extend({
|
||||||
serverName: "NM",
|
serverName: "NM",
|
||||||
|
|
||||||
urlForQuery(query) {
|
urlForQuery(query) {
|
||||||
this.host = this.get("host") + query.nodeHttpAddr;
|
var extension = this.get("host").split('/').pop();
|
||||||
|
if (extension != query.nodeHttpAddr) {
|
||||||
|
this.host = this.get("host") + query.nodeHttpAddr;
|
||||||
|
}
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
url = url + "/containers";
|
url = url + "/containers";
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
urlForQueryRecord(query) {
|
urlForQueryRecord(query) {
|
||||||
this.host = this.get("host") + query.nodeHttpAddr;
|
var extension = this.get("host").split('/').pop();
|
||||||
|
if (extension != query.nodeHttpAddr) {
|
||||||
|
this.host = this.get("host") + query.nodeHttpAddr;
|
||||||
|
}
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
url = url + "/containers/" + query.containerId;
|
url = url + "/containers/" + query.containerId;
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -25,7 +25,10 @@ export default AbstractAdapter.extend({
|
||||||
serverName: "NM",
|
serverName: "NM",
|
||||||
|
|
||||||
urlForFindRecord(id, modelName, snapshot) {
|
urlForFindRecord(id, modelName, snapshot) {
|
||||||
this.host = this.get("host") + id;
|
var extension = this.get("host").split('/').pop();
|
||||||
|
if (extension != id) {
|
||||||
|
this.host = this.get("host") + id;
|
||||||
|
}
|
||||||
var url = this._buildURL();
|
var url = this._buildURL();
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
|
@ -225,18 +225,27 @@ export default Ember.Component.extend({
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
// init tooltip
|
// init tooltip
|
||||||
this.initTooltip();
|
this.initTooltip();
|
||||||
|
this.modelArr = [];
|
||||||
|
|
||||||
// init model
|
// init model
|
||||||
if (this.get("rmModel")) {
|
if (this.get("rmModel")) {
|
||||||
this.get("rmModel").forEach(function(o) {
|
this.get("rmModel").forEach(function(o) {
|
||||||
this.modelArr.push(o);
|
if(!this.modelArr.contains(o)) {
|
||||||
|
this.modelArr.push(o);
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.get("tsModel")) {
|
if (this.get("tsModel")) {
|
||||||
this.get("tsModel").forEach(function(o) {
|
this.get("tsModel").forEach(function(o) {
|
||||||
this.modelArr.push(o);
|
if(!this.modelArr.contains(o)) {
|
||||||
}.bind(this));
|
this.modelArr.push(o);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.modelArr.length == 0) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modelArr.sort(function(a, b) {
|
this.modelArr.sort(function(a, b) {
|
||||||
|
|
|
@ -126,7 +126,7 @@ export default Ember.Component.extend({
|
||||||
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
|
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
|
||||||
.on("click", function(d,i){
|
.on("click", function(d,i){
|
||||||
if (d.queueData.get("name") != this.get("selected")) {
|
if (d.queueData.get("name") != this.get("selected")) {
|
||||||
document.location.href = "yarn-queue/" + d.queueData.get("name");
|
document.location.href = "#/yarn-queue/" + d.queueData.get("name");
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
// .on("click", click);
|
// .on("click", click);
|
||||||
|
@ -176,7 +176,7 @@ export default Ember.Component.extend({
|
||||||
.attr("r", 20)
|
.attr("r", 20)
|
||||||
.attr("href",
|
.attr("href",
|
||||||
function(d) {
|
function(d) {
|
||||||
return "yarn-queues/" + d.queueData.get("name");
|
return "#/yarn-queues/" + d.queueData.get("name");
|
||||||
})
|
})
|
||||||
.style("stroke", function(d) {
|
.style("stroke", function(d) {
|
||||||
if (d.queueData.get("name") == this.get("selected")) {
|
if (d.queueData.get("name") == this.get("selected")) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default Ember.Helper.helper(function(params,hash) {
|
||||||
var html = '<td>';
|
var html = '<td>';
|
||||||
var logFilesCommaSeparated = "";
|
var logFilesCommaSeparated = "";
|
||||||
for (var i = 0; i < logFilesLen; i++) {
|
for (var i = 0; i < logFilesLen; i++) {
|
||||||
html = html + '<a href="yarn-container-log/' + nodeId + '/' +
|
html = html + '<a href="#/yarn-container-log/' + nodeId + '/' +
|
||||||
nodeAddr + '/' + containerId + '/' + logFiles[i] + '">' + logFiles[i] +
|
nodeAddr + '/' + containerId + '/' + logFiles[i] + '">' + logFiles[i] +
|
||||||
'</a>';
|
'</a>';
|
||||||
if (i != logFilesLen - 1) {
|
if (i != logFilesLen - 1) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default Ember.Helper.helper(function(params,hash) {
|
||||||
if (nodeState == "SHUTDOWN" || nodeState == "LOST") {
|
if (nodeState == "SHUTDOWN" || nodeState == "LOST") {
|
||||||
html = html + nodeHTTPAddress;
|
html = html + nodeHTTPAddress;
|
||||||
} else {
|
} else {
|
||||||
html = html + '<a href="yarn-node/' + nodeId + "/" + nodeHTTPAddress + '">' +
|
html = html + '<a href="#/yarn-node/' + nodeId + "/" + nodeHTTPAddress + '">' +
|
||||||
nodeHTTPAddress + '</a>';
|
nodeHTTPAddress + '</a>';
|
||||||
}
|
}
|
||||||
html = html + '</td>';
|
html = html + '</td>';
|
||||||
|
|
|
@ -50,17 +50,17 @@ export default Ember.Helper.helper(function(params,hash) {
|
||||||
if (hash.path == 'yarn-node') {
|
if (hash.path == 'yarn-node') {
|
||||||
html = html + ' class="active"';
|
html = html + ' class="active"';
|
||||||
}
|
}
|
||||||
html = html + '><a href="yarn-node/' + hash.nodeId + '/' + hash.nodeAddr +
|
html = html + '><a href="#/yarn-node/' + hash.nodeId + '/' + hash.nodeAddr +
|
||||||
'">Node Information</a></li><li';
|
'">Node Information</a></li><li';
|
||||||
if (hash.path == 'yarn-node-apps') {
|
if (hash.path == 'yarn-node-apps') {
|
||||||
html = html + ' class="active"';
|
html = html + ' class="active"';
|
||||||
}
|
}
|
||||||
html = html + '><a href="yarn-node-apps/' + hash.nodeId + '/' + hash.nodeAddr +
|
html = html + '><a href="#/yarn-node-apps/' + hash.nodeId + '/' + hash.nodeAddr +
|
||||||
'">List of Applications</a></li><li';
|
'">List of Applications</a></li><li';
|
||||||
if (hash.path == 'yarn-node-containers') {
|
if (hash.path == 'yarn-node-containers') {
|
||||||
html = html + ' class="active"';
|
html = html + ' class="active"';
|
||||||
}
|
}
|
||||||
html = html + '><a href="yarn-node-containers/' +hash.nodeId + '/' + hash.nodeAddr +
|
html = html + '><a href="#/yarn-node-containers/' +hash.nodeId + '/' + hash.nodeAddr +
|
||||||
'">List of Containers</a></li></ul></ul></div>';
|
'">List of Containers</a></li></ul></ul></div>';
|
||||||
return Ember.String.htmlSafe(html);
|
return Ember.String.htmlSafe(html);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
export function nodeName(params/*, hash*/) {
|
||||||
|
// Place a menu within a panel inside col-md-2 container.
|
||||||
|
console.log('nodes-uid', params[0]);
|
||||||
|
var nodeIdSplitAtPort = params[0];
|
||||||
|
var portIndex = nodeIdSplitAtPort.indexOf(':');
|
||||||
|
if (portIndex != -1) {
|
||||||
|
nodeIdSplitAtPort = nodeIdSplitAtPort.substring(0, portIndex) +
|
||||||
|
':​' + nodeIdSplitAtPort.substring(portIndex + 1);
|
||||||
|
}
|
||||||
|
var normalizedNodeId = '';
|
||||||
|
var splitsAlongDots = nodeIdSplitAtPort.split('.');
|
||||||
|
if (splitsAlongDots) {
|
||||||
|
var len = splitsAlongDots.length;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
normalizedNodeId = normalizedNodeId + splitsAlongDots[i];
|
||||||
|
if (i != len - 1) {
|
||||||
|
normalizedNodeId = normalizedNodeId + '.​';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
normalizedNodeId = nodeIdSplitAtPort;
|
||||||
|
}
|
||||||
|
return Ember.String.htmlSafe(normalizedNodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Ember.Helper.helper(nodeName);
|
|
@ -21,14 +21,29 @@ import Converter from 'yarn-ui/utils/converter';
|
||||||
|
|
||||||
export default DS.Model.extend({
|
export default DS.Model.extend({
|
||||||
startTime: DS.attr('string'),
|
startTime: DS.attr('string'),
|
||||||
|
startedTime: DS.attr('string'),
|
||||||
finishedTime: DS.attr('string'),
|
finishedTime: DS.attr('string'),
|
||||||
containerId: DS.attr('string'),
|
containerId: DS.attr('string'),
|
||||||
|
amContainerId: DS.attr('string'),
|
||||||
nodeHttpAddress: DS.attr('string'),
|
nodeHttpAddress: DS.attr('string'),
|
||||||
nodeId: DS.attr('string'),
|
nodeId: DS.attr('string'),
|
||||||
|
hosts: DS.attr('string'),
|
||||||
logsLink: DS.attr('string'),
|
logsLink: DS.attr('string'),
|
||||||
|
state: DS.attr('string'),
|
||||||
|
|
||||||
|
attemptStartedTime: function() {
|
||||||
|
var startTime = this.get("startTime");
|
||||||
|
// If startTime variable is not present, get from startedTime
|
||||||
|
if (startTime == undefined ||
|
||||||
|
startTime == "Invalid date") {
|
||||||
|
startTime = this.get("startedTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
return startTime;
|
||||||
|
}.property("startedTime"),
|
||||||
|
|
||||||
startTs: function() {
|
startTs: function() {
|
||||||
return Converter.dateToTimeStamp(this.get("startTime"));
|
return Converter.dateToTimeStamp(this.get('attemptStartedTime'));
|
||||||
}.property("startTime"),
|
}.property("startTime"),
|
||||||
|
|
||||||
finishedTs: function() {
|
finishedTs: function() {
|
||||||
|
@ -36,11 +51,57 @@ export default DS.Model.extend({
|
||||||
return ts;
|
return ts;
|
||||||
}.property("finishedTime"),
|
}.property("finishedTime"),
|
||||||
|
|
||||||
|
validatedFinishedTs: function() {
|
||||||
|
if (this.get("finishedTs") < this.get("startTs")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return this.get("finishedTime");
|
||||||
|
}.property("finishedTime"),
|
||||||
|
|
||||||
shortAppAttemptId: function() {
|
shortAppAttemptId: function() {
|
||||||
|
if (!this.get("containerId")) {
|
||||||
|
return this.get("id");
|
||||||
|
}
|
||||||
return "attempt_" +
|
return "attempt_" +
|
||||||
parseInt(Converter.containerIdToAttemptId(this.get("containerId")).split("_")[3]);
|
parseInt(Converter.containerIdToAttemptId(this.get("containerId")).split("_")[3]);
|
||||||
}.property("containerId"),
|
}.property("containerId"),
|
||||||
|
|
||||||
|
appMasterContainerId: function() {
|
||||||
|
var id = this.get("containerId");
|
||||||
|
// If containerId variable is not present, get from amContainerId
|
||||||
|
if (id == undefined) {
|
||||||
|
id = this.get("amContainerId");
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}.property("amContainerId"),
|
||||||
|
|
||||||
|
IsAmNodeUrl: function() {
|
||||||
|
var url = this.get("nodeHttpAddress");
|
||||||
|
// If nodeHttpAddress variable is not present, hardcode it.
|
||||||
|
if (url == undefined) {
|
||||||
|
url = "Not Available";
|
||||||
|
}
|
||||||
|
return url != "Not Available";
|
||||||
|
}.property("nodeHttpAddress"),
|
||||||
|
|
||||||
|
amNodeId : function() {
|
||||||
|
var id = this.get("nodeId");
|
||||||
|
// If nodeId variable is not present, get from host
|
||||||
|
if (id == undefined) {
|
||||||
|
id = this.get("hosts");
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}.property("nodeId"),
|
||||||
|
|
||||||
|
IsLinkAvailable: function() {
|
||||||
|
var url = this.get("logsLink");
|
||||||
|
// If logsLink variable is not present, hardcode its.
|
||||||
|
if (url == undefined) {
|
||||||
|
url = "Not Available";
|
||||||
|
}
|
||||||
|
return url != "Not Available";
|
||||||
|
}.property("logsLink"),
|
||||||
|
|
||||||
elapsedTime: function() {
|
elapsedTime: function() {
|
||||||
var elapsedMs = this.get("finishedTs") - this.get("startTs");
|
var elapsedMs = this.get("finishedTs") - this.get("startTs");
|
||||||
if (elapsedMs <= 0) {
|
if (elapsedMs <= 0) {
|
||||||
|
@ -59,4 +120,13 @@ export default DS.Model.extend({
|
||||||
link: function() {
|
link: function() {
|
||||||
return "/yarn-app-attempt/" + this.get("id");
|
return "/yarn-app-attempt/" + this.get("id");
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
|
linkname: function() {
|
||||||
|
return "yarn-app-attempt";
|
||||||
|
}.property(),
|
||||||
|
|
||||||
|
attemptState: function() {
|
||||||
|
return this.get("state");
|
||||||
|
}.property(),
|
||||||
|
|
||||||
});
|
});
|
|
@ -51,6 +51,13 @@ export default DS.Model.extend({
|
||||||
return this.get('finalStatus') == "FAILED"
|
return this.get('finalStatus') == "FAILED"
|
||||||
}.property("finalStatus"),
|
}.property("finalStatus"),
|
||||||
|
|
||||||
|
validatedFinishedTs: function() {
|
||||||
|
if (this.get("finishedTime") < this.get("startTime")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return this.get("finishedTime");
|
||||||
|
}.property("finishedTime"),
|
||||||
|
|
||||||
allocatedResource: function() {
|
allocatedResource: function() {
|
||||||
return Converter.resourceToString(this.get("allocatedMB"), this.get("allocatedVCores"));
|
return Converter.resourceToString(this.get("allocatedMB"), this.get("allocatedVCores"));
|
||||||
}.property("allocatedMB", "allocatedVCores"),
|
}.property("allocatedMB", "allocatedVCores"),
|
||||||
|
@ -67,6 +74,13 @@ export default DS.Model.extend({
|
||||||
return "width: " + this.get("progress") + "%";
|
return "width: " + this.get("progress") + "%";
|
||||||
}.property("progress"),
|
}.property("progress"),
|
||||||
|
|
||||||
|
runningContainersNumber: function() {
|
||||||
|
if(this.get("runningContainers") < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return this.get("runningContainers");
|
||||||
|
}.property("progress"),
|
||||||
|
|
||||||
finalStatusStyle: function() {
|
finalStatusStyle: function() {
|
||||||
var style = "default";
|
var style = "default";
|
||||||
var finalStatus = this.get("finalStatus");
|
var finalStatus = this.get("finalStatus");
|
||||||
|
|
|
@ -40,6 +40,13 @@ export default DS.Model.extend({
|
||||||
return ts;
|
return ts;
|
||||||
}.property("finishedTime"),
|
}.property("finishedTime"),
|
||||||
|
|
||||||
|
validatedFinishedTs: function() {
|
||||||
|
if (this.get("finishedTs") < this.get("startTs")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return this.get("finishedTime");
|
||||||
|
}.property("finishedTime"),
|
||||||
|
|
||||||
elapsedTime: function() {
|
elapsedTime: function() {
|
||||||
var elapsedMs = this.get("finishedTs") - this.get("startTs");
|
var elapsedMs = this.get("finishedTs") - this.get("startTs");
|
||||||
if (elapsedMs <= 0) {
|
if (elapsedMs <= 0) {
|
||||||
|
|
|
@ -33,7 +33,11 @@ export default Ember.Route.extend({
|
||||||
{
|
{
|
||||||
app_attempt_id: param.app_attempt_id,
|
app_attempt_id: param.app_attempt_id,
|
||||||
is_rm: false
|
is_rm: false
|
||||||
}),
|
}).catch (function() {
|
||||||
|
// Promise rejected, fulfill with some default value to
|
||||||
|
// use as the route's model and continue on with the transition
|
||||||
|
return [];
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -32,11 +32,14 @@ export default DS.JSONAPISerializer.extend({
|
||||||
type: primaryModelClass.modelName, // yarn-app
|
type: primaryModelClass.modelName, // yarn-app
|
||||||
attributes: {
|
attributes: {
|
||||||
startTime: Converter.timeStampToDate(payload.startTime),
|
startTime: Converter.timeStampToDate(payload.startTime),
|
||||||
|
startedTime: Converter.timeStampToDate(payload.startedTime),
|
||||||
finishedTime: Converter.timeStampToDate(payload.finishedTime),
|
finishedTime: Converter.timeStampToDate(payload.finishedTime),
|
||||||
containerId: payload.containerId,
|
containerId: payload.containerId,
|
||||||
|
amContainerId: payload.amContainerId,
|
||||||
nodeHttpAddress: payload.nodeHttpAddress,
|
nodeHttpAddress: payload.nodeHttpAddress,
|
||||||
nodeId: payload.nodeId,
|
nodeId: payload.nodeId,
|
||||||
state: payload.nodeId,
|
hosts: payload.host,
|
||||||
|
state: payload.appAttemptState,
|
||||||
logsLink: payload.logsLink
|
logsLink: payload.logsLink
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,10 +75,15 @@ export default DS.JSONAPISerializer.extend({
|
||||||
|
|
||||||
// payload has apps : { app: [ {},{},{} ] }
|
// payload has apps : { app: [ {},{},{} ] }
|
||||||
// need some error handling for ex apps or app may not be defined.
|
// need some error handling for ex apps or app may not be defined.
|
||||||
normalizedArrayResponse.data = payload.apps.app.map(singleApp => {
|
if(payload.apps) {
|
||||||
return this.internalNormalizeSingleResponse(store, primaryModelClass,
|
normalizedArrayResponse.data = payload.apps.app.map(singleApp => {
|
||||||
|
return this.internalNormalizeSingleResponse(store, primaryModelClass,
|
||||||
singleApp, singleApp.id, requestType);
|
singleApp, singleApp.id, requestType);
|
||||||
}, this);
|
}, this);
|
||||||
|
} else {
|
||||||
|
normalizedArrayResponse.data = [];
|
||||||
|
}
|
||||||
|
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -64,9 +64,10 @@ export default DS.JSONAPISerializer.extend({
|
||||||
singleContainer, singleContainer.id, requestType);
|
singleContainer, singleContainer.id, requestType);
|
||||||
}, this);
|
}, this);
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
|
} else {
|
||||||
|
normalizedArrayResponse.data = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizedArrayResponse.data = [];
|
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
}
|
}
|
||||||
});
|
});
|
|
@ -76,10 +76,7 @@ export default DS.JSONAPISerializer.extend({
|
||||||
} else {
|
} else {
|
||||||
// No container reported inside containers.
|
// No container reported inside containers.
|
||||||
// Response of the form { "apps": null }
|
// Response of the form { "apps": null }
|
||||||
normalizedArrayResponse.data = Ember.makeArray({
|
normalizedArrayResponse.data = [];
|
||||||
id: "dummy",
|
|
||||||
type: primaryModelClass.modelName,
|
|
||||||
attributes: {}});
|
|
||||||
}
|
}
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,10 +64,7 @@ export default DS.JSONAPISerializer.extend({
|
||||||
} else {
|
} else {
|
||||||
// No container reported inside containers.
|
// No container reported inside containers.
|
||||||
// Response of the form { "containers": null }
|
// Response of the form { "containers": null }
|
||||||
normalizedArrayResponse.data = Ember.makeArray({
|
normalizedArrayResponse.data = [];
|
||||||
id: "dummy",
|
|
||||||
type: primaryModelClass.modelName,
|
|
||||||
attributes: {}});
|
|
||||||
}
|
}
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,10 +67,7 @@ export default DS.JSONAPISerializer.extend({
|
||||||
singleNode, singleNode.id);
|
singleNode, singleNode.id);
|
||||||
}, this);
|
}, this);
|
||||||
} else {
|
} else {
|
||||||
normalizedArrayResponse.data = Ember.makeArray({
|
normalizedArrayResponse.data = [];
|
||||||
id: "dummy",
|
|
||||||
type: primaryModelClass.modelName,
|
|
||||||
attributes: {}});
|
|
||||||
}
|
}
|
||||||
return normalizedArrayResponse;
|
return normalizedArrayResponse;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,26 @@
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
{{outputMainMenu}}
|
{{#link-to 'yarn-queue' 'root' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-queue' 'root'}}Queues
|
||||||
|
<span class="sr-only">(current)</span>
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
{{#link-to 'yarn-apps' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-apps'}}Applications
|
||||||
|
<span class="sr-only">(current)</span>
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
{{#link-to 'cluster-overview' tagName="li"}}
|
||||||
|
{{#link-to 'cluster-overview'}}Cluster Overview
|
||||||
|
<span class="sr-only">(current)</span>
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
{{#link-to 'yarn-nodes' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-nodes'}}Nodes
|
||||||
|
<span class="sr-only">(current)</span>
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
</ul>
|
</ul>
|
||||||
</div><!-- /.navbar-collapse -->
|
</div><!-- /.navbar-collapse -->
|
||||||
</div><!-- /.container-fluid -->
|
</div><!-- /.container-fluid -->
|
||||||
|
|
|
@ -24,23 +24,39 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Start Time</td>
|
<td>Start Time</td>
|
||||||
<td>{{attempt.startTime}}</td>
|
<td>{{attempt.attemptStartedTime}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>AM Container Id</td>
|
<td>AM Container Id</td>
|
||||||
<td>{{attempt.containerId}}</td>
|
<td>{{attempt.appMasterContainerId}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{{#if attempt.IsAmNodeUrl}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>AM Node Web UI</td>
|
<td>AM Node Web UI</td>
|
||||||
<td><a href={{attempt.nodeHttpAddress}}>{{attempt.nodeHttpAddress}}</a></td>
|
<td><a href={{attempt.nodeHttpAddress}}>{{attempt.nodeHttpAddress}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{{/if}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>AM Node Id</td>
|
<td>AM Node Id</td>
|
||||||
<td>{{attempt.nodeId}}</td>
|
<td>{{attempt.amNodeId}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{{#if attempt.IsLinkAvailable}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Log</td>
|
<td>Log</td>
|
||||||
<td><a href={{attempt.logsLink}}>link</a></td>
|
<td><a href={{attempt.logsLink}}>link</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{{/if}}
|
||||||
|
{{#if attempt.attemptState}}
|
||||||
|
<tr>
|
||||||
|
<td>Attempt State</td>
|
||||||
|
<td>{{attempt.attemptState}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/if}}
|
||||||
|
{{#if attempt.elapsedTime}}
|
||||||
|
<tr>
|
||||||
|
<td>Elapsed Time</td>
|
||||||
|
<td>{{attempt.elapsedTime}}</td>
|
||||||
|
</tr>
|
||||||
|
{{/if}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
|
@ -36,7 +36,7 @@
|
||||||
{{#if arr}}
|
{{#if arr}}
|
||||||
{{#each arr as |app|}}
|
{{#each arr as |app|}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="yarn-app/{{app.id}}">{{app.id}}</a></td>
|
<td><a href="#/yarn-app/{{app.id}}">{{app.id}}</a></td>
|
||||||
<td>{{app.appName}}</td>
|
<td>{{app.appName}}</td>
|
||||||
<td>{{app.user}}</td>
|
<td>{{app.user}}</td>
|
||||||
<td>{{app.queue}}</td>
|
<td>{{app.queue}}</td>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<td><span class={{app.finalStatusStyle}}>{{app.finalStatus}}</span></td>
|
<td><span class={{app.finalStatusStyle}}>{{app.finalStatus}}</span></td>
|
||||||
<td>{{app.startTime}}</td>
|
<td>{{app.startTime}}</td>
|
||||||
<td>{{app.elapsedTime}}</td>
|
<td>{{app.elapsedTime}}</td>
|
||||||
<td>{{app.finishedTime}}</td>
|
<td>{{app.validatedFinishedTs}}</td>
|
||||||
<td>{{app.priority}}</td>
|
<td>{{app.priority}}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="progress" style="margin-bottom: 0;">
|
<div class="progress" style="margin-bottom: 0;">
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="yarn-app/{{app.id}}">{{app.id}}</a></td>
|
<td><a href="#/yarn-app/{{app.id}}">{{app.id}}</a></td>
|
||||||
<td>{{app.appName}}</td>
|
<td>{{app.appName}}</td>
|
||||||
<td>{{app.user}}</td>
|
<td>{{app.user}}</td>
|
||||||
<td>{{app.queue}}</td>
|
<td>{{app.queue}}</td>
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
<td><span class={{app.finalStatusStyle}}>{{app.finalStatus}}</span></td>
|
<td><span class={{app.finalStatusStyle}}>{{app.finalStatus}}</span></td>
|
||||||
<td>{{app.startTime}}</td>
|
<td>{{app.startTime}}</td>
|
||||||
<td>{{app.elapsedTime}}</td>
|
<td>{{app.elapsedTime}}</td>
|
||||||
<td>{{app.finishedTime}}</td>
|
<td>{{app.validatedFinishedTs}}</td>
|
||||||
<td>{{app.priority}}</td>
|
<td>{{app.priority}}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="progress" style="margin-bottom: 0;">
|
<div class="progress" style="margin-bottom: 0;">
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Finished Time</td>
|
<td>Finished Time</td>
|
||||||
<td>{{container.finishedTime}}</td>
|
<td>{{container.validatedFinishedTs}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Elapsed Time</td>
|
<td>Elapsed Time</td>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>NodeManager UI</td>
|
<td>NodeManager UI</td>
|
||||||
<td>{{container.nodeHttpAddress}}</td>
|
<td><a href={{container.nodeHttpAddress}}>{{container.nodeHttpAddress}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
|
@ -0,0 +1,44 @@
|
||||||
|
{{!
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
}}
|
||||||
|
|
||||||
|
<div class="col-md-2 container-fluid">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>Node Manager<br>({{node-name nodeId}})</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul class="nav nav-pills nav-stacked" id="stacked-menu">
|
||||||
|
<ul class="nav nav-pills nav-stacked collapse in">
|
||||||
|
{{#link-to 'yarn-node' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-node' nodeId nodeAddr}}Node Information
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
{{#link-to 'yarn-node-apps' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-node-apps' nodeId nodeAddr}}List of Applications
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
{{#link-to 'yarn-node-containers' tagName="li"}}
|
||||||
|
{{#link-to 'yarn-node-containers' nodeId nodeAddr}}List of Containers
|
||||||
|
{{/link-to}}
|
||||||
|
{{/link-to}}
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{outlet}}
|
|
@ -34,7 +34,7 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
{{#if selected.link}}
|
{{#if selected.link}}
|
||||||
<a href={{selected.link}}>{{selected.id}}</a>
|
{{#link-to selected.linkname selected.id}}{{selected.id}}{{/link-to}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{selected.id}}
|
{{selected.id}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -16,4 +16,4 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
--}}
|
--}}
|
||||||
|
|
||||||
<h3 align = "center">Sorry, Error Occured.</h3>
|
<h3 align = "center">Sorry, Error Occurred.</h3>
|
||||||
|
|
|
@ -18,12 +18,16 @@
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
{{#if model.attempt}}
|
||||||
{{app-attempt-table attempt=model.attempt}}
|
{{app-attempt-table attempt=model.attempt}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- containers table -->
|
<!-- containers table -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
{{#if (or model.rmContainers model.tsContainers)}}
|
||||||
{{timeline-view parent-id="containers-timeline-div" my-id="timeline-view" height="400" rmModel=model.rmContainers tsModel=model.tsContainers label="shortAppAttemptId" attemptModel=false}}
|
{{timeline-view parent-id="containers-timeline-div" my-id="timeline-view" height="400" rmModel=model.rmContainers tsModel=model.tsContainers label="shortAppAttemptId" attemptModel=false}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Running Containers</td>
|
<td>Running Containers</td>
|
||||||
<td>{{model.app.runningContainers}}</td>
|
<td>{{model.app.runningContainersNumber}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Preempted Resource</td>
|
<td>Preempted Resource</td>
|
||||||
|
|
|
@ -15,7 +15,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
}}
|
}}
|
||||||
|
{{#if model}}
|
||||||
{{app-table table-id="apps-table" arr=model}}
|
{{app-table table-id="apps-table" arr=model}}
|
||||||
{{simple-table table-id="apps-table" bFilter=true colsOrder="0,desc" colTypes="natural elapsed-time" colTargets="0 7"}}
|
{{simple-table table-id="apps-table" bFilter=true colsOrder="0,desc" colTypes="natural elapsed-time" colTargets="0 7"}}
|
||||||
|
{{else}}
|
||||||
|
<h4 align = "center">Could not find any applications from this cluster</h4>
|
||||||
|
{{/if}}
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{node-menu path="yarn-node-app" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
{{node-menu-panel path="yarn-node-app" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
||||||
<div class="col-md-10 container-fluid">
|
<div class="col-md-10 container-fluid">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><b>Application Information</b></div>
|
<div class="panel-heading"><b>Application Information</b></div>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each model.nodeApp.containers as |container|}}
|
{{#each model.nodeApp.containers as |container|}}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="yarn-node-container/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{container}}">{{container}}</a></td>
|
<td><a href="#/yarn-node-container/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{container}}">{{container}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{node-menu path="yarn-node-apps" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
{{node-menu-panel path="yarn-node-apps" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
||||||
|
{{#if model.apps}}
|
||||||
<div class="col-md-10 container-fluid">
|
<div class="col-md-10 container-fluid">
|
||||||
<table id="node-apps-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
<table id="node-apps-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -31,21 +32,20 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#if model.apps}}
|
{{#if model.apps}}
|
||||||
{{#each model.apps as |app|}}
|
{{#each model.apps as |app|}}
|
||||||
{{#if app.isDummyApp}}
|
|
||||||
<tr><td colspan="3" align="center">No apps found on this node</td></tr>
|
|
||||||
{{else}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="yarn-node-app/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{app.appId}}">{{app.appId}}</a></td>
|
<td><a href="#/yarn-node-app/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{app.appId}}">{{app.appId}}</a></td>
|
||||||
<td><span class={{app.appStateStyle}}>{{app.state}}</span></td>
|
<td><span class={{app.appStateStyle}}>{{app.state}}</span></td>
|
||||||
<td>{{app.user}}</td>
|
<td>{{app.user}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{simple-table table-id="node-apps-table" bFilter=true colsOrder="0,desc" colTypes="natural" colTargets="0"}}
|
{{simple-table table-id="node-apps-table" bFilter=true colsOrder="0,desc" colTypes="natural" colTargets="0"}}
|
||||||
</div>
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<h4 align = "center">No apps found on this node</h4>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{node-menu path="yarn-node-container" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
{{node-menu-panel path="yarn-node-container" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
||||||
<div class="col-md-10 container-fluid">
|
<div class="col-md-10 container-fluid">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><b>Container Information</b></div>
|
<div class="panel-heading"><b>Container Information</b></div>
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{node-menu path="yarn-node-containers" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
{{node-menu-panel path="yarn-node-containers" nodeAddr=model.nodeInfo.addr nodeId=model.nodeInfo.id}}
|
||||||
|
{{#if model.containers}}
|
||||||
<div class="col-md-10 container-fluid">
|
<div class="col-md-10 container-fluid">
|
||||||
<table id="node-containers-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
<table id="node-containers-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -32,11 +33,8 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#if model.containers}}
|
{{#if model.containers}}
|
||||||
{{#each model.containers as |container|}}
|
{{#each model.containers as |container|}}
|
||||||
{{#if container.isDummyContainer}}
|
|
||||||
<tr><td colspan="4" align="center">No containers found on this node</td></tr>
|
|
||||||
{{else}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="yarn-node-container/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{container.containerId}}">{{container.containerId}}</a></td>
|
<td><a href="#/yarn-node-container/{{model.nodeInfo.id}}/{{model.nodeInfo.addr}}/{{container.containerId}}">{{container.containerId}}</a></td>
|
||||||
<td><span class={{container.containerStateStyle}}>{{container.state}}</span></td>
|
<td><span class={{container.containerStateStyle}}>{{container.state}}</span></td>
|
||||||
<td>{{container.user}}</td>
|
<td>{{container.user}}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -46,13 +44,15 @@
|
||||||
logFiles=container.containerLogFiles}}
|
logFiles=container.containerLogFiles}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{simple-table table-id="node-containers-table" bFilter=true colsOrder="0,desc" colTypes="natural" colTargets="0"}}
|
{{simple-table table-id="node-containers-table" bFilter=true colsOrder="0,desc" colTypes="natural" colTargets="0"}}
|
||||||
</div>
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<h4 align = "center">No containers found on this node</h4>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{node-menu path="yarn-node" nodeId=model.rmNode.id nodeAddr=model.node.id}}
|
{{node-menu-panel path="yarn-node" nodeId=model.rmNode.id nodeAddr=model.node.id}}
|
||||||
<div class="col-md-10 container-fluid">
|
<div class="col-md-10 container-fluid">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Node Information</div>
|
<div class="panel-heading">Node Information</div>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
--}}
|
--}}
|
||||||
|
|
||||||
|
{{#if model}}
|
||||||
<table id="nodes-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
<table id="nodes-table" class="display table table-striped table-bordered" cellspacing="0" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -35,11 +36,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#if model}}
|
|
||||||
{{#each model as |node|}}
|
{{#each model as |node|}}
|
||||||
{{#if node.isDummyNode}}
|
|
||||||
<tr><td colspan="13" align="center">No nodes found on this cluster</td></tr>
|
|
||||||
{{else}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{node.nodeLabelsAsString}}</td>
|
<td>{{node.nodeLabelsAsString}}</td>
|
||||||
<td>{{node.rack}}</td>
|
<td>{{node.rack}}</td>
|
||||||
|
@ -55,11 +52,12 @@
|
||||||
<td>{{node.availableVirtualCores}}</td>
|
<td>{{node.availableVirtualCores}}</td>
|
||||||
<td>{{node.version}}</td>
|
<td>{{node.version}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/if}}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{{simple-table table-id="nodes-table" bFilter=true}}
|
{{simple-table table-id="nodes-table" bFilter=true}}
|
||||||
|
{{else}}
|
||||||
|
<h4 align = "center">No nodes found on this cluster</h4>
|
||||||
|
{{/if}}
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
|
|
|
@ -58,8 +58,12 @@
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12 container-fluid">
|
<div class="col-md-12 container-fluid">
|
||||||
{{app-table table-id="apps-table" arr=model.apps}}
|
{{#if model.apps}}
|
||||||
{{simple-table table-id="apps-table" bFilter=true colTypes="elapsed-time" colTargets="7"}}
|
{{app-table table-id="apps-table" arr=model.apps}}
|
||||||
|
{{simple-table table-id="apps-table" bFilter=true colTypes="elapsed-time" colTargets="7"}}
|
||||||
|
{{else}}
|
||||||
|
<h4 align = "center">Could not find any applications from this cluster</h4>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ module.exports = function(environment) {
|
||||||
modulePrefix: 'yarn-ui',
|
modulePrefix: 'yarn-ui',
|
||||||
environment: environment,
|
environment: environment,
|
||||||
baseURL: '/',
|
baseURL: '/',
|
||||||
locationType: 'auto',
|
locationType: 'hash',
|
||||||
EmberENV: {
|
EmberENV: {
|
||||||
FEATURES: {
|
FEATURES: {
|
||||||
// Here you can enable experimental features on an ember canary build
|
// Here you can enable experimental features on an ember canary build
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"broccoli-asset-rev": "2.4.2",
|
"broccoli-asset-rev": "2.4.2",
|
||||||
"broccoli-funnel": "1.0.1",
|
"broccoli-funnel": "1.0.1",
|
||||||
"ember-bootstrap": "0.5.1",
|
"ember-bootstrap": "0.5.1",
|
||||||
|
"ember-array-contains-helper": "1.0.2",
|
||||||
"ember-cli": "1.13.13",
|
"ember-cli": "1.13.13",
|
||||||
"ember-cli-app-version": "1.0.0",
|
"ember-cli-app-version": "1.0.0",
|
||||||
"ember-cli-babel": "5.1.6",
|
"ember-cli-babel": "5.1.6",
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
"ember-export-application-global": "1.0.5",
|
"ember-export-application-global": "1.0.5",
|
||||||
"ember-resolver": "2.0.3",
|
"ember-resolver": "2.0.3",
|
||||||
"ember-spin-spinner": "0.2.3",
|
"ember-spin-spinner": "0.2.3",
|
||||||
|
"ember-truth-helpers": "1.2.0",
|
||||||
"select2": "4.0.0"
|
"select2": "4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { nodeName } from '../../../helpers/node-name';
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
|
||||||
|
module('Unit | Helper | node name');
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it works', function(assert) {
|
||||||
|
let result = nodeName(42);
|
||||||
|
assert.ok(result);
|
||||||
|
});
|
Loading…
Reference in New Issue