/** * 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.hadoop.hdfs.server.datanode; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URLEncoder; import java.security.PrivilegedExceptionAction; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspWriter; import org.apache.commons.lang.StringEscapeUtils; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hdfs.DFSClient; import org.apache.hadoop.hdfs.DFSConfigKeys; import org.apache.hadoop.hdfs.DFSUtil; import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.DirectoryListing; import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; import org.apache.hadoop.hdfs.protocol.LocatedBlock; import org.apache.hadoop.hdfs.security.token.block.BlockTokenIdentifier; import org.apache.hadoop.hdfs.security.token.block.BlockTokenSecretManager; import org.apache.hadoop.hdfs.server.common.JspHelper; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.token.Token; import org.apache.hadoop.util.ServletUtil; import org.apache.hadoop.util.StringUtils; @InterfaceAudience.Private public class DatanodeJspHelper { private static DFSClient getDFSClient(final UserGroupInformation user, final String addr, final Configuration conf ) throws IOException, InterruptedException { return user.doAs(new PrivilegedExceptionAction<DFSClient>() { public DFSClient run() throws IOException { return new DFSClient(NetUtils.createSocketAddr(addr), conf); } }); } /** * Internal convenience method for canonicalizing host name. * @param addr name:port or name * @return canonicalized host name */ private static String canonicalize(String addr) { // default port 1 is supplied to allow addr without port. // the port will be ignored. return NetUtils.createSocketAddr(addr, 1).getAddress() .getCanonicalHostName(); } private static final SimpleDateFormat lsDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); /** * Get the default chunk size. * @param conf the configuration * @return the number of bytes to chunk in */ private static int getDefaultChunkSize(Configuration conf) { return conf.getInt(DFSConfigKeys.DFS_DEFAULT_CHUNK_VIEW_SIZE_KEY, DFSConfigKeys.DFS_DEFAULT_CHUNK_VIEW_SIZE_DEFAULT); } static void generateDirectoryStructure(JspWriter out, HttpServletRequest req, HttpServletResponse resp, Configuration conf ) throws IOException, InterruptedException { final String dir = JspHelper.validatePath( StringEscapeUtils.unescapeHtml(req.getParameter("dir"))); if (dir == null) { out.print("Invalid input"); return; } String tokenString = req.getParameter(JspHelper.DELEGATION_PARAMETER_NAME); UserGroupInformation ugi = JspHelper.getUGI(req, conf); String namenodeInfoPortStr = req.getParameter("namenodeInfoPort"); int namenodeInfoPort = -1; if (namenodeInfoPortStr != null) namenodeInfoPort = Integer.parseInt(namenodeInfoPortStr); final String nnAddr = req.getParameter(JspHelper.NAMENODE_ADDRESS); if (nnAddr == null){ out.print(JspHelper.NAMENODE_ADDRESS + " url param is null"); return; } DFSClient dfs = getDFSClient(ugi, nnAddr, conf); String target = dir; final HdfsFileStatus targetStatus = dfs.getFileInfo(target); if (targetStatus == null) { // not exists out.print("<h3>File or directory : " + target + " does not exist</h3>"); JspHelper.printGotoForm(out, namenodeInfoPort, tokenString, target, nnAddr); } else { if (!targetStatus.isDir()) { // a file List<LocatedBlock> blocks = dfs.getNamenode().getBlockLocations(dir, 0, 1) .getLocatedBlocks(); LocatedBlock firstBlock = null; DatanodeInfo[] locations = null; if (blocks.size() > 0) { firstBlock = blocks.get(0); locations = firstBlock.getLocations(); } if (locations == null || locations.length == 0) { out.print("Empty file"); } else { DatanodeInfo chosenNode = JspHelper.bestNode(firstBlock, conf); String fqdn = canonicalize(chosenNode.getHost()); String datanodeAddr = chosenNode.getName(); int datanodePort = Integer.parseInt(datanodeAddr.substring( datanodeAddr.indexOf(':') + 1, datanodeAddr.length())); String redirectLocation = "http://" + fqdn + ":" + chosenNode.getInfoPort() + "/browseBlock.jsp?blockId=" + firstBlock.getBlock().getBlockId() + "&blockSize=" + firstBlock.getBlock().getNumBytes() + "&genstamp=" + firstBlock.getBlock().getGenerationStamp() + "&filename=" + URLEncoder.encode(dir, "UTF-8") + "&datanodePort=" + datanodePort + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr); resp.sendRedirect(redirectLocation); } return; } // directory // generate a table and dump the info String[] headings = { "Name", "Type", "Size", "Replication", "Block Size", "Modification Time", "Permission", "Owner", "Group" }; out.print("<h3>Contents of directory "); JspHelper.printPathWithLinks(dir, out, namenodeInfoPort, tokenString, nnAddr); out.print("</h3><hr>"); JspHelper.printGotoForm(out, namenodeInfoPort, tokenString, dir, nnAddr); out.print("<hr>"); File f = new File(dir); String parent; if ((parent = f.getParent()) != null) out.print("<a href=\"" + req.getRequestURL() + "?dir=" + parent + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr) + "\">Go to parent directory</a><br>"); DirectoryListing thisListing = dfs.listPaths(target, HdfsFileStatus.EMPTY_NAME); if (thisListing == null || thisListing.getPartialListing().length == 0) { out.print("Empty directory"); } else { JspHelper.addTableHeader(out); int row = 0; JspHelper.addTableRow(out, headings, row++); String cols[] = new String[headings.length]; do { HdfsFileStatus[] files = thisListing.getPartialListing(); for (int i = 0; i < files.length; i++) { String localFileName = files[i].getLocalName(); // Get the location of the first block of the file if (!files[i].isDir()) { cols[1] = "file"; cols[2] = StringUtils.byteDesc(files[i].getLen()); cols[3] = Short.toString(files[i].getReplication()); cols[4] = StringUtils.byteDesc(files[i].getBlockSize()); } else { cols[1] = "dir"; cols[2] = ""; cols[3] = ""; cols[4] = ""; } String datanodeUrl = req.getRequestURL() + "?dir=" + URLEncoder.encode(files[i].getFullName(target), "UTF-8") + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr); cols[0] = "<a href=\"" + datanodeUrl + "\">" + localFileName + "</a>"; cols[5] = lsDateFormat.format(new Date((files[i] .getModificationTime()))); cols[6] = files[i].getPermission().toString(); cols[7] = files[i].getOwner(); cols[8] = files[i].getGroup(); JspHelper.addTableRow(out, cols, row++); } if (!thisListing.hasMore()) { break; } thisListing = dfs.listPaths(target, thisListing.getLastName()); } while (thisListing != null); JspHelper.addTableFooter(out); } } out.print("<br><a href=\"http://" + canonicalize(nnAddr) + ":" + namenodeInfoPort + "/dfshealth.jsp\">Go back to DFS home</a>"); dfs.close(); } static void generateFileDetails(JspWriter out, HttpServletRequest req, Configuration conf ) throws IOException, InterruptedException { long startOffset = 0; int datanodePort; final Long blockId = JspHelper.validateLong(req.getParameter("blockId")); if (blockId == null) { out.print("Invalid input (blockId absent)"); return; } String tokenString = req.getParameter(JspHelper.DELEGATION_PARAMETER_NAME); UserGroupInformation ugi = JspHelper.getUGI(req, conf); String datanodePortStr = req.getParameter("datanodePort"); if (datanodePortStr == null) { out.print("Invalid input (datanodePort absent)"); return; } datanodePort = Integer.parseInt(datanodePortStr); final Long genStamp = JspHelper.validateLong(req.getParameter("genstamp")); if (genStamp == null) { out.print("Invalid input (genstamp absent)"); return; } String namenodeInfoPortStr = req.getParameter("namenodeInfoPort"); int namenodeInfoPort = -1; if (namenodeInfoPortStr != null) namenodeInfoPort = Integer.parseInt(namenodeInfoPortStr); final String nnAddr = req.getParameter(JspHelper.NAMENODE_ADDRESS); if (nnAddr == null){ out.print(JspHelper.NAMENODE_ADDRESS + " url param is null"); return; } final int chunkSizeToView = JspHelper.string2ChunkSizeToView( req.getParameter("chunkSizeToView"), getDefaultChunkSize(conf)); String startOffsetStr = req.getParameter("startOffset"); if (startOffsetStr == null || Long.parseLong(startOffsetStr) < 0) startOffset = 0; else startOffset = Long.parseLong(startOffsetStr); String path = StringEscapeUtils.unescapeHtml(req.getParameter("filename")); if (path == null) { path = req.getPathInfo() == null ? "/" : req.getPathInfo(); } final String filename = JspHelper.validatePath(path); if (filename == null) { out.print("Invalid input"); return; } final String blockSizeStr = req.getParameter("blockSize"); if (blockSizeStr == null || blockSizeStr.length() == 0) { out.print("Invalid input"); return; } long blockSize = Long.parseLong(blockSizeStr); final DFSClient dfs = getDFSClient(ugi, nnAddr, conf); List<LocatedBlock> blocks = dfs.getNamenode().getBlockLocations(filename, 0, Long.MAX_VALUE).getLocatedBlocks(); // Add the various links for looking at the file contents // URL for downloading the full file String downloadUrl = "http://" + req.getServerName() + ":" + req.getServerPort() + "/streamFile" + ServletUtil.encodePath(filename) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr, true) + JspHelper.getDelegationTokenUrlParam(tokenString); out.print("<a name=\"viewOptions\"></a>"); out.print("<a href=\"" + downloadUrl + "\">Download this file</a><br>"); DatanodeInfo chosenNode; // URL for TAIL LocatedBlock lastBlk = blocks.get(blocks.size() - 1); try { chosenNode = JspHelper.bestNode(lastBlk, conf); } catch (IOException e) { out.print(e.toString()); dfs.close(); return; } String fqdn = canonicalize(chosenNode.getHost()); String tailUrl = "http://" + fqdn + ":" + chosenNode.getInfoPort() + "/tail.jsp?filename=" + URLEncoder.encode(filename, "UTF-8") + "&namenodeInfoPort=" + namenodeInfoPort + "&chunkSizeToView=" + chunkSizeToView + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr) + "&referrer=" + URLEncoder.encode( req.getRequestURL() + "?" + req.getQueryString(), "UTF-8"); out.print("<a href=\"" + tailUrl + "\">Tail this file</a><br>"); out.print("<form action=\"/browseBlock.jsp\" method=GET>"); out.print("<b>Chunk size to view (in bytes, up to file's DFS block size): </b>"); out.print("<input type=\"hidden\" name=\"blockId\" value=\"" + blockId + "\">"); out.print("<input type=\"hidden\" name=\"blockSize\" value=\"" + blockSize + "\">"); out.print("<input type=\"hidden\" name=\"startOffset\" value=\"" + startOffset + "\">"); out.print("<input type=\"hidden\" name=\"filename\" value=\"" + filename + "\">"); out.print("<input type=\"hidden\" name=\"genstamp\" value=\"" + genStamp + "\">"); out.print("<input type=\"hidden\" name=\"datanodePort\" value=\"" + datanodePort + "\">"); out.print("<input type=\"hidden\" name=\"namenodeInfoPort\" value=\"" + namenodeInfoPort + "\">"); out.print("<input type=\"hidden\" name=\"" + JspHelper.NAMENODE_ADDRESS + "\" value=\"" + nnAddr + "\">"); out.print("<input type=\"text\" name=\"chunkSizeToView\" value=" + chunkSizeToView + " size=10 maxlength=10>"); out.print("  <input type=\"submit\" name=\"submit\" value=\"Refresh\">"); out.print("</form>"); out.print("<hr>"); out.print("<a name=\"blockDetails\"></a>"); out.print("<B>Total number of blocks: " + blocks.size() + "</B><br>"); // generate a table and dump the info out.println("\n<table>"); String nnCanonicalName = canonicalize(nnAddr); for (LocatedBlock cur : blocks) { out.print("<tr>"); final String blockidstring = Long.toString(cur.getBlock().getBlockId()); blockSize = cur.getBlock().getNumBytes(); out.print("<td>" + blockidstring + ":</td>"); DatanodeInfo[] locs = cur.getLocations(); for (int j = 0; j < locs.length; j++) { String datanodeAddr = locs[j].getName(); datanodePort = Integer.parseInt(datanodeAddr.substring(datanodeAddr .indexOf(':') + 1, datanodeAddr.length())); fqdn = canonicalize(locs[j].getHost()); String blockUrl = "http://" + fqdn + ":" + locs[j].getInfoPort() + "/browseBlock.jsp?blockId=" + blockidstring + "&blockSize=" + blockSize + "&filename=" + URLEncoder.encode(filename, "UTF-8") + "&datanodePort=" + datanodePort + "&genstamp=" + cur.getBlock().getGenerationStamp() + "&namenodeInfoPort=" + namenodeInfoPort + "&chunkSizeToView=" + chunkSizeToView + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr); String blockInfoUrl = "http://" + nnCanonicalName + ":" + namenodeInfoPort + "/block_info_xml.jsp?blockId=" + blockidstring; out.print("<td> </td><td><a href=\"" + blockUrl + "\">" + datanodeAddr + "</a></td><td>" + "<a href=\"" + blockInfoUrl + "\">View Block Info</a></td>"); } out.println("</tr>"); } out.println("</table>"); out.print("<hr>"); out.print("<br><a href=\"http://" + nnCanonicalName + ":" + namenodeInfoPort + "/dfshealth.jsp\">Go back to DFS home</a>"); dfs.close(); } static void generateFileChunks(JspWriter out, HttpServletRequest req, Configuration conf ) throws IOException, InterruptedException { long startOffset = 0; int datanodePort = 0; final String namenodeInfoPortStr = req.getParameter("namenodeInfoPort"); final String nnAddr = req.getParameter(JspHelper.NAMENODE_ADDRESS); if (nnAddr == null) { out.print(JspHelper.NAMENODE_ADDRESS + " url param is null"); return; } final String tokenString = req.getParameter(JspHelper.DELEGATION_PARAMETER_NAME); UserGroupInformation ugi = JspHelper.getUGI(req, conf); int namenodeInfoPort = -1; if (namenodeInfoPortStr != null) namenodeInfoPort = Integer.parseInt(namenodeInfoPortStr); final String filename = JspHelper .validatePath(StringEscapeUtils.unescapeHtml(req.getParameter("filename"))); if (filename == null) { out.print("Invalid input (filename absent)"); return; } final Long blockId = JspHelper.validateLong(req.getParameter("blockId")); if (blockId == null) { out.print("Invalid input (blockId absent)"); return; } final DFSClient dfs = getDFSClient(ugi, nnAddr, conf); String bpid = null; Token<BlockTokenIdentifier> blockToken = BlockTokenSecretManager.DUMMY_TOKEN; List<LocatedBlock> blks = dfs.getNamenode().getBlockLocations(filename, 0, Long.MAX_VALUE).getLocatedBlocks(); if (blks == null || blks.size() == 0) { out.print("Can't locate file blocks"); dfs.close(); return; } boolean needBlockToken = conf.getBoolean( DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_KEY, DFSConfigKeys.DFS_BLOCK_ACCESS_TOKEN_ENABLE_DEFAULT); for (int i = 0; i < blks.size(); i++) { if (blks.get(i).getBlock().getBlockId() == blockId) { bpid = blks.get(i).getBlock().getBlockPoolId(); if (needBlockToken) { blockToken = blks.get(i).getBlockToken(); } break; } } final Long genStamp = JspHelper.validateLong(req.getParameter("genstamp")); if (genStamp == null) { out.print("Invalid input (genstamp absent)"); return; } long blockSize = 0; final String blockSizeStr = req.getParameter("blockSize"); if (blockSizeStr == null) { out.print("Invalid input (blockSize absent)"); return; } blockSize = Long.parseLong(blockSizeStr); final int chunkSizeToView = JspHelper.string2ChunkSizeToView(req .getParameter("chunkSizeToView"), getDefaultChunkSize(conf)); String startOffsetStr = req.getParameter("startOffset"); if (startOffsetStr == null || Long.parseLong(startOffsetStr) < 0) startOffset = 0; else startOffset = Long.parseLong(startOffsetStr); String datanodePortStr = req.getParameter("datanodePort"); if (datanodePortStr == null) { out.print("Invalid input (datanodePort absent)"); return; } datanodePort = Integer.parseInt(datanodePortStr); out.print("<h3>File: "); JspHelper.printPathWithLinks(filename, out, namenodeInfoPort, tokenString, nnAddr); out.print("</h3><hr>"); String parent = new File(filename).getParent(); JspHelper.printGotoForm(out, namenodeInfoPort, tokenString, parent, nnAddr); out.print("<hr>"); out.print("<a href=\"http://" + req.getServerName() + ":" + req.getServerPort() + "/browseDirectory.jsp?dir=" + URLEncoder.encode(parent, "UTF-8") + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr) + "\"><i>Go back to dir listing</i></a><br>"); out.print("<a href=\"#viewOptions\">Advanced view/download options</a><br>"); out.print("<hr>"); // Determine the prev & next blocks long nextStartOffset = 0; long nextBlockSize = 0; String nextBlockIdStr = null; String nextGenStamp = null; String nextHost = req.getServerName(); int nextPort = req.getServerPort(); int nextDatanodePort = datanodePort; // determine data for the next link if (startOffset + chunkSizeToView >= blockSize) { // we have to go to the next block from this point onwards List<LocatedBlock> blocks = dfs.getNamenode().getBlockLocations(filename, 0, Long.MAX_VALUE).getLocatedBlocks(); for (int i = 0; i < blocks.size(); i++) { if (blocks.get(i).getBlock().getBlockId() == blockId) { if (i != blocks.size() - 1) { LocatedBlock nextBlock = blocks.get(i + 1); nextBlockIdStr = Long.toString(nextBlock.getBlock().getBlockId()); nextGenStamp = Long.toString(nextBlock.getBlock() .getGenerationStamp()); nextStartOffset = 0; nextBlockSize = nextBlock.getBlock().getNumBytes(); DatanodeInfo d = JspHelper.bestNode(nextBlock, conf); String datanodeAddr = d.getName(); nextDatanodePort = Integer.parseInt(datanodeAddr.substring( datanodeAddr.indexOf(':') + 1, datanodeAddr.length())); nextHost = d.getHost(); nextPort = d.getInfoPort(); } } } } else { // we are in the same block nextBlockIdStr = blockId.toString(); nextStartOffset = startOffset + chunkSizeToView; nextBlockSize = blockSize; nextGenStamp = genStamp.toString(); } String nextUrl = null; if (nextBlockIdStr != null) { nextUrl = "http://" + canonicalize(nextHost) + ":" + nextPort + "/browseBlock.jsp?blockId=" + nextBlockIdStr + "&blockSize=" + nextBlockSize + "&startOffset=" + nextStartOffset + "&genstamp=" + nextGenStamp + "&filename=" + URLEncoder.encode(filename, "UTF-8") + "&chunkSizeToView=" + chunkSizeToView + "&datanodePort=" + nextDatanodePort + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr); out.print("<a href=\"" + nextUrl + "\">View Next chunk</a>  "); } // determine data for the prev link String prevBlockIdStr = null; String prevGenStamp = null; long prevStartOffset = 0; long prevBlockSize = 0; String prevHost = req.getServerName(); int prevPort = req.getServerPort(); int prevDatanodePort = datanodePort; if (startOffset == 0) { List<LocatedBlock> blocks = dfs.getNamenode().getBlockLocations(filename, 0, Long.MAX_VALUE).getLocatedBlocks(); for (int i = 0; i < blocks.size(); i++) { if (blocks.get(i).getBlock().getBlockId() == blockId) { if (i != 0) { LocatedBlock prevBlock = blocks.get(i - 1); prevBlockIdStr = Long.toString(prevBlock.getBlock().getBlockId()); prevGenStamp = Long.toString(prevBlock.getBlock() .getGenerationStamp()); prevStartOffset = prevBlock.getBlock().getNumBytes() - chunkSizeToView; if (prevStartOffset < 0) prevStartOffset = 0; prevBlockSize = prevBlock.getBlock().getNumBytes(); DatanodeInfo d = JspHelper.bestNode(prevBlock, conf); String datanodeAddr = d.getName(); prevDatanodePort = Integer.parseInt(datanodeAddr.substring( datanodeAddr.indexOf(':') + 1, datanodeAddr.length())); prevHost = d.getHost(); prevPort = d.getInfoPort(); } } } } else { // we are in the same block prevBlockIdStr = blockId.toString(); prevStartOffset = startOffset - chunkSizeToView; if (prevStartOffset < 0) prevStartOffset = 0; prevBlockSize = blockSize; prevGenStamp = genStamp.toString(); } String prevUrl = null; if (prevBlockIdStr != null) { prevUrl = "http://" + canonicalize(prevHost) + ":" + prevPort + "/browseBlock.jsp?blockId=" + prevBlockIdStr + "&blockSize=" + prevBlockSize + "&startOffset=" + prevStartOffset + "&filename=" + URLEncoder.encode(filename, "UTF-8") + "&chunkSizeToView=" + chunkSizeToView + "&genstamp=" + prevGenStamp + "&datanodePort=" + prevDatanodePort + "&namenodeInfoPort=" + namenodeInfoPort + JspHelper.getDelegationTokenUrlParam(tokenString) + JspHelper.getUrlParam(JspHelper.NAMENODE_ADDRESS, nnAddr); out.print("<a href=\"" + prevUrl + "\">View Prev chunk</a>  "); } out.print("<hr>"); out.print("<textarea cols=\"100\" rows=\"25\" wrap=\"virtual\" style=\"width:100%\" READONLY>"); try { JspHelper.streamBlockInAscii(new InetSocketAddress(req.getServerName(), datanodePort), bpid, blockId, blockToken, genStamp, blockSize, startOffset, chunkSizeToView, out, conf); } catch (Exception e) { out.print(e); } out.print("</textarea>"); dfs.close(); } static void generateFileChunksForTail(JspWriter out, HttpServletRequest req, Configuration conf ) throws IOException, InterruptedException { final String referrer = JspHelper.validateURL(req.getParameter("referrer")); boolean noLink = false; if (referrer == null) { noLink = true; } final String filename = JspHelper .validatePath(StringEscapeUtils.unescapeHtml(req.getParameter("filename"))); if (filename == null) { out.print("Invalid input (file name absent)"); return; } String tokenString = req.getParameter(JspHelper.DELEGATION_PARAMETER_NAME); UserGroupInformation ugi = JspHelper.getUGI(req, conf); String namenodeInfoPortStr = req.getParameter("namenodeInfoPort"); String nnAddr = req.getParameter(JspHelper.NAMENODE_ADDRESS); int namenodeInfoPort = -1; if (namenodeInfoPortStr != null) namenodeInfoPort = Integer.parseInt(namenodeInfoPortStr); final int chunkSizeToView = JspHelper.string2ChunkSizeToView(req .getParameter("chunkSizeToView"), getDefaultChunkSize(conf)); if (!noLink) { out.print("<h3>Tail of File: "); JspHelper.printPathWithLinks(filename, out, namenodeInfoPort, tokenString, nnAddr); out.print("</h3><hr>"); out.print("<a href=\"" + referrer + "\">Go Back to File View</a><hr>"); } else { out.print("<h3>" + filename + "</h3>"); } out.print("<b>Chunk size to view (in bytes, up to file's DFS block size): </b>"); out.print("<input type=\"text\" name=\"chunkSizeToView\" value=" + chunkSizeToView + " size=10 maxlength=10>"); out.print("  <input type=\"submit\" name=\"submit\" value=\"Refresh\"><hr>"); out.print("<input type=\"hidden\" name=\"filename\" value=\"" + filename + "\">"); out.print("<input type=\"hidden\" name=\"namenodeInfoPort\" value=\"" + namenodeInfoPort + "\">"); out.print("<input type=\"hidden\" name=\"" + JspHelper.NAMENODE_ADDRESS + "\" value=\"" + nnAddr + "\">"); if (!noLink) out.print("<input type=\"hidden\" name=\"referrer\" value=\"" + referrer + "\">"); // fetch the block from the datanode that has the last block for this file final DFSClient dfs = getDFSClient(ugi, nnAddr, conf); List<LocatedBlock> blocks = dfs.getNamenode().getBlockLocations(filename, 0, Long.MAX_VALUE).getLocatedBlocks(); if (blocks == null || blocks.size() == 0) { out.print("No datanodes contain blocks of file " + filename); dfs.close(); return; } LocatedBlock lastBlk = blocks.get(blocks.size() - 1); String poolId = lastBlk.getBlock().getBlockPoolId(); long blockSize = lastBlk.getBlock().getNumBytes(); long blockId = lastBlk.getBlock().getBlockId(); Token<BlockTokenIdentifier> accessToken = lastBlk.getBlockToken(); long genStamp = lastBlk.getBlock().getGenerationStamp(); DatanodeInfo chosenNode; try { chosenNode = JspHelper.bestNode(lastBlk, conf); } catch (IOException e) { out.print(e.toString()); dfs.close(); return; } InetSocketAddress addr = NetUtils.createSocketAddr(chosenNode.getName()); // view the last chunkSizeToView bytes while Tailing final long startOffset = blockSize >= chunkSizeToView ? blockSize - chunkSizeToView : 0; out.print("<textarea cols=\"100\" rows=\"25\" wrap=\"virtual\" style=\"width:100%\" READONLY>"); JspHelper.streamBlockInAscii(addr, poolId, blockId, accessToken, genStamp, blockSize, startOffset, chunkSizeToView, out, conf); out.print("</textarea>"); dfs.close(); } /** Get DFSClient for a namenode corresponding to the BPID from a datanode */ public static DFSClient getDFSClient(final HttpServletRequest request, final DataNode datanode, final Configuration conf, final UserGroupInformation ugi) throws IOException, InterruptedException { final String nnAddr = request.getParameter(JspHelper.NAMENODE_ADDRESS); return getDFSClient(ugi, nnAddr, conf); } }