controls_view.js 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633
  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 delay = (function(){
  20. var timer = 0;
  21. return function(callback, ms){
  22. clearTimeout (timer);
  23. timer = setTimeout(callback, ms);
  24. };
  25. })();
  26. /**
  27. * Abstract view for config fields.
  28. * Add popover support to control
  29. */
  30. App.ServiceConfigPopoverSupport = Ember.Mixin.create({
  31. /**
  32. * Config object. It will instance of App.ServiceConfigProperty
  33. */
  34. serviceConfig: null,
  35. attributeBindings:['readOnly'],
  36. isPopoverEnabled: true,
  37. popoverPlacement: 'right',
  38. didInsertElement: function () {
  39. $('body').tooltip({
  40. selector: '[data-toggle=tooltip]',
  41. placement: 'top'
  42. });
  43. // if description for this serviceConfig not exist, then no need to show popover
  44. if (this.get('isPopoverEnabled') !== 'false' && this.get('serviceConfig.description')) {
  45. App.popover(this.$(), {
  46. title: Em.I18n.t('installer.controls.serviceConfigPopover.title').format(
  47. this.get('serviceConfig.displayName'),
  48. (this.get('serviceConfig.displayName') == this.get('serviceConfig.name')) ? '' : this.get('serviceConfig.name')
  49. ),
  50. content: this.get('serviceConfig.description'),
  51. placement: this.get('popoverPlacement'),
  52. trigger: 'hover'
  53. });
  54. }
  55. },
  56. willDestroyElement: function() {
  57. this.$().popover('destroy');
  58. },
  59. readOnly: function () {
  60. return !this.get('serviceConfig.isEditable');
  61. }.property('serviceConfig.isEditable')
  62. });
  63. App.SupportsDependentConfigs = Ember.Mixin.create({
  64. /**
  65. * do not apply recommended value if user change value by himself.
  66. */
  67. keyUp: function() {
  68. if (App.get('isClusterSupportsEnhancedConfigs')) {
  69. this.get('controller').removeCurrentFromDependentList(this.get('serviceConfig') || this.get('config'));
  70. }
  71. },
  72. /**
  73. * method send request to check if some of dependent configs was changes
  74. * and in case there was changes shows popup with info about changed configs
  75. *
  76. * @param {App.ServiceConfigProperty} config
  77. * @returns {$.Deferred}
  78. */
  79. sendRequestRorDependentConfigs: function(config) {
  80. if (App.get('isClusterSupportsEnhancedConfigs') && ['mainServiceInfoConfigsController','wizardStep7Controller'].contains(this.get('controller.name'))) {
  81. var name = config.get('name');
  82. var controller = this.get('controller');
  83. var type = App.config.getConfigTagFromFileName(config.get('filename'));
  84. var p = App.StackConfigProperty.find(name + '_' + type);
  85. if (p && p.get('propertyDependedBy.length') > 0) {
  86. return controller.getRecommendationsForDependencies([{
  87. "type": type,
  88. "name": name
  89. }], false, function() {
  90. controller.removeCurrentFromDependentList(config);
  91. });
  92. } else {
  93. controller.removeCurrentFromDependentList(config);
  94. }
  95. }
  96. return $.Deferred().resolve().promise();
  97. },
  98. /**
  99. * Restore values for dependent configs by parent config info.
  100. * NOTE: If dependent config inherited from multiply configs its
  101. * value will be restored only when all parent configs are being restored.
  102. *
  103. * @param {App.ServiceConfigProperty} parentConfig
  104. */
  105. restoreDependentConfigs: function(parentConfig) {
  106. var controller = this.get('controller');
  107. var dependentConfigs = controller.get('_dependentConfigValues');
  108. if (controller._updateDependentConfigs) {
  109. controller._updateDependentConfigs();
  110. controller.set('_dependentConfigValues', dependentConfigs.reject(function(item) {
  111. if (item.parentConfigs.contains(parentConfig.get('name'))) {
  112. if (item.parentConfigs.length > 1) {
  113. item.parentConfigs.removeObject(parentConfig.get('name'));
  114. } else {
  115. return true;
  116. }
  117. }
  118. return false;
  119. }));
  120. }
  121. }
  122. });
  123. /**
  124. * mixin set class that serve as unique element identifier,
  125. * id not used in order to avoid collision with ember ids
  126. */
  127. App.ServiceConfigCalculateId = Ember.Mixin.create({
  128. idClass: Ember.computed(function () {
  129. var config = this.get('config') && this.get('config.widget') ? this.get('config') : this.get('serviceConfig') || {};
  130. var label = Em.get(config, 'name') ? Em.get(config, 'name').toLowerCase().replace(/\./g, '-') : '',
  131. fileName = Em.get(config, 'filename') ? Em.get(config, 'filename').toLowerCase().replace(/\./g, '-') : '',
  132. group = Em.get(config, 'group.name') || 'default',
  133. isOrigin = Em.getWithDefault(config, 'compareConfigs.length', 0) > 0 ? '-origin' : '';
  134. return 'service-config-' + label + '-' + fileName + '-' + group + isOrigin;
  135. }),
  136. classNameBindings: 'idClass'
  137. });
  138. /**
  139. * Default input control
  140. * @type {*}
  141. */
  142. App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  143. valueBinding: 'serviceConfig.value',
  144. classNameBindings: 'textFieldClassName',
  145. placeholderBinding: 'serviceConfig.defaultValue',
  146. keyPress: function (event) {
  147. if (event.keyCode == 13) {
  148. return false;
  149. }
  150. var self = this;
  151. delay(function(){
  152. self.sendRequestRorDependentConfigs(self.get('serviceConfig'));
  153. }, 500);
  154. },
  155. //Set editDone true for last edited config text field parameter
  156. focusOut: function () {
  157. this.sendRequestRorDependentConfigs(this.get('serviceConfig'));
  158. this.get('serviceConfig').set("editDone", true);
  159. },
  160. //Set editDone false for all current category config text field parameter
  161. focusIn: function () {
  162. if (!this.get('serviceConfig.isOverridden') && !this.get('serviceConfig.isComparison')) {
  163. if (this.get('parentView.categoryConfigsAll')) {
  164. this.get("parentView.categoryConfigsAll").setEach("editDone", false);
  165. }
  166. }
  167. },
  168. textFieldClassName: function () {
  169. if (this.get('serviceConfig.unit')) {
  170. return ['input-small'];
  171. } else if (this.get('serviceConfig.displayType') === 'principal') {
  172. return ['span12'];
  173. } else {
  174. return ['span9'];
  175. }
  176. }.property('serviceConfig.displayType', 'serviceConfig.unit')
  177. });
  178. /**
  179. * Customized input control with Units type specified
  180. * @type {Em.View}
  181. */
  182. App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, App.SupportsDependentConfigs, {
  183. valueBinding: 'serviceConfig.value',
  184. classNames: ['input-append', 'with-unit'],
  185. placeholderBinding: 'serviceConfig.defaultValue',
  186. //Set editDone true for last edited config text field parameter
  187. focusOut: function () {
  188. this.sendRequestRorDependentConfigs(this.get('serviceConfig'));
  189. },
  190. keyPress: function (event) {
  191. var self = this;
  192. delay(function(){
  193. self.sendRequestRorDependentConfigs(self.get('serviceConfig'));
  194. }, 500);
  195. },
  196. templateName: require('templates/wizard/controls_service_config_textfield_with_unit')
  197. });
  198. /**
  199. * Password control
  200. * @type {*}
  201. */
  202. App.ServiceConfigPasswordField = Ember.TextField.extend({
  203. serviceConfig: null,
  204. type: 'password',
  205. attributeBindings:['readOnly'],
  206. valueBinding: 'serviceConfig.value',
  207. classNames: [ 'span4' ],
  208. placeholder: Em.I18n.t('form.item.placeholders.typePassword'),
  209. template: Ember.Handlebars.compile('{{view view.retypePasswordView}}'),
  210. keyPress: function (event) {
  211. if (event.keyCode == 13) {
  212. return false;
  213. }
  214. },
  215. retypePasswordView: Ember.TextField.extend({
  216. placeholder: Em.I18n.t('form.passwordRetype'),
  217. attributeBindings:['readOnly'],
  218. type: 'password',
  219. classNames: [ 'span4', 'retyped-password' ],
  220. keyPress: function (event) {
  221. if (event.keyCode == 13) {
  222. return false;
  223. }
  224. },
  225. valueBinding: 'parentView.serviceConfig.retypedPassword',
  226. readOnly: function () {
  227. return !this.get('parentView.serviceConfig.isEditable');
  228. }.property('parentView.serviceConfig.isEditable')
  229. }),
  230. readOnly: function () {
  231. return !this.get('serviceConfig.isEditable');
  232. }.property('serviceConfig.isEditable')
  233. });
  234. /**
  235. * Textarea control
  236. * @type {*}
  237. */
  238. App.ServiceConfigTextArea = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  239. focusOut: function () {
  240. this.sendRequestRorDependentConfigs(this.get('serviceConfig'));
  241. },
  242. keyPress: function (event) {
  243. var self = this;
  244. delay(function(){
  245. self.sendRequestRorDependentConfigs(self.get('serviceConfig'));
  246. }, 500);
  247. },
  248. valueBinding: 'serviceConfig.value',
  249. rows: 4,
  250. classNames: ['directories'],
  251. classNameBindings: ['widthClass'],
  252. widthClass: 'span9'
  253. });
  254. /**
  255. * Textarea control for content type
  256. * @type {*}
  257. */
  258. App.ServiceConfigTextAreaContent = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  259. valueBinding: 'serviceConfig.value',
  260. rows: 20,
  261. classNames: ['span10']
  262. });
  263. /**
  264. * Textarea control with bigger height
  265. * @type {*}
  266. */
  267. App.ServiceConfigBigTextArea = App.ServiceConfigTextArea.extend(App.ServiceConfigCalculateId, {
  268. rows: 10
  269. });
  270. /**
  271. * Checkbox control
  272. * @type {*}
  273. */
  274. App.ServiceConfigCheckbox = Ember.Checkbox.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  275. allowedPairs: {
  276. 'trueFalse': ["true", "false"],
  277. 'YesNo': ["Yes", "No"],
  278. 'YESNO': ["YES", "NO"],
  279. 'yesNo': ["yes", "no"]
  280. },
  281. trueValue: true,
  282. falseValue: false,
  283. checked: false,
  284. /**
  285. * set appropriate config values pair
  286. * to define which value is positive (checked) property
  287. * and what value is negative (unchecked) proeprty
  288. */
  289. didInsertElement: function() {
  290. this._super();
  291. this.addObserver('serviceConfig.value', this, 'toggleChecker');
  292. Object.keys(this.get('allowedPairs')).forEach(function(key) {
  293. if (this.get('allowedPairs')[key].contains(this.get('serviceConfig.value'))) {
  294. this.set('trueValue', this.get('allowedPairs')[key][0]);
  295. this.set('falseValue', this.get('allowedPairs')[key][1]);
  296. }
  297. }, this);
  298. this.set('checked', this.get('serviceConfig.value') === this.get('trueValue'))
  299. },
  300. willDestroyElement: function() {
  301. this.removeObserver('serviceConfig.value', this, 'checkedBinding');
  302. },
  303. /***
  304. * defines if checkbox value appropriate to the config value
  305. * @returns {boolean}
  306. */
  307. isNotAppropriateValue: function() {
  308. return this.get('serviceConfig.value') !== this.get(this.get('checked') + 'Value');
  309. },
  310. /**
  311. * change service config value if click on checkbox
  312. */
  313. toggleValue: function() {
  314. if (this.isNotAppropriateValue()){
  315. this.set('serviceConfig.value', this.get(this.get('checked') + 'Value'));
  316. this.get('serviceConfig').set("editDone", true);
  317. this.sendRequestRorDependentConfigs(this.get('serviceConfig'));
  318. }
  319. }.observes('checked'),
  320. /**
  321. * change checkbox value if click on undo
  322. */
  323. toggleChecker: function() {
  324. if (this.isNotAppropriateValue())
  325. this.set('checked', !this.get('checked'));
  326. },
  327. disabled: function () {
  328. return !this.get('serviceConfig.isEditable');
  329. }.property('serviceConfig.isEditable'),
  330. //Set editDone false for all current category config text field parameter
  331. focusIn: function (event) {
  332. if (!this.get('serviceConfig.isOverridden') && !this.get('serviceConfig.isComparison')) {
  333. this.get("parentView.categoryConfigsAll").setEach("editDone", false);
  334. }
  335. }
  336. });
  337. /**
  338. * Checkbox control which can hide or show dependent properties
  339. * @type {*|void}
  340. */
  341. App.ServiceConfigCheckboxWithDependencies = App.ServiceConfigCheckbox.extend({
  342. toggleDependentConfigs: function() {
  343. if (this.get('serviceConfig.dependentConfigPattern')) {
  344. if (this.get('serviceConfig.dependentConfigPattern') === "CATEGORY") {
  345. this.disableEnableCategoryConfigs();
  346. } else {
  347. this.showHideDependentConfigs();
  348. }
  349. }
  350. }.observes('checked'),
  351. disableEnableCategoryConfigs: function () {
  352. this.get('categoryConfigsAll').setEach('isEditable', this.get('checked'));
  353. this.set('serviceConfig.isEditable', true);
  354. },
  355. showHideDependentConfigs: function () {
  356. this.get('categoryConfigsAll').forEach(function (c) {
  357. if (c.get('name').match(this.get('serviceConfig.dependentConfigPattern')) && c.get('name') != this.get('serviceConfig.name'))
  358. c.set('isVisible', this.get('checked'))
  359. }, this);
  360. }
  361. });
  362. App.ServiceConfigRadioButtons = Ember.View.extend(App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  363. templateName: require('templates/wizard/controls_service_config_radio_buttons'),
  364. didInsertElement: function () {
  365. // on page render, automatically populate JDBC URLs only for default database settings
  366. // so as to not lose the user's customizations on these fields
  367. if (['addServiceController', 'installerController'].contains(this.get('controller.wizardController.name'))) {
  368. if (/^New\s\w+\sDatabase$/.test(this.get('serviceConfig.value')) ||
  369. this.get('dontUseHandleDbConnection').contains(this.get('serviceConfig.name')) ||
  370. this.get('serviceConfig.serviceName') === 'RANGER') {
  371. this.onOptionsChange();
  372. } else {
  373. if (App.get('isHadoopWindowsStack') && /SQL\sauthentication/.test(this.get('serviceConfig.value'))) {
  374. this.onOptionsChange();
  375. }
  376. this.handleDBConnectionProperty();
  377. }
  378. }
  379. },
  380. /**
  381. * properties with these names don'use handleDBConnectionProperty method
  382. */
  383. dontUseHandleDbConnection: function () {
  384. var version = App.get('currentStackVersion').match(/(\d+)[\.,]?(\d+)?/),
  385. majorVersion = version?version[1]: 0,
  386. minorVersion = version? version[2]: 0;
  387. // functionality added in HDP 2.3
  388. // remove DB_FLAVOR so it can handle DB Connection checks
  389. if (App.get('currentStackName') == 'HDP' && majorVersion >= 2 && minorVersion>= 3) {
  390. return ['authentication_method'];
  391. }
  392. return ['DB_FLAVOR', 'authentication_method'];
  393. }.property(),
  394. configs: function () {
  395. if (this.get('controller.name') == 'mainServiceInfoConfigsController') return this.get('categoryConfigsAll');
  396. return this.get('categoryConfigsAll').filterProperty('isObserved', true);
  397. }.property('categoryConfigsAll'),
  398. serviceConfig: null,
  399. categoryConfigsAll: null,
  400. onOptionsChange: function () {
  401. // The following if condition will be satisfied only for installer wizard flow
  402. if (this.get('configs').length) {
  403. var connectionUrl = this.get('connectionUrl');
  404. if (connectionUrl) {
  405. var dbClass = this.get('dbClass');
  406. var hostName = this.get('hostName');
  407. var databaseName = this.get('databaseName');
  408. var hostNameDefault;
  409. var databaseNameDefault;
  410. var connectionUrlValue = connectionUrl.get('value');
  411. var connectionUrlDefaultValue = connectionUrl.get('defaultValue');
  412. var dbClassValue = dbClass.get('value');
  413. var serviceName = this.get('serviceConfig.serviceName');
  414. var isServiceInstalled = App.Service.find().someProperty('serviceName', serviceName);
  415. var postgresUrl = 'jdbc:postgresql://{0}:5432/{1}';
  416. var oracleUrl = 'jdbc:oracle:thin:@//{0}:1521/{1}';
  417. var mssqlUrl = 'jdbc:sqlserver://{0};databaseName={1}';
  418. var mssqlIntegratedAuthUrl = 'jdbc:sqlserver://{0};databaseName={1};integratedSecurity=true';
  419. var isNotExistingMySQLServer = this.get('serviceConfig.value') !== 'Existing MSSQL Server database with integrated authentication';
  420. var categoryConfigsAll = this.get('categoryConfigsAll');
  421. if (isServiceInstalled) {
  422. hostNameDefault = this.get('hostNameProperty.defaultValue');
  423. databaseNameDefault = this.get('databaseNameProperty.defaultValue');
  424. } else {
  425. hostNameDefault = hostName;
  426. databaseNameDefault = databaseName;
  427. }
  428. switch (serviceName) {
  429. case 'HIVE':
  430. var hiveDbType = this.get('parentView.serviceConfigs').findProperty('name', 'hive_database_type');
  431. var mysqlUrl = 'jdbc:mysql://{0}/{1}?createDatabaseIfNotExist=true';
  432. switch (this.get('serviceConfig.value')) {
  433. case 'New MySQL Database':
  434. case 'Existing MySQL Database':
  435. connectionUrlValue = mysqlUrl.format(hostName, databaseName);
  436. connectionUrlDefaultValue = mysqlUrl.format(hostNameDefault, databaseNameDefault);
  437. dbClassValue = 'com.mysql.jdbc.Driver';
  438. Em.set(hiveDbType, 'value', 'mysql');
  439. break;
  440. case Em.I18n.t('services.service.config.hive.oozie.postgresql'):
  441. connectionUrlValue = postgresUrl.format(hostName, databaseName);
  442. connectionUrlDefaultValue = postgresUrl.format(hostNameDefault, databaseNameDefault);
  443. dbClassValue = 'org.postgresql.Driver';
  444. Em.set(hiveDbType, 'value', 'postgres');
  445. break;
  446. case 'Existing Oracle Database':
  447. connectionUrlValue = oracleUrl.format(hostName, databaseName);
  448. connectionUrlDefaultValue = oracleUrl.format(hostNameDefault, databaseNameDefault);
  449. dbClassValue = 'oracle.jdbc.driver.OracleDriver';
  450. Em.set(hiveDbType, 'value', 'oracle');
  451. break;
  452. case 'Existing MSSQL Server database with SQL authentication':
  453. connectionUrlValue = mssqlUrl.format(hostName, databaseName);
  454. connectionUrlDefaultValue = mssqlUrl.format(hostNameDefault, databaseNameDefault);
  455. dbClassValue = 'com.microsoft.sqlserver.jdbc.SQLServerDriver';
  456. Em.set(hiveDbType, 'value', 'mssql');
  457. break;
  458. case 'Existing MSSQL Server database with integrated authentication':
  459. connectionUrlValue = mssqlIntegratedAuthUrl.format(hostName, databaseName);
  460. connectionUrlDefaultValue = mssqlIntegratedAuthUrl.format(hostNameDefault, databaseNameDefault);
  461. dbClassValue = 'com.microsoft.sqlserver.jdbc.SQLServerDriver';
  462. Em.set(hiveDbType, 'value', 'mssql');
  463. break;
  464. }
  465. categoryConfigsAll.findProperty('name', 'javax.jdo.option.ConnectionUserName').setProperties({
  466. isVisible: isNotExistingMySQLServer,
  467. isRequired: isNotExistingMySQLServer
  468. });
  469. categoryConfigsAll.findProperty('name', 'javax.jdo.option.ConnectionPassword').setProperties({
  470. isVisible: isNotExistingMySQLServer,
  471. isRequired: isNotExistingMySQLServer
  472. });
  473. break;
  474. case 'OOZIE':
  475. var derbyUrl = 'jdbc:derby:${oozie.data.dir}/${oozie.db.schema.name}-db;create=true';
  476. var mysqlUrl = 'jdbc:mysql://{0}/{1}';
  477. switch (this.get('serviceConfig.value')) {
  478. case 'New Derby Database':
  479. connectionUrlValue = derbyUrl;
  480. connectionUrlDefaultValue = derbyUrl;
  481. dbClassValue = 'org.apache.derby.jdbc.EmbeddedDriver';
  482. break;
  483. case 'Existing MySQL Database':
  484. connectionUrlValue = mysqlUrl.format(hostName, databaseName);
  485. connectionUrlDefaultValue = mysqlUrl.format(hostNameDefault, databaseNameDefault);
  486. dbClassValue = 'com.mysql.jdbc.Driver';
  487. break;
  488. case Em.I18n.t('services.service.config.hive.oozie.postgresql'):
  489. connectionUrlValue = postgresUrl.format(hostName, databaseName);
  490. connectionUrlDefaultValue = postgresUrl.format(hostNameDefault, databaseNameDefault);
  491. dbClassValue = 'org.postgresql.Driver';
  492. break;
  493. case 'Existing Oracle Database':
  494. connectionUrlValue = oracleUrl.format(hostName, databaseName);
  495. connectionUrlDefaultValue = oracleUrl.format(hostNameDefault, databaseNameDefault);
  496. dbClassValue = 'oracle.jdbc.driver.OracleDriver';
  497. break;
  498. case 'Existing MSSQL Server database with SQL authentication':
  499. connectionUrlValue = mssqlUrl.format(hostName, databaseName);
  500. connectionUrlDefaultValue = mssqlUrl.format(hostNameDefault, databaseNameDefault);
  501. dbClassValue = 'com.microsoft.sqlserver.jdbc.SQLServerDriver';
  502. break;
  503. case 'Existing MSSQL Server database with integrated authentication':
  504. connectionUrlValue = mssqlIntegratedAuthUrl.format(hostName, databaseName);
  505. connectionUrlDefaultValue = mssqlIntegratedAuthUrl.format(hostNameDefault, databaseNameDefault);
  506. dbClassValue = 'com.microsoft.sqlserver.jdbc.SQLServerDriver';
  507. break;
  508. }
  509. categoryConfigsAll.findProperty('name', 'oozie.service.JPAService.jdbc.username').setProperties({
  510. isVisible: isNotExistingMySQLServer,
  511. isRequired: isNotExistingMySQLServer
  512. });
  513. categoryConfigsAll.findProperty('name', 'oozie.service.JPAService.jdbc.password').setProperties({
  514. isVisible: isNotExistingMySQLServer,
  515. isRequired: isNotExistingMySQLServer
  516. });
  517. break;
  518. case 'RANGER':
  519. var mysqlUrl = 'jdbc:mysql://{0}/{1}',
  520. sqlCommand = 'mysql',
  521. sqlConnectorJARValue = '/usr/share/java/mysql-connector-java.jar',
  522. sqlCommandInvoker = categoryConfigsAll.findProperty('name','SQL_COMMAND_INVOKER'),
  523. sqlConnectorJAR = this.get('parentView.serviceConfigs').findProperty('name', 'SQL_CONNECTOR_JAR'),
  524. dbFlavor = this.get('serviceConfig.value'),
  525. databasesTypes = /MYSQL|POSTGRES|ORACLE|MSSQL/gi,
  526. currentDBFlavor = dbFlavor.match(databasesTypes).length?dbFlavor.match(databasesTypes)[0]:'';
  527. switch (currentDBFlavor.toUpperCase()) {
  528. case 'ORACLE':
  529. connectionUrlValue = oracleUrl.format(hostName, databaseName);
  530. connectionUrlDefaultValue = oracleUrl.format(hostNameDefault, databaseNameDefault);
  531. dbClassValue = 'oracle.jdbc.driver.OracleDriver';
  532. sqlCommand = 'sqlplus';
  533. sqlConnectorJARValue = '/usr/share/java/ojdbc6.jar';
  534. break;
  535. case 'MYSQL':
  536. connectionUrlValue = mysqlUrl.format(hostName, databaseName);
  537. connectionUrlDefaultValue = mysqlUrl.format(hostNameDefault, databaseNameDefault);
  538. dbClassValue = 'com.mysql.jdbc.Driver';
  539. sqlConnectorJARValue = '/usr/share/java/mysql-connector-java.jar';
  540. break;
  541. case 'POSTGRES':
  542. connectionUrlValue = postgresUrl.format(hostName, databaseName);
  543. connectionUrlDefaultValue = postgresUrl.format(hostNameDefault, databaseNameDefault);
  544. dbClassValue = 'org.postgresql.Driver';
  545. sqlCommand = 'psql';
  546. sqlConnectorJARValue = '/usr/share/java/postgresql.jar';
  547. break;
  548. case 'MSSQL':
  549. connectionUrlValue = mssqlUrl.format(hostName, databaseName);
  550. connectionUrlDefaultValue = mssqlUrl.format(hostNameDefault, databaseNameDefault);
  551. dbClassValue = 'com.microsoft.sqlserver.jdbc.SQLServerDriver';
  552. sqlCommand = 'sqlcmd';
  553. sqlConnectorJARValue = '/usr/share/java/sqljdbc4.jar';
  554. break;
  555. }
  556. this.get('categoryConfigsAll').findProperty('name', 'db_host').set('value', this.get('hostNameProperty.value'));
  557. sqlConnectorJAR.set('value',sqlConnectorJARValue);
  558. sqlConnectorJAR.set('defaultValue',sqlConnectorJARValue);
  559. sqlCommandInvoker.set('value', sqlCommand);
  560. break;
  561. }
  562. connectionUrl.set('value', connectionUrlValue);
  563. connectionUrl.set('defaultValue', connectionUrlDefaultValue);
  564. dbClass.set('value', dbClassValue);
  565. }
  566. }
  567. }.observes('databaseName', 'hostName'),
  568. nameBinding: 'serviceConfig.radioName',
  569. databaseNameProperty: function () {
  570. var databaseNameConfig = {
  571. 'HIVE': 'ambari.hive.db.schema.name',
  572. 'OOZIE':'oozie.db.schema.name',
  573. 'RANGER': 'db_name'
  574. };
  575. return Object.keys(databaseNameConfig).contains(this.get('serviceConfig.serviceName'))?
  576. this.get('categoryConfigsAll').findProperty('name', databaseNameConfig[this.get('serviceConfig.serviceName')]):
  577. null;
  578. }.property('serviceConfig.serviceName'),
  579. databaseName: function () {
  580. return this.get('databaseNameProperty.value');
  581. }.property('databaseNameProperty.value'),
  582. hostNameProperty: function () {
  583. var value = this.get('serviceConfig.value');
  584. var returnValue;
  585. var hostname;
  586. if (this.get('serviceConfig.serviceName') === 'HIVE') {
  587. switch (value) {
  588. case 'New MySQL Database':
  589. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_ambari_host');
  590. break;
  591. case 'Existing MySQL Database':
  592. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_mysql_host');
  593. break;
  594. case Em.I18n.t('services.service.config.hive.oozie.postgresql'):
  595. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_postgresql_host');
  596. break;
  597. case 'Existing Oracle Database':
  598. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_oracle_host');
  599. break;
  600. case 'Existing MSSQL Server database with SQL authentication':
  601. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_mssql_server_host');
  602. break;
  603. case 'Existing MSSQL Server database with integrated authentication':
  604. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_mssql_server_2_host');
  605. break;
  606. }
  607. if (hostname) {
  608. Em.set(hostname, 'isUserProperty', false);
  609. returnValue = hostname;
  610. } else {
  611. returnValue = this.get('categoryConfigsAll').findProperty('name', 'hive_hostname');
  612. }
  613. } else if (this.get('serviceConfig.serviceName') === 'OOZIE') {
  614. switch (value) {
  615. case 'New Derby Database':
  616. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_ambari_host');
  617. break;
  618. case 'Existing MySQL Database':
  619. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_mysql_host');
  620. break;
  621. case Em.I18n.t('services.service.config.hive.oozie.postgresql'):
  622. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_postgresql_host');
  623. break;
  624. case 'Existing Oracle Database':
  625. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_oracle_host');
  626. break;
  627. case 'Existing MSSQL Server database with SQL authentication':
  628. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_mssql_server_host');
  629. break;
  630. case 'Existing MSSQL Server database with integrated authentication':
  631. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_mssql_server_2_host');
  632. break;
  633. }
  634. if (hostname) {
  635. Em.set(hostname, 'isUserProperty', false);
  636. returnValue = hostname;
  637. } else {
  638. returnValue = this.get('categoryConfigsAll').findProperty('name', 'oozie_hostname');
  639. }
  640. } else if (this.get('serviceConfig.serviceName') === 'RANGER') {
  641. if (value) {
  642. var databasesTypes = /MYSQL|POSTGRES|ORACLE|MSSQL/gi,
  643. currentDBFlavor = value.match(databasesTypes),
  644. dbHost = this.get('categoryConfigsAll').findProperty('name', 'db_host'),
  645. hostnameConfig = {
  646. 'MYSQL': 'ranger_mysql_host',
  647. 'ORACLE': 'ranger_oracle_host',
  648. 'POSTGRES': 'ranger_postgres_host',
  649. 'MSSQL': 'ranger_mssql_host'
  650. };
  651. if (currentDBFlavor) {
  652. hostname = this.get('categoryConfigsAll').findProperty('name', hostnameConfig[currentDBFlavor[0].toUpperCase()]);
  653. }
  654. if (hostname) {
  655. if (!hostname.value) {
  656. hostname.set('value', this.get('categoryConfigsAll').findProperty('name', 'db_host').get('value'));
  657. }
  658. Em.set(hostname, 'isUserProperty', false);
  659. if (dbHost) {
  660. dbHost.set('value', hostname.value);
  661. }
  662. returnValue = hostname;
  663. } else {
  664. returnValue = this.get('categoryConfigsAll').findProperty('name', 'db_host');
  665. }
  666. }
  667. }
  668. return returnValue;
  669. }.property('serviceConfig.serviceName', 'serviceConfig.value'),
  670. hostName: function () {
  671. return this.get('hostNameProperty.value');
  672. }.property('hostNameProperty.value'),
  673. connectionUrl: function () {
  674. var connectionUrlConfig = {
  675. 'HIVE': 'javax.jdo.option.ConnectionURL',
  676. 'OOZIE':'oozie.service.JPAService.jdbc.url',
  677. 'RANGER': 'ranger_jdbc_connection_url'
  678. };
  679. return this.get('categoryConfigsAll').findProperty('name', connectionUrlConfig[this.get('serviceConfig.serviceName')]);
  680. }.property('serviceConfig.serviceName'),
  681. dbClass: function () {
  682. var dbClassConfig = {
  683. 'HIVE': 'javax.jdo.option.ConnectionDriverName',
  684. 'OOZIE':'oozie.service.JPAService.jdbc.driver',
  685. 'RANGER': 'ranger_jdbc_driver'
  686. };
  687. return this.get('categoryConfigsAll').findProperty('name', dbClassConfig[this.get('serviceConfig.serviceName')]);
  688. }.property('serviceConfig.serviceName'),
  689. /**
  690. * `Observer` that add <code>additionalView</code> to <code>App.ServiceConfigProperty</code>
  691. * that responsible for (if existing db selected)
  692. * 1. checking database connection
  693. * 2. showing jdbc driver setup warning msg.
  694. *
  695. * @method handleDBConnectionProperty
  696. **/
  697. handleDBConnectionProperty: function() {
  698. if (this.get('dontUseHandleDbConnection').contains(this.get('serviceConfig.name'))) {
  699. return;
  700. }
  701. var handledProperties = ['oozie_database', 'hive_database', 'DB_FLAVOR'];
  702. var currentValue = this.get('serviceConfig.value');
  703. var databases = /MySQL|PostgreSQL|Postgres|Oracle|Derby|MSSQL/gi;
  704. var currentDB = currentValue.match(databases)[0];
  705. var databasesTypes = /MySQL|Postgres|Oracle|Derby|MSSQL/gi;
  706. var currentDBType = currentValue.match(databasesTypes)[0];
  707. var checkDatabase = /existing/gi.test(currentValue);
  708. // db connection check button show up if existed db selected
  709. var propertyAppendTo1 = this.get('categoryConfigsAll').findProperty('displayName', 'Database URL');
  710. // warning msg under database type radio buttons, to warn the user to setup jdbc driver if existed db selected
  711. var propertyHive = this.get('categoryConfigsAll').findProperty('displayName', 'Hive Database');
  712. var propertyOozie = this.get('categoryConfigsAll').findProperty('displayName', 'Oozie Database');
  713. var propertyAppendTo2 = propertyHive ? propertyHive : propertyOozie;
  714. // RANGER specific
  715. if (this.get('serviceConfig.serviceName') === 'RANGER') {
  716. propertyAppendTo1 = this.get('categoryConfigsAll').findProperty('name', 'db_name');
  717. propertyAppendTo2 = this.get('categoryConfigsAll').findProperty('name', 'DB_FLAVOR');
  718. // check for all db types when installing Ranger - not only for existing ones
  719. checkDatabase = true;
  720. }
  721. propertyAppendTo1.set('additionalView', null);
  722. propertyAppendTo2.set('additionalView', null);
  723. if (currentDB && checkDatabase) {
  724. if (handledProperties.contains(this.get('serviceConfig.name'))) {
  725. if (propertyAppendTo1) {
  726. propertyAppendTo1.set('additionalView', App.CheckDBConnectionView.extend({databaseName: currentDB}));
  727. }
  728. if (propertyAppendTo2) {
  729. propertyAppendTo2.set('additionalView', Ember.View.extend({
  730. template: Ember.Handlebars.compile('<div class="alert">{{{view.message}}}</div>'),
  731. message: Em.I18n.t('services.service.config.database.msg.jdbcSetup').format(currentDBType.toLowerCase(), currentDBType.toLowerCase())
  732. }));
  733. }
  734. }
  735. } else {
  736. propertyAppendTo1.set('additionalView', null);
  737. propertyAppendTo2.set('additionalView', null);
  738. }
  739. }.observes('serviceConfig.value'),
  740. optionsBinding: 'serviceConfig.options'
  741. });
  742. App.ServiceConfigRadioButton = Ember.Checkbox.extend({
  743. tagName: 'input',
  744. attributeBindings: ['type', 'name', 'value', 'checked', 'disabled'],
  745. checked: false,
  746. type: 'radio',
  747. name: null,
  748. value: null,
  749. didInsertElement: function () {
  750. console.debug('App.ServiceConfigRadioButton.didInsertElement');
  751. if (this.get('parentView.serviceConfig.value') === this.get('value')) {
  752. console.debug(this.get('name') + ":" + this.get('value') + ' is checked');
  753. this.set('checked', true);
  754. }
  755. },
  756. click: function () {
  757. this.set('checked', true);
  758. console.debug('App.ServiceConfigRadioButton.click');
  759. this.onChecked();
  760. },
  761. onChecked: function () {
  762. // Wrapping the call with Ember.run.next prevents a problem where setting isVisible on component
  763. // causes JS error due to re-rendering. For example, this occurs when switching the Config Group
  764. // in Service Config page
  765. Em.run.next(this, function() {
  766. console.debug('App.ServiceConfigRadioButton.onChecked');
  767. this.set('parentView.serviceConfig.value', this.get('value'));
  768. var components = this.get('parentView.serviceConfig.options');
  769. if (components) {
  770. components.forEach(function (_component) {
  771. if (_component.foreignKeys) {
  772. _component.foreignKeys.forEach(function (_componentName) {
  773. if (this.get('parentView.parentView.serviceConfigs') && this.get('parentView.parentView.serviceConfigs').someProperty('name', _componentName)) {
  774. var component = this.get('parentView.parentView.serviceConfigs').findProperty('name', _componentName);
  775. component.set('isVisible', _component.displayName === this.get('value'));
  776. }
  777. }, this);
  778. }
  779. }, this);
  780. }
  781. });
  782. }.observes('checked'),
  783. disabled: function () {
  784. return !this.get('parentView.serviceConfig.isEditable') ||
  785. !['addServiceController', 'installerController'].contains(this.get('controller.wizardController.name')) && /^New\s\w+\sDatabase$/.test(this.get('value'));
  786. }.property('parentView.serviceConfig.isEditable')
  787. });
  788. App.ServiceConfigComboBox = Ember.Select.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, {
  789. contentBinding: 'serviceConfig.options',
  790. selectionBinding: 'serviceConfig.value',
  791. placeholderBinding: 'serviceConfig.defaultValue',
  792. classNames: [ 'span3' ]
  793. });
  794. /**
  795. * Base component for host config with popover support
  796. */
  797. App.ServiceConfigHostPopoverSupport = Ember.Mixin.create({
  798. /**
  799. * Config object. It will instance of App.ServiceConfigProperty
  800. */
  801. serviceConfig: null,
  802. didInsertElement: function () {
  803. App.popover(this.$(), {
  804. title: this.get('serviceConfig.displayName'),
  805. content: this.get('serviceConfig.description'),
  806. placement: 'right',
  807. trigger: 'hover'
  808. });
  809. }
  810. });
  811. /**
  812. * Master host component.
  813. * Show hostname without ability to edit it
  814. * @type {*}
  815. */
  816. App.ServiceConfigMasterHostView = Ember.View.extend(App.ServiceConfigHostPopoverSupport, App.ServiceConfigCalculateId, {
  817. classNames: ['master-host', 'span6'],
  818. valueBinding: 'serviceConfig.value',
  819. template: Ember.Handlebars.compile('{{value}}')
  820. });
  821. /**
  822. * text field property view that enables possibility
  823. * for check connection
  824. * @type {*}
  825. */
  826. App.checkConnectionView = App.ServiceConfigTextField.extend({
  827. didInsertElement: function() {
  828. this._super();
  829. var kdc = this.get('categoryConfigsAll').findProperty('name', 'kdc_type');
  830. var propertyAppendTo = this.get('categoryConfigsAll').findProperty('name', 'domains');
  831. if (propertyAppendTo) propertyAppendTo.set('additionalView', App.CheckDBConnectionView.extend({databaseName: kdc && kdc.get('value')}));
  832. }
  833. });
  834. /**
  835. * Show value as plain label in italics
  836. * @type {*}
  837. */
  838. App.ServiceConfigLabelView = Ember.View.extend(App.ServiceConfigHostPopoverSupport, App.ServiceConfigCalculateId, {
  839. classNames: ['master-host', 'span6'],
  840. valueBinding: 'serviceConfig.value',
  841. template: Ember.Handlebars.compile('<i>{{view.value}}</i>')
  842. });
  843. /**
  844. * Base component to display Multiple hosts
  845. * @type {*}
  846. */
  847. App.ServiceConfigMultipleHostsDisplay = Ember.Mixin.create(App.ServiceConfigHostPopoverSupport, App.ServiceConfigCalculateId, {
  848. hasNoHosts: function () {
  849. console.log('view', this.get('viewName')); //to know which View cause errors
  850. console.log('controller', this.get('controller').name); //should be slaveComponentGroupsController
  851. if (!this.get('value')) {
  852. return true;
  853. }
  854. return this.get('value').length === 0;
  855. }.property('value'),
  856. hasOneHost: function () {
  857. return this.get('value').length === 1;
  858. }.property('value'),
  859. hasMultipleHosts: function () {
  860. return this.get('value').length > 1;
  861. }.property('value'),
  862. otherLength: function () {
  863. var len = this.get('value').length;
  864. if (len > 2) {
  865. return Em.I18n.t('installer.controls.serviceConfigMultipleHosts.others').format(len - 1);
  866. } else {
  867. return Em.I18n.t('installer.controls.serviceConfigMultipleHosts.other');
  868. }
  869. }.property('value')
  870. });
  871. /**
  872. * Multiple master host component.
  873. * Show hostnames without ability to edit it
  874. * @type {*}
  875. */
  876. App.ServiceConfigMasterHostsView = Ember.View.extend(App.ServiceConfigMultipleHostsDisplay, App.ServiceConfigCalculateId, {
  877. viewName: "serviceConfigMasterHostsView",
  878. valueBinding: 'serviceConfig.value',
  879. classNames: ['master-hosts', 'span6'],
  880. templateName: require('templates/wizard/master_hosts'),
  881. /**
  882. * Onclick handler for link
  883. */
  884. showHosts: function () {
  885. var serviceConfig = this.get('serviceConfig');
  886. App.ModalPopup.show({
  887. header: Em.I18n.t('installer.controls.serviceConfigMasterHosts.header').format(serviceConfig.category),
  888. bodyClass: Ember.View.extend({
  889. serviceConfig: serviceConfig,
  890. templateName: require('templates/wizard/master_hosts_popup')
  891. }),
  892. secondary: null
  893. });
  894. }
  895. });
  896. /**
  897. * Show tabs list for slave hosts
  898. * @type {*}
  899. */
  900. App.SlaveComponentGroupsMenu = Em.CollectionView.extend(App.ServiceConfigCalculateId, {
  901. content: function () {
  902. return this.get('controller.componentGroups');
  903. }.property('controller.componentGroups'),
  904. tagName: 'ul',
  905. classNames: ["nav", "nav-tabs"],
  906. itemViewClass: Em.View.extend({
  907. classNameBindings: ["active"],
  908. active: function () {
  909. return this.get('content.active');
  910. }.property('content.active'),
  911. errorCount: function () {
  912. return this.get('content.properties').filterProperty('isValid', false).filterProperty('isVisible', true).get('length');
  913. }.property('content.properties.@each.isValid', 'content.properties.@each.isVisible'),
  914. templateName: require('templates/wizard/controls_slave_component_groups_menu')
  915. })
  916. });
  917. /**
  918. * <code>Add group</code> button
  919. * @type {*}
  920. */
  921. App.AddSlaveComponentGroupButton = Ember.View.extend(App.ServiceConfigCalculateId, {
  922. tagName: 'span',
  923. slaveComponentName: null,
  924. didInsertElement: function () {
  925. App.popover(this.$(), {
  926. title: Em.I18n.t('installer.controls.addSlaveComponentGroupButton.title').format(this.get('slaveComponentName')),
  927. content: Em.I18n.t('installer.controls.addSlaveComponentGroupButton.content').format(this.get('slaveComponentName'), this.get('slaveComponentName'), this.get('slaveComponentName')),
  928. placement: 'right',
  929. trigger: 'hover'
  930. });
  931. }
  932. });
  933. /**
  934. * Multiple Slave Hosts component
  935. * @type {*}
  936. */
  937. App.ServiceConfigSlaveHostsView = Ember.View.extend(App.ServiceConfigMultipleHostsDisplay, App.ServiceConfigCalculateId, {
  938. viewName: 'serviceConfigSlaveHostsView',
  939. classNames: ['slave-hosts', 'span6'],
  940. valueBinding: 'serviceConfig.value',
  941. templateName: require('templates/wizard/slave_hosts'),
  942. /**
  943. * Onclick handler for link
  944. */
  945. showHosts: function () {
  946. var serviceConfig = this.get('serviceConfig');
  947. App.ModalPopup.show({
  948. header: Em.I18n.t('installer.controls.serviceConfigMasterHosts.header').format(serviceConfig.category),
  949. bodyClass: Ember.View.extend({
  950. serviceConfig: serviceConfig,
  951. templateName: require('templates/wizard/master_hosts_popup')
  952. }),
  953. secondary: null
  954. });
  955. }
  956. });
  957. /**
  958. * properties for present active slave group
  959. * @type {*}
  960. */
  961. App.SlaveGroupPropertiesView = Ember.View.extend(App.ServiceConfigCalculateId, {
  962. viewName: 'serviceConfigSlaveHostsView',
  963. group: function () {
  964. return this.get('controller.activeGroup');
  965. }.property('controller.activeGroup'),
  966. groupConfigs: function () {
  967. console.log("************************************************************************");
  968. console.log("The value of group is: " + this.get('group'));
  969. console.log("************************************************************************");
  970. return this.get('group.properties');
  971. }.property('group.properties.@each').cacheable(),
  972. errorCount: function () {
  973. return this.get('group.properties').filterProperty('isValid', false).filterProperty('isVisible', true).get('length');
  974. }.property('configs.@each.isValid', 'configs.@each.isVisible')
  975. });
  976. /**
  977. * DropDown component for <code>select hosts for groups</code> popup
  978. * @type {*}
  979. */
  980. App.SlaveComponentDropDownGroupView = Ember.View.extend(App.ServiceConfigCalculateId, {
  981. viewName: "slaveComponentDropDownGroupView",
  982. /**
  983. * On change handler for <code>select hosts for groups</code> popup
  984. * @param event
  985. */
  986. changeGroup: function (event) {
  987. var host = this.get('content');
  988. var groupName = $('#' + this.get('elementId') + ' select').val();
  989. this.get('controller').changeHostGroup(host, groupName);
  990. },
  991. optionTag: Ember.View.extend({
  992. /**
  993. * Whether current value(OptionTag value) equals to host value(assigned to SlaveComponentDropDownGroupView.content)
  994. */
  995. selected: function () {
  996. return this.get('parentView.content.group') === this.get('content');
  997. }.property('content')
  998. })
  999. });
  1000. /**
  1001. * Show info about current group
  1002. * @type {*}
  1003. */
  1004. App.SlaveComponentChangeGroupNameView = Ember.View.extend(App.ServiceConfigCalculateId, {
  1005. contentBinding: 'controller.activeGroup',
  1006. classNames: ['control-group'],
  1007. classNameBindings: 'error',
  1008. error: false,
  1009. setError: function () {
  1010. this.set('error', false);
  1011. }.observes('controller.activeGroup'),
  1012. errorMessage: function () {
  1013. return this.get('error') ? Em.I18n.t('installer.controls.slaveComponentChangeGroupName.error') : '';
  1014. }.property('error'),
  1015. /**
  1016. * Onclick handler for saving updated group name
  1017. * @param event
  1018. */
  1019. changeGroupName: function (event) {
  1020. var inputVal = $('#' + this.get('elementId') + ' input[type="text"]').val();
  1021. if (inputVal !== this.get('content.name')) {
  1022. var result = this.get('controller').changeSlaveGroupName(this.get('content'), inputVal);
  1023. this.set('error', result);
  1024. }
  1025. }
  1026. });
  1027. /**
  1028. * View for testing connection to database.
  1029. **/
  1030. App.CheckDBConnectionView = Ember.View.extend({
  1031. templateName: require('templates/common/form/check_db_connection'),
  1032. /** @property {string} btnCaption - text for button **/
  1033. btnCaption: function() {
  1034. return this.get('parentView.service.serviceName') === 'KERBEROS'
  1035. ? Em.I18n.t('services.service.config.kdc.btn.idle')
  1036. : Em.I18n.t('services.service.config.database.btn.idle')
  1037. }.property('parentView.service.serviceName'),
  1038. /** @property {string} responseCaption - text for status link **/
  1039. responseCaption: null,
  1040. /** @property {boolean} isConnecting - is request to server activated **/
  1041. isConnecting: false,
  1042. /** @property {boolean} isValidationPassed - check validation for required fields **/
  1043. isValidationPassed: null,
  1044. /** @property {string} databaseName- name of current database **/
  1045. databaseName: null,
  1046. /** @property {boolean} isRequestResolved - check for finished request to server **/
  1047. isRequestResolved: false,
  1048. /** @property {boolean} isConnectionSuccess - check for successful connection to database **/
  1049. isConnectionSuccess: null,
  1050. /** @property {string} responseFromServer - message from server response **/
  1051. responseFromServer: null,
  1052. /** @property {Object} ambariRequiredProperties - properties that need for custom action request **/
  1053. ambariRequiredProperties: null,
  1054. /** @property {Number} currentRequestId - current custom action request id **/
  1055. currentRequestId: null,
  1056. /** @property {Number} currentTaskId - current custom action task id **/
  1057. currentTaskId: null,
  1058. /** @property {jQuery.Deferred} request - current $.ajax request **/
  1059. request: null,
  1060. /** @property {Number} pollInterval - timeout interval for ajax polling **/
  1061. pollInterval: 3000,
  1062. /** @property {string} hostNameProperty - host name property based on service and database names **/
  1063. hostNameProperty: function() {
  1064. if (!/wizard/i.test(this.get('controller.name')) && this.get('parentView.service.serviceName') === 'HIVE') {
  1065. return this.get('parentView.service.serviceName').toLowerCase() + '_hostname';
  1066. } else if (this.get('parentView.service.serviceName') === 'KERBEROS') {
  1067. return 'kdc_host';
  1068. } else if (this.get('parentView.service.serviceName') === 'RANGER') {
  1069. return '{0}_{1}_host'.format(this.get('parentView.service.serviceName').toLowerCase(), this.get('databaseName').toLowerCase());
  1070. }
  1071. return '{0}_existing_{1}_host'.format(this.get('parentView.service.serviceName').toLowerCase(), this.get('databaseName').toLowerCase());
  1072. }.property('databaseName'),
  1073. /** @property {boolean} isBtnDisabled - disable button on failed validation or active request **/
  1074. isBtnDisabled: function() {
  1075. return !this.get('isValidationPassed') || this.get('isConnecting');
  1076. }.property('isValidationPassed', 'isConnecting'),
  1077. /** @property {object} requiredProperties - properties that necessary for database connection **/
  1078. requiredProperties: function() {
  1079. var propertiesMap = {
  1080. OOZIE: ['oozie.db.schema.name', 'oozie.service.JPAService.jdbc.username', 'oozie.service.JPAService.jdbc.password', 'oozie.service.JPAService.jdbc.driver', 'oozie.service.JPAService.jdbc.url'],
  1081. HIVE: ['ambari.hive.db.schema.name', 'javax.jdo.option.ConnectionUserName', 'javax.jdo.option.ConnectionPassword', 'javax.jdo.option.ConnectionDriverName', 'javax.jdo.option.ConnectionURL'],
  1082. KERBEROS: ['kdc_host'],
  1083. RANGER: ['db_root_user', 'db_root_password', 'db_name', 'ranger_jdbc_connection_url', 'ranger_jdbc_driver']
  1084. };
  1085. return propertiesMap[this.get('parentView.service.serviceName')];
  1086. }.property(),
  1087. /** @property {Object} propertiesPattern - check pattern according to type of connection properties **/
  1088. propertiesPattern: function() {
  1089. var patterns = {
  1090. db_connection_url: /jdbc\.url|connection_url|connectionurl|kdc_host/ig
  1091. };
  1092. if (this.get('parentView.service.serviceName') != "KERBEROS") {
  1093. patterns.user_name = /(username|dblogin|root_user)$/ig;
  1094. patterns.user_passwd = /(dbpassword|password|root_password)$/ig;
  1095. }
  1096. return patterns;
  1097. }.property('parentView.service.serviceName'),
  1098. /** @property {String} masterHostName - host name location of Master Component related to Service **/
  1099. masterHostName: function() {
  1100. var serviceMasterMap = {
  1101. 'OOZIE': 'oozie_ambari_host',
  1102. 'HDFS': 'hadoop_host',
  1103. 'HIVE': 'hive_ambari_host',
  1104. 'KERBEROS': 'kdc_host',
  1105. 'RANGER': 'rangerserver_host'
  1106. };
  1107. return this.get('parentView.categoryConfigsAll').findProperty('name', serviceMasterMap[this.get('parentView.service.serviceName')]).get('value');
  1108. }.property('parentView.service.serviceName', 'parentView.categoryConfigsAll.@each.value'),
  1109. /** @property {Object} connectionProperties - service specific config values mapped for custom action request **/
  1110. connectionProperties: function() {
  1111. var propObj = {};
  1112. for (var key in this.get('propertiesPattern')) {
  1113. propObj[key] = this.getConnectionProperty(this.get('propertiesPattern')[key]);
  1114. }
  1115. if (this.get('parentView.service.serviceName') === 'RANGER') {
  1116. var dbFlavor = this.get('parentView.categoryConfigsAll').findProperty('name','DB_FLAVOR').get('value'),
  1117. databasesTypes = /MYSQL|POSTGRES|ORACLE|MSSQL/gi,
  1118. dbType = dbFlavor.match(databasesTypes)?dbFlavor.match(databasesTypes)[0].toLowerCase():'';
  1119. if (dbType==='oracle') {
  1120. // fixes oracle SYSDBA issue
  1121. propObj['user_name'] = "\'%@ as sysdba\'".fmt(propObj['user_name']);
  1122. }
  1123. }
  1124. return propObj;
  1125. }.property('parentView.categoryConfigsAll.@each.value'),
  1126. /**
  1127. * Properties that stores in local storage used for handling
  1128. * last success connection.
  1129. *
  1130. * @property {Object} preparedDBProperties
  1131. **/
  1132. preparedDBProperties: function() {
  1133. var propObj = {};
  1134. for (var key in this.get('propertiesPattern')) {
  1135. var propName = this.getConnectionProperty(this.get('propertiesPattern')[key], true);
  1136. propObj[propName] = this.get('parentView.categoryConfigsAll').findProperty('name', propName).get('value');
  1137. }
  1138. return propObj;
  1139. }.property(),
  1140. /** Check validation and load ambari properties **/
  1141. didInsertElement: function() {
  1142. var kdc = this.get('parentView.categoryConfigsAll').findProperty('name', 'kdc_type');
  1143. if (kdc) {
  1144. var name = kdc.get('value') == 'Existing MIT KDC' ? 'KDC' : 'AD';
  1145. App.popover(this.$(), {
  1146. title: Em.I18n.t('services.service.config.database.btn.idle'),
  1147. content: Em.I18n.t('installer.controls.checkConnection.popover').format(name),
  1148. placement: 'right',
  1149. trigger: 'hover'
  1150. });
  1151. }
  1152. this.handlePropertiesValidation();
  1153. this.getAmbariProperties();
  1154. },
  1155. /** On view destroy **/
  1156. willDestroyElement: function() {
  1157. this.set('isConnecting', false);
  1158. this._super();
  1159. },
  1160. /**
  1161. * Observer that take care about enabling/disabling button based on required properties validation.
  1162. *
  1163. * @method handlePropertiesValidation
  1164. **/
  1165. handlePropertiesValidation: function() {
  1166. this.restore();
  1167. var isValid = true;
  1168. var properties = [].concat(this.get('requiredProperties'));
  1169. properties.push(this.get('hostNameProperty'));
  1170. properties.forEach(function(propertyName) {
  1171. var property = this.get('parentView.categoryConfigsAll').findProperty('name', propertyName);
  1172. if(property && !property.get('isValid')) isValid = false;
  1173. }, this);
  1174. this.set('isValidationPassed', isValid);
  1175. }.observes('parentView.categoryConfigsAll.@each.isValid', 'parentView.categoryConfigsAll.@each.value', 'databaseName'),
  1176. getConnectionProperty: function(regexp, isGetName) {
  1177. var _this = this;
  1178. var propertyName = _this.get('requiredProperties').filter(function(item) {
  1179. return regexp.test(item);
  1180. })[0];
  1181. return (isGetName) ? propertyName : _this.get('parentView.categoryConfigsAll').findProperty('name', propertyName).get('value');
  1182. },
  1183. /**
  1184. * Set up ambari properties required for custom action request
  1185. *
  1186. * @method getAmbariProperties
  1187. **/
  1188. getAmbariProperties: function() {
  1189. var clusterController = App.router.get('clusterController');
  1190. var _this = this;
  1191. if (!App.isEmptyObject(App.db.get('tmp', 'ambariProperties')) && !this.get('ambariProperties')) {
  1192. this.set('ambariProperties', App.db.get('tmp', 'ambariProperties'));
  1193. return;
  1194. }
  1195. if (App.isEmptyObject(clusterController.get('ambariProperties'))) {
  1196. clusterController.loadAmbariProperties().done(function(data) {
  1197. _this.formatAmbariProperties(data.RootServiceComponents.properties);
  1198. });
  1199. } else {
  1200. this.formatAmbariProperties(clusterController.get('ambariProperties'));
  1201. }
  1202. },
  1203. formatAmbariProperties: function(properties) {
  1204. var defaults = {
  1205. threshold: "60",
  1206. ambari_server_host: location.hostname,
  1207. check_execute_list : "db_connection_check"
  1208. };
  1209. var properties = App.permit(properties, ['jdk.name','jdk_location','java.home']);
  1210. var renameKey = function(oldKey, newKey) {
  1211. if (properties[oldKey]) {
  1212. defaults[newKey] = properties[oldKey];
  1213. delete properties[oldKey];
  1214. }
  1215. };
  1216. renameKey('java.home', 'java_home');
  1217. renameKey('jdk.name', 'jdk_name');
  1218. $.extend(properties, defaults);
  1219. App.db.set('tmp', 'ambariProperties', properties);
  1220. this.set('ambariProperties', properties);
  1221. },
  1222. /**
  1223. * `Action` method for starting connect to current database.
  1224. *
  1225. * @method connectToDatabase
  1226. **/
  1227. connectToDatabase: function() {
  1228. if (this.get('isBtnDisabled')) return;
  1229. this.set('isRequestResolved', false);
  1230. App.db.set('tmp', this.get('parentView.service.serviceName') + '_connection', {});
  1231. this.setConnectingStatus(true);
  1232. if (App.get('testMode')) {
  1233. this.startPolling();
  1234. } else {
  1235. this.runCheckConnection();
  1236. }
  1237. },
  1238. /**
  1239. * runs check connections methods depending on service
  1240. * @return {void}
  1241. * @method runCheckConnection
  1242. */
  1243. runCheckConnection: function() {
  1244. if (this.get('parentView.service.serviceName') === 'KERBEROS') {
  1245. this.runKDCCheck();
  1246. } else {
  1247. this.createCustomAction();
  1248. }
  1249. },
  1250. /**
  1251. * send ajax request to perforn kdc host check
  1252. * @return {App.ajax}
  1253. * @method runKDCCheck
  1254. */
  1255. runKDCCheck: function() {
  1256. return App.ajax.send({
  1257. name: 'admin.kerberos_security.test_connection',
  1258. sender: this,
  1259. data: {
  1260. kdcHostname: this.get('masterHostName')
  1261. },
  1262. success: 'onRunKDCCheckSuccess',
  1263. error: 'onCreateActionError'
  1264. });
  1265. },
  1266. /**
  1267. *
  1268. * @param data
  1269. */
  1270. onRunKDCCheckSuccess: function(data) {
  1271. var statusCode = {
  1272. success: 'REACHABLE',
  1273. failed: 'UNREACHABLE'
  1274. };
  1275. if (data == statusCode['success']) {
  1276. this.setResponseStatus('success');
  1277. } else {
  1278. this.setResponseStatus('failed');
  1279. }
  1280. this.set('responseFromServer', data);
  1281. },
  1282. /**
  1283. * Run custom action for database connection.
  1284. *
  1285. * @method createCustomAction
  1286. **/
  1287. createCustomAction: function() {
  1288. var dbName = this.get('databaseName').toLowerCase() === 'postgresql' ? 'postgres' : this.get('databaseName').toLowerCase();
  1289. var params = $.extend(true, {}, { db_name: dbName }, this.get('connectionProperties'), this.get('ambariProperties'));
  1290. App.ajax.send({
  1291. name: 'custom_action.create',
  1292. sender: this,
  1293. data: {
  1294. requestInfo: {
  1295. parameters: params
  1296. },
  1297. filteredHosts: [this.get('masterHostName')]
  1298. },
  1299. success: 'onCreateActionSuccess',
  1300. error: 'onCreateActionError'
  1301. });
  1302. },
  1303. /**
  1304. * Run updater if task is created successfully.
  1305. *
  1306. * @method onConnectActionS
  1307. **/
  1308. onCreateActionSuccess: function(data) {
  1309. this.set('currentRequestId', data.Requests.id);
  1310. App.ajax.send({
  1311. name: 'custom_action.request',
  1312. sender: this,
  1313. data: {
  1314. requestId: this.get('currentRequestId')
  1315. },
  1316. success: 'setCurrentTaskId'
  1317. });
  1318. },
  1319. setCurrentTaskId: function(data) {
  1320. this.set('currentTaskId', data.items[0].Tasks.id);
  1321. this.startPolling();
  1322. },
  1323. startPolling: function() {
  1324. if (this.get('isConnecting'))
  1325. this.getTaskInfo();
  1326. },
  1327. getTaskInfo: function() {
  1328. var request = App.ajax.send({
  1329. name: 'custom_action.request',
  1330. sender: this,
  1331. data: {
  1332. requestId: this.get('currentRequestId'),
  1333. taskId: this.get('currentTaskId')
  1334. },
  1335. success: 'getTaskInfoSuccess'
  1336. });
  1337. this.set('request', request);
  1338. },
  1339. getTaskInfoSuccess: function(data) {
  1340. var task = data.Tasks;
  1341. this.set('responseFromServer', {
  1342. stderr: task.stderr,
  1343. stdout: task.stdout
  1344. });
  1345. if (task.status === 'COMPLETED') {
  1346. var structuredOut = task.structured_out.db_connection_check;
  1347. if (structuredOut.exit_code != 0) {
  1348. this.set('responseFromServer', {
  1349. stderr: task.stderr,
  1350. stdout: task.stdout,
  1351. structuredOut: structuredOut.message
  1352. });
  1353. this.setResponseStatus('failed');
  1354. } else {
  1355. App.db.set('tmp', this.get('parentView.service.serviceName') + '_connection', this.get('preparedDBProperties'));
  1356. this.setResponseStatus('success');
  1357. }
  1358. }
  1359. if (task.status === 'FAILED') {
  1360. this.setResponseStatus('failed');
  1361. }
  1362. if (/PENDING|QUEUED|IN_PROGRESS/.test(task.status)) {
  1363. Em.run.later(this, function() {
  1364. this.startPolling();
  1365. }, this.get('pollInterval'));
  1366. }
  1367. },
  1368. onCreateActionError: function(jqXhr, status, errorMessage) {
  1369. this.setResponseStatus('failed');
  1370. this.set('responseFromServer', errorMessage);
  1371. },
  1372. setResponseStatus: function(isSuccess) {
  1373. var isSuccess = isSuccess == 'success';
  1374. this.setConnectingStatus(false);
  1375. this.set('responseCaption', isSuccess ? Em.I18n.t('services.service.config.database.connection.success') : Em.I18n.t('services.service.config.database.connection.failed'));
  1376. this.set('isConnectionSuccess', isSuccess);
  1377. this.set('isRequestResolved', true);
  1378. },
  1379. /**
  1380. * Switch captions and statuses for active/non-active request.
  1381. *
  1382. * @method setConnectionStatus
  1383. * @param {Boolean} [active]
  1384. */
  1385. setConnectingStatus: function(active) {
  1386. if (active) {
  1387. this.set('responseCaption', Em.I18n.t('services.service.config.database.connection.inProgress'));
  1388. }
  1389. this.set('controller.testConnectionInProgress', !!active);
  1390. this.set('btnCaption', !!active ? Em.I18n.t('services.service.config.database.btn.connecting') : Em.I18n.t('services.service.config.database.btn.idle'));
  1391. this.set('isConnecting', !!active);
  1392. },
  1393. /**
  1394. * Set view to init status.
  1395. *
  1396. * @method restore
  1397. **/
  1398. restore: function() {
  1399. if (this.get('request')) {
  1400. this.get('request').abort();
  1401. this.set('request', null);
  1402. }
  1403. this.set('responseCaption', null);
  1404. this.set('responseFromServer', null);
  1405. this.setConnectingStatus(false);
  1406. this.set('isRequestResolved', false);
  1407. },
  1408. /**
  1409. * `Action` method for showing response from server in popup.
  1410. *
  1411. * @method showLogsPopup
  1412. **/
  1413. showLogsPopup: function() {
  1414. if (this.get('isConnectionSuccess')) return;
  1415. var _this = this;
  1416. var popup = App.showAlertPopup('Error: {0} connection'.format(this.get('databaseName')));
  1417. if (typeof this.get('responseFromServer') == 'object') {
  1418. popup.set('bodyClass', Em.View.extend({
  1419. templateName: require('templates/common/error_log_body'),
  1420. openedTask: _this.get('responseFromServer')
  1421. }));
  1422. } else {
  1423. popup.set('body', this.get('responseFromServer'));
  1424. }
  1425. return popup;
  1426. }
  1427. });
  1428. /**
  1429. * View with input field used to repo-version URLs
  1430. * @type {*}
  1431. */
  1432. App.BaseUrlTextField = Ember.TextField.extend({
  1433. layout: Ember.Handlebars.compile('<div class="pull-left">{{yield}}</div> {{#if view.valueWasChanged}}<div class="pull-right"><a class="btn btn-small" {{action "restoreValue" target="view"}}><i class="icon-undo"></i></a></div>{{/if}}'),
  1434. /**
  1435. * Binding in the template
  1436. * @type {App.RepositoryVersion}
  1437. */
  1438. repository: null,
  1439. /**
  1440. * @type {string}
  1441. */
  1442. valueBinding: 'repository.baseUrl',
  1443. /**
  1444. * @type {string}
  1445. */
  1446. defaultValue: '',
  1447. /**
  1448. * Determines if user have put some new value
  1449. * @type {boolean}
  1450. */
  1451. valueWasChanged: false,
  1452. didInsertElement: function () {
  1453. this.set('defaultValue', this.get('value'));
  1454. this.addObserver('value', this, this.valueWasChangedObs);
  1455. },
  1456. valueWasChangedObs: function () {
  1457. var value = this.get('value'),
  1458. defaultValue = this.get('defaultValue');
  1459. this.set('valueWasChanged', value !== defaultValue);
  1460. },
  1461. /**
  1462. * Restore value and unset error-flag
  1463. * @method restoreValue
  1464. */
  1465. restoreValue: function () {
  1466. this.set('value', this.get('defaultValue'));
  1467. this.keyUp();
  1468. },
  1469. /**
  1470. * Remove error-highlight after user puts some new value
  1471. * @method keyUp
  1472. */
  1473. keyUp: function () {
  1474. if (Em.get(this, 'repository.hasError')) {
  1475. Em.set(this, 'repository.hasError', false);
  1476. }
  1477. }
  1478. });