You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ao...@apache.org on 2014/11/14 15:19:51 UTC

ambari git commit: AMBARI-8316. Bootstaraping and starting agents as non-root (aonishuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk ef42c32b4 -> 2ae722627


AMBARI-8316. Bootstaraping and starting agents as non-root (aonishuk)


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

Branch: refs/heads/trunk
Commit: 2ae72262758b2a05c9d5181315136facefbc413e
Parents: ef42c32
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Fri Nov 14 16:19:41 2014 +0200
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Fri Nov 14 16:19:41 2014 +0200

----------------------------------------------------------------------
 ambari-agent/conf/unix/ambari-agent             | 11 ++++--
 ambari-agent/conf/unix/ambari-agent.ini         |  1 +
 ambari-agent/etc/init.d/ambari-agent            | 18 +++++++---
 .../python/ambari_agent/AgentConfig_linux.py    |  1 +
 .../src/main/python/ambari_agent/main.py        | 13 +++++--
 .../src/main/python/ambari_agent/shell.py       |  8 +++--
 .../ambari/server/bootstrap/BSRunner.java       |  8 +++--
 .../ambari/server/bootstrap/SshHostInfo.java    | 14 ++++++++
 ambari-server/src/main/python/bootstrap.py      | 20 +++++++----
 ambari-server/src/main/python/setupAgent.py     | 38 +++++++++++---------
 10 files changed, 94 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/conf/unix/ambari-agent
----------------------------------------------------------------------
diff --git a/ambari-agent/conf/unix/ambari-agent b/ambari-agent/conf/unix/ambari-agent
index 88fa0b9..d364ff8 100755
--- a/ambari-agent/conf/unix/ambari-agent
+++ b/ambari-agent/conf/unix/ambari-agent
@@ -48,6 +48,12 @@ AMBARI_AGENT_PY_SCRIPT=/usr/lib/python2.6/site-packages/ambari_agent/AmbariAgent
 OK=1
 NOTOK=0
 
+current_user=`awk -v val=$EUID -F ":" '$3==val{print $1}' /etc/passwd`
+# setup necessary ownership
+sudo chown -R $current_user "/var/lib/ambari-agent/ambari-env.sh"
+sudo chown -R $current_user "/var/run/ambari-agent"
+sudo chown -R $current_user "/var/log/ambari-agent"
+sudo chown -R $current_user "/var/lib/ambari-agent/data"
 
 if [ -a /usr/bin/python2.7 ] && [ -z "$PYTHON" ]; then
   PYTHON=/usr/bin/python2.7
@@ -106,8 +112,9 @@ check_python_version ()
 
 retcode=0
 
-if [ "$(id -u)" != "0" ]; then
- echo "You can't perform this operation as non-root user. Please, re-login as root user"
+sudo -v
+if [ "$?" != "0" ]; then
+ echo "You can't perform this operation as non-sudoer user. Please, re-login as one"
  exit 0
 fi
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/conf/unix/ambari-agent.ini
----------------------------------------------------------------------
diff --git a/ambari-agent/conf/unix/ambari-agent.ini b/ambari-agent/conf/unix/ambari-agent.ini
index 41e2895..ed9dab3 100644
--- a/ambari-agent/conf/unix/ambari-agent.ini
+++ b/ambari-agent/conf/unix/ambari-agent.ini
@@ -28,6 +28,7 @@ data_cleanup_max_size_MB = 100
 ping_port=8670
 cache_dir=/var/lib/ambari-agent/cache
 tolerate_download_failures=true
+run_as_user=root
 
 [command]
 maxretries=2

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/etc/init.d/ambari-agent
----------------------------------------------------------------------
diff --git a/ambari-agent/etc/init.d/ambari-agent b/ambari-agent/etc/init.d/ambari-agent
index 994ca77..4e255cd 100644
--- a/ambari-agent/etc/init.d/ambari-agent
+++ b/ambari-agent/etc/init.d/ambari-agent
@@ -19,20 +19,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+run_as_user=`cat /etc/ambari-agent/conf/ambari-agent.ini | grep run_as_user | tr -d ' ' | awk -F '=' '{ print $2}'`
+
+if [ "$EUID" != `id -u $run_as_user` ] ; then
+  command_prefx="su - $run_as_user -c"
+else
+  command_prefx="bash -c"
+fi
+
 case "$1" in
   start)
-        /usr/sbin/ambari-agent $@
+        $command_prefx "/usr/sbin/ambari-agent $@"
         ;;
   stop)
-        /usr/sbin/ambari-agent $@
+        $command_prefx "/usr/sbin/ambari-agent $@"
         ;;
   status)
-        /usr/sbin/ambari-agent $@
+        $command_prefx "/usr/sbin/ambari-agent $@"
         exit $?
         ;;
   restart)
-        $0 stop
-        $0 start
+        $command_prefx "$0 stop"
+        $command_prefx "$0 start"
         ;;
   reset)
         /usr/sbin/ambari-agent $@

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/src/main/python/ambari_agent/AgentConfig_linux.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AgentConfig_linux.py b/ambari-agent/src/main/python/ambari_agent/AgentConfig_linux.py
index a90b8ba..4be52cb 100644
--- a/ambari-agent/src/main/python/ambari_agent/AgentConfig_linux.py
+++ b/ambari-agent/src/main/python/ambari_agent/AgentConfig_linux.py
@@ -35,6 +35,7 @@ data_cleanup_max_age=2592000
 data_cleanup_max_size_MB = 100
 ping_port=8670
 cache_dir=/var/lib/ambari-agent/cache
+run_as_user=root
 
 [services]
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/src/main/python/ambari_agent/main.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/main.py b/ambari-agent/src/main/python/ambari_agent/main.py
index 84182c0..6448ca3 100644
--- a/ambari-agent/src/main/python/ambari_agent/main.py
+++ b/ambari-agent/src/main/python/ambari_agent/main.py
@@ -23,6 +23,7 @@ import signal
 from optparse import OptionParser
 import sys
 import traceback
+import getpass
 import os
 import time
 import platform
@@ -35,6 +36,7 @@ from PingPortListener import PingPortListener
 import hostname
 from DataCleaner import DataCleaner
 import socket
+from ambari_agent import shell
 logger = logging.getLogger()
 
 formatstr = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d - %(message)s"
@@ -153,7 +155,7 @@ def stop_agent():
     pid = f.read()
     pid = int(pid)
     f.close()
-    os.killpg(os.getpgid(pid), signal.SIGTERM)
+    kill_process_group(pid, signal.SIGTERM)
     time.sleep(5)
     if os.path.exists(ProcessHelper.pidfile):
       raise Exception("PID file still exists.")
@@ -162,8 +164,11 @@ def stop_agent():
     if pid == -1:
       print ("Agent process is not running")
     else:
-      os.killpg(os.getpgid(pid), signal.SIGKILL)
+      kill_process_group(pid, signal.SIGKILL) 
     os._exit(1)
+    
+def kill_process_group(pid, sig):
+  shell.shellRunner().run("sudo kill -{0} -$(ps -o pgid= {1} | grep -o [0-9]*)".format(sig, pid))
 
 def reset_agent(options):
   try:
@@ -204,8 +209,10 @@ def main(heartbeat_stop_callback=None):
 
   expected_hostname = options.expected_hostname
 
-  setup_logging(options.verbose)
+  current_user = getpass.getuser()
 
+  setup_logging(options.verbose)
+  
   default_cfg = {'agent': {'prefix': '/home/ambari'}}
   config.load(default_cfg)
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-agent/src/main/python/ambari_agent/shell.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/shell.py b/ambari-agent/src/main/python/ambari_agent/shell.py
index df6f0ca..2022646 100644
--- a/ambari-agent/src/main/python/ambari_agent/shell.py
+++ b/ambari-agent/src/main/python/ambari_agent/shell.py
@@ -156,8 +156,12 @@ class shellRunnerLinux:
     except Exception:
       logger.warn("can not switch user for RUN_COMMAND.")
     code = 0
-    cmd = " "
-    cmd = cmd.join(script)
+    
+    cmd = script
+    
+    if isinstance(script, list):
+      cmd = " ".join(script)
+
     p = subprocess.Popen(cmd, preexec_fn=_changeUid, stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE, shell=True, close_fds=True)
     out, err = p.communicate()

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
index 3bce55a..31343b5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
@@ -150,10 +150,11 @@ class BSRunner extends Thread {
   public void run() {
     String hostString = createHostString(sshHostInfo.getHosts());
     String user = sshHostInfo.getUser();
+    String userRunAs = sshHostInfo.getUserRunAs();
     if (user == null || user.isEmpty()) {
       user = DEFAULT_USER;
     }
-    String commands[] = new String[11];
+    String commands[] = new String[12];
     String shellCommand[] = new String[3];
     BSStat stat = BSStat.RUNNING;
     String scriptlog = "";
@@ -193,13 +194,14 @@ class BSRunner extends Thread {
       commands[7] = this.clusterOsFamily;
       commands[8] = this.projectVersion;
       commands[9] = this.serverPort+"";
+      commands[10] = userRunAs;
       if (this.passwordFile != null) {
-        commands[10] = this.passwordFile.toString();
+        commands[11] = this.passwordFile.toString();
       }
       LOG.info("Host= " + hostString + " bs=" + this.bsScript + " requestDir=" +
           requestIdDir + " user=" + user + " keyfile=" + this.sshKeyFile +
           " passwordFile " + this.passwordFile + " server=" + this.ambariHostname +
-          " version=" + projectVersion + " serverPort=" + this.serverPort);
+          " version=" + projectVersion + " serverPort=" + this.serverPort + " userRunAs="+ userRunAs);
 
       String[] env = new String[] { "AMBARI_PASSPHRASE=" + agentSetupPassword };
       if (this.verbose)

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
index 34813f4..50ac257 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
@@ -50,6 +50,9 @@ public class SshHostInfo {
 
   @XmlElement
   private String password;
+  
+  @XmlElement
+  private String userRunAs;
 
   public String getSshKey() {
     return sshKey;
@@ -90,6 +93,17 @@ public class SshHostInfo {
   public void setPassword(String password) {
     this.password = password;
   }
+  
+  public String getUserRunAs() {
+    // TODO: remove this once UI supports customizing ambari run-as-user
+    if(userRunAs == null)
+      return "root";
+    return userRunAs;
+  }
+
+  public void setUserRunAs(String userRunAs) {
+    this.userRunAs = userRunAs;
+  }
 
   public String hostListAsString() {
     StringBuilder ret = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-server/src/main/python/bootstrap.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/bootstrap.py b/ambari-server/src/main/python/bootstrap.py
index bf989d0..e27f399 100755
--- a/ambari-server/src/main/python/bootstrap.py
+++ b/ambari-server/src/main/python/bootstrap.py
@@ -364,11 +364,12 @@ class Bootstrap(threading.Thread):
     setupFile = self.getRemoteName(self.SETUP_SCRIPT_FILENAME)
     passphrase = os.environ[AMBARI_PASSPHRASE_VAR_NAME]
     server = self.shared_state.ambari_server
+    user_run_as = self.shared_state.user_run_as
     version = self.getAmbariVersion()
     port = self.getAmbariPort()
     passwordFile = self.getPasswordFile()
     return "sudo -S python " + str(setupFile) + " " + str(expected_hostname) + \
-           " " + str(passphrase) + " " + str(server) + " " + str(version) + \
+           " " + str(passphrase) + " " + str(server)+ " " + str(user_run_as) + " " + str(version) + \
            " " + str(port) + " < " + str(passwordFile)
 
 
@@ -376,10 +377,11 @@ class Bootstrap(threading.Thread):
     setupFile=self.getRemoteName(self.SETUP_SCRIPT_FILENAME)
     passphrase=os.environ[AMBARI_PASSPHRASE_VAR_NAME]
     server=self.shared_state.ambari_server
+    user_run_as = self.shared_state.user_run_as
     version=self.getAmbariVersion()
     port=self.getAmbariPort()
     return "sudo python " + str(setupFile) + " " + str(expected_hostname) + \
-           " " + str(passphrase) + " " + str(server) + " " + str(version) + \
+           " " + str(passphrase) + " " + str(server)+ " " + str(user_run_as) + " " + str(version) + \
            " " + str(port)
 
 
@@ -620,7 +622,7 @@ class PBootstrap:
 class SharedState:
   def __init__(self, user, sshkey_file, script_dir, boottmpdir, setup_agent_file,
                ambari_server, cluster_os_type, ambari_version, server_port,
-               password_file = None):
+               user_run_as, password_file = None):
     self.hostlist_to_remove_password_file = None
     self.user = user
     self.sshkey_file = sshkey_file
@@ -630,6 +632,7 @@ class SharedState:
     self.ambari_server = ambari_server
     self.cluster_os_type = cluster_os_type
     self.ambari_version = ambari_version
+    self.user_run_as = user_run_as
     self.password_file = password_file
     self.statuses = None
     self.server_port = server_port
@@ -644,9 +647,11 @@ def main(argv=None):
   if len(onlyargs) < 3:
     sys.stderr.write("Usage: <comma separated hosts> "
                      "<tmpdir for storage> <user> <sshkey_file> <agent setup script>"
-                     " <ambari-server name> <cluster os type> <ambari version> <ambari port> <passwordFile>\n")
+                     " <ambari-server name> <cluster os type> <ambari version> <ambari port> <user_run_as> <passwordFile>\n")
     sys.exit(2)
     pass
+  
+
   #Parse the input
   hostList = onlyargs[0].split(",")
   bootdir =  onlyargs[1]
@@ -657,7 +662,8 @@ def main(argv=None):
   cluster_os_type = onlyargs[6]
   ambariVersion = onlyargs[7]
   server_port = onlyargs[8]
-  passwordFile = onlyargs[9]
+  user_run_as = onlyargs[9]
+  passwordFile = onlyargs[10]
 
   # ssh doesn't like open files
   subprocess.Popen(["chmod", "600", sshkey_file], stdout=subprocess.PIPE)
@@ -669,10 +675,10 @@ def main(argv=None):
                " using " + scriptDir + " cluster primary OS: " + cluster_os_type +
                " with user '" + user + "' sshKey File " + sshkey_file + " password File " + passwordFile +\
                " using tmp dir " + bootdir + " ambari: " + ambariServer +"; server_port: " + server_port +\
-               "; ambari version: " + ambariVersion)
+               "; ambari version: " + ambariVersion+"; user_run_as: " + user_run_as)
   sharedState = SharedState(user, sshkey_file, scriptDir, bootdir, setupAgentFile,
                        ambariServer, cluster_os_type, ambariVersion,
-                       server_port, passwordFile)
+                       server_port, user_run_as, passwordFile)
   pbootstrap = PBootstrap(hostList, sharedState)
   pbootstrap.run()
   return 0 # Hack to comply with current usage

http://git-wip-us.apache.org/repos/asf/ambari/blob/2ae72262/ambari-server/src/main/python/setupAgent.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/setupAgent.py b/ambari-server/src/main/python/setupAgent.py
index aae5935..e320245 100755
--- a/ambari-server/src/main/python/setupAgent.py
+++ b/ambari-server/src/main/python/setupAgent.py
@@ -62,18 +62,21 @@ def installAgent(projectVersion):
   return execOsCommand(Command, tries=3, try_sleep=10)
 
 
-def configureAgent(server_hostname):
+def configureAgent(server_hostname, user_run_as):
   """ Configure the agent so that it has all the configs knobs properly installed """
   osCommand = ["sed", "-i.bak", "s/hostname=localhost/hostname=" + server_hostname +
                                 "/g", "/etc/ambari-agent/conf/ambari-agent.ini"]
   execOsCommand(osCommand)
+  osCommand = ["sed", "-i.bak", "s/run_as_user=.*$/run_as_user=" + user_run_as +
+                                "/g", "/etc/ambari-agent/conf/ambari-agent.ini"]
+  execOsCommand(osCommand)
   return
 
 
-def runAgent(passPhrase, expected_hostname):
+def runAgent(passPhrase, expected_hostname, user_run_as):
   os.environ[AMBARI_PASSPHRASE_VAR] = passPhrase
-  agent_retcode = subprocess.call("/usr/sbin/ambari-agent restart --expected-hostname=" +
-                                  expected_hostname, shell=True)
+  agent_retcode = subprocess.call("su - {0} -c '/usr/sbin/ambari-agent restart --expected-hostname={1}'".format(user_run_as, expected_hostname)
+                                  , shell=True)
   for i in range(3):
     time.sleep(1)
     ret = execOsCommand(["tail", "-20", "/var/log/ambari-agent/ambari-agent.log"])
@@ -168,8 +171,9 @@ def checkServerReachability(host, port):
 #               0        Expected host name
 #               1        Password
 #               2        Host name
-#      X        3        Project Version (Ambari)
-#      X        4        Server port
+#               3        User to run agent as
+#      X        4        Project Version (Ambari)
+#      X        5        Server port
 
 
 def parseArguments(argv=None):
@@ -182,28 +186,30 @@ def parseArguments(argv=None):
   expected_hostname = args[0]
   passPhrase = args[1]
   hostname = args[2]
+  user_run_as = args[3]
   projectVersion = ""
   server_port = 8080
 
-  if len(args) > 3:
-    projectVersion = args[3]
-
   if len(args) > 4:
+    projectVersion = args[4]
+
+  if len(args) > 5:
     try:
-      server_port = int(args[4])
+      server_port = int(args[5])
     except (Exception):
       server_port = 8080
 
-  return expected_hostname, passPhrase, hostname, projectVersion, server_port
+  return expected_hostname, passPhrase, hostname, user_run_as, projectVersion, server_port
 
 
 def main(argv=None):
   # Parse passed arguments
   expected_hostname, passPhrase, hostname,\
-  projectVersion, server_port = parseArguments(argv)
+  user_run_as, projectVersion, server_port = parseArguments(argv)
 
   checkServerReachability(hostname, server_port)
-
+  
+  projectVersion = "1.7.0"
   if projectVersion == "null" or projectVersion == "{ambariVersion}" or projectVersion == "":
     retcode = getOptimalVersion("")
   else:
@@ -224,9 +230,9 @@ def main(argv=None):
                                         "versions of ambari-agent:"+retcode["log"][0].strip()})
   else:
       sys.exit(retcode)
-
-  configureAgent(hostname)
-  sys.exit(runAgent(passPhrase, expected_hostname))
+  
+  configureAgent(hostname, user_run_as)
+  sys.exit(runAgent(passPhrase, expected_hostname, user_run_as))
 
 if __name__ == '__main__':
   logging.basicConfig(level=logging.DEBUG)