AMBARI-13449. FE changes for persisting/updating/removing KDC admin credentials.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1076ec76 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1076ec76 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1076ec76 Branch: refs/heads/branch-dev-patch-upgrade Commit: 1076ec760bdafae4de876e66e39acad4f26c0b7e Parents: 4a95428 Author: Alex Antonenko <hiv...@gmail.com> Authored: Fri Oct 16 13:13:53 2015 +0300 Committer: Alex Antonenko <hiv...@gmail.com> Committed: Fri Oct 16 13:38:21 2015 +0300 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 1 + .../app/controllers/main/admin/kerberos.js | 5 + .../main/admin/kerberos/wizard_controller.js | 10 +- ambari-web/app/messages.js | 3 + .../common/kdc_credentials_controller_mixin.js | 5 +- ambari-web/app/styles/common.less | 8 +- .../common/form/manage_credentilas_form.hbs | 58 +++++ .../app/templates/main/admin/kerberos.hbs | 3 + ambari-web/app/utils/ajax/ajax.js | 2 +- ambari-web/app/utils/credentials.js | 47 ++++- ambari-web/app/views.js | 2 + .../common/form/manage_credentials_form_view.js | 209 +++++++++++++++++++ .../common/modal_popups/invalid_KDC_popup.js | 2 +- .../manage_kdc_credentials_popup.js | 58 +++++ .../form/manage_kdc_credentials_form_test.js | 138 ++++++++++++ 15 files changed, 535 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index 5b5f588..b59f91f 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -273,6 +273,7 @@ var files = [ 'test/views/common/controls_view_test', 'test/views/common/configs/widgets/time_interval_spinner_view_test', 'test/views/common/form/spinner_input_view_test', + 'test/views/common/form/manage_kdc_credentials_form_test', 'test/views/wizard/step3/hostLogPopupBody_view_test', 'test/views/wizard/step3/hostWarningPopupBody_view_test', 'test/views/wizard/step3/hostWarningPopupFooter_view_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/controllers/main/admin/kerberos.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/kerberos.js b/ambari-web/app/controllers/main/admin/kerberos.js index ca2f0dc..d339f63 100644 --- a/ambari-web/app/controllers/main/admin/kerberos.js +++ b/ambari-web/app/controllers/main/admin/kerberos.js @@ -582,5 +582,10 @@ App.MainAdminKerberosController = App.KerberosWizardStep4Controller.extend({ dfd.reject(); }, Em.I18n.t('common.warning'), Em.I18n.t('common.proceedAnyway')); } + }, + + showManageKDCCredentialsPopup: function() { + return App.showManageCredentialsPopup(); } + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js b/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js index 6209f29..e0e146a 100644 --- a/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js +++ b/ambari-web/app/controllers/main/admin/kerberos/wizard_controller.js @@ -263,10 +263,14 @@ App.KerberosWizardController = App.WizardController.extend(App.InstallComponent, callback: function() { var self = this; var dfd = $.Deferred(); - credentialsUtils.isStorePersisted(App.get('clusterName')).then(function(isPersisted) { - self.set('content.secureStoragePersisted', isPersisted); + if (App.get('supports.storeKDCCredentials')) { + credentialsUtils.isStorePersisted(App.get('clusterName')).then(function(isPersisted) { + self.set('content.secureStoragePersisted', isPersisted); + dfd.resolve(); + }); + } else { dfd.resolve(); - }); + } return dfd.promise(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 6437ee9..5df161b 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -1033,6 +1033,9 @@ Em.I18n.translations = { 'admin.kerberos.credentials.store.hint.supported': 'When checked, Ambari will store the KDC Admin credentials so they are not required to be re-entered during future changes of services, hosts, and components.', 'admin.kerberos.credentials.store.hint.not.supported': 'Ambari is not configured for storing credentials', 'admin.kerberos.credentials.store.label': 'Save Admin Credentials', + 'admin.kerberos.credentials.store.menu.label': 'Manage KDC Credentials', + 'admin.kerberos.credentials.remove.confirmation.header': 'Remove KDC Credentials Confirmation', + 'admin.kerberos.credentials.remove.confirmation.body': 'You are about to remove the KDC Credentials from Ambari. Are you sure?', 'admin.kerberos.wizard.configuration.note': 'This is the initial configuration created by Enable Kerberos wizard.', 'admin.kerberos.wizard.header':'Enable Kerberos Wizard', 'admin.kerberos.button.enable': 'Enable Kerberos', http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/mixins/common/kdc_credentials_controller_mixin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/kdc_credentials_controller_mixin.js b/ambari-web/app/mixins/common/kdc_credentials_controller_mixin.js index 67f2664..070ea35 100644 --- a/ambari-web/app/mixins/common/kdc_credentials_controller_mixin.js +++ b/ambari-web/app/mixins/common/kdc_credentials_controller_mixin.js @@ -81,14 +81,11 @@ App.KDCCredentialsControllerMixin = Em.Mixin.create({ * @returns {$.Deferred} promise object */ createKDCCredentials: function(configs) { - var self = this; var resource = credentialsUtils.createCredentialResource( configs.findProperty('name', 'admin_principal').get('value'), configs.findProperty('name', 'admin_password').get('value'), this._getStorageTypeValue(configs)); - return credentialsUtils.createCredentials(App.get('clusterName'), this.get('credentialAlias'), resource).fail(function() { - return self.updateKDCCredentials(resource); - }); + return credentialsUtils.createOrUpdateCredentials(App.get('clusterName'), this.get('credentialAlias'), resource); }, /** http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/styles/common.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/common.less b/ambari-web/app/styles/common.less index b4cb61d..60b7553 100644 --- a/ambari-web/app/styles/common.less +++ b/ambari-web/app/styles/common.less @@ -224,8 +224,8 @@ text-overflow: ellipsis; white-space: nowrap; position: relative; - padding: 0px 0px; - margin: 0px 0px; + padding: 0 0; + margin: 0 0; border: none; width: 50px; height: 18px; @@ -365,4 +365,8 @@ outline: 0 none; } } +} + +.lh-btn { + line-height: 30px; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/templates/common/form/manage_credentilas_form.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/form/manage_credentilas_form.hbs b/ambari-web/app/templates/common/form/manage_credentilas_form.hbs new file mode 100644 index 0000000..c72e024 --- /dev/null +++ b/ambari-web/app/templates/common/form/manage_credentilas_form.hbs @@ -0,0 +1,58 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + + +<form class="form-horizontal"> + <div class="control-group"> + <label class="control-label">{{t popup.invalid.KDC.admin.principal}}</label> + <div class="controls"> + {{view Ember.TextField valueBinding="view.principal" class="form-control"}} + </div> + </div> + <div class="control-group"> + <label class="control-label">{{t popup.invalid.KDC.admin.password}}</label> + <div class="controls"> + {{view Ember.TextField type="password" valueBinding="view.password" class="form-control"}} + </div> + </div> + <div class="control-group"> + <span class="control-label"></span> + <div class="controls"> + {{#if App.supports.storeKDCCredentials}} + <label> + {{view Ember.Checkbox checkedBinding="view.storeCredentials" disabledBinding="view.checkboxDisabled" classNames="pull-left"}} + <span {{bindAttr class=":mls view.checkboxDisabled:muted"}}> + {{t admin.kerberos.credentials.store.label}} + <a class="icon-question-sign icon-blue" rel="tooltip" href="javascript:void(null);" data-toggle="tooltip" {{bindAttr data-original-title="view.hintMessage"}}><a/> + </span> + </label> + {{/if}} + </div> + </div> + <div class="control-group"> + <span class="control-label"></span> + <div class="controls"> + <button {{bindAttr class=":btn :btn-danger :pull-left view.isRemovable::hidden" disabled="view.isRemoveDisabled"}} {{action removeKDCCredentials target="view"}}> + <i class="icon-remove-circle"></i> {{t common.remove}}</button> + <div {{bindAttr class=":spinner :mll :pull-left view.isActionInProgress::hide"}}></div> + {{#if view.actionStatus}} + <span class="pull-left lh-btn mll text-success">{{view.actionStatus}}</span> + {{/if}} + </div> + </div> +</form> http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/templates/main/admin/kerberos.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/kerberos.hbs b/ambari-web/app/templates/main/admin/kerberos.hbs index 88aa4e2..2ba6001 100644 --- a/ambari-web/app/templates/main/admin/kerberos.hbs +++ b/ambari-web/app/templates/main/admin/kerberos.hbs @@ -24,6 +24,9 @@ {{#unless isManualKerberos}} <button class="btn btn-success" {{bindAttr disabled="isKerberosButtonsDisabled"}} {{action regenerateKeytabs target="controller"}}> <i class="icon-repeat"></i> {{t admin.kerberos.button.regenerateKeytabs}}</button> + {{#if App.supports.storeKDCCredentials}} + <button class="btn btn-primary" {{action showManageKDCCredentialsPopup target="controller"}}>{{t admin.kerberos.credentials.store.menu.label}}</button> + {{/if}} {{/unless}} <br/> {{#unless isEditMode}} http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index f0ebbff..52f3aca 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -797,7 +797,7 @@ var urls = { }, 'credentials.list': { - 'real': '/clusters/{clusterName}/credentials', + 'real': '/clusters/{clusterName}/credentials?fields=Credential/*', 'mock': '' }, http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/utils/credentials.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/credentials.js b/ambari-web/app/utils/credentials.js index 0639091..cc45288 100644 --- a/ambari-web/app/utils/credentials.js +++ b/ambari-web/app/utils/credentials.js @@ -69,11 +69,37 @@ module.exports = { }); }, + credentialsSuccessCallback: function(data, opt, params) { + params.callback(data.items.length ? data.items.mapProperty('Credential') : []); + }, + createCredentialsErrorCallback: function(req, ajaxOpts, error) { console.error('createCredentials ERROR:', error); }, /** + * @see createCredentials + * @param {string} clusterName + * @param {string} alias + * @param {object} resource + * @returns {$.Deferred} promise object + */ + createOrUpdateCredentials: function(clusterName, alias, resource) { + var self = this; + var dfd = $.Deferred(); + this.createCredentials(clusterName, alias, resource).then(function() { + dfd.resolve(); + }, function() { + self.updateCredentials(clusterName, alias, resource).always(function() { + var status = arguments[1]; + var result = arguments[2]; + dfd.resolve(status === "success", result); + }); + }); + return dfd.promise(); + }, + + /** * Retrieve single credential from cluster by specified alias name * * @member utils.credentials @@ -131,16 +157,13 @@ module.exports = { sender: this, name: 'credentials.list', data: { - clusterName: clusterName + clusterName: clusterName, + callback: callback }, success: 'credentialsSuccessCallback' }); }, - credentialsSuccessCallback: function(data, opt, params) { - params.callback(data.items.length ? data.items.mapProperty('Credential') : []); - }, - /** * Remove credential from server by specified cluster name and alias * @@ -241,5 +264,19 @@ module.exports = { key: key, type: type }; + }, + + /** + * Check that KDC credentials stored as <b>persisted</b> and not <b>temporary</b> from specified credentials list. + * + * @param {object[]} credentials credentials list retrieved from API @see credentials + * @returns {boolean} <code>true</code> if credentials are persisted + */ + isKDCCredentialsPersisted: function(credentials) { + var kdcCredentials = credentials.findProperty('alias', this.ALIAS.KDC_CREDENTIALS); + if (kdcCredentials) { + return Em.getWithDefault(kdcCredentials, 'type', this.STORE_TYPES.TEMPORARY) === this.STORE_TYPES.PERSISTENT; + } + return false; } }; http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index e83b5d2..d6132e6 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -27,6 +27,7 @@ require('views/common/chart/linear'); require('views/common/chart/linear_time'); require('views/common/modal_popup'); require('views/common/modal_popups/alert_popup'); +require('views/common/modal_popups/manage_kdc_credentials_popup'); require('views/common/modal_popups/confirmation_feedback_popup'); require('views/common/modal_popups/confirmation_popup'); require('views/common/modal_popups/hosts_table_list_popup'); @@ -42,6 +43,7 @@ require('views/common/time_range'); require('views/common/time_range_list'); require('views/common/form/field'); require('views/common/form/spinner_input_view'); +require('views/common/form/manage_credentials_form_view'); require('views/common/quick_view_link_view'); require('views/common/configs/services_config'); require('views/common/configs/service_config_container_view'); http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/views/common/form/manage_credentials_form_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/form/manage_credentials_form_view.js b/ambari-web/app/views/common/form/manage_credentials_form_view.js new file mode 100644 index 0000000..c71021c --- /dev/null +++ b/ambari-web/app/views/common/form/manage_credentials_form_view.js @@ -0,0 +1,209 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var credentialsUtils = require('utils/credentials'); + +App.ManageCredentialsFormView = Em.View.extend({ + templateName: require('templates/common/form/manage_credentilas_form'), + viewName: 'manageCredentialsForm', + principal: "", + password: "", + + /** + * Store Admin credentials checkbox value + * + * @type {boolean} + */ + storeCredentials: false, + + /** + * Status of persistent storage. Returns <code>true</code> if persistent storage is available. + * @type {boolean} + */ + storePersisted: false, + + /** + * Disable checkbox if persistent storage not available + * + * @type {boolean} + */ + checkboxDisabled: Ember.computed.not('storePersisted'), + + /** + * Credentials can be removed, in case when they stored to persistent secure storage. + * + * @type {boolean} + */ + isRemovable: false, + + /** + * Remove button disabled status. + * + * @type {boolean} + */ + isRemoveDisabled: true, + + /** + * Signalize that action was performed and waiting for result. + * + * @type {boolean} + */ + isActionInProgress: false, + + /** + * Status message of performed action, e.g. remove or save credentials. Set to <code>false</code> to hide this message. + * + * @type {boolean|string} + */ + actionStatus: false, + + isSubmitDisabled: function() { + return Em.isEmpty(this.get('principal')) || Em.isEmpty(this.get('password')); + }.property('principal', 'password'), + + /** + * Returns storage type used to save credentials e.g. <b>persistent</b>, <b>temporary</b> (default) + * + * @type {string} + */ + storageType: function() { + return this.get('storeCredentials') ? credentialsUtils.STORE_TYPES.PERSISTENT : credentialsUtils.STORE_TYPES.TEMPORARY; + }.property('storeCredentials'), + + /** + * Message to display in tooltip regarding persistent storage state. + * + * @type {string} + */ + hintMessage: function() { + return this.get('storePersisted') ? + Em.I18n.t('admin.kerberos.credentials.store.hint.supported') : + Em.I18n.t('admin.kerberos.credentials.store.hint.not.supported'); + }.property('storePersisted'), + + /** + * Observe changes for principal and password. + * Hide status message and toggle action progress if performed. + */ + formInputObserver: function() { + if (this.get('actionStatus') || this.get('isActionInProgress')) { + this.setInProgress(false); + this.set('actionStatus', false); + } + }.observes('password', 'principal'), + + didInsertElement: function() { + this._super(); + App.tooltip(this.$('[rel="tooltip"]')); + }, + + willInsertElement: function() { + this._super(); + this.prepareContent(); + }, + + prepareContent: function() { + var self = this; + credentialsUtils.isStorePersisted(App.get('clusterName')).then(function(isPersisted) { + Em.run.next(function() { + self.set('storePersisted', isPersisted); + }); + }); + credentialsUtils.credentials(App.get('clusterName'), function(credentials) { + Em.run.next(function() { + self.set('isRemovable', credentialsUtils.isKDCCredentialsPersisted(credentials)); + self.set('isRemoveDisabled', !self.get('isRemovable')); + }); + }); + }, + + /** + * Save credentials action. + * + * @returns {boolean|$.Deferred} + */ + saveKDCCredentials: function () { + var self = this; + var dfd = $.Deferred(); + + this.setInProgress(true); + credentialsUtils.createOrUpdateCredentials( + App.get('clusterName'), + credentialsUtils.ALIAS.KDC_CREDENTIALS, + credentialsUtils.createCredentialResource(this.get('principal'), this.get('password'), this.get('storageType'))) + .always(function() { + self.setInProgress(false); + self.prepareContent(); + self.set('actionStatus', Em.I18n.t('common.success')); + self.get('parentView').set('isCredentialsSaved', true); + dfd.resolve(); + }); + return dfd.promise(); + }, + + /** + * Remove KDC credentials action. + * + * @returns {App.ModalPopup} + */ + removeKDCCredentials: function() { + var t = Em.I18n.t; + var self = this; + this.set('actionStatus', false); + var popup = App.showConfirmationPopup( + function() { + self.setInProgress(true); + credentialsUtils.removeCredentials(App.get('clusterName'), credentialsUtils.ALIAS.KDC_CREDENTIALS) + .always(function() { + self.setInProgress(false); + self.prepareContent(); + self.set('actionStatus', Em.I18n.t('common.success')); + self.get('parentView').set('isCredentialsRemoved', true); + }); + }, t('admin.kerberos.credentials.remove.confirmation.body'), + function () {}, + null, + t('yes'), + false); + popup.set('secondary', t('no')); + return popup; + }, + + /** + * Toggle action status and disable/enable appropriate buttons. + * + * @param {boolean} [isInProgress=false] progress status + */ + setInProgress: function(isInProgress) { + if (isInProgress) { + this.set('actionStatus', false); + if (this.get('isRemovable')) { + this.set('isRemoveDisabled', true); + } + this.set('isSubmitDisabled', true); + this.set('isActionInProgress', true); + } else { + if (this.get('isRemovable')) { + this.set('isRemoveDisabled', false); + } + this.set('isSubmitDisabled', false); + this.set('isActionInProgress', false); + } + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js b/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js index 9c63f8f..ca5de7d 100644 --- a/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js +++ b/ambari-web/app/views/common/modal_popups/invalid_KDC_popup.js @@ -110,7 +110,7 @@ App.showInvalidKDCPopup = function (ajaxOpt, message) { this.hide(); if (App.get('supports.storeKDCCredentials')) { var resource = credentialsUtils.createCredentialResource(this.get('principal'), this.get('password'), this.get('storageType')); - credentialsUtils.updateCredentials(App.get('clusterName'), credentialsUtils.ALIAS.KDC_CREDENTIALS, resource); + credentialsUtils.createOrUpdateCredentials(App.get('clusterName'), credentialsUtils.ALIAS.KDC_CREDENTIALS, resource); } App.get('router.clusterController').createKerberosAdminSession(this.get('principal'), this.get('password'), ajaxOpt); } http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/app/views/common/modal_popups/manage_kdc_credentials_popup.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/modal_popups/manage_kdc_credentials_popup.js b/ambari-web/app/views/common/modal_popups/manage_kdc_credentials_popup.js new file mode 100644 index 0000000..1de8e56 --- /dev/null +++ b/ambari-web/app/views/common/modal_popups/manage_kdc_credentials_popup.js @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var credentialsUtils = require('utils/credentials'); + +/** + * @return {*} + */ +App.showManageCredentialsPopup = function () { + return App.ModalPopup.show({ + header: Em.I18n.t('admin.kerberos.credentials.store.menu.label'), + bodyClass: App.ManageCredentialsFormView, + primary: Em.I18n.t('common.save'), + isCredentialsRemoved: false, + + disablePrimary: function() { + return this.get('formView.isSubmitDisabled'); + }.property('formView.isSubmitDisabled'), + + formView: function() { + return this.get('childViews').findProperty('viewName', 'manageCredentialsForm'); + }.property(), + + credentialsRemoveObserver: function() { + if (this.get('isCredentialsRemoved')) { + this.hide(); + } + }.observes('isCredentialsRemoved'), + + onPrimary: function() { + var self = this; + var formView = this.get('formView'); + if (formView) { + formView.saveKDCCredentials().always(function() { + self.hide(); + }); + } else { + this.hide(); + } + } + }); +}; http://git-wip-us.apache.org/repos/asf/ambari/blob/1076ec76/ambari-web/test/views/common/form/manage_kdc_credentials_form_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/common/form/manage_kdc_credentials_form_test.js b/ambari-web/test/views/common/form/manage_kdc_credentials_form_test.js new file mode 100644 index 0000000..ca5e4d0 --- /dev/null +++ b/ambari-web/test/views/common/form/manage_kdc_credentials_form_test.js @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var credentialUtils = require('utils/credentials'); + +var view; + +describe('#App.ManageCredentialsFormView', function() { + beforeEach(function() { + view = App.ManageCredentialsFormView.create({ + parentView: Em.Object.create({}) + }); + }); + + afterEach(function() { + view.destroy(); + }); + + describe('#prepareContent', function() { + [ + { + isStorePersistent: true, + credentials: [ + { + alias: 'kdc.admin.credential', + type: 'persisted' + } + ], + e: { + isRemovable: true, + isRemoveDisabled: false, + storePersisted: true + }, + m: 'persistent store is available, previous credentials were stored as persisted. Remove button should be visible and active.' + }, + { + isStorePersistent: true, + credentials: [ + { + alias: 'kdc.admin.credential', + type: 'temporary' + } + ], + e: { + isRemovable: false, + isRemoveDisabled: true, + storePersisted: true + }, + m: 'persistent store is available, previous credentials were stored as temporary. Remove button should be hidden and disabled.' + } + ].forEach(function(test) { + it(test.m, function(done) { + sinon.stub(credentialUtils, 'credentials', function(clusterName, callback) { + callback(test.credentials); + }); + sinon.stub(credentialUtils, 'isStorePersisted', function() { + return $.Deferred().resolve(test.isStorePersistent).promise(); + }); + view.prepareContent(); + Em.run.next(function() { + assert.equal(view.get('isRemovable'), test.e.isRemovable, '#isRemovable property validation'); + assert.equal(view.get('isRemoveDisabled'), test.e.isRemoveDisabled, '#isRemoveDisabled property validation'); + assert.equal(view.get('storePersisted'), test.e.storePersisted, '#storePersisted property validation'); + credentialUtils.credentials.restore(); + credentialUtils.isStorePersisted.restore(); + done(); + }); + }); + }); + }); + + describe('#isSubmitDisabled', function() { + it('save button disabled by default', function() { + expect(view.get('isSubmitDisabled')).to.be.true; + }); + it('save button disabled when password is empty', function() { + view.set('principal', 'some_principal'); + expect(view.get('isSubmitDisabled')).to.be.true; + }); + it('save button disabled when principal is empty', function() { + view.set('password', 'some_password'); + expect(view.get('isSubmitDisabled')).to.be.true; + }); + it('save button should be enabled when principal and password are filled', function() { + view.set('password', 'some_password'); + view.set('principal', 'principal'); + expect(view.get('isSubmitDisabled')).to.be.false; + }); + }); + + describe('#removeKDCCredentials', function() { + it('should show confirmation popup', function() { + var popup = view.removeKDCCredentials(); + expect(popup).be.instanceof(App.ModalPopup); + popup.destroy(); + }); + it('should call credentialUtils#removeCredentials', function() { + this.clock = sinon.useFakeTimers(); + var popup = view.removeKDCCredentials(); + assert.isFalse(view.get('actionStatus'), '#actionStatus before remove'); + sinon.stub(credentialUtils, 'removeCredentials', function() { + var dfd = $.Deferred(); + setTimeout(function() { + dfd.resolve(); + }, 500); + return dfd.promise(); + }); + popup.onPrimary(); + assert.isTrue(view.get('isActionInProgress'), 'action in progress'); + assert.isTrue(view.get('isRemoveDisabled'), 'remove button disabled'); + assert.isTrue(view.get('isSubmitDisabled'), 'submit button disabled'); + this.clock.tick(1000); + assert.isFalse(view.get('isActionInProgress'), 'action finished'); + assert.equal(Em.I18n.t('common.success'), view.get('actionStatus'), '#actionStatus after remove'); + assert.isTrue(view.get('parentView.isCredentialsRemoved'), 'parentView#isCredentialsRemoved property should be triggered when remove complete'); + credentialUtils.removeCredentials.restore(); + this.clock.restore(); + popup.destroy(); + }); + }); + +});