controls_view.js 49 KB

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