Przeglądaj źródła

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

Dmitry Sen 11 lat temu
rodzic
commit
03e04a684a

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

@@ -31,13 +31,13 @@ from random import randint
 
 
 import hostname
 import hostname
 import AmbariConfig
 import AmbariConfig
-import ProcessHelper
 from Heartbeat import Heartbeat
 from Heartbeat import Heartbeat
 from Register import Register
 from Register import Register
 from ActionQueue import ActionQueue
 from ActionQueue import ActionQueue
 import security
 import security
 from NetUtil import NetUtil
 from NetUtil import NetUtil
 import ssl
 import ssl
+from LiveStatus import LiveStatus
 
 
 
 
 logger = logging.getLogger()
 logger = logging.getLogger()
@@ -58,6 +58,7 @@ class Controller(threading.Thread):
                          ':' + config.get('server', 'secured_url_port')
                          ':' + config.get('server', 'secured_url_port')
     self.registerUrl = server_secured_url + '/agent/v1/register/' + self.hostname
     self.registerUrl = server_secured_url + '/agent/v1/register/' + self.hostname
     self.heartbeatUrl = server_secured_url + '/agent/v1/heartbeat/' + self.hostname
     self.heartbeatUrl = server_secured_url + '/agent/v1/heartbeat/' + self.hostname
+    self.componentsUrl = server_secured_url + '/agent/v1/components/'
     self.netutil = NetUtil()
     self.netutil = NetUtil()
     self.responseId = -1
     self.responseId = -1
     self.repeatRegistration = False
     self.repeatRegistration = False
@@ -77,6 +78,9 @@ class Controller(threading.Thread):
     pass
     pass
   
   
   def registerWithServer(self):
   def registerWithServer(self):
+    LiveStatus.SERVICES = []
+    LiveStatus.CLIENT_COMPONENTS = []
+    LiveStatus.COMPONENTS = []
     id = -1
     id = -1
     ret = {}
     ret = {}
 
 
@@ -142,6 +146,8 @@ class Controller(threading.Thread):
     if not commands:
     if not commands:
       logger.debug("No status commands from the server : " + pprint.pformat(commands))
       logger.debug("No status commands from the server : " + pprint.pformat(commands))
     else:
     else:
+      if not LiveStatus.SERVICES:
+        self.updateComponents(commands[0]['clusterName'])
       self.actionQueue.put_status(commands)
       self.actionQueue.put_status(commands)
     pass
     pass
 
 
@@ -283,6 +289,24 @@ class Controller(threading.Thread):
     response = self.cachedconnect.request(req)
     response = self.cachedconnect.request(req)
     return response
     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):
 def main(argv=None):
   # Allow Ctrl-C
   # Allow Ctrl-C
   signal.signal(signal.SIGINT, signal.SIG_DFL)
   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:
 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"
   LIVE_STATUS = "STARTED"
   DEAD_STATUS = "INSTALLED"
   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 os
 import logging
 import logging
 from mock.mock import patch
 from mock.mock import patch
+from ambari_agent.LiveStatus import LiveStatus
 
 
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
   from ambari_agent.AmbariConfig import AmbariConfig
   from ambari_agent.AmbariConfig import AmbariConfig
@@ -30,6 +31,107 @@ with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
 
 
 class TestActualConfigHandler(TestCase):
 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()
   logger = logging.getLogger()
 
 
   def test_read_write(self):
   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 logging
 import platform
 import platform
 from threading import Event
 from threading import Event
+import json
 
 
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
 with patch("platform.linux_distribution", return_value = ('Suse','11','Final')):
   from ambari_agent import Controller, ActionQueue
   from ambari_agent import Controller, ActionQueue
@@ -63,12 +64,17 @@ class TestController(unittest.TestCase):
   @patch("time.sleep")
   @patch("time.sleep")
   @patch("pprint.pformat")
   @patch("pprint.pformat")
   @patch.object(Controller, "randint")
   @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):
                               dumpsMock):
 
 
     out = StringIO.StringIO()
     out = StringIO.StringIO()
     sys.stdout = out
     sys.stdout = out
 
 
+    LiveStatus_mock.SERVICES = ["foo"]
+    LiveStatus_mock.CLIENT_COMPONENTS = ["foo"]
+    LiveStatus_mock.COMPONENTS = ["foo"]
+
     register = MagicMock()
     register = MagicMock()
     self.controller.register = register
     self.controller.register = register
 
 
@@ -78,6 +84,9 @@ class TestController(unittest.TestCase):
     self.controller.sendRequest.return_value = '{"log":"Error text", "exitstatus":"1"}'
     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({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.controller.sendRequest.return_value = '{"responseId":1}'
     self.assertEqual({"responseId":1}, self.controller.registerWithServer())
     self.assertEqual({"responseId":1}, self.controller.registerWithServer())
@@ -122,14 +131,29 @@ class TestController(unittest.TestCase):
 
 
 
 
   @patch("pprint.pformat")
   @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()
     actionQueue = MagicMock()
     self.controller.actionQueue = actionQueue
     self.controller.actionQueue = actionQueue
+    updateComponents = Mock()
+    self.controller.updateComponents = updateComponents
     self.controller.addToStatusQueue(None)
     self.controller.addToStatusQueue(None)
     self.assertFalse(actionQueue.put_status.called)
     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.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")
   @patch("urllib2.build_opener")
@@ -459,6 +483,36 @@ class TestController(unittest.TestCase):
     #Conroller thread and the agent stop if the repeatRegistration flag is False
     #Conroller thread and the agent stop if the repeatRegistration flag is False
     self.assertFalse(self.controller.repeatRegistration)
     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__":
 if __name__ == "__main__":
   unittest.main(verbosity=2)
   unittest.main(verbosity=2)
 
 

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

@@ -34,6 +34,105 @@ class TestLiveStatus(TestCase):
     # disable stdout
     # disable stdout
     out = StringIO.StringIO()
     out = StringIO.StringIO()
     sys.stdout = out
     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):
   def tearDown(self):

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

@@ -60,36 +60,6 @@ class TestManifestGenerator(TestCase):
     print tmpFile.read()
     print tmpFile.read()
     tmpFile.close()
     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):
   def testEscape(self):
     shouldBe = '\\\'\\\\'
     shouldBe = '\\\'\\\\'
     result = manifestGenerator.escape('\'\\')
     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["exitcode"], 1)
     self.assertEquals(res["stderr"], "Cannot access JDK! Make sure java_home is specified in hostLevelParams")
     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")
   @patch("os.path.exists")
   def test_configure_environ(self, osPathExistsMock):
   def test_configure_environ(self, osPathExistsMock):
     config = AmbariConfig().getConfig()
     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;
 package org.apache.ambari.server.agent;
 
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 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.Service;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponent;
 import org.apache.ambari.server.state.ServiceComponentHost;
 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.StackId;
+import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.State;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
 import org.apache.ambari.server.state.host.HostHealthyHeartbeatEvent;
 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.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MediaType;
 
 
 import org.apache.ambari.server.AmbariException;
 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.HeartBeat;
 import org.apache.ambari.server.agent.HeartBeatHandler;
 import org.apache.ambari.server.agent.HeartBeatHandler;
 import org.apache.ambari.server.agent.HeartBeatResponse;
 import org.apache.ambari.server.agent.HeartBeatResponse;
@@ -38,6 +41,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.logging.LogFactory;
 
 
 import com.google.inject.Inject;
 import com.google.inject.Inject;
+
 import org.apache.ambari.server.agent.RegistrationStatus;
 import org.apache.ambari.server.agent.RegistrationStatus;
 
 
 /**
 /**
@@ -127,4 +131,40 @@ public class AgentResource {
     }
     }
     return heartBeatResponse;
     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());    
     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 {
   public class MockModule extends AbstractModule {
 
 
     RegistrationResponse response = new RegistrationResponse();
     RegistrationResponse response = new RegistrationResponse();
     HeartBeatResponse hresponse = new HeartBeatResponse();
     HeartBeatResponse hresponse = new HeartBeatResponse();
+    ComponentsResponse componentsResponse = new ComponentsResponse();
 
 
     @Override
     @Override
     protected void configure() {
     protected void configure() {
@@ -244,11 +256,14 @@ public class AgentResourceTest extends JerseyTest {
       handler = mock(HeartBeatHandler.class);
       handler = mock(HeartBeatHandler.class);
       response.setResponseStatus(RegistrationStatus.OK);
       response.setResponseStatus(RegistrationStatus.OK);
       hresponse.setResponseId(0L);
       hresponse.setResponseId(0L);
+      componentsResponse.setClusterName("dummycluster");
       try {
       try {
         when(handler.handleRegistration(any(Register.class))).thenReturn(
         when(handler.handleRegistration(any(Register.class))).thenReturn(
             response);
             response);
         when(handler.handleHeartBeat(any(HeartBeat.class))).thenReturn(
         when(handler.handleHeartBeat(any(HeartBeat.class))).thenReturn(
             hresponse);
             hresponse);
+        when(handler.handleComponents(any(String.class))).thenReturn(
+            componentsResponse);
       } catch (Exception ex) {
       } catch (Exception ex) {
         // The test will fail anyway
         // 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() {
   private ActionManager getMockActionManager() {
     return new ActionManager(0, 0, null, null,
     return new ActionManager(0, 0, null, null,
         actionDBAccessor, new HostsMap((String) null), null, unitOfWork,
         actionDBAccessor, new HostsMap((String) null), null, unitOfWork,
@@ -1692,7 +1739,9 @@ public class TestHeartbeatHandler {
     clusters.addCluster(DummyCluster);
     clusters.addCluster(DummyCluster);
 
 
     Cluster cluster = clusters.getCluster(DummyCluster);
     Cluster cluster = clusters.getCluster(DummyCluster);
-    cluster.setDesiredStackVersion(new StackId(DummyStackId));
+    StackId stackId = new StackId(DummyStackId);
+    cluster.setDesiredStackVersion(stackId);
+    cluster.setCurrentStackVersion(stackId);
     return cluster;
     return cluster;
   }
   }
 }
 }