controls_view.js 60 KB

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