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