From ef2dd7b78c5bf15bd85a9c793e57855255148b7f Mon Sep 17 00:00:00 2001 From: Sunil G Date: Mon, 19 Dec 2016 11:44:03 +0530 Subject: [PATCH] YARN-5650. Render Application Timeout value in web UI. Contributed by Akhil PB. --- .../hadoop/yarn/server/webapp/AppBlock.java | 9 +++ .../resourcemanager/webapp/dao/AppInfo.java | 8 ++- .../webapp/app/components/app-timeout-bar.js | 60 +++++++++++++++++++ .../src/main/webapp/app/models/yarn-app.js | 2 + .../main/webapp/app/serializers/yarn-app.js | 21 +++++-- .../templates/components/app-timeout-bar.hbs | 34 +++++++++++ .../main/webapp/app/templates/yarn-app.hbs | 10 +++- .../src/main/webapp/app/utils/converter.js | 3 + .../components/app-timeout-bar-test.js | 34 +++++++++++ 9 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/app-timeout-bar.js create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/app-timeout-bar.hbs create mode 100644 hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/app-timeout-bar-test.js diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java index 69beef27ae6..349a98c97f7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/AppBlock.java @@ -40,6 +40,7 @@ import org.apache.hadoop.yarn.api.records.ApplicationAttemptReport; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationReport; +import org.apache.hadoop.yarn.api.records.ApplicationTimeoutType; import org.apache.hadoop.yarn.api.records.ContainerReport; import org.apache.hadoop.yarn.api.records.FinalApplicationStatus; import org.apache.hadoop.yarn.api.records.LogAggregationStatus; @@ -207,6 +208,14 @@ public ApplicationReport run() throws Exception { overviewTable._("Log Aggregation Status:", root_url("logaggregationstatus", app.getAppId()), status.name()); } + long timeout = appReport.getApplicationTimeouts() + .get(ApplicationTimeoutType.LIFETIME).getRemainingTime(); + if (timeout < 0) { + overviewTable._("Application Timeout (Remaining Time):", "Unlimited"); + } else { + overviewTable._("Application Timeout (Remaining Time):", + String.format("%d seconds", timeout)); + } } overviewTable._("Diagnostics:", app.getDiagnosticsInfo() == null ? "" : app.getDiagnosticsInfo()); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java index 2d364f474c5..4e85b671da7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java @@ -259,8 +259,12 @@ public AppInfo(ResourceManager rm, RMApp app, Boolean hasAccess, timeout.setTimeoutType(entry.getKey()); long timeoutInMillis = entry.getValue().longValue(); timeout.setExpiryTime(Times.formatISO8601(timeoutInMillis)); - timeout.setRemainingTime(Math - .max((timeoutInMillis - System.currentTimeMillis()) / 1000, 0)); + if (app.isAppInCompletedStates()) { + timeout.setRemainingTime(0); + } else { + timeout.setRemainingTime(Math + .max((timeoutInMillis - System.currentTimeMillis()) / 1000, 0)); + } timeouts.add(timeout); } } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/app-timeout-bar.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/app-timeout-bar.js new file mode 100644 index 00000000000..0eac82759f2 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/components/app-timeout-bar.js @@ -0,0 +1,60 @@ +/** + * 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'; +import Converter from 'yarn-ui/utils/converter'; + +export default Ember.Component.extend({ + app: null, + + appTimeoutValue: function() { + var timeoutValueInSecs = this.get("app.remainingTimeoutInSeconds"); + if (timeoutValueInSecs > -1) { + return Converter.msToElapsedTime(timeoutValueInSecs * 1000); + } else { + return timeoutValueInSecs; + } + }.property("app.remainingTimeoutInSeconds"), + + isAppTimedOut: function() { + if (this.get("app.remainingTimeoutInSeconds") > 0) { + return false; + } else { + return true; + } + }.property("app.remainingTimeoutInSeconds"), + + appTimeoutBarStyle: function() { + var remainingInSecs = this.get("app.remainingTimeoutInSeconds"), + expiryTimestamp = Converter.dateToTimeStamp(this.get("app.applicationExpiryTime")), + expiryInSecs = expiryTimestamp / 1000, + startTimestamp = Converter.dateToTimeStamp(this.get("app.startTime")), + startInSecs = startTimestamp / 1000, + totalRunInSecs = 0, + appRunDurationInSecs = 0, + width = 0; + + if (remainingInSecs > 0) { + totalRunInSecs = expiryInSecs - startInSecs; + appRunDurationInSecs = totalRunInSecs - remainingInSecs; + width = appRunDurationInSecs / totalRunInSecs * 100; + } + + return "width: " + width + "%"; + }.property("app.remainingTimeoutInSeconds", "app.applicationExpiryTime", "app.startTime") +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-app.js index 8b5474f2f5c..4138a874736 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-app.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/models/yarn-app.js @@ -50,6 +50,8 @@ export default DS.Model.extend({ clusterUsagePercentage: DS.attr('number'), queueUsagePercentage: DS.attr('number'), currentAppAttemptId: DS.attr('string'), + remainingTimeoutInSeconds: DS.attr('number'), + applicationExpiryTime: DS.attr('string'), isFailed: function() { return this.get('finalStatus') == "FAILED" diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app.js index 427c3d82691..fdba04ae285 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app.js @@ -23,9 +23,18 @@ export default DS.JSONAPISerializer.extend({ internalNormalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { if (payload.app) { - payload = payload.app; + payload = payload.app; } - + + var timeoutInSecs = -1; + var appExpiryTime = Converter.timeStampToDate(payload.finishedTime); + if (payload.timeouts && payload.timeouts.timeout && payload.timeouts.timeout[0]) { + timeoutInSecs = payload.timeouts.timeout[0].remainingTimeInSeconds; + if (timeoutInSecs > -1) { + appExpiryTime = Converter.isoDateToDate(payload.timeouts.timeout[0].expiryTime); + } + } + var fixedPayload = { id: id, type: primaryModelClass.modelName, // yarn-app @@ -58,7 +67,9 @@ export default DS.JSONAPISerializer.extend({ numAMContainerPreempted: payload.numAMContainerPreempted, clusterUsagePercentage: payload.clusterUsagePercentage, queueUsagePercentage: payload.queueUsagePercentage, - currentAppAttemptId: payload.currentAppAttemptId + currentAppAttemptId: payload.currentAppAttemptId, + remainingTimeoutInSeconds: timeoutInSecs, + applicationExpiryTime: appExpiryTime } }; @@ -67,7 +78,7 @@ export default DS.JSONAPISerializer.extend({ normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { - var p = this.internalNormalizeSingleResponse(store, + var p = this.internalNormalizeSingleResponse(store, primaryModelClass, payload, id, requestType); return { data: p }; }, @@ -90,4 +101,4 @@ export default DS.JSONAPISerializer.extend({ return normalizedArrayResponse; } -}); \ No newline at end of file +}); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/app-timeout-bar.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/app-timeout-bar.hbs new file mode 100644 index 00000000000..acbe0b2470b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/components/app-timeout-bar.hbs @@ -0,0 +1,34 @@ +{{! + * 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. +}} + +
+ {{#unless isAppTimedOut}} +
+
+ +
+
+
+
+ + +
+
+
+ {{/unless}} +
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-app.hbs b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-app.hbs index acf00d1c3ff..578cc9501e1 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-app.hbs +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-app.hbs @@ -45,6 +45,12 @@
+
+
+ {{app-timeout-bar app=model.app}} +
+
+
@@ -116,10 +122,10 @@
{{else}}
-
+
Diagnostics
- +
{{model.app.diagnostics}}
{{/if}}
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js index 6fd9d3060b4..fb6b61c8f11 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js @@ -91,6 +91,9 @@ export default { return ts; } }, + isoDateToDate: function(isoDate) { + return moment(isoDate).format("YYYY/MM/DD HH:mm:ss"); + }, splitForContainerLogs: function(id) { if (id) { var splits = id.split(Constants.PARAM_SEPARATOR); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/app-timeout-bar-test.js b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/app-timeout-bar-test.js new file mode 100644 index 00000000000..fb2a73a3b3a --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/tests/integration/components/app-timeout-bar-test.js @@ -0,0 +1,34 @@ +/** + * 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 { moduleForComponent, test } from 'ember-qunit'; +import hbs from 'htmlbars-inline-precompile'; + +moduleForComponent('app-timeout-bar', 'Integration | Component | app timeout bar', { + integration: true +}); + +test('it renders', function(assert) { + + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL + + + this.render(hbs`{{app-timeout-bar}}`); + + assert.equal(this.$().text().trim(), ''); +});