001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.server.namenode.web.resources; 019 020import java.io.FileNotFoundException; 021import java.io.IOException; 022import java.io.OutputStream; 023import java.io.OutputStreamWriter; 024import java.io.PrintWriter; 025import java.net.InetAddress; 026import java.net.URI; 027import java.net.URISyntaxException; 028import java.security.PrivilegedExceptionAction; 029import java.util.EnumSet; 030import java.util.HashSet; 031import java.util.List; 032 033import javax.servlet.ServletContext; 034import javax.servlet.http.HttpServletRequest; 035import javax.servlet.http.HttpServletResponse; 036import javax.ws.rs.Consumes; 037import javax.ws.rs.DELETE; 038import javax.ws.rs.DefaultValue; 039import javax.ws.rs.GET; 040import javax.ws.rs.POST; 041import javax.ws.rs.PUT; 042import javax.ws.rs.Path; 043import javax.ws.rs.PathParam; 044import javax.ws.rs.Produces; 045import javax.ws.rs.QueryParam; 046import javax.ws.rs.core.Context; 047import javax.ws.rs.core.MediaType; 048import javax.ws.rs.core.Response; 049import javax.ws.rs.core.StreamingOutput; 050 051import org.apache.commons.logging.Log; 052import org.apache.commons.logging.LogFactory; 053import org.apache.hadoop.conf.Configuration; 054import org.apache.hadoop.fs.ContentSummary; 055import org.apache.hadoop.fs.FileStatus; 056import org.apache.hadoop.fs.Options; 057import org.apache.hadoop.fs.XAttr; 058import org.apache.hadoop.fs.permission.AclStatus; 059import org.apache.hadoop.fs.permission.FsAction; 060import org.apache.hadoop.hdfs.DFSUtil; 061import org.apache.hadoop.hdfs.XAttrHelper; 062import org.apache.hadoop.hdfs.protocol.DatanodeInfo; 063import org.apache.hadoop.hdfs.protocol.DirectoryListing; 064import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; 065import org.apache.hadoop.hdfs.protocol.LocatedBlocks; 066import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 067import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenSecretManager; 068import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager; 069import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor; 070import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo; 071import org.apache.hadoop.hdfs.server.common.JspHelper; 072import org.apache.hadoop.hdfs.server.namenode.NameNode; 073import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols; 074import org.apache.hadoop.hdfs.web.JsonUtil; 075import org.apache.hadoop.hdfs.web.ParamFilter; 076import org.apache.hadoop.hdfs.web.SWebHdfsFileSystem; 077import org.apache.hadoop.hdfs.web.WebHdfsFileSystem; 078import org.apache.hadoop.hdfs.web.resources.*; 079import org.apache.hadoop.io.Text; 080import org.apache.hadoop.ipc.RetriableException; 081import org.apache.hadoop.ipc.Server; 082import org.apache.hadoop.net.NetworkTopology.InvalidTopologyException; 083import org.apache.hadoop.net.Node; 084import org.apache.hadoop.net.NodeBase; 085import org.apache.hadoop.security.Credentials; 086import org.apache.hadoop.security.UserGroupInformation; 087import org.apache.hadoop.security.token.Token; 088import org.apache.hadoop.security.token.TokenIdentifier; 089import org.apache.hadoop.util.StringUtils; 090 091import com.google.common.annotations.VisibleForTesting; 092import com.google.common.base.Charsets; 093import com.google.common.collect.Lists; 094import com.sun.jersey.spi.container.ResourceFilters; 095 096/** Web-hdfs NameNode implementation. */ 097@Path("") 098@ResourceFilters(ParamFilter.class) 099public class NamenodeWebHdfsMethods { 100 public static final Log LOG = LogFactory.getLog(NamenodeWebHdfsMethods.class); 101 102 private static final UriFsPathParam ROOT = new UriFsPathParam(""); 103 104 private static final ThreadLocal<String> REMOTE_ADDRESS = new ThreadLocal<String>(); 105 106 /** @return the remote client address. */ 107 public static String getRemoteAddress() { 108 return REMOTE_ADDRESS.get(); 109 } 110 111 public static InetAddress getRemoteIp() { 112 try { 113 return InetAddress.getByName(getRemoteAddress()); 114 } catch (Exception e) { 115 return null; 116 } 117 } 118 119 /** 120 * Returns true if a WebHdfs request is in progress. Akin to 121 * {@link Server#isRpcInvocation()}. 122 */ 123 public static boolean isWebHdfsInvocation() { 124 return getRemoteAddress() != null; 125 } 126 127 private @Context ServletContext context; 128 private @Context HttpServletRequest request; 129 private @Context HttpServletResponse response; 130 131 private void init(final UserGroupInformation ugi, 132 final DelegationParam delegation, 133 final UserParam username, final DoAsParam doAsUser, 134 final UriFsPathParam path, final HttpOpParam<?> op, 135 final Param<?, ?>... parameters) { 136 if (LOG.isTraceEnabled()) { 137 LOG.trace("HTTP " + op.getValue().getType() + ": " + op + ", " + path 138 + ", ugi=" + ugi + ", " + username + ", " + doAsUser 139 + Param.toSortedString(", ", parameters)); 140 } 141 142 //clear content type 143 response.setContentType(null); 144 145 // set the remote address, if coming in via a trust proxy server then 146 // the address with be that of the proxied client 147 REMOTE_ADDRESS.set(JspHelper.getRemoteAddr(request)); 148 } 149 150 private void reset() { 151 REMOTE_ADDRESS.set(null); 152 } 153 154 private static NamenodeProtocols getRPCServer(NameNode namenode) 155 throws IOException { 156 final NamenodeProtocols np = namenode.getRpcServer(); 157 if (np == null) { 158 throw new RetriableException("Namenode is in startup mode"); 159 } 160 return np; 161 } 162 163 @VisibleForTesting 164 static DatanodeInfo chooseDatanode(final NameNode namenode, 165 final String path, final HttpOpParam.Op op, final long openOffset, 166 final long blocksize, final String excludeDatanodes) throws IOException { 167 final BlockManager bm = namenode.getNamesystem().getBlockManager(); 168 169 HashSet<Node> excludes = new HashSet<Node>(); 170 if (excludeDatanodes != null) { 171 for (String host : StringUtils 172 .getTrimmedStringCollection(excludeDatanodes)) { 173 int idx = host.indexOf(":"); 174 if (idx != -1) { 175 excludes.add(bm.getDatanodeManager().getDatanodeByXferAddr( 176 host.substring(0, idx), Integer.parseInt(host.substring(idx + 1)))); 177 } else { 178 excludes.add(bm.getDatanodeManager().getDatanodeByHost(host)); 179 } 180 } 181 } 182 183 if (op == PutOpParam.Op.CREATE) { 184 //choose a datanode near to client 185 final DatanodeDescriptor clientNode = bm.getDatanodeManager( 186 ).getDatanodeByHost(getRemoteAddress()); 187 if (clientNode != null) { 188 final DatanodeStorageInfo[] storages = bm.chooseTarget4WebHDFS( 189 path, clientNode, excludes, blocksize); 190 if (storages.length > 0) { 191 return storages[0].getDatanodeDescriptor(); 192 } 193 } 194 } else if (op == GetOpParam.Op.OPEN 195 || op == GetOpParam.Op.GETFILECHECKSUM 196 || op == PostOpParam.Op.APPEND) { 197 //choose a datanode containing a replica 198 final NamenodeProtocols np = getRPCServer(namenode); 199 final HdfsFileStatus status = np.getFileInfo(path); 200 if (status == null) { 201 throw new FileNotFoundException("File " + path + " not found."); 202 } 203 final long len = status.getLen(); 204 if (op == GetOpParam.Op.OPEN) { 205 if (openOffset < 0L || (openOffset >= len && len > 0)) { 206 throw new IOException("Offset=" + openOffset 207 + " out of the range [0, " + len + "); " + op + ", path=" + path); 208 } 209 } 210 211 if (len > 0) { 212 final long offset = op == GetOpParam.Op.OPEN? openOffset: len - 1; 213 final LocatedBlocks locations = np.getBlockLocations(path, offset, 1); 214 final int count = locations.locatedBlockCount(); 215 if (count > 0) { 216 return bestNode(locations.get(0).getLocations(), excludes); 217 } 218 } 219 } 220 221 return (DatanodeDescriptor)bm.getDatanodeManager().getNetworkTopology( 222 ).chooseRandom(NodeBase.ROOT); 223 } 224 225 /** 226 * Choose the datanode to redirect the request. Note that the nodes have been 227 * sorted based on availability and network distances, thus it is sufficient 228 * to return the first element of the node here. 229 */ 230 private static DatanodeInfo bestNode(DatanodeInfo[] nodes, 231 HashSet<Node> excludes) throws IOException { 232 for (DatanodeInfo dn: nodes) { 233 if (false == dn.isDecommissioned() && false == excludes.contains(dn)) { 234 return dn; 235 } 236 } 237 throw new IOException("No active nodes contain this block"); 238 } 239 240 private Token<? extends TokenIdentifier> generateDelegationToken( 241 final NameNode namenode, final UserGroupInformation ugi, 242 final String renewer) throws IOException { 243 final Credentials c = DelegationTokenSecretManager.createCredentials( 244 namenode, ugi, renewer != null? renewer: ugi.getShortUserName()); 245 if (c == null) { 246 return null; 247 } 248 final Token<? extends TokenIdentifier> t = c.getAllTokens().iterator().next(); 249 Text kind = request.getScheme().equals("http") ? WebHdfsFileSystem.TOKEN_KIND 250 : SWebHdfsFileSystem.TOKEN_KIND; 251 t.setKind(kind); 252 return t; 253 } 254 255 private URI redirectURI(final NameNode namenode, 256 final UserGroupInformation ugi, final DelegationParam delegation, 257 final UserParam username, final DoAsParam doAsUser, 258 final String path, final HttpOpParam.Op op, final long openOffset, 259 final long blocksize, final String excludeDatanodes, 260 final Param<?, ?>... parameters) throws URISyntaxException, IOException { 261 final DatanodeInfo dn; 262 try { 263 dn = chooseDatanode(namenode, path, op, openOffset, blocksize, 264 excludeDatanodes); 265 } catch (InvalidTopologyException ite) { 266 throw new IOException("Failed to find datanode, suggest to check cluster health.", ite); 267 } 268 269 final String delegationQuery; 270 if (!UserGroupInformation.isSecurityEnabled()) { 271 //security disabled 272 delegationQuery = Param.toSortedString("&", doAsUser, username); 273 } else if (delegation.getValue() != null) { 274 //client has provided a token 275 delegationQuery = "&" + delegation; 276 } else { 277 //generate a token 278 final Token<? extends TokenIdentifier> t = generateDelegationToken( 279 namenode, ugi, request.getUserPrincipal().getName()); 280 delegationQuery = "&" + new DelegationParam(t.encodeToUrlString()); 281 } 282 final String query = op.toQueryString() + delegationQuery 283 + "&" + new NamenodeAddressParam(namenode) 284 + Param.toSortedString("&", parameters); 285 final String uripath = WebHdfsFileSystem.PATH_PREFIX + path; 286 287 final String scheme = request.getScheme(); 288 int port = "http".equals(scheme) ? dn.getInfoPort() : dn 289 .getInfoSecurePort(); 290 final URI uri = new URI(scheme, null, dn.getHostName(), port, uripath, 291 query, null); 292 293 if (LOG.isTraceEnabled()) { 294 LOG.trace("redirectURI=" + uri); 295 } 296 return uri; 297 } 298 299 /** Handle HTTP PUT request for the root. */ 300 @PUT 301 @Path("/") 302 @Consumes({"*/*"}) 303 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 304 public Response putRoot( 305 @Context final UserGroupInformation ugi, 306 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 307 final DelegationParam delegation, 308 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 309 final UserParam username, 310 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 311 final DoAsParam doAsUser, 312 @QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT) 313 final PutOpParam op, 314 @QueryParam(DestinationParam.NAME) @DefaultValue(DestinationParam.DEFAULT) 315 final DestinationParam destination, 316 @QueryParam(OwnerParam.NAME) @DefaultValue(OwnerParam.DEFAULT) 317 final OwnerParam owner, 318 @QueryParam(GroupParam.NAME) @DefaultValue(GroupParam.DEFAULT) 319 final GroupParam group, 320 @QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT) 321 final PermissionParam permission, 322 @QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT) 323 final OverwriteParam overwrite, 324 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 325 final BufferSizeParam bufferSize, 326 @QueryParam(ReplicationParam.NAME) @DefaultValue(ReplicationParam.DEFAULT) 327 final ReplicationParam replication, 328 @QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT) 329 final BlockSizeParam blockSize, 330 @QueryParam(ModificationTimeParam.NAME) @DefaultValue(ModificationTimeParam.DEFAULT) 331 final ModificationTimeParam modificationTime, 332 @QueryParam(AccessTimeParam.NAME) @DefaultValue(AccessTimeParam.DEFAULT) 333 final AccessTimeParam accessTime, 334 @QueryParam(RenameOptionSetParam.NAME) @DefaultValue(RenameOptionSetParam.DEFAULT) 335 final RenameOptionSetParam renameOptions, 336 @QueryParam(CreateParentParam.NAME) @DefaultValue(CreateParentParam.DEFAULT) 337 final CreateParentParam createParent, 338 @QueryParam(TokenArgumentParam.NAME) @DefaultValue(TokenArgumentParam.DEFAULT) 339 final TokenArgumentParam delegationTokenArgument, 340 @QueryParam(AclPermissionParam.NAME) @DefaultValue(AclPermissionParam.DEFAULT) 341 final AclPermissionParam aclPermission, 342 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 343 final XAttrNameParam xattrName, 344 @QueryParam(XAttrValueParam.NAME) @DefaultValue(XAttrValueParam.DEFAULT) 345 final XAttrValueParam xattrValue, 346 @QueryParam(XAttrSetFlagParam.NAME) @DefaultValue(XAttrSetFlagParam.DEFAULT) 347 final XAttrSetFlagParam xattrSetFlag, 348 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 349 final SnapshotNameParam snapshotName, 350 @QueryParam(OldSnapshotNameParam.NAME) @DefaultValue(OldSnapshotNameParam.DEFAULT) 351 final OldSnapshotNameParam oldSnapshotName, 352 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 353 final ExcludeDatanodesParam excludeDatanodes 354 ) throws IOException, InterruptedException { 355 return put(ugi, delegation, username, doAsUser, ROOT, op, destination, 356 owner, group, permission, overwrite, bufferSize, replication, 357 blockSize, modificationTime, accessTime, renameOptions, createParent, 358 delegationTokenArgument, aclPermission, xattrName, xattrValue, 359 xattrSetFlag, snapshotName, oldSnapshotName, excludeDatanodes); 360 } 361 362 /** Handle HTTP PUT request. */ 363 @PUT 364 @Path("{" + UriFsPathParam.NAME + ":.*}") 365 @Consumes({"*/*"}) 366 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 367 public Response put( 368 @Context final UserGroupInformation ugi, 369 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 370 final DelegationParam delegation, 371 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 372 final UserParam username, 373 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 374 final DoAsParam doAsUser, 375 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 376 @QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT) 377 final PutOpParam op, 378 @QueryParam(DestinationParam.NAME) @DefaultValue(DestinationParam.DEFAULT) 379 final DestinationParam destination, 380 @QueryParam(OwnerParam.NAME) @DefaultValue(OwnerParam.DEFAULT) 381 final OwnerParam owner, 382 @QueryParam(GroupParam.NAME) @DefaultValue(GroupParam.DEFAULT) 383 final GroupParam group, 384 @QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT) 385 final PermissionParam permission, 386 @QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT) 387 final OverwriteParam overwrite, 388 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 389 final BufferSizeParam bufferSize, 390 @QueryParam(ReplicationParam.NAME) @DefaultValue(ReplicationParam.DEFAULT) 391 final ReplicationParam replication, 392 @QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT) 393 final BlockSizeParam blockSize, 394 @QueryParam(ModificationTimeParam.NAME) @DefaultValue(ModificationTimeParam.DEFAULT) 395 final ModificationTimeParam modificationTime, 396 @QueryParam(AccessTimeParam.NAME) @DefaultValue(AccessTimeParam.DEFAULT) 397 final AccessTimeParam accessTime, 398 @QueryParam(RenameOptionSetParam.NAME) @DefaultValue(RenameOptionSetParam.DEFAULT) 399 final RenameOptionSetParam renameOptions, 400 @QueryParam(CreateParentParam.NAME) @DefaultValue(CreateParentParam.DEFAULT) 401 final CreateParentParam createParent, 402 @QueryParam(TokenArgumentParam.NAME) @DefaultValue(TokenArgumentParam.DEFAULT) 403 final TokenArgumentParam delegationTokenArgument, 404 @QueryParam(AclPermissionParam.NAME) @DefaultValue(AclPermissionParam.DEFAULT) 405 final AclPermissionParam aclPermission, 406 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 407 final XAttrNameParam xattrName, 408 @QueryParam(XAttrValueParam.NAME) @DefaultValue(XAttrValueParam.DEFAULT) 409 final XAttrValueParam xattrValue, 410 @QueryParam(XAttrSetFlagParam.NAME) @DefaultValue(XAttrSetFlagParam.DEFAULT) 411 final XAttrSetFlagParam xattrSetFlag, 412 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 413 final SnapshotNameParam snapshotName, 414 @QueryParam(OldSnapshotNameParam.NAME) @DefaultValue(OldSnapshotNameParam.DEFAULT) 415 final OldSnapshotNameParam oldSnapshotName, 416 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 417 final ExcludeDatanodesParam excludeDatanodes 418 ) throws IOException, InterruptedException { 419 420 init(ugi, delegation, username, doAsUser, path, op, destination, owner, 421 group, permission, overwrite, bufferSize, replication, blockSize, 422 modificationTime, accessTime, renameOptions, delegationTokenArgument, 423 aclPermission, xattrName, xattrValue, xattrSetFlag, snapshotName, 424 oldSnapshotName, excludeDatanodes); 425 426 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 427 @Override 428 public Response run() throws IOException, URISyntaxException { 429 try { 430 return put(ugi, delegation, username, doAsUser, 431 path.getAbsolutePath(), op, destination, owner, group, 432 permission, overwrite, bufferSize, replication, blockSize, 433 modificationTime, accessTime, renameOptions, createParent, 434 delegationTokenArgument, aclPermission, xattrName, xattrValue, 435 xattrSetFlag, snapshotName, oldSnapshotName, excludeDatanodes); 436 } finally { 437 reset(); 438 } 439 } 440 }); 441 } 442 443 private Response put( 444 final UserGroupInformation ugi, 445 final DelegationParam delegation, 446 final UserParam username, 447 final DoAsParam doAsUser, 448 final String fullpath, 449 final PutOpParam op, 450 final DestinationParam destination, 451 final OwnerParam owner, 452 final GroupParam group, 453 final PermissionParam permission, 454 final OverwriteParam overwrite, 455 final BufferSizeParam bufferSize, 456 final ReplicationParam replication, 457 final BlockSizeParam blockSize, 458 final ModificationTimeParam modificationTime, 459 final AccessTimeParam accessTime, 460 final RenameOptionSetParam renameOptions, 461 final CreateParentParam createParent, 462 final TokenArgumentParam delegationTokenArgument, 463 final AclPermissionParam aclPermission, 464 final XAttrNameParam xattrName, 465 final XAttrValueParam xattrValue, 466 final XAttrSetFlagParam xattrSetFlag, 467 final SnapshotNameParam snapshotName, 468 final OldSnapshotNameParam oldSnapshotName, 469 final ExcludeDatanodesParam exclDatanodes 470 ) throws IOException, URISyntaxException { 471 472 final Configuration conf = (Configuration)context.getAttribute(JspHelper.CURRENT_CONF); 473 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 474 final NamenodeProtocols np = getRPCServer(namenode); 475 476 switch(op.getValue()) { 477 case CREATE: 478 { 479 final URI uri = redirectURI(namenode, ugi, delegation, username, 480 doAsUser, fullpath, op.getValue(), -1L, blockSize.getValue(conf), 481 exclDatanodes.getValue(), permission, overwrite, bufferSize, 482 replication, blockSize); 483 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 484 } 485 case MKDIRS: 486 { 487 final boolean b = np.mkdirs(fullpath, permission.getFsPermission(), true); 488 final String js = JsonUtil.toJsonString("boolean", b); 489 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 490 } 491 case CREATESYMLINK: 492 { 493 np.createSymlink(destination.getValue(), fullpath, 494 PermissionParam.getDefaultFsPermission(), createParent.getValue()); 495 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 496 } 497 case RENAME: 498 { 499 final EnumSet<Options.Rename> s = renameOptions.getValue(); 500 if (s.isEmpty()) { 501 final boolean b = np.rename(fullpath, destination.getValue()); 502 final String js = JsonUtil.toJsonString("boolean", b); 503 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 504 } else { 505 np.rename2(fullpath, destination.getValue(), 506 s.toArray(new Options.Rename[s.size()])); 507 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 508 } 509 } 510 case SETREPLICATION: 511 { 512 final boolean b = np.setReplication(fullpath, replication.getValue(conf)); 513 final String js = JsonUtil.toJsonString("boolean", b); 514 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 515 } 516 case SETOWNER: 517 { 518 if (owner.getValue() == null && group.getValue() == null) { 519 throw new IllegalArgumentException("Both owner and group are empty."); 520 } 521 522 np.setOwner(fullpath, owner.getValue(), group.getValue()); 523 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 524 } 525 case SETPERMISSION: 526 { 527 np.setPermission(fullpath, permission.getFsPermission()); 528 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 529 } 530 case SETTIMES: 531 { 532 np.setTimes(fullpath, modificationTime.getValue(), accessTime.getValue()); 533 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 534 } 535 case RENEWDELEGATIONTOKEN: 536 { 537 final Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(); 538 token.decodeFromUrlString(delegationTokenArgument.getValue()); 539 final long expiryTime = np.renewDelegationToken(token); 540 final String js = JsonUtil.toJsonString("long", expiryTime); 541 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 542 } 543 case CANCELDELEGATIONTOKEN: 544 { 545 final Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(); 546 token.decodeFromUrlString(delegationTokenArgument.getValue()); 547 np.cancelDelegationToken(token); 548 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 549 } 550 case MODIFYACLENTRIES: { 551 np.modifyAclEntries(fullpath, aclPermission.getAclPermission(true)); 552 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 553 } 554 case REMOVEACLENTRIES: { 555 np.removeAclEntries(fullpath, aclPermission.getAclPermission(false)); 556 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 557 } 558 case REMOVEDEFAULTACL: { 559 np.removeDefaultAcl(fullpath); 560 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 561 } 562 case REMOVEACL: { 563 np.removeAcl(fullpath); 564 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 565 } 566 case SETACL: { 567 np.setAcl(fullpath, aclPermission.getAclPermission(true)); 568 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 569 } 570 case SETXATTR: { 571 np.setXAttr( 572 fullpath, 573 XAttrHelper.buildXAttr(xattrName.getXAttrName(), 574 xattrValue.getXAttrValue()), xattrSetFlag.getFlag()); 575 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 576 } 577 case REMOVEXATTR: { 578 np.removeXAttr(fullpath, XAttrHelper.buildXAttr(xattrName.getXAttrName())); 579 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 580 } 581 case CREATESNAPSHOT: { 582 String snapshotPath = np.createSnapshot(fullpath, snapshotName.getValue()); 583 final String js = JsonUtil.toJsonString( 584 org.apache.hadoop.fs.Path.class.getSimpleName(), snapshotPath); 585 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 586 } 587 case RENAMESNAPSHOT: { 588 np.renameSnapshot(fullpath, oldSnapshotName.getValue(), 589 snapshotName.getValue()); 590 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 591 } 592 default: 593 throw new UnsupportedOperationException(op + " is not supported"); 594 } 595 } 596 597 /** Handle HTTP POST request for the root. */ 598 @POST 599 @Path("/") 600 @Consumes({"*/*"}) 601 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 602 public Response postRoot( 603 @Context final UserGroupInformation ugi, 604 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 605 final DelegationParam delegation, 606 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 607 final UserParam username, 608 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 609 final DoAsParam doAsUser, 610 @QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT) 611 final PostOpParam op, 612 @QueryParam(ConcatSourcesParam.NAME) @DefaultValue(ConcatSourcesParam.DEFAULT) 613 final ConcatSourcesParam concatSrcs, 614 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 615 final BufferSizeParam bufferSize, 616 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 617 final ExcludeDatanodesParam excludeDatanodes, 618 @QueryParam(NewLengthParam.NAME) @DefaultValue(NewLengthParam.DEFAULT) 619 final NewLengthParam newLength 620 ) throws IOException, InterruptedException { 621 return post(ugi, delegation, username, doAsUser, ROOT, op, concatSrcs, 622 bufferSize, excludeDatanodes, newLength); 623 } 624 625 /** Handle HTTP POST request. */ 626 @POST 627 @Path("{" + UriFsPathParam.NAME + ":.*}") 628 @Consumes({"*/*"}) 629 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 630 public Response post( 631 @Context final UserGroupInformation ugi, 632 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 633 final DelegationParam delegation, 634 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 635 final UserParam username, 636 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 637 final DoAsParam doAsUser, 638 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 639 @QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT) 640 final PostOpParam op, 641 @QueryParam(ConcatSourcesParam.NAME) @DefaultValue(ConcatSourcesParam.DEFAULT) 642 final ConcatSourcesParam concatSrcs, 643 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 644 final BufferSizeParam bufferSize, 645 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 646 final ExcludeDatanodesParam excludeDatanodes, 647 @QueryParam(NewLengthParam.NAME) @DefaultValue(NewLengthParam.DEFAULT) 648 final NewLengthParam newLength 649 ) throws IOException, InterruptedException { 650 651 init(ugi, delegation, username, doAsUser, path, op, concatSrcs, bufferSize, 652 excludeDatanodes, newLength); 653 654 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 655 @Override 656 public Response run() throws IOException, URISyntaxException { 657 try { 658 return post(ugi, delegation, username, doAsUser, 659 path.getAbsolutePath(), op, concatSrcs, bufferSize, 660 excludeDatanodes, newLength); 661 } finally { 662 reset(); 663 } 664 } 665 }); 666 } 667 668 private Response post( 669 final UserGroupInformation ugi, 670 final DelegationParam delegation, 671 final UserParam username, 672 final DoAsParam doAsUser, 673 final String fullpath, 674 final PostOpParam op, 675 final ConcatSourcesParam concatSrcs, 676 final BufferSizeParam bufferSize, 677 final ExcludeDatanodesParam excludeDatanodes, 678 final NewLengthParam newLength 679 ) throws IOException, URISyntaxException { 680 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 681 final NamenodeProtocols np = getRPCServer(namenode); 682 683 switch(op.getValue()) { 684 case APPEND: 685 { 686 final URI uri = redirectURI(namenode, ugi, delegation, username, 687 doAsUser, fullpath, op.getValue(), -1L, -1L, 688 excludeDatanodes.getValue(), bufferSize); 689 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 690 } 691 case CONCAT: 692 { 693 np.concat(fullpath, concatSrcs.getAbsolutePaths()); 694 return Response.ok().build(); 695 } 696 case TRUNCATE: 697 { 698 // We treat each rest request as a separate client. 699 final boolean b = np.truncate(fullpath, newLength.getValue(), 700 "DFSClient_" + DFSUtil.getSecureRandom().nextLong()); 701 final String js = JsonUtil.toJsonString("boolean", b); 702 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 703 } 704 default: 705 throw new UnsupportedOperationException(op + " is not supported"); 706 } 707 } 708 709 /** Handle HTTP GET request for the root. */ 710 @GET 711 @Path("/") 712 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 713 public Response getRoot( 714 @Context final UserGroupInformation ugi, 715 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 716 final DelegationParam delegation, 717 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 718 final UserParam username, 719 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 720 final DoAsParam doAsUser, 721 @QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT) 722 final GetOpParam op, 723 @QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT) 724 final OffsetParam offset, 725 @QueryParam(LengthParam.NAME) @DefaultValue(LengthParam.DEFAULT) 726 final LengthParam length, 727 @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) 728 final RenewerParam renewer, 729 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 730 final BufferSizeParam bufferSize, 731 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 732 final List<XAttrNameParam> xattrNames, 733 @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) 734 final XAttrEncodingParam xattrEncoding, 735 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 736 final ExcludeDatanodesParam excludeDatanodes, 737 @QueryParam(FsActionParam.NAME) @DefaultValue(FsActionParam.DEFAULT) 738 final FsActionParam fsAction, 739 @QueryParam(TokenKindParam.NAME) @DefaultValue(TokenKindParam.DEFAULT) 740 final TokenKindParam tokenKind, 741 @QueryParam(TokenServiceParam.NAME) @DefaultValue(TokenServiceParam.DEFAULT) 742 final TokenServiceParam tokenService 743 ) throws IOException, InterruptedException { 744 return get(ugi, delegation, username, doAsUser, ROOT, op, offset, length, 745 renewer, bufferSize, xattrNames, xattrEncoding, excludeDatanodes, fsAction, 746 tokenKind, tokenService); 747 } 748 749 /** Handle HTTP GET request. */ 750 @GET 751 @Path("{" + UriFsPathParam.NAME + ":.*}") 752 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 753 public Response get( 754 @Context final UserGroupInformation ugi, 755 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 756 final DelegationParam delegation, 757 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 758 final UserParam username, 759 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 760 final DoAsParam doAsUser, 761 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 762 @QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT) 763 final GetOpParam op, 764 @QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT) 765 final OffsetParam offset, 766 @QueryParam(LengthParam.NAME) @DefaultValue(LengthParam.DEFAULT) 767 final LengthParam length, 768 @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) 769 final RenewerParam renewer, 770 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 771 final BufferSizeParam bufferSize, 772 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 773 final List<XAttrNameParam> xattrNames, 774 @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) 775 final XAttrEncodingParam xattrEncoding, 776 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 777 final ExcludeDatanodesParam excludeDatanodes, 778 @QueryParam(FsActionParam.NAME) @DefaultValue(FsActionParam.DEFAULT) 779 final FsActionParam fsAction, 780 @QueryParam(TokenKindParam.NAME) @DefaultValue(TokenKindParam.DEFAULT) 781 final TokenKindParam tokenKind, 782 @QueryParam(TokenServiceParam.NAME) @DefaultValue(TokenServiceParam.DEFAULT) 783 final TokenServiceParam tokenService 784 ) throws IOException, InterruptedException { 785 786 init(ugi, delegation, username, doAsUser, path, op, offset, length, 787 renewer, bufferSize, xattrEncoding, excludeDatanodes, fsAction, 788 tokenKind, tokenService); 789 790 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 791 @Override 792 public Response run() throws IOException, URISyntaxException { 793 try { 794 return get(ugi, delegation, username, doAsUser, 795 path.getAbsolutePath(), op, offset, length, renewer, bufferSize, 796 xattrNames, xattrEncoding, excludeDatanodes, fsAction, tokenKind, 797 tokenService); 798 } finally { 799 reset(); 800 } 801 } 802 }); 803 } 804 805 private Response get( 806 final UserGroupInformation ugi, 807 final DelegationParam delegation, 808 final UserParam username, 809 final DoAsParam doAsUser, 810 final String fullpath, 811 final GetOpParam op, 812 final OffsetParam offset, 813 final LengthParam length, 814 final RenewerParam renewer, 815 final BufferSizeParam bufferSize, 816 final List<XAttrNameParam> xattrNames, 817 final XAttrEncodingParam xattrEncoding, 818 final ExcludeDatanodesParam excludeDatanodes, 819 final FsActionParam fsAction, 820 final TokenKindParam tokenKind, 821 final TokenServiceParam tokenService 822 ) throws IOException, URISyntaxException { 823 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 824 final NamenodeProtocols np = getRPCServer(namenode); 825 826 switch(op.getValue()) { 827 case OPEN: 828 { 829 final URI uri = redirectURI(namenode, ugi, delegation, username, 830 doAsUser, fullpath, op.getValue(), offset.getValue(), -1L, 831 excludeDatanodes.getValue(), offset, length, bufferSize); 832 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 833 } 834 case GET_BLOCK_LOCATIONS: 835 { 836 final long offsetValue = offset.getValue(); 837 final Long lengthValue = length.getValue(); 838 final LocatedBlocks locatedblocks = np.getBlockLocations(fullpath, 839 offsetValue, lengthValue != null? lengthValue: Long.MAX_VALUE); 840 final String js = JsonUtil.toJsonString(locatedblocks); 841 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 842 } 843 case GETFILESTATUS: 844 { 845 final HdfsFileStatus status = np.getFileInfo(fullpath); 846 if (status == null) { 847 throw new FileNotFoundException("File does not exist: " + fullpath); 848 } 849 850 final String js = JsonUtil.toJsonString(status, true); 851 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 852 } 853 case LISTSTATUS: 854 { 855 final StreamingOutput streaming = getListingStream(np, fullpath); 856 return Response.ok(streaming).type(MediaType.APPLICATION_JSON).build(); 857 } 858 case GETCONTENTSUMMARY: 859 { 860 final ContentSummary contentsummary = np.getContentSummary(fullpath); 861 final String js = JsonUtil.toJsonString(contentsummary); 862 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 863 } 864 case GETFILECHECKSUM: 865 { 866 final URI uri = redirectURI(namenode, ugi, delegation, username, doAsUser, 867 fullpath, op.getValue(), -1L, -1L, null); 868 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 869 } 870 case GETDELEGATIONTOKEN: 871 { 872 if (delegation.getValue() != null) { 873 throw new IllegalArgumentException(delegation.getName() 874 + " parameter is not null."); 875 } 876 final Token<? extends TokenIdentifier> token = generateDelegationToken( 877 namenode, ugi, renewer.getValue()); 878 879 final String setServiceName = tokenService.getValue(); 880 final String setKind = tokenKind.getValue(); 881 if (setServiceName != null) { 882 token.setService(new Text(setServiceName)); 883 } 884 if (setKind != null) { 885 token.setKind(new Text(setKind)); 886 } 887 final String js = JsonUtil.toJsonString(token); 888 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 889 } 890 case GETHOMEDIRECTORY: 891 { 892 final String js = JsonUtil.toJsonString( 893 org.apache.hadoop.fs.Path.class.getSimpleName(), 894 WebHdfsFileSystem.getHomeDirectoryString(ugi)); 895 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 896 } 897 case GETACLSTATUS: { 898 AclStatus status = np.getAclStatus(fullpath); 899 if (status == null) { 900 throw new FileNotFoundException("File does not exist: " + fullpath); 901 } 902 903 final String js = JsonUtil.toJsonString(status); 904 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 905 } 906 case GETXATTRS: { 907 List<String> names = null; 908 if (xattrNames != null) { 909 names = Lists.newArrayListWithCapacity(xattrNames.size()); 910 for (XAttrNameParam xattrName : xattrNames) { 911 if (xattrName.getXAttrName() != null) { 912 names.add(xattrName.getXAttrName()); 913 } 914 } 915 } 916 List<XAttr> xAttrs = np.getXAttrs(fullpath, (names != null && 917 !names.isEmpty()) ? XAttrHelper.buildXAttrs(names) : null); 918 final String js = JsonUtil.toJsonString(xAttrs, 919 xattrEncoding.getEncoding()); 920 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 921 } 922 case LISTXATTRS: { 923 final List<XAttr> xAttrs = np.listXAttrs(fullpath); 924 final String js = JsonUtil.toJsonString(xAttrs); 925 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 926 } 927 case CHECKACCESS: { 928 np.checkAccess(fullpath, FsAction.getFsAction(fsAction.getValue())); 929 return Response.ok().build(); 930 } 931 default: 932 throw new UnsupportedOperationException(op + " is not supported"); 933 } 934 } 935 936 private static DirectoryListing getDirectoryListing(final NamenodeProtocols np, 937 final String p, byte[] startAfter) throws IOException { 938 final DirectoryListing listing = np.getListing(p, startAfter, false); 939 if (listing == null) { // the directory does not exist 940 throw new FileNotFoundException("File " + p + " does not exist."); 941 } 942 return listing; 943 } 944 945 private static StreamingOutput getListingStream(final NamenodeProtocols np, 946 final String p) throws IOException { 947 // allows exceptions like FNF or ACE to prevent http response of 200 for 948 // a failure since we can't (currently) return error responses in the 949 // middle of a streaming operation 950 final DirectoryListing firstDirList = getDirectoryListing(np, p, 951 HdfsFileStatus.EMPTY_NAME); 952 953 // must save ugi because the streaming object will be executed outside 954 // the remote user's ugi 955 final UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); 956 return new StreamingOutput() { 957 @Override 958 public void write(final OutputStream outstream) throws IOException { 959 final PrintWriter out = new PrintWriter(new OutputStreamWriter( 960 outstream, Charsets.UTF_8)); 961 out.println("{\"" + FileStatus.class.getSimpleName() + "es\":{\"" 962 + FileStatus.class.getSimpleName() + "\":["); 963 964 try { 965 // restore remote user's ugi 966 ugi.doAs(new PrivilegedExceptionAction<Void>() { 967 @Override 968 public Void run() throws IOException { 969 long n = 0; 970 for (DirectoryListing dirList = firstDirList; ; 971 dirList = getDirectoryListing(np, p, dirList.getLastName()) 972 ) { 973 // send each segment of the directory listing 974 for (HdfsFileStatus s : dirList.getPartialListing()) { 975 if (n++ > 0) { 976 out.println(','); 977 } 978 out.print(JsonUtil.toJsonString(s, false)); 979 } 980 // stop if last segment 981 if (!dirList.hasMore()) { 982 break; 983 } 984 } 985 return null; 986 } 987 }); 988 } catch (InterruptedException e) { 989 throw new IOException(e); 990 } 991 992 out.println(); 993 out.println("]}}"); 994 out.flush(); 995 } 996 }; 997 } 998 999 /** Handle HTTP DELETE request for the root. */ 1000 @DELETE 1001 @Path("/") 1002 @Produces(MediaType.APPLICATION_JSON) 1003 public Response deleteRoot( 1004 @Context final UserGroupInformation ugi, 1005 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 1006 final DelegationParam delegation, 1007 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 1008 final UserParam username, 1009 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 1010 final DoAsParam doAsUser, 1011 @QueryParam(DeleteOpParam.NAME) @DefaultValue(DeleteOpParam.DEFAULT) 1012 final DeleteOpParam op, 1013 @QueryParam(RecursiveParam.NAME) @DefaultValue(RecursiveParam.DEFAULT) 1014 final RecursiveParam recursive, 1015 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 1016 final SnapshotNameParam snapshotName 1017 ) throws IOException, InterruptedException { 1018 return delete(ugi, delegation, username, doAsUser, ROOT, op, recursive, 1019 snapshotName); 1020 } 1021 1022 /** Handle HTTP DELETE request. */ 1023 @DELETE 1024 @Path("{" + UriFsPathParam.NAME + ":.*}") 1025 @Produces(MediaType.APPLICATION_JSON) 1026 public Response delete( 1027 @Context final UserGroupInformation ugi, 1028 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 1029 final DelegationParam delegation, 1030 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 1031 final UserParam username, 1032 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 1033 final DoAsParam doAsUser, 1034 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 1035 @QueryParam(DeleteOpParam.NAME) @DefaultValue(DeleteOpParam.DEFAULT) 1036 final DeleteOpParam op, 1037 @QueryParam(RecursiveParam.NAME) @DefaultValue(RecursiveParam.DEFAULT) 1038 final RecursiveParam recursive, 1039 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 1040 final SnapshotNameParam snapshotName 1041 ) throws IOException, InterruptedException { 1042 1043 init(ugi, delegation, username, doAsUser, path, op, recursive, snapshotName); 1044 1045 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 1046 @Override 1047 public Response run() throws IOException { 1048 try { 1049 return delete(ugi, delegation, username, doAsUser, 1050 path.getAbsolutePath(), op, recursive, snapshotName); 1051 } finally { 1052 reset(); 1053 } 1054 } 1055 }); 1056 } 1057 1058 private Response delete( 1059 final UserGroupInformation ugi, 1060 final DelegationParam delegation, 1061 final UserParam username, 1062 final DoAsParam doAsUser, 1063 final String fullpath, 1064 final DeleteOpParam op, 1065 final RecursiveParam recursive, 1066 final SnapshotNameParam snapshotName 1067 ) throws IOException { 1068 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 1069 final NamenodeProtocols np = getRPCServer(namenode); 1070 1071 switch(op.getValue()) { 1072 case DELETE: { 1073 final boolean b = np.delete(fullpath, recursive.getValue()); 1074 final String js = JsonUtil.toJsonString("boolean", b); 1075 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 1076 } 1077 case DELETESNAPSHOT: { 1078 np.deleteSnapshot(fullpath, snapshotName.getValue()); 1079 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 1080 } 1081 default: 1082 throw new UnsupportedOperationException(op + " is not supported"); 1083 } 1084 } 1085}