blob: 4b1e57b5ec8c4b5e18334a49b9893bc4a112f604 [file] [log] [blame]
/**
* 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';
export default Ember.Controller.extend({
queryParams: ["service", "attempt", "containerid"],
service: undefined,
attempt: undefined,
containerid: undefined,
selectedAttemptId: "",
attemptContainerList: null,
selectedContainerId: "",
selectedLogFileName: "",
containerLogFiles: null,
selectedContainerThreaddumpContent: "",
containerNodeMappings: [],
threaddumpErrorMessage: "",
stdoutLogsFetchFailedError: "",
appAttemptToStateMappings: [],
_isLoadingTopPanel: false,
_isLoadingBottomPanel: false,
_isThreaddumpAttemptFailed: false,
_isStdoutLogsFetchFailed: false,
initializeSelect: function(selector = ".js-fetch-attempt-containers") {
Ember.run.schedule("afterRender", this, function() {
$(selector).select2({ width: "350px", multiple: false });
});
},
actions: {
showContainersForAttemptId(attemptId, containerId = "") {
this.set("selectedAttemptId", "");
if (attemptId) {
this.set("_isLoadingTopPanel", true);
this.set("selectedAttemptId", attemptId);
this.fetchRunningContainersForAttemptId(attemptId)
.then(hash => {
let containers = null;
let containerIdArr = {};
var containerNodeMapping = null;
var nodeHttpAddress = null;
// Getting RUNNING containers from the RM first.
if (
hash.rmContainers.get("length") > 0 &&
hash.rmContainers.get("content")
) {
// Create a container-to-NMnode mapping for later use.
hash.rmContainers.get("content").forEach(
function(containerInfo) {
nodeHttpAddress = containerInfo._data.nodeHttpAddress;
nodeHttpAddress = nodeHttpAddress
.replace(/(^\w+:|^)\/\//, '');
containerNodeMapping = Ember.Object.create({
name: containerInfo.id,
value: nodeHttpAddress
});
this.containerNodeMappings.push(containerNodeMapping);
containerIdArr[containerInfo.id] = true;
}.bind(this));
containers = (containers || []).concat(
hash.rmContainers.get("content")
);
}
this.set("attemptContainerList", containers);
this.initializeSelect(".js-fetch-threaddump-containers");
if (containerId) {
this.send("showThreaddumpForContainer", containerId);
}
})
.finally(() => {
this.set("_isLoadingTopPanel", false);
});
} else {
this.set("attemptContainerList", null);
this.set("selectedContainerId", "");
this.set("containerLogFiles", null);
this.set("selectedLogFileName", "");
this.set("selectedContainerThreaddumpContent", "");
this.set("containerNodeMappings", []);
}
},
showThreaddumpForContainer(containerIdForThreaddump) {
Ember.$("#logContentTextArea1234554321").val("");
this.set("showFullThreaddump", false);
this.set("selectedContainerId", containerIdForThreaddump);
this.set("_isLoadingBottomPanel", true);
this.set("_isStdoutLogsFetchFailed", false);
this.set("stdoutLogsFetchFailedError", "");
this.set("_isThreaddumpAttemptFailed", false);
this.set("threaddumpErrorMessage", "");
if (containerIdForThreaddump) {
this.set("selectedContainerThreaddumpContent", "");
this.fetchThreaddumpForContainer(containerIdForThreaddump)
.then(function() {
Ember.Logger.log("Threaddump attempt has been successful!");
var currentContainerId = null;
var currentContainerNode = null;
var nodeForContainerThreaddump = null;
// Fetch the NM node for the selected container from the
// mappings stored above when
this.containerNodeMappings.forEach(function(item) {
currentContainerId = item.name;
currentContainerNode = item.value;
if ((currentContainerId === containerIdForThreaddump)
&& nodeForContainerThreaddump == null) {
nodeForContainerThreaddump = currentContainerNode;
}
});
if (nodeForContainerThreaddump) {
// Fetch stdout logs after 1.2 seconds of a successful POST
// request to RM. This is to allow for sufficient time for the NM
// to heartbeat into RM (default of 1 second) whereupon it will
// receive RM's signal to post a threaddump that will be captured
// in the stdout logs of the container. The extra 200ms is to
// allow for any network/IO delays.
Ember.run.later((function() {
this.fetchLogsForContainer(nodeForContainerThreaddump,
containerIdForThreaddump,
"stdout")
.then(
hash => {
this.set("selectedContainerThreaddumpContent",
hash.logs.get('logs').trim());
}.bind(this))
.catch(function(error) {
this.set("_isStdoutLogsFetchFailed", true);
this.set("stdoutLogsFetchFailedError", error);
}.bind(this))
.finally(function() {
this.set("_isLoadingBottomPanel", false);
}.bind(this));
}.bind(this)), 1200);
}
}.bind(this), function(error) {
this.set("_isThreaddumpAttemptFailed", true);
this.set("threaddumpErrorMessage", error);
this.set("_isLoadingBottomPanel", false);
}.bind(this)).finally(function() {
this.set("selectedContainerThreaddumpContent", "");
}.bind(this));
} else {
this.set("selectedContainerId", "");
this.set("selectedContainerThreaddumpContent", "");
}
}
},
// Set up the running attempt for the first time threaddump button is clicked.
runningAttempt: Ember.computed("model.attempts", function() {
let attempts = this.get("model.attempts");
let runningAttemptId = null;
if (attempts && attempts.get("length") && attempts.get("content")) {
attempts.get("content").forEach(function(appAttempt) {
if (appAttempt._data.state === "RUNNING") {
runningAttemptId = appAttempt._data.appAttemptId;
}
});
}
return runningAttemptId;
}),
/**
* Create and send fetch running containers request.
*/
fetchRunningContainersForAttemptId(attemptId) {
let request = {};
request["rmContainers"] = this.store
.query("yarn-container", {
app_attempt_id: attemptId
})
.catch(function(error) {
return Ember.A();
});
return Ember.RSVP.hash(request);
},
/**
* Create and send fetch logs request for a selected container, from a
* specific node.
*/
fetchLogsForContainer(nodeForContainer, containerId, logFile) {
let request = {};
request["logs"] = this.store
.queryRecord("yarn-node-container-log", {
nodeHttpAddr: nodeForContainer,
containerId: containerId,
fileName: logFile
})
return Ember.RSVP.hash(request);
},
/**
* Send out a POST request to RM to signal a threaddump for the selected
* container for the currently logged-in user.
*/
fetchThreaddumpForContainer(containerId) {
var adapter = this.store.adapterFor("yarn-container-threaddump");
let requestedUser = "";
if (this.model
&& this.model.userInfo
&& this.model.userInfo.get('firstObject')) {
requestedUser = this.model.userInfo
.get('firstObject')
.get('requestedUser');
}
return adapter.signalContainerForThreaddump({}, containerId, requestedUser);
},
/**
* Reset attributes after a refresh.
*/
resetAfterRefresh() {
this.set("selectedAttemptId", "");
this.set("attemptContainerList", null);
this.set("selectedContainerId", "");
this.set("selectedLogFileName", "");
this.set("containerLogFiles", null);
this.set("selectedContainerThreaddumpContent", "");
this.set("containerNodeMappings", []);
this.set("_isThreaddumpAttemptFailed", false);
this.set("threaddumpErrorMessage", "");
this.set("_isStdoutLogsFetchFailed", false);
this.set("stdoutLogsFetchFailedError", "");
this.set("appAttemptToStateMappings", []);
},
// Set the threaddump content in the content area.
showThreaddumpContent: Ember.computed(
"selectedContainerThreaddumpContent",
function() {
return this.get("selectedContainerThreaddumpContent");
}
),
/**
* Check if the application for the container whose threaddump is being attempted
* is even running.
*/
isRunningApp: Ember.computed('model.app.state', function() {
return this.get('model.app.state') === "RUNNING";
})
});