AMBARI-3770. Need better error log message when agent unable to reach server (Dmytro Shkvyra via dlysnichenko)
diff --git a/ambari-agent/src/main/python/ambari_agent/Controller.py b/ambari-agent/src/main/python/ambari_agent/Controller.py
index 7c51b5f..30f9a4d 100644
--- a/ambari-agent/src/main/python/ambari_agent/Controller.py
+++ b/ambari-agent/src/main/python/ambari_agent/Controller.py
@@ -60,6 +60,7 @@
     self.netutil = NetUtil()
     self.responseId = -1
     self.repeatRegistration = False
+    self.isRegistered = False
     self.cachedconnect = None
     self.range = range
     self.hasMappedComponents = True
@@ -74,21 +75,34 @@
   def registerWithServer(self):
     retry=False
     firstTime=True
-    registered=False
     id = -1
     ret = {}
 
-    while not registered:
+    while not self.isRegistered:
       try:
         data = json.dumps(self.register.build(id))
         logger.info("Registering with the server " + pprint.pformat(data))
         response = self.sendRequest(self.registerUrl, data)
         ret = json.loads(response)
-
+        exitstatus = 0
+        # exitstatus is a code of error which was rised on server side.
+        # exitstatus = 0 (OK - Default)
+        # exitstatus = 1 (Registration failed because
+        #                different version of agent and server)
+        if 'exitstatus' in ret.keys():
+          exitstatus = int(ret['exitstatus'])
+        # log - message, which will be printed to agents  log  
+        if 'log' in ret.keys():
+          log = ret['log']
+        if exitstatus == 1:
+          logger.error(log)
+          self.isRegistered = False
+          self.repeatRegistration=False
+          return ret
         logger.info("Registered with the server with " + pprint.pformat(ret))
         print("Registered with the server")
         self.responseId= int(ret['responseId'])
-        registered = True
+        self.isRegistered = True
         if 'statusCommands' in ret.keys():
           logger.info("Got status commands on registration " + pprint.pformat(ret['statusCommands']) )
           self.addToQueue(ret['statusCommands'])
@@ -98,6 +112,7 @@
         pass
       except ssl.SSLError:
         self.repeatRegistration=False
+        self.isRegistered = False
         return
       except Exception, err:
         # try a reconnect only after a certain amount of random time
@@ -160,6 +175,7 @@
           # check if the registration command is None. If none skip
           if response['registrationCommand'] is not None:
             logger.info("RegistrationCommand received - repeat agent registration")
+            self.isRegistered = False
             self.repeatRegistration = True
             return
 
@@ -192,6 +208,7 @@
         self.heartbeat_wait_event.clear()
       except ssl.SSLError:
         self.repeatRegistration=False
+        self.isRegistered = False
         return
       except Exception, err:
         #randomize the heartbeat
@@ -239,8 +256,9 @@
     registerResponse = self.registerWithServer()
     message = registerResponse['response']
     logger.info("Response from server = " + message)
-    time.sleep(self.netutil.HEARTBEAT_IDDLE_INTERVAL_SEC)
-    self.heartbeatWithServer()
+    if self.isRegistered:
+     time.sleep(self.netutil.HEARTBEAT_IDDLE_INTERVAL_SEC)
+     self.heartbeatWithServer()
 
   def restartAgent(self):
     os._exit(AGENT_AUTO_RESTART_EXIT_CODE)
diff --git a/ambari-agent/src/test/python/TestController.py b/ambari-agent/src/test/python/TestController.py
index 2b0e614..87e00fe 100644
--- a/ambari-agent/src/test/python/TestController.py
+++ b/ambari-agent/src/test/python/TestController.py
@@ -55,12 +55,11 @@
 
 
   @patch("json.dumps")
-  @patch("json.loads")
   @patch("time.sleep")
   @patch("pprint.pformat")
   @patch.object(Controller, "randint")
   def test_registerWithServer(self, randintMock, pformatMock, sleepMock,
-                              loadsMock, dumpsMock):
+                              dumpsMock):
 
     out = StringIO.StringIO()
     sys.stdout = out
@@ -68,19 +67,20 @@
     register = MagicMock()
     self.controller.register = register
 
-    sendRequest = MagicMock()
-    self.controller.sendRequest = sendRequest
+    self.controller.sendRequest = MagicMock()
 
     dumpsMock.return_value = "request"
-    response = {"responseId":1,}
-    loadsMock.return_value = response
+    self.controller.sendRequest.return_value = '{"log":"Error text", "exitstatus":"1"}'
 
-    self.assertEqual(response, self.controller.registerWithServer())
+    self.assertEqual({u'exitstatus': u'1', u'log': u'Error text'}, self.controller.registerWithServer())
 
-    response["statusCommands"] = "commands"
+    self.controller.sendRequest.return_value = '{"responseId":1}'
+    self.assertEqual({"responseId":1}, self.controller.registerWithServer())
+
+    self.controller.sendRequest.return_value = '{"responseId":1, "statusCommands": "commands", "log":"", "exitstatus":"0"}'
     self.controller.addToQueue = MagicMock(name="addToQueue")
-
-    self.assertEqual(response, self.controller.registerWithServer())
+    self.controller.isRegistered = False
+    self.assertEqual({'exitstatus': '0', 'responseId': 1, 'log': '', 'statusCommands': 'commands'}, self.controller.registerWithServer())
     self.controller.addToQueue.assert_called_with("commands")
 
     calls = []
@@ -91,10 +91,11 @@
         raise Exception("test")
       return "request"
 
-    del response["statusCommands"]
+    self.controller.sendRequest.return_value = '{"responseId":1}'
 
     dumpsMock.side_effect = side_effect
-    self.assertEqual(response, self.controller.registerWithServer())
+    self.controller.isRegistered = False
+    self.assertEqual({"responseId":1}, self.controller.registerWithServer())
     self.assertTrue(randintMock.called)
     self.assertTrue(sleepMock.called)
 
@@ -189,6 +190,7 @@
 
     Controller.Controller.__sendRequest__ = MagicMock(side_effect=Exception())
 
+    self.controller.isRegistered = True
     self.controller.registerAndHeartbeat()
     registerWithServer.assert_called_once_with()
     heartbeatWithServer.assert_called_once_with()
@@ -207,6 +209,7 @@
     heartbeatWithServer = MagicMock(name="heartbeatWithServer")
     self.controller.heartbeatWithServer = heartbeatWithServer
 
+    self.controller.isRegistered = True;
     self.controller.registerAndHeartbeat()
     registerWithServer.assert_called_once_with()
     heartbeatWithServer.assert_called_once_with()
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
index 5e466aa..dae80bb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java
@@ -30,6 +30,21 @@
 public class RegistrationResponse {
   @JsonProperty("response")
   private RegistrationStatus response;
+
+  /**
+   * exitstatus is a code of error which was rised on server side.
+   * exitstatus = 0 (OK - Default)
+   * exitstatus = 1 (Registration failed because
+   *                different version of agent and server)
+   */
+  @JsonProperty("exitstatus")
+  private int exitstatus;
+
+  /**
+   * log - message, which will be printed to agents  log
+   */
+  @JsonProperty("log")
+  private String log;  
   
   //Response id to start with, usually zero.
   @JsonProperty("responseId")
@@ -62,6 +77,14 @@
     this.responseId = responseId;
   }
 
+  public void setExitstatus(int exitstatus) {
+    this.exitstatus = exitstatus;
+  }
+
+  public void setLog(String log) {
+    this.log = log;
+  }
+ 
   @Override
   public String toString() {
     return "RegistrationResponse{" +
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/rest/AgentResource.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/rest/AgentResource.java
index 1aac28e..9037162 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/rest/AgentResource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/rest/AgentResource.java
@@ -38,6 +38,7 @@
 import org.apache.commons.logging.LogFactory;
 
 import com.google.inject.Inject;
+import org.apache.ambari.server.agent.RegistrationStatus;
 
 /**
  * Agent Resource represents Ambari agent controller.
@@ -75,11 +76,21 @@
   @Produces({MediaType.APPLICATION_JSON})
   public RegistrationResponse register(Register message,
       @Context HttpServletRequest req)
-      throws WebApplicationException, AmbariException, InvalidStateTransitionException {
+      throws WebApplicationException, InvalidStateTransitionException {
     /* Call into the heartbeat handler */
 
-    RegistrationResponse response = hh.handleRegistration(message);
-    LOG.debug("Sending registration response " + response);
+    RegistrationResponse response = null;
+    try {
+      response = hh.handleRegistration(message);
+      LOG.debug("Sending registration response " + response);
+    } catch (AmbariException ex) {
+      response = new RegistrationResponse();
+      response.setResponseId(-1);
+      response.setResponseStatus(RegistrationStatus.FAILED);
+      response.setExitstatus(1);
+      response.setLog(ex.getMessage());
+      return response;
+    }
     return response;
   }