YARN-8964. [UI2] YARN ui2 should use clusters/{cluster name} for all ATSv2 REST APIs. Contributed by Akhil PB.
This commit is contained in:
parent
8d2789c5eb
commit
5fe1dbf195
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
});
|
|
@ -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 };
|
||||
|
|
|
@ -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}}
|
|
@ -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) {
|
||||
|
|
|
@ -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'
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue