You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2013/04/13 02:46:21 UTC
svn commit: r1467531 - in /incubator/ambari/trunk: ./
ambari-server/src/main/java/org/apache/ambari/server/bootstrap/
ambari-server/src/main/python/
ambari-server/src/test/java/org/apache/ambari/server/bootstrap/
ambari-server/src/test/python/
Author: swagle
Date: Sat Apr 13 00:46:21 2013
New Revision: 1467531
URL: http://svn.apache.org/r1467531
Log:
AMBARI-1922. Support not root ssh via a user that can sudo in as root. (Sumit Mohanty via swagle)
Modified:
incubator/ambari/trunk/CHANGES.txt
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py
incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/bootstrap/BootStrapTest.java
incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py
Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Sat Apr 13 00:46:21 2013
@@ -11,6 +11,9 @@ Trunk (unreleased changes):
INCOMPATIBLE CHANGES
NEW FEATURES
+
+ AMBARI-1922. Support not root ssh via a user that can sudo in as root.
+ (Sumit Mohanty via swagle)
AMBARI-1914. Add Nagios alerts for Hue service. (swagle)
Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSRunner.java Sat Apr 13 00:46:21 2013
@@ -39,12 +39,15 @@ import org.apache.commons.logging.LogFac
class BSRunner extends Thread {
private static Log LOG = LogFactory.getLog(BSRunner.class);
+ private static final String DEFAULT_USER = "root";
+
private boolean finished = false;
private SshHostInfo sshHostInfo;
private File bootDir;
private String bsScript;
private File requestIdDir;
private File sshKeyFile;
+ private File passwordFile;
private int requestId;
private String agentSetupScript;
private String agentSetupPassword;
@@ -130,6 +133,10 @@ class BSRunner extends Thread {
FileUtils.writeStringToFile(sshKeyFile, data);
}
+ private void writePasswordFile(String data) throws IOException {
+ FileUtils.writeStringToFile(passwordFile, data);
+ }
+
public synchronized void finished() {
this.finished = true;
}
@@ -137,7 +144,11 @@ class BSRunner extends Thread {
@Override
public void run() {
String hostString = createHostString(sshHostInfo.getHosts());
- String commands[] = new String[6];
+ String user = sshHostInfo.getUser();
+ if (user == null || user.isEmpty()) {
+ user = DEFAULT_USER;
+ }
+ String commands[] = new String[8];
String shellCommand[] = new String[3];
BSStat stat = BSStat.RUNNING;
String scriptlog = "";
@@ -150,9 +161,19 @@ class BSRunner extends Thread {
+ sshHostInfo.getSshKey() + "\"");
}
+ String password = sshHostInfo.getPassword();
+ if (password != null && !password.isEmpty()) {
+ this.passwordFile = new File(this.requestIdDir, "host_pass");
+ // TODO : line separator should be changed
+ // if we are going to support multi platform server-agent solution
+ String lineSeparator = System.getProperty("line.separator");
+ password = password + lineSeparator;
+ writePasswordFile(password);
+ }
+
writeSshKeyFile(sshHostInfo.getSshKey());
/* Running command:
- * script hostlist bsdir sshkeyfile
+ * script hostlist bsdir user sshkeyfile
*/
shellCommand[0] = "sh";
shellCommand[1] = "-c";
@@ -160,11 +181,16 @@ class BSRunner extends Thread {
commands[0] = this.bsScript;
commands[1] = hostString;
commands[2] = this.requestIdDir.toString();
- commands[3] = this.sshKeyFile.toString();
- commands[4] = this.agentSetupScript.toString();
- commands[5] = this.ambariHostname;
+ commands[3] = user;
+ commands[4] = this.sshKeyFile.toString();
+ commands[5] = this.agentSetupScript.toString();
+ commands[6] = this.ambariHostname;
+ if (this.passwordFile != null) {
+ commands[7] = this.passwordFile.toString();
+ }
LOG.info("Host= " + hostString + " bs=" + this.bsScript + " requestDir=" +
- requestIdDir + " keyfile=" + this.sshKeyFile + " server=" + this.ambariHostname);
+ requestIdDir + " user=" + user + " keyfile=" + this.sshKeyFile +
+ " passwordFile " + this.passwordFile + " server=" + this.ambariHostname);
String[] env = new String[] { "AMBARI_PASSPHRASE=" + agentSetupPassword };
if (this.verbose)
@@ -275,7 +301,15 @@ class BSRunner extends Thread {
try {
FileUtils.forceDelete(sshKeyFile);
} catch (IOException io) {
- LOG.info(io.getMessage());
+ LOG.warn(io.getMessage());
+ }
+ if (passwordFile != null) {
+ // Remove password file after bootstrap is complete
+ try {
+ FileUtils.forceDelete(passwordFile);
+ } catch (IOException io) {
+ LOG.warn(io.getMessage());
+ }
}
finished();
}
Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/SshHostInfo.java Sat Apr 13 00:46:21 2013
@@ -41,10 +41,16 @@ public class SshHostInfo {
@XmlElement
private List<String> hosts = new ArrayList<String>();
-
+
@XmlElement
private boolean verbose = false;
+ @XmlElement
+ private String user;
+
+ @XmlElement
+ private String password;
+
public String getSshKey() {
return sshKey;
}
@@ -69,6 +75,22 @@ public class SshHostInfo {
this.verbose = verbose;
}
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
public String hostListAsString() {
StringBuilder ret = new StringBuilder();
if (this.hosts == null) {
Modified: incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py (original)
+++ incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py Sat Apr 13 00:46:21 2013
@@ -35,7 +35,8 @@ HOST_BOOTSTRAP_TIMEOUT = 300
class SCP(threading.Thread):
""" SCP implementation that is thread based. The status can be returned using
status val """
- def __init__(self, sshKeyFile, host, inputFile, remote, bootdir):
+ def __init__(self, user, sshKeyFile, host, inputFile, remote, bootdir):
+ self.user = user
self.sshKeyFile = sshKeyFile
self.host = host
self.inputFile = inputFile
@@ -58,7 +59,7 @@ class SCP(threading.Thread):
"-o", "ConnectTimeout=60",
"-o", "BatchMode=yes",
"-o", "StrictHostKeyChecking=no",
- "-i", self.sshKeyFile, self.inputFile, "root@" +
+ "-i", self.sshKeyFile, self.inputFile, self.user + "@" +
self.host + ":" + self.remote]
logging.info("Running scp command " + ' '.join(scpcommand))
scpstat = subprocess.Popen(scpcommand, stdout=subprocess.PIPE,
@@ -67,19 +68,25 @@ class SCP(threading.Thread):
self.ret["exitstatus"] = scpstat.returncode
self.ret["log"] = "STDOUT\n" + log[0] + "\nSTDERR\n" + log[1]
logFilePath = os.path.join(self.bootdir, self.host + ".log")
+ self.writeLogToFile(logFilePath)
+ logging.info("scp " + self.inputFile + " done for host " + self.host + ", exitcode=" + str(scpstat.returncode))
+ pass
+
+ def writeLogToFile(self, logFilePath):
logFile = open(logFilePath, "a+")
logFile.write(self.ret["log"])
logFile.close
- logging.info("scp " + self.inputFile + " done for host " + self.host + ", exitcode=" + str(scpstat.returncode))
pass
class SSH(threading.Thread):
""" Ssh implementation of this """
- def __init__(self, sshKeyFile, host, command, bootdir):
+ def __init__(self, user, sshKeyFile, host, command, bootdir, errorMessage = None):
+ self.user = user
self.sshKeyFile = sshKeyFile
self.host = host
self.command = command
self.bootdir = bootdir
+ self.errorMessage = errorMessage
self.ret = {"exitstatus" : -1, "log": "FAILED"}
threading.Thread.__init__(self)
self.daemon = True
@@ -98,24 +105,35 @@ class SSH(threading.Thread):
"-o", "BatchMode=yes",
"-tt", # Should prevent "tput: No value for $TERM and no -T specified" warning
"-i", self.sshKeyFile,
- "root@" + self.host, self.command]
+ self.user + "@" + self.host, self.command]
logging.info("Running ssh command " + ' '.join(sshcommand))
sshstat = subprocess.Popen(sshcommand, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
log = sshstat.communicate()
self.ret["exitstatus"] = sshstat.returncode
- self.ret["log"] = "STDOUT\n" + log[0] + "\nSTDERR\n" + log[1]
+ errorMsg = log[1]
+ if self.errorMessage and sshstat.returncode != 0:
+ errorMsg = self.errorMessage + "\n" + errorMsg
+ self.ret["log"] = "STDOUT\n" + log[0] + "\nSTDERR\n" + errorMsg
logFilePath = os.path.join(self.bootdir, self.host + ".log")
+ self.writeLogToFile(logFilePath)
+
+ doneFilePath = os.path.join(self.bootdir, self.host + ".done")
+ self.writeDoneToFile(doneFilePath, str(sshstat.returncode))
+
+ logging.info("Setup agent done for host " + self.host + ", exitcode=" + str(sshstat.returncode))
+ pass
+
+ def writeLogToFile(self, logFilePath):
logFile = open(logFilePath, "a+")
logFile.write(self.ret["log"])
logFile.close
+ pass
- doneFilePath = os.path.join(self.bootdir, self.host + ".done")
+ def writeDoneToFile(self, doneFilePath, returncode):
doneFile = open(doneFilePath, "w+")
- doneFile.write(str(sshstat.returncode))
+ doneFile.write(str(returncode))
doneFile.close()
-
- logging.info("Setup agent done for host " + self.host + ", exitcode=" + str(sshstat.returncode))
pass
pass
@@ -154,11 +172,13 @@ def get_difference(list1, list2):
class PSSH:
"""Run SSH in parallel for a given list of hosts"""
- def __init__(self, hosts, sshKeyFile, command, bootdir):
+ def __init__(self, hosts, user, sshKeyFile, command, bootdir, errorMessage = None):
self.hosts = hosts
+ self.user = user
self.sshKeyFile = sshKeyFile
self.command = command
self.bootdir = bootdir
+ self.errorMessage = errorMessage
self.ret = {}
pass
@@ -171,7 +191,7 @@ class PSSH:
for chunk in splitlist(self.hosts, 20):
chunkstats = []
for host in chunk:
- ssh = SSH(self.sshKeyFile, host, self.command, self.bootdir)
+ ssh = SSH(self.user, self.sshKeyFile, host, self.command, self.bootdir, self.errorMessage)
ssh.start()
chunkstats.append(ssh)
pass
@@ -191,8 +211,9 @@ pass
class PSCP:
"""Run SCP in parallel for a given list of hosts"""
- def __init__(self, hosts, sshKeyFile, inputfile, remote, bootdir):
+ def __init__(self, hosts, user, sshKeyFile, inputfile, remote, bootdir):
self.hosts = hosts
+ self.user = user
self.sshKeyFile = sshKeyFile
self.inputfile = inputfile
self.remote = remote
@@ -209,7 +230,7 @@ class PSCP:
for chunk in splitlist(self.hosts, 20):
chunkstats = []
for host in chunk:
- scp = SCP(self.sshKeyFile, host, self.inputfile, self.remote, self.bootdir)
+ scp = SCP(self.user, self.sshKeyFile, host, self.inputfile, self.remote, self.bootdir)
scp.start()
chunkstats.append(scp)
pass
@@ -230,14 +251,17 @@ pass
class BootStrap:
""" BootStrapping the agents on a list of hosts"""
- def __init__(self, hosts, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer):
+ def __init__(self, hosts, user, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer, passwordFile = None):
self.hostlist = hosts
self.successive_hostlist = hosts
+ self.hostlist_to_remove_password_file = None
+ self.user = user
self.sshkeyFile = sshkeyFile
self.bootdir = boottmpdir
self.scriptDir = scriptDir
self.setupAgentFile = setupAgentFile
self.ambariServer = ambariServer
+ self.passwordFile = passwordFile
self.statuses = None
pass
@@ -261,22 +285,57 @@ class BootStrap:
def getSetupScript(self):
return os.path.join(self.scriptDir, "setupAgent.py")
+ def getPasswordFile(self):
+ return "/tmp/host_pass"
+
+ def hasPassword(self):
+ return self.passwordFile != None and self.passwordFile != 'null'
+
+ def getMoveRepoFileWithPasswordCommand(self, targetDir):
+ return "sudo -S mv /tmp/ambari.repo " + targetDir + " < " + self.getPasswordFile()
+
+ def getMoveRepoFileWithoutPasswordCommand(self, targetDir):
+ return "sudo mv /tmp/ambari.repo " + targetDir
+
+ def getMoveRepoFileCommand(self, targetDir):
+ if self.hasPassword():
+ return self.getMoveRepoFileWithPasswordCommand(targetDir)
+ else:
+ return self.getMoveRepoFileWithoutPasswordCommand(targetDir)
+
def copyNeededFiles(self):
try:
# Copying the files
fileToCopy = self.getRepoFile()
- targetDir = self.getRepoDir()
- pscp = PSCP(self.hostlist, self.sshkeyFile, fileToCopy, targetDir, self.bootdir)
+ logging.info("Copying repo file to 'tmp' folder...")
+ pscp = PSCP(self.successive_hostlist, self.user, self.sshkeyFile, fileToCopy, "/tmp", self.bootdir)
pscp.run()
out = pscp.getstatus()
# Prepearing report about failed hosts
+ failed_current = get_difference(self.successive_hostlist, skip_failed_hosts(out))
self.successive_hostlist = skip_failed_hosts(out)
failed = get_difference(self.hostlist, self.successive_hostlist)
- logging.info("Parallel scp returns for repo file. Failed hosts are: " + str(failed))
+ logging.info("Parallel scp returns for copying repo file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
#updating statuses
- self.statuses = out
+ self.statuses = unite_statuses(self.statuses, out)
+
+ logging.info("Moving repo file...")
+ targetDir = self.getRepoDir()
+ command = self.getMoveRepoFileCommand(targetDir)
+ pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, command, self.bootdir)
+ pssh.run()
+ out = pssh.getstatus()
+ # Prepearing report about failed hosts
+ failed_current = get_difference(self.successive_hostlist, skip_failed_hosts(out))
+ self.successive_hostlist = skip_failed_hosts(out)
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.info("Parallel scp returns for moving repo file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
+ #updating statuses
+ self.statuses = unite_statuses(self.statuses, out)
- pscp = PSCP(self.successive_hostlist, self.sshkeyFile, self.setupAgentFile, "/tmp", self.bootdir)
+ pscp = PSCP(self.successive_hostlist, self.user, self.sshkeyFile, self.setupAgentFile, "/tmp", self.bootdir)
pscp.run()
out = pscp.getstatus()
# Prepearing report about failed hosts
@@ -300,10 +359,22 @@ class BootStrap:
pass
+ def getRunSetupWithPasswordCommand(self):
+ return "sudo -S python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer + " < " + self.getPasswordFile()
+
+ def getRunSetupWithoutPasswordCommand(self):
+ return "sudo python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer
+
+ def getRunSetupCommand(self):
+ if self.hasPassword():
+ return self.getRunSetupWithPasswordCommand()
+ else:
+ return self.getRunSetupWithoutPasswordCommand()
+
def runSetupAgent(self):
logging.info("Running setup agent...")
- command = "python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer
- pssh = PSSH(self.successive_hostlist, self.sshkeyFile, command, self.bootdir)
+ command = self.getRunSetupCommand()
+ pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, command, self.bootdir)
pssh.run()
out = pssh.getstatus()
@@ -334,13 +405,154 @@ class BootStrap:
doneFile.close()
pass
+ def checkSudoPackage(self):
+ try:
+ """ Checking 'sudo' package on remote hosts """
+ command = "rpm -qa | grep sudo"
+ pssh = PSSH(self.hostlist, self.user, self.sshkeyFile, command, self.bootdir, "Error: Sudo command is not available. Please install the sudo command.")
+ pssh.run()
+ out = pssh.getstatus()
+ # Prepearing report about failed hosts
+ self.successive_hostlist = skip_failed_hosts(out)
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.info("Parallel ssh returns for checking 'sudo' package. Failed hosts are: " + str(failed))
+ #updating statuses
+ self.statuses = out
+
+ retstatus = 0
+ if not failed:
+ retstatus = 0
+ else:
+ retstatus = 1
+ return retstatus
+
+ except Exception, e:
+ logging.info("Traceback " + traceback.format_exc())
+ pass
+ pass
+
+ def copyPasswordFile(self):
+ try:
+ # Copying the password file
+ logging.info("Copying password file to 'tmp' folder...")
+ pscp = PSCP(self.successive_hostlist, self.user, self.sshkeyFile, self.passwordFile, "/tmp", self.bootdir)
+ pscp.run()
+ out = pscp.getstatus()
+ # Prepearing report about failed hosts
+ failed_current = get_difference(self.successive_hostlist, skip_failed_hosts(out))
+ self.successive_hostlist = skip_failed_hosts(out)
+ self.hostlist_to_remove_password_file = self.successive_hostlist
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.warn("Parallel scp returns for copying password file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
+ #updating statuses
+ self.statuses = unite_statuses(self.statuses, out)
+
+ # Change password file mode to 600
+ logging.info("Changing password file mode...")
+ targetDir = self.getRepoDir()
+ command = "chmod 600 " + self.getPasswordFile()
+ pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, command, self.bootdir)
+ pssh.run()
+ out = pssh.getstatus()
+ # Prepearing report about failed hosts
+ failed_current = get_difference(self.successive_hostlist, skip_failed_hosts(out))
+ self.successive_hostlist = skip_failed_hosts(out)
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.warning("Parallel scp returns for copying password file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
+ #updating statuses
+ self.statuses = unite_statuses(self.statuses, out)
+
+ if not failed:
+ retstatus = 0
+ else:
+ retstatus = 1
+ return retstatus
+
+ except Exception, e:
+ logging.info("Traceback " + traceback.format_exc())
+ return 1
+ pass
+
+ def changePasswordFileModeOnHost(self):
+ try:
+ # Change password file mode to 600
+ logging.info("Changing password file mode...")
+ targetDir = self.getRepoDir()
+ command = "chmod 600 " + self.getPasswordFile()
+ pssh = PSSH(self.successive_hostlist, self.user, self.sshkeyFile, command, self.bootdir)
+ pssh.run()
+ out = pssh.getstatus()
+ # Prepearing report about failed hosts
+ failed_current = get_difference(self.successive_hostlist, skip_failed_hosts(out))
+ self.successive_hostlist = skip_failed_hosts(out)
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.warning("Parallel scp returns for copying password file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
+ #updating statuses
+ self.statuses = unite_statuses(self.statuses, out)
+
+ if not failed:
+ retstatus = 0
+ else:
+ retstatus = 1
+ return retstatus
+
+ except Exception, e:
+ logging.info("Traceback " + traceback.format_exc())
+ return 1
+ pass
+
+ def deletePasswordFile(self):
+ try:
+ # Deleting the password file
+ logging.info("Deleting password file...")
+ targetDir = self.getRepoDir()
+ command = "rm " + self.getPasswordFile()
+ pssh = PSSH(self.hostlist_to_remove_password_file, self.user, self.sshkeyFile, command, self.bootdir)
+ pssh.run()
+ out = pssh.getstatus()
+ # Prepearing report about failed hosts
+ failed_current = get_difference(self.hostlist_to_remove_password_file, skip_failed_hosts(out))
+ self.successive_hostlist = skip_failed_hosts(out)
+ failed = get_difference(self.hostlist, self.successive_hostlist)
+ logging.warn("Parallel scp returns for deleting password file. All failed hosts are: " + str(failed) +
+ ". Failed on last step: " + str(failed_current))
+ #updating statuses
+ self.statuses = unite_statuses(self.statuses, out)
+
+ if not failed:
+ retstatus = 0
+ else:
+ retstatus = 1
+ return retstatus
+
+ except Exception, e:
+ logging.info("Traceback " + traceback.format_exc())
+ return 1
+ pass
+
def run(self):
""" Copy files and run commands on remote hosts """
- ret1 = self.copyNeededFiles()
+ ret1 = self.checkSudoPackage()
+ logging.info("Checking 'sudo' package finished")
+ ret2 = 0
+ ret3 = 0
+ if self.hasPassword():
+ ret2 = self.copyPasswordFile()
+ logging.info("Copying password file finished")
+ ret3 = self.changePasswordFileModeOnHost()
+ logging.info("Change password file mode on host finished")
+ ret4 = self.copyNeededFiles()
logging.info("Copying files finished")
- ret2 = self.runSetupAgent()
+ ret5 = self.runSetupAgent()
logging.info("Running ssh command finished")
- retcode = max(ret1, ret2)
+ ret6 = 0
+ if self.hasPassword() and self.hostlist_to_remove_password_file is not None:
+ ret6 = self.deletePasswordFile()
+ logging.info("Deleting password file finished")
+ retcode = max(ret1, ret2, ret3, ret4, ret5, ret6)
self.createDoneFiles()
return retcode
pass
@@ -352,23 +564,29 @@ def main(argv=None):
onlyargs = argv[1:]
if len(onlyargs) < 3:
sys.stderr.write("Usage: <comma separated hosts> "
- "<tmpdir for storage> <sshkeyFile> <agent setup script> <ambari-server name>\n")
+ "<tmpdir for storage> <user> <sshkeyFile> <agent setup script> <ambari-server name> <passwordFile>\n")
sys.exit(2)
pass
#Parse the input
hostList = onlyargs[0].split(",")
bootdir = onlyargs[1]
- sshKeyFile = onlyargs[2]
- setupAgentFile = onlyargs[3]
- ambariServer = onlyargs[4]
+ user = onlyargs[2]
+ sshKeyFile = onlyargs[3]
+ setupAgentFile = onlyargs[4]
+ ambariServer = onlyargs[5]
+ passwordFile = onlyargs[6]
# ssh doesn't like open files
stat = subprocess.Popen(["chmod", "600", sshKeyFile], stdout=subprocess.PIPE)
+
+ if passwordFile != None and passwordFile != 'null':
+ stat = subprocess.Popen(["chmod", "600", passwordFile], stdout=subprocess.PIPE)
logging.info("BootStrapping hosts " + pprint.pformat(hostList) +
"using " + scriptDir +
- " with sshKey File " + sshKeyFile + " using tmp dir " + bootdir + " ambari: " + ambariServer)
- bootstrap = BootStrap(hostList, sshKeyFile, scriptDir, bootdir, setupAgentFile, ambariServer)
+ " with user '" + user + "' sshKey File " + sshKeyFile + " password File " + passwordFile +
+ " using tmp dir " + bootdir + " ambari: " + ambariServer)
+ bootstrap = BootStrap(hostList, user, sshKeyFile, scriptDir, bootdir, setupAgentFile, ambariServer, passwordFile)
ret = bootstrap.run()
#return ret
return 0 # Hack to comply with current usage
Modified: incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/bootstrap/BootStrapTest.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/bootstrap/BootStrapTest.java?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/bootstrap/BootStrapTest.java (original)
+++ incubator/ambari/trunk/ambari-server/src/test/java/org/apache/ambari/server/bootstrap/BootStrapTest.java Sat Apr 13 00:46:21 2013
@@ -73,6 +73,8 @@ public class BootStrapTest extends TestC
hosts.add("host1");
hosts.add("host2");
info.setHosts(hosts);
+ info.setUser("user");
+ info.setPassword("passwd");
BSResponse response = impl.runBootStrap(info);
LOG.info("Response id from bootstrap " + response.getRequestId());
/* do a query */
@@ -90,6 +92,7 @@ public class BootStrapTest extends TestC
Assert.assertTrue(status.getLog().contains("host1,host2"));
Assert.assertEquals(BSStat.SUCCESS, status.getStatus());
Assert.assertFalse(new File(bootdir + File.separator + "1" + File.separator + "sshKey").exists());
+ Assert.assertFalse(new File(bootdir + File.separator + "1" + File.separator + "host_pass").exists());
}
Modified: incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py?rev=1467531&r1=1467530&r2=1467531&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py (original)
+++ incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py Sat Apr 13 00:46:21 2013
@@ -18,21 +18,31 @@ limitations under the License.
import bootstrap
import time
+import subprocess
+import os
+import logging
from bootstrap import SCP
from bootstrap import PSCP
from bootstrap import SSH
from bootstrap import PSSH
+from bootstrap import BootStrap
from unittest import TestCase
+from subprocess import Popen
+from bootstrap import AMBARI_PASSPHRASE_VAR_NAME
+from mock.mock import MagicMock, call
class TestBootstrap(TestCase):
+ def setUp(self):
+ logging.basicConfig(level=logging.ERROR)
+
#Timout is specified in bootstrap.HOST_BOOTSTRAP_TIMEOUT, default is 300 seconds
def test_return_failed_status_for_hanging_ssh_threads_after_timeout(self):
bootstrap.HOST_BOOTSTRAP_TIMEOUT = 1
forever_hanging_timeout = 5
SSH.run = lambda self: time.sleep(forever_hanging_timeout)
- pssh = PSSH(["hostname"], "sshKeyFile", "command", "bootdir")
+ pssh = PSSH(["hostname"], "root", "sshKeyFile", "command", "bootdir")
self.assertTrue(pssh.ret == {})
starttime = time.time()
pssh.run()
@@ -46,7 +56,7 @@ class TestBootstrap(TestCase):
bootstrap.HOST_BOOTSTRAP_TIMEOUT = 1
forever_hanging_timeout = 5
SCP.run = lambda self: time.sleep(forever_hanging_timeout)
- pscp = PSCP(["hostname"], "sshKeyFile", "inputfile", "remote", "bootdir")
+ pscp = PSCP(["hostname"], "root", "sshKeyFile", "inputfile", "remote", "bootdir")
self.assertTrue(pscp.ret == {})
starttime = time.time()
pscp.run()
@@ -54,3 +64,114 @@ class TestBootstrap(TestCase):
self.assertTrue(time.time() - starttime < forever_hanging_timeout)
self.assertTrue(pscp.ret["hostname"]["log"] == "FAILED")
self.assertTrue(pscp.ret["hostname"]["exitstatus"] == -1)
+
+ def test_return_error_message_for_missing_sudo_package(self):
+ Popen.communicate = lambda self: ("", "")
+ SCP.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeDoneToFile = lambda self, doneFilePath, returncode: None
+ bootstrap = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer")
+ ret = bootstrap.checkSudoPackage()
+ self.assertTrue("Error: Sudo command is not available. Please install the sudo command." in bootstrap.statuses["hostname"]["log"])
+
+ def test_copy_and_delete_password_file_methods_are_called_for_user_with_password(self):
+ Popen.communicate = lambda self: ("", "")
+ SCP.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeDoneToFile = lambda self, doneFilePath, returncode: None
+ BootStrap.createDoneFiles = lambda self: None
+
+ def side_effect(self):
+ self.copyPasswordFile_called = True
+ self.hostlist_to_remove_password_file = ["hostname"]
+ return 0
+ BootStrap.copyPasswordFile = side_effect
+
+ deletePasswordFile = MagicMock()
+ deletePasswordFile.return_value = 0
+ BootStrap.deletePasswordFile = deletePasswordFile
+
+ changePasswordFileModeOnHost = MagicMock()
+ changePasswordFileModeOnHost.return_value = 0
+ BootStrap.changePasswordFileModeOnHost = changePasswordFileModeOnHost
+
+ os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+ bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "passwordFile")
+ ret = bootstrap.run()
+ self.assertTrue(bootstrap.copyPasswordFile_called)
+ self.assertTrue(deletePasswordFile.called)
+ self.assertTrue(changePasswordFileModeOnHost.called)
+
+ def test_copy_and_delete_password_file_methods_are_not_called_for_passwordless_user(self):
+ Popen.communicate = lambda self: ("", "")
+ SCP.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeDoneToFile = lambda self, doneFilePath, returncode: None
+ BootStrap.createDoneFiles = lambda self: None
+
+ def side_effect(self):
+ self.copyPasswordFile_called = True
+ self.hostlist_to_remove_password_file = ["hostname"]
+ return 0
+ BootStrap.copyPasswordFile = side_effect
+
+ deletePasswordFile = MagicMock()
+ deletePasswordFile.return_value = 0
+ BootStrap.deletePasswordFile = deletePasswordFile
+
+ changePasswordFileModeOnHost = MagicMock()
+ changePasswordFileModeOnHost.return_value = 0
+ BootStrap.changePasswordFileModeOnHost = changePasswordFileModeOnHost
+
+ os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+ bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer")
+ bootstrap.copyPasswordFile_called = False
+ ret = bootstrap.run()
+ self.assertFalse(bootstrap.copyPasswordFile_called)
+ self.assertFalse(deletePasswordFile.called)
+ self.assertFalse(changePasswordFileModeOnHost.called)
+
+ def test_commands_with_password_are_called_for_user_with_password(self):
+ def communicate(self, input=None, timeout=None):
+ self.returncode = 0
+ return ("", "")
+ Popen.communicate = communicate
+ SCP.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeDoneToFile = lambda self, doneFilePath, returncode: None
+ BootStrap.createDoneFiles = lambda self: None
+
+ getRunSetupWithPasswordCommand = MagicMock()
+ getRunSetupWithPasswordCommand.return_value = ""
+ BootStrap.getRunSetupWithPasswordCommand = getRunSetupWithPasswordCommand
+
+ getMoveRepoFileWithPasswordCommand = MagicMock()
+ getMoveRepoFileWithPasswordCommand.return_value = ""
+ BootStrap.getMoveRepoFileWithPasswordCommand = getMoveRepoFileWithPasswordCommand
+
+ os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+ bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "passwordFile")
+ ret = bootstrap.run()
+ self.assertTrue(getRunSetupWithPasswordCommand.called)
+ self.assertTrue(getMoveRepoFileWithPasswordCommand.called)
+
+ def test_commands_without_password_are_called_for_passwordless_user(self):
+ Popen.communicate = lambda self: ("", "")
+ SCP.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeLogToFile = lambda self, logFilePath: None
+ SSH.writeDoneToFile = lambda self, doneFilePath, returncode: None
+ BootStrap.createDoneFiles = lambda self: None
+
+ getRunSetupWithoutPasswordCommand = MagicMock()
+ getRunSetupWithoutPasswordCommand.return_value = ""
+ BootStrap.getRunSetupWithoutPasswordCommand = getRunSetupWithoutPasswordCommand
+
+ getMoveRepoFileWithoutPasswordCommand = MagicMock()
+ getMoveRepoFileWithoutPasswordCommand.return_value = ""
+ BootStrap.getMoveRepoFileWithoutPasswordCommand = getMoveRepoFileWithoutPasswordCommand
+
+ os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+ bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer")
+ ret = bootstrap.run()
+ self.assertTrue(getRunSetupWithoutPasswordCommand.called)
+ self.assertTrue(getMoveRepoFileWithoutPasswordCommand.called)