step4_controller.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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. App.ReassignMasterWizardStep4Controller = App.HighAvailabilityProgressPageController.extend({
  20. isReassign: true,
  21. commands: ['stopServices', 'createHostComponents', 'putHostComponentsInMaintenanceMode', 'reconfigure', 'installHostComponents', 'startZooKeeperServers', 'startNameNode', 'deleteHostComponents', 'startServices'],
  22. clusterDeployState: 'REASSIGN_MASTER_INSTALLING',
  23. multiTaskCounter: 0,
  24. hostComponents: [],
  25. restartYarnMRComponents: false,
  26. /**
  27. * additional configs with template values
  28. * Part of value to substitute has following format: "<replace-value>"
  29. */
  30. additionalConfigsMap: [
  31. {
  32. componentName: 'RESOURCEMANAGER',
  33. configs: {
  34. 'yarn-site': {
  35. 'yarn.resourcemanager.address': '<replace-value>:8050',
  36. 'yarn.resourcemanager.admin.address': '<replace-value>:8141',
  37. 'yarn.resourcemanager.resource-tracker.address': '<replace-value>:8025',
  38. 'yarn.resourcemanager.scheduler.address': '<replace-value>:8030',
  39. 'yarn.resourcemanager.webapp.address': '<replace-value>:8088',
  40. 'yarn.resourcemanager.hostname': '<replace-value>'
  41. }
  42. }
  43. },
  44. {
  45. componentName: 'JOBTRACKER',
  46. configs: {
  47. 'mapred-site': {
  48. 'mapred.job.tracker.http.address': '<replace-value>:50030',
  49. 'mapred.job.tracker': '<replace-value>:50300'
  50. }
  51. }
  52. },
  53. {
  54. componentName: 'SECONDARY_NAMENODE',
  55. configs: {
  56. 'hdfs-site': {
  57. 'dfs.secondary.http.address': '<replace-value>:50090'
  58. }
  59. },
  60. configs_Hadoop2: {
  61. 'hdfs-site': {
  62. 'dfs.namenode.secondary.http-address': '<replace-value>:50090'
  63. }
  64. }
  65. },
  66. {
  67. componentName: 'NAMENODE',
  68. configs: {
  69. 'hdfs-site': {
  70. 'dfs.http.address': '<replace-value>:50070',
  71. 'dfs.https.address': '<replace-value>:50470'
  72. },
  73. 'core-site': {
  74. 'fs.default.name': 'hdfs://<replace-value>:8020'
  75. }
  76. },
  77. configs_Hadoop2: {
  78. 'hdfs-site': {
  79. 'dfs.namenode.http-address': '<replace-value>:50070',
  80. 'dfs.namenode.https-address': '<replace-value>:50470'
  81. },
  82. 'core-site': {
  83. 'fs.defaultFS': 'hdfs://<replace-value>:8020'
  84. }
  85. }
  86. }
  87. ],
  88. secureConfigsMap: [
  89. {
  90. componentName: 'NAMENODE',
  91. configs: [
  92. {
  93. site: 'hdfs-site',
  94. keytab: 'dfs.namenode.keytab.file',
  95. principal: 'dfs.namenode.kerberos.principal'
  96. },
  97. {
  98. site: 'hdfs-site',
  99. keytab: 'dfs.web.authentication.kerberos.keytab',
  100. principal: 'dfs.web.authentication.kerberos.principal'
  101. }
  102. ]
  103. },
  104. {
  105. componentName: 'SECONDARY_NAMENODE',
  106. configs: [
  107. {
  108. site: 'hdfs-site',
  109. keytab: 'dfs.secondary.namenode.keytab.file',
  110. principal: 'dfs.secondary.namenode.kerberos.principal'
  111. },
  112. {
  113. site: 'hdfs-site',
  114. keytab: 'dfs.web.authentication.kerberos.keytab',
  115. principal: 'dfs.web.authentication.kerberos.principal'
  116. }
  117. ]
  118. },
  119. {
  120. componentName: 'RESOURCEMANAGER',
  121. configs: [
  122. {
  123. site: 'yarn-site',
  124. keytab: 'yarn.resourcemanager.keytab',
  125. principal: 'yarn.resourcemanager.principal'
  126. },
  127. {
  128. site: 'yarn-site',
  129. keytab: 'yarn.resourcemanager.webapp.spnego-keytab-file',
  130. principal: 'yarn.resourcemanager.webapp.spnego-principal'
  131. }
  132. ]
  133. },
  134. {
  135. componentName: 'JOBTRACKER',
  136. configs: [
  137. {
  138. site: 'mapred-site',
  139. keytab: 'mapreduce.jobtracker.keytab.file',
  140. principal: 'mapreduce.jobtracker.kerberos.principal'
  141. }
  142. ]
  143. }
  144. ],
  145. /**
  146. * set additional configs
  147. * configs_Hadoop2 - configs which belongs to Hadoop 2 stack only
  148. * @param configs
  149. * @param componentName
  150. * @param replaceValue
  151. * @return {Boolean}
  152. */
  153. setAdditionalConfigs: function (configs, componentName, replaceValue) {
  154. var isHadoop2Stack = App.get('isHadoop2Stack');
  155. var component = this.get('additionalConfigsMap').findProperty('componentName', componentName);
  156. if (Em.isNone(component)) return false;
  157. var additionalConfigs = (component.configs_Hadoop2 && isHadoop2Stack) ? component.configs_Hadoop2 : component.configs;
  158. for (var site in additionalConfigs) {
  159. for (var property in additionalConfigs[site]) {
  160. configs[site][property] = additionalConfigs[site][property].replace('<replace-value>', replaceValue);
  161. }
  162. }
  163. return true;
  164. },
  165. /**
  166. * load step info
  167. */
  168. loadStep: function () {
  169. if (this.get('content.reassign.component_name') === 'NAMENODE' && App.get('isHaEnabled')) {
  170. this.set('hostComponents', ['NAMENODE', 'ZKFC']);
  171. } else {
  172. this.set('hostComponents', [this.get('content.reassign.component_name')]);
  173. }
  174. this.set('restartYarnMRComponents', ['RESOURCEMANAGER', 'JOBTRACKER'].contains(this.get('content.reassign.component_name')));
  175. this.set('serviceName', [this.get('content.reassign.service_id')]);
  176. this._super();
  177. },
  178. /**
  179. * concat host-component names into string
  180. * @return {String}
  181. */
  182. getHostComponentsNames: function () {
  183. var hostComponentsNames = '';
  184. this.get('hostComponents').forEach(function (comp, index) {
  185. hostComponentsNames += index ? '+' : '';
  186. hostComponentsNames += comp === 'ZKFC' ? comp : App.format.role(comp);
  187. }, this);
  188. return hostComponentsNames;
  189. },
  190. /**
  191. * remove unneeded tasks
  192. */
  193. removeUnneededTasks: function () {
  194. if (this.get('content.hasManualSteps')) {
  195. if (this.get('content.reassign.component_name') === 'NAMENODE' && App.get('isHaEnabled')) {
  196. // Only for reassign NameNode with HA enabled
  197. this.get('tasks').splice(7, 2);
  198. } else {
  199. this.get('tasks').splice(5, 4);
  200. }
  201. } else {
  202. this.get('tasks').splice(5, 2);
  203. }
  204. },
  205. /**
  206. * initialize tasks
  207. */
  208. initializeTasks: function () {
  209. var commands = this.get('commands');
  210. var currentStep = App.router.get('reassignMasterController.currentStep');
  211. var hostComponentsNames = this.getHostComponentsNames();
  212. for (var i = 0; i < commands.length; i++) {
  213. var TaskLabel = i === 3 ? this.get('serviceName') : hostComponentsNames; //For Reconfigure task, show serviceName
  214. var title = Em.I18n.t('services.reassign.step4.task' + i + '.title').format(TaskLabel);
  215. this.get('tasks').pushObject(Ember.Object.create({
  216. title: title,
  217. status: 'PENDING',
  218. id: i,
  219. command: commands[i],
  220. showRetry: false,
  221. showRollback: false,
  222. name: title,
  223. displayName: title,
  224. progress: 0,
  225. isRunning: false,
  226. hosts: []
  227. }));
  228. }
  229. this.removeUnneededTasks();
  230. },
  231. hideRollbackButton: function () {
  232. var failedTask = this.get('tasks').findProperty('showRollback');
  233. if (failedTask) {
  234. failedTask.set('showRollback', false);
  235. }
  236. }.observes('tasks.@each.showRollback'),
  237. onComponentsTasksSuccess: function () {
  238. this.incrementProperty('multiTaskCounter');
  239. if (this.get('multiTaskCounter') >= this.get('hostComponents').length) {
  240. this.onTaskCompleted();
  241. }
  242. },
  243. /**
  244. * compute data for call to stop services
  245. */
  246. getStopServicesData: function () {
  247. var data = {
  248. "ServiceInfo": {
  249. "state": "INSTALLED"
  250. }
  251. };
  252. if (this.get('restartYarnMRComponents')) {
  253. var list = App.Service.find().mapProperty("serviceName").without("HDFS").join(',');
  254. data.context = "Stop without HDFS";
  255. data.urlParams = "ServiceInfo/service_name.in(" + list + ")";
  256. } else {
  257. data.context = "Stop all services";
  258. }
  259. return data;
  260. },
  261. /**
  262. * make server call to stop services
  263. */
  264. stopServices: function () {
  265. App.ajax.send({
  266. name: 'common.services.update',
  267. sender: this,
  268. data: this.getStopServicesData(),
  269. success: 'startPolling',
  270. error: 'onTaskError'
  271. });
  272. },
  273. createHostComponents: function () {
  274. this.set('multiTaskCounter', 0);
  275. var hostComponents = this.get('hostComponents');
  276. var hostName = this.get('content.reassignHosts.target');
  277. for (var i = 0; i < hostComponents.length; i++) {
  278. this.createComponent(hostComponents[i], hostName, this.get('content.reassign.service_id'));
  279. }
  280. },
  281. onCreateComponent: function () {
  282. this.onComponentsTasksSuccess();
  283. },
  284. putHostComponentsInMaintenanceMode: function () {
  285. this.set('multiTaskCounter', 0);
  286. var hostComponents = this.get('hostComponents');
  287. var hostName = this.get('content.reassignHosts.source');
  288. for (var i = 0; i < hostComponents.length; i++) {
  289. App.ajax.send({
  290. name: 'common.host.host_component.passive',
  291. sender: this,
  292. data: {
  293. hostName: hostName,
  294. passive_state: "ON",
  295. componentName: hostComponents[i]
  296. },
  297. success: 'onComponentsTasksSuccess',
  298. error: 'onTaskError'
  299. });
  300. }
  301. },
  302. installHostComponents: function () {
  303. this.set('multiTaskCounter', 0);
  304. var hostComponents = this.get('hostComponents');
  305. var hostName = this.get('content.reassignHosts.target');
  306. for (var i = 0; i < hostComponents.length; i++) {
  307. this.updateComponent(hostComponents[i], hostName, this.get('content.reassign.service_id'), "Install", hostComponents.length);
  308. }
  309. },
  310. reconfigure: function () {
  311. this.loadConfigsTags();
  312. },
  313. loadConfigsTags: function () {
  314. App.ajax.send({
  315. name: 'config.tags',
  316. sender: this,
  317. success: 'onLoadConfigsTags',
  318. error: 'onTaskError'
  319. });
  320. },
  321. /**
  322. * construct URL parameters for config call
  323. * @param componentName
  324. * @param data
  325. * @return {Array}
  326. */
  327. getConfigUrlParams: function (componentName, data) {
  328. var urlParams = [];
  329. switch (componentName) {
  330. case 'NAMENODE':
  331. urlParams.push('(type=hdfs-site&tag=' + data.Clusters.desired_configs['hdfs-site'].tag + ')');
  332. urlParams.push('(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')');
  333. if (App.Service.find().someProperty('serviceName', 'HBASE')) {
  334. urlParams.push('(type=hbase-site&tag=' + data.Clusters.desired_configs['hbase-site'].tag + ')');
  335. }
  336. break;
  337. case 'SECONDARY_NAMENODE':
  338. urlParams.push('(type=hdfs-site&tag=' + data.Clusters.desired_configs['hdfs-site'].tag + ')');
  339. urlParams.push('(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')');
  340. break;
  341. case 'JOBTRACKER':
  342. urlParams.push('(type=mapred-site&tag=' + data.Clusters.desired_configs['mapred-site'].tag + ')');
  343. break;
  344. case 'RESOURCEMANAGER':
  345. urlParams.push('(type=yarn-site&tag=' + data.Clusters.desired_configs['yarn-site'].tag + ')');
  346. break;
  347. }
  348. return urlParams;
  349. },
  350. onLoadConfigsTags: function (data) {
  351. var urlParams = this.getConfigUrlParams(this.get('content.reassign.component_name'), data);
  352. App.ajax.send({
  353. name: 'reassign.load_configs',
  354. sender: this,
  355. data: {
  356. urlParams: urlParams.join('|')
  357. },
  358. success: 'onLoadConfigs',
  359. error: 'onTaskError'
  360. });
  361. },
  362. configsSitesCount: null,
  363. configsSitesNumber: null,
  364. onLoadConfigs: function (data) {
  365. var componentName = this.get('content.reassign.component_name');
  366. var targetHostName = this.get('content.reassignHosts.target');
  367. var configs = {};
  368. var secureConfigs = [];
  369. this.set('configsSitesNumber', data.items.length);
  370. this.set('configsSitesCount', 0);
  371. data.items.forEach(function (item) {
  372. configs[item.type] = item.properties;
  373. }, this);
  374. this.setAdditionalConfigs(configs, componentName, targetHostName);
  375. this.setSecureConfigs(secureConfigs, configs, componentName);
  376. if (componentName === 'NAMENODE') {
  377. this.setSpecificNamenodeConfigs(configs, targetHostName);
  378. }
  379. if (componentName === 'RESOURCEMANAGER') {
  380. this.setSpecificResourceMangerConfigs(configs, targetHostName);
  381. }
  382. this.saveClusterStatus(secureConfigs, this.getComponentDir(configs, componentName));
  383. this.saveConfigsToServer(configs);
  384. },
  385. /**
  386. * make PUT call to save configs to server
  387. * @param configs
  388. */
  389. saveConfigsToServer: function (configs) {
  390. for (var site in configs) {
  391. App.ajax.send({
  392. name: 'reassign.save_configs',
  393. sender: this,
  394. data: {
  395. siteName: site,
  396. properties: configs[site]
  397. },
  398. success: 'onSaveConfigs',
  399. error: 'onTaskError'
  400. });
  401. }
  402. },
  403. /**
  404. * set specific configs which applies only to NameNode component
  405. * @param configs
  406. * @param targetHostName
  407. */
  408. setSpecificNamenodeConfigs: function (configs, targetHostName) {
  409. var sourceHostName = this.get('content.reassignHosts.source');
  410. if (App.get('isHadoop2Stack') && App.get('isHaEnabled')) {
  411. var nameServices = configs['hdfs-site']['dfs.nameservices'];
  412. if (configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] === sourceHostName + ':50070') {
  413. configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] = targetHostName + ':50070';
  414. configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn1'] = targetHostName + ':50470';
  415. configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn1'] = targetHostName + ':8020';
  416. } else {
  417. configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn2'] = targetHostName + ':50070';
  418. configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn2'] = targetHostName + ':50470';
  419. configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn2'] = targetHostName + ':8020';
  420. }
  421. }
  422. if (!App.get('isHaEnabled') && App.Service.find('HBASE').get('isLoaded')) {
  423. configs['hbase-site']['hbase.rootdir'] = configs['hbase-site']['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + targetHostName + ':8020');
  424. }
  425. },
  426. /**
  427. * set specific configs which applies only to ResourceManager component
  428. * @param configs
  429. * @param targetHostName
  430. */
  431. setSpecificResourceMangerConfigs: function (configs, targetHostName) {
  432. var sourceHostName = this.get('content.reassignHosts.source');
  433. if (App.get('isHadoop2Stack') && App.get('isRMHaEnabled')) {
  434. if (configs['yarn-site']['yarn.resourcemanager.hostname.rm1'] === sourceHostName) {
  435. configs['yarn-site']['yarn.resourcemanager.hostname.rm1'] = targetHostName;
  436. } else {
  437. configs['yarn-site']['yarn.resourcemanager.hostname.rm2'] = targetHostName;
  438. }
  439. }
  440. },
  441. /**
  442. * set secure configs for component
  443. * @param secureConfigs
  444. * @param configs
  445. * @param componentName
  446. * @return {Boolean}
  447. */
  448. setSecureConfigs: function (secureConfigs, configs, componentName) {
  449. var securityEnabled = this.get('content.securityEnabled');
  450. var component = this.get('secureConfigsMap').findProperty('componentName', componentName);
  451. if (Em.isNone(component) || !securityEnabled) return false;
  452. component.configs.forEach(function (config) {
  453. secureConfigs.push({
  454. keytab: configs[config.site][config.keytab],
  455. principal: configs[config.site][config.principal]
  456. });
  457. });
  458. return true;
  459. },
  460. /**
  461. * derive component directory from configurations
  462. * @param configs
  463. * @param componentName
  464. * @return {String}
  465. */
  466. getComponentDir: function (configs, componentName) {
  467. if (componentName === 'NAMENODE') {
  468. return (App.get('isHadoop2Stack')) ? configs['hdfs-site']['dfs.namenode.name.dir'] : configs['hdfs-site']['dfs.name.dir'];
  469. }
  470. else if (componentName === 'SECONDARY_NAMENODE') {
  471. return (App.get('isHadoop2Stack')) ? configs['hdfs-site']['dfs.namenode.checkpoint.dir'] : configs['core-site']['fs.checkpoint.dir'];
  472. }
  473. return '';
  474. },
  475. /**
  476. * save cluster status to server
  477. *
  478. * @param secureConfigs
  479. * @param componentDir
  480. * @return {Boolean}
  481. */
  482. saveClusterStatus: function (secureConfigs, componentDir) {
  483. if (componentDir || secureConfigs.length) {
  484. App.router.get(this.get('content.controllerName')).saveComponentDir(componentDir);
  485. App.router.get(this.get('content.controllerName')).saveSecureConfigs(secureConfigs);
  486. App.clusterStatus.setClusterStatus({
  487. clusterName: this.get('content.cluster.name'),
  488. clusterState: this.get('clusterDeployState'),
  489. wizardControllerName: this.get('content.controllerName'),
  490. localdb: App.db.data
  491. });
  492. return true;
  493. }
  494. return false;
  495. },
  496. onSaveConfigs: function () {
  497. this.set('configsSitesCount', this.get('configsSitesCount') + 1);
  498. if (this.get('configsSitesCount') === this.get('configsSitesNumber')) {
  499. this.onTaskCompleted();
  500. }
  501. },
  502. startZooKeeperServers: function () {
  503. var components = this.get('content.masterComponentHosts').filterProperty('component', 'ZOOKEEPER_SERVER');
  504. this.updateComponent('ZOOKEEPER_SERVER', components.mapProperty('hostName'), "ZOOKEEPER", "Start");
  505. },
  506. startNameNode: function () {
  507. var components = this.get('content.masterComponentHosts').filterProperty('component', 'NAMENODE');
  508. this.updateComponent('NAMENODE', components.mapProperty('hostName').without(this.get('content.reassignHosts.source')), "HDFS", "Start");
  509. },
  510. startServices: function () {
  511. if (this.get('restartYarnMRComponents')) {
  512. var list = App.Service.find().mapProperty("serviceName").without("HDFS").join(',');
  513. var conf = {
  514. name: 'common.services.update',
  515. sender: this,
  516. data: {
  517. "context": "Start without HDFS",
  518. "ServiceInfo": {
  519. "state": "STARTED"
  520. },
  521. urlParams: "ServiceInfo/service_name.in("+list+")"},
  522. success: 'startPolling',
  523. error: 'onTaskError'
  524. };
  525. App.ajax.send(conf);
  526. } else {
  527. App.ajax.send({
  528. name: 'common.services.update',
  529. sender: this,
  530. data: {
  531. "context": "Start all services",
  532. "ServiceInfo": {
  533. "state": "STARTED"
  534. },
  535. urlParams: "params/run_smoke_test=true"
  536. },
  537. success: 'startPolling',
  538. error: 'onTaskError'
  539. });
  540. }
  541. },
  542. deleteHostComponents: function () {
  543. this.set('multiTaskCounter', 0);
  544. var hostComponents = this.get('hostComponents');
  545. var hostName = this.get('content.reassignHosts.source');
  546. for (var i = 0; i < hostComponents.length; i++) {
  547. App.ajax.send({
  548. name: 'common.delete.host_component',
  549. sender: this,
  550. data: {
  551. hostName: hostName,
  552. componentName: hostComponents[i]
  553. },
  554. success: 'onComponentsTasksSuccess',
  555. error: 'onDeleteHostComponentsError'
  556. });
  557. }
  558. },
  559. onDeleteHostComponentsError: function (error) {
  560. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.NoSuchResourceException') !== -1) {
  561. this.onComponentsTasksSuccess();
  562. } else {
  563. this.onTaskError();
  564. }
  565. },
  566. done: function () {
  567. if (!this.get('isSubmitDisabled')) {
  568. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  569. if (this.get('content.hasManualSteps')) {
  570. App.router.send('next');
  571. } else {
  572. App.router.send('complete');
  573. }
  574. }
  575. }
  576. });