Ver código fonte

HDFS-1860. when renewing/canceling DelegationToken over http we need to pass exception information back to the caller. Contributed by Boris Shkolnik and Benoy Antony.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.22@1346229 13f79535-47bb-0310-9956-ffa450edef68
Konstantin Shvachko 13 anos atrás
pai
commit
c58e435206

+ 4 - 0
hdfs/CHANGES.txt

@@ -42,6 +42,10 @@ Release 0.22.1 - Unreleased
     HDFS-3403. SecondaryNameNode doesn't start up in secure cluster.
     (Benoy Antony via shv)
 
+    HDFS-1860. when renewing/canceling DelegationToken over http we need to
+    pass exception information back to the caller.
+    (Boris Shkolnik and Benoy Antony via shv)
+
 Release 0.22.0 - 2011-11-29
 
   INCOMPATIBLE CHANGES

+ 2 - 0
hdfs/src/java/org/apache/hadoop/hdfs/DFSConfigKeys.java

@@ -187,6 +187,8 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
   public static final boolean DFS_SUPPORT_APPEND_DEFAULT = true;
   public static final String  DFS_HTTPS_ENABLE_KEY = "dfs.https.enable";
   public static final boolean DFS_HTTPS_ENABLE_DEFAULT = false;
+  public static final String  DFS_HTTPS_PORT_KEY = "dfs.https.port";                                                                                                
+  public static final int     DFS_HTTPS_PORT_DEFAULT = 50470;
   public static final String  DFS_DEFAULT_CHUNK_VIEW_SIZE_KEY = "dfs.default.chunk.view.size";
   public static final int     DFS_DEFAULT_CHUNK_VIEW_SIZE_DEFAULT = 32*1024;
   public static final String  DFS_DATANODE_HTTPS_ADDRESS_KEY = "dfs.datanode.https.address";

+ 12 - 3
hdfs/src/java/org/apache/hadoop/hdfs/HftpFileSystem.java

@@ -138,9 +138,18 @@ public class HftpFileSystem extends FileSystem {
     setConf(conf);
     this.ugi = UserGroupInformation.getCurrentUser(); 
     nnAddr = NetUtils.createSocketAddr(name.toString());
-   
-    nnHttpUrl = buildUri("https://", NetUtils.normalizeHostName(name.getHost()), 
-        conf.getInt("dfs.https.port", DEFAULT_PORT));
+
+    // in case we open connection to hftp of a different cluster
+    // we need to know this cluster https port
+    // if it is not set we assume it is the same cluster or same port
+    int urlPort = conf.getInt("dfs.hftp.https.port", -1);
+    if(urlPort == -1)
+      urlPort = conf.getInt(DFSConfigKeys.DFS_HTTPS_PORT_KEY, 
+          DFSConfigKeys.DFS_HTTPS_PORT_DEFAULT);
+
+    nnHttpUrl = 
+      buildUri("https://", NetUtils.normalizeHostName(name.getHost()), urlPort);
+    LOG.debug("using url to get DT:" + nnHttpUrl);
 
     // if one uses RPC port different from the Default one,  
     // one should specify what is the setvice name for this delegation token

+ 6 - 3
hdfs/src/java/org/apache/hadoop/hdfs/server/namenode/RenewDelegationTokenServlet.java

@@ -78,9 +78,12 @@ public class RenewDelegationTokenServlet extends DfsServlet {
       os.println(result);
       os.close();
     } catch(Exception e) {
-      LOG.info("Exception while renewing token. Re-throwing. ", e);
-      resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
-                     e.getMessage());
+      // transfer exception over the http
+      String exceptionClass = e.getClass().getName();
+      String exceptionMsg = e.getLocalizedMessage();
+      String strException = exceptionClass + ";" + exceptionMsg;
+      LOG.info("Exception while renewing token. Re-throwing. s=" + strException, e);
+      resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, strException);
     }
   }
 }

+ 68 - 2
hdfs/src/java/org/apache/hadoop/hdfs/tools/DelegationTokenFetcher.java

@@ -254,10 +254,12 @@ public class DelegationTokenFetcher {
     buf.append("=");
     buf.append(tok.encodeToUrlString());
     BufferedReader in = null;
+    HttpURLConnection connection = null;
+    
     try {
       URL url = new URL(buf.toString());
       SecurityUtil.fetchServiceTicket(url);
-      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+      connection = (HttpURLConnection) url.openConnection();
       if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
         throw new IOException("Error renewing token: " + 
             connection.getResponseMessage());
@@ -268,11 +270,67 @@ public class DelegationTokenFetcher {
       in.close();
       return result;
     } catch (IOException ie) {
+      LOG.info("error in renew over HTTP", ie);
+      IOException e = getExceptionFromResponse(connection);
+
       IOUtils.cleanup(LOG, in);
+      if(e!=null) {
+        LOG.info("rethrowing exception from HTTP request: " + e.getLocalizedMessage());
+        throw e;
+      }
       throw ie;
     }
   }
 
+  // parse the message and extract the name of the exception and the message
+  static private IOException getExceptionFromResponse(HttpURLConnection con) {
+    IOException e = null;
+    String resp;
+    if(con == null) 
+      return null;    
+    
+    try {
+      resp = con.getResponseMessage();
+    } catch (IOException ie) { return null; }
+    if(resp == null || resp.isEmpty())
+      return null;
+
+    String exceptionClass = "", exceptionMsg = "";
+    String[] rs = resp.split(";");
+    if(rs.length < 2)
+      return null;
+    exceptionClass = rs[0];
+    exceptionMsg = rs[1];
+    LOG.info("Error response from HTTP request=" + resp + 
+        ";ec=" + exceptionClass + ";em="+exceptionMsg);
+    
+    if(exceptionClass == null || exceptionClass.isEmpty())
+      return null;
+    
+    // recreate exception objects
+    try {
+      Class<? extends Exception> ec = 
+         Class.forName(exceptionClass).asSubclass(Exception.class);
+      // we are interested in constructor with String arguments
+      java.lang.reflect.Constructor<? extends Exception> constructor =
+        (java.lang.reflect.Constructor<? extends Exception>) 
+        ec.getConstructor (new Class[] {String.class});
+
+      // create an instance
+      e =  (IOException) constructor.newInstance (exceptionMsg);
+
+    } catch (Exception ee)  {
+      LOG.warn("failed to create object of this class", ee);
+    }
+    if(e == null)
+      return null;
+    
+    e.setStackTrace(new StackTraceElement[0]); // local stack is not relevant
+    LOG.info("Exception from HTTP response=" + e.getLocalizedMessage());
+    return e;
+  }
+
+  
   /**
    * Cancel a Delegation Token.
    * @param nnAddr the NameNode's address
@@ -290,16 +348,24 @@ public class DelegationTokenFetcher {
     buf.append("=");
     buf.append(tok.encodeToUrlString());
     BufferedReader in = null;
+    HttpURLConnection connection=null;
     try {
       URL url = new URL(buf.toString());
       SecurityUtil.fetchServiceTicket(url);
-      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+      connection = (HttpURLConnection) url.openConnection();
       if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
         throw new IOException("Error cancelling token: " + 
             connection.getResponseMessage());
       }
     } catch (IOException ie) {
+      LOG.info("error in cancel over HTTP", ie);
+      IOException e = getExceptionFromResponse(connection);
+
       IOUtils.cleanup(LOG, in);
+      if(e!=null) {
+        LOG.info("rethrowing exception from HTTP request: " + e.getLocalizedMessage());
+        throw e;
+      }
       throw ie;
     }
   }