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 2015/10/13 19:58:34 UTC

[1/2] ambari git commit: AMBARI-13328. Enable skipSurefireTests for ambari-metrics project (Nahappan Somasundaram via smohanty)

Repository: ambari
Updated Branches:
  refs/heads/trunk 595a99611 -> 6df37bba8


AMBARI-13328. Enable skipSurefireTests for ambari-metrics project (Nahappan Somasundaram via smohanty)


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

Branch: refs/heads/trunk
Commit: d7269e6e08d2b9e9de735c89277a889c8499b6a1
Parents: 595a996
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Tue Oct 13 10:51:57 2015 -0700
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Tue Oct 13 10:51:57 2015 -0700

----------------------------------------------------------------------
 ambari-metrics/pom.xml | 7 +++++++
 1 file changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d7269e6e/ambari-metrics/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-metrics/pom.xml b/ambari-metrics/pom.xml
index d08cc28..8931340 100644
--- a/ambari-metrics/pom.xml
+++ b/ambari-metrics/pom.xml
@@ -149,6 +149,13 @@
         </executions>
       </plugin>
       <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <skip>${skipSurefireTests}</skip>
+        </configuration>
+      </plugin>
+      <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.2</version>
         <configuration>


[2/2] ambari git commit: AMBARI-13327. Agents to automatically communicate with Active Server (Nahappan Somasundaram via smohanty)

Posted by sm...@apache.org.
AMBARI-13327. Agents to automatically communicate with Active Server (Nahappan Somasundaram via smohanty)


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

Branch: refs/heads/trunk
Commit: 6df37bba87c2951f564c00ee69fa2c385d1cf1ff
Parents: d7269e6
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Tue Oct 13 10:56:16 2015 -0700
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Tue Oct 13 10:56:16 2015 -0700

----------------------------------------------------------------------
 .../main/python/ambari_agent/AmbariConfig.py    | 46 ++++++++----
 .../src/main/python/ambari_agent/Controller.py  |  6 +-
 .../src/main/python/ambari_agent/NetUtil.py     |  2 +-
 .../src/main/python/ambari_agent/hostname.py    | 29 +++++---
 .../src/main/python/ambari_agent/main.py        | 73 ++++++++++++++------
 .../src/main/python/ambari_agent/security.py    | 13 ++--
 .../python/ambari_agent/TestCertGeneration.py   |  3 +-
 .../test/python/ambari_agent/TestController.py  |  5 +-
 .../test/python/ambari_agent/TestHostname.py    | 53 ++++++++++++--
 .../src/test/python/ambari_agent/TestMain.py    | 27 +++++++-
 .../src/test/python/ambari_agent/TestNetUtil.py |  6 +-
 .../test/python/ambari_agent/TestSecurity.py    | 22 +++---
 12 files changed, 205 insertions(+), 80 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/main/python/ambari_agent/AmbariConfig.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/AmbariConfig.py b/ambari-agent/src/main/python/ambari_agent/AmbariConfig.py
index 453d59c..03e14ad 100644
--- a/ambari-agent/src/main/python/ambari_agent/AmbariConfig.py
+++ b/ambari-agent/src/main/python/ambari_agent/AmbariConfig.py
@@ -240,13 +240,13 @@ class AmbariConfig:
         pass
     return default
 
-  def get_api_url(self):
+  def get_api_url(self, server_hostname):
     return "%s://%s:%s" % (self.CONNECTION_PROTOCOL,
-                           hostname.server_hostname(self),
+                           server_hostname,
                            self.get('server', 'url_port'))
 
-  def isTwoWaySSLConnection(self):
-    req_url = self.get_api_url()
+  def isTwoWaySSLConnection(self, server_hostname):
+    req_url = self.get_api_url(server_hostname)
     response = self.getServerOption(self.SERVER_CONNECTION_INFO.format(req_url), self.TWO_WAY_SSL_PROPERTY, 'false')
     if response is None:
       return False
@@ -267,17 +267,39 @@ class AmbariConfig:
         logger.info("Updating config property (%s) with value (%s)", k, v)
     pass
 
-def updateConfigServerHostname(configFile, new_host):
+def isSameHostList(hostlist1, hostlist2):
+  is_same = True
+
+  if (hostlist1 is not None and hostlist2 is not None):
+    if (len(hostlist1) != len(hostlist2)):
+      is_same = False
+    else:
+      host_lookup = {}
+      for item1 in hostlist1:
+        host_lookup[item1.lower()] = True
+      for item2 in hostlist2:
+        if item2.lower() in host_lookup:
+          del host_lookup[item2.lower()]
+        else:
+          is_same = False
+          break
+    pass
+  elif (hostlist1 is not None or hostlist2 is not None):
+    is_same = False
+  return is_same
+
+def updateConfigServerHostname(configFile, new_hosts):
   # update agent config file
   agent_config = ConfigParser.ConfigParser()
   agent_config.read(configFile)
-  server_host = agent_config.get('server', 'hostname')
-  if new_host is not None and server_host != new_host:
-    print "Updating server host from " + server_host + " to " + new_host
-    agent_config.set('server', 'hostname', new_host)
-    with (open(configFile, "wb")) as new_agent_config:
-      agent_config.write(new_agent_config)
-
+  server_hosts = agent_config.get('server', 'hostname')
+  if new_hosts is not None:
+      new_host_names = hostname.arrayFromCsvString(new_hosts)
+      if not isSameHostList(server_hosts, new_host_names):
+        print "Updating server hostname from " + server_hosts + " to " + new_hosts
+        agent_config.set('server', 'hostname', new_hosts)
+        with (open(configFile, "wb")) as new_agent_config:
+          agent_config.write(new_agent_config)
 
 def main():
   print AmbariConfig().config

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/main/python/ambari_agent/Controller.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/Controller.py b/ambari-agent/src/main/python/ambari_agent/Controller.py
index 74a8eac..5a4bb00 100644
--- a/ambari-agent/src/main/python/ambari_agent/Controller.py
+++ b/ambari-agent/src/main/python/ambari_agent/Controller.py
@@ -54,7 +54,7 @@ AGENT_AUTO_RESTART_EXIT_CODE = 77
 
 class Controller(threading.Thread):
 
-  def __init__(self, config, heartbeat_stop_callback = None, range=30):
+  def __init__(self, config, server_hostname, heartbeat_stop_callback = None, range=30):
     threading.Thread.__init__(self)
     logger.debug('Initializing Controller RPC thread.')
     if heartbeat_stop_callback is None:
@@ -66,7 +66,7 @@ class Controller(threading.Thread):
     self.credential = None
     self.config = config
     self.hostname = hostname.hostname(config)
-    self.serverHostname = hostname.server_hostname(config)
+    self.serverHostname = server_hostname
     server_secured_url = 'https://' + self.serverHostname + \
                          ':' + config.get('server', 'secured_url_port')
     self.registerUrl = server_secured_url + '/agent/v1/register/' + self.hostname
@@ -408,7 +408,7 @@ class Controller(threading.Thread):
 
     try:
       if self.cachedconnect is None: # Lazy initialization
-        self.cachedconnect = security.CachedHTTPSConnection(self.config)
+        self.cachedconnect = security.CachedHTTPSConnection(self.config, self.serverHostname)
       req = urllib2.Request(url, data, {'Content-Type': 'application/json',
                                         'Accept-encoding': 'gzip'})
       response = self.cachedconnect.request(req)

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/main/python/ambari_agent/NetUtil.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/NetUtil.py b/ambari-agent/src/main/python/ambari_agent/NetUtil.py
index def43f3..50fb97b 100644
--- a/ambari-agent/src/main/python/ambari_agent/NetUtil.py
+++ b/ambari-agent/src/main/python/ambari_agent/NetUtil.py
@@ -110,4 +110,4 @@ class NetUtil:
         if logger is not None:
           logger.info("Stop event received")
         self.DEBUG_STOP_RETRIES_FLAG = True
-    return retries, connected
+    return retries, connected, self.DEBUG_STOP_RETRIES_FLAG

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/main/python/ambari_agent/hostname.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/hostname.py b/ambari-agent/src/main/python/ambari_agent/hostname.py
index 9cb75d6..2ee79bd 100644
--- a/ambari-agent/src/main/python/ambari_agent/hostname.py
+++ b/ambari-agent/src/main/python/ambari_agent/hostname.py
@@ -28,8 +28,17 @@ logger = logging.getLogger(__name__)
 
 cached_hostname = None
 cached_public_hostname = None
-cached_server_hostname = None
+cached_server_hostnames = []
 
+def arrayFromCsvString(str):
+  CSV_DELIMITER = ','
+
+  result_array = []
+  items = str.lower().split(CSV_DELIMITER)
+
+  for item in items:
+    result_array.append(item.strip())
+  return result_array
 
 def hostname(config):
   global cached_hostname
@@ -87,13 +96,13 @@ def public_hostname(config):
     logger.info("Read public hostname '" + cached_public_hostname + "' using socket.getfqdn()")
   return cached_public_hostname
 
-def server_hostname(config):
+def server_hostnames(config):
   """
   Reads the ambari server name from the config or using the supplied script
   """
-  global cached_server_hostname
-  if cached_server_hostname is not None:
-    return cached_server_hostname
+  global cached_server_hostnames
+  if cached_server_hostnames != []:
+    return cached_server_hostnames
 
   if config.has_option('server', 'hostname_script'):
     scriptname = config.get('server', 'hostname_script')
@@ -101,14 +110,14 @@ def server_hostname(config):
       osStat = subprocess.Popen([scriptname], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
       out, err = osStat.communicate()
       if (0 == osStat.returncode and 0 != len(out.strip())):
-        cached_server_hostname = out.strip()
-        logger.info("Read server hostname '" + cached_server_hostname + "' using server:hostname_script")
+        cached_server_hostnames = arrayFromCsvString(out)
+        logger.info("Read server hostname '" + cached_server_hostnames + "' using server:hostname_script")
     except Exception, err:
       logger.info("Unable to execute hostname_script for server hostname. " + str(err))
 
-  if cached_server_hostname is None:
-    cached_server_hostname  = config.get('server', 'hostname')
-  return cached_server_hostname
+  if not cached_server_hostnames:
+    cached_server_hostnames  = arrayFromCsvString(config.get('server', 'hostname'))
+  return cached_server_hostnames
 
 
 def main(argv=None):

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/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 6ab89fd..72f9b04 100644
--- a/ambari-agent/src/main/python/ambari_agent/main.py
+++ b/ambari-agent/src/main/python/ambari_agent/main.py
@@ -221,6 +221,8 @@ def reset_agent(options):
 
   sys.exit(0)
 
+MAX_RETRIES = 10
+
 # event - event, that will be passed to Controller and NetUtil to make able to interrupt loops form outside process
 # we need this for windows os, where no sigterm available
 def main(heartbeat_stop_callback=None):
@@ -275,31 +277,58 @@ def main(heartbeat_stop_callback=None):
 
   update_log_level(config)
 
-  server_hostname = hostname.server_hostname(config)
-  server_url = config.get_api_url()
-
   if not OSCheck.get_os_family() == OSConst.WINSRV_FAMILY:
     daemonize()
 
-  try:
-    server_ip = socket.gethostbyname(server_hostname)
-    logger.info('Connecting to Ambari server at %s (%s)', server_url, server_ip)
-  except socket.error:
-    logger.warn("Unable to determine the IP address of the Ambari server '%s'", server_hostname)
-
-  # Wait until server is reachable
-  netutil = NetUtil(heartbeat_stop_callback)
-  retries, connected = netutil.try_to_connect(server_url, -1, logger)
-  # Ambari Agent was stopped using stop event
-  if connected:
-    # Launch Controller communication
-    controller = Controller(config, heartbeat_stop_callback)
-    controller.start()
-    controller.join()
-  if not OSCheck.get_os_family() == OSConst.WINSRV_FAMILY:
-    ExitHelper.execute_cleanup()
-    stop_agent()
-  logger.info("finished")
+  #
+  # Iterate through the list of server hostnames and connect to the first active server
+  #
+
+  active_server = None
+  server_hostnames = hostname.server_hostnames(config)
+
+  connected = False
+  stopped = False
+
+  # Keep trying to connect to a server or bail out if ambari-agent was stopped
+  while not connected and not stopped:
+    for server_hostname in server_hostnames:
+      try:
+        server_ip = socket.gethostbyname(server_hostname)
+        server_url = config.get_api_url(server_hostname)
+        logger.info('Connecting to Ambari server at %s (%s)', server_url, server_ip)
+      except socket.error:
+        logger.warn("Unable to determine the IP address of the Ambari server '%s'", server_hostname)
+
+      # Wait until MAX_RETRIES to see if server is reachable
+      netutil = NetUtil(heartbeat_stop_callback)
+      (retries, connected, stopped) = netutil.try_to_connect(server_url, MAX_RETRIES, logger)
+
+      # if connected, launch controller
+      if connected:
+        logger.info('Connected to Ambari server %s', server_hostname)
+        # Set the active server
+        active_server = server_hostname
+        # Launch Controller communication
+        controller = Controller(config, server_hostname, heartbeat_stop_callback)
+        controller.start()
+        controller.join()
+
+      #
+      # If Ambari Agent connected to the server or
+      # Ambari Agent was stopped using stop event
+      # Clean up if not Windows OS
+      #
+      if connected or stopped:
+        if not OSCheck.get_os_family() == OSConst.WINSRV_FAMILY:
+          ExitHelper.execute_cleanup()
+          stop_agent()
+        logger.info("finished")
+        break
+    pass # for server_hostname in server_hostnames
+  pass # while not (connected or stopped)
+
+  return active_server
 
 if __name__ == "__main__":
   is_logger_setup = False

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/main/python/ambari_agent/security.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/security.py b/ambari-agent/src/main/python/ambari_agent/security.py
index dc1f141..779b85c 100644
--- a/ambari-agent/src/main/python/ambari_agent/security.py
+++ b/ambari-agent/src/main/python/ambari_agent/security.py
@@ -43,10 +43,11 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
   def __init__(self, host, port=None, config=None):
     httplib.HTTPSConnection.__init__(self, host, port=port)
     self.two_way_ssl_required = False
+    self.host = host
     self.config = config
 
   def connect(self):
-    self.two_way_ssl_required = self.config.isTwoWaySSLConnection()
+    self.two_way_ssl_required = self.config.isTwoWaySSLConnection(self.host)
     logger.debug("Server two-way SSL authentication required: %s" % str(
       self.two_way_ssl_required))
     if self.two_way_ssl_required is True:
@@ -66,7 +67,7 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
           '/ failed. Reconnecting using two-way SSL authentication..')
 
     if self.two_way_ssl_required:
-      self.certMan = CertificateManager(self.config)
+      self.certMan = CertificateManager(self.config, self.host)
       self.certMan.initSecurity()
       agent_key = self.certMan.getAgentKeyName()
       agent_crt = self.certMan.getAgentCrtName()
@@ -109,10 +110,10 @@ class VerifiedHTTPSConnection(httplib.HTTPSConnection):
 class CachedHTTPSConnection:
   """ Caches a ssl socket and uses a single https connection to the server. """
 
-  def __init__(self, config):
+  def __init__(self, config, server_hostname):
     self.connected = False
     self.config = config
-    self.server = hostname.server_hostname(config)
+    self.server = server_hostname
     self.port = config.get('server', 'secured_url_port')
     self.connect()
 
@@ -151,11 +152,11 @@ class CachedHTTPSConnection:
 
 
 class CertificateManager():
-  def __init__(self, config):
+  def __init__(self, config, server_hostname):
     self.config = config
     self.keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     self.server_crt = self.config.get('security', 'server_crt')
-    self.server_url = 'https://' + hostname.server_hostname(config) + ':' \
+    self.server_url = 'https://' + server_hostname + ':' \
                       + self.config.get('server', 'url_port')
 
   def getAgentKeyName(self):

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py b/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
index 1cf7866..30bf2df 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
@@ -39,7 +39,8 @@ class TestCertGeneration(TestCase):
     #config.add_section('security')
     config.set('security', 'keysdir', self.tmpdir)
     config.set('security', 'server_crt', 'ca.crt')
-    self.certMan = CertificateManager(config)
+    server_hostname = config.get('server', 'hostname')
+    self.certMan = CertificateManager(config, server_hostname)
 
   @patch.object(os, "chmod")
   def test_generation(self, chmod_mock):

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestController.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestController.py b/ambari-agent/src/test/python/ambari_agent/TestController.py
index fd20dce..045f077 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestController.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestController.py
@@ -64,8 +64,9 @@ class TestController(unittest.TestCase):
     config = MagicMock()
     #config.get.return_value = "something"
     config.get.return_value = "5"
+    server_hostname = "test_server"
 
-    self.controller = Controller.Controller(config)
+    self.controller = Controller.Controller(config, server_hostname)
     self.controller.netutil.MINIMUM_INTERVAL_BETWEEN_HEARTBEATS = 0.1
     self.controller.netutil.HEARTBEAT_NOT_IDDLE_INTERVAL_SEC = 0.1
 
@@ -384,7 +385,7 @@ class TestController(unittest.TestCase):
     self.assertEqual(actual, expected)
     
     security_mock.CachedHTTPSConnection.assert_called_once_with(
-      self.controller.config)
+      self.controller.config, self.controller.serverHostname)
     requestMock.called_once_with(url, data,
       {'Content-Type': 'application/ambari_simplejson'})
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestHostname.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestHostname.py b/ambari-agent/src/test/python/ambari_agent/TestHostname.py
index 3cf6b17..c7edf37 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestHostname.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestHostname.py
@@ -41,19 +41,32 @@ class TestHostname(TestCase):
                       "hostname should equal the socket-based hostname")
     pass
 
-  def test_server_hostname(self):
-    hostname.cached_server_hostname = None
+  def test_server_hostnames(self):
+    hostname.cached_server_hostnames = []
     config = AmbariConfig()
     default_server_hostname = config.get('server', 'hostname')
     config.set('server', 'hostname', 'ambari-host')
-    self.assertEquals('ambari-host', hostname.server_hostname(config),
-                      "hostname should equal the socket-based hostname")
+    server_hostnames = hostname.server_hostnames(config)
+    self.assertEquals(['ambari-host'], server_hostnames,
+                      "expected host name ['ambari-host']; got {0}".format(server_hostnames))
+    config.set('server', 'hostname', default_server_hostname)
+    pass
+
+  def test_server_hostnames_multiple(self):
+    hostname.cached_server_hostnames = []
+    config = AmbariConfig()
+    default_server_hostname = config.get('server', 'hostname')
+    config.set('server', 'hostname', 'ambari-host, ambari-host2, ambari-host3')
+    server_hostnames = hostname.server_hostnames(config)
+    self.assertEquals(len(server_hostnames), 3)
+    self.assertEquals(['ambari-host', 'ambari-host2', 'ambari-host3'], server_hostnames,
+                      "expected host name ['ambari-host']; got {0}".format(server_hostnames))
     config.set('server', 'hostname', default_server_hostname)
     pass
 
   @not_for_platform(PLATFORM_WINDOWS)
-  def test_server_hostname_override(self):
-    hostname.cached_server_hostname = None
+  def test_server_hostnames_override(self):
+    hostname.cached_server_hostnames = []
     fd = tempfile.mkstemp(text=True)
     tmpname = fd[1]
     os.close(fd[0])
@@ -67,7 +80,33 @@ class TestHostname(TestCase):
 
       config.set('server', 'hostname_script', tmpname)
 
-      self.assertEquals(hostname.server_hostname(config), 'test.example.com', "expected hostname 'test.example.com'")
+      server_hostnames = hostname.server_hostnames(config)
+      self.assertEquals(server_hostnames, ['test.example.com'], "expected hostname ['test.example.com']; got {0}".format(server_hostnames))
+    finally:
+      os.remove(tmpname)
+      config.remove_option('server', 'hostname_script')
+    pass
+
+
+  @not_for_platform(PLATFORM_WINDOWS)
+  def test_server_hostnames_multiple_override(self):
+    hostname.cached_server_hostnames = []
+    fd = tempfile.mkstemp(text=True)
+    tmpname = fd[1]
+    os.close(fd[0])
+    os.chmod(tmpname, os.stat(tmpname).st_mode | stat.S_IXUSR)
+
+    tmpfile = file(tmpname, "w+")
+    config = AmbariConfig()
+    try:
+      tmpfile.write("#!/bin/sh\n\necho 'host1.example.com, host2.example.com, host3.example.com'")
+      tmpfile.close()
+
+      config.set('server', 'hostname_script', tmpname)
+
+      expected_hostnames = ['host1.example.com', 'host2.example.com', 'host3.example.com']
+      server_hostnames = hostname.server_hostnames(config)
+      self.assertEquals(server_hostnames, expected_hostnames, "expected hostnames {0}; got {1}".format(expected_hostnames, server_hostnames))
     finally:
       os.remove(tmpname)
       config.remove_option('server', 'hostname_script')

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestMain.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestMain.py b/ambari-agent/src/test/python/ambari_agent/TestMain.py
index e837fcf..d921b54 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestMain.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestMain.py
@@ -26,6 +26,7 @@ import os
 import socket
 import tempfile
 import ConfigParser
+import ambari_agent.hostname as hostname
 
 from ambari_commons import OSCheck
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
@@ -322,7 +323,7 @@ class TestMain(unittest.TestCase):
     ping_port_init_mock.return_value = None
     options = MagicMock()
     parse_args_mock.return_value = (options, MagicMock)
-    try_to_connect_mock.return_value = (0, True)
+    try_to_connect_mock.return_value = (0, True, False)  # (retries, connected, stopped)
     # use default unix config
     ambari_config_mock.return_value = self.init_ambari_config_mock()
     #testing call without command-line arguments
@@ -337,7 +338,7 @@ class TestMain(unittest.TestCase):
     if OSCheck.get_os_family() != OSConst.WINSRV_FAMILY:
       self.assertTrue(daemonize_mock.called)
     self.assertTrue(update_log_level_mock.called)
-    try_to_connect_mock.assert_called_once_with(ANY, -1, ANY)
+    try_to_connect_mock.assert_called_once_with(ANY, main.MAX_RETRIES, ANY)
     self.assertTrue(start_mock.called)
     self.assertTrue(data_clean_init_mock.called)
     self.assertTrue(data_clean_start_mock.called)
@@ -351,4 +352,26 @@ class TestMain(unittest.TestCase):
     options.expected_hostname = "test.hst"
     main.main()
     perform_prestart_checks_mock.assert_called_once_with(options.expected_hostname)
+
+    # Test with multiple server hostnames
+    default_server_hostnames = hostname.cached_server_hostnames
+    hostname.cached_server_hostnames = ['host1', 'host2', 'host3']
+    def try_to_connect_impl(*args, **kwargs):
+      for server_hostname in hostname.cached_server_hostnames:
+        if (args[0].find(server_hostname) != -1):
+          if server_hostname == 'host1':
+            return 0, False, False
+          elif server_hostname == 'host2':
+            return 0, False, False
+          elif server_hostname == 'host3':
+            return 0, True, False
+          else:
+            return 0, True, False
+      pass
+
+    try_to_connect_mock.reset_mock()
+    try_to_connect_mock.side_effect = try_to_connect_impl
+    active_server = main.main()
+    self.assertEquals(active_server, 'host3')
+    hostname.cached_server_hostnames = default_server_hostnames
     pass
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py b/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
index ec4818e..0cbf1e9 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
@@ -65,7 +65,7 @@ class TestNetUtil(unittest.TestCase):
     netutil.checkURL = checkURL
 
     # one successful get
-    self.assertEqual((0, True), netutil.try_to_connect("url", 10))
+    self.assertEqual((0, True, False), netutil.try_to_connect("url", 10))
 
     # got successful after N retries
     gets = [[True, ""], [False, ""], [False, ""]]
@@ -73,9 +73,9 @@ class TestNetUtil(unittest.TestCase):
     def side_effect(*args):
       return gets.pop()
     checkURL.side_effect = side_effect
-    self.assertEqual((2, True), netutil.try_to_connect("url", 10))
+    self.assertEqual((2, True, False), netutil.try_to_connect("url", 10))
 
     # max retries
     checkURL.side_effect = None
     checkURL.return_value = False, "test"
-    self.assertEqual((5,False), netutil.try_to_connect("url", 5))
+    self.assertEqual((5, False, False), netutil.try_to_connect("url", 5))

http://git-wip-us.apache.org/repos/asf/ambari/blob/6df37bba/ambari-agent/src/test/python/ambari_agent/TestSecurity.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestSecurity.py b/ambari-agent/src/test/python/ambari_agent/TestSecurity.py
index c1b7812..d4160e4 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestSecurity.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestSecurity.py
@@ -52,7 +52,7 @@ class TestSecurity(unittest.TestCase):
     self.config = AmbariConfig()
     # Instantiate CachedHTTPSConnection (skip connect() call)
     with patch.object(security.VerifiedHTTPSConnection, "connect"):
-      self.cachedHTTPSConnection = security.CachedHTTPSConnection(self.config)
+      self.cachedHTTPSConnection = security.CachedHTTPSConnection(self.config, "example.com")
 
 
   def tearDown(self):
@@ -177,7 +177,7 @@ class TestSecurity(unittest.TestCase):
   def test_getAgentKeyName(self, hostname_mock):
     hostname_mock.return_value = "dummy.hostname"
     self.config.set('security', 'keysdir', '/dummy-keysdir')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     res = man.getAgentKeyName()
     self.assertEquals(res, os.path.abspath("/dummy-keysdir/dummy.hostname.key"))
 
@@ -186,7 +186,7 @@ class TestSecurity(unittest.TestCase):
   def test_getAgentCrtName(self, hostname_mock):
     hostname_mock.return_value = "dummy.hostname"
     self.config.set('security', 'keysdir', '/dummy-keysdir')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     res = man.getAgentCrtName()
     self.assertEquals(res, os.path.abspath("/dummy-keysdir/dummy.hostname.crt"))
 
@@ -195,14 +195,14 @@ class TestSecurity(unittest.TestCase):
   def test_getAgentCrtReqName(self, hostname_mock):
     hostname_mock.return_value = "dummy.hostname"
     self.config.set('security', 'keysdir', '/dummy-keysdir')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     res = man.getAgentCrtReqName()
     self.assertEquals(res, os.path.abspath("/dummy-keysdir/dummy.hostname.csr"))
 
 
   def test_getSrvrCrtName(self):
     self.config.set('security', 'keysdir', '/dummy-keysdir')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     res = man.getSrvrCrtName()
     self.assertEquals(res, os.path.abspath("/dummy-keysdir/ca.crt"))
 
@@ -219,7 +219,7 @@ class TestSecurity(unittest.TestCase):
     self.config.set('security', 'keysdir', '/dummy-keysdir')
     getAgentKeyName_mock.return_value = "dummy AgentKeyName"
     getAgentCrtName_mock.return_value = "dummy AgentCrtName"
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
 
     # Case when all files exist
     exists_mock.side_effect = [True, True, True]
@@ -263,7 +263,7 @@ class TestSecurity(unittest.TestCase):
     _, tmpoutfile = tempfile.mkstemp()
     getSrvrCrtName_mock.return_value = tmpoutfile
 
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     man.loadSrvrCrt()
 
     # Checking file contents
@@ -285,7 +285,7 @@ class TestSecurity(unittest.TestCase):
   def test_reqSignCrt(self, loads_mock, urlopen_mock, request_mock, dumps_mock, open_mock, hostname_mock):
     self.config.set('security', 'keysdir', '/dummy-keysdir')
     self.config.set('security', 'passphrase_env_var_name', 'DUMMY_PASSPHRASE')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     hostname_mock.return_value = "dummy-hostname"
 
     open_mock.return_value.read.return_value = "dummy_request"
@@ -345,7 +345,7 @@ class TestSecurity(unittest.TestCase):
   @patch("subprocess.Popen.communicate")
   @patch.object(os, "chmod")
   def test_genAgentCrtReq(self, chmod_mock, communicate_mock, popen_mock):
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     p = MagicMock(spec=subprocess.Popen)
     p.communicate = communicate_mock
     popen_mock.return_value = p
@@ -363,7 +363,7 @@ class TestSecurity(unittest.TestCase):
     open_mock.return_value.read.return_value = "dummy_request"
     self.config.set('security', 'keysdir', '/dummy-keysdir')
     self.config.set('security', 'passphrase_env_var_name', 'DUMMY_PASSPHRASE')
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
 
     # test valid JSON response
     urlopen_mock.return_value.read.return_value = '{"result": "OK", "signedCa":"dummy"}'
@@ -385,7 +385,7 @@ class TestSecurity(unittest.TestCase):
 
   @patch.object(security.CertificateManager, "checkCertExists")
   def test_initSecurity(self, checkCertExists_method):
-    man = CertificateManager(self.config)
+    man = CertificateManager(self.config, "active_server")
     man.initSecurity()
     self.assertTrue(checkCertExists_method.called)