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.StorageType; 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 ) throws IOException, InterruptedException { 619 return post(ugi, delegation, username, doAsUser, ROOT, op, concatSrcs, 620 bufferSize, excludeDatanodes); 621 } 622 623 /** Handle HTTP POST request. */ 624 @POST 625 @Path("{" + UriFsPathParam.NAME + ":.*}") 626 @Consumes({"*/*"}) 627 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 628 public Response post( 629 @Context final UserGroupInformation ugi, 630 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 631 final DelegationParam delegation, 632 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 633 final UserParam username, 634 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 635 final DoAsParam doAsUser, 636 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 637 @QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT) 638 final PostOpParam op, 639 @QueryParam(ConcatSourcesParam.NAME) @DefaultValue(ConcatSourcesParam.DEFAULT) 640 final ConcatSourcesParam concatSrcs, 641 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 642 final BufferSizeParam bufferSize, 643 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 644 final ExcludeDatanodesParam excludeDatanodes 645 ) throws IOException, InterruptedException { 646 647 init(ugi, delegation, username, doAsUser, path, op, concatSrcs, bufferSize, 648 excludeDatanodes); 649 650 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 651 @Override 652 public Response run() throws IOException, URISyntaxException { 653 try { 654 return post(ugi, delegation, username, doAsUser, 655 path.getAbsolutePath(), op, concatSrcs, bufferSize, 656 excludeDatanodes); 657 } finally { 658 reset(); 659 } 660 } 661 }); 662 } 663 664 private Response post( 665 final UserGroupInformation ugi, 666 final DelegationParam delegation, 667 final UserParam username, 668 final DoAsParam doAsUser, 669 final String fullpath, 670 final PostOpParam op, 671 final ConcatSourcesParam concatSrcs, 672 final BufferSizeParam bufferSize, 673 final ExcludeDatanodesParam excludeDatanodes 674 ) throws IOException, URISyntaxException { 675 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 676 677 switch(op.getValue()) { 678 case APPEND: 679 { 680 final URI uri = redirectURI(namenode, ugi, delegation, username, 681 doAsUser, fullpath, op.getValue(), -1L, -1L, 682 excludeDatanodes.getValue(), bufferSize); 683 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 684 } 685 case CONCAT: 686 { 687 getRPCServer(namenode).concat(fullpath, concatSrcs.getAbsolutePaths()); 688 return Response.ok().build(); 689 } 690 default: 691 throw new UnsupportedOperationException(op + " is not supported"); 692 } 693 } 694 695 /** Handle HTTP GET request for the root. */ 696 @GET 697 @Path("/") 698 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 699 public Response getRoot( 700 @Context final UserGroupInformation ugi, 701 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 702 final DelegationParam delegation, 703 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 704 final UserParam username, 705 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 706 final DoAsParam doAsUser, 707 @QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT) 708 final GetOpParam op, 709 @QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT) 710 final OffsetParam offset, 711 @QueryParam(LengthParam.NAME) @DefaultValue(LengthParam.DEFAULT) 712 final LengthParam length, 713 @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) 714 final RenewerParam renewer, 715 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 716 final BufferSizeParam bufferSize, 717 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 718 final List<XAttrNameParam> xattrNames, 719 @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) 720 final XAttrEncodingParam xattrEncoding, 721 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 722 final ExcludeDatanodesParam excludeDatanodes, 723 @QueryParam(FsActionParam.NAME) @DefaultValue(FsActionParam.DEFAULT) 724 final FsActionParam fsAction, 725 @QueryParam(TokenKindParam.NAME) @DefaultValue(TokenKindParam.DEFAULT) 726 final TokenKindParam tokenKind, 727 @QueryParam(TokenServiceParam.NAME) @DefaultValue(TokenServiceParam.DEFAULT) 728 final TokenServiceParam tokenService 729 ) throws IOException, InterruptedException { 730 return get(ugi, delegation, username, doAsUser, ROOT, op, offset, length, 731 renewer, bufferSize, xattrNames, xattrEncoding, excludeDatanodes, fsAction, 732 tokenKind, tokenService); 733 } 734 735 /** Handle HTTP GET request. */ 736 @GET 737 @Path("{" + UriFsPathParam.NAME + ":.*}") 738 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 739 public Response get( 740 @Context final UserGroupInformation ugi, 741 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 742 final DelegationParam delegation, 743 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 744 final UserParam username, 745 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 746 final DoAsParam doAsUser, 747 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 748 @QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT) 749 final GetOpParam op, 750 @QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT) 751 final OffsetParam offset, 752 @QueryParam(LengthParam.NAME) @DefaultValue(LengthParam.DEFAULT) 753 final LengthParam length, 754 @QueryParam(RenewerParam.NAME) @DefaultValue(RenewerParam.DEFAULT) 755 final RenewerParam renewer, 756 @QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT) 757 final BufferSizeParam bufferSize, 758 @QueryParam(XAttrNameParam.NAME) @DefaultValue(XAttrNameParam.DEFAULT) 759 final List<XAttrNameParam> xattrNames, 760 @QueryParam(XAttrEncodingParam.NAME) @DefaultValue(XAttrEncodingParam.DEFAULT) 761 final XAttrEncodingParam xattrEncoding, 762 @QueryParam(ExcludeDatanodesParam.NAME) @DefaultValue(ExcludeDatanodesParam.DEFAULT) 763 final ExcludeDatanodesParam excludeDatanodes, 764 @QueryParam(FsActionParam.NAME) @DefaultValue(FsActionParam.DEFAULT) 765 final FsActionParam fsAction, 766 @QueryParam(TokenKindParam.NAME) @DefaultValue(TokenKindParam.DEFAULT) 767 final TokenKindParam tokenKind, 768 @QueryParam(TokenServiceParam.NAME) @DefaultValue(TokenServiceParam.DEFAULT) 769 final TokenServiceParam tokenService 770 ) throws IOException, InterruptedException { 771 772 init(ugi, delegation, username, doAsUser, path, op, offset, length, 773 renewer, bufferSize, xattrEncoding, excludeDatanodes, fsAction, 774 tokenKind, tokenService); 775 776 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 777 @Override 778 public Response run() throws IOException, URISyntaxException { 779 try { 780 return get(ugi, delegation, username, doAsUser, 781 path.getAbsolutePath(), op, offset, length, renewer, bufferSize, 782 xattrNames, xattrEncoding, excludeDatanodes, fsAction, tokenKind, 783 tokenService); 784 } finally { 785 reset(); 786 } 787 } 788 }); 789 } 790 791 private Response get( 792 final UserGroupInformation ugi, 793 final DelegationParam delegation, 794 final UserParam username, 795 final DoAsParam doAsUser, 796 final String fullpath, 797 final GetOpParam op, 798 final OffsetParam offset, 799 final LengthParam length, 800 final RenewerParam renewer, 801 final BufferSizeParam bufferSize, 802 final List<XAttrNameParam> xattrNames, 803 final XAttrEncodingParam xattrEncoding, 804 final ExcludeDatanodesParam excludeDatanodes, 805 final FsActionParam fsAction, 806 final TokenKindParam tokenKind, 807 final TokenServiceParam tokenService 808 ) throws IOException, URISyntaxException { 809 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 810 final NamenodeProtocols np = getRPCServer(namenode); 811 812 switch(op.getValue()) { 813 case OPEN: 814 { 815 final URI uri = redirectURI(namenode, ugi, delegation, username, 816 doAsUser, fullpath, op.getValue(), offset.getValue(), -1L, 817 excludeDatanodes.getValue(), offset, length, bufferSize); 818 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 819 } 820 case GET_BLOCK_LOCATIONS: 821 { 822 final long offsetValue = offset.getValue(); 823 final Long lengthValue = length.getValue(); 824 final LocatedBlocks locatedblocks = np.getBlockLocations(fullpath, 825 offsetValue, lengthValue != null? lengthValue: Long.MAX_VALUE); 826 final String js = JsonUtil.toJsonString(locatedblocks); 827 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 828 } 829 case GETFILESTATUS: 830 { 831 final HdfsFileStatus status = np.getFileInfo(fullpath); 832 if (status == null) { 833 throw new FileNotFoundException("File does not exist: " + fullpath); 834 } 835 836 final String js = JsonUtil.toJsonString(status, true); 837 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 838 } 839 case LISTSTATUS: 840 { 841 final StreamingOutput streaming = getListingStream(np, fullpath); 842 return Response.ok(streaming).type(MediaType.APPLICATION_JSON).build(); 843 } 844 case GETCONTENTSUMMARY: 845 { 846 final ContentSummary contentsummary = np.getContentSummary(fullpath); 847 final String js = JsonUtil.toJsonString(contentsummary); 848 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 849 } 850 case GETFILECHECKSUM: 851 { 852 final URI uri = redirectURI(namenode, ugi, delegation, username, doAsUser, 853 fullpath, op.getValue(), -1L, -1L, null); 854 return Response.temporaryRedirect(uri).type(MediaType.APPLICATION_OCTET_STREAM).build(); 855 } 856 case GETDELEGATIONTOKEN: 857 { 858 if (delegation.getValue() != null) { 859 throw new IllegalArgumentException(delegation.getName() 860 + " parameter is not null."); 861 } 862 final Token<? extends TokenIdentifier> token = generateDelegationToken( 863 namenode, ugi, renewer.getValue()); 864 865 final String setServiceName = tokenService.getValue(); 866 final String setKind = tokenKind.getValue(); 867 if (setServiceName != null) { 868 token.setService(new Text(setServiceName)); 869 } 870 if (setKind != null) { 871 token.setKind(new Text(setKind)); 872 } 873 final String js = JsonUtil.toJsonString(token); 874 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 875 } 876 case GETHOMEDIRECTORY: 877 { 878 final String js = JsonUtil.toJsonString( 879 org.apache.hadoop.fs.Path.class.getSimpleName(), 880 WebHdfsFileSystem.getHomeDirectoryString(ugi)); 881 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 882 } 883 case GETACLSTATUS: { 884 AclStatus status = np.getAclStatus(fullpath); 885 if (status == null) { 886 throw new FileNotFoundException("File does not exist: " + fullpath); 887 } 888 889 final String js = JsonUtil.toJsonString(status); 890 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 891 } 892 case GETXATTRS: { 893 List<String> names = null; 894 if (xattrNames != null) { 895 names = Lists.newArrayListWithCapacity(xattrNames.size()); 896 for (XAttrNameParam xattrName : xattrNames) { 897 if (xattrName.getXAttrName() != null) { 898 names.add(xattrName.getXAttrName()); 899 } 900 } 901 } 902 List<XAttr> xAttrs = np.getXAttrs(fullpath, (names != null && 903 !names.isEmpty()) ? XAttrHelper.buildXAttrs(names) : null); 904 final String js = JsonUtil.toJsonString(xAttrs, 905 xattrEncoding.getEncoding()); 906 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 907 } 908 case LISTXATTRS: { 909 final List<XAttr> xAttrs = np.listXAttrs(fullpath); 910 final String js = JsonUtil.toJsonString(xAttrs); 911 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 912 } 913 case CHECKACCESS: { 914 np.checkAccess(fullpath, FsAction.getFsAction(fsAction.getValue())); 915 return Response.ok().build(); 916 } 917 default: 918 throw new UnsupportedOperationException(op + " is not supported"); 919 } 920 } 921 922 private static DirectoryListing getDirectoryListing(final NamenodeProtocols np, 923 final String p, byte[] startAfter) throws IOException { 924 final DirectoryListing listing = np.getListing(p, startAfter, false); 925 if (listing == null) { // the directory does not exist 926 throw new FileNotFoundException("File " + p + " does not exist."); 927 } 928 return listing; 929 } 930 931 private static StreamingOutput getListingStream(final NamenodeProtocols np, 932 final String p) throws IOException { 933 // allows exceptions like FNF or ACE to prevent http response of 200 for 934 // a failure since we can't (currently) return error responses in the 935 // middle of a streaming operation 936 final DirectoryListing firstDirList = getDirectoryListing(np, p, 937 HdfsFileStatus.EMPTY_NAME); 938 939 // must save ugi because the streaming object will be executed outside 940 // the remote user's ugi 941 final UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); 942 return new StreamingOutput() { 943 @Override 944 public void write(final OutputStream outstream) throws IOException { 945 final PrintWriter out = new PrintWriter(new OutputStreamWriter( 946 outstream, Charsets.UTF_8)); 947 out.println("{\"" + FileStatus.class.getSimpleName() + "es\":{\"" 948 + FileStatus.class.getSimpleName() + "\":["); 949 950 try { 951 // restore remote user's ugi 952 ugi.doAs(new PrivilegedExceptionAction<Void>() { 953 @Override 954 public Void run() throws IOException { 955 long n = 0; 956 for (DirectoryListing dirList = firstDirList; ; 957 dirList = getDirectoryListing(np, p, dirList.getLastName()) 958 ) { 959 // send each segment of the directory listing 960 for (HdfsFileStatus s : dirList.getPartialListing()) { 961 if (n++ > 0) { 962 out.println(','); 963 } 964 out.print(JsonUtil.toJsonString(s, false)); 965 } 966 // stop if last segment 967 if (!dirList.hasMore()) { 968 break; 969 } 970 } 971 return null; 972 } 973 }); 974 } catch (InterruptedException e) { 975 throw new IOException(e); 976 } 977 978 out.println(); 979 out.println("]}}"); 980 out.flush(); 981 } 982 }; 983 } 984 985 /** Handle HTTP DELETE request for the root. */ 986 @DELETE 987 @Path("/") 988 @Produces(MediaType.APPLICATION_JSON) 989 public Response deleteRoot( 990 @Context final UserGroupInformation ugi, 991 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 992 final DelegationParam delegation, 993 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 994 final UserParam username, 995 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 996 final DoAsParam doAsUser, 997 @QueryParam(DeleteOpParam.NAME) @DefaultValue(DeleteOpParam.DEFAULT) 998 final DeleteOpParam op, 999 @QueryParam(RecursiveParam.NAME) @DefaultValue(RecursiveParam.DEFAULT) 1000 final RecursiveParam recursive, 1001 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 1002 final SnapshotNameParam snapshotName 1003 ) throws IOException, InterruptedException { 1004 return delete(ugi, delegation, username, doAsUser, ROOT, op, recursive, 1005 snapshotName); 1006 } 1007 1008 /** Handle HTTP DELETE request. */ 1009 @DELETE 1010 @Path("{" + UriFsPathParam.NAME + ":.*}") 1011 @Produces(MediaType.APPLICATION_JSON) 1012 public Response delete( 1013 @Context final UserGroupInformation ugi, 1014 @QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT) 1015 final DelegationParam delegation, 1016 @QueryParam(UserParam.NAME) @DefaultValue(UserParam.DEFAULT) 1017 final UserParam username, 1018 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) 1019 final DoAsParam doAsUser, 1020 @PathParam(UriFsPathParam.NAME) final UriFsPathParam path, 1021 @QueryParam(DeleteOpParam.NAME) @DefaultValue(DeleteOpParam.DEFAULT) 1022 final DeleteOpParam op, 1023 @QueryParam(RecursiveParam.NAME) @DefaultValue(RecursiveParam.DEFAULT) 1024 final RecursiveParam recursive, 1025 @QueryParam(SnapshotNameParam.NAME) @DefaultValue(SnapshotNameParam.DEFAULT) 1026 final SnapshotNameParam snapshotName 1027 ) throws IOException, InterruptedException { 1028 1029 init(ugi, delegation, username, doAsUser, path, op, recursive, snapshotName); 1030 1031 return ugi.doAs(new PrivilegedExceptionAction<Response>() { 1032 @Override 1033 public Response run() throws IOException { 1034 try { 1035 return delete(ugi, delegation, username, doAsUser, 1036 path.getAbsolutePath(), op, recursive, snapshotName); 1037 } finally { 1038 reset(); 1039 } 1040 } 1041 }); 1042 } 1043 1044 private Response delete( 1045 final UserGroupInformation ugi, 1046 final DelegationParam delegation, 1047 final UserParam username, 1048 final DoAsParam doAsUser, 1049 final String fullpath, 1050 final DeleteOpParam op, 1051 final RecursiveParam recursive, 1052 final SnapshotNameParam snapshotName 1053 ) throws IOException { 1054 final NameNode namenode = (NameNode)context.getAttribute("name.node"); 1055 final NamenodeProtocols np = getRPCServer(namenode); 1056 1057 switch(op.getValue()) { 1058 case DELETE: { 1059 final boolean b = np.delete(fullpath, recursive.getValue()); 1060 final String js = JsonUtil.toJsonString("boolean", b); 1061 return Response.ok(js).type(MediaType.APPLICATION_JSON).build(); 1062 } 1063 case DELETESNAPSHOT: { 1064 np.deleteSnapshot(fullpath, snapshotName.getValue()); 1065 return Response.ok().type(MediaType.APPLICATION_OCTET_STREAM).build(); 1066 } 1067 default: 1068 throw new UnsupportedOperationException(op + " is not supported"); 1069 } 1070 } 1071}