host.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  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
  7. * "License"); 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. var App = require('app');
  19. var validator = require('utils/validator');
  20. var batchUtils = require('utils/batch_scheduled_requests');
  21. App.MainHostController = Em.ArrayController.extend(App.TableServerMixin, {
  22. name: 'mainHostController',
  23. dataSource: App.Host.find(),
  24. clearFilters: null,
  25. filteredCount: 0,
  26. /**
  27. * total number of installed hosts
  28. */
  29. totalCount: function () {
  30. return this.get('hostsCountMap')['TOTAL'] || 0;
  31. }.property('hostsCountMap'),
  32. resetStartIndex: false,
  33. /**
  34. * flag responsible for updating status counters of hosts
  35. */
  36. isCountersUpdating: false,
  37. hostsCountMap: {},
  38. startIndex: 1,
  39. expandedComponentsSections: [],
  40. expandedVersionsSections: [],
  41. /**
  42. * Components which will be shown in component filter
  43. * @returns {Array}
  44. */
  45. componentsForFilter: function () {
  46. var installedComponents = App.StackServiceComponent.find().toArray();
  47. installedComponents.setEach('checkedForHostFilter', false);
  48. return installedComponents;
  49. }.property('App.router.clusterController.isLoaded'),
  50. content: function () {
  51. return this.get('dataSource').filterProperty('isRequested');
  52. }.property('dataSource.@each.isRequested'),
  53. allHostStackVersions: App.HostStackVersion.find(),
  54. /**
  55. * filterProperties support follow types of filter:
  56. * MATCH - match of RegExp
  57. * EQUAL - equality "="
  58. * LESS - "<"
  59. * MORE - ">"
  60. * MULTIPLE - multiple values to compare
  61. * CUSTOM - substitute values with keys "{#}" in alias
  62. */
  63. filterProperties: [
  64. {
  65. name: 'hostName',
  66. key: 'Hosts/host_name',
  67. type: 'MATCH'
  68. },
  69. {
  70. name: 'ip',
  71. key: 'Hosts/ip',
  72. type: 'MATCH'
  73. },
  74. {
  75. name: 'cpu',
  76. key: 'Hosts/cpu_count',
  77. type: 'EQUAL'
  78. },
  79. {
  80. name: 'memoryFormatted',
  81. key: 'Hosts/total_mem',
  82. type: 'EQUAL'
  83. },
  84. {
  85. name: 'loadAvg',
  86. key: 'metrics/load/load_one',
  87. type: 'EQUAL'
  88. },
  89. {
  90. name: 'hostComponents',
  91. key: 'host_components/HostRoles/component_name',
  92. type: 'MULTIPLE'
  93. },
  94. {
  95. name: 'healthClass',
  96. key: 'Hosts/host_status',
  97. type: 'EQUAL'
  98. },
  99. {
  100. name: 'criticalWarningAlertsCount',
  101. key: 'alerts_summary/CRITICAL{0}|alerts_summary/WARNING{1}',
  102. type: 'CUSTOM'
  103. },
  104. {
  105. name: 'componentsWithStaleConfigsCount',
  106. key: 'host_components/HostRoles/stale_configs',
  107. type: 'EQUAL'
  108. },
  109. {
  110. name: 'componentsInPassiveStateCount',
  111. key: 'host_components/HostRoles/maintenance_state',
  112. type: 'MULTIPLE'
  113. },
  114. {
  115. name: 'selected',
  116. key: 'Hosts/host_name',
  117. type: 'MULTIPLE'
  118. },
  119. {
  120. name: 'hostStackVersion',
  121. key: 'stack_versions',
  122. type: 'EQUAL'
  123. }
  124. ],
  125. sortProps: [
  126. {
  127. name: 'hostName',
  128. key: 'Hosts/host_name'
  129. },
  130. {
  131. name: 'ip',
  132. key: 'Hosts/ip'
  133. },
  134. {
  135. name: 'cpu',
  136. key: 'Hosts/cpu_count'
  137. },
  138. {
  139. name: 'memoryFormatted',
  140. key: 'Hosts/total_mem'
  141. },
  142. {
  143. name: 'diskUsage',
  144. //TODO disk_usage is relative property and need support from API, metrics/disk/disk_free used temporarily
  145. key: 'metrics/disk/disk_free'
  146. },
  147. {
  148. name: 'loadAvg',
  149. key: 'metrics/load/load_one'
  150. }
  151. ],
  152. /**
  153. * Validate and convert input string to valid url parameter.
  154. * Detect if user have passed string as regular expression or extend
  155. * string to regexp.
  156. *
  157. * @param {String} value
  158. * @return {String}
  159. **/
  160. getRegExp: function (value) {
  161. value = validator.isValidMatchesRegexp(value) ? value.replace(/(\.+\*?|(\.\*)+)$/, '') + '.*' : '^$';
  162. value = /^\.\*/.test(value) || value == '^$' ? value : '.*' + value;
  163. return value;
  164. },
  165. /**
  166. * Sort by host_name by default
  167. * @method getSortProps
  168. * @returns {{value: 'asc|desc', name: string, type: 'SORT'}[]}
  169. */
  170. getSortProps: function () {
  171. var controllerName = this.get('name'),
  172. db = App.db.getSortingStatuses(controllerName);
  173. if (db && db.everyProperty('status', 'sorting')) {
  174. App.db.setSortingStatuses(controllerName, {
  175. name: 'hostName',
  176. status: 'sorting_asc'
  177. });
  178. }
  179. return this._super();
  180. },
  181. /**
  182. * get query parameters computed from filter properties, sort properties and custom properties of view
  183. * @param {boolean} [skipNonFilterProperties]
  184. * @return {Array}
  185. * @method getQueryParameters
  186. */
  187. getQueryParameters: function (skipNonFilterProperties) {
  188. skipNonFilterProperties = skipNonFilterProperties || false;
  189. var queryParams = [],
  190. savedFilterConditions = App.db.getFilterConditions(this.get('name')) || [],
  191. savedSortConditions = App.db.getSortingStatuses(this.get('name')) || [],
  192. colPropAssoc = this.get('colPropAssoc'),
  193. filterProperties = this.get('filterProperties'),
  194. sortProperties = this.get('sortProps'),
  195. oldProperties = App.router.get('updateController.queryParams.Hosts');
  196. this.set('resetStartIndex', false);
  197. queryParams.pushObjects(this.getPaginationProps());
  198. savedFilterConditions.forEach(function (filter) {
  199. var property = filterProperties.findProperty('name', colPropAssoc[filter.iColumn]);
  200. if (property && filter.value.length > 0 && !filter.skipFilter) {
  201. var result = {
  202. key: property.key,
  203. value: filter.value,
  204. type: property.type,
  205. isFilter: true
  206. };
  207. if (filter.type === 'string' && sortProperties.someProperty('name', colPropAssoc[filter.iColumn])) {
  208. result.value = this.getRegExp(filter.value);
  209. }
  210. if (filter.type === 'number' || filter.type === 'ambari-bandwidth') {
  211. result.type = this.getComparisonType(filter.value);
  212. result.value = this.getProperValue(filter.value);
  213. }
  214. // enter an exact number for RAM filter, need to do a range number match for this
  215. if (filter.type === 'ambari-bandwidth' && result.type == 'EQUAL' && result.value) {
  216. var valuePair = this.convertMemoryToRange(filter.value);
  217. queryParams.push({
  218. key: result.key,
  219. value: valuePair[0],
  220. type: 'MORE'
  221. });
  222. queryParams.push({
  223. key: result.key,
  224. value: valuePair[1],
  225. type: 'LESS'
  226. });
  227. } else if (filter.type === 'ambari-bandwidth' && result.type != 'EQUAL' && result.value){
  228. // enter a comparison type, eg > 1, just do regular match
  229. result.value = this.convertMemory(filter.value);
  230. queryParams.push(result);
  231. } else if (filter.type === 'sub-resource') {
  232. filter.value.forEach(function (item) {
  233. queryParams.push({
  234. key: result.key + "/" + item.property,
  235. value: item.value,
  236. type: 'EQUAL'
  237. });
  238. }, this);
  239. } else {
  240. queryParams.push(result);
  241. }
  242. }
  243. }, this);
  244. if (queryParams.filterProperty('isFilter').length !== oldProperties.filterProperty('isFilter').length) {
  245. queryParams.findProperty('key', 'from').value = 0;
  246. this.set('resetStartIndex', true);
  247. } else {
  248. queryParams.filterProperty('isFilter').forEach(function (queryParam) {
  249. var oldProperty = oldProperties.filterProperty('isFilter').findProperty('key', queryParam.key);
  250. if (!oldProperty || JSON.stringify(oldProperty.value) !== JSON.stringify(queryParam.value)) {
  251. queryParams.findProperty('key', 'from').value = 0;
  252. this.set('resetStartIndex', true);
  253. }
  254. }, this);
  255. }
  256. if (!skipNonFilterProperties) {
  257. queryParams.pushObjects(this.getSortProps());
  258. }
  259. return queryParams;
  260. },
  261. /**
  262. * update status counters of hosts
  263. */
  264. updateStatusCounters: function () {
  265. var self = this;
  266. if (this.get('isCountersUpdating')) {
  267. App.ajax.send({
  268. name: 'host.status.counters',
  269. sender: this,
  270. data: {},
  271. success: 'updateStatusCountersSuccessCallback',
  272. error: 'updateStatusCountersErrorCallback',
  273. callback: function() {
  274. setTimeout(function () {
  275. self.updateStatusCounters();
  276. }, App.get('hostStatusCountersUpdateInterval'));
  277. }
  278. });
  279. }
  280. },
  281. /**
  282. * success callback on <code>updateStatusCounters()</code>
  283. * map counters' value to categories
  284. * @param data
  285. */
  286. updateStatusCountersSuccessCallback: function (data) {
  287. var hostsCountMap = {
  288. 'HEALTHY': data.Clusters.health_report['Host/host_status/HEALTHY'],
  289. 'UNHEALTHY': data.Clusters.health_report['Host/host_status/UNHEALTHY'],
  290. 'ALERT': data.Clusters.health_report['Host/host_status/ALERT'],
  291. 'UNKNOWN': data.Clusters.health_report['Host/host_status/UNKNOWN'],
  292. 'health-status-WITH-ALERTS': (data.alerts_summary_hosts) ? data.alerts_summary_hosts.CRITICAL + data.alerts_summary_hosts.WARNING : 0,
  293. 'health-status-CRITICAL': (data.alerts_summary_hosts) ? data.alerts_summary_hosts.CRITICAL : 0,
  294. 'health-status-RESTART': data.Clusters.health_report['Host/stale_config'],
  295. 'health-status-PASSIVE_STATE': data.Clusters.health_report['Host/maintenance_state'],
  296. 'TOTAL': data.Clusters.total_hosts
  297. };
  298. this.set('hostsCountMap', hostsCountMap);
  299. },
  300. /**
  301. * success callback on <code>updateStatusCounters()</code>
  302. */
  303. updateStatusCountersErrorCallback: function() {
  304. console.warn('ERROR: updateStatusCounters failed')
  305. },
  306. /**
  307. * Return value without predicate
  308. * @param {String} value
  309. * @return {String}
  310. */
  311. getProperValue: function (value) {
  312. return (value.charAt(0) === '>' || value.charAt(0) === '<' || value.charAt(0) === '=') ? value.substr(1, value.length) : value;
  313. },
  314. /**
  315. * Return value converted to kilobytes
  316. * @param {String} value
  317. * @return {*}
  318. */
  319. convertMemory: function (value) {
  320. var scale = value.charAt(value.length - 1);
  321. // first char may be predicate for comparison
  322. value = this.getProperValue(value);
  323. var parsedValue = parseFloat(value);
  324. if (isNaN(parsedValue)) {
  325. return value;
  326. }
  327. switch (scale) {
  328. case 'g':
  329. parsedValue *= 1048576;
  330. break;
  331. case 'm':
  332. parsedValue *= 1024;
  333. break;
  334. case 'k':
  335. break;
  336. default:
  337. //default value in GB
  338. parsedValue *= 1048576;
  339. }
  340. return Math.round(parsedValue);
  341. },
  342. /**
  343. * Return value converted to a range of kilobytes
  344. * @param {String} value
  345. * @return {Array}
  346. */
  347. convertMemoryToRange: function (value) {
  348. var scale = value.charAt(value.length - 1);
  349. // first char may be predicate for comparison
  350. value = this.getProperValue(value);
  351. var parsedValue = parseFloat(value);
  352. if (isNaN(parsedValue)) {
  353. return value;
  354. }
  355. var parsedValuePair = this.rangeConvertNumber(parsedValue, scale);
  356. var multiplyingFactor = 1;
  357. switch (scale) {
  358. case 'g':
  359. multiplyingFactor = 1048576;
  360. break;
  361. case 'm':
  362. multiplyingFactor = 1024;
  363. break;
  364. case 'k':
  365. break;
  366. default:
  367. //default value in GB
  368. multiplyingFactor = 1048576;
  369. }
  370. parsedValuePair[0] = Math.round( parsedValuePair[0] * multiplyingFactor);
  371. parsedValuePair[1] = Math.round( parsedValuePair[1] * multiplyingFactor);
  372. return parsedValuePair;
  373. },
  374. /**
  375. * Return value converted to a range of kilobytes
  376. * eg, return value 1.83 g will target 1.82500 ~ 1.83499 g
  377. * eg, return value 1.8 k will target 1.7500 ~ 1.8499 k
  378. * eg, return value 1.8 m will target 1.7500 ~ 1.8499 m
  379. * @param {number} value
  380. * @param {String} scale
  381. * @return {Array}
  382. */
  383. rangeConvertNumber: function (value, scale) {
  384. if (isNaN(value)) {
  385. return value;
  386. }
  387. var valuePair = [];
  388. switch (scale) {
  389. case 'g':
  390. valuePair = [value - 0.005000, value + 0.004999999];
  391. break;
  392. case 'm':
  393. case 'k':
  394. valuePair = [value - 0.05000, value + 0.04999];
  395. break;
  396. default:
  397. //default value in GB
  398. valuePair = [value - 0.005000, value + 0.004999999];
  399. }
  400. return valuePair;
  401. },
  402. /**
  403. * Return comparison type depending on populated predicate
  404. * @param value
  405. * @return {String}
  406. */
  407. getComparisonType: function (value) {
  408. var comparisonChar = value.charAt(0);
  409. var result = 'EQUAL';
  410. if (isNaN(comparisonChar)) {
  411. switch (comparisonChar) {
  412. case '>':
  413. result = 'MORE';
  414. break;
  415. case '<':
  416. result = 'LESS';
  417. break;
  418. }
  419. }
  420. return result;
  421. },
  422. /**
  423. * Filter hosts by componentName of <code>component</code>
  424. * @param {App.HostComponent} component
  425. */
  426. filterByComponent: function (component) {
  427. if (!component)
  428. return;
  429. var id = component.get('componentName');
  430. var column = 6;
  431. this.get('componentsForFilter').setEach('checkedForHostFilter', false);
  432. var filterForComponent = {
  433. iColumn: column,
  434. value: [id],
  435. type: 'multiple'
  436. };
  437. App.db.setFilterConditions(this.get('name'), [filterForComponent]);
  438. },
  439. /**
  440. * Filter hosts by stack version and state
  441. * @param {String} displayName
  442. * @param {String} state
  443. */
  444. filterByStack: function (displayName, state) {
  445. if (!displayName || !state)
  446. return;
  447. var column = 11;
  448. var filterForStack = {
  449. iColumn: column,
  450. value: [
  451. {
  452. property: 'repository_versions/RepositoryVersions/display_name',
  453. value: displayName
  454. },
  455. {
  456. property: 'HostStackVersions/state',
  457. value: state.toUpperCase()
  458. }
  459. ],
  460. type: 'sub-resource'
  461. };
  462. App.db.setFilterConditions(this.get('name'), [filterForStack]);
  463. },
  464. goToHostAlerts: function (event) {
  465. var host = event && event.context;
  466. if (host) {
  467. App.router.transitionTo('main.hosts.hostDetails.alerts', host);
  468. }
  469. },
  470. /**
  471. * remove selected hosts
  472. */
  473. removeHosts: function () {
  474. var hosts = this.get('content');
  475. var selectedHosts = hosts.filterProperty('isChecked', true);
  476. selectedHosts.forEach(function (_hostInfo) {
  477. console.log('Removing: ' + _hostInfo.hostName);
  478. });
  479. this.get('fullContent').removeObjects(selectedHosts);
  480. },
  481. /**
  482. * remove hosts with id equal host_id
  483. * @param {String} host_id
  484. */
  485. checkRemoved: function (host_id) {
  486. var hosts = this.get('content');
  487. var selectedHosts = hosts.filterProperty('id', host_id);
  488. this.get('fullContent').removeObjects(selectedHosts);
  489. },
  490. /**
  491. * Bulk operation wrapper
  492. * @param {Object} operationData - data about bulk operation (action, hosts or hostComponents etc)
  493. * @param {Array} hosts - list of affected hosts
  494. */
  495. bulkOperation: function (operationData, hosts) {
  496. if (operationData.componentNameFormatted) {
  497. if (operationData.action === 'RESTART') {
  498. this.bulkOperationForHostComponentsRestart(operationData, hosts);
  499. }
  500. else {
  501. if (operationData.action.indexOf('DECOMMISSION') != -1) {
  502. this.bulkOperationForHostComponentsDecommission(operationData, hosts);
  503. }
  504. else {
  505. this.bulkOperationForHostComponents(operationData, hosts);
  506. }
  507. }
  508. }
  509. else {
  510. if (operationData.action === 'RESTART') {
  511. this.bulkOperationForHostsRestart(operationData, hosts);
  512. }
  513. else {
  514. if (operationData.action === 'PASSIVE_STATE') {
  515. this.bulkOperationForHostsPassiveState(operationData, hosts);
  516. }
  517. else {
  518. this.bulkOperationForHosts(operationData, hosts);
  519. }
  520. }
  521. }
  522. },
  523. /**
  524. * Bulk operation (start/stop all) for selected hosts
  525. * @param {Object} operationData - data about bulk operation (action, hostComponents etc)
  526. * @param {Array} hosts - list of affected hosts
  527. */
  528. bulkOperationForHosts: function (operationData, hosts) {
  529. var self = this;
  530. batchUtils.getComponentsFromServer({
  531. hosts: hosts.mapProperty('hostName'),
  532. passiveState: 'OFF',
  533. displayParams: ['host_components/HostRoles/component_name']
  534. }, function (data) {
  535. self.bulkOperationForHostsCallback(operationData, data);
  536. });
  537. },
  538. /**
  539. * run Bulk operation (start/stop all) for selected hosts
  540. * after host and components are loaded
  541. * @param operationData
  542. * @param data
  543. */
  544. bulkOperationForHostsCallback: function (operationData, data) {
  545. var query = [];
  546. var hostNames = [];
  547. var hostsMap = {};
  548. var context = this,
  549. shouldRun = false;
  550. data.items.forEach(function (host) {
  551. host.host_components.forEach(function (hostComponent) {
  552. if (!App.components.get('clients').contains((hostComponent.HostRoles.component_name))) {
  553. if (hostsMap[host.Hosts.host_name]) {
  554. hostsMap[host.Hosts.host_name].push(hostComponent.HostRoles.component_name);
  555. } else {
  556. hostsMap[host.Hosts.host_name] = [hostComponent.HostRoles.component_name];
  557. }
  558. }
  559. });
  560. hostsMap[host.Hosts.host_name].healthStatus = context.dataSource.filterProperty('hostName', host.Hosts.host_name)[0].get('healthStatus');
  561. });
  562. for (var hostName in hostsMap) {
  563. var subQuery = '(HostRoles/component_name.in(%@)&HostRoles/host_name=' + hostName + ')';
  564. var components = hostsMap[hostName];
  565. var action = operationData.get('action'),
  566. healthStatus = hostsMap[hostName].healthStatus;
  567. if (components.length) {
  568. query.push(subQuery.fmt(components.join(',')));
  569. }
  570. hostNames.push(hostName);
  571. if ((action === App.HostComponentStatus.started && healthStatus !== 'HEALTHY') || // start all and already started
  572. (action === App.HostComponentStatus.stopped && healthStatus !== 'UNHEALTHY')) { // stop all and already stopped
  573. shouldRun = true;
  574. }
  575. }
  576. hostNames = hostNames.join(",");
  577. if (query.length && shouldRun) {
  578. query = query.join('|');
  579. App.ajax.send({
  580. name: 'common.host_components.update',
  581. sender: this,
  582. data: {
  583. query: query,
  584. HostRoles: {
  585. state: operationData.action
  586. },
  587. context: operationData.message,
  588. hostName: hostNames
  589. },
  590. success: 'bulkOperationForHostComponentsSuccessCallback'
  591. });
  592. }
  593. else {
  594. App.ModalPopup.show({
  595. header: Em.I18n.t('rolling.nothingToDo.header'),
  596. body: Em.I18n.t('rolling.nothingToDo.body').format(Em.I18n.t('hosts.host.maintainance.allComponents.context')),
  597. secondary: false
  598. });
  599. }
  600. },
  601. /**
  602. * Bulk restart for selected hosts
  603. * @param {Object} operationData - data about bulk operation (action, hostComponents etc)
  604. * @param {Ember.Enumerable} hosts - list of affected hosts
  605. */
  606. bulkOperationForHostsRestart: function (operationData, hosts) {
  607. batchUtils.getComponentsFromServer({
  608. passiveState: 'OFF',
  609. hosts: hosts.mapProperty('hostName'),
  610. displayParams: ['host_components/HostRoles/component_name']
  611. }, function (data) {
  612. var hostComponents = [];
  613. data.items.forEach(function (host) {
  614. host.host_components.forEach(function (hostComponent) {
  615. hostComponents.push(Em.Object.create({
  616. componentName: hostComponent.HostRoles.component_name,
  617. hostName: host.Hosts.host_name
  618. }));
  619. })
  620. });
  621. batchUtils.restartHostComponents(hostComponents, Em.I18n.t('rollingrestart.context.allOnSelectedHosts'), "HOST");
  622. });
  623. },
  624. /**
  625. * Bulk turn on/off passive state for selected hosts
  626. * @param {Object} operationData - data about bulk operation (action, hostComponents etc)
  627. * @param {Array} hosts - list of affected hosts
  628. */
  629. bulkOperationForHostsPassiveState: function (operationData, hosts) {
  630. var self = this;
  631. batchUtils.getComponentsFromServer({
  632. hosts: hosts.mapProperty('hostName'),
  633. displayParams: ['Hosts/maintenance_state']
  634. }, function (data) {
  635. var hostNames = [];
  636. data.items.forEach(function (host) {
  637. if (host.Hosts.maintenance_state !== operationData.state) {
  638. hostNames.push(host.Hosts.host_name);
  639. }
  640. });
  641. if (hostNames.length) {
  642. App.ajax.send({
  643. name: 'bulk_request.hosts.passive_state',
  644. sender: self,
  645. data: {
  646. hostNames: hostNames.join(','),
  647. passive_state: operationData.state,
  648. requestInfo: operationData.message
  649. },
  650. success: 'updateHostPassiveState'
  651. });
  652. } else {
  653. App.ModalPopup.show({
  654. header: Em.I18n.t('rolling.nothingToDo.header'),
  655. body: Em.I18n.t('hosts.bulkOperation.passiveState.nothingToDo.body'),
  656. secondary: false
  657. });
  658. }
  659. });
  660. },
  661. updateHostPassiveState: function (data, opt, params) {
  662. batchUtils.infoPassiveState(params.passive_state);
  663. },
  664. /**
  665. * Bulk operation for selected hostComponents
  666. * @param {Object} operationData - data about bulk operation (action, hostComponents etc)
  667. * @param {Array} hosts - list of affected hosts
  668. */
  669. bulkOperationForHostComponents: function (operationData, hosts) {
  670. var self = this;
  671. batchUtils.getComponentsFromServer({
  672. components: [operationData.componentName],
  673. hosts: hosts.mapProperty('hostName'),
  674. passiveState: 'OFF'
  675. }, function (data) {
  676. if (data.items.length) {
  677. var hostsWithComponentInProperState = data.items.mapProperty('Hosts.host_name');
  678. App.ajax.send({
  679. name: 'common.host_components.update',
  680. sender: self,
  681. data: {
  682. HostRoles: {
  683. state: operationData.action
  684. },
  685. query: 'HostRoles/component_name=' + operationData.componentName + '&HostRoles/host_name.in(' + hostsWithComponentInProperState.join(',') + ')&HostRoles/maintenance_state=OFF',
  686. context: operationData.message + ' ' + operationData.componentNameFormatted,
  687. level: 'SERVICE'
  688. },
  689. success: 'bulkOperationForHostComponentsSuccessCallback'
  690. });
  691. }
  692. else {
  693. App.ModalPopup.show({
  694. header: Em.I18n.t('rolling.nothingToDo.header'),
  695. body: Em.I18n.t('rolling.nothingToDo.body').format(operationData.componentNameFormatted),
  696. secondary: false
  697. });
  698. }
  699. });
  700. },
  701. /**
  702. * Bulk decommission/recommission for selected hostComponents
  703. * @param {Object} operationData
  704. * @param {Array} hosts
  705. */
  706. bulkOperationForHostComponentsDecommission: function (operationData, hosts) {
  707. var self = this;
  708. batchUtils.getComponentsFromServer({
  709. components: [operationData.realComponentName],
  710. hosts: hosts.mapProperty('hostName'),
  711. passiveState: 'OFF',
  712. displayParams: ['host_components/HostRoles/state']
  713. }, function (data) {
  714. self.bulkOperationForHostComponentsDecommissionCallBack(operationData, data)
  715. });
  716. },
  717. /**
  718. * run Bulk decommission/recommission for selected hostComponents
  719. * after host and components are loaded
  720. * @param operationData
  721. * @param data
  722. */
  723. bulkOperationForHostComponentsDecommissionCallBack: function (operationData, data) {
  724. var service = App.Service.find(operationData.serviceName);
  725. var components = [];
  726. data.items.forEach(function (host) {
  727. host.host_components.forEach(function (hostComponent) {
  728. components.push(Em.Object.create({
  729. componentName: hostComponent.HostRoles.component_name,
  730. hostName: host.Hosts.host_name,
  731. workStatus: hostComponent.HostRoles.state
  732. }))
  733. });
  734. });
  735. if (components.length) {
  736. var hostsWithComponentInProperState = components.mapProperty('hostName');
  737. var turn_off = operationData.action.indexOf('OFF') !== -1;
  738. var svcName = operationData.serviceName;
  739. var masterName = operationData.componentName;
  740. var slaveName = operationData.realComponentName;
  741. var hostNames = hostsWithComponentInProperState.join(',');
  742. if (turn_off) {
  743. // For recommession
  744. if (svcName === "YARN" || svcName === "HBASE" || svcName === "HDFS") {
  745. App.router.get('mainHostDetailsController').doRecommissionAndStart(hostNames, svcName, masterName, slaveName);
  746. }
  747. } else {
  748. hostsWithComponentInProperState = components.filterProperty('workStatus', 'STARTED').mapProperty('hostName');
  749. //For decommession
  750. if (svcName == "HBASE") {
  751. // HBASE service, decommission RegionServer in batch requests
  752. this.warnBeforeDecommission(hostNames);
  753. } else {
  754. var parameters = {
  755. "slave_type": slaveName
  756. };
  757. var contextString = turn_off ? 'hosts.host.' + slaveName.toLowerCase() + '.recommission' :
  758. 'hosts.host.' + slaveName.toLowerCase() + '.decommission';
  759. if (turn_off) {
  760. parameters['included_hosts'] = hostsWithComponentInProperState.join(',')
  761. }
  762. else {
  763. parameters['excluded_hosts'] = hostsWithComponentInProperState.join(',');
  764. }
  765. App.ajax.send({
  766. name: 'bulk_request.decommission',
  767. sender: this,
  768. data: {
  769. context: Em.I18n.t(contextString),
  770. serviceName: service.get('serviceName'),
  771. componentName: operationData.componentName,
  772. parameters: parameters
  773. },
  774. success: 'bulkOperationForHostComponentsSuccessCallback'
  775. });
  776. }
  777. }
  778. }
  779. else {
  780. App.ModalPopup.show({
  781. header: Em.I18n.t('rolling.nothingToDo.header'),
  782. body: Em.I18n.t('rolling.nothingToDo.body').format(operationData.componentNameFormatted),
  783. secondary: false
  784. });
  785. }
  786. },
  787. /**
  788. * get info about regionserver passive_state
  789. * @method warnBeforeDecommission
  790. * @param {String} hostNames
  791. * @return {$.ajax}
  792. */
  793. warnBeforeDecommission: function (hostNames) {
  794. return App.ajax.send({
  795. 'name': 'host_components.hbase_regionserver.active',
  796. 'sender': this,
  797. 'data': {
  798. hostNames: hostNames
  799. },
  800. success: 'warnBeforeDecommissionSuccess'
  801. });
  802. },
  803. /**
  804. * check is hbase regionserver in mm. If so - run decommission
  805. * otherwise shows warning
  806. * @method warnBeforeDecommission
  807. * @param {Object} data
  808. * @param {Object} opt
  809. * @param {Object} params
  810. */
  811. warnBeforeDecommissionSuccess: function(data, opt, params) {
  812. if (Em.get(data, 'items.length')) {
  813. App.router.get('mainHostDetailsController').showHbaseActiveWarning();
  814. } else {
  815. App.router.get('mainHostDetailsController').checkRegionServerState(params.hostNames);
  816. }
  817. },
  818. /**
  819. * Bulk restart for selected hostComponents
  820. * @param {Object} operationData
  821. * @param {Array} hosts
  822. */
  823. bulkOperationForHostComponentsRestart: function (operationData, hosts) {
  824. var service = App.Service.find(operationData.serviceName);
  825. batchUtils.getComponentsFromServer({
  826. components: [operationData.componentName],
  827. hosts: hosts.mapProperty('hostName'),
  828. passiveState: 'OFF',
  829. displayParams: ['Hosts/maintenance_state', 'host_components/HostRoles/stale_configs', 'host_components/HostRoles/maintenance_state']
  830. }, function (data) {
  831. var wrappedHostComponents = [];
  832. data.items.forEach(function (host) {
  833. host.host_components.forEach(function (hostComponent) {
  834. wrappedHostComponents.push(Em.Object.create({
  835. componentName: hostComponent.HostRoles.component_name,
  836. serviceName: operationData.serviceName,
  837. hostName: host.Hosts.host_name,
  838. hostPassiveState: host.Hosts.maintenance_state,
  839. staleConfigs: hostComponent.HostRoles.stale_configs,
  840. passiveState: hostComponent.HostRoles.maintenance_state
  841. }))
  842. });
  843. });
  844. if (wrappedHostComponents.length) {
  845. batchUtils.showRollingRestartPopup(wrappedHostComponents.objectAt(0).get('componentName'), service.get('displayName'), service.get('passiveState') === "ON", false, wrappedHostComponents);
  846. } else {
  847. App.ModalPopup.show({
  848. header: Em.I18n.t('rolling.nothingToDo.header'),
  849. body: Em.I18n.t('rolling.nothingToDo.body').format(operationData.componentNameFormatted),
  850. secondary: false
  851. });
  852. }
  853. });
  854. },
  855. updateHostComponentsPassiveState: function (data, opt, params) {
  856. batchUtils.infoPassiveState(params.passive_state);
  857. },
  858. /**
  859. * Show BO popup after bulk request
  860. */
  861. bulkOperationForHostComponentsSuccessCallback: function () {
  862. App.router.get('applicationController').dataLoading().done(function (initValue) {
  863. if (initValue) {
  864. App.router.get('backgroundOperationsController').showPopup();
  865. }
  866. });
  867. },
  868. /**
  869. * associations between host property and column index
  870. * @type {Array}
  871. */
  872. colPropAssoc: function () {
  873. var associations = [];
  874. associations[0] = 'healthClass';
  875. associations[1] = 'hostName';
  876. associations[2] = 'ip';
  877. associations[3] = 'cpu';
  878. associations[4] = 'memoryFormatted';
  879. associations[5] = 'loadAvg';
  880. associations[6] = 'hostComponents';
  881. associations[7] = 'criticalWarningAlertsCount';
  882. associations[8] = 'componentsWithStaleConfigsCount';
  883. associations[9] = 'componentsInPassiveStateCount';
  884. associations[10] = 'selected';
  885. associations[11] = 'hostStackVersion';
  886. return associations;
  887. }.property()
  888. });