Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-21674 a11a8712a -> d43882d1a


UI changes for prompting user during registration failure for new OS family 
(Sonia Garudi via ncole)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d43882d1
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d43882d1
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d43882d1

Branch: refs/heads/branch-feature-AMBARI-21674
Commit: d43882d1aa55dc2f7e358fec176641b57a6c71f6
Parents: a11a871
Author: Nate Cole <[email protected]>
Authored: Thu Nov 30 09:07:47 2017 -0500
Committer: Nate Cole <[email protected]>
Committed: Thu Nov 30 09:07:47 2017 -0500

----------------------------------------------------------------------
 .../ambari/server/bootstrap/BSHostStatus.java   |   9 ++
 .../server/bootstrap/BSHostStatusCollector.java |   7 +
 .../app/controllers/wizard/step3_controller.js  | 114 +++++++++++++++
 ambari-web/app/messages.js                      |   3 +
 ambari-web/app/styles/wizard.less               |  22 +++
 ambari-web/app/templates/wizard/step3.hbs       |  47 +++++++
 .../test/controllers/wizard/step3_test.js       | 140 +++++++++++++++++++
 7 files changed, 342 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatus.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatus.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatus.java
index 3d1b31c..a91a1f2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatus.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatus.java
@@ -41,7 +41,16 @@ public class BSHostStatus {
   private String statusAction;
   @XmlElement
   private String log;
+  @XmlElement
+  private String osType;
+
+  public String getOsType() {
+    return osType;
+  }
 
+  public void setOsType(String osType) {
+    this.osType = osType;
+  }
 
   public void setStatus(String status) {
     this.status = status;

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
index b72ca20..45e0870 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
@@ -79,6 +79,13 @@ class BSHostStatusCollector {
           if (statusCode.equals("0")) {
             status.setStatus("DONE");
           }
+          //the status code 44 is returned if ambari-repo property isn't set 
for the host's os_type in ambari.properties file.
+          //'44:<os_type>' is written to the .done file for the respective 
host.
+          if (statusCode.startsWith("44")) {
+            String[] sc = statusCode.split(":");
+            status.setOsType(sc[1]);
+            statusCode = sc[0];
+          }
           
           updateStatus(status, statusCode);
         } catch (IOException e) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-web/app/controllers/wizard/step3_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step3_controller.js 
b/ambari-web/app/controllers/wizard/step3_controller.js
index 29393e3..5ff2cdc 100644
--- a/ambari-web/app/controllers/wizard/step3_controller.js
+++ b/ambari-web/app/controllers/wizard/step3_controller.js
@@ -184,6 +184,9 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
     this.set('isLoaded', false);
     this.set('isSubmitDisabled', true);
     this.set('stopChecking', false);
+    this.set('newAmbariOsTypes', []);
+    this.set('promptAmbariRepoUrl', false);
+    this.set('bootstrapInProgress', false);
   },
 
   /**
@@ -301,6 +304,24 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
     return App.showConfirmationPopup(function () {
       App.router.send('removeHosts', hosts);
       self.hosts.removeObjects(hosts);
+      hosts.forEach(function(_host) {
+        var ambariOsTypeIndex = -1;
+        self.newAmbariOsTypes.some(function(os, index) {
+          if (os.hosts.contains(_host.name)){
+            ambariOsTypeIndex = index;
+            return true;
+          }
+        });
+        if (ambariOsTypeIndex != -1) {
+          
self.newAmbariOsTypes[ambariOsTypeIndex].hosts.removeObject(_host.name);
+          if (self.newAmbariOsTypes[ambariOsTypeIndex].hosts.length == 0) {
+            self.newAmbariOsTypes.removeAt(ambariOsTypeIndex);
+          }
+          if (!self.newAmbariOsTypes.length) {
+            self.set('promptAmbariRepoUrl', false);
+          }
+        }
+      });
       self.stopRegistration();
       if (!self.hosts.length) {
         self.set('isSubmitDisabled', true);
@@ -371,6 +392,7 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
    * @method retryHosts
    */
   retryHosts: function (hosts) {
+    this.set('promptAmbariRepoUrl', false);
     var self = this;
     var bootStrapData = JSON.stringify({
         'verbose': true,
@@ -385,6 +407,7 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
     this.set('isHostsWarningsLoaded', false);
     this.set('stopChecking', false);
     this.set('isSubmitDisabled', true);
+    this.set('bootstrapInProgress', true);
     if (this.get('content.installOptions.manualInstall')) {
       this.startRegistration();
     } else {
@@ -523,6 +546,37 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
       var installedHosts = App.Host.find().mapProperty('hostName');
       var isErrorStatus = data.status == 'ERROR';
       this.set('isBootstrapFailed', isErrorStatus);
+
+      this.set('bootstrapInProgress', keepPolling);
+      // check for prompting ambari repo url
+      if (!keepPolling && data.hostsStatus.someProperty('statusCode', "44")) {
+        data.hostsStatus.forEach(function(host) {
+          if (host.statusCode == 44) {
+            var ambariOsTypeIndex = -1;
+            this.newAmbariOsTypes.some(function(diffOs, index) {
+              if (diffOs.os_type == host.osType) {
+                ambariOsTypeIndex = index;
+                return true;
+              }
+            });
+            if (ambariOsTypeIndex == -1) {
+              var tmpNewAmbariOsType = {
+                  'os_type' : host.osType,
+                  'ambari_repo' : "",
+                  'hosts' : []
+              };
+              tmpNewAmbariOsType.hosts.push(host.hostName);
+              this.newAmbariOsTypes.pushObject(tmpNewAmbariOsType);
+            } else {
+              if 
(!this.newAmbariOsTypes[ambariOsTypeIndex].hosts.contains(host.hostName)){
+                
this.newAmbariOsTypes[ambariOsTypeIndex].hosts.push(host.hostName);
+              }
+            }
+          }
+        },this);
+        this.set('promptAmbariRepoUrl',true);
+      }
+
       if (isErrorStatus || 
data.hostsStatus.mapProperty('hostName').removeObjects(installedHosts).length 
!= this.get('bootHosts').length) {
 
         var hosts = this.get('bootHosts');
@@ -552,6 +606,66 @@ App.WizardStep3Controller = 
Em.Controller.extend(App.ReloadPopupMixin, App.Check
   },
 
   /**
+   * check ambari repository URL entered on the UI
+   * @method checkAmbariRepoUI
+   */
+  checkAmbariRepoUI : (function() {
+    var regex = 
/(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
+    this.newAmbariOsTypes.forEach(function(obj) {
+      if (obj.ambari_repo == '' || obj.ambari_repo == null) {
+        Em.set(obj, 'ambariRepoUIError', "");
+        Em.set(obj, 'hasError', false);
+      } else if (/\s/.test(obj.ambari_repo) || !regex.test(obj.ambari_repo)) {
+        Em.set(obj, 'ambariRepoUIError', 
Em.I18n.t('installer.step3.ambariRepoUIError.stringError'));
+        Em.set(obj, 'hasError', true);
+      } else {
+        Em.set(obj, 'ambariRepoUIError', "");
+        Em.set(obj, 'hasError', false);
+      }
+    }, this);
+  }).observes('[email protected]_repo'),
+
+  /**
+   * return true if 1 or more ostypes have invalid URL
+   * @type {bool}
+   */
+  invalidAmbariRepoUrlExists : (function() {
+    return this.newAmbariOsTypes.someProperty('hasError', true);
+  }).property('[email protected]'),
+
+  /**
+   * return true if all textboxes for ambari repo url are empty
+   * @type {bool}
+   */
+  allAmbariRepoUrlsEmpty : (function() {
+    return this.newAmbariOsTypes.getEach('ambari_repo').every(function(value) {
+      return value == null || value == "";
+    });
+  }).property('[email protected]_repo'),
+
+  /**
+   * check conditions to disable ambari repo submit button
+   * @type {bool}
+   */
+  checkAmbariRepoSubmitDisabled : function() {
+    return (this.get('isRegistrationInProgress') || 
!this.get('isWarningsLoaded')) || App.get('router.btnClickInProgress') || 
this.get('bootstrapInProgress');
+  }.property('isRegistrationInProgress', 'isWarningsLoaded', 
'bootstrapInProgress'),
+
+  /**
+   * Is ambari repo submit button disabled
+   * @type {bool}
+   */
+  isAmbariRepoURLSubmitDisabled : Em.computed.or('invalidAmbariRepoUrlExists', 
'allAmbariRepoUrlsEmpty', 'checkAmbariRepoSubmitDisabled'),
+
+  /**
+   * Do bootstrap calls with entered ambari repo url
+   * @method bootstrapWithAmbariRepoUrl
+   */
+  bootstrapWithAmbariRepoUrl : function() {
+
+  },
+
+  /**
    * Start hosts registration
    * @method startRegistration
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 390f803..a7a238c 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -871,6 +871,9 @@ Em.I18n.translations = {
   'installer.step3.hostLogPopup.copy':'press CTRL+C',
   'installer.step3.hostsTable.selectAll':'Select All Hosts',
   'installer.step3.selectedHosts.popup.header':'Selected Hosts',
+  'ambari.repository.url.os.textbox':'Please enter valid Ambari Repository 
URLs for the below OS types',
+  'ambari.repository.baseUrl':'Ambari Repository Base URL',
+  'installer.step3.ambariRepoUIError.stringError':'Please enter a valid URL',
 
   'installer.step4.header':'Choose Services',
   'installer.step4.body':'Choose which services you want to install on your 
cluster.',

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-web/app/styles/wizard.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/wizard.less 
b/ambari-web/app/styles/wizard.less
index cb9eb92..fb51701 100644
--- a/ambari-web/app/styles/wizard.less
+++ b/ambari-web/app/styles/wizard.less
@@ -189,6 +189,28 @@
     #warningsSection {
       margin: 0px 10px;
     }
+    .ambari-repo-url-panel {
+      p.help-block.validation-block {
+        &::before {
+          content: '\e083';
+          color:  #EF6162;
+        }
+      }
+      .btn-area {
+        padding: 10px;
+      }
+      input {
+        width:85%;
+      }
+      td {
+        .onerror {
+          .ember-text-field {
+            border-color: #EF6162;
+          }
+        }
+      }
+    }
+
   }
   #step4, #step5, #step6 {
     a.selected {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-web/app/templates/wizard/step3.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/step3.hbs 
b/ambari-web/app/templates/wizard/step3.hbs
index e00012c..571c86e 100644
--- a/ambari-web/app/templates/wizard/step3.hbs
+++ b/ambari-web/app/templates/wizard/step3.hbs
@@ -140,6 +140,53 @@
             {{/unless}}
           </div>
         {{/unless}}
+
+        {{#if promptAmbariRepoUrl}}
+          <div class="ambari-repo-url-panel">
+            <div class="step-title"> <p>Ambari Repositories</p></div>
+            <div class="step-description">
+              <div class="alert alert-info">
+                <label>{{t ambari.repository.url.os.textbox}}</label>
+              </div>
+            </div>
+            <table class="table table-hover">
+              <thead>
+                <tr>
+                  <th class="col-sm-2">{{t common.os}} </th>
+                  <th class="col-sm-3">{{t ambari.repository.baseUrl}}</th>
+                </tr>
+              </thead>
+              <tbody>
+                {{#each os in newAmbariOsTypes}}
+                  <tr>
+                    <td class="col-sm-2">{{os.os_type }}</td>
+                    <td class="col-sm-9" colspan="2">
+                      <table class="table table-condensed no-borders 
inner-table">
+                        <tbody>
+                          <tr>
+                            <td class="col-sm-3" {{bindAttr 
class="os.hasError:onerror"}}>{{view Ember.TextField 
valueBinding="os.ambari_repo" }}</td>
+                          </tr>
+                          <tr>
+                            <td class="col-sm-3">
+                            {{#if os.hasError}}
+                              <p class="help-block validation-block col-sm-9"  
{{QAAttr "ambari-repo-validation"}}>{{os.ambariRepoUIError}}</p>
+                            {{/if}}
+                            </td>
+                          </tr>
+                        </tbody>
+                      </table>
+                    </td>
+                  </tr>
+                {{/each}}
+              </tbody>
+            </table>
+
+            <div class="btn-area">
+              <button type="button" class="btn" {{bindAttr 
disabled="isAmbariRepoURLSubmitDisabled" }} {{action bootstrapWithAmbariRepoUrl 
 target="controller"}}>Validate
+            </div>
+          </div>
+        {{/if}}
+
       </div>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d43882d1/ambari-web/test/controllers/wizard/step3_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/wizard/step3_test.js 
b/ambari-web/test/controllers/wizard/step3_test.js
index b8bc794..be1affe 100644
--- a/ambari-web/test/controllers/wizard/step3_test.js
+++ b/ambari-web/test/controllers/wizard/step3_test.js
@@ -378,6 +378,41 @@ describe('App.WizardStep3Controller', function () {
       expect(c.get('isSubmitDisabled')).to.equal(true);
     });
 
+    it('should remove ambari repo prompt if no host of os_type exist', 
function () {
+      var hosts = [
+            Em.Object.create({name: 'host1'}),
+            Em.Object.create({name: 'host2'})
+          ];
+      c.reopen({
+        hosts: hosts,
+        promptAmbariRepoUrl: true,
+        newAmbariOsTypes : [
+          Em.Object.create({os_type : 'os1', hosts : ['host2']})
+        ]
+      });
+      var removeHosts = [{name: 'host2'}];
+      c.removeHosts(removeHosts).onPrimary();;
+      expect(c.get('promptAmbariRepoUrl')).to.equal(false);
+    });
+
+    it('should not remove ambari repo prompt if a host of os_type exist', 
function () {
+      var hosts = [
+            Em.Object.create({name: 'host1'}),
+            Em.Object.create({name: 'host2'}),
+            Em.Object.create({name: 'host3'})
+          ];
+      c.reopen({
+        hosts: hosts,
+        promptAmbariRepoUrl: true,
+        newAmbariOsTypes : [
+          Em.Object.create({os_type : 'os1', hosts : ['host2','host3']})
+        ]
+      });
+      var removeHosts = [{name: 'host2'}];
+      c.removeHosts(removeHosts).onPrimary();;
+      expect(c.get('promptAmbariRepoUrl')).to.equal(true);
+    });
+
   });
 
   describe('#removeSelectedHosts', function () {
@@ -2560,6 +2595,111 @@ describe('App.WizardStep3Controller', function () {
 
   });
 
+  describe('#doBootstrapSuccessCallback', function () {
+
+    it('should prompt for ambari repo url if os_type of host added is 
different', function () {
+      c.reopen({
+        bootHosts: [
+          Em.Object.create({name: 'host1', bootStatus: 'FAILED'})
+        ],
+        newAmbariOsTypes: []
+      });
+      var data1 = {
+            status: 'ERROR',
+            hostsStatus: [
+              Em.Object.create({hostName: 'host1', status: 'FAILED', 
statusCode: '44', osType: 'os1', log: 'log'})
+            ]
+          };
+      c.doBootstrapSuccessCallback(data1);
+      expect(c.get('promptAmbariRepoUrl')).to.equal(true);
+    });
+  });
+
+  describe('#checkAmbariRepoUI', function () {
+
+    it('check space', function () {
+      var newAmbariOsTypes = [
+                              Em.Object.create({os_type : 'os1', ambari_repo : 
"ambari repo", hosts : ['host1']})
+                              ];
+      c.reopen({
+        newAmbariOsTypes: newAmbariOsTypes
+      });
+      c.checkAmbariRepoUI();
+      expect(c.get('newAmbariOsTypes')[0].hasError).to.equal(true);
+      expect(c.get('newAmbariOsTypes')[0].ambariRepoUIError).to.equal("Please 
enter a valid URL");
+    });
+
+    it('check invalid url', function () {
+      var newAmbariOsTypes = [
+                              Em.Object.create({os_type : 'os1', ambari_repo : 
"http//ambari-repo", hosts : ['host1']})
+                              ];
+      c.reopen({
+        newAmbariOsTypes: newAmbariOsTypes
+      });
+      c.checkAmbariRepoUI();
+      expect(c.get('newAmbariOsTypes')[0].hasError).to.equal(true);
+      expect(c.get('newAmbariOsTypes')[0].ambariRepoUIError).to.equal("Please 
enter a valid URL");
+    });
+  });
+
+  describe('#isAmbariRepoURLSubmitDisabled', function () {
+
+    var cases = [
+                 {
+                   allAmbariRepoUrlsEmpty: true,
+                   invalidAmbariRepoUrlExists: false,
+                   isAmbariRepoURLSubmitDisabled: true,
+                   description: 'all textboxes are empty',
+                   title: 'all empty '
+                 },
+                 {
+                   allAmbariRepoUrlsEmpty: false,
+                   invalidAmbariRepoUrlExists: true,
+                   isAmbariRepoURLSubmitDisabled: true,
+                   description: 'multiple textboxes with some empty and some 
with invalid urls',
+                   title: 'has invalid, has empty'
+                 },
+                 {
+                   allAmbariRepoUrlsEmpty: false,
+                   invalidAmbariRepoUrlExists: false,
+                   isAmbariRepoURLSubmitDisabled: false,
+                   description: 'multiple textboxes with some empty and some 
with valid urls',
+                   title: 'has valid, has empty'
+                 },
+                 {
+                   allAmbariRepoUrlsEmpty: false,
+                   invalidAmbariRepoUrlExists: false,
+                   isAmbariRepoURLSubmitDisabled: false,
+                   description: 'all textboxes valid urls',
+                   title: 'all valid'
+                 }
+                 ];
+
+    cases.forEach(function (item) {
+
+      describe(item.description, function () {
+
+        beforeEach(function () {
+          c.reopen({
+            checkAmbariRepoSubmitDisabled: false,
+            allAmbariRepoUrlsEmpty: item.allAmbariRepoUrlsEmpty,
+            invalidAmbariRepoUrlExists: item.invalidAmbariRepoUrlExists
+          });
+          sinon.stub(App, 
'get').withArgs('router.btnClickInProgress').returns(false);
+        });
+
+        afterEach(function () {
+          App.get.restore();
+        });
+
+        it(item.title, function () {
+          
expect(c.get('isAmbariRepoURLSubmitDisabled')).to.equal(item.isAmbariRepoURLSubmitDisabled);
+        });
+      });
+    });
+
+  });
+
   describe('#getJDKNameSuccessCallback', function () {
 
     it('should set proper data to controller properties', function () {

Reply via email to