threaddump.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. import Ember from 'ember';
  19. import Constants from 'yarn-ui/constants';
  20. export default Ember.Controller.extend({
  21. queryParams: ["service", "attempt", "containerid"],
  22. service: undefined,
  23. attempt: undefined,
  24. containerid: undefined,
  25. selectedAttemptId: "",
  26. attemptContainerList: null,
  27. selectedContainerId: "",
  28. selectedLogFileName: "",
  29. containerLogFiles: null,
  30. selectedContainerThreaddumpContent: "",
  31. containerNodeMappings: [],
  32. threaddumpErrorMessage: "",
  33. stdoutLogsFetchFailedError: "",
  34. appAttemptToStateMappings: [],
  35. _isLoadingTopPanel: false,
  36. _isLoadingBottomPanel: false,
  37. _isThreaddumpAttemptFailed: false,
  38. _isStdoutLogsFetchFailed: false,
  39. initializeSelect: function(selector = ".js-fetch-attempt-containers") {
  40. Ember.run.schedule("afterRender", this, function() {
  41. $(selector).select2({ width: "350px", multiple: false });
  42. });
  43. },
  44. actions: {
  45. showContainersForAttemptId(attemptId, containerId = "") {
  46. this.set("selectedAttemptId", "");
  47. if (attemptId) {
  48. this.set("_isLoadingTopPanel", true);
  49. this.set("selectedAttemptId", attemptId);
  50. this.fetchRunningContainersForAttemptId(attemptId)
  51. .then(hash => {
  52. let containers = null;
  53. let containerIdArr = {};
  54. var containerNodeMapping = null;
  55. var nodeHttpAddress = null;
  56. // Getting RUNNING containers from the RM first.
  57. if (
  58. hash.rmContainers.get("length") > 0 &&
  59. hash.rmContainers.get("content")
  60. ) {
  61. // Create a container-to-NMnode mapping for later use.
  62. hash.rmContainers.get("content").forEach(
  63. function(containerInfo) {
  64. nodeHttpAddress = containerInfo._data.nodeHttpAddress;
  65. nodeHttpAddress = nodeHttpAddress
  66. .replace(/(^\w+:|^)\/\//, '');
  67. containerNodeMapping = Ember.Object.create({
  68. name: containerInfo.id,
  69. value: nodeHttpAddress
  70. });
  71. this.containerNodeMappings.push(containerNodeMapping);
  72. containerIdArr[containerInfo.id] = true;
  73. }.bind(this));
  74. containers = (containers || []).concat(
  75. hash.rmContainers.get("content")
  76. );
  77. }
  78. this.set("attemptContainerList", containers);
  79. this.initializeSelect(".js-fetch-threaddump-containers");
  80. if (containerId) {
  81. this.send("showThreaddumpForContainer", containerId);
  82. }
  83. })
  84. .finally(() => {
  85. this.set("_isLoadingTopPanel", false);
  86. });
  87. } else {
  88. this.set("attemptContainerList", null);
  89. this.set("selectedContainerId", "");
  90. this.set("containerLogFiles", null);
  91. this.set("selectedLogFileName", "");
  92. this.set("selectedContainerThreaddumpContent", "");
  93. this.set("containerNodeMappings", []);
  94. }
  95. },
  96. showThreaddumpForContainer(containerIdForThreaddump) {
  97. Ember.$("#logContentTextArea1234554321").val("");
  98. this.set("showFullThreaddump", false);
  99. this.set("selectedContainerId", containerIdForThreaddump);
  100. this.set("_isLoadingBottomPanel", true);
  101. this.set("_isStdoutLogsFetchFailed", false);
  102. this.set("stdoutLogsFetchFailedError", "");
  103. this.set("_isThreaddumpAttemptFailed", false);
  104. this.set("threaddumpErrorMessage", "");
  105. if (containerIdForThreaddump) {
  106. this.set("selectedContainerThreaddumpContent", "");
  107. this.fetchThreaddumpForContainer(containerIdForThreaddump)
  108. .then(function() {
  109. Ember.Logger.log("Threaddump attempt has been successful!");
  110. var currentContainerId = null;
  111. var currentContainerNode = null;
  112. var nodeForContainerThreaddump = null;
  113. // Fetch the NM node for the selected container from the
  114. // mappings stored above when
  115. this.containerNodeMappings.forEach(function(item) {
  116. currentContainerId = item.name;
  117. currentContainerNode = item.value;
  118. if ((currentContainerId === containerIdForThreaddump)
  119. && nodeForContainerThreaddump == null) {
  120. nodeForContainerThreaddump = currentContainerNode;
  121. }
  122. });
  123. if (nodeForContainerThreaddump) {
  124. // Fetch stdout logs after 1.2 seconds of a successful POST
  125. // request to RM. This is to allow for sufficient time for the NM
  126. // to heartbeat into RM (default of 1 second) whereupon it will
  127. // receive RM's signal to post a threaddump that will be captured
  128. // in the stdout logs of the container. The extra 200ms is to
  129. // allow for any network/IO delays.
  130. Ember.run.later((function() {
  131. this.fetchLogsForContainer(nodeForContainerThreaddump,
  132. containerIdForThreaddump,
  133. "stdout")
  134. .then(
  135. hash => {
  136. this.set("selectedContainerThreaddumpContent",
  137. hash.logs.get('logs').trim());
  138. }.bind(this))
  139. .catch(function(error) {
  140. this.set("_isStdoutLogsFetchFailed", true);
  141. this.set("stdoutLogsFetchFailedError", error);
  142. }.bind(this))
  143. .finally(function() {
  144. this.set("_isLoadingBottomPanel", false);
  145. }.bind(this));
  146. }.bind(this)), 1200);
  147. }
  148. }.bind(this), function(error) {
  149. this.set("_isThreaddumpAttemptFailed", true);
  150. this.set("threaddumpErrorMessage", error);
  151. this.set("_isLoadingBottomPanel", false);
  152. }.bind(this)).finally(function() {
  153. this.set("selectedContainerThreaddumpContent", "");
  154. }.bind(this));
  155. } else {
  156. this.set("selectedContainerId", "");
  157. this.set("selectedContainerThreaddumpContent", "");
  158. }
  159. }
  160. },
  161. // Set up the running attempt for the first time threaddump button is clicked.
  162. runningAttempt: Ember.computed("model.attempts", function() {
  163. let attempts = this.get("model.attempts");
  164. let runningAttemptId = null;
  165. if (attempts && attempts.get("length") && attempts.get("content")) {
  166. attempts.get("content").forEach(function(appAttempt) {
  167. if (appAttempt._data.state === "RUNNING") {
  168. runningAttemptId = appAttempt._data.appAttemptId;
  169. }
  170. });
  171. }
  172. return runningAttemptId;
  173. }),
  174. /**
  175. * Create and send fetch running containers request.
  176. */
  177. fetchRunningContainersForAttemptId(attemptId) {
  178. let request = {};
  179. request["rmContainers"] = this.store
  180. .query("yarn-container", {
  181. app_attempt_id: attemptId
  182. })
  183. .catch(function(error) {
  184. return Ember.A();
  185. });
  186. return Ember.RSVP.hash(request);
  187. },
  188. /**
  189. * Create and send fetch logs request for a selected container, from a
  190. * specific node.
  191. */
  192. fetchLogsForContainer(nodeForContainer, containerId, logFile) {
  193. let request = {};
  194. request["logs"] = this.store
  195. .queryRecord("yarn-node-container-log", {
  196. nodeHttpAddr: nodeForContainer,
  197. containerId: containerId,
  198. fileName: logFile
  199. })
  200. return Ember.RSVP.hash(request);
  201. },
  202. /**
  203. * Send out a POST request to RM to signal a threaddump for the selected
  204. * container for the currently logged-in user.
  205. */
  206. fetchThreaddumpForContainer(containerId) {
  207. var adapter = this.store.adapterFor("yarn-container-threaddump");
  208. let requestedUser = "";
  209. if (this.model
  210. && this.model.userInfo
  211. && this.model.userInfo.get('firstObject')) {
  212. requestedUser = this.model.userInfo
  213. .get('firstObject')
  214. .get('requestedUser');
  215. }
  216. return adapter.signalContainerForThreaddump({}, containerId, requestedUser);
  217. },
  218. /**
  219. * Reset attributes after a refresh.
  220. */
  221. resetAfterRefresh() {
  222. this.set("selectedAttemptId", "");
  223. this.set("attemptContainerList", null);
  224. this.set("selectedContainerId", "");
  225. this.set("selectedLogFileName", "");
  226. this.set("containerLogFiles", null);
  227. this.set("selectedContainerThreaddumpContent", "");
  228. this.set("containerNodeMappings", []);
  229. this.set("_isThreaddumpAttemptFailed", false);
  230. this.set("threaddumpErrorMessage", "");
  231. this.set("_isStdoutLogsFetchFailed", false);
  232. this.set("stdoutLogsFetchFailedError", "");
  233. this.set("appAttemptToStateMappings", []);
  234. },
  235. // Set the threaddump content in the content area.
  236. showThreaddumpContent: Ember.computed(
  237. "selectedContainerThreaddumpContent",
  238. function() {
  239. return this.get("selectedContainerThreaddumpContent");
  240. }
  241. ),
  242. /**
  243. * Check if the application for the container whose threaddump is being attempted
  244. * is even running.
  245. */
  246. isRunningApp: Ember.computed('model.app.state', function() {
  247. return this.get('model.app.state') === "RUNNING";
  248. })
  249. });