You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/07/19 12:39:03 UTC

[10/21] ambari git commit: AMBARI-21483. Add UID/GID related enhancements (echekanskiy)

AMBARI-21483. Add UID/GID related enhancements (echekanskiy)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: f92d12193b30d53dc06ab9642ef4b9d61b5bac1c
Parents: 56462b2
Author: Eugene Chekanskiy <ec...@hortonworks.com>
Authored: Sun Jul 16 20:22:34 2017 +0300
Committer: Eugene Chekanskiy <ec...@hortonworks.com>
Committed: Sun Jul 16 20:22:34 2017 +0300

----------------------------------------------------------------------
 .../ambari/server/state/PropertyInfo.java       |   2 +
 .../hooks/before-ANY/files/changeToSecureUid.sh |  13 +-
 .../before-ANY/scripts/shared_initialization.py |  45 ++-
 .../2.0.6/hooks/before-ANY/test_before_any.py   | 294 +++++++++++--------
 .../app/controllers/wizard/step7_controller.js  |  67 +++++
 .../configs/stack_config_properties_mapper.js   |  14 +-
 ambari-web/app/styles/application.less          |  15 +
 ...ontrols_service_config_usergroup_with_id.hbs |  27 ++
 ambari-web/app/utils/config.js                  |   3 +
 .../configs/service_configs_by_category_view.js |   6 +
 ambari-web/app/views/common/controls_view.js    |  39 +++
 11 files changed, 392 insertions(+), 133 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
index 62396e3..63c850e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/PropertyInfo.java
@@ -281,7 +281,9 @@ public class PropertyInfo {
   public enum PropertyType {
     PASSWORD,
     USER,
+    UID,
     GROUP,
+    GID,
     TEXT,
     ADDITIONAL_USER_PROPERTY,
     NOT_MANAGED_HDFS_PATH,

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/files/changeToSecureUid.sh
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/files/changeToSecureUid.sh b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/files/changeToSecureUid.sh
index 08542c4..4663f10 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/files/changeToSecureUid.sh
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/files/changeToSecureUid.sh
@@ -21,6 +21,7 @@
 
 username=$1
 directories=$2
+newUid=$3
 
 function find_available_uid() {
  for ((i=1001; i<=2000; i++))
@@ -34,7 +35,16 @@ function find_available_uid() {
  done
 }
 
-find_available_uid
+if [ -z $2 ]; then
+  test $(id -u ${username} 2>/dev/null)
+  if [ $? -ne 1 ]; then
+   newUid=`id -u ${username}`
+  else
+   find_available_uid
+  fi
+  echo $newUid
+  exit 0
+fi
 
 if [ $newUid -eq 0 ]
 then
@@ -43,7 +53,6 @@ then
 fi
 
 set -e
-
 dir_array=($(echo $directories | sed 's/,/\n/g'))
 old_uid=$(id -u $username)
 sudo_prefix="/var/lib/ambari-agent/ambari-sudo.sh -H -E"

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
index 39f5a47..bcc1a3a 100644
--- a/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
+++ b/ambari-server/src/main/resources/stacks/HDP/2.0.6/hooks/before-ANY/scripts/shared_initialization.py
@@ -24,6 +24,7 @@ import tempfile
 from copy import copy
 from resource_management.libraries.functions.version import compare_versions
 from resource_management import *
+from resource_management.core import shell
 
 def setup_users():
   """
@@ -43,11 +44,17 @@ def setup_users():
       )
 
     for user in params.user_list:
-      User(user,
-          gid = params.user_to_gid_dict[user],
-          groups = params.user_to_groups_dict[user],
-          fetch_nonlocal_groups = params.fetch_nonlocal_groups
-      )
+      if params.override_uid == "true":
+        User(user,
+             uid = get_uid(user),
+             gid = params.user_to_gid_dict[user],
+             groups = params.user_to_groups_dict[user],
+             )
+      else:
+        User(user,
+             gid = params.user_to_gid_dict[user],
+             groups = params.user_to_groups_dict[user],
+             )
 
     if params.override_uid == "true":
       set_uid(params.smoke_user, params.smoke_user_dirs)
@@ -65,6 +72,7 @@ def setup_users():
                create_parents = True,
                cd_access="a",
     )
+
     if params.override_uid == "true":
       set_uid(params.hbase_user, params.hbase_user_dirs)
     else:
@@ -125,7 +133,7 @@ def create_users_and_groups(user_and_groups):
     Group(copy(groups_list),
     )
   return groups_list
-    
+
 def set_uid(user, user_dirs):
   """
   user_dirs - comma separated directories
@@ -136,9 +144,30 @@ def set_uid(user, user_dirs):
        content=StaticFile("changeToSecureUid.sh"),
        mode=0555)
   ignore_groupsusers_create_str = str(params.ignore_groupsusers_create).lower()
-  Execute(format("{tmp_dir}/changeUid.sh {user} {user_dirs}"),
+  uid = get_uid(user)
+  Execute(format("{tmp_dir}/changeUid.sh {user} {user_dirs} {uid}"),
           not_if = format("(test $(id -u {user}) -gt 1000) || ({ignore_groupsusers_create_str})"))
-    
+
+def get_uid(user):
+  import params
+  user_str = str(user) + "_uid"
+  service_env = [ serviceEnv for serviceEnv in params.config['configurations'] if user_str in params.config['configurations'][serviceEnv]]
+
+  if service_env and params.config['configurations'][service_env[0]][user_str]:
+    service_env_str = str(service_env[0])
+    uid = params.config['configurations'][service_env_str][user_str]
+    if len(service_env) > 1:
+      Logger.warning("Multiple values found for %s, using %s"  % (user_str, uid))
+    return uid
+  else:
+    if user == params.smoke_user:
+      return 0
+    File(format("{tmp_dir}/changeUid.sh"),
+         content=StaticFile("changeToSecureUid.sh"),
+         mode=0555)
+    conde, newUid = shell.call((format("{tmp_dir}/changeUid.sh"), format("{user}")), sudo=True)
+    return newUid
+
 def setup_hadoop_env():
   import params
   stackversion = params.stack_version_unformatted

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py b/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
index 75c6543..1d2351f 100644
--- a/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
+++ b/ambari-server/src/test/python/stacks/2.0.6/hooks/before-ANY/test_before_any.py
@@ -21,6 +21,7 @@ limitations under the License.
 from stacks.utils.RMFTestCase import *
 from mock.mock import MagicMock, call, patch
 from resource_management import Hook
+import itertools
 import getpass
 import os
 
@@ -45,147 +46,201 @@ class TestHookBeforeInstall(RMFTestCase):
     self.executeScript("2.0.6/hooks/before-ANY/scripts/hook.py",
                        classname="BeforeAnyHook",
                        command="hook",
-                       config_file="default.json"
-    )
-
-    self.assertResourceCalled('Group', 'hadoop',
-    )
-    self.assertResourceCalled('Group', 'nobody',
-    )
-    self.assertResourceCalled('Group', 'users',
+                       config_file="default.json",
+                       call_mocks=itertools.cycle([(0, "1000")])
     )
+    self.assertResourceCalled('Group', 'hadoop',)
+    self.assertResourceCalled('Group', 'nobody',)
+    self.assertResourceCalled('Group', 'users',)
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'hive',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'oozie',
-        gid = 'hadoop',
-        groups = [u'users'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'users'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'nobody',
-        gid = 'hadoop',
-        groups = [u'nobody'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'nobody'],
+                              )
     self.assertResourceCalled('User', 'ambari-qa',
-        gid = 'hadoop',
-        groups = [u'users'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = 0,
+                              groups = [u'users'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'flume',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'hdfs',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'storm',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'mapred',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'hbase',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'tez',
-        gid = 'hadoop',
-        groups = [u'users'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'users'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'zookeeper',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'falcon',
-        gid = 'hadoop',
-        groups = [u'users'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'users'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'sqoop',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'yarn',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
     self.assertResourceCalled('User', 'hcat',
-        gid = 'hadoop',
-        groups = [u'hadoop'],
-        fetch_nonlocal_groups = True,
-    )
+                              gid = 'hadoop',
+                              uid = '1000',
+                              groups = [u'hadoop'],
+                              )
     self.assertResourceCalled('File', '/tmp/changeUid.sh',
-        content = StaticFile('changeToSecureUid.sh'),
-        mode = 0555,
-    )
-    self.assertResourceCalled('Execute', '/tmp/changeUid.sh ambari-qa /tmp/hadoop-ambari-qa,/tmp/hsperfdata_ambari-qa,/home/ambari-qa,/tmp/ambari-qa,/tmp/sqoop-ambari-qa',
-        not_if = '(test $(id -u ambari-qa) -gt 1000) || (false)',
-    )
-    self.assertResourceCalled('Directory', self.TMP_PATH,
-        owner = 'hbase',
-        mode = 0775,
-        create_parents = True,
-        cd_access='a'
-    )
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
+    self.assertResourceCalled('Execute', '/tmp/changeUid.sh ambari-qa /tmp/hadoop-ambari-qa,/tmp/hsperfdata_ambari-qa,/home/ambari-qa,/tmp/ambari-qa,/tmp/sqoop-ambari-qa 0',
+                              not_if = '(test $(id -u ambari-qa) -gt 1000) || (false)',
+                              )
+    self.assertResourceCalled('Directory', '/tmp/hbase-hbase',
+                              owner = 'hbase',
+                              create_parents = True,
+                              mode = 0775,
+                              cd_access = 'a',
+                              )
     self.assertResourceCalled('File', '/tmp/changeUid.sh',
-        content = StaticFile('changeToSecureUid.sh'),
-        mode = 0555,
-    )
-    self.assertResourceCalled('Execute', '/tmp/changeUid.sh hbase /home/hbase,/tmp/hbase,/usr/bin/hbase,/var/log/hbase,' + self.TMP_PATH,
-        not_if = '(test $(id -u hbase) -gt 1000) || (false)',
-    )
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
+    self.assertResourceCalled('File', '/tmp/changeUid.sh',
+                              content = StaticFile('changeToSecureUid.sh'),
+                              mode = 0555,
+                              )
+    self.assertResourceCalled('Execute', '/tmp/changeUid.sh hbase /home/hbase,/tmp/hbase,/usr/bin/hbase,/var/log/hbase,/tmp/hbase-hbase 1000',
+                              not_if = '(test $(id -u hbase) -gt 1000) || (false)',
+                              )
     self.assertResourceCalled('User', 'test_user1',
-        fetch_nonlocal_groups = True,
-    )
+                              fetch_nonlocal_groups = True,
+                              )
     self.assertResourceCalled('User', 'test_user2',
-        fetch_nonlocal_groups = True,
-    )
-    self.assertResourceCalled('Group', 'hdfs',
-    )
-    self.assertResourceCalled('Group', 'test_group',
-    )
+                              fetch_nonlocal_groups = True,
+                              )
+    self.assertResourceCalled('Group', 'hdfs',)
+    self.assertResourceCalled('Group', 'test_group',)
     self.assertResourceCalled('User', 'hdfs',
-        groups = [u'hadoop', u'hdfs', u'test_group'],
-        fetch_nonlocal_groups = True,
-    )
+                              fetch_nonlocal_groups = True,
+                              groups = [u'hadoop', u'hdfs', u'test_group'],
+                              )
     self.assertResourceCalled('Directory', '/etc/hadoop',
-        mode = 0755
-    )
+                              mode = 0755,
+                              )
     self.assertResourceCalled('Directory', '/etc/hadoop/conf.empty',
-        owner = 'root',
-        group = 'hadoop',
-        create_parents = True,
-    )
+                              owner = 'root',
+                              create_parents = True,
+                              group = 'hadoop',
+                              )
     self.assertResourceCalled('Link', '/etc/hadoop/conf',
-        not_if = 'ls /etc/hadoop/conf',
-        to = '/etc/hadoop/conf.empty',
-    )
+                              not_if = 'ls /etc/hadoop/conf',
+                              to = '/etc/hadoop/conf.empty',
+                              )
     self.assertResourceCalled('File', '/etc/hadoop/conf/hadoop-env.sh',
-        content = InlineTemplate(self.getConfig()['configurations']['hadoop-env']['content']),
-        owner = 'hdfs',
-        group = 'hadoop'
+                              content = InlineTemplate(self.getConfig()['configurations']['hadoop-env']['content']),
+                              owner = 'hdfs',
+                              group = 'hadoop'
     )
     self.assertResourceCalled('Directory', '/tmp/hadoop_java_io_tmpdir',
                               owner = 'hdfs',
                               group = 'hadoop',
-                              mode = 01777
-    )
-
+                              mode = 01777,
+                              )
     self.assertResourceCalled('Directory', '/tmp/AMBARI-artifacts/',
                               create_parents = True,
                               )
@@ -198,20 +253,17 @@ class TestHookBeforeInstall(RMFTestCase):
                               )
     self.assertResourceCalled('Directory', '/usr/jdk64',)
     self.assertResourceCalled('Execute', ('chmod', 'a+x', u'/usr/jdk64'),
-                              sudo = True
-                              )
-    self.assertResourceCalled('Execute', 'cd /tmp/jdk_tmp_dir && tar -xf /tmp/jdk-7u67-linux-x64.tar.gz && ambari-sudo.sh cp -rp /tmp/jdk_tmp_dir/* /usr/jdk64'
+                              sudo = True,
                               )
+    self.assertResourceCalled('Execute', 'cd /tmp/jdk_tmp_dir && tar -xf /tmp/jdk-7u67-linux-x64.tar.gz && ambari-sudo.sh cp -rp /tmp/jdk_tmp_dir/* /usr/jdk64',)
     self.assertResourceCalled('Directory', '/tmp/jdk_tmp_dir',
-                              action = ['delete']
+                              action = ['delete'],
                               )
-
     self.assertResourceCalled('File', '/usr/jdk64/jdk1.7.0_45/bin/java',
                               mode = 0755,
-                              cd_access = "a",
+                              cd_access = 'a',
                               )
     self.assertResourceCalled('Execute', ('chmod', '-R', '755', u'/usr/jdk64/jdk1.7.0_45'),
-      sudo = True,
-    )
-
+                              sudo = True,
+                              )
     self.assertNoMoreResources()

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/controllers/wizard/step7_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js
index 9a897d0..6a90c26 100644
--- a/ambari-web/app/controllers/wizard/step7_controller.js
+++ b/ambari-web/app/controllers/wizard/step7_controller.js
@@ -531,6 +531,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
     }
     var stepConfigs = this.createStepConfigs();
     var serviceConfigs = this.renderConfigs(stepConfigs, configs);
+    this.addUidAndGidRepresentations(serviceConfigs);
     // if HA is enabled -> Make some reconfigurations
     if (this.get('wizardController.name') === 'addServiceController') {
       this.updateComponentActionConfigs(configs, serviceConfigs);
@@ -802,6 +803,38 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
   },
 
   /**
+   * Set the uid property for user properties. The uid is later used to help map the user and uid values in adjacent columns
+   * @param {object} miscSvc
+   * @param {string} svcName
+   * @private
+   */
+  _setUID: function (miscSvc, svcName) {
+    var user = miscSvc.configs.findProperty('name', svcName + '_user');
+    if (user) {
+      var uid = miscSvc.configs.findProperty('name', user.value + '_uid');
+      if (uid) {
+        user.set('ugid', uid);
+      }
+    }
+  },
+
+  /**
+   * Set the gid property for group properties. The gid is later used to help map the group and gid values in adjacent columns
+   * @param {object} miscSvc
+   * @param {string} svcName
+   * @private
+   */
+  _setGID: function (miscSvc, svcName) {
+    var group = miscSvc.configs.findProperty('name', svcName + '_group');
+    if (group) {
+      var gid = miscSvc.configs.findProperty('name', group.value + '_gid');
+      if (gid) {
+        group.set('ugid', gid);
+      }
+    }
+  },
+
+  /**
    * render configs, distribute them by service
    * and wrap each in ServiceConfigProperty object
    * @param stepConfigs
@@ -841,6 +874,11 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
       this.updateHostOverrides(serviceConfigProperty, _config);
       if (this.get('wizardController.name') === 'addServiceController') {
         this._updateIsEditableFlagForConfig(serviceConfigProperty, true);
+        //since the override_uid and ignore_groupusers_create changes are not saved to the database post install, they should be editable only
+        //during initial cluster installation
+        if (['override_uid', 'ignore_groupsusers_create'].contains(serviceConfigProperty.get('name'))) {
+          serviceConfigProperty.set('isEditable', false);
+        }
       }
       if (!this.get('content.serviceConfigProperties.length') && !serviceConfigProperty.get('hasInitialValue')) {
         App.ConfigInitializer.initialValue(serviceConfigProperty, localDB, dependencies);
@@ -860,6 +898,35 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E
     return stepConfigs;
   },
 
+  addUidAndGidRepresentations: function(serviceConfigs) {
+    //map the uids to the corresponding users
+    var miscSvc = serviceConfigs.findProperty('serviceName', 'MISC');
+    if (miscSvc) {
+      //iterate through the list of users and groups and assign the uid/gid accordingly
+      //user properties are servicename_user
+      //uid properties are value of servicename_user + _uid
+      //group properties are servicename_group
+      //gid properties are value of servicename_group + _gid
+      //we will map the users/uids and groups/gids based on this assumption
+      this.get('selectedServiceNames').forEach(function (serviceName) {
+        this._setUID(miscSvc, serviceName.toLowerCase());
+        this._setGID(miscSvc, serviceName.toLowerCase());
+      }, this);
+
+      //for zookeeper, the user property name does not follow the convention that users for other services do. i.e. the user property name is not servicename_user as is the case with other services
+      //the user property name is zk_user and not zookeeper_user, hence set the uid for zk_user separately
+      this._setUID(miscSvc, 'zk');
+      //the user property name is mapred_user and not mapreduce2_user for mapreduce2 service, hence set the uid for mapred_user separately
+      this._setUID(miscSvc, 'mapred');
+      //for haddop, the group property name does not follow the convention that groups for other services do. i.e. the group property name is not servicename_group as is the case with other services
+      //the group property name is user_group and not zookeeper_group, hence set the gid for user_group separately
+      this._setGID(miscSvc, 'user');
+
+      // uid/gid properties are displayed in a separate column, hence prevent the properties from showing up on a separate line
+      miscSvc.configs.filterProperty('displayType', 'uid_gid').setEach('isVisible', false);
+    }
+  },
+
   /**
    * Add host name properties to appropriate categories (for installer and add service)
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/configs/stack_config_properties_mapper.js b/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
index 9b4b920..75a5564 100644
--- a/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
+++ b/ambari-web/app/mappers/configs/stack_config_properties_mapper.js
@@ -197,9 +197,14 @@ App.stackConfigPropertiesMapper = App.QuickDataMapper.create({
    * @param config
    */
   handleSpecialProperties: function(config) {
-    if (!config.StackConfigurations.property_type.contains('ADDITIONAL_USER_PROPERTY')) {
+    var types = config.StackConfigurations.property_type;
+    if (!types.contains('ADDITIONAL_USER_PROPERTY')) {
       config.index = App.StackService.displayOrder.indexOf(config.StackConfigurations.service_name) + 1 || 30;
     }
+    // displayType from stack ignored, cause UID and GID should be shown along with service's user config
+    if (types.contains('UID') || types.contains('GID')) {
+      config.StackConfigurations.property_value_attributes.type = 'uid_gid';
+    }
     config.StackConfigurations.service_name = 'MISC';
     config.category = 'Users and Groups';
   },
@@ -210,7 +215,12 @@ App.stackConfigPropertiesMapper = App.QuickDataMapper.create({
    * @returns {Boolean}
    */
   isMiscService: function(type) {
-    return type.length && (type.contains('USER') || type.contains('GROUP') || type.contains('ADDITIONAL_USER_PROPERTY'));
+    return type.length &&
+      (type.contains('USER')
+      || type.contains('GROUP')
+      || type.contains('ADDITIONAL_USER_PROPERTY')
+      || type.contains('UID')
+      || type.contains('GID'));
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 29788bc..a32275f 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -1147,6 +1147,21 @@ a:focus {
   }
 }
 
+.serviceConfigUGIDLbl {
+  display: inline-block;
+  text-align: left;
+  margin-left: 92px;
+  width: 100px;
+}
+
+.serviceConfigUGID {
+  width: 150px !important;
+}
+
+.serviceConfigNoUGID {
+  width: 500px !important;
+}
+
 .chart-container {
   cursor: pointer;
   cursor: -moz-zoom-in;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/templates/wizard/controls_service_config_usergroup_with_id.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/wizard/controls_service_config_usergroup_with_id.hbs b/ambari-web/app/templates/wizard/controls_service_config_usergroup_with_id.hbs
new file mode 100644
index 0000000..24c785c
--- /dev/null
+++ b/ambari-web/app/templates/wizard/controls_service_config_usergroup_with_id.hbs
@@ -0,0 +1,27 @@
+{{!
+* 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.
+}}
+
+{{#if view.isUIDGIDVisible}}
+    {{view App.ServiceConfigTextField serviceConfigBinding="view.serviceConfig" class="serviceConfigUGID"}}
+    <label class="serviceConfigUGIDLbl control-label" {{bindAttr for="view.serviceConfig.ugid.name"}}>
+        {{view.serviceConfig.ugid.displayName}}
+    </label>
+    {{view Ember.TextField valueBinding="view.serviceConfig.ugid.value" class="serviceConfigUGID"}}
+{{else}}
+    {{view App.ServiceConfigTextField serviceConfigBinding="view.serviceConfig" class="serviceConfigNoUGID"}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 00cc2a3..7cfcb13 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -545,6 +545,9 @@ App.config = Em.Object.create({
    */
   getViewClass: function (displayType, dependentConfigPattern, unit) {
     switch (displayType) {
+      case 'user':
+      case 'group':
+        return App.ServiceConfigTextFieldUserGroupWithID;
       case 'checkbox':
       case 'boolean':
         return dependentConfigPattern ? App.ServiceConfigCheckboxWithDependencies : App.ServiceConfigCheckbox;

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/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 4058020..6cf9b99 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
@@ -50,6 +50,7 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.Persist, App.ConfigOverrid
    * @type {App.ServiceConfigProperty[]}
    */
   serviceConfigs: null,
+  isUIDGIDVisible: true,
 
   /**
    * This is array of all the properties which apply
@@ -744,6 +745,11 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.Persist, App.ConfigOverrid
   setRecommendedValue: function (event) {
     var serviceConfigProperty = event.contexts[0];
     serviceConfigProperty.set('value', serviceConfigProperty.get('recommendedValue'));
+
+    //in case of USER/GROUP fields, if they have uid/gid set, then these need to be reset to the recommended value as well
+    if (serviceConfigProperty.get('ugid')) {
+      serviceConfigProperty.set('ugid.value', serviceConfigProperty.get('ugid.recommendedValue'));
+    }
     serviceConfigProperty = null;
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f92d1219/ambari-web/app/views/common/controls_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/controls_view.js b/ambari-web/app/views/common/controls_view.js
index edeaf0a..4e926ba 100644
--- a/ambari-web/app/views/common/controls_view.js
+++ b/ambari-web/app/views/common/controls_view.js
@@ -247,6 +247,40 @@ App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupp
 });
 
 /**
+ * Customized input control for user/group configs with corresponding uid/gid specified
+ * @type {Em.View}
+ */
+App.ServiceConfigTextFieldUserGroupWithID = Ember.View.extend(App.ServiceConfigPopoverSupport, {
+  valueBinding: 'serviceConfig.value',
+  placeholderBinding: 'serviceConfig.savedValue',
+  classNames: 'display-inline-block',
+
+  templateName: require('templates/wizard/controls_service_config_usergroup_with_id'),
+
+  isUIDGIDVisible: function () {
+    var overrideUidDisabled = this.get('parentView').serviceConfigs.findProperty('name', 'override_uid').value === 'false';
+    //don't display the ugid field if there is no uid/gid for this property or override_uid is unchecked
+    if (Em.isNone(this.get('serviceConfig.ugid')) || overrideUidDisabled) {
+      return false;
+    }
+
+    var serviceName = this.get('serviceConfig').name.substr(0, this.get('serviceConfig').name.indexOf('_')).toUpperCase();
+    if (serviceName === 'ZK') {
+      serviceName = 'ZOOKEEPER';
+    }
+    if (serviceName === 'MAPRED') {
+      serviceName = 'YARN';
+    }
+    //addServiceController and service already installed or Hadoop user group
+    if (App.Service.find(serviceName).get('isLoaded') || serviceName === 'USER') {
+      return false;
+    }
+
+    return this.get('parentView.isUIDGIDVisible');
+  }.property('parentView.isUIDGIDVisible')
+});
+
+/**
  * Customized input control with Units type specified
  * @type {Em.View}
  */
@@ -415,6 +449,11 @@ var checkboxConfigView = Ember.Checkbox.extend(App.ServiceConfigPopoverSupport,
       this.set('serviceConfig.value', this.get(this.get('checked') + 'Value'));
       this.get('serviceConfig').set("editDone", true);
       this.sendRequestRorDependentConfigs(this.get('serviceConfig'));
+
+      //if the checkbox being toggled is the 'Have Ambari manage UIDs' in Misc Tab, show/hide uid/gid column accordingly
+      if (this.get('serviceConfig.name') === 'override_uid') {
+         this.set('parentView.isUIDGIDVisible', this.get('checked'));
+      }
     }
   }.observes('checked'),