Repository: ambari
Updated Branches:
  refs/heads/branch-2.2 dd532e13f -> fc7338795


AMBARI-15657: HAWQ config should not allow multiple Master/Segment directories 
(Lav Jain via mithmatt)


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

Branch: refs/heads/branch-2.2
Commit: fc7338795ca7ef157afff031ed96c2d1ec7962df
Parents: dd532e1
Author: Matt <[email protected]>
Authored: Tue Apr 5 11:03:16 2016 -0700
Committer: Matt <[email protected]>
Committed: Tue Apr 5 11:03:16 2016 -0700

----------------------------------------------------------------------
 .../HAWQ/2.0.0/configuration/hawq-site.xml      |  5 +--
 .../HAWQ/2.0.0/themes/theme.json                |  4 +--
 .../stacks/HDP/2.3/services/stack_advisor.py    | 17 +++++++++
 .../stacks/2.3/common/test_stack_advisor.py     | 36 ++++++++++++++++++++
 ambari-web/app/messages.js                      |  1 +
 ambari-web/app/mixins/common/serverValidator.js | 11 ++++--
 .../configs/objects/service_config_property.js  |  3 ++
 ambari-web/app/styles/application.less          | 16 ++++++---
 .../config_recommendation_popup.hbs             | 25 ++++++++++----
 .../configs/service_config_layout_tab_view.js   |  2 +-
 10 files changed, 100 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/configuration/hawq-site.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/configuration/hawq-site.xml
 
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/configuration/hawq-site.xml
index ec7275f..170e8cf 100644
--- 
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/configuration/hawq-site.xml
+++ 
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/configuration/hawq-site.xml
@@ -88,7 +88,8 @@
     <display-name>HAWQ Master Directory</display-name>
     <value>/data/hawq/master</value>
     <description>
-      The directory of HAWQ master.
+      The base path for the HAWQ master data directory. Multiple directories 
are not allowed.
+      The default is /data/hawq/master.
     </description>
     <value-attributes>
       <type>directory</type>
@@ -102,7 +103,7 @@
     <display-name>HAWQ Segment Directory</display-name>
     <value>/data/hawq/segment</value>
     <description>
-      The base path for the HAWQ segment data directory.
+      The base path for the HAWQ segment data directory. Multiple directories 
are not allowed.
       The default is /data/hawq/segment.
     </description>
     <value-attributes>

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/themes/theme.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/themes/theme.json 
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/themes/theme.json
index a23afe6..e4d1c45 100644
--- 
a/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/themes/theme.json
+++ 
b/ambari-server/src/main/resources/common-services/HAWQ/2.0.0/themes/theme.json
@@ -136,13 +136,13 @@
          {
             "config":"hawq-site/hawq_master_directory",
             "widget":{
-               "type":"text-field"
+               "type":"directory"
             }
          },
          {
             "config":"hawq-site/hawq_segment_directory",
             "widget":{
-               "type":"text-field"
+               "type":"directory"
             }
          },
          {

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py 
b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
index 6e1c148..21b4bff 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.3/services/stack_advisor.py
@@ -17,6 +17,7 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 """
 import os
+import re
 import fnmatch
 import socket
 
@@ -942,6 +943,14 @@ class HDP23StackAdvisor(HDP22StackAdvisor):
                               "It is not advisable to have " + display_name + 
" at " + root_dir +". Consider creating a sub directory for HAWQ")})
 
 
+  def checkForMultipleDirs(self, properties, validationItems, prop_name, 
display_name):
+    # check for delimiters space, comma, colon and semi-colon
+    if prop_name in properties and len(re.sub(r'[,;:]', ' ', 
properties[prop_name]).split(' ')) > 1:
+      validationItems.append({"config-name": prop_name,
+                              "item": self.getErrorItem(
+                              "Multiple directories for " + display_name + " 
are not allowed.")})
+
+
   def validateHAWQSiteConfigurations(self, properties, recommendedDefaults, 
configurations, services, hosts):
     hawq_site = properties
     validationItems = []
@@ -965,6 +974,14 @@ class HDP23StackAdvisor(HDP22StackAdvisor):
     for property_name, display_name in directories.iteritems():
       self.validateIfRootDir(properties, validationItems, property_name, 
display_name)
 
+    # 2.1 Check if any master or segment directories has multiple values
+    directories = {
+                    'hawq_master_directory': 'HAWQ Master directory',
+                    'hawq_segment_directory': 'HAWQ Segment directory'
+                  }
+    for property_name, display_name in directories.iteritems():
+      self.checkForMultipleDirs(properties, validationItems, property_name, 
display_name)
+
     # 3. Check YARN RM address properties
     YARN = "YARN"
     servicesList = [service["StackServices"]["service_name"] for service in 
services["services"]]

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py 
b/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
index dc478d9..38f5415 100644
--- a/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
+++ b/ambari-server/src/test/python/stacks/2.3/common/test_stack_advisor.py
@@ -2021,6 +2021,42 @@ class TestHDP23StackAdvisor(TestCase):
     self.assertEqual(len(problems), 2)
     self.assertEqual(problems_dict, expected_warnings)
 
+    # Test hawq_master_directory multiple directories validation
+    configurations["hawq-site"] = {"properties": {"hawq_master_directory": 
"/data/hawq/master",
+                                                  "hawq_segment_directory": 
"/data/hawq/segment"}}
+    properties = configurations["hawq-site"]["properties"]
+    problems = self.stackAdvisor.validateHAWQSiteConfigurations(properties, 
defaults, configurations, services, hosts)
+    problems_dict = {}
+    self.assertEqual(len(problems), 0)
+    expected_warnings = {}
+    self.assertEqual(problems_dict, expected_warnings)
+
+    configurations["hawq-site"] = {"properties": {"hawq_master_directory": 
"/data/hawq/master1,/data/hawq/master2",
+                                                  "hawq_segment_directory": 
"/data/hawq/segment1 /data/hawq/segment2"}}
+    properties = configurations["hawq-site"]["properties"]
+    problems = self.stackAdvisor.validateHAWQSiteConfigurations(properties, 
defaults, configurations, services, hosts)
+    problems_dict = {}
+    for problem in problems:
+      problems_dict[problem['config-name']] = problem
+    self.assertEqual(len(problems), 2)
+    expected_warnings = {
+      'hawq_master_directory': {
+        'config-type': 'hawq-site',
+        'message': 'Multiple directories for HAWQ Master directory are not 
allowed.',
+        'type': 'configuration',
+        'config-name': 'hawq_master_directory',
+        'level': 'ERROR'
+      },
+      'hawq_segment_directory': {
+        'config-type': 'hawq-site',
+        'message': 'Multiple directories for HAWQ Segment directory are not 
allowed.',
+        'type': 'configuration',
+        'config-name': 'hawq_segment_directory',
+        'level': 'ERROR'
+      }
+    }
+    self.assertEqual(problems_dict, expected_warnings)
+
     # Test hawq_global_rm_type validation
     services = {
                  "services" : [

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 7ef7b7b..2f844c6 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -799,6 +799,7 @@ Em.I18n.translations = {
   'installer.step7.popup.validation.request.failed.body': 'The configuration 
changes could not be validated for consistency due to an unknown error.  Your 
changes have not been saved yet.  Would you like to proceed and save the 
changes?',
   'installer.step7.popup.validation.warning.header': 'Configurations',
   'installer.step7.popup.validation.warning.body': 'Some service 
configurations are not configured properly. We recommend you review and change 
the highlighted configuration values. Are you sure you want to proceed without 
correcting configurations?',
+  'installer.step7.popup.validation.error.body': 'Service configurations 
resulted in validation errors. Please address them before proceeding.',
   'installer.step7.popup.oozie.derby.warning': 'Derby is not recommended for 
production use. With Derby, Oozie Server HA and concurrent connection support 
will not be available.',
   'installer.step7.oozie.database.new': 'New Derby Database',
   'installer.step7.hive.database.new.mysql': 'New MySQL Database',

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/mixins/common/serverValidator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/serverValidator.js 
b/ambari-web/app/mixins/common/serverValidator.js
index ebb68ad..e66e329 100644
--- a/ambari-web/app/mixins/common/serverValidator.js
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -393,7 +393,7 @@ App.ServerValidatorMixin = Em.Mixin.create({
         body: Em.I18n.t('installer.step7.popup.validation.request.failed.body')
       });
     } else if (this.get('configValidationWarning') || 
this.get('configValidationError')) {
-      // Motivation: for server-side validation warnings and EVEN errors allow 
user to continue wizard
+      // Motivation: for server-side validation warnings allow user to 
continue wizard
       var stepConfigs = self.get('name') === 'mainServiceInfoConfigsController'
         ? [self.get('selectedService')]
         : self.get('stepConfigs');
@@ -404,11 +404,13 @@ App.ServerValidatorMixin = Em.Mixin.create({
       });
       if (configsWithErrors) {
         return App.ModalPopup.show({
-          header: Em. 
I18n.t('installer.step7.popup.validation.warning.header'),
+          header: Em.I18n.t('installer.step7.popup.validation.warning.header'),
           classNames: ['sixty-percent-width-modal','modal-full-width'],
           primary: Em.I18n.t('common.proceedAnyway'),
           primaryClass: 'btn-danger',
           marginBottom: 200,
+          // Do not allow "Proceed Anyway" for validation errors
+          disablePrimary: self.get('configValidationError'),
           onPrimary: function () {
             this.hide();
             deferred.resolve();
@@ -424,7 +426,10 @@ App.ServerValidatorMixin = Em.Mixin.create({
           bodyClass: Em.View.extend({
             controller: self,
             templateName: 
require('templates/common/modal_popups/config_recommendation_popup'),
-            serviceConfigs: stepConfigs
+            serviceConfigs: stepConfigs,
+            messageBody: Em.I18n.t(self.get('configValidationError')
+                                 ? 
'installer.step7.popup.validation.error.body'
+                                 : 
'installer.step7.popup.validation.warning.body')
           })
         });
       } else {

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/models/configs/objects/service_config_property.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/configs/objects/service_config_property.js 
b/ambari-web/app/models/configs/objects/service_config_property.js
index 328703a..f063fa0 100644
--- a/ambari-web/app/models/configs/objects/service_config_property.js
+++ b/ambari-web/app/models/configs/objects/service_config_property.js
@@ -351,6 +351,9 @@ App.ServiceConfigProperty = Em.Object.extend({
       case 'directories':
         return App.ServiceConfigTextArea;
         break;
+      case 'directory':
+        return App.ServiceConfigTextField;
+        break;
       case 'content':
         return App.ServiceConfigTextAreaContent;
         break;

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less 
b/ambari-web/app/styles/application.less
index 77834f5..2819a08 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -5824,19 +5824,25 @@ input[type="radio"].align-checkbox, 
input[type="checkbox"].align-checkbox {
   }
 }
 
+@warning-background: #fcf8e3;
+@error-background: #f2dede;
+
 .table td.no-borders { border-top: none; }
-.table td.error { background-color: #f2dede; }
-.table td.warning { background-color: #fcf8e3; }
+.table td.error { background-color: @error-background; }
+.table td.warning { background-color: @warning-background; }
 
 #config-validation-warnings {
   table {
     tbody{
       tr {
-        background:#fcf8e3;
+        &.warning {
+          background: @warning-background;
+        }
+        &.error {
+          background: @error-background;
+        }
         border:1px solid #c09853;
-        border-right:none;
         td {
-          min-width: 150px;
           .property-message {
             font-weight: bold;
           }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs 
b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
index f58e086..4243137 100644
--- 
a/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
+++ 
b/ambari-web/app/templates/common/modal_popups/config_recommendation_popup.hbs
@@ -16,11 +16,12 @@
 * limitations under the License.
 }}
 
-<p>{{t installer.step7.popup.validation.warning.body}}</p>
+<p>{{view.messageBody}}</p>
 <div id="config-validation-warnings" class="limited-height-2">
   <table class="table no-borders">
     <thead>
     <tr>
+      <th>{{t common.type}}</th>
       <th>{{t common.service}}</th>
       <th>{{t common.property}}</th>
       <th>{{t common.value}}</th>
@@ -32,24 +33,34 @@
         {{#each property in service.configs}}
           {{#if property.isVisible}}
             {{#unless property.hiddenBySection}}
-              {{#if property.warn}}
-                <tr>
+              {{#if property.error}}
+                <tr class="error">
+                  <td>{{t common.error}}</td>
                   <td>{{property.serviceName}}</td>
                   <td>{{property.name}}</td>
                   <td>{{property.value}}</td>
                   <td>
-                    <div 
class="property-message">{{property.warnMessage}}</div>
+                    <div 
class="property-message">{{property.errorMessage}}</div>
                     <div 
class="property-description">{{property.description}}</div>
                   </td>
                 </tr>
               {{/if}}
-              {{#if property.error}}
-                <tr>
+            {{/unless}}
+          {{/if}}
+        {{/each}}
+      {{/each}}
+      {{#each service in view.serviceConfigs}}
+        {{#each property in service.configs}}
+          {{#if property.isVisible}}
+            {{#unless property.hiddenBySection}}
+              {{#if property.warn}}
+                <tr class="warning">
+                  <td>{{t common.warning}}</td>
                   <td>{{property.serviceName}}</td>
                   <td>{{property.name}}</td>
                   <td>{{property.value}}</td>
                   <td>
-                    <div 
class="property-message">{{property.errorMessage}}</div>
+                    <div 
class="property-message">{{property.warnMessage}}</div>
                     <div 
class="property-description">{{property.description}}</div>
                   </td>
                 </tr>

http://git-wip-us.apache.org/repos/asf/ambari/blob/fc733879/ambari-web/app/views/common/configs/service_config_layout_tab_view.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/views/common/configs/service_config_layout_tab_view.js 
b/ambari-web/app/views/common/configs/service_config_layout_tab_view.js
index 9029448..13d009e 100644
--- a/ambari-web/app/views/common/configs/service_config_layout_tab_view.js
+++ b/ambari-web/app/views/common/configs/service_config_layout_tab_view.js
@@ -55,7 +55,7 @@ App.ServiceConfigLayoutTabView = 
Em.View.extend(App.ConfigOverridable, {
   widgetTypeMap: {
     checkbox: App.CheckboxConfigWidgetView,
     combo: App.ComboConfigWidgetView,
-    directory: App.DirectoryConfigWidgetView,
+    directory: App.TextFieldConfigWidgetView,
     directories: App.DirectoryConfigWidgetView,
     list: App.ListConfigWidgetView,
     password: App.PasswordConfigWidgetView,

Reply via email to