You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2016/07/26 08:30:05 UTC

ambari git commit: AMBARI-17041. Support password type for custom properties (alexantonenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 08644fa7c -> 2fb19c7b1


AMBARI-17041. Support password type for custom properties (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 2fb19c7b1a0497a40df8d11e7d426190836d6a24
Parents: 08644fa
Author: Alex Antonenko <hi...@gmail.com>
Authored: Tue Jul 26 11:29:37 2016 +0300
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Tue Jul 26 11:30:00 2016 +0300

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         | 35 ++++++++++++----
 .../controller/ConfigurationResponse.java       |  2 +
 .../ambari/server/utils/SecretReference.java    | 23 +++++++++++
 ambari-web/app/messages.js                      |  1 +
 .../app/mixins/common/configs/configs_saver.js  |  9 +++-
 .../configs/objects/service_config_property.js  |  7 ++++
 .../common/configs/addPropertyWindow.hbs        | 12 ++++++
 ambari-web/app/utils/config.js                  | 27 ++++++++++--
 .../configs/service_configs_by_category_view.js |  5 +++
 .../mixins/common/configs/configs_saver_test.js | 43 ++++++++++++++++++--
 10 files changed, 149 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index aba45bf..075b85a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -224,6 +224,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
   private static final String BASE_LOG_DIR = "/tmp/ambari";
 
+  private static final String PASSWORD = "password";
+
   private final Clusters clusters;
 
   private final ActionManager actionManager;
@@ -810,6 +812,25 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
     Map<String, String> requestProperties = request.getProperties();
 
+    // Configuration attributes are optional. If not present, use default(provided by stack), otherwise merge default
+    // with request-provided
+    Map<String, Map<String, String>> requestPropertiesAttributes = request.getPropertiesAttributes();
+
+    if (requestPropertiesAttributes != null && requestPropertiesAttributes.containsKey(PASSWORD)) {
+      for (Map.Entry<String, String> requestEntry : requestPropertiesAttributes.get(PASSWORD).entrySet()) {
+        String passwordProperty = requestEntry.getKey();
+        if(requestProperties.containsKey(passwordProperty) && requestEntry.getValue().equals("true")) {
+          String passwordPropertyValue = requestProperties.get(passwordProperty);
+          if (!SecretReference.isSecret(passwordPropertyValue)) {
+            continue;
+          }
+          SecretReference ref = new SecretReference(passwordPropertyValue, cluster);
+          String refValue = ref.getValue();
+          requestProperties.put(passwordProperty, refValue);
+        }
+      }
+    }
+
     Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = cluster.getConfigPropertiesTypes(request.getType());
     if(propertiesTypes.containsKey(PropertyType.PASSWORD)) {
       for(String passwordProperty : propertiesTypes.get(PropertyType.PASSWORD)) {
@@ -833,10 +854,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
       configs = new HashMap<String, Config>();
     }
 
-    // Configuration attributes are optional. If not present, use default(provided by stack), otherwise merge default
-    // with request-provided
-    Map<String, Map<String, String>> requestPropertiesAttributes = request.getPropertiesAttributes();
-
     Map<String, Map<String, String>> propertiesAttributes = new HashMap<String, Map<String,String>>();
 
     StackId currentStackId = cluster.getCurrentStackVersion();
@@ -1531,6 +1548,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     if (request.getDesiredConfig() != null) {
       for (ConfigurationRequest desiredConfig : request.getDesiredConfig()) {
         Map<String, String> requestConfigProperties = desiredConfig.getProperties();
+        Map<String,Map<String,String>> requestConfigAttributes = desiredConfig.getPropertiesAttributes();
 
         // processing password properties
         if(requestConfigProperties != null && !requestConfigProperties.isEmpty()) {
@@ -1540,8 +1558,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
           for (Entry<String, String> property : requestConfigProperties.entrySet()) {
             String propertyName = property.getKey();
             String propertyValue = property.getValue();
-            if (propertiesTypes.containsKey(PropertyType.PASSWORD) &&
-                propertiesTypes.get(PropertyType.PASSWORD).contains(propertyName)) {
+            if ((propertiesTypes.containsKey(PropertyType.PASSWORD) &&
+                propertiesTypes.get(PropertyType.PASSWORD).contains(propertyName)) ||
+                (requestConfigAttributes != null && requestConfigAttributes.containsKey(PASSWORD) &&
+                requestConfigAttributes.get(PASSWORD).containsKey(propertyName) &&
+                requestConfigAttributes.get(PASSWORD).get(propertyName).equals("true"))) {
               if (SecretReference.isSecret(propertyValue)) {
                 SecretReference ref = new SecretReference(propertyValue, cluster);
                 requestConfigProperties.put(propertyName, ref.getValue());
@@ -1549,7 +1570,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
             }
           }
         }
-        Map<String,Map<String,String>> requestConfigAttributes = desiredConfig.getPropertiesAttributes();
+
         Config clusterConfig = cluster.getDesiredConfigByType(desiredConfig.getType());
         Map<String, String> clusterConfigProperties = null;
         Map<String,Map<String,String>> clusterConfigAttributes = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
index eef3474..8632c09 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
@@ -63,6 +63,7 @@ public class ConfigurationResponse {
     this.version = version;
     this.configs = configs;
     this.configAttributes = configAttributes;
+    SecretReference.replacePasswordsWithReferencesForCustomProperties(configAttributes, configs, type, version);
   }
 
   public ConfigurationResponse(String clusterName, StackId stackId,
@@ -80,6 +81,7 @@ public class ConfigurationResponse {
     this.configAttributes = configAttributes;
     this.propertiesTypes = propertiesTypes;
     SecretReference.replacePasswordsWithReferences(propertiesTypes, configs, type, version);
+    SecretReference.replacePasswordsWithReferencesForCustomProperties(configAttributes, configs, type, version);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
index 84f3109..9788569 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
@@ -148,4 +148,27 @@ public class SecretReference {
       }
     }
   }
+
+  /**
+   * Replace real passwords with secret references
+   * @param configAttributes map with config attributes containing properties types as part of their content
+   * @param propertiesMap map with properties in which replacement will be performed
+   * @param configType configuration type
+   * @param configVersion configuration version
+   */
+  public static void replacePasswordsWithReferencesForCustomProperties(Map<String, Map<String, String>> configAttributes,
+                                                    Map<String, String> propertiesMap,
+                                                    String configType,
+                                                    Long configVersion){
+    if(configAttributes != null && configAttributes.containsKey("password")) {
+      for(String pwdPropertyName: configAttributes.get("password").keySet()) {
+        if(propertiesMap.containsKey(pwdPropertyName)){
+          if(!propertiesMap.get(pwdPropertyName).equals("")) {
+            String stub = SecretReference.generateStub(configType, configVersion, pwdPropertyName);
+            propertiesMap.put(pwdPropertyName, stub);
+          }
+        }
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index c768749..c6aa350 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -313,6 +313,7 @@ Em.I18n.translations = {
   'common.timezone': 'Timezone',
   'common.loading.eclipses': 'Loading...',
   'common.optional': 'Optional',
+  'common.propertyType': 'Property Type',
   'common.running': 'Running',
   'common.stopped': 'Stopped',
   'common.enter': 'Enter',

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/app/mixins/common/configs/configs_saver.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/configs_saver.js b/ambari-web/app/mixins/common/configs/configs_saver.js
index 43a77ce..832ec3a 100644
--- a/ambari-web/app/mixins/common/configs/configs_saver.js
+++ b/ambari-web/app/mixins/common/configs/configs_saver.js
@@ -454,7 +454,7 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     if (!ignoreVersionNote) {
       desired_config.service_config_version_note = serviceConfigNote || "";
     }
-    var attributes = { final: {} };
+    var attributes = { final: {}, password: {}, user: {}, group: {}, text: {}, additional_user_property: {}, not_managed_hdfs_path: {}, value_from_property_file: {} };
     if (Em.isArray(properties)) {
       properties.forEach(function(property) {
 
@@ -466,11 +466,16 @@ App.ConfigsSaverMixin = Em.Mixin.create({
           if (Em.get(property, 'isFinal')) {
             attributes.final[Em.get(property, 'name')] = "true";
           }
+          if (Em.get(property,'propertyType') != null) {
+            Em.get(property,'propertyType').map(function(propType) {
+              attributes[propType.toLowerCase()][Em.get(property,'name')] = "true";
+            });
+          }
         }
       }, this);
     }
 
-    if (Object.keys(attributes.final).length) {
+    if (Object.keys(attributes.final).length || Object.keys(attributes.password).length) {
       desired_config.properties_attributes = attributes;
     }
     return desired_config;

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/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 844806f..becbd19b 100644
--- a/ambari-web/app/models/configs/objects/service_config_property.js
+++ b/ambari-web/app/models/configs/objects/service_config_property.js
@@ -95,6 +95,13 @@ App.ServiceConfigProperty = Em.Object.extend({
   rightSideLabel: false,
 
   /**
+   * type of property
+   * @type {String[]}
+   * @default empty array
+   */
+  propertyType: [],
+
+  /**
    * Text to be shown as placeholder
    * By default savedValue is shown as placeholder
    * @type {String}

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/app/templates/common/configs/addPropertyWindow.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/configs/addPropertyWindow.hbs b/ambari-web/app/templates/common/configs/addPropertyWindow.hbs
index 659435c..1d41b04 100644
--- a/ambari-web/app/templates/common/configs/addPropertyWindow.hbs
+++ b/ambari-web/app/templates/common/configs/addPropertyWindow.hbs
@@ -87,5 +87,17 @@
         {{view Ember.TextArea valueBinding="view.serviceConfigObj.value" rows="4" classNames="input-block-level"}}
       </div>
     </div>
+    <div class="each-row control-group">
+      <label class="control-label">{{t common.propertyType}}</label>
+
+      <div class="controls">
+        {{view Em.Select
+            classNames="input-block-level"
+            multiple="multiple"
+            contentBinding="view.serviceConfigObj.content"
+            selectionBinding="view.serviceConfigObj.propertyType"
+        }}
+      </div>
+    </div>
   {{/if}}
 </form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 9bb977a..20202e4 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -22,6 +22,7 @@ var stringUtils = require('utils/string_utils');
 var validator = require('utils/validator');
 
 var configTagFromFileNameMap = {};
+var PASSWORD = "PASSWORD";
 
 App.config = Em.Object.create({
 
@@ -237,14 +238,34 @@ App.config = Em.Object.create({
     var configs = [],
       filename = App.config.getOriginalFileName(configJSON.type),
       properties = configJSON.properties,
-      finalAttributes = Em.get(configJSON, 'properties_attributes.final') || {};
+      attributes = [];
+      ['FINAL', 'PASSWORD', 'USER', 'GROUP', 'TEXT', 'ADDITIONAL_USER_PROPERTY', 'NOT_MANAGED_HDFS_PATH', 'VALUE_FROM_PROPERTY_FILE'].forEach(function (attribute){
+        var json = {};
+        json[attribute] = Em.get(configJSON, 'properties_attributes.' + attribute.toLowerCase()) || {};
+        attributes.push(json);
+      });
 
     for (var index in properties) {
       var serviceConfigObj = this.getDefaultConfig(index, filename);
 
       if (serviceConfigObj.isRequiredByAgent !== false) {
         serviceConfigObj.value = serviceConfigObj.savedValue = this.formatPropertyValue(serviceConfigObj, properties[index]);
-        serviceConfigObj.isFinal = serviceConfigObj.savedIsFinal = finalAttributes[index] === "true";
+        serviceConfigObj.isFinal = serviceConfigObj.savedIsFinal = attributes[0]['FINAL'][index] === "true";
+
+        var propertyType = [];
+        // iterate through all the attributes, except for FINAL
+        for (var i=1; i<attributes.length; i++) {
+          for (var type in attributes[i]) {
+            if (attributes[i][type][index] === "true") {
+              propertyType.push(type);
+
+              if (type === PASSWORD) {
+                serviceConfigObj.displayType = "password";
+              }
+            }
+          }
+        }
+        serviceConfigObj.propertyType = propertyType;
         serviceConfigObj.isEditable = serviceConfigObj.isReconfigurable;
       }
 
@@ -305,7 +326,7 @@ App.config = Em.Object.create({
       supportsAddingForbidden: this.shouldSupportAddingForbidden(serviceName, fileName),
       serviceName: serviceName,
       displayName: name,
-      displayType: this.getDefaultDisplayType(coreObject ? coreObject.value : ''),
+      displayType: (coreObject && coreObject.propertyType && coreObject.propertyType.contains(PASSWORD)) ? 'password' : this.getDefaultDisplayType(coreObject ? coreObject.value : ''),
       description: '',
       category: this.getDefaultCategory(definedInStack, fileName),
       isSecureConfig: this.getIsSecure(name),

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/service_configs_by_category_view.js b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
index ad1a2f9..579348a 100644
--- a/ambari-web/app/views/common/configs/service_configs_by_category_view.js
+++ b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
@@ -346,6 +346,7 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, App.ConfigOverri
     if (selectedConfigGroup.get('isDefault')) {
       config = App.config.createDefaultConfig(propertyObj.name, propertyObj.filename, false, {
         value: propertyObj.value,
+        propertyType: propertyObj.propertyType,
         category: propertyObj.categoryName,
         isNotSaved: true
       });
@@ -354,6 +355,7 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, App.ConfigOverri
         propertyName: propertyObj.name,
         filename: propertyObj.filename,
         value: propertyObj.value,
+        propertyType: propertyObj.propertyType,
         category: propertyObj.categoryName,
         isNotSaved: true
       }, selectedConfigGroup);
@@ -416,6 +418,8 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, App.ConfigOverri
 
           name: '',
           value: '',
+          propertyType: [],
+          content: ['PASSWORD', 'USER', 'GROUP', 'TEXT', 'ADDITIONAL_USER_PROPERTY', 'NOT_MANAGED_HDFS_PATH', 'VALUE_FROM_PROPERTY_FILE'],
           isKeyError: false,
           showFilterLink: false,
           errorMessage: '',
@@ -540,6 +544,7 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, App.ConfigOverri
               if (!serviceConfigObj.isKeyError) {
                 propertyObj.name = serviceConfigObj.get('name');
                 propertyObj.value = serviceConfigObj.get('value');
+                propertyObj.propertyType = serviceConfigObj.get('propertyType');
                 persistController.createProperty(propertyObj);
                 this.hide();
               }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2fb19c7b/ambari-web/test/mixins/common/configs/configs_saver_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/configs_saver_test.js b/ambari-web/test/mixins/common/configs/configs_saver_test.js
index 4baf303..74e630b 100644
--- a/ambari-web/test/mixins/common/configs/configs_saver_test.js
+++ b/ambari-web/test/mixins/common/configs/configs_saver_test.js
@@ -150,17 +150,54 @@ describe('App.ConfigsSaverMixin', function() {
       })
     });
 
-    it('generates config with final', function() {
-      expect(instanceObject.createDesiredConfig('type1', 'version1', [Em.Object.create({name: 'p1', value: 'v1', isFinal: true, isRequiredByAgent: true}), Em.Object.create({name: 'p2', value: 'v2', isRequiredByAgent: true})], "note")).to.eql({
+    it('generates config with final, password, user, group, text, additional_user_property, not_managed_hdfs_path, value_from_property_file', function() {
+      expect(instanceObject.createDesiredConfig('type1', 'version1', [
+          Em.Object.create({name: 'p1', value: 'v1', isFinal: true, isRequiredByAgent: true}),
+          Em.Object.create({name: 'p2', value: 'v2', isRequiredByAgent: true}),
+          Em.Object.create({name: 'p3', value: 'v3', isRequiredByAgent: true, propertyType: ["PASSWORD", "USER", "GROUP"]}),
+          Em.Object.create({name: 'p4', value: 'v4', isRequiredByAgent: true, propertyType: ["PASSWORD", "TEXT", "ADDITIONAL_USER_PROPERTY"]}),
+          Em.Object.create({name: 'p5', value: 'v5', isRequiredByAgent: true, propertyType: ["NOT_MANAGED_HDFS_PATH"]}),
+          Em.Object.create({name: 'p6', value: 'v6', isRequiredByAgent: true, propertyType: ["TEXT", "VALUE_FROM_PROPERTY_FILE"]}),
+          Em.Object.create({name: 'p7', value: 'v7', isRequiredByAgent: true, propertyType: ["PASSWORD"]})
+        ], "note")).to.eql({
         "type": 'type1',
         "tag": 'version1',
         "properties": {
           p1: 'v1',
-          p2: 'v2'
+          p2: 'v2',
+          p3: 'v3',
+          p4: 'v4',
+          p5: 'v5',
+          p6: 'v6',
+          p7: 'v7'
         },
         "properties_attributes": {
           final: {
             'p1': "true"
+          },
+          password: {
+            "p3": "true",
+            "p4": "true",
+            "p7": "true"
+          },
+          user: {
+            "p3": "true"
+          },
+          group: {
+            "p3": "true"
+          },
+          text: {
+            "p4": "true",
+            "p6": "true"
+          },
+          additional_user_property: {
+            "p4": "true"
+          },
+          not_managed_hdfs_path: {
+            "p5": "true"
+          },
+          value_from_property_file: {
+            "p6": "true"
           }
         },
         "service_config_version_note": 'note'