You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sm...@apache.org on 2013/04/17 20:57:55 UTC

svn commit: r1469025 - 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: smohanty
Date: Wed Apr 17 18:57:55 2013
New Revision: 1469025

URL: http://svn.apache.org/r1469025
Log:
AMBARI-1951. Ambari agent setup during bootstrap should install the same version of agent as the server. (smohanty)

Added:
    incubator/ambari/trunk/ambari-server/src/test/python/TestSetupAgent.py
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/BootStrapImpl.java
    incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py
    incubator/ambari/trunk/ambari-server/src/main/python/setupAgent.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=1469025&r1=1469024&r2=1469025&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Wed Apr 17 18:57:55 2013
@@ -745,6 +745,9 @@ Trunk (unreleased changes):
 
  BUG FIXES
 
+ AMBARI-1951. Ambari agent setup during bootstrap should install the same
+ version of agent as the server. (smohanty)
+
  AMBARI-1950. Hadoop install was failed on SUSE-11.1sp1 cluster with all 
  services except Hue. (smohanty)
 

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=1469025&r1=1469024&r2=1469025&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 Wed Apr 17 18:57:55 2013
@@ -53,10 +53,12 @@ class BSRunner extends Thread {
   private boolean verbose;
   private BootStrapImpl bsImpl;
   private final String clusterOsType;
+  private String projectVersion;
 
   public BSRunner(BootStrapImpl impl, SshHostInfo sshHostInfo, String bootDir,
       String bsScript, String agentSetupScript, String agentSetupPassword,
-      int requestId, long timeout, String hostName, boolean isVerbose, String clusterOsType)
+      int requestId, long timeout, String hostName, boolean isVerbose, String clusterOsType,
+      String projectVersion)
   {
     this.requestId = requestId;
     this.sshHostInfo = sshHostInfo;
@@ -69,6 +71,7 @@ class BSRunner extends Thread {
     this.ambariHostname = hostName;
     this.verbose = isVerbose;
     this.clusterOsType = clusterOsType;
+    this.projectVersion = projectVersion;
     this.bsImpl = impl;
     BootStrapStatus status = new BootStrapStatus();
     status.setLog("RUNNING");
@@ -148,7 +151,7 @@ class BSRunner extends Thread {
     if (user == null || user.isEmpty()) {
       user = DEFAULT_USER;
     }
-    String commands[] = new String[9];
+    String commands[] = new String[10];
     String shellCommand[] = new String[3];
     BSStat stat = BSStat.RUNNING;
     String scriptlog = "";
@@ -186,12 +189,14 @@ class BSRunner extends Thread {
       commands[5] = this.agentSetupScript.toString();
       commands[6] = this.ambariHostname;
       commands[7] = this.clusterOsType;
+      commands[8] = this.projectVersion;
       if (this.passwordFile != null) {
-        commands[8] = this.passwordFile.toString();
+        commands[9] = this.passwordFile.toString();
       }
       LOG.info("Host= " + hostString + " bs=" + this.bsScript + " requestDir=" +
           requestIdDir + " user=" + user + " keyfile=" + this.sshKeyFile +
-          " passwordFile " + this.passwordFile + " server=" + this.ambariHostname);
+          " passwordFile " + this.passwordFile + " server=" + this.ambariHostname +
+          " version=" + projectVersion);
 
       String[] env = new String[] { "AMBARI_PASSPHRASE=" + agentSetupPassword };
       if (this.verbose)

Modified: incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BootStrapImpl.java
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BootStrapImpl.java?rev=1469025&r1=1469024&r2=1469025&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BootStrapImpl.java (original)
+++ incubator/ambari/trunk/ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BootStrapImpl.java Wed Apr 17 18:57:55 2013
@@ -24,6 +24,7 @@ import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.bootstrap.BSResponse.BSRunStat;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.commons.logging.Log;
@@ -48,10 +49,10 @@ public class BootStrapImpl {
   int requestId = 0;
   private FifoLinkedHashMap<Long, BootStrapStatus> bsStatus;
   private final String clusterOsType;
-
+  private String projectVersion;
 
   @Inject
-  public BootStrapImpl(Configuration conf) throws IOException {
+  public BootStrapImpl(Configuration conf, AmbariMetaInfo ambariMetaInfo) throws IOException {
     this.bootStrapDir = conf.getBootStrapDir();
     this.bootScript = conf.getBootStrapScript();
     this.bootSetupAgentScript = conf.getBootSetupAgentScript();
@@ -60,6 +61,7 @@ public class BootStrapImpl {
     this.masterHostname = conf.getMasterHostname(
         InetAddress.getLocalHost().getCanonicalHostName());
     this.clusterOsType = conf.getServerOsType();
+    this.projectVersion = ambariMetaInfo.getServerVersion();
   }
 
   /**
@@ -107,7 +109,7 @@ public class BootStrapImpl {
 
     bsRunner = new BSRunner(this, info, bootStrapDir.toString(),
         bootScript, bootSetupAgentScript, bootSetupAgentPassword, requestId, 0L,
-        this.masterHostname, info.isVerbose(), this.clusterOsType);
+        this.masterHostname, info.isVerbose(), this.clusterOsType, this.projectVersion);
     bsRunner.start();
     response.setStatus(BSRunStat.OK);
     response.setLog("Running Bootstrap now.");

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=1469025&r1=1469024&r2=1469025&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py (original)
+++ incubator/ambari/trunk/ambari-server/src/main/python/bootstrap.py Wed Apr 17 18:57:55 2013
@@ -251,7 +251,7 @@ pass    
     
 class BootStrap:
   """ BootStrapping the agents on a list of hosts"""
-  def __init__(self, hosts, user, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer, cluster_os_type, passwordFile = None):
+  def __init__(self, hosts, user, sshkeyFile, scriptDir, boottmpdir, setupAgentFile, ambariServer, cluster_os_type, ambariVersion, passwordFile = None):
     self.hostlist = hosts
     self.successive_hostlist = hosts
     self.hostlist_to_remove_password_file = None
@@ -262,10 +262,17 @@ class BootStrap:
     self.setupAgentFile = setupAgentFile
     self.ambariServer = ambariServer
     self.cluster_os_type = cluster_os_type
+    self.ambariVersion = ambariVersion
     self.passwordFile = passwordFile
     self.statuses = None
     pass
 
+  # This method is needed  to implement the descriptor protocol (make object  to pass self reference to mockups)
+  def __get__(self, obj, objtype):
+    def _call(*args, **kwargs):
+      self(obj, *args, **kwargs)
+    return _call
+
   def is_suse(self):
     if os.path.isfile("/etc/issue"):
       if "suse" in open("/etc/issue").read().lower():
@@ -392,11 +399,19 @@ class BootStrap:
 
     pass
 
+  def getAmbariVersion(self):
+    if self.ambariVersion is None or self.ambariVersion == "null":
+      return ""
+    else:
+      return self.ambariVersion
+
   def getRunSetupWithPasswordCommand(self):
-    return "sudo -S python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer + " < " + self.getPasswordFile()
+    return "sudo -S python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer +\
+           " " + self.getAmbariVersion() + " < " + self.getPasswordFile()
 
   def getRunSetupWithoutPasswordCommand(self):
-    return "sudo python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer
+    return "sudo python /tmp/setupAgent.py " + os.environ[AMBARI_PASSPHRASE_VAR_NAME] + " " + self.ambariServer +\
+           " " + self.getAmbariVersion()
 
   def getRunSetupCommand(self):
     if self.hasPassword():
@@ -627,7 +642,7 @@ def main(argv=None):
   onlyargs = argv[1:]
   if len(onlyargs) < 3:
     sys.stderr.write("Usage: <comma separated hosts> "
-                     "<tmpdir for storage> <user> <sshkeyFile> <agent setup script> <ambari-server name> <cluster os type> <passwordFile>\n")
+                     "<tmpdir for storage> <user> <sshkeyFile> <agent setup script> <ambari-server name> <cluster os type> <ambari version> <passwordFile>\n")
     sys.exit(2)
     pass
   #Parse the input
@@ -638,7 +653,8 @@ def main(argv=None):
   setupAgentFile = onlyargs[4]
   ambariServer = onlyargs[5]
   cluster_os_type = onlyargs[6]
-  passwordFile = onlyargs[7]
+  ambariVersion = onlyargs[7]
+  passwordFile = onlyargs[8]
 
   # ssh doesn't like open files
   stat = subprocess.Popen(["chmod", "600", sshKeyFile], stdout=subprocess.PIPE)
@@ -649,8 +665,8 @@ def main(argv=None):
   logging.info("BootStrapping hosts " + pprint.pformat(hostList) +
                "using " + scriptDir + " cluster primary OS: " + cluster_os_type +
               " with user '" + user + "' sshKey File " + sshKeyFile + " password File " + passwordFile +
-              " using tmp dir " + bootdir + " ambari: " + ambariServer)
-  bootstrap = BootStrap(hostList, user, sshKeyFile, scriptDir, bootdir, setupAgentFile, ambariServer, cluster_os_type, passwordFile)
+              " using tmp dir " + bootdir + " ambari: " + ambariServer + "; ambari version: " + ambariVersion)
+  bootstrap = BootStrap(hostList, user, sshKeyFile, scriptDir, bootdir, setupAgentFile, ambariServer, cluster_os_type, ambariVersion, passwordFile)
   ret = bootstrap.run()
   #return  ret
   return 0 # Hack to comply with current usage

Modified: incubator/ambari/trunk/ambari-server/src/main/python/setupAgent.py
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/main/python/setupAgent.py?rev=1469025&r1=1469024&r2=1469025&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/main/python/setupAgent.py (original)
+++ incubator/ambari/trunk/ambari-server/src/main/python/setupAgent.py Wed Apr 17 18:57:55 2013
@@ -48,9 +48,9 @@ def is_suse():
       return True
   return False
 
-def installAgentSuse():
+def installAgentSuse(projectVersion):
   """ Run zypper install and make sure the agent install alright """
-  zypperCommand = ["zypper", "install", "-y", "ambari-agent"]
+  zypperCommand = ["zypper", "install", "-y", "ambari-agent" + projectVersion]
   return execOsCommand(zypperCommand)
 
 def installPreReq():
@@ -64,10 +64,10 @@ def installPreReq():
     yumCommand = ["echo", "Epel already exists"]
   return execOsCommand(yumCommand)
 
-def installAgent():
+def installAgent(projectVersion):
   """ Run yum install and make sure the agent install alright """
   # The command doesn't work with file mask ambari-agent*.rpm, so rename it on agent host
-  rpmCommand = ["yum", "-y", "install", "--nogpgcheck", "ambari-agent"]
+  rpmCommand = ["yum", "-y", "install", "--nogpgcheck", "ambari-agent" + projectVersion]
   return execOsCommand(rpmCommand)
 
 def configureAgent(host):
@@ -96,22 +96,77 @@ def runAgent(passPhrase):
   except (Exception), e:
     return 1
 
+def getOptimalVersion(initialProjectVersion):
+  if initialProjectVersion == "":
+    return initialProjectVersion
+  optimalVersion = initialProjectVersion
+
+  if is_suse():
+    ret = checkAgentPackageAvailabilitySuse(optimalVersion)
+  else:
+    ret = checkAgentPackageAvailability(optimalVersion)
+
+  # Specified package version found
+  if ret["exitstatus"] == 0:
+    return optimalVersion
+
+  # Specified package version not found; find nearest version
+  optimalVersion = optimalVersion + "."
+
+  if is_suse():
+    ret = findNearestAgentPackageVersionSuse(optimalVersion)
+  else:
+    ret = findNearestAgentPackageVersion(optimalVersion)
+
+  if ret["exitstatus"] == 0 and ret["log"][0].strip() != "":
+    optimalVersion = ret["log"][0].strip()
+  else:
+    optimalVersion = ""
+
+  return optimalVersion
+
+def checkAgentPackageAvailabilitySuse(projectVersion):
+  zypperCommand = ["bash", "-c", "zypper search -s --match-exact ambari-agent | grep ' " + projectVersion + " '"]
+  return execOsCommand(zypperCommand)
+
+def checkAgentPackageAvailability(projectVersion):
+  yumCommand = ["bash", "-c", "yum list available ambari-agent | grep ' " + projectVersion + " '"]
+  return execOsCommand(yumCommand)
+
+def findNearestAgentPackageVersionSuse(projectVersion):
+  zypperCommand = ["bash", "-c", "zypper search -s --match-exact ambari-agent | grep ' " + projectVersion + "' | cut -d '|' -f 4 | head -n1"]
+  return execOsCommand(zypperCommand)
+
+def findNearestAgentPackageVersion(projectVersion):
+  yumCommand = ["bash", "-c", "yum list available ambari-agent | grep ' " + projectVersion + "' | sed -re 's/\s+/ /g' | cut -d ' ' -f 2 | head -n1"]
+  return execOsCommand(yumCommand)
+
 def main(argv=None):
   scriptDir = os.path.realpath(os.path.dirname(argv[0]))
   # Parse the input
   onlyargs = argv[1:]
   passPhrase = onlyargs[0]
   hostName = onlyargs[1]
+  projectVersion = None
+  if len(onlyargs) > 2:
+    projectVersion = onlyargs[2]
+
+  if projectVersion is None or projectVersion == "null":
+    projectVersion = ""
+
+  projectVersion = getOptimalVersion(projectVersion)
+  if projectVersion != "":
+    projectVersion = "-" + projectVersion
 
   if is_suse():
-    installAgentSuse()
+    installAgentSuse(projectVersion)
   else:
     installPreReq()
-    installAgent()
+    installAgent(projectVersion)
 
   configureAgent(hostName)
   sys.exit(runAgent(passPhrase))
-  
+
 if __name__ == '__main__':
   logging.basicConfig(level=logging.DEBUG)
   main(sys.argv)

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=1469025&r1=1469024&r2=1469025&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 Wed Apr 17 18:57:55 2013
@@ -27,6 +27,7 @@ import java.util.Properties;
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.bootstrap.BootStrapStatus.BSStat;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.commons.io.FileUtils;
@@ -65,7 +66,8 @@ public class BootStrapTest extends TestC
     properties.setProperty(Configuration.BOOTSTRAP_SCRIPT, "echo");
     properties.setProperty(Configuration.SRVR_KSTR_DIR_KEY, "target" + File.separator + "classes");
     Configuration conf = new Configuration(properties);
-    BootStrapImpl impl = new BootStrapImpl(conf);
+    AmbariMetaInfo ambariMetaInfo = new AmbariMetaInfo(conf);
+    BootStrapImpl impl = new BootStrapImpl(conf, ambariMetaInfo);
     impl.init();
     SshHostInfo info = new SshHostInfo();
     info.setSshKey("xyz");

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=1469025&r1=1469024&r2=1469025&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py (original)
+++ incubator/ambari/trunk/ambari-server/src/test/python/TestBootstrap.py Wed Apr 17 18:57:55 2013
@@ -67,135 +67,164 @@ class TestBootstrap(TestCase):
     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", "centos6")
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  def test_return_error_message_for_missing_sudo_package(self, communicate_method,
+                                                         SSH_writeDoneToFile_method,
+                                                         SSH_writeLogToFile_method,
+                                                         SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    bootstrap = BootStrap(["hostname"], "root", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None)
     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
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  @patch.object(BootStrap, "deletePasswordFile")
+  @patch.object(BootStrap, "changePasswordFileModeOnHost")
+  def test_copy_and_delete_password_file_methods_are_called_for_user_with_password(self,
+                                                                                   changePasswordFileModeOnHost_method,
+                                                                                   deletePasswordFile_method,
+                                                                                   createDoneFiles_method,
+                                                                                   communicate_method,
+                                                                                   SSH_writeDoneToFile_method,
+                                                                                   SSH_writeLogToFile_method,
+                                                                                   SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
 
-    deletePasswordFile = MagicMock()
-    deletePasswordFile.return_value = 0
-    BootStrap.deletePasswordFile = deletePasswordFile
+    deletePasswordFile_method.return_value = 0
 
-    changePasswordFileModeOnHost = MagicMock()
-    changePasswordFileModeOnHost.return_value = 0
-    BootStrap.changePasswordFileModeOnHost = changePasswordFileModeOnHost
+    changePasswordFileModeOnHost_method.return_value = 0
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", "passwordFile")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "passwordFile")
+    def side_effect():
+      bootstrap.copyPasswordFile_called = True
+      bootstrap.hostlist_to_remove_password_file = ["hostname"]
+      return 0
+    bootstrap.copyPasswordFile = side_effect
     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
+    self.assertTrue(deletePasswordFile_method.called)
+    self.assertTrue(changePasswordFileModeOnHost_method.called)
 
-    deletePasswordFile = MagicMock()
-    deletePasswordFile.return_value = 0
-    BootStrap.deletePasswordFile = deletePasswordFile
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  @patch.object(BootStrap, "deletePasswordFile")
+  @patch.object(BootStrap, "changePasswordFileModeOnHost")
+  def test_copy_and_delete_password_file_methods_are_not_called_for_passwordless_user(self,
+                                                                                      changePasswordFileModeOnHost_method,
+                                                                                      deletePasswordFile_method,
+                                                                                      createDoneFiles_method,
+                                                                                      communicate_method,
+                                                                                      SSH_writeDoneToFile_method,
+                                                                                      SSH_writeLogToFile_method,
+                                                                                      SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
 
-    changePasswordFileModeOnHost = MagicMock()
-    changePasswordFileModeOnHost.return_value = 0
-    BootStrap.changePasswordFileModeOnHost = changePasswordFileModeOnHost
+    deletePasswordFile_method.return_value = 0
+    changePasswordFileModeOnHost_method.return_value = 0
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None)
     bootstrap.copyPasswordFile_called = False
+    def side_effect():
+      bootstrap.copyPasswordFile_called = True
+      bootstrap.hostlist_to_remove_password_file = ["hostname"]
+      return 0
+    bootstrap.copyPasswordFile = side_effect
     ret = bootstrap.run()
     self.assertFalse(bootstrap.copyPasswordFile_called)
-    self.assertFalse(deletePasswordFile.called)
-    self.assertFalse(changePasswordFileModeOnHost.called)
+    self.assertFalse(deletePasswordFile_method.called)
+    self.assertFalse(changePasswordFileModeOnHost_method.called)
+
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  @patch.object(BootStrap, "getRunSetupWithPasswordCommand")
+  @patch.object(BootStrap, "getMoveRepoFileWithPasswordCommand")
+  def test_commands_with_password_are_called_for_user_with_password(self, getMoveRepoFileWithPasswordCommand_method,
+                                                                    getRunSetupWithPasswordCommand_method,
+                                                                    createDoneFiles_method,
+                                                                    communicate_method,
+                                                                    SSH_writeDoneToFile_method,
+                                                                    SSH_writeLogToFile_method,
+                                                                    SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
 
-  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
+    getRunSetupWithPasswordCommand_method.return_value = ""
+    getMoveRepoFileWithPasswordCommand_method.return_value = ""
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", "passwordFile")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None, "passwordFile")
     ret = bootstrap.run()
-    self.assertTrue(getRunSetupWithPasswordCommand.called)
-    self.assertTrue(getMoveRepoFileWithPasswordCommand.called)
+    self.assertTrue(getRunSetupWithPasswordCommand_method.called)
+    self.assertTrue(getMoveRepoFileWithPasswordCommand_method.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
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  @patch.object(BootStrap, "getRunSetupWithoutPasswordCommand")
+  @patch.object(BootStrap, "getMoveRepoFileWithoutPasswordCommand")
+  def test_commands_without_password_are_called_for_passwordless_user(self, getMoveRepoFileWithoutPasswordCommand_method,
+                                                                      getRunSetupWithoutPasswordCommand_method,
+                                                                      createDoneFiles_method,
+                                                                      communicate_method,
+                                                                      SSH_writeDoneToFile_method,
+                                                                      SSH_writeLogToFile_method,
+                                                                      SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
+
+    getRunSetupWithoutPasswordCommand_method.return_value = ""
+    getMoveRepoFileWithoutPasswordCommand_method.return_value = ""
 
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
-    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6")
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", None)
     ret = bootstrap.run()
-    self.assertTrue(getRunSetupWithoutPasswordCommand.called)
-    self.assertTrue(getMoveRepoFileWithoutPasswordCommand.called)
-
+    self.assertTrue(getRunSetupWithoutPasswordCommand_method.called)
+    self.assertTrue(getMoveRepoFileWithoutPasswordCommand_method.called)
 
   @patch.object(BootStrap, "runSetupAgent")
   @patch.object(BootStrap, "copyNeededFiles")
   @patch.object(BootStrap, "checkSudoPackage")
   @patch.object(BootStrap, "runOsCheckScript")
   @patch.object(BootStrap, "copyOsCheckScript")
-  def test_os_check_performed(self, copyOsCheckScript_method,
+  @patch.object(BootStrap, "createDoneFiles")
+  def test_os_check_performed(self, createDoneFiles_method, copyOsCheckScript_method,
                               runOsCheckScript_method, checkSudoPackage_method,
                               copyNeededFiles_method, runSetupAgent_method):
-    BootStrap.createDoneFiles = lambda self: None
-
-    getRunSetupWithoutPasswordCommand = MagicMock()
-    getRunSetupWithoutPasswordCommand.return_value = ""
-    BootStrap.getRunSetupWithoutPasswordCommand = getRunSetupWithoutPasswordCommand
-
-    getMoveRepoFileWithoutPasswordCommand = MagicMock()
-    getMoveRepoFileWithoutPasswordCommand.return_value = ""
-    BootStrap.getMoveRepoFileWithoutPasswordCommand = getMoveRepoFileWithoutPasswordCommand
+    createDoneFiles_method.return_value = None
 
     copyOsCheckScript_method.return_value = 0
     runOsCheckScript_method.return_value = 0
@@ -203,16 +232,10 @@ class TestBootstrap(TestCase):
     copyNeededFiles_method.return_value = 0
     runSetupAgent_method.return_value = 0
 
-    BootStrap.copyOsCheckScript = copyOsCheckScript_method
-    BootStrap.runOsCheckScript = runOsCheckScript_method
-    BootStrap.checkSudoPackage = checkSudoPackage_method
-    BootStrap.copyNeededFiles = copyNeededFiles_method
-    BootStrap.runSetupAgent = runSetupAgent_method
-
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir",
                           "bootdir", "setupAgentFile", "ambariServer",
-                          "centos6")
+                          "centos6", None)
     ret = bootstrap.run()
     self.assertTrue(copyOsCheckScript_method.called)
     self.assertTrue(runOsCheckScript_method.called)
@@ -230,7 +253,7 @@ class TestBootstrap(TestCase):
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir",
                           "bootdir", "setupAgentFile", "ambariServer",
-                          "centos6")
+                          "centos6", None)
     res = bootstrap.copyOsCheckScript()
     self.assertTrue(run_method.called)
     self.assertTrue(getstatus_method.called)
@@ -250,7 +273,7 @@ class TestBootstrap(TestCase):
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir",
                           "bootdir", "setupAgentFile", "ambariServer",
-                          "centos6")
+                          "centos6", None)
     bootstrap.statuses = good_stats
     bootstrap.runOsCheckScript()
 
@@ -272,11 +295,55 @@ class TestBootstrap(TestCase):
     os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
     bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir",
                           "bootdir", "setupAgentFile", "ambariServer",
-                          "centos6")
+                          "centos6", None)
     bootstrap.statuses = good_stats
     bootstrap.runOsCheckScript()
 
     self.assertTrue(run_method.called)
     self.assertTrue(getstatus_method.called)
     self.assertTrue("hostname" not in bootstrap.successive_hostlist)
-    pass
\ No newline at end of file
+    pass
+
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  def test_run_setup_agent_command_ends_with_project_version(self, createDoneFiles_method,
+                                                             communicate_method,
+                                                             SSH_writeDoneToFile_method,
+                                                             SSH_writeLogToFile_method,
+                                                             SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
+
+    os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+    version = "1.1.1"
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", version)
+    runSetupCommand = bootstrap.getRunSetupCommand()
+    self.assertTrue(runSetupCommand.endswith(version))
+
+  @patch.object(SCP, "writeLogToFile")
+  @patch.object(SSH, "writeLogToFile")
+  @patch.object(SSH, "writeDoneToFile")
+  @patch.object(Popen, "communicate")
+  @patch.object(BootStrap, "createDoneFiles")
+  def test_agent_setup_command_without_project_version(self, createDoneFiles_method,
+                                                       communicate_method,
+                                                       SSH_writeDoneToFile_method,
+                                                       SSH_writeLogToFile_method,
+                                                       SCP_writeLogToFile_method):
+    SCP_writeLogToFile_method.return_value = None
+    SSH_writeLogToFile_method.return_value = None
+    SSH_writeDoneToFile_method.return_value = None
+    communicate_method.return_value = ("", "")
+    createDoneFiles_method.return_value = None
+
+    os.environ[AMBARI_PASSPHRASE_VAR_NAME] = ""
+    version = None
+    bootstrap = BootStrap(["hostname"], "user", "sshKeyFile", "scriptDir", "bootdir", "setupAgentFile", "ambariServer", "centos6", version)
+    runSetupCommand = bootstrap.getRunSetupCommand()
+    self.assertTrue(runSetupCommand.endswith("ambariServer "))

Added: incubator/ambari/trunk/ambari-server/src/test/python/TestSetupAgent.py
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-server/src/test/python/TestSetupAgent.py?rev=1469025&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-server/src/test/python/TestSetupAgent.py (added)
+++ incubator/ambari/trunk/ambari-server/src/test/python/TestSetupAgent.py Wed Apr 17 18:57:55 2013
@@ -0,0 +1,193 @@
+'''
+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.
+'''
+
+from unittest import TestCase
+from mock.mock import patch
+from subprocess import Popen
+setup_agent = __import__('setupAgent')
+
+class TestSetupAgent(TestCase):
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_initial_on_suse(self, findNearestAgentPackageVersion_method,
+                                                       findNearestAgentPackageVersionSuse_method,
+                                                       checkAgentPackageAvailability_method,
+                                                       checkAgentPackageAvailabilitySuse_method,
+                                                       is_suse_method):
+    is_suse_method.return_value = True
+    checkAgentPackageAvailabilitySuse_method.return_value = {
+      "exitstatus" : 0
+    }
+
+    projectVersion = "1.1.1"
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertTrue(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertFalse(checkAgentPackageAvailability_method.called)
+    self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
+    self.assertFalse(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == projectVersion)
+    pass
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_nearest_on_suse(self, findNearestAgentPackageVersion_method,
+                                                       findNearestAgentPackageVersionSuse_method,
+                                                       checkAgentPackageAvailability_method,
+                                                       checkAgentPackageAvailabilitySuse_method,
+                                                       is_suse_method):
+    is_suse_method.return_value = True
+    checkAgentPackageAvailabilitySuse_method.return_value = {
+      "exitstatus" : 1
+    }
+    projectVersion = "1.1.1"
+    nearest_version = projectVersion + ".1"
+    findNearestAgentPackageVersionSuse_method.return_value = {
+      "exitstatus" : 0,
+      "log": [nearest_version, ""]
+    }
+
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertTrue(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertFalse(checkAgentPackageAvailability_method.called)
+    self.assertTrue(findNearestAgentPackageVersionSuse_method.called)
+    self.assertFalse(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == nearest_version)
+    pass
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_default_on_suse(self, findNearestAgentPackageVersion_method,
+                                                       findNearestAgentPackageVersionSuse_method,
+                                                       checkAgentPackageAvailability_method,
+                                                       checkAgentPackageAvailabilitySuse_method,
+                                                       is_suse_method):
+    is_suse_method.return_value = True
+    checkAgentPackageAvailabilitySuse_method.return_value = {
+      "exitstatus" : 1
+    }
+    findNearestAgentPackageVersionSuse_method.return_value = {
+      "exitstatus" : 0,
+      "log": ["", ""]
+    }
+
+    projectVersion = "1.1.1"
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertTrue(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertFalse(checkAgentPackageAvailability_method.called)
+    self.assertTrue(findNearestAgentPackageVersionSuse_method.called)
+    self.assertFalse(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == "")
+    pass
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_initial(self, findNearestAgentPackageVersion_method,
+                                               findNearestAgentPackageVersionSuse_method,
+                                               checkAgentPackageAvailability_method,
+                                               checkAgentPackageAvailabilitySuse_method,
+                                               is_suse_method):
+    is_suse_method.return_value = False
+    checkAgentPackageAvailability_method.return_value = {
+      "exitstatus" : 0
+    }
+
+    projectVersion = "1.1.1"
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertFalse(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertTrue(checkAgentPackageAvailability_method.called)
+    self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
+    self.assertFalse(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == projectVersion)
+    pass
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_nearest(self, findNearestAgentPackageVersion_method,
+                                               findNearestAgentPackageVersionSuse_method,
+                                               checkAgentPackageAvailability_method,
+                                               checkAgentPackageAvailabilitySuse_method,
+                                               is_suse_method):
+    is_suse_method.return_value = False
+    checkAgentPackageAvailability_method.return_value = {
+      "exitstatus" : 1
+    }
+
+    projectVersion = "1.1.1"
+    nearest_version = projectVersion + ".1"
+    findNearestAgentPackageVersion_method.return_value = {
+      "exitstatus" : 0,
+      "log": [nearest_version, ""]
+    }
+
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertFalse(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertTrue(checkAgentPackageAvailability_method.called)
+    self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
+    self.assertTrue(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == nearest_version)
+    pass
+
+  @patch.object(setup_agent, 'is_suse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailabilitySuse')
+  @patch.object(setup_agent, 'checkAgentPackageAvailability')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersionSuse')
+  @patch.object(setup_agent, 'findNearestAgentPackageVersion')
+  def test_returned_optimal_version_is_default(self, findNearestAgentPackageVersion_method,
+                                               findNearestAgentPackageVersionSuse_method,
+                                               checkAgentPackageAvailability_method,
+                                               checkAgentPackageAvailabilitySuse_method,
+                                               is_suse_method):
+    is_suse_method.return_value = False
+    checkAgentPackageAvailability_method.return_value = {
+      "exitstatus" : 1
+    }
+    findNearestAgentPackageVersion_method.return_value = {
+      "exitstatus" : 0,
+      "log": ["", ""]
+    }
+
+    projectVersion = "1.1.1"
+    result_version = setup_agent.getOptimalVersion(projectVersion)
+
+    self.assertFalse(checkAgentPackageAvailabilitySuse_method.called)
+    self.assertTrue(checkAgentPackageAvailability_method.called)
+    self.assertFalse(findNearestAgentPackageVersionSuse_method.called)
+    self.assertTrue(findNearestAgentPackageVersion_method.called)
+    self.assertTrue(result_version == "")
+    pass
\ No newline at end of file