controls_view.js 50 KB

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