controls_view.js 52 KB

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