YARN-10029. Add option to UIv2 to get container logs from the new JHS API. Contributed by Adam Antal

This commit is contained in:
Szilard Nemeth 2020-02-13 12:08:54 +01:00
parent fe7d67a8a2
commit f1b1b332f5
21 changed files with 607 additions and 77 deletions

View File

@ -0,0 +1,30 @@
/**
* 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 RESTAbstractAdapter from './restabstract';
export default RESTAbstractAdapter.extend({
address: "jhsAddress",
restNameSpace: "jhs",
serverName: "JHS",
urlForQueryRecord(/*query, modelName*/) {
var url = this.buildURL();
return url + '/info';
}
});

View File

@ -0,0 +1,67 @@
/**
* 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';
import RESTAbstractAdapter from './restabstract';
/**
* REST URL's response when fetching container logs will be
* in plain text format and not JSON.
*/
export default RESTAbstractAdapter.extend({
address: "jhsAddress",
restNameSpace: "jhs",
serverName: "JHS",
headers: {
Accept: 'text/plain'
},
urlForFindRecord(id/*, modelName, snapshot*/) {
var splits = Converter.splitForAppLogs(id);
var containerId = splits[0];
var logFile = splits[1];
var url = this._buildURL();
url = url + '/containerlogs/' + containerId + '/' + logFile;
Ember.Logger.info('The URL for getting the log: ' + url);
return url;
},
/**
* Override options so that result is not expected to be JSON
*/
ajaxOptions: function (url, type, options) {
var hash = options || {};
hash.url = url;
hash.type = type;
// Make sure jQuery does not try to convert response to JSON.
hash.dataType = 'text';
hash.context = this;
var headers = Ember.get(this, 'headers');
if (headers !== undefined) {
hash.beforeSend = function (xhr) {
Object.keys(headers).forEach(function (key) {
return xhr.setRequestHeader(key, headers[key]);
});
};
}
return hash;
}
});

View File

@ -43,7 +43,7 @@ export default RESTAbstractAdapter.extend({
}
var url = this._buildURL();
url = url + '/containers/' + containerId + '/logs/' + logFile + '?clusterid=' + clusterId;
console.log('log url' + url);
Ember.Logger.info('The URL for getting the log: ' + url);
return url;
},

View File

@ -0,0 +1,33 @@
/**
* 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 RESTAbstractAdapter from './restabstract';
export default RESTAbstractAdapter.extend({
address: "jhsAddress",
restNameSpace: "jhs",
serverName: "JHS",
urlForQuery(query/*, modelName*/) {
var url = this.buildURL();
url = url + '/aggregatedlogs?appattemptid=' + query.app_attempt_id;
delete query.app_attempt_id;
return url;
}
});

View File

@ -0,0 +1,32 @@
/**
* 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 AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
address: "jhsAddress",
restNameSpace: "jhs",
serverName: "JHS",
urlForQuery(query/*, modelName*/) {
var url = this._buildURL();
var containerId = query['containerId'];
delete query.containerId;
return url + '/containers/' + containerId + '/logs';
}
});

View File

@ -50,31 +50,39 @@ export default Ember.Controller.extend({
this.fetchContainersForAttemptId(attemptId)
.then(hash => {
let containers = null;
let containerIdArr = [];
let containerIdArr = {};
// Getting running containers from the RM first
if (
hash.rmContainers.get("length") > 0 &&
hash.rmContainers.get("content")
) {
hash.rmContainers.get("content").forEach(function(o) {
containerIdArr.push(o.id);
containerIdArr[o.id] = true;
}.bind(this));
containers = (containers || []).concat(
hash.rmContainers.get("content")
);
}
let historyProvider = this.fallbackToJHS ? hash.jhsContainers : hash.tsContainers;
let fieldName = this.fallbackToJHS ? "containerId" : "id";
// Getting aggregated containers from the selected history provider
if (
hash.tsContainers.get("length") > 0 &&
hash.tsContainers.get("content")
historyProvider.get("length") > 0 &&
historyProvider.get("content")
) {
let tscontainer = [];
hash.tsContainers.get("content").forEach(function(o) {
if(!containerIdArr.contains(o.id)) {
tscontainer.push(o);
let historyContainers = [];
historyProvider.get("content").forEach(function(o) {
if(!containerIdArr[o[fieldName]])) {
historyContainers.push(o);
}
}.bind(this));
containers = (containers || []).concat(
tscontainer);
historyContainers);
}
this.set("attemptContainerList", containers);
this.initializeSelect(".js-fetch-logs-containers");
if (containerId) {
@ -201,28 +209,36 @@ export default Ember.Controller.extend({
}),
fetchContainersForAttemptId(attemptId) {
return Ember.RSVP.hash({
rmContainers: this.store
.query("yarn-container", {
app_attempt_id: attemptId
})
.catch(function() {
return Ember.A();
}),
tsContainers: this.store
.query("yarn-timeline-container", {
app_attempt_id: attemptId
})
.catch(function() {
return Ember.A();
})
});
let request = {};
request["rmContainers"] = this.store
.query("yarn-container", {
app_attempt_id: attemptId
})
.catch(function(error) {
return Ember.A();
});
let historyProvider = this.fallbackToJHS ? "jhsContainers" : "tsContainers";
let historyQuery = this.fallbackToJHS ? "yarn-jhs-container" : "yarn-timeline-container";
request[historyProvider] = this.store
.query(historyQuery, {
app_attempt_id: attemptId
})
.catch(function(error) {
return Ember.A();
});
return Ember.RSVP.hash(request);
},
fetchLogFilesForContainerId(containerId) {
let queryName = this.fallbackToJHS ? "yarn-jhs-log" : "yarn-log";
return Ember.RSVP.hash({
logs: this.store
.query("yarn-log", {
.query(queryName, {
containerId: containerId
})
.catch(function() {
@ -232,8 +248,10 @@ export default Ember.Controller.extend({
},
fetchContentForLogFile(id) {
let queryName = this.fallbackToJHS ? 'yarn-app-jhs-log' : 'yarn-app-log';
return Ember.RSVP.hash({
logs: this.store.findRecord('yarn-app-log', id)
logs: this.store.findRecord(queryName, id)
});
},
@ -265,10 +283,24 @@ export default Ember.Controller.extend({
return logAggregationStatus !== "SUCCEEDED";
}),
isTimelineUnHealthy: function() {
if (this.model && this.model.timelineHealth) {
return this.model.timelineHealth.get('isTimelineUnHealthy');
fallbackToJHS: function() {
// Let's fall back to JHS if ATS is not available, but JHS is.
return this.model &&
(!this.model.timelineHealth || this.model.timelineHealth.get('isTimelineUnHealthy')) &&
this.model.jhsHealth && this.model.jhsHealth.get('isJHSHealthy');
}.property('model.timelineHealth', 'model.isJHSHealthy'),
areJHSandATSUnhealthy: function() {
if (this.model && this.model.timelineHealth) {
if (!this.model.timelineHealth.get('isTimelineUnHealthy')) {
return false;
}
return true;
}.property('model.timelineHealth')
}
if (this.model && this.model.jhsHealth) {
if (this.model.jhsHealth.get('isJHSHealthy')) {
return false;
}
}
return true;
}.property('model.timelineHealth', 'model.isJHSHealthy')
});

View File

@ -20,31 +20,46 @@
import Ember from 'ember';
function getYarnHttpProtocolScheme(rmhost, application) {
function getConfigFromYarn(rmhost, application, config) {
var httpUrl = window.location.protocol + '//' +
(ENV.hosts.localBaseAddress? ENV.hosts.localBaseAddress + '/' : '') + rmhost;
httpUrl += '/conf?name=yarn.http.policy';
Ember.Logger.log("yarn.http.policy URL is: " + httpUrl);
httpUrl += '/conf?name=' + config;
Ember.Logger.log("The RM URL is: " + httpUrl);
var protocolScheme = "";
$.ajax({
type: 'GET',
dataType: 'json',
async: false,
context: this,
url: httpUrl,
success: function(data) {
protocolScheme = data.property.value;
Ember.Logger.log("Protocol scheme from RM: " + protocolScheme);
var configValue = "";
$.ajax({
type: 'GET',
dataType: 'json',
async: false,
context: this,
url: httpUrl,
success: function(data) {
configValue = data.property.value;
Ember.Logger.log("Value of the config returned from RM: " + configValue);
application.advanceReadiness();
},
error: function() {
application.advanceReadiness();
}
});
return protocolScheme;
application.advanceReadiness();
},
error: function() {
application.advanceReadiness();
}
});
return configValue;
}
function getJHSURL(rmhost, application, isHttpsSchemeEnabled) {
Ember.Logger.log("getJHSURL, params:rmhost=" + rmhost + ",application=" + application + ",isHttpsSchemeEnabled=" + isHttpsSchemeEnabled);
var config = '';
if (isHttpsSchemeEnabled) {
config = 'mapreduce.jobhistory.webapp.https.address';
} else {
config = 'mapreduce.jobhistory.webapp.address';
}
return getConfigFromYarn(rmhost, application, config);
}
function getYarnHttpProtocolScheme(rmhost, application) {
return getConfigFromYarn(rmhost, application, 'yarn.http.policy');
}
function getTimeLineURL(rmhost, isHttpsSchemeEnabled) {
@ -134,6 +149,21 @@ function getNodeManagerPort(rmhost, application) {
return port;
}
function transformURL(url, hostname) {
// Deleting the scheme from the beginning of the url
url = url.replace(/(^\w+:|^)\/\//, '');
var address = url.split(":")[0];
var port = url.split(":")[1];
// Instead of localhost, use the name of the host
if (address === "0.0.0.0" || address === "localhost") {
url = hostname + ":" + port;
}
Ember.Logger.log("The transformed URL is: " + url);
return url;
}
function updateConfigs(application) {
var hostname = window.location.hostname;
var rmhost = hostname + (window.location.port ? ':' + window.location.port: '') +
@ -162,6 +192,13 @@ function updateConfigs(application) {
Ember.Logger.log("NodeMananger port: " + nodeManagerPort);
ENV.nodeManagerPort = nodeManagerPort;
if (!ENV.hosts.jhsAddress) {
var jhsAddress = getJHSURL(rmhost, application, isHttpsSchemeEnabled);
jhsAddress = transformURL(jhsAddress, hostname);
Ember.Logger.log("The JHS address is " + jhsAddress);
ENV.hosts.jhsAddress = jhsAddress;
}
if(!ENV.hosts.timelineWebAddress) {
var timelinehost = "";
$.ajax({
@ -172,19 +209,10 @@ function updateConfigs(application) {
url: getTimeLineURL(rmhost, isHttpsSchemeEnabled),
success: function(data) {
timelinehost = data.property.value;
timelinehost = timelinehost.replace(/(^\w+:|^)\/\//, '');
timelinehost = transformURL(timelinehost, hostname);
ENV.hosts.timelineWebAddress = timelinehost;
var address = timelinehost.split(":")[0];
var port = timelinehost.split(":")[1];
Ember.Logger.log("Timeline Address from RM: " + timelinehost);
if(address === "0.0.0.0" || address === "localhost") {
var updatedAddress = hostname + ":" + port;
ENV.hosts.timelineWebAddress = updatedAddress;
Ember.Logger.log("Timeline Updated Address: " + updatedAddress);
}
application.advanceReadiness();
},
error: function() {
@ -206,19 +234,10 @@ function updateConfigs(application) {
url: getTimeLineV1URL(rmhost, isHttpsSchemeEnabled),
success: function(data) {
timelinehost = data.property.value;
timelinehost = timelinehost.replace(/(^\w+:|^)\/\//, '');
timelinehost = transformURL(timelinehost, hostname);
ENV.hosts.timelineV1WebAddress = timelinehost;
var address = timelinehost.split(":")[0];
var port = timelinehost.split(":")[1];
Ember.Logger.log("Timeline V1 Address from RM: " + timelinehost);
if(address === "0.0.0.0" || address === "localhost") {
var updatedAddress = hostname + ":" + port;
ENV.hosts.timelineV1WebAddress = updatedAddress;
Ember.Logger.log("Timeline V1 Updated Address: " + updatedAddress);
}
application.advanceReadiness();
},
error: function() {

View File

@ -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 DS from 'ember-data';
import Ember from 'ember';
export default DS.Model.extend({
startedOn: DS.attr('string'),
isJHSHealthy: function() {
return this.get('startedOn') !== null;
}.property('startedOn')
});

View File

@ -0,0 +1,25 @@
/**
* 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 DS from 'ember-data';
export default DS.Model.extend({
logs: DS.attr('string'),
containerID: DS.attr('string'),
logFileName: DS.attr('string')
});

View File

@ -0,0 +1,27 @@
/**
* 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 DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
containerLogInfo: DS.attr('array'),
logAggregationType: DS.attr('string'),
containerId: DS.attr('string'),
nodeId: DS.attr('string')
});

View File

@ -0,0 +1,27 @@
/**
* 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 DS from 'ember-data';
export default DS.Model.extend({
fileName: DS.attr('string'),
fileSize: DS.attr('string'),
lastModifiedTime: DS.attr('string'),
containerId: DS.attr('string'),
nodeId: DS.attr('string')
});

View File

@ -28,6 +28,9 @@ export default AbstractRoute.extend({
userInfo: this.store.findAll('cluster-user-info', {reload: true}).catch(function() {
return null;
}),
jhsHealth: this.store.queryRecord('jhs-health', {}).catch(function() {
return null;
}),
timelineHealth: this.store.queryRecord('timeline-health', {}).catch(function() {
return null;
})
@ -60,5 +63,6 @@ export default AbstractRoute.extend({
this.store.unloadAll('ClusterInfo');
this.store.unloadAll('cluster-user-info');
this.store.unloadAll('timeline-health');
this.store.unloadAll('jhs-health');
},
});

View File

@ -32,6 +32,11 @@ export default AbstractRoute.extend(AppAttemptMixin, {
return [];
}),
app: this.fetchAppInfoFromRMorATS(app_id, this.store),
jhsHealth: this.store.queryRecord('jhs-health', {}).catch(function(error) {
Ember.Logger.log("jhs-health querying failed");
Ember.Logger.log(error);
return null;
}),
timelineHealth: this.store.queryRecord('timeline-health', {}).catch(function() {
return null;
})
@ -55,6 +60,7 @@ export default AbstractRoute.extend(AppAttemptMixin, {
this.store.unloadAll('yarn-timeline-appattempt');
this.store.unloadAll('yarn-container');
this.store.unloadAll('yarn-timeline-container');
this.store.unloadAll('yarn-jhs-container');
this.store.unloadAll('yarn-log');
if (this.controller) {
this.controller.resetAfterRefresh();

View File

@ -0,0 +1,32 @@
/**
* 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 DS from 'ember-data';
import Ember from 'ember';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload) {
var fixedPayload = {
id: Date.now(),
type: primaryModelClass.modelName,
attributes: payload.historyInfo
};
return { data: fixedPayload };
}
});

View File

@ -0,0 +1,38 @@
/**
* 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 DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
normalizeSingleResponse(store, primaryModelClass, payload, id/*, requestType*/) {
// Convert plain text response into JSON.
// ID is of the form containerId!fileName
var splits = Converter.splitForAppLogs(id);
var convertedPayload = {
id: id,
type: primaryModelClass.modelName,
attributes: {
logs: payload,
containerID: splits[0],
logFileName: splits[1]
}
};
return { data: convertedPayload };
},
});

View File

@ -0,0 +1,62 @@
/**
* 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 DS from 'ember-data';
import Ember from 'ember';
import Converter from 'yarn-ui/utils/converter';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload) {
var fixedPayload = {
id: payload.containerId,
type: primaryModelClass.modelName,
attributes: {
containerLogInfo: payload.containerLogInfo,
logAggregationType: payload.logAggregationType,
containerId: payload.containerId,
nodeId: payload.nodeId
}
};
return fixedPayload;
},
normalizeSingleResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalized = this.internalNormalizeSingleResponse(store,
primaryModelClass, payload);
return {
data: normalized
};
},
normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) {
payload = payload["containerLogsInfo"]
var normalizedArrayResponse = {
data: []
};
if (payload && Ember.isArray(payload) && !Ember.isEmpty(payload)) {
normalizedArrayResponse.data = payload.map(singleContainer => {
return this.internalNormalizeSingleResponse(store, primaryModelClass,
singleContainer);
});
}
return normalizedArrayResponse;
}
});

View File

@ -0,0 +1,56 @@
/**
* 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 DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
internalNormalizeSingleResponse(store, primaryModelClass, payload, containerId, nodeId) {
var fixedPayload = {
id: "yarn_log_" + payload.fileName + "_" + Date.now(),
type: primaryModelClass.modelName,
attributes: {
fileName: payload.fileName,
fileSize: payload.fileSize,
lastModifiedTime: payload.lastModifiedTime,
containerId: containerId,
nodeId: nodeId
}
};
return fixedPayload;
},
normalizeArrayResponse(store, primaryModelClass, payload/*, id, requestType*/) {
var normalizedArrayResponse = {
data: []
};
// If JSON payload is an object with a containerLogsInfo property
if (payload && payload.containerLogsInfo && payload.containerLogsInfo.containerLogInfo) {
normalizedArrayResponse.data = payload.containerLogsInfo.containerLogInfo.map((signle_payload) => {
return this.internalNormalizeSingleResponse(store, primaryModelClass, signle_payload,
payload.containerLogsInfo.containerId, payload.containerLogsInfo.nodeId);
});
}
// If JSON payload is an array
if (payload && payload[0] && payload[0].containerLogInfo) {
normalizedArrayResponse.data = payload[0].containerLogInfo.map((signle_payload) => {
return this.internalNormalizeSingleResponse(store, primaryModelClass, signle_payload,
payload[0].containerId, payload[0].nodeId);
});
}
return normalizedArrayResponse;
}
});

View File

@ -80,6 +80,10 @@ export default Ember.Service.extend({
return this.normalizeURL(this.get("env.app.hosts.rmWebAddress"));
}),
jhsAddress: Ember.computed(function() {
return this.normalizeURL(this.get("env.app.hosts.jhsAddress"));
}),
dashWebAddress: Ember.computed(function () {
return this.normalizeURL(this.get("env.app.hosts.dashWebAddress"));
}),

View File

@ -32,11 +32,11 @@
<img src="assets/images/spinner.gif" alt="Loading...">
</div>
{{/if}}
{{#if isTimelineUnHealthy}}
{{#if areJHSandATSUnhealthy}}
<div class="row">
<div class="col-md-8 col-md-offset-2 alert alert-warning text-center">
<span class="glyphicon glyphicon-warning-sign" style="padding-right: 10px"></span>
<span>Logs are unavailable because Application Timeline Service seems unhealthy.</span>
<span>Logs are unavailable because Application Timeline Service seems unhealthy and could not connect to the JobHistory server.</span>
</div>
</div>
{{else}}

View File

@ -43,6 +43,12 @@ ENV = {
/*
* Protocol scheme. It can be "http:" or "https:". By default, http is used.
*/
//protocolScheme: "http:"
//protocolScheme: "http:",
/*
* JHS web interface can be configured below.
*/
//jhsAddress: "localhost:19888"
},
};

View File

@ -22,6 +22,7 @@ module.exports = { // YARN UI App configurations
timelineWebAddress: "localhost:8188",
timelineV1WebAddress: "localhost:8188",
rmWebAddress: "localhost:8088",
jhsAddress: "localhost:19888",
protocolScheme: "http:",
isSecurityEnabled: ""
},
@ -33,6 +34,7 @@ module.exports = { // YARN UI App configurations
timelineV2: 'ws/v2/timeline',
timelineV2Log: 'ws/v2/applicationlog',
dashService: 'app/v1/services',
node: '{nodeAddress}/ws/v1/node'
node: '{nodeAddress}/ws/v1/node',
jhs: 'ws/v1/history'
},
};