瀏覽代碼

AMBARI-5423 Remove hard coded Service, Component mapping from LiveStatus.py (dsen)

Dmitry Sen 11 年之前
父節點
當前提交
03e04a684a

+ 25 - 1
ambari-agent/src/main/python/ambari_agent/Controller.py

@@ -31,13 +31,13 @@ from random import randint
 
 import hostname
 import AmbariConfig
-import ProcessHelper
 from Heartbeat import Heartbeat
 from Register import Register
 from ActionQueue import ActionQueue
 import security
 from NetUtil import NetUtil
 import ssl
+from LiveStatus import LiveStatus
 
 
 logger = logging.getLogger()
@@ -58,6 +58,7 @@ class Controller(threading.Thread):
                          ':' + config.get('server', 'secured_url_port')
     self.registerUrl = server_secured_url + '/agent/v1/register/' + self.hostname
     self.heartbeatUrl = server_secured_url + '/agent/v1/heartbeat/' + self.hostname
+    self.componentsUrl = server_secured_url + '/agent/v1/components/'
     self.netutil = NetUtil()
     self.responseId = -1
     self.repeatRegistration = False
@@ -77,6 +78,9 @@ class Controller(threading.Thread):
     pass
   
   def registerWithServer(self):
+    LiveStatus.SERVICES = []
+    LiveStatus.CLIENT_COMPONENTS = []
+    LiveStatus.COMPONENTS = []
     id = -1
     ret = {}
 
@@ -142,6 +146,8 @@ class Controller(threading.Thread):
     if not commands:
       logger.debug("No status commands from the server : " + pprint.pformat(commands))
     else:
+      if not LiveStatus.SERVICES:
+        self.updateComponents(commands[0]['clusterName'])
       self.actionQueue.put_status(commands)
     pass
 
@@ -283,6 +289,24 @@ class Controller(threading.Thread):
     response = self.cachedconnect.request(req)
     return response
 
+  def updateComponents(self, cluster_name):
+    logger.info("Updating components map of cluster " + cluster_name)
+    response = self.sendRequest(self.componentsUrl + cluster_name, None)
+    logger.debug("Response from server = " + response)
+    response = json.loads(response)
+    for service, components in response['components'].items():
+      LiveStatus.SERVICES.append(service)
+      for component, category in components.items():
+        if category == 'CLIENT':
+          LiveStatus.CLIENT_COMPONENTS.append({"serviceName": service, "componentName": component})
+        else:
+          LiveStatus.COMPONENTS.append({"serviceName": service, "componentName": component})
+    logger.info("Components map updated")
+    logger.debug("LiveStatus.SERVICES" + str(LiveStatus.SERVICES))
+    logger.debug("LiveStatus.CLIENT_COMPONENTS" + str(LiveStatus.CLIENT_COMPONENTS))
+    logger.debug("LiveStatus.COMPONENTS" + str(LiveStatus.COMPONENTS))
+    pass
+
 def main(argv=None):
   # Allow Ctrl-C
   signal.signal(signal.SIGINT, signal.SIG_DFL)

+ 3 - 116
ambari-agent/src/main/python/ambari_agent/LiveStatus.py

@@ -29,122 +29,9 @@ logger = logging.getLogger()
 
 class LiveStatus:
 
-  SERVICES = [
-    "HDFS", "MAPREDUCE", "GANGLIA", "HBASE",
-    "NAGIOS", "ZOOKEEPER", "OOZIE", "HCATALOG",
-    "KERBEROS", "TEMPLETON", "HIVE", "WEBHCAT",
-    "YARN", "MAPREDUCE2", "FLUME", "TEZ",
-    "FALCON", "STORM"
-  ]
-
-  CLIENT_COMPONENTS = [
-    {"serviceName" : "HBASE",
-     "componentName" : "HBASE_CLIENT"},
-    {"serviceName" : "HDFS",
-     "componentName" : "HDFS_CLIENT"},
-    {"serviceName" : "MAPREDUCE",
-     "componentName" : "MAPREDUCE_CLIENT"},
-    {"serviceName" : "ZOOKEEPER",
-     "componentName" : "ZOOKEEPER_CLIENT"},
-    {"serviceName" : "OOZIE",
-     "componentName" : "OOZIE_CLIENT"},
-    {"serviceName" : "HCATALOG",
-     "componentName" : "HCAT"},
-    {"serviceName" : "HIVE",
-     "componentName" : "HIVE_CLIENT"},
-    {"serviceName" : "YARN",
-     "componentName" : "YARN_CLIENT"},
-    {"serviceName" : "MAPREDUCE2",
-     "componentName" : "MAPREDUCE2_CLIENT"},
-    {"serviceName" : "PIG",
-     "componentName" : "PIG"},
-    {"serviceName" : "SQOOP",
-     "componentName" : "SQOOP"},
-    {"serviceName" : "TEZ",
-     "componentName" : "TEZ_CLIENT"},
-    {"serviceName" : "FALCON",
-     "componentName" : "FALCON_CLIENT"}
-  ]
-
-  COMPONENTS = [
-      {"serviceName" : "HDFS",
-       "componentName" : "DATANODE"},
-      {"serviceName" : "HDFS",
-       "componentName" : "NAMENODE"},
-      {"serviceName" : "HDFS",
-       "componentName" : "SECONDARY_NAMENODE"},
-      {"serviceName" : "HDFS",
-       "componentName" : "JOURNALNODE"},
-      {"serviceName" : "HDFS",
-       "componentName" : "ZKFC"},
-
-      {"serviceName" : "MAPREDUCE",
-       "componentName" : "JOBTRACKER"},
-      {"serviceName" : "MAPREDUCE",
-       "componentName" : "TASKTRACKER"},
-
-      {"serviceName" : "GANGLIA",
-       "componentName" : "GANGLIA_SERVER"},
-      {"serviceName" : "GANGLIA",
-       "componentName" : "GANGLIA_MONITOR"},
-
-      {"serviceName" : "HBASE",
-       "componentName" : "HBASE_MASTER"},
-      {"serviceName" : "HBASE",
-       "componentName" : "HBASE_REGIONSERVER"},
-
-      {"serviceName" : "NAGIOS",
-       "componentName" : "NAGIOS_SERVER"},
-
-      {"serviceName" : "FLUME",
-       "componentName" : "FLUME_SERVER"},
-
-      {"serviceName" : "ZOOKEEPER",
-       "componentName" : "ZOOKEEPER_SERVER"},
-
-      {"serviceName" : "OOZIE",
-       "componentName" : "OOZIE_SERVER"},
-
-      {"serviceName" : "HCATALOG",
-       "componentName" : "HCATALOG_SERVER"},
-
-      {"serviceName" : "KERBEROS",
-       "componentName" : "KERBEROS_SERVER"},
-
-      {"serviceName" : "HIVE",
-       "componentName" : "HIVE_SERVER"},
-      {"serviceName" : "HIVE",
-       "componentName" : "HIVE_METASTORE"},
-      {"serviceName" : "HIVE",
-       "componentName" : "MYSQL_SERVER"},
-
-      {"serviceName" : "WEBHCAT",
-       "componentName" : "WEBHCAT_SERVER"},
-
-      {"serviceName" : "YARN",
-       "componentName" : "RESOURCEMANAGER"},
-      {"serviceName" : "YARN",
-       "componentName" : "NODEMANAGER"},
-      {"serviceName" : "YARN",
-       "componentName" : "APP_TIMELINE_SERVER"},
-
-      {"serviceName" : "MAPREDUCE2",
-       "componentName" : "HISTORYSERVER"},
-
-      {"serviceName" : "FALCON",
-       "componentName" : "FALCON_SERVER"},
-
-      {"serviceName" : "STORM",
-       "componentName" : "NIMBUS"},
-      {"serviceName" : "STORM",
-       "componentName" : "STORM_REST_API"},
-      {"serviceName" : "STORM",
-       "componentName" : "SUPERVISOR"},
-      {"serviceName" : "STORM",
-       "componentName" : "STORM_UI_SERVER"},
-      {"serviceName" : "STORM",
-       "componentName" : "DRPC_SERVER"}
-  ]
+  SERVICES = []
+  CLIENT_COMPONENTS = []
+  COMPONENTS = []
 
   LIVE_STATUS = "STARTED"
   DEAD_STATUS = "INSTALLED"

+ 102 - 0
ambari-agent/src/test/python/ambari_agent/TestActualConfigHandler.py

@@ -22,6 +22,7 @@ from unittest import TestCase
 import os
 import logging
 from mock.mock import patch
+from ambari_agent.LiveStatus import LiveStatus
 
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
   from ambari_agent.AmbariConfig import AmbariConfig
@@ -30,6 +31,107 @@ with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
 
 class TestActualConfigHandler(TestCase):
 
+  def setUp(self):
+    LiveStatus.SERVICES = [
+      "HDFS", "MAPREDUCE", "GANGLIA", "HBASE",
+      "NAGIOS", "ZOOKEEPER", "OOZIE", "HCATALOG",
+      "KERBEROS", "TEMPLETON", "HIVE", "WEBHCAT",
+      "YARN", "MAPREDUCE2", "FLUME", "TEZ",
+      "FALCON", "STORM"
+    ]
+    LiveStatus.CLIENT_COMPONENTS = [
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_CLIENT"},
+      {"serviceName" : "HDFS",
+       "componentName" : "HDFS_CLIENT"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "MAPREDUCE_CLIENT"},
+      {"serviceName" : "ZOOKEEPER",
+       "componentName" : "ZOOKEEPER_CLIENT"},
+      {"serviceName" : "OOZIE",
+       "componentName" : "OOZIE_CLIENT"},
+      {"serviceName" : "HCATALOG",
+       "componentName" : "HCAT"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_CLIENT"},
+      {"serviceName" : "YARN",
+       "componentName" : "YARN_CLIENT"},
+      {"serviceName" : "MAPREDUCE2",
+       "componentName" : "MAPREDUCE2_CLIENT"},
+      {"serviceName" : "PIG",
+       "componentName" : "PIG"},
+      {"serviceName" : "SQOOP",
+       "componentName" : "SQOOP"},
+      {"serviceName" : "TEZ",
+       "componentName" : "TEZ_CLIENT"},
+      {"serviceName" : "FALCON",
+       "componentName" : "FALCON_CLIENT"}
+    ]
+    LiveStatus.COMPONENTS = [
+      {"serviceName" : "HDFS",
+       "componentName" : "DATANODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "NAMENODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "SECONDARY_NAMENODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "JOURNALNODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "ZKFC"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "JOBTRACKER"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "TASKTRACKER"},
+      {"serviceName" : "GANGLIA",
+       "componentName" : "GANGLIA_SERVER"},
+      {"serviceName" : "GANGLIA",
+       "componentName" : "GANGLIA_MONITOR"},
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_MASTER"},
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_REGIONSERVER"},
+      {"serviceName" : "NAGIOS",
+       "componentName" : "NAGIOS_SERVER"},
+      {"serviceName" : "FLUME",
+       "componentName" : "FLUME_SERVER"},
+      {"serviceName" : "ZOOKEEPER",
+       "componentName" : "ZOOKEEPER_SERVER"},
+      {"serviceName" : "OOZIE",
+       "componentName" : "OOZIE_SERVER"},
+      {"serviceName" : "HCATALOG",
+       "componentName" : "HCATALOG_SERVER"},
+      {"serviceName" : "KERBEROS",
+       "componentName" : "KERBEROS_SERVER"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_SERVER"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_METASTORE"},
+      {"serviceName" : "HIVE",
+       "componentName" : "MYSQL_SERVER"},
+      {"serviceName" : "WEBHCAT",
+       "componentName" : "WEBHCAT_SERVER"},
+      {"serviceName" : "YARN",
+       "componentName" : "RESOURCEMANAGER"},
+      {"serviceName" : "YARN",
+       "componentName" : "NODEMANAGER"},
+      {"serviceName" : "YARN",
+       "componentName" : "APP_TIMELINE_SERVER"},
+      {"serviceName" : "MAPREDUCE2",
+       "componentName" : "HISTORYSERVER"},
+      {"serviceName" : "FALCON",
+       "componentName" : "FALCON_SERVER"},
+      {"serviceName" : "STORM",
+       "componentName" : "NIMBUS"},
+      {"serviceName" : "STORM",
+       "componentName" : "STORM_REST_API"},
+      {"serviceName" : "STORM",
+       "componentName" : "SUPERVISOR"},
+      {"serviceName" : "STORM",
+       "componentName" : "STORM_UI_SERVER"},
+      {"serviceName" : "STORM",
+       "componentName" : "DRPC_SERVER"}
+    ]
+
   logger = logging.getLogger()
 
   def test_read_write(self):

+ 58 - 4
ambari-agent/src/test/python/ambari_agent/TestController.py

@@ -27,6 +27,7 @@ from mock.mock import patch, MagicMock, call, Mock
 import logging
 import platform
 from threading import Event
+import json
 
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
   from ambari_agent import Controller, ActionQueue
@@ -63,12 +64,17 @@ class TestController(unittest.TestCase):
   @patch("time.sleep")
   @patch("pprint.pformat")
   @patch.object(Controller, "randint")
-  def test_registerWithServer(self, randintMock, pformatMock, sleepMock,
+  @patch.object(Controller, "LiveStatus")
+  def test_registerWithServer(self, LiveStatus_mock, randintMock, pformatMock, sleepMock,
                               dumpsMock):
 
     out = StringIO.StringIO()
     sys.stdout = out
 
+    LiveStatus_mock.SERVICES = ["foo"]
+    LiveStatus_mock.CLIENT_COMPONENTS = ["foo"]
+    LiveStatus_mock.COMPONENTS = ["foo"]
+
     register = MagicMock()
     self.controller.register = register
 
@@ -78,6 +84,9 @@ class TestController(unittest.TestCase):
     self.controller.sendRequest.return_value = '{"log":"Error text", "exitstatus":"1"}'
 
     self.assertEqual({u'exitstatus': u'1', u'log': u'Error text'}, self.controller.registerWithServer())
+    self.assertEqual(LiveStatus_mock.SERVICES, [])
+    self.assertEqual(LiveStatus_mock.CLIENT_COMPONENTS, [])
+    self.assertEqual(LiveStatus_mock.COMPONENTS, [])
 
     self.controller.sendRequest.return_value = '{"responseId":1}'
     self.assertEqual({"responseId":1}, self.controller.registerWithServer())
@@ -122,14 +131,29 @@ class TestController(unittest.TestCase):
 
 
   @patch("pprint.pformat")
-  def test_addToStatusQueue(self, pformatMock):
-
+  @patch.object(Controller, "LiveStatus")
+  def test_addToStatusQueue(self, LiveStatus_mock, pformatMock):
+    LiveStatus_mock.SERVICES = ["foo"]
+    LiveStatus_mock.CLIENT_COMPONENTS = ["foo"]
+    LiveStatus_mock.COMPONENTS = ["foo"]
+    commands = json.loads('[{"clusterName":"dummy_cluster"}]')
     actionQueue = MagicMock()
     self.controller.actionQueue = actionQueue
+    updateComponents = Mock()
+    self.controller.updateComponents = updateComponents
     self.controller.addToStatusQueue(None)
     self.assertFalse(actionQueue.put_status.called)
-    self.controller.addToStatusQueue("cmd")
+    self.assertFalse(updateComponents.called)
+    self.controller.addToStatusQueue(commands)
     self.assertTrue(actionQueue.put_status.called)
+    self.assertFalse(updateComponents.called)
+    LiveStatus_mock.SERVICES = []
+    LiveStatus_mock.CLIENT_COMPONENTS = []
+    LiveStatus_mock.COMPONENTS = []
+    self.controller.addToStatusQueue(commands)
+    self.assertTrue(updateComponents.called)
+    self.assertTrue(actionQueue.put_status.called)
+
 
 
   @patch("urllib2.build_opener")
@@ -459,6 +483,36 @@ class TestController(unittest.TestCase):
     #Conroller thread and the agent stop if the repeatRegistration flag is False
     self.assertFalse(self.controller.repeatRegistration)
 
+  @patch.object(Controller, "LiveStatus")
+  def test_updateComponents(self, LiveStatus_mock):
+    LiveStatus_mock.SERVICES = []
+    LiveStatus_mock.CLIENT_COMPONENTS = []
+    LiveStatus_mock.COMPONENTS = []
+    self.controller.componentsUrl = "foo_url/"
+    sendRequest = Mock()
+    self.controller.sendRequest = sendRequest
+    self.controller.sendRequest.return_value = ('{"clusterName":"dummy_cluster_name",'
+                                                '"stackName":"dummy_stack_name",'
+                                                '"stackVersion":"dummy_stack_version",'
+                                                '"components":{"PIG":{"PIG":"CLIENT"},'
+                                                '"MAPREDUCE":{"MAPREDUCE_CLIENT":"CLIENT",'
+                                                '"JOBTRACKER":"MASTER","TASKTRACKER":"SLAVE"}}}')
+    self.controller.updateComponents("dummy_cluster_name")
+    sendRequest.assert_called_with('foo_url/dummy_cluster_name', None)
+    services_expected = [u'MAPREDUCE', u'PIG']
+    client_components_expected = [
+      {'serviceName':u'MAPREDUCE','componentName':u'MAPREDUCE_CLIENT'},
+      {'serviceName':u'PIG','componentName':u'PIG'}
+    ]
+    components_expected = [
+      {'serviceName':u'MAPREDUCE','componentName':u'TASKTRACKER'},
+      {'serviceName':u'MAPREDUCE','componentName':u'JOBTRACKER'}
+    ]
+    self.assertEquals(LiveStatus_mock.SERVICES, services_expected)
+    self.assertEquals(LiveStatus_mock.CLIENT_COMPONENTS, client_components_expected)
+    self.assertEquals(LiveStatus_mock.COMPONENTS, components_expected)
+
+
 if __name__ == "__main__":
   unittest.main(verbosity=2)
 

+ 99 - 0
ambari-agent/src/test/python/ambari_agent/TestLiveStatus.py

@@ -34,6 +34,105 @@ class TestLiveStatus(TestCase):
     # disable stdout
     out = StringIO.StringIO()
     sys.stdout = out
+    LiveStatus.SERVICES = [
+      "HDFS", "MAPREDUCE", "GANGLIA", "HBASE",
+      "NAGIOS", "ZOOKEEPER", "OOZIE", "HCATALOG",
+      "KERBEROS", "TEMPLETON", "HIVE", "WEBHCAT",
+      "YARN", "MAPREDUCE2", "FLUME", "TEZ",
+      "FALCON", "STORM"
+    ]
+    LiveStatus.CLIENT_COMPONENTS = [
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_CLIENT"},
+      {"serviceName" : "HDFS",
+       "componentName" : "HDFS_CLIENT"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "MAPREDUCE_CLIENT"},
+      {"serviceName" : "ZOOKEEPER",
+       "componentName" : "ZOOKEEPER_CLIENT"},
+      {"serviceName" : "OOZIE",
+       "componentName" : "OOZIE_CLIENT"},
+      {"serviceName" : "HCATALOG",
+       "componentName" : "HCAT"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_CLIENT"},
+      {"serviceName" : "YARN",
+       "componentName" : "YARN_CLIENT"},
+      {"serviceName" : "MAPREDUCE2",
+       "componentName" : "MAPREDUCE2_CLIENT"},
+      {"serviceName" : "PIG",
+       "componentName" : "PIG"},
+      {"serviceName" : "SQOOP",
+       "componentName" : "SQOOP"},
+      {"serviceName" : "TEZ",
+       "componentName" : "TEZ_CLIENT"},
+      {"serviceName" : "FALCON",
+       "componentName" : "FALCON_CLIENT"}
+    ]
+    LiveStatus.COMPONENTS = [
+      {"serviceName" : "HDFS",
+       "componentName" : "DATANODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "NAMENODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "SECONDARY_NAMENODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "JOURNALNODE"},
+      {"serviceName" : "HDFS",
+       "componentName" : "ZKFC"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "JOBTRACKER"},
+      {"serviceName" : "MAPREDUCE",
+       "componentName" : "TASKTRACKER"},
+      {"serviceName" : "GANGLIA",
+       "componentName" : "GANGLIA_SERVER"},
+      {"serviceName" : "GANGLIA",
+       "componentName" : "GANGLIA_MONITOR"},
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_MASTER"},
+      {"serviceName" : "HBASE",
+       "componentName" : "HBASE_REGIONSERVER"},
+      {"serviceName" : "NAGIOS",
+       "componentName" : "NAGIOS_SERVER"},
+      {"serviceName" : "FLUME",
+       "componentName" : "FLUME_SERVER"},
+      {"serviceName" : "ZOOKEEPER",
+       "componentName" : "ZOOKEEPER_SERVER"},
+      {"serviceName" : "OOZIE",
+       "componentName" : "OOZIE_SERVER"},
+      {"serviceName" : "HCATALOG",
+       "componentName" : "HCATALOG_SERVER"},
+      {"serviceName" : "KERBEROS",
+       "componentName" : "KERBEROS_SERVER"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_SERVER"},
+      {"serviceName" : "HIVE",
+       "componentName" : "HIVE_METASTORE"},
+      {"serviceName" : "HIVE",
+       "componentName" : "MYSQL_SERVER"},
+      {"serviceName" : "WEBHCAT",
+       "componentName" : "WEBHCAT_SERVER"},
+      {"serviceName" : "YARN",
+       "componentName" : "RESOURCEMANAGER"},
+      {"serviceName" : "YARN",
+       "componentName" : "NODEMANAGER"},
+      {"serviceName" : "YARN",
+       "componentName" : "APP_TIMELINE_SERVER"},
+      {"serviceName" : "MAPREDUCE2",
+       "componentName" : "HISTORYSERVER"},
+      {"serviceName" : "FALCON",
+       "componentName" : "FALCON_SERVER"},
+      {"serviceName" : "STORM",
+       "componentName" : "NIMBUS"},
+      {"serviceName" : "STORM",
+       "componentName" : "STORM_REST_API"},
+      {"serviceName" : "STORM",
+       "componentName" : "SUPERVISOR"},
+      {"serviceName" : "STORM",
+       "componentName" : "STORM_UI_SERVER"},
+      {"serviceName" : "STORM",
+       "componentName" : "DRPC_SERVER"}
+    ]
 
 
   def tearDown(self):

+ 0 - 30
ambari-agent/src/test/python/ambari_agent/TestManifestGenerator.py

@@ -60,36 +60,6 @@ class TestManifestGenerator(TestCase):
     print tmpFile.read()
     tmpFile.close()
 
-
-    pass
-
-  @patch.object(manifestGenerator, 'writeHostnames')
-  @patch.object(manifestGenerator, 'writeImports')
-  @patch.object(manifestGenerator, 'writeNodes')
-  @patch.object(manifestGenerator, 'writeParams')
-  @patch.object(manifestGenerator, 'writeTasks')
-  @patch.object(manifestGenerator, 'decompressClusterHostInfo')
-  def testGenerateManifest(self, decompressClusterHostInfoMock, writeTasksMock,
-                           writeParamsMock, writeNodesMock, writeImportsMock, writeHostnamesMock):
-    tmpFileName = tempfile.mkstemp(dir=self.dir, text=True)[1]
-    self.parsedJson['roleParams'] = 'role param'
-    manifestGenerator.generateManifest(self.parsedJson, tmpFileName, '../../main/puppet/modules', self.config.getConfig())
-
-    self.assertTrue(decompressClusterHostInfoMock.called)
-    self.assertTrue(writeImportsMock.called)
-    self.assertTrue(writeHostnamesMock.called)
-    self.assertTrue(writeNodesMock.called)
-    self.assertTrue(writeParamsMock.called)
-    self.assertTrue(writeTasksMock.called)
-
-    print file(tmpFileName).read()
-
-    def raiseTypeError():
-      raise TypeError()
-    writeNodesMock.side_effect = raiseTypeError
-    manifestGenerator.generateManifest(self.parsedJson, tmpFileName, '../../main/puppet/modules', self.config.getConfig())
-    pass
-
   def testEscape(self):
     shouldBe = '\\\'\\\\'
     result = manifestGenerator.escape('\'\\')

+ 0 - 45
ambari-agent/src/test/python/ambari_agent/TestPuppetExecutor.py

@@ -112,51 +112,6 @@ class TestPuppetExecutor(TestCase):
     self.assertEquals(res["exitcode"], 1)
     self.assertEquals(res["stderr"], "Cannot access JDK! Make sure java_home is specified in hostLevelParams")
 
-
-  @patch.object(manifestGenerator, 'generateManifest')
-  @patch.object(PuppetExecutor, 'isJavaAvailable')
-  @patch.object(RepoInstaller, 'generate_repo_manifests')
-  @patch.object(PuppetExecutor, 'runPuppetFile')
-  def test_overwrite_repos(self, runPuppetFileMock, generateRepoManifestMock,
-                           isJavaAvailableMock, generateManifestMock):
-    tmpdir = tempfile.gettempdir()
-    puppetInstance = PuppetExecutor("/tmp", "/x", "/y", tmpdir, AmbariConfig().getConfig())
-    jsonFile = open('../../main/python/ambari_agent/test.json', 'r')
-    jsonStr = jsonFile.read()
-    parsedJson = json.loads(jsonStr)
-    parsedJson["taskId"] = 77
-    parsedJson['roleCommand'] = "START"
-    def side_effect_generate_manifest(command, siteppFileName,
-                                      modulesdir, config):
-      return None
-    generateManifestMock.side_effect = side_effect_generate_manifest
-    def side_effect(puppetFile, result, puppetEnv, tmpoutfile, tmperrfile, timeout):
-      result["exitcode"] = 0
-    runPuppetFileMock.side_effect = side_effect
-    
-    isJavaAvailableMock.return_value = True
-
-    #If ambari-agent has been just started and no any commands were executed by
-    # PuppetExecutor.runCommand, then no repo files were updated by
-    # RepoInstaller.generate_repo_manifests
-    self.assertEquals(0, generateRepoManifestMock.call_count)
-    self.assertFalse(puppetInstance.reposInstalled)
-
-    # After executing of the first command, RepoInstaller.generate_repo_manifests
-    # generates a .pp file for updating repo files
-    puppetInstance.runCommand(parsedJson, tmpdir + '/out.txt', tmpdir + '/err.txt')
-    self.assertTrue(puppetInstance.reposInstalled)
-    self.assertEquals(1, generateRepoManifestMock.call_count)
-    isJavaAvailableMock.assert_called_with("java64_home")
-
-    # After executing of the next commands, repo manifest aren't generated again
-    puppetInstance.runCommand(parsedJson, tmpdir + '/out.txt', tmpdir + '/err.txt')
-    self.assertTrue(puppetInstance.reposInstalled)
-    self.assertEquals(1, generateRepoManifestMock.call_count)
-    puppetInstance.runCommand(parsedJson, tmpdir + '/out.txt', tmpdir + '/err.txt')
-    self.assertTrue(puppetInstance.reposInstalled)
-    self.assertEquals(1, generateRepoManifestMock.call_count)
-
   @patch("os.path.exists")
   def test_configure_environ(self, osPathExistsMock):
     config = AmbariConfig().getConfig()

+ 79 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/ComponentsResponse.java

@@ -0,0 +1,79 @@
+/**
+ * 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.
+ */
+
+package org.apache.ambari.server.agent;
+
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class ComponentsResponse {
+	@JsonProperty("clusterName")
+	private String clusterName;
+
+	@JsonProperty("stackName")
+	private String stackName;
+
+	@JsonProperty("stackVersion")
+	private String stackVersion;
+
+	// <service, <component, category>>
+	@JsonProperty("components")
+	private Map<String, Map<String, String>> components;
+
+	public String getClusterName() {
+		return clusterName;
+	}
+
+	public void setClusterName(String clusterName) {
+		this.clusterName = clusterName;
+	}
+
+	public String getStackName() {
+		return stackName;
+	}
+
+	public void setStackName(String stackName) {
+		this.stackName = stackName;
+	}
+
+	public String getStackVersion() {
+		return stackVersion;
+	}
+
+	public void setStackVersion(String stackVersion) {
+		this.stackVersion = stackVersion;
+	}
+
+	public Map<String, Map<String, String>> getComponents() {
+		return components;
+	}
+
+	public void setComponents(Map<String, Map<String, String>> components) {
+		this.components = components;
+	}
+
+	@Override
+	public String toString() {
+		return "ComponentsResponse [clusterName=" + clusterName +
+      ", stackName=" + stackName +
+      ", stackVersion=" + stackVersion +
+      ", components=" + components + "]";
+	}
+
+}

+ 46 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java

@@ -17,6 +17,7 @@
  */
 package org.apache.ambari.server.agent;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -45,7 +46,9 @@ import org.apache.ambari.server.state.MaintenanceState;
 import org.apache.ambari.server.state.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
@@ -601,4 +604,47 @@ public class HeartBeatHandler {
       }
     }
   }
+
+  /**
+   * Response
+   * @param clusterName
+   * @return
+   * @throws AmbariException
+   */
+  public ComponentsResponse handleComponents(String clusterName)
+      throws AmbariException {
+    ComponentsResponse response = new ComponentsResponse();
+
+    Cluster cluster = this.clusterFsm.getCluster(clusterName);
+    StackId stackId = cluster.getCurrentStackVersion();
+    if (stackId == null) {
+      throw new AmbariException("Cannot provide stack components map. " +
+        "Stack hasn't been selected yet.");
+    }
+    StackInfo stack = this.ambariMetaInfo.getStackInfo(stackId.getStackName(),
+        stackId.getStackVersion());
+
+    response.setClusterName(clusterName);
+    response.setStackName(stackId.getStackName());
+    response.setStackVersion(stackId.getStackVersion());
+    response.setComponents(this.getComponentsMap(stack));
+
+    return response;
+  }
+
+  private Map<String, Map<String, String>> getComponentsMap(StackInfo stack) {
+    Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+
+    for (ServiceInfo service : stack.getServices()) {
+      Map<String, String> components = new HashMap<String, String>();
+
+      for (ComponentInfo component : service.getComponents()) {
+        components.put(component.getName(), component.getCategory());
+      }
+
+      result.put(service.getName(), components);
+    }
+
+    return result;
+  }
 }

+ 40 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/rest/AgentResource.java

@@ -20,14 +20,17 @@ package org.apache.ambari.server.agent.rest;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.agent.ComponentsResponse;
 import org.apache.ambari.server.agent.HeartBeat;
 import org.apache.ambari.server.agent.HeartBeatHandler;
 import org.apache.ambari.server.agent.HeartBeatResponse;
@@ -38,6 +41,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import com.google.inject.Inject;
+
 import org.apache.ambari.server.agent.RegistrationStatus;
 
 /**
@@ -127,4 +131,40 @@ public class AgentResource {
     }
     return heartBeatResponse;
   }
+
+  /**
+   * Retrieves the components category map for stack used on cluster
+   * (Internal API to be used by Ambari agent).
+   *
+   * @response.representation.200.doc This API is invoked by Ambari agent running
+   *  on a cluster to update the components category map of stack used by this cluster
+   * @response.representation.200.mediaType application/json
+   * @response.representation.408.doc Request Timed out
+   * @param clusterName of cluster
+   * @throws Exception
+   */
+  @Path("components/{clusterName}")
+  @GET
+  @Produces({MediaType.APPLICATION_JSON})
+  public ComponentsResponse components(
+      @PathParam("clusterName") String clusterName) {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Received Components request for cluster " + clusterName);
+    }
+
+    ComponentsResponse componentsResponse;
+
+    try {
+      componentsResponse = hh.handleComponents(clusterName);
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Sending components response");
+        LOG.debug("Response details " + componentsResponse);
+      }
+    } catch (Exception e) {
+      LOG.warn("Error in Components", e);
+      throw new WebApplicationException(500);
+    }
+
+    return componentsResponse;
+  }
 }

+ 15 - 0
ambari-server/src/test/java/org/apache/ambari/server/agent/AgentResourceTest.java

@@ -232,10 +232,22 @@ public class AgentResourceTest extends JerseyTest {
     Assert.assertEquals("directory", agentEnv.getStackFoldersAndFiles()[1].getType());    
   }
 
+  @Test
+  public void agentComponents() {
+    ComponentsResponse response;
+    ClientConfig clientConfig = new DefaultClientConfig();
+    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+    client = Client.create(clientConfig);
+    WebResource webResource = client.resource("http://localhost:9998/components/dummycluster");
+    response = webResource.get(ComponentsResponse.class);
+    Assert.assertEquals(response.getClusterName(), "dummycluster");
+  }
+
   public class MockModule extends AbstractModule {
 
     RegistrationResponse response = new RegistrationResponse();
     HeartBeatResponse hresponse = new HeartBeatResponse();
+    ComponentsResponse componentsResponse = new ComponentsResponse();
 
     @Override
     protected void configure() {
@@ -244,11 +256,14 @@ public class AgentResourceTest extends JerseyTest {
       handler = mock(HeartBeatHandler.class);
       response.setResponseStatus(RegistrationStatus.OK);
       hresponse.setResponseId(0L);
+      componentsResponse.setClusterName("dummycluster");
       try {
         when(handler.handleRegistration(any(Register.class))).thenReturn(
             response);
         when(handler.handleHeartBeat(any(HeartBeat.class))).thenReturn(
             hresponse);
+        when(handler.handleComponents(any(String.class))).thenReturn(
+            componentsResponse);
       } catch (Exception ex) {
         // The test will fail anyway
       }

+ 50 - 1
ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java

@@ -1642,6 +1642,53 @@ public class TestHeartbeatHandler {
 
   }
 
+  @Test
+  public void testComponents() throws AmbariException,
+      InvalidStateTransitionException {
+    ComponentsResponse expected = new ComponentsResponse();
+    StackId dummyStackId = new StackId(DummyStackId);
+    Map<String, Map<String, String>> dummyComponents = new HashMap<String, Map<String, String>>();
+
+    Map<String, String> dummyCategoryMap = new HashMap<String, String>();
+    dummyCategoryMap.put("PIG", "CLIENT");
+    dummyComponents.put("PIG", dummyCategoryMap);
+
+    dummyCategoryMap = new HashMap<String, String>();
+    dummyCategoryMap.put("MAPREDUCE_CLIENT", "CLIENT");
+    dummyCategoryMap.put("JOBTRACKER", "MASTER");
+    dummyCategoryMap.put("TASKTRACKER", "SLAVE");
+    dummyComponents.put("MAPREDUCE", dummyCategoryMap);
+
+    dummyCategoryMap = new HashMap<String, String>();
+    dummyCategoryMap.put("DATANODE2", "SLAVE");
+    dummyCategoryMap.put("NAMENODE", "MASTER");
+    dummyCategoryMap.put("HDFS_CLIENT", "CLIENT");
+    dummyCategoryMap.put("DATANODE1", "SLAVE");
+    dummyCategoryMap.put("SECONDARY_NAMENODE", "MASTER");
+    dummyCategoryMap.put("DATANODE", "SLAVE");
+    dummyComponents.put("HDFS", dummyCategoryMap);
+
+    expected.setClusterName(DummyCluster);
+    expected.setStackName(dummyStackId.getStackName());
+    expected.setStackVersion(dummyStackId.getStackVersion());
+    expected.setComponents(dummyComponents);
+
+    this.getDummyCluster();
+    HeartBeatHandler handler = getHeartBeatHandler(getMockActionManager(),
+        new ActionQueue());
+
+    ComponentsResponse actual = handler.handleComponents(DummyCluster);
+
+    if (log.isDebugEnabled()) {
+      log.debug(actual.toString());
+    }
+
+    assertEquals(expected.getClusterName(), actual.getClusterName());
+    assertEquals(expected.getStackName(), actual.getStackName());
+    assertEquals(expected.getStackVersion(), actual.getStackVersion());
+    assertEquals(expected.getComponents(), actual.getComponents());
+  }
+
   private ActionManager getMockActionManager() {
     return new ActionManager(0, 0, null, null,
         actionDBAccessor, new HostsMap((String) null), null, unitOfWork,
@@ -1692,7 +1739,9 @@ public class TestHeartbeatHandler {
     clusters.addCluster(DummyCluster);
 
     Cluster cluster = clusters.getCluster(DummyCluster);
-    cluster.setDesiredStackVersion(new StackId(DummyStackId));
+    StackId stackId = new StackId(DummyStackId);
+    cluster.setDesiredStackVersion(stackId);
+    cluster.setCurrentStackVersion(stackId);
     return cluster;
   }
 }