diff --git a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rest/RestClient.java b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rest/RestClient.java index 1fd2091495..ac71abe494 100644 --- a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rest/RestClient.java +++ b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rest/RestClient.java @@ -678,7 +678,21 @@ public void deleteKey(String volumeName, String bucketName, String keyName) @Override public void renameKey(String volumeName, String bucketName, String fromKeyName, String toKeyName) throws IOException { - throw new UnsupportedOperationException("Not yet implemented."); + try { + Preconditions.checkNotNull(volumeName); + Preconditions.checkNotNull(bucketName); + Preconditions.checkNotNull(fromKeyName); + Preconditions.checkNotNull(toKeyName); + URIBuilder builder = new URIBuilder(ozoneRestUri); + builder.setPath(PATH_SEPARATOR + volumeName + PATH_SEPARATOR + bucketName + + PATH_SEPARATOR + fromKeyName); + builder.addParameter(Header.OZONE_RENAME_TO_KEY_PARAM_NAME, toKeyName); + HttpPost httpPost = new HttpPost(builder.build()); + addOzoneHeaders(httpPost); + EntityUtils.consume(executeHttpRequest(httpPost)); + } catch (URISyntaxException e) { + throw new IOException(e); + } } @Override diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/rest/headers/Header.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/rest/headers/Header.java index 00d4857622..ebfc0a9bd3 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/rest/headers/Header.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/client/rest/headers/Header.java @@ -65,6 +65,8 @@ public final class Header { public static final String OZONE_LIST_QUERY_PREVKEY="prev-key"; public static final String OZONE_LIST_QUERY_ROOTSCAN="root-scan"; + public static final String OZONE_RENAME_TO_KEY_PARAM_NAME = "toKey"; + private Header() { // Never constructed. } diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rest/TestOzoneRestClient.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rest/TestOzoneRestClient.java index a94ee6c4a0..9918d63668 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rest/TestOzoneRestClient.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rest/TestOzoneRestClient.java @@ -389,6 +389,36 @@ public void testDeleteKey() bucket.getKey(keyName); } + @Test + public void testRenameKey() + throws IOException, OzoneException { + String volumeName = UUID.randomUUID().toString(); + String bucketName = UUID.randomUUID().toString(); + String fromKeyName = UUID.randomUUID().toString(); + String value = "sample value"; + store.createVolume(volumeName); + OzoneVolume volume = store.getVolume(volumeName); + volume.createBucket(bucketName); + OzoneBucket bucket = volume.getBucket(bucketName); + OzoneOutputStream out = bucket.createKey(fromKeyName, + value.getBytes().length, ReplicationType.STAND_ALONE, + ReplicationFactor.ONE); + out.write(value.getBytes()); + out.close(); + OzoneKey key = bucket.getKey(fromKeyName); + Assert.assertEquals(fromKeyName, key.getName()); + + String toKeyName = UUID.randomUUID().toString(); + bucket.renameKey(fromKeyName, toKeyName); + + key = bucket.getKey(toKeyName); + Assert.assertEquals(toKeyName, key.getName()); + + // Lookup for old key should fail. + thrown.expectMessage("Lookup key failed, error"); + bucket.getKey(fromKeyName); + } + /** * Close OzoneClient and shutdown MiniDFSCluster. */ diff --git a/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/handlers/KeyHandler.java b/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/handlers/KeyHandler.java index d4c5a7995d..8c0b103ca3 100644 --- a/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/handlers/KeyHandler.java +++ b/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/handlers/KeyHandler.java @@ -242,4 +242,49 @@ public Response doProcess(KeyArgs args, InputStream input, } }.handleCall(volume, bucket, keys, req, headers, info, null); } + + /** + * Renames an existing key within a bucket. + * + * @param volume Storage Volume Name + * @param bucket Name of the bucket + * @param key Name of the Object + * @param toKeyName New name of the Object + * @param req http Request + * @param info UriInfo + * @param headers HttpHeaders + * @return Response + * @throws OzoneException + */ + @Override + public Response renameKey(String volume, String bucket, String key, + String toKeyName, Request req, UriInfo info, HttpHeaders headers) + throws OzoneException { + return new KeyProcessTemplate() { + /** + * Abstract function that gets implemented in the KeyHandler functions. + * This function will just deal with the core file system related logic + * and will rely on handleCall function for repetitive error checks + * + * @param args - parsed bucket args, name, userName, ACLs etc + * @param input - The body as an Input Stream + * @param request - Http request + * @param headers - Parsed http Headers. + * @param info - UriInfo + * + * @return Response + * + * @throws IOException - From the file system operations + */ + @Override + public Response doProcess(KeyArgs args, InputStream input, + Request request, HttpHeaders headers, + UriInfo info) + throws IOException, OzoneException, NoSuchAlgorithmException { + StorageHandler fs = StorageHandlerBuilder.getStorageHandler(); + fs.renameKey(args, toKeyName); + return OzoneRestUtils.getResponse(args, HTTP_OK, ""); + } + }.handleCall(volume, bucket, key, req, headers, info, null); + } } diff --git a/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/interfaces/Keys.java b/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/interfaces/Keys.java index f9255f2d54..1ce81c244b 100644 --- a/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/interfaces/Keys.java +++ b/hadoop-ozone/objectstore-service/src/main/java/org/apache/hadoop/ozone/web/interfaces/Keys.java @@ -29,6 +29,7 @@ import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.PUT; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; @@ -142,5 +143,35 @@ Response deleteKey(@PathParam("volume") String volume, @PathParam("bucket") String bucket, @PathParam("keys") String keys, @Context Request req, @Context UriInfo info, @Context HttpHeaders headers) throws OzoneException; + + /** + * Renames an existing key within a bucket. + * + * @param volume Storage Volume Name + * @param bucket Name of the bucket + * @param keys Name of the Object + * @param req http Request + * @param headers HttpHeaders + * + * @return Response + * + * @throws OzoneException + */ + @POST + @ApiOperation("Renames an existing key within a bucket") + @ApiImplicitParams({ + @ApiImplicitParam(name = "x-ozone-version", example = "v1", required = + true, paramType = "header"), + @ApiImplicitParam(name = "x-ozone-user", example = "user", required = + true, paramType = "header"), + @ApiImplicitParam(name = "Date", example = "Date: Mon, 26 Jun 2017 " + + "04:23:30 GMT", required = true, paramType = "header"), + @ApiImplicitParam(name = "Authorization", example = "OZONE", required = + true, paramType = "header")}) + Response renameKey(@PathParam("volume") String volume, + @PathParam("bucket") String bucket, @PathParam("keys") String keys, + @QueryParam(Header.OZONE_RENAME_TO_KEY_PARAM_NAME) String toKeyName, + @Context Request req, @Context UriInfo info, @Context HttpHeaders headers) + throws OzoneException; }