Просмотр исходного кода

YARN-8964. [UI2] YARN ui2 should use clusters/{cluster name} for all ATSv2 REST APIs. Contributed by Akhil PB.

Sunil G 6 лет назад
Родитель
Сommit
5fe1dbf195
16 измененных файлов с 194 добавлено и 21 удалено
  1. 7 4
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-log.js
  2. 5 1
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-timeline.js
  3. 6 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-component-instance.js
  4. 4 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js
  5. 4 4
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-log.js
  6. 6 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-service-component.js
  7. 6 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-service-info.js
  8. 8 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-appattempt.js
  9. 4 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-container.js
  10. 33 1
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/initializers/loader.js
  11. 4 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js
  12. 66 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-log-service.js
  13. 2 2
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-log.js
  14. 37 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-log-service.hbs
  15. 1 1
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js
  16. 1 0
      hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/config/default-config.js

+ 7 - 4
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-log.js

@@ -16,7 +16,6 @@
  * limitations under the License.
  */
 
-import DS from 'ember-data';
 import Ember from 'ember';
 import Converter from 'yarn-ui/utils/converter';
 import RESTAbstractAdapter from './restabstract';
@@ -26,8 +25,8 @@ import RESTAbstractAdapter from './restabstract';
  * in plain text format and not JSON.
  */
 export default RESTAbstractAdapter.extend({
-  address: "timelineV1WebAddress",
-  restNameSpace: "timeline",
+  address: "timelineWebAddress",
+  restNameSpace: "timelineV2Log",
   serverName: "ATS",
 
   headers: {
@@ -36,10 +35,14 @@ export default RESTAbstractAdapter.extend({
 
   urlForFindRecord(id/*, modelName, snapshot*/) {
     var splits = Converter.splitForAppLogs(id);
+    var clusterId = this.get("env.app.clusterId");
     var containerId = splits[0];
     var logFile = splits[1];
+    if (splits[2]) {
+      clusterId = splits[2];
+    }
     var url = this._buildURL();
-    url = url + '/containers/' + containerId + '/logs/' + logFile;
+    url = url + '/containers/' + containerId + '/logs/' + logFile + '?clusterid=' + clusterId;
     console.log('log url' + url);
     return url;
   },

+ 5 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-app-timeline.js

@@ -25,7 +25,11 @@ export default AbstractAdapter.extend({
 
   urlForFindRecord(id/*, modelName, snapshot*/) {
     var url = this._buildURL();
-    url = url + '/apps/' + id + '?fields=ALL';
+    var clusterId = this.get("env.app.clusterId");
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
+    url += '/apps/' + id + '?fields=ALL';
     return url;
   },
 

+ 6 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-component-instance.js

@@ -20,12 +20,16 @@ import AbstractAdapter from './abstract';
 
 export default AbstractAdapter.extend({
   address: "timelineWebAddress",
-  restNameSpace: "timelineService",
+  restNameSpace: "timelineV2",
   serverName: "ATS",
 
   urlForQuery(query/*, modelName*/) {
     var url = this.buildURL();
-    url += '/' + query.appId + '/entities/COMPONENT_INSTANCE?fields=ALL';
+    var clusterId = this.get("env.app.clusterId");
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
+    url += '/apps/' + query.appId + '/entities/COMPONENT_INSTANCE?fields=ALL';
     delete query.appId;
     return url;
   }

+ 4 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-flow-activity.js

@@ -25,6 +25,10 @@ export default AbstractAdapter.extend({
   serverName: "ATS",
 
   pathForType(/*modelName*/) {
+    var clusterId = this.get("env.app.clusterId");
+    if (clusterId) {
+      return `clusters/${clusterId}/flows`;
+    }
     return 'flows'; // move to some common place, return path by modelname.
   },
 });

+ 4 - 4
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-log.js

@@ -19,15 +19,15 @@
 import AbstractAdapter from './abstract';
 
 export default AbstractAdapter.extend({
-  address: "timelineV1WebAddress",
-  // restNameSpace: "timelineV2", // Use ATSv2 when it supports log APIs.
-  restNameSpace: "timeline", //Using ATSv1.5 now, would be supported by ATSv2 very soon.
+  address: "timelineWebAddress",
+  restNameSpace: "timelineV2Log",
   serverName: "ATS",
 
   urlForQuery(query/*, modelName*/) {
     var url = this._buildURL();
     var containerId = query['containerId'];
+    var clusterId = this.get("env.app.clusterId");
     delete query.containerId;
-    return url + '/containers/' + containerId + '/logs';
+    return url + '/containers/' + containerId + '/logs' + '?clusterid=' + clusterId;
   }
 });

+ 6 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-service-component.js

@@ -20,12 +20,16 @@ import AbstractAdapter from './abstract';
 
 export default AbstractAdapter.extend({
   address: "timelineWebAddress",
-  restNameSpace: "timelineService",
+  restNameSpace: "timelineV2",
   serverName: "ATS",
 
   urlForQuery(query/*, modelName*/) {
     var url = this.buildURL();
-    url += '/' + query.appId + '/entities/COMPONENT?fields=ALL';
+    var clusterId = this.get("env.app.clusterId");
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
+    url += '/apps/' + query.appId + '/entities/COMPONENT?fields=ALL';
     delete query.appId;
     return url;
   }

+ 6 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-service-info.js

@@ -20,12 +20,16 @@ import AbstractAdapter from './abstract';
 
 export default AbstractAdapter.extend({
   address: "timelineWebAddress",
-  restNameSpace: "timelineService",
+  restNameSpace: "timelineV2",
   serverName: "ATS",
 
   urlForQueryRecord(query/*, modelName*/) {
     var url = this.buildURL();
-    url += '/' + query.appId + '/entities/SERVICE_ATTEMPT?fields=ALL';
+    var clusterId = this.get("env.app.clusterId");
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
+    url += '/apps/' + query.appId + '/entities/SERVICE_ATTEMPT?fields=ALL';
     delete query.appId;
     return url;
   }

+ 8 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-appattempt.js

@@ -26,6 +26,10 @@ export default AbstractAdapter.extend({
 
   urlForQuery(query/*, modelName*/) {
     var url = this._buildURL();
+    var clusterId = this.get("env.app.clusterId")
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
     var appId = query.appId;
     query.fields = 'ALL';
     delete query.appId;
@@ -34,6 +38,10 @@ export default AbstractAdapter.extend({
 
   urlForFindRecord(id/*, modelName, snapshot*/) {
     var url = this._buildURL();
+    var clusterId = this.get("env.app.clusterId")
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
     return url + '/apps/' + Converter.attemptIdToAppId(id) +
       "/entities/YARN_APPLICATION_ATTEMPT/" + id + "?fields=ALL";
   }

+ 4 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/adapters/yarn-timeline-container.js

@@ -26,6 +26,10 @@ export default AbstractAdapter.extend({
 
   urlForQuery(query/*, modelName*/){
     var url = this._buildURL();
+    var clusterId = this.get("env.app.clusterId")
+    if (clusterId) {
+      url += `/clusters/${clusterId}`;
+    }
     var app_attempt_id = query.app_attempt_id;
     query.fields = 'ALL';
     delete query.app_attempt_id;

+ 33 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/initializers/loader.js

@@ -84,9 +84,36 @@ function getSecurityURL(rmhost) {
   return url;
 }
 
+function getClusterIdFromYARN(rmhost, application) {
+  var httpUrl = window.location.protocol + '//' +
+    (ENV.hosts.localBaseAddress? ENV.hosts.localBaseAddress + '/' : '') + rmhost;
+
+  httpUrl += '/conf?name=yarn.resourcemanager.cluster-id';
+  Ember.Logger.log("Get cluster-id URL is: " + httpUrl);
+
+  var clusterId = "";
+  $.ajax({
+    type: 'GET',
+    dataType: 'json',
+    async: false,
+    context: this,
+    url: httpUrl,
+    success: function(data) {
+      clusterId = data.property.value;
+      Ember.Logger.log("Cluster Id from RM: " + clusterId);
+      application.advanceReadiness();
+    },
+    error: function() {
+      application.advanceReadiness();
+    }
+  });
+  return clusterId;
+}
+
 function updateConfigs(application) {
   var hostname = window.location.hostname;
-  var rmhost = hostname + (window.location.port ? ':' + window.location.port: '') + skipTrailingSlash(window.location.pathname);
+  var rmhost = hostname + (window.location.port ? ':' + window.location.port: '') +
+    skipTrailingSlash(window.location.pathname);
 
   window.ENV = window.ENV || {};
   window.ENV.hosts = window.ENV.hosts || {};
@@ -103,6 +130,10 @@ function updateConfigs(application) {
   var protocolSchemeFromRM = getYarnHttpProtocolScheme(rmhost, application);
   Ember.Logger.log("Is protocol scheme https? " + (protocolSchemeFromRM == "HTTPS_ONLY"));
   var isHttpsSchemeEnabled = (protocolSchemeFromRM == "HTTPS_ONLY");
+
+  var clusterIdFromYARN = getClusterIdFromYARN(rmhost, application);
+  ENV.clusterId = clusterIdFromYARN;
+
   if(!ENV.hosts.timelineWebAddress) {
     var timelinehost = "";
     $.ajax({
@@ -207,6 +238,7 @@ export default {
 };
 
 const skipTrailingSlash = function(path) {
+  path = path.replace('index.html', '');
   path = path.replace('ui2/', '');
   path = path.replace(/\/$/, '');
   console.log('base url:' + path)

+ 4 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/router.js

@@ -49,8 +49,10 @@ Router.map(function() {
       { path: '/yarn-node-containers/:node_id/:node_addr' });
   this.route('yarn-node-container',
       { path: '/yarn-node-container/:node_id/:node_addr/:container_id' });
-  this.route('yarn-container-log', { path:
-      '/yarn-container-log/:node_id/:node_addr/:container_id/:filename' });
+  this.route('yarn-container-log',
+    { path: '/yarn-container-log/:node_id/:node_addr/:container_id/:filename' });
+  this.route('yarn-log-service',
+    { path: '/yarn-log-service/:cluster_id/:container_id/:filename' });
 
   this.route('yarn-deploy-service');
   this.route('cluster-overview');

+ 66 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/routes/yarn-log-service.js

@@ -0,0 +1,66 @@
+/**
+ * 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 Constants from 'yarn-ui/constants';
+
+import AbstractRoute from './abstract';
+
+export default AbstractRoute.extend({
+  model(param) {
+    var id = param.container_id + Constants.PARAM_SEPARATOR + param.filename
+      + Constants.PARAM_SEPARATOR + param.cluster_id;
+    return Ember.RSVP.hash({
+      containerLog: this.store.findRecord('yarn-app-log', id),
+      containerInfo: { id: param.container_id }
+    }).then(function (hash) {
+      // Just return as its success.
+      return hash;
+    }, function (reason) {
+      if (reason.errors && reason.errors[0]) {
+        // This means HTTP error response was sent by adapter.
+        return reason;
+      } else {
+        // Assume empty response received from server.
+        return {
+          containerInfo: { id: param.container_id },
+          containerLog: {
+            logs: "",
+            containerID: param.container_id,
+            logFileName: param.filename
+          }
+        };
+      }
+    });
+  },
+
+  afterModel(model) {
+    // Handle errors and redirect if promise is rejected.
+    if (model.errors && model.errors[0]) {
+      if (parseInt(model.errors[0].status) === 404) {
+        this.replaceWith('/notfound');
+      } else {
+        this.replaceWith('/error');
+      }
+    }
+  },
+
+  unloadAll() {
+    this.store.unloadAll('yarn-app-log');
+  }
+});

+ 2 - 2
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/serializers/yarn-app-log.js

@@ -29,8 +29,8 @@ export default DS.JSONAPISerializer.extend({
       type: primaryModelClass.modelName,
       attributes: {
         logs: payload,
-        containerID: splits[1],
-        logFileName: splits[2]
+        containerID: splits[0],
+        logFileName: splits[1]
       }
     };
     return { data: convertedPayload };

+ 37 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/templates/yarn-log-service.hbs

@@ -0,0 +1,37 @@
+{{!--
+  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-12 container-fluid">
+  <div class="col-md-12">
+    <div class="panel panel-default">
+      <div class="panel-heading">
+        <h5 align="center">
+          <b>Log: {{model.containerLog.logFileName}} [ {{model.containerLog.containerID}} ]</b>
+        </h5>
+      </div>
+      <div class="panel-body">
+        {{#if model.containerLog.logs}}
+          <pre>{{model.containerLog.logs}}</pre>
+        {{else}}
+          <p>No logs were written in {{model.containerLog.logFileName}}.</p>
+        {{/if}}
+      </div>
+    </div>
+  </div>
+</div>
+{{outlet}}

+ 1 - 1
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/app/utils/converter.js

@@ -119,7 +119,7 @@ export default {
       if (splitLen < 2) {
         return null;
       }
-      return [splits[0], splits[1]];
+      return splits[2] ? [splits[0], splits[1], splits[2]] : [splits[0], splits[1]];
     }
   },
   memoryToSimpliedUnit: function(mb) {

+ 1 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-ui/src/main/webapp/config/default-config.js

@@ -31,6 +31,7 @@ module.exports = { // YARN UI App configurations
       cluster: 'ws/v1/cluster',
       metrics: 'ws/v1/cluster/metrics',
       timelineV2: 'ws/v2/timeline',
+      timelineV2Log: 'ws/v2/applicationlog',
       dashService: 'app/v1/services',
       node: '{nodeAddress}/ws/v1/node'
     },