step4_controller.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. this.saveClusterStatus(secureConfigs, this.getComponentDir(configs, componentName));
  380. this.saveConfigsToServer(configs);
  381. },
  382. /**
  383. * make PUT call to save configs to server
  384. * @param configs
  385. */
  386. saveConfigsToServer: function (configs) {
  387. for (var site in configs) {
  388. App.ajax.send({
  389. name: 'reassign.save_configs',
  390. sender: this,
  391. data: {
  392. siteName: site,
  393. properties: configs[site]
  394. },
  395. success: 'onSaveConfigs',
  396. error: 'onTaskError'
  397. });
  398. }
  399. },
  400. /**
  401. * set specific configs which applies only to NameNode component
  402. * @param configs
  403. * @param targetHostName
  404. */
  405. setSpecificNamenodeConfigs: function (configs, targetHostName) {
  406. var sourceHostName = this.get('content.reassignHosts.source');
  407. if (App.get('isHadoop2Stack') && App.get('isHaEnabled')) {
  408. var nameServices = configs['hdfs-site']['dfs.nameservices'];
  409. if (configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] === sourceHostName + ':50070') {
  410. configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn1'] = targetHostName + ':50070';
  411. configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn1'] = targetHostName + ':50470';
  412. configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn1'] = targetHostName + ':8020';
  413. } else {
  414. configs['hdfs-site']['dfs.namenode.http-address.' + nameServices + '.nn2'] = targetHostName + ':50070';
  415. configs['hdfs-site']['dfs.namenode.https-address.' + nameServices + '.nn2'] = targetHostName + ':50470';
  416. configs['hdfs-site']['dfs.namenode.rpc-address.' + nameServices + '.nn2'] = targetHostName + ':8020';
  417. }
  418. }
  419. if (!App.get('isHaEnabled') && App.Service.find('HBASE').get('isLoaded')) {
  420. configs['hbase-site']['hbase.rootdir'] = configs['hbase-site']['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + targetHostName + ':8020');
  421. }
  422. },
  423. /**
  424. * set secure configs for component
  425. * @param secureConfigs
  426. * @param configs
  427. * @param componentName
  428. * @return {Boolean}
  429. */
  430. setSecureConfigs: function (secureConfigs, configs, componentName) {
  431. var securityEnabled = this.get('content.securityEnabled');
  432. var component = this.get('secureConfigsMap').findProperty('componentName', componentName);
  433. if (Em.isNone(component) || !securityEnabled) return false;
  434. component.configs.forEach(function (config) {
  435. secureConfigs.push({
  436. keytab: configs[config.site][config.keytab],
  437. principal: configs[config.site][config.principal]
  438. });
  439. });
  440. return true;
  441. },
  442. /**
  443. * derive component directory from configurations
  444. * @param configs
  445. * @param componentName
  446. * @return {String}
  447. */
  448. getComponentDir: function (configs, componentName) {
  449. if (componentName === 'NAMENODE') {
  450. return (App.get('isHadoop2Stack')) ? configs['hdfs-site']['dfs.namenode.name.dir'] : configs['hdfs-site']['dfs.name.dir'];
  451. }
  452. else if (componentName === 'SECONDARY_NAMENODE') {
  453. return (App.get('isHadoop2Stack')) ? configs['hdfs-site']['dfs.namenode.checkpoint.dir'] : configs['core-site']['fs.checkpoint.dir'];
  454. }
  455. return '';
  456. },
  457. /**
  458. * save cluster status to server
  459. *
  460. * @param secureConfigs
  461. * @param componentDir
  462. * @return {Boolean}
  463. */
  464. saveClusterStatus: function (secureConfigs, componentDir) {
  465. if (componentDir || secureConfigs.length) {
  466. App.router.get(this.get('content.controllerName')).saveComponentDir(componentDir);
  467. App.router.get(this.get('content.controllerName')).saveSecureConfigs(secureConfigs);
  468. App.clusterStatus.setClusterStatus({
  469. clusterName: this.get('content.cluster.name'),
  470. clusterState: this.get('clusterDeployState'),
  471. wizardControllerName: this.get('content.controllerName'),
  472. localdb: App.db.data
  473. });
  474. return true;
  475. }
  476. return false;
  477. },
  478. onSaveConfigs: function () {
  479. this.set('configsSitesCount', this.get('configsSitesCount') + 1);
  480. if (this.get('configsSitesCount') === this.get('configsSitesNumber')) {
  481. this.onTaskCompleted();
  482. }
  483. },
  484. startZooKeeperServers: function () {
  485. var components = this.get('content.masterComponentHosts').filterProperty('component', 'ZOOKEEPER_SERVER');
  486. this.updateComponent('ZOOKEEPER_SERVER', components.mapProperty('hostName'), "ZOOKEEPER", "Start");
  487. },
  488. startNameNode: function () {
  489. var components = this.get('content.masterComponentHosts').filterProperty('component', 'NAMENODE');
  490. this.updateComponent('NAMENODE', components.mapProperty('hostName').without(this.get('content.reassignHosts.source')), "HDFS", "Start");
  491. },
  492. startServices: function () {
  493. if (this.get('restartYarnMRComponents')) {
  494. var list = App.Service.find().mapProperty("serviceName").without("HDFS").join(',');
  495. var conf = {
  496. name: 'common.services.update',
  497. sender: this,
  498. data: {
  499. "context": "Start without HDFS",
  500. "ServiceInfo": {
  501. "state": "STARTED"
  502. },
  503. urlParams: "ServiceInfo/service_name.in("+list+")"},
  504. success: 'startPolling',
  505. error: 'onTaskError'
  506. };
  507. App.ajax.send(conf);
  508. } else {
  509. App.ajax.send({
  510. name: 'common.services.update',
  511. sender: this,
  512. data: {
  513. "context": "Start all services",
  514. "ServiceInfo": {
  515. "state": "STARTED"
  516. },
  517. urlParams: "params/run_smoke_test=true"
  518. },
  519. success: 'startPolling',
  520. error: 'onTaskError'
  521. });
  522. }
  523. },
  524. deleteHostComponents: function () {
  525. this.set('multiTaskCounter', 0);
  526. var hostComponents = this.get('hostComponents');
  527. var hostName = this.get('content.reassignHosts.source');
  528. for (var i = 0; i < hostComponents.length; i++) {
  529. App.ajax.send({
  530. name: 'common.delete.host_component',
  531. sender: this,
  532. data: {
  533. hostName: hostName,
  534. componentName: hostComponents[i]
  535. },
  536. success: 'onComponentsTasksSuccess',
  537. error: 'onDeleteHostComponentsError'
  538. });
  539. }
  540. },
  541. onDeleteHostComponentsError: function (error) {
  542. if (error.responseText.indexOf('org.apache.ambari.server.controller.spi.NoSuchResourceException') !== -1) {
  543. this.onComponentsTasksSuccess();
  544. } else {
  545. this.onTaskError();
  546. }
  547. },
  548. done: function () {
  549. if (!this.get('isSubmitDisabled')) {
  550. this.removeObserver('tasks.@each.status', this, 'onTaskStatusChange');
  551. if (this.get('content.hasManualSteps')) {
  552. App.router.send('next');
  553. } else {
  554. App.router.send('complete');
  555. }
  556. }
  557. }
  558. });