Jelajahi Sumber

AMBARI-6056. Agent Custom Command Output Coerces Integers to Floats (Jonathan Hurley via ncole)

Nate Cole 11 tahun lalu
induk
melakukan
f1a2af1017

+ 2 - 0
ambari-agent/src/main/python/ambari_agent/ActionQueue.py

@@ -191,6 +191,7 @@ class ActionQueue(threading.Thread):
       roleResult['structuredOut'] = str(json.dumps(commandresult['structuredOut']))
     else:
       roleResult['structuredOut'] = ''
+
     # let ambari know that configuration tags were applied
     if status == self.COMPLETED_STATUS:
       configHandler = ActualConfigHandler(self.config, self.configTags)
@@ -208,6 +209,7 @@ class ActionQueue(threading.Thread):
         configHandler.write_actual_component(command['role'], command['configurationTags'])
         configHandler.write_client_components(command['serviceName'], command['configurationTags'])
         roleResult['configurationTags'] = configHandler.read_actual_component(command['role'])
+
     self.commandStatuses.put_command_status(command, roleResult)
 
 

+ 4 - 4
ambari-agent/src/main/python/ambari_agent/CustomServiceOrchestrator.py

@@ -69,10 +69,10 @@ class CustomServiceOrchestrator():
       pass # Ignore fail
 
 
-  def runCommand(self, command, tmpoutfile, tmperrfile, forsed_command_name = None,
+  def runCommand(self, command, tmpoutfile, tmperrfile, forced_command_name = None,
                  override_output_files = True):
     """
-    forsed_command_name may be specified manually. In this case, value, defined at
+    forced_command_name may be specified manually. In this case, value, defined at
     command json, is ignored.
     """
     try:
@@ -90,8 +90,8 @@ class CustomServiceOrchestrator():
       except KeyError:
         pass # Status commands have no taskId
 
-      if forsed_command_name is not None: # If not supplied as an argument
-        command_name = forsed_command_name
+      if forced_command_name is not None: # If not supplied as an argument
+        command_name = forced_command_name
 
       if command_name == self.CUSTOM_ACTION_COMMAND:
         base_dir = self.file_cache.get_custom_actions_base_dir(server_url_prefix)

+ 2 - 2
ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py

@@ -204,12 +204,12 @@ class TestCustomServiceOrchestrator(TestCase):
         'exitcode': 0,
       }
     ret = orchestrator.runCommand(command, "out.txt", "err.txt",
-              forsed_command_name=CustomServiceOrchestrator.COMMAND_NAME_STATUS)
+              forced_command_name=CustomServiceOrchestrator.COMMAND_NAME_STATUS)
     ## Check that override_output_files was true only during first call
     self.assertEquals(run_file_mock.call_args_list[0][0][7], True)
     self.assertEquals(run_file_mock.call_args_list[1][0][7], False)
     self.assertEquals(run_file_mock.call_args_list[2][0][7], False)
-    ## Check that forsed_command_name was taken into account
+    ## Check that forced_command_name was taken into account
     self.assertEqual(run_file_mock.call_args_list[0][0][1][0],
                                   CustomServiceOrchestrator.COMMAND_NAME_STATUS)
 

+ 31 - 16
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/TaskResourceProvider.java

@@ -17,8 +17,12 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import com.google.gson.Gson;
-import com.google.gson.JsonSyntaxException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.TaskStatusRequest;
@@ -32,12 +36,7 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import org.codehaus.jackson.map.ObjectMapper;
 
 /**
  * Resource provider for task resources.
@@ -65,8 +64,6 @@ class TaskResourceProvider extends AbstractControllerResourceProvider {
   protected static final String TASK_COMMAND_DET_PROPERTY_ID  = PropertyHelper.getPropertyId("Tasks", "command_detail");
   protected static final String TASK_CUST_CMD_NAME_PROPERTY_ID  = PropertyHelper.getPropertyId("Tasks", "custom_command_name");
 
-  private static final Gson gson = new Gson();
-
   private static Set<String> pkPropertyIds =
       new HashSet<String>(Arrays.asList(new String[]{
           TASK_ID_PROPERTY_ID}));
@@ -151,31 +148,49 @@ class TaskResourceProvider extends AbstractControllerResourceProvider {
         setResourceProperty(resource, TASK_EXIT_CODE_PROPERTY_ID, response.getExitCode(), requestedIds);
         setResourceProperty(resource, TASK_STDERR_PROPERTY_ID, response.getStderr(), requestedIds);
         setResourceProperty(resource, TASK_STOUT_PROPERTY_ID, response.getStdout(), requestedIds);
-        setResourceProperty(resource, TASK_STRUCT_OUT_PROPERTY_ID, prepareStructuredOutJson(response.getStructuredOut()), requestedIds);
+        setResourceProperty(resource, TASK_STRUCT_OUT_PROPERTY_ID, parseStructuredOutput(response.getStructuredOut()), requestedIds);
         setResourceProperty(resource, TASK_START_TIME_PROPERTY_ID, response.getStartTime(), requestedIds);
         setResourceProperty(resource, TASK_END_TIME_PROPERTY_ID, response.getEndTime(), requestedIds);
         setResourceProperty(resource, TASK_ATTEMPT_CNT_PROPERTY_ID, response.getAttemptCount(), requestedIds);
+
         if (response.getCustomCommandName() != null) {
           setResourceProperty(resource, TASK_CUST_CMD_NAME_PROPERTY_ID, response.getCustomCommandName(), requestedIds);
         }
+
         if (response.getCommandDetail() == null) {
           setResourceProperty(resource, TASK_COMMAND_DET_PROPERTY_ID,
               String.format("%s %s", response.getRole(), response.getCommand()), requestedIds);
         } else {
           setResourceProperty(resource, TASK_COMMAND_DET_PROPERTY_ID, response.getCommandDetail(), requestedIds);
         }
+
         resources.add(resource);
       }
     }
     return resources;
   }
 
-  Object prepareStructuredOutJson(String structuredOutStr) {
-    Object result = null;
+  /**
+   * Converts the specified JSON string into a {@link Map}. For now, use Jackson
+   * instead of gson since none of the integers will convert properly without a
+   * well-defined first-class object to map to.
+   * 
+   * @param structuredOutput
+   *          the JSON string to convert.
+   * @return the converted JSON as key-value pairs, or {@code null} if an
+   *         exception was encountered or if the JSON string was empty.
+   */
+  Map<?, ?> parseStructuredOutput(String structuredOutput) {
+    if (null == structuredOutput || structuredOutput.isEmpty())
+      return null;
+
+    Map<?, ?> result = null;
+
     try {
-      result = gson.fromJson(structuredOutStr, Map.class);
-    } catch (JsonSyntaxException exception) {
-      LOG.warn("Can not parse structured output string " + structuredOutStr);
+      ObjectMapper mapper = new ObjectMapper();
+      result = mapper.readValue(structuredOutput, Map.class);
+    } catch (Exception excepton) {
+      LOG.warn("Unable to parse task structured output: {}", structuredOutput);
     }
     return result;
   }

+ 13 - 13
ambari-server/src/main/resources/custom_actions/check_host.py

@@ -60,7 +60,7 @@ class CheckHost(Script):
         structured_output[CHECK_JAVA_HOME] = java_home_check_structured_output
       except Exception, exception:
         print "There was an unexpected error while checking for the Java home location: " + str(exception)
-        structured_output[CHECK_JAVA_HOME] = {"exit_code" : "1", "message": str(exception)}
+        structured_output[CHECK_JAVA_HOME] = {"exit_code" : 1, "message": str(exception)}
 
     if CHECK_DB_CONNECTION in check_execute_list:
       try :
@@ -68,7 +68,7 @@ class CheckHost(Script):
         structured_output[CHECK_DB_CONNECTION] = db_connection_check_structured_output
       except Exception, exception:
         print "There was an unknown error while checking database connectivity: " + str(exception)
-        structured_output[CHECK_DB_CONNECTION] = {"exit_code" : "1", "message": str(exception)}
+        structured_output[CHECK_DB_CONNECTION] = {"exit_code" : 1, "message": str(exception)}
 
     if CHECK_HOST_RESOLUTION in check_execute_list:
       try : 
@@ -76,7 +76,7 @@ class CheckHost(Script):
         structured_output[CHECK_HOST_RESOLUTION] = host_resolution_structured_output
       except Exception, exception :
         print "There was an unknown error while checking IP address lookups: " + str(exception)
-        structured_output[CHECK_HOST_RESOLUTION] = {"exit_code" : "1", "message": str(exception)}
+        structured_output[CHECK_HOST_RESOLUTION] = {"exit_code" : 1, "message": str(exception)}
 
     self.put_structured_out(structured_output)
 
@@ -89,10 +89,10 @@ class CheckHost(Script):
   
     if not os.path.isfile(os.path.join(java64_home, "bin", "java")):
       print "Java home doesn't exist!"
-      java_home_check_structured_output = {"exit_code" : "1", "message": "Java home doesn't exist!"}
+      java_home_check_structured_output = {"exit_code" : 1, "message": "Java home doesn't exist!"}
     else:
       print "Java home exists!"
-      java_home_check_structured_output = {"exit_code" : "0", "message": "Java home exists!"}
+      java_home_check_structured_output = {"exit_code" : 0, "message": "Java home exists!"}
   
     return java_home_check_structured_output
 
@@ -131,7 +131,7 @@ class CheckHost(Script):
       message = "Custom java is not available on host. Please install it. Java home should be the same as on server. " \
                 "\n"
       print message
-      db_connection_check_structured_output = {"exit_code" : "1", "message": message}
+      db_connection_check_structured_output = {"exit_code" : 1, "message": message}
       return db_connection_check_structured_output
 
     environment = { "no_proxy": format("{ambari_server_hostname}") }
@@ -152,7 +152,7 @@ class CheckHost(Script):
         message = "Error downloading JDK from Ambari Server resources. Check network access to " \
                   "Ambari Server.\n" + str(e)
         print message
-        db_connection_check_structured_output = {"exit_code" : "1", "message": message}
+        db_connection_check_structured_output = {"exit_code" : 1, "message": message}
         return db_connection_check_structured_output
 
       if jdk_name.endswith(".bin"):
@@ -166,7 +166,7 @@ class CheckHost(Script):
       except Exception, e:
         message = "Error installing java.\n" + str(e)
         print message
-        db_connection_check_structured_output = {"exit_code" : "1", "message": message}
+        db_connection_check_structured_output = {"exit_code" : 1, "message": message}
         return db_connection_check_structured_output
 
     try:
@@ -178,7 +178,7 @@ class CheckHost(Script):
       message = "Error downloading DBConnectionVerification.jar from Ambari Server resources. Check network access to " \
                 "Ambari Server.\n" + str(e)
       print message
-      db_connection_check_structured_output = {"exit_code" : "1", "message": message}
+      db_connection_check_structured_output = {"exit_code" : 1, "message": message}
       return db_connection_check_structured_output
   
     # download jdbc driver from ambari-server resources
@@ -192,7 +192,7 @@ class CheckHost(Script):
                 "install JDBC connector. Use \"ambari-server setup --help\" for more information. Check network access to " \
                 "Ambari Server.\n" + str(e)
       print message
-      db_connection_check_structured_output = {"exit_code" : "1", "message": message}
+      db_connection_check_structured_output = {"exit_code" : 1, "message": message}
       return db_connection_check_structured_output
   
   
@@ -213,9 +213,9 @@ class CheckHost(Script):
     print "INFO returncode: " + str(process.returncode)
   
     if process.returncode == 0:
-      db_connection_check_structured_output = {"exit_code" : "0", "message": "DB connection check completed successfully!" }
+      db_connection_check_structured_output = {"exit_code" : 0, "message": "DB connection check completed successfully!" }
     else:
-      db_connection_check_structured_output = {"exit_code" : "1", "message":  stdoutdata + stderrdata }
+      db_connection_check_structured_output = {"exit_code" : 1, "message":  stdoutdata + stderrdata }
   
     return db_connection_check_structured_output
   
@@ -257,7 +257,7 @@ class CheckHost(Script):
     print message
         
     host_resolution_check_structured_output = {
-      "exit_code" : "0",
+      "exit_code" : 0,
       "message" : message,                                          
       "failed_count" : failedCount, 
       "success_count" : successCount,

+ 75 - 19
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/TaskResourceProviderTest.java

@@ -18,6 +18,21 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.TaskStatusResponse;
@@ -29,20 +44,6 @@ import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.junit.Assert;
 import org.junit.Test;
-import static org.junit.Assert.*;
-
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.createNiceMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
 
 /**
  * TaskResourceProvider tests.
@@ -202,29 +203,84 @@ public class TaskResourceProviderTest {
   }
 
   @Test
-  public void testPrepareStructuredOutJson() {
+  public void testParseStructuredOutput() {
     Resource.Type type = Resource.Type.Task;
     // Test general case
     AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
     TaskResourceProvider taskResourceProvider = new TaskResourceProvider(
             PropertyHelper.getPropertyIds(type),
             PropertyHelper.getKeyPropertyIds(type), managementController);
+
     replay(managementController);
 
     // Check parsing of nested JSON
-    Map result = (Map) taskResourceProvider.prepareStructuredOutJson("{\"a\":\"b\", \"c\": {\"d\":\"e\",\"f\": [\"g\",\"h\"],\"i\": {\"k\":\"l\"}}}");
+    Map<?, ?> result = taskResourceProvider
+        .parseStructuredOutput("{\"a\":\"b\", \"c\": {\"d\":\"e\",\"f\": [\"g\",\"h\"],\"i\": {\"k\":\"l\"}}}");
     assertEquals(result.size(), 2);
-    Map submap = (Map) result.get("c");
+    Map<?, ?> submap = (Map<?, ?>) result.get("c");
     assertEquals(submap.size(), 3);
     List sublist = (List) submap.get("f");
     assertEquals(sublist.size(), 2);
-    Map subsubmap = (Map) submap.get("i");
+    Map<?, ?> subsubmap = (Map<?, ?>) submap.get("i");
     assertEquals(subsubmap.size(), 1);
     assertEquals(subsubmap.get("k"), "l");
+
     // Check negative case - invalid JSON
-    result = (Map) taskResourceProvider.prepareStructuredOutJson("{\"a\": invalid JSON}");
+    result = taskResourceProvider.parseStructuredOutput("{\"a\": invalid JSON}");
     assertNull(result);
 
+    // ensure that integers come back as integers
+    result = taskResourceProvider.parseStructuredOutput("{\"a\": 5}");
+    assertEquals(result.get("a"), 5);
+
     verify(managementController);
   }
+  
+  @Test
+  public void testParseStructuredOutputForHostCheck() {
+    Resource.Type type = Resource.Type.Task;
+
+    // Test general case
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
+    TaskResourceProvider taskResourceProvider = new TaskResourceProvider(
+            PropertyHelper.getPropertyIds(type),
+            PropertyHelper.getKeyPropertyIds(type), managementController);
+
+    replay(managementController);
+
+    Map<?, ?> result = taskResourceProvider.parseStructuredOutput("{\"host_resolution_check\": {\"failures\": [{\"cause\": [-2, \"Name or service not known\"], \"host\": \"foobar\", \"type\": \"FORWARD_LOOKUP\"}], \"message\": \"There were 1 host(s) that could not resolve to an IP address.\", \"failed_count\": 1, \"success_count\": 3, \"exit_code\": 0}}");
+
+    Assert.assertNotNull(result);
+    Map<?,?> host_resolution_check = (Map<?,?>)result.get("host_resolution_check");
+    
+    assertEquals(host_resolution_check.get("success_count"), 3);
+    assertEquals(host_resolution_check.get("failed_count"), 1);
+    
+    verify(managementController);
+  }
+  
+  @Test
+  public void testInvalidStructuredOutput() {
+    Resource.Type type = Resource.Type.Task;
+
+    // Test general case
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+
+    TaskResourceProvider taskResourceProvider = new TaskResourceProvider(
+        PropertyHelper.getPropertyIds(type),
+        PropertyHelper.getKeyPropertyIds(type), managementController);
+
+    replay(managementController);
+
+    Map<?, ?> result = taskResourceProvider.parseStructuredOutput(null);
+    Assert.assertNull(result);
+
+    result = taskResourceProvider.parseStructuredOutput("This is some bad JSON");
+    Assert.assertNull(result);
+
+    verify(managementController);
+  }
+
 }

+ 30 - 9
ambari-server/src/test/python/TestCheckHost.py

@@ -44,7 +44,7 @@ class TestCheckHost(TestCase):
 
     self.assertEquals(os_isfile_mock.call_args[0][0], 'test_java_home/bin/java')
     self.assertEquals(structured_out_mock.call_args[0][0], {'java_home_check': {'message': 'Java home exists!',
-                                                                                'exit_code': '0'}})
+                                                                                'exit_code': 0}})
     # test, java home doesn't exist
     os_isfile_mock.reset_mock()
     os_isfile_mock.return_value = False
@@ -53,7 +53,7 @@ class TestCheckHost(TestCase):
 
     self.assertEquals(os_isfile_mock.call_args[0][0], 'test_java_home/bin/java')
     self.assertEquals(structured_out_mock.call_args[0][0], {'java_home_check': {"message": "Java home doesn't exist!",
-                                                                                "exit_code" : "1"}})
+                                                                                "exit_code" : 1}})
 
 
   @patch.object(Script, 'get_config')
@@ -81,9 +81,11 @@ class TestCheckHost(TestCase):
 
     self.assertEquals(structured_out_mock.call_args[0][0], {'db_connection_check': {'message': 'Error downloading ' \
                      'DBConnectionVerification.jar from Ambari Server resources. Check network access to Ambari ' \
-                     'Server.\ntest exception', 'exit_code': '1'}})
+                     'Server.\ntest exception', 'exit_code': 1}})
+    
     self.assertEquals(format_mock.call_args_list[2][0][0], "/bin/sh -c 'cd /usr/lib/ambari-agent/ && curl -kf " \
                       "--retry 5 {jdk_location}{check_db_connection_jar_name} -o {check_db_connection_jar_name}'")
+    
     self.assertEquals(format_mock.call_args_list[3][0][0], "[ -f /usr/lib/ambari-agent/{check_db_connection_jar_name}]")
 
     # test, download jdbc driver failed
@@ -106,9 +108,11 @@ class TestCheckHost(TestCase):
     self.assertEquals(structured_out_mock.call_args[0][0], {'db_connection_check': {'message': 'Error downloading JDBC ' \
                               'connector from Ambari Server resources. Confirm you ran ambari-server setup to ' \
                               'install JDBC connector. Use "ambari-server setup --help" for more information. Check ' \
-                              'network access to Ambari Server.\ntest exception', 'exit_code': '1'}})
+                              'network access to Ambari Server.\ntest exception', 'exit_code': 1}})
+    
     self.assertEquals(format_mock.call_args_list[4][0][0], "/bin/sh -c 'cd /usr/lib/ambari-agent/ && curl -kf " \
                                                             "--retry 5 {jdbc_url} -o {jdbc_name}'")
+    
     self.assertEquals(format_mock.call_args_list[5][0][0], "[ -f /usr/lib/ambari-agent/{jdbc_name}]")
 
     # test, no connection to remote db
@@ -132,7 +136,7 @@ class TestCheckHost(TestCase):
     checkHost.actionexecute(None)
 
     self.assertEquals(structured_out_mock.call_args[0][0], {'db_connection_check': {'message': 'test message',
-                                                                                    'exit_code': '1'}})
+                                                                                    'exit_code': 1}})
     self.assertEquals(format_mock.call_args[0][0],'{java64_home}/bin/java -cp /usr/lib/ambari-agent/{check_db_' \
                                                 'connection_jar_name}:/usr/lib/ambari-agent/{jdbc_name} org.' \
                                                 'apache.ambari.server.DBConnectionVerification {db_connection_url} ' \
@@ -146,7 +150,7 @@ class TestCheckHost(TestCase):
     checkHost.actionexecute(None)
 
     self.assertEquals(structured_out_mock.call_args[0][0], {'db_connection_check':
-                                        {'message': 'DB connection check completed successfully!', 'exit_code': '0'}})
+                                        {'message': 'DB connection check completed successfully!', 'exit_code': 0}})
 
     #test jdk_name and java home are not available
     mock_config.return_value = {"commandParams" : {"check_execute_list" : "db_connection_check",
@@ -161,7 +165,7 @@ class TestCheckHost(TestCase):
     isfile_mock.return_value = False
     checkHost.actionexecute(None)
     self.assertEquals(structured_out_mock.call_args[0][0], {'db_connection_check': {'message': 'Custom java is not ' \
-            'available on host. Please install it. Java home should be the same as on server. \n', 'exit_code': '1'}})
+            'available on host. Please install it. Java home should be the same as on server. \n', 'exit_code': 1}})
 
 
 
@@ -187,7 +191,7 @@ class TestCheckHost(TestCase):
        'message': 'All hosts resolved to an IP address.', 
        'failed_count': 0, 
        'success_count': 5, 
-       'exit_code': '0'}})
+       'exit_code': 0}})
     
     # try it now with errors
     mock_socket.side_effect = socket.error
@@ -201,4 +205,21 @@ class TestCheckHost(TestCase):
                     {'cause': (), 'host': u'foobar', 'type': 'FORWARD_LOOKUP'}, 
                     {'cause': (), 'host': u'!!!', 'type': 'FORWARD_LOOKUP'}], 
        'message': 'There were 5 host(s) that could not resolve to an IP address.', 
-       'failed_count': 5, 'success_count': 0, 'exit_code': '0'}})
+       'failed_count': 5, 'success_count': 0, 'exit_code': 0}})
+    
+  @patch.object(Script, 'get_config')
+  @patch("resource_management.libraries.script.Script.put_structured_out")
+  def testInvalidCheck(self, structured_out_mock, mock_config):    
+    jsonFilePath = os.path.join("../resources/custom_actions", "invalid_check.json")
+    
+    with open(jsonFilePath, "r") as jsonFile:
+      jsonPayload = json.load(jsonFile)
+ 
+    mock_config.return_value = ConfigDictionary(jsonPayload)
+    
+    checkHost = CheckHost()
+    checkHost.actionexecute(None)
+    
+    # ensure the correct function was called
+    self.assertTrue(structured_out_mock.called)
+    structured_out_mock.assert_called_with({})

+ 42 - 0
ambari-server/src/test/resources/custom_actions/invalid_check.json

@@ -0,0 +1,42 @@
+{
+    "roleCommand": "ACTIONEXECUTE",
+    "clusterName": "c1",
+    "hostname": "c6401.ambari.apache.org",
+    "passiveInfo": [],
+    "hostLevelParams": {
+        "jdk_location": "http://192.168.64.1:8080/resources/",
+        "ambari_db_rca_password": "mapred",
+        "java_home": "/usr/jdk64/jdk1.6.0_31",
+        "ambari_db_rca_url": "jdbc:postgresql://192.168.64.1/ambarirca",
+        "stack_name": "HDP",
+        "oracle_jdbc_url": "http://192.168.64.1:8080/resources//ojdbc6.jar",
+        "stack_version": "2.1",
+        "db_name": "ambari",
+        "ambari_db_rca_driver": "org.postgresql.Driver",
+        "jdk_name": "jdk-6u31-linux-x64.bin",
+        "ambari_db_rca_username": "mapred",
+        "db_driver_filename": "mysql-connector-java.jar",
+        "mysql_jdbc_url": "http://192.168.64.1:8080/resources//mysql-connector-java.jar"
+    },
+    "serviceName": "null",
+    "role": "check_host",
+    "commandParams": {
+        "script": "check_host.py",
+        "check_execute_list": "bad_check",
+        "threshold": "20",
+        "hosts": "c6401.ambari.apache.org, c6402.ambari.apache.org, c6403.ambari.apache.org, foobar, !!!",
+        "command_timeout": "60",
+        "script_type": "PYTHON"
+    },
+    "taskId": 158,
+    "public_hostname": "c6401.ambari.apache.org",
+    "configurations": {},
+    "commandId": "27-1",
+    "clusterHostInfo": {
+        "ambari_server_host": [
+            "192.168.64.1"
+        ],
+        "all_hosts": [],
+        "all_ping_ports": []
+    }
+}