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 */
018 package org.apache.hadoop.hdfs.server.namenode.web.resources;
019
020 import java.io.FileNotFoundException;
021 import java.io.IOException;
022 import java.io.OutputStream;
023 import java.io.OutputStreamWriter;
024 import java.io.PrintWriter;
025 import java.net.InetAddress;
026 import java.net.URI;
027 import java.net.URISyntaxException;
028 import java.security.PrivilegedExceptionAction;
029 import java.util.EnumSet;
030 import java.util.HashSet;
031 import java.util.List;
032
033 import javax.servlet.ServletContext;
034 import javax.servlet.http.HttpServletRequest;
035 import javax.servlet.http.HttpServletResponse;
036 import javax.ws.rs.Consumes;
037 import javax.ws.rs.DELETE;
038 import javax.ws.rs.DefaultValue;
039 import javax.ws.rs.GET;
040 import javax.ws.rs.POST;
041 import javax.ws.rs.PUT;
042 import javax.ws.rs.Path;
043 import javax.ws.rs.PathParam;
044 import javax.ws.rs.Produces;
045 import javax.ws.rs.QueryParam;
046 import javax.ws.rs.core.Context;
047 import javax.ws.rs.core.MediaType;
048 import javax.ws.rs.core.Response;
049 import javax.ws.rs.core.StreamingOutput;
050
051 import org.apache.commons.logging.Log;
052 import org.apache.commons.logging.LogFactory;
053 import org.apache.hadoop.conf.Configuration;
054 import org.apache.hadoop.fs.ContentSummary;
055 import org.apache.hadoop.fs.FileStatus;
056 import org.apache.hadoop.fs.Options;
057 import org.apache.hadoop.fs.XAttr;
058 import org.apache.hadoop.fs.permission.AclStatus;
059 import org.apache.hadoop.fs.permission.FsAction;
060 import org.apache.hadoop.hdfs.StorageType;
061 import org.apache.hadoop.hdfs.XAttrHelper;
062 import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
063 import org.apache.hadoop.hdfs.protocol.DirectoryListing;
064 import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
065 import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
066 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
067 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenSecretManager;
068 import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
069 import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
070 import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeStorageInfo;
071 import org.apache.hadoop.hdfs.server.common.JspHelper;
072 import org.apache.hadoop.hdfs.server.namenode.NameNode;
073 import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols;
074 import org.apache.hadoop.hdfs.web.JsonUtil;
075 import org.apache.hadoop.hdfs.web.ParamFilter;
076 import org.apache.hadoop.hdfs.web.SWebHdfsFileSystem;
077 import org.apache.hadoop.hdfs.web.WebHdfsFileSystem;
078 import org.apache.hadoop.hdfs.web.resources.*;
079 import org.apache.hadoop.io.Text;
080 import org.apache.hadoop.ipc.RetriableException;
081 import org.apache.hadoop.ipc.Server;
082 import org.apache.hadoop.net.NetworkTopology.InvalidTopologyException;
083 import org.apache.hadoop.net.Node;
084 import org.apache.hadoop.net.NodeBase;
085 import org.apache.hadoop.security.Credentials;
086 import org.apache.hadoop.security.UserGroupInformation;
087 import org.apache.hadoop.security.token.Token;
088 import org.apache.hadoop.security.token.TokenIdentifier;
089 import org.apache.hadoop.util.StringUtils;
090
091 import com.google.common.annotations.VisibleForTesting;
092 import com.google.common.base.Charsets;
093 import com.google.common.collect.Lists;
094 import com.sun.jersey.spi.container.ResourceFilters;
095
096 /** Web-hdfs NameNode implementation. */
097 @Path("")
098 @ResourceFilters(ParamFilter.class)
099 public 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 }