HDDS-444. Add rest service to the s3gateway. Contributed by Elek Marton.

This commit is contained in:
Bharat Viswanadham 2018-09-24 21:56:36 -07:00
parent 29dad7d258
commit 9c3fbbc4f6
48 changed files with 2041 additions and 42 deletions

View File

@ -82,7 +82,7 @@ public class GenericCli implements Callable<Void>, GenericParentCommand {
if (configurationOverrides != null) { if (configurationOverrides != null) {
for (Entry<String, String> entry : configurationOverrides.entrySet()) { for (Entry<String, String> entry : configurationOverrides.entrySet()) {
ozoneConf ozoneConf
.set(entry.getKey(), configurationOverrides.get(entry.getValue())); .set(entry.getKey(), entry.getValue());
} }
} }
return ozoneConf; return ozoneConf;

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.ozone.client; package org.apache.hadoop.ozone.client;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdds.scm.client.HddsClientUtils; import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
@ -56,6 +57,11 @@ public class ObjectStore {
this.listCacheSize = HddsClientUtils.getListCacheSize(conf); this.listCacheSize = HddsClientUtils.getListCacheSize(conf);
} }
@VisibleForTesting
protected ObjectStore() {
proxy = null;
}
/** /**
* Creates the volume with default values. * Creates the volume with default values.
* @param volumeName Name of the volume to be created. * @param volumeName Name of the volume to be created.
@ -96,7 +102,7 @@ public class ObjectStore {
* @param volumePrefix Volume prefix to match * @param volumePrefix Volume prefix to match
* @return {@code Iterator<OzoneVolume>} * @return {@code Iterator<OzoneVolume>}
*/ */
public Iterator<OzoneVolume> listVolumes(String volumePrefix) public Iterator<? extends OzoneVolume> listVolumes(String volumePrefix)
throws IOException { throws IOException {
return listVolumes(volumePrefix, null); return listVolumes(volumePrefix, null);
} }
@ -111,7 +117,7 @@ public class ObjectStore {
* @param prevVolume Volumes will be listed after this volume name * @param prevVolume Volumes will be listed after this volume name
* @return {@code Iterator<OzoneVolume>} * @return {@code Iterator<OzoneVolume>}
*/ */
public Iterator<OzoneVolume> listVolumes(String volumePrefix, public Iterator<? extends OzoneVolume> listVolumes(String volumePrefix,
String prevVolume) throws IOException { String prevVolume) throws IOException {
return new VolumeIterator(null, volumePrefix, prevVolume); return new VolumeIterator(null, volumePrefix, prevVolume);
} }
@ -127,7 +133,7 @@ public class ObjectStore {
* @param prevVolume Volumes will be listed after this volume name * @param prevVolume Volumes will be listed after this volume name
* @return {@code Iterator<OzoneVolume>} * @return {@code Iterator<OzoneVolume>}
*/ */
public Iterator<OzoneVolume> listVolumesByUser(String user, public Iterator<? extends OzoneVolume> listVolumesByUser(String user,
String volumePrefix, String prevVolume) String volumePrefix, String prevVolume)
throws IOException { throws IOException {
if(Strings.isNullOrEmpty(user)) { if(Strings.isNullOrEmpty(user)) {

View File

@ -18,7 +18,7 @@
package org.apache.hadoop.ozone.client; package org.apache.hadoop.ozone.client;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.StorageType; import org.apache.hadoop.fs.StorageType;
@ -121,6 +121,23 @@ public class OzoneBucket {
OzoneConfigKeys.OZONE_REPLICATION_TYPE_DEFAULT)); OzoneConfigKeys.OZONE_REPLICATION_TYPE_DEFAULT));
} }
@VisibleForTesting
OzoneBucket(String volumeName, String name,
ReplicationFactor defaultReplication,
ReplicationType defaultReplicationType,
List<OzoneAcl> acls, StorageType storageType, Boolean versioning,
long creationTime) {
this.proxy = null;
this.volumeName = volumeName;
this.name = name;
this.defaultReplication = defaultReplication;
this.defaultReplicationType = defaultReplicationType;
this.acls = acls;
this.storageType = storageType;
this.versioning = versioning;
this.creationTime = creationTime;
}
/** /**
* Returns Volume Name. * Returns Volume Name.
* *
@ -273,7 +290,7 @@ public class OzoneBucket {
* @param keyPrefix Bucket prefix to match * @param keyPrefix Bucket prefix to match
* @return {@code Iterator<OzoneKey>} * @return {@code Iterator<OzoneKey>}
*/ */
public Iterator<OzoneKey> listKeys(String keyPrefix) { public Iterator<? extends OzoneKey> listKeys(String keyPrefix) {
return listKeys(keyPrefix, null); return listKeys(keyPrefix, null);
} }
@ -287,7 +304,8 @@ public class OzoneBucket {
* @param prevKey Keys will be listed after this key name * @param prevKey Keys will be listed after this key name
* @return {@code Iterator<OzoneKey>} * @return {@code Iterator<OzoneKey>}
*/ */
public Iterator<OzoneKey> listKeys(String keyPrefix, String prevKey) { public Iterator<? extends OzoneKey> listKeys(String keyPrefix,
String prevKey) {
return new KeyIterator(keyPrefix, prevKey); return new KeyIterator(keyPrefix, prevKey);
} }

View File

@ -24,6 +24,8 @@ import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import com.google.common.annotations.VisibleForTesting;
/** /**
* OzoneClient connects to Ozone Cluster and * OzoneClient connects to Ozone Cluster and
* perform basic operations. * perform basic operations.
@ -84,6 +86,11 @@ public class OzoneClient implements Closeable {
this.objectStore = new ObjectStore(conf, this.proxy); this.objectStore = new ObjectStore(conf, this.proxy);
} }
@VisibleForTesting
protected OzoneClient(ObjectStore objectStore) {
this.objectStore = objectStore;
this.proxy = null;
}
/** /**
* Returns the object store associated with the Ozone Cluster. * Returns the object store associated with the Ozone Cluster.
* @return ObjectStore * @return ObjectStore

View File

@ -18,17 +18,19 @@
package org.apache.hadoop.ozone.client; package org.apache.hadoop.ozone.client;
import com.google.common.base.Preconditions; import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdds.client.OzoneQuota; import org.apache.hadoop.hdds.client.OzoneQuota;
import org.apache.hadoop.hdds.scm.client.HddsClientUtils; import org.apache.hadoop.hdds.scm.client.HddsClientUtils;
import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.client.protocol.ClientProtocol; import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
import java.io.IOException; import com.google.common.annotations.VisibleForTesting;
import java.util.Iterator; import com.google.common.base.Preconditions;
import java.util.List;
import java.util.NoSuchElementException;
/** /**
* A class that encapsulates OzoneVolume. * A class that encapsulates OzoneVolume.
@ -94,6 +96,19 @@ public class OzoneVolume {
this.listCacheSize = HddsClientUtils.getListCacheSize(conf); this.listCacheSize = HddsClientUtils.getListCacheSize(conf);
} }
@VisibleForTesting
protected OzoneVolume(String name, String admin, String owner,
long quotaInBytes,
long creationTime, List<OzoneAcl> acls) {
this.proxy = null;
this.name = name;
this.admin = admin;
this.owner = owner;
this.quotaInBytes = quotaInBytes;
this.creationTime = creationTime;
this.acls = acls;
}
/** /**
* Returns Volume name. * Returns Volume name.
* *
@ -208,12 +223,13 @@ public class OzoneVolume {
* @param bucketPrefix Bucket prefix to match * @param bucketPrefix Bucket prefix to match
* @return {@code Iterator<OzoneBucket>} * @return {@code Iterator<OzoneBucket>}
*/ */
public Iterator<OzoneBucket> listBuckets(String bucketPrefix) { public Iterator<? extends OzoneBucket> listBuckets(String bucketPrefix) {
return listBuckets(bucketPrefix, null); return listBuckets(bucketPrefix, null);
} }
/** /**
* Returns Iterator to iterate over all buckets after prevBucket in the volume. * Returns Iterator to iterate over all buckets after prevBucket in the
* volume.
* If prevBucket is null it iterates from the first bucket in the volume. * If prevBucket is null it iterates from the first bucket in the volume.
* The result can be restricted using bucket prefix, will return all * The result can be restricted using bucket prefix, will return all
* buckets if bucket prefix is null. * buckets if bucket prefix is null.
@ -222,7 +238,7 @@ public class OzoneVolume {
* @param prevBucket Buckets are listed after this bucket * @param prevBucket Buckets are listed after this bucket
* @return {@code Iterator<OzoneBucket>} * @return {@code Iterator<OzoneBucket>}
*/ */
public Iterator<OzoneBucket> listBuckets(String bucketPrefix, public Iterator<? extends OzoneBucket> listBuckets(String bucketPrefix,
String prevBucket) { String prevBucket) {
return new BucketIterator(bucketPrefix, prevBucket); return new BucketIterator(bucketPrefix, prevBucket);
} }

View File

@ -51,6 +51,8 @@ services:
image: apache/hadoop-runner image: apache/hadoop-runner
volumes: volumes:
- ../..:/opt/hadoop - ../..:/opt/hadoop
ports:
- 9878:9878
env_file: env_file:
- ./docker-config - ./docker-config
command: ["ozone","s3g"] command: ["ozone","s3g"]

View File

@ -701,26 +701,29 @@ public class TestOzoneRpcClient {
store.createVolume( store.createVolume(
volBaseNameB + i + "-" + RandomStringUtils.randomNumeric(5)); volBaseNameB + i + "-" + RandomStringUtils.randomNumeric(5));
} }
Iterator<OzoneVolume> volIterator = store.listVolumes(volBase); Iterator<? extends OzoneVolume> volIterator = store.listVolumes(volBase);
int totalVolumeCount = 0; int totalVolumeCount = 0;
while(volIterator.hasNext()) { while(volIterator.hasNext()) {
volIterator.next(); volIterator.next();
totalVolumeCount++; totalVolumeCount++;
} }
Assert.assertEquals(20, totalVolumeCount); Assert.assertEquals(20, totalVolumeCount);
Iterator<OzoneVolume> volAIterator = store.listVolumes(volBaseNameA); Iterator<? extends OzoneVolume> volAIterator = store.listVolumes(
volBaseNameA);
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
Assert.assertTrue(volAIterator.next().getName() Assert.assertTrue(volAIterator.next().getName()
.startsWith(volBaseNameA + i + "-")); .startsWith(volBaseNameA + i + "-"));
} }
Assert.assertFalse(volAIterator.hasNext()); Assert.assertFalse(volAIterator.hasNext());
Iterator<OzoneVolume> volBIterator = store.listVolumes(volBaseNameB); Iterator<? extends OzoneVolume> volBIterator = store.listVolumes(
volBaseNameB);
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
Assert.assertTrue(volBIterator.next().getName() Assert.assertTrue(volBIterator.next().getName()
.startsWith(volBaseNameB + i + "-")); .startsWith(volBaseNameB + i + "-"));
} }
Assert.assertFalse(volBIterator.hasNext()); Assert.assertFalse(volBIterator.hasNext());
Iterator<OzoneVolume> iter = store.listVolumes(volBaseNameA + "1-"); Iterator<? extends OzoneVolume> iter = store.listVolumes(volBaseNameA +
"1-");
Assert.assertTrue(iter.next().getName().startsWith(volBaseNameA + "1-")); Assert.assertTrue(iter.next().getName().startsWith(volBaseNameA + "1-"));
Assert.assertFalse(iter.hasNext()); Assert.assertFalse(iter.hasNext());
} }
@ -751,7 +754,7 @@ public class TestOzoneRpcClient {
volB.createBucket( volB.createBucket(
bucketBaseNameB + i + "-" + RandomStringUtils.randomNumeric(5)); bucketBaseNameB + i + "-" + RandomStringUtils.randomNumeric(5));
} }
Iterator<OzoneBucket> volABucketIter = Iterator<? extends OzoneBucket> volABucketIter =
volA.listBuckets("bucket-"); volA.listBuckets("bucket-");
int volABucketCount = 0; int volABucketCount = 0;
while(volABucketIter.hasNext()) { while(volABucketIter.hasNext()) {
@ -759,7 +762,7 @@ public class TestOzoneRpcClient {
volABucketCount++; volABucketCount++;
} }
Assert.assertEquals(20, volABucketCount); Assert.assertEquals(20, volABucketCount);
Iterator<OzoneBucket> volBBucketIter = Iterator<? extends OzoneBucket> volBBucketIter =
volA.listBuckets("bucket-"); volA.listBuckets("bucket-");
int volBBucketCount = 0; int volBBucketCount = 0;
while(volBBucketIter.hasNext()) { while(volBBucketIter.hasNext()) {
@ -768,7 +771,7 @@ public class TestOzoneRpcClient {
} }
Assert.assertEquals(20, volBBucketCount); Assert.assertEquals(20, volBBucketCount);
Iterator<OzoneBucket> volABucketAIter = Iterator<? extends OzoneBucket> volABucketAIter =
volA.listBuckets("bucket-a-"); volA.listBuckets("bucket-a-");
int volABucketACount = 0; int volABucketACount = 0;
while(volABucketAIter.hasNext()) { while(volABucketAIter.hasNext()) {
@ -776,7 +779,7 @@ public class TestOzoneRpcClient {
volABucketACount++; volABucketACount++;
} }
Assert.assertEquals(10, volABucketACount); Assert.assertEquals(10, volABucketACount);
Iterator<OzoneBucket> volBBucketBIter = Iterator<? extends OzoneBucket> volBBucketBIter =
volA.listBuckets("bucket-b-"); volA.listBuckets("bucket-b-");
int volBBucketBCount = 0; int volBBucketBCount = 0;
while(volBBucketBIter.hasNext()) { while(volBBucketBIter.hasNext()) {
@ -784,13 +787,15 @@ public class TestOzoneRpcClient {
volBBucketBCount++; volBBucketBCount++;
} }
Assert.assertEquals(10, volBBucketBCount); Assert.assertEquals(10, volBBucketBCount);
Iterator<OzoneBucket> volABucketBIter = volA.listBuckets("bucket-b-"); Iterator<? extends OzoneBucket> volABucketBIter = volA.listBuckets(
"bucket-b-");
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
Assert.assertTrue(volABucketBIter.next().getName() Assert.assertTrue(volABucketBIter.next().getName()
.startsWith(bucketBaseNameB + i + "-")); .startsWith(bucketBaseNameB + i + "-"));
} }
Assert.assertFalse(volABucketBIter.hasNext()); Assert.assertFalse(volABucketBIter.hasNext());
Iterator<OzoneBucket> volBBucketAIter = volB.listBuckets("bucket-a-"); Iterator<? extends OzoneBucket> volBBucketAIter = volB.listBuckets(
"bucket-a-");
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
Assert.assertTrue(volBBucketAIter.next().getName() Assert.assertTrue(volBBucketAIter.next().getName()
.startsWith(bucketBaseNameA + i + "-")); .startsWith(bucketBaseNameA + i + "-"));
@ -805,7 +810,7 @@ public class TestOzoneRpcClient {
String volume = "vol-" + RandomStringUtils.randomNumeric(5); String volume = "vol-" + RandomStringUtils.randomNumeric(5);
store.createVolume(volume); store.createVolume(volume);
OzoneVolume vol = store.getVolume(volume); OzoneVolume vol = store.getVolume(volume);
Iterator<OzoneBucket> buckets = vol.listBuckets(""); Iterator<? extends OzoneBucket> buckets = vol.listBuckets("");
while(buckets.hasNext()) { while(buckets.hasNext()) {
Assert.fail(); Assert.fail();
} }
@ -889,7 +894,7 @@ public class TestOzoneRpcClient {
four.write(value); four.write(value);
four.close(); four.close();
} }
Iterator<OzoneKey> volABucketAIter = Iterator<? extends OzoneKey> volABucketAIter =
volAbucketA.listKeys("key-"); volAbucketA.listKeys("key-");
int volABucketAKeyCount = 0; int volABucketAKeyCount = 0;
while(volABucketAIter.hasNext()) { while(volABucketAIter.hasNext()) {
@ -897,7 +902,7 @@ public class TestOzoneRpcClient {
volABucketAKeyCount++; volABucketAKeyCount++;
} }
Assert.assertEquals(20, volABucketAKeyCount); Assert.assertEquals(20, volABucketAKeyCount);
Iterator<OzoneKey> volABucketBIter = Iterator<? extends OzoneKey> volABucketBIter =
volAbucketB.listKeys("key-"); volAbucketB.listKeys("key-");
int volABucketBKeyCount = 0; int volABucketBKeyCount = 0;
while(volABucketBIter.hasNext()) { while(volABucketBIter.hasNext()) {
@ -905,7 +910,7 @@ public class TestOzoneRpcClient {
volABucketBKeyCount++; volABucketBKeyCount++;
} }
Assert.assertEquals(20, volABucketBKeyCount); Assert.assertEquals(20, volABucketBKeyCount);
Iterator<OzoneKey> volBBucketAIter = Iterator<? extends OzoneKey> volBBucketAIter =
volBbucketA.listKeys("key-"); volBbucketA.listKeys("key-");
int volBBucketAKeyCount = 0; int volBBucketAKeyCount = 0;
while(volBBucketAIter.hasNext()) { while(volBBucketAIter.hasNext()) {
@ -913,7 +918,7 @@ public class TestOzoneRpcClient {
volBBucketAKeyCount++; volBBucketAKeyCount++;
} }
Assert.assertEquals(20, volBBucketAKeyCount); Assert.assertEquals(20, volBBucketAKeyCount);
Iterator<OzoneKey> volBBucketBIter = Iterator<? extends OzoneKey> volBBucketBIter =
volBbucketB.listKeys("key-"); volBbucketB.listKeys("key-");
int volBBucketBKeyCount = 0; int volBBucketBKeyCount = 0;
while(volBBucketBIter.hasNext()) { while(volBBucketBIter.hasNext()) {
@ -921,7 +926,7 @@ public class TestOzoneRpcClient {
volBBucketBKeyCount++; volBBucketBKeyCount++;
} }
Assert.assertEquals(20, volBBucketBKeyCount); Assert.assertEquals(20, volBBucketBKeyCount);
Iterator<OzoneKey> volABucketAKeyAIter = Iterator<? extends OzoneKey> volABucketAKeyAIter =
volAbucketA.listKeys("key-a-"); volAbucketA.listKeys("key-a-");
int volABucketAKeyACount = 0; int volABucketAKeyACount = 0;
while(volABucketAKeyAIter.hasNext()) { while(volABucketAKeyAIter.hasNext()) {
@ -929,7 +934,7 @@ public class TestOzoneRpcClient {
volABucketAKeyACount++; volABucketAKeyACount++;
} }
Assert.assertEquals(10, volABucketAKeyACount); Assert.assertEquals(10, volABucketAKeyACount);
Iterator<OzoneKey> volABucketAKeyBIter = Iterator<? extends OzoneKey> volABucketAKeyBIter =
volAbucketA.listKeys("key-b-"); volAbucketA.listKeys("key-b-");
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
Assert.assertTrue(volABucketAKeyBIter.next().getName() Assert.assertTrue(volABucketAKeyBIter.next().getName()
@ -947,7 +952,7 @@ public class TestOzoneRpcClient {
OzoneVolume vol = store.getVolume(volume); OzoneVolume vol = store.getVolume(volume);
vol.createBucket(bucket); vol.createBucket(bucket);
OzoneBucket buc = vol.getBucket(bucket); OzoneBucket buc = vol.getBucket(bucket);
Iterator<OzoneKey> keys = buc.listKeys(""); Iterator<? extends OzoneKey> keys = buc.listKeys("");
while(keys.hasNext()) { while(keys.hasNext()) {
Assert.fail(); Assert.fail();
} }

View File

@ -305,7 +305,7 @@ public class TestBuckets {
.build(); .build();
vol.createBucket(bucketName, bucketArgs); vol.createBucket(bucketName, bucketArgs);
} }
Iterator<OzoneBucket> bucketIterator = vol.listBuckets(null); Iterator<? extends OzoneBucket> bucketIterator = vol.listBuckets(null);
int count = 0; int count = 0;
while (bucketIterator.hasNext()) { while (bucketIterator.hasNext()) {
@ -324,7 +324,7 @@ public class TestBuckets {
client.close(); client.close();
} }
private static int getSize(Iterator<OzoneBucket> bucketIterator) { private static int getSize(Iterator<? extends OzoneBucket> bucketIterator) {
int count = 0; int count = 0;
while (bucketIterator.hasNext()) { while (bucketIterator.hasNext()) {
count++; count++;

View File

@ -88,7 +88,8 @@ public class ListBucketHandler extends Handler {
OzoneVolume vol = client.getObjectStore().getVolume(volumeName); OzoneVolume vol = client.getObjectStore().getVolume(volumeName);
Iterator<OzoneBucket> bucketIterator = vol.listBuckets(prefix, startBucket); Iterator<? extends OzoneBucket> bucketIterator =
vol.listBuckets(prefix, startBucket);
List<BucketInfo> bucketList = new ArrayList<>(); List<BucketInfo> bucketList = new ArrayList<>();
while (maxBuckets > 0 && bucketIterator.hasNext()) { while (maxBuckets > 0 && bucketIterator.hasNext()) {
BucketInfo bucketInfo = BucketInfo bucketInfo =

View File

@ -91,7 +91,8 @@ public class ListKeyHandler extends Handler {
OzoneVolume vol = client.getObjectStore().getVolume(volumeName); OzoneVolume vol = client.getObjectStore().getVolume(volumeName);
OzoneBucket bucket = vol.getBucket(bucketName); OzoneBucket bucket = vol.getBucket(bucketName);
Iterator<OzoneKey> keyIterator = bucket.listKeys(prefix, startKey); Iterator<? extends OzoneKey> keyIterator = bucket.listKeys(prefix,
startKey);
List<KeyInfo> keyInfos = new ArrayList<>(); List<KeyInfo> keyInfos = new ArrayList<>();
while (maxKeys > 0 && keyIterator.hasNext()) { while (maxKeys > 0 && keyIterator.hasNext()) {

View File

@ -89,7 +89,7 @@ public class ListVolumeHandler extends Handler {
"the length should be a positive number"); "the length should be a positive number");
} }
Iterator<OzoneVolume> volumeIterator; Iterator<? extends OzoneVolume> volumeIterator;
if(userName != null) { if(userName != null) {
volumeIterator = client.getObjectStore() volumeIterator = client.getObjectStore()
.listVolumesByUser(userName, prefix, startVolume); .listVolumesByUser(userName, prefix, startVolume);

View File

@ -638,7 +638,7 @@ public class OzoneFileSystem extends FileSystem {
private final Path path; private final Path path;
private final FileStatus status; private final FileStatus status;
private String pathKey; private String pathKey;
private Iterator<OzoneKey> keyIterator; private Iterator<? extends OzoneKey> keyIterator;
OzoneListingIterator(Path path) OzoneListingIterator(Path path)
throws IOException { throws IOException {

View File

@ -183,6 +183,17 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
/**
* This class adds common header responses for all the requests.
*/
@Provider
public class CommonHeadersContainerResponseFilter implements
ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext containerRequestContext,
ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add("Server", "Ozone");
}
}

View File

@ -0,0 +1,76 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import javax.inject.Inject;
import javax.ws.rs.NotFoundException;
import java.io.IOException;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.OzoneClient;
import org.apache.hadoop.ozone.client.OzoneVolume;
import com.google.common.annotations.VisibleForTesting;
/**
* Basic helpers for all the REST endpoints.
*/
public class EndpointBase {
@Inject
private OzoneClient client;
protected OzoneBucket getBucket(String volumeName, String bucketName)
throws IOException {
return getVolume(volumeName).getBucket(bucketName);
}
protected OzoneBucket getBucket(OzoneVolume volume, String bucketName)
throws IOException {
OzoneBucket bucket = null;
try {
bucket = volume.getBucket(bucketName);
} catch (Exception ex) {
if (ex.getMessage().contains("NOT_FOUND")) {
throw new NotFoundException("Bucket" + bucketName + " is not found");
} else {
throw ex;
}
}
return bucket;
}
protected OzoneVolume getVolume(String volumeName) throws IOException {
OzoneVolume volume = null;
try {
volume = client.getObjectStore().getVolume(volumeName);
} catch (Exception ex) {
if (ex.getMessage().contains("NOT_FOUND")) {
throw new NotFoundException("Volume " + volumeName + " is not found");
} else {
throw ex;
}
}
return volume;
}
@VisibleForTesting
public void setClient(OzoneClient ozoneClient) {
this.client = ozoneClient;
}
}

View File

@ -17,8 +17,11 @@
*/ */
package org.apache.hadoop.ozone.s3; package org.apache.hadoop.ozone.s3;
import java.io.IOException;
import org.apache.hadoop.hdds.cli.GenericCli; import org.apache.hadoop.hdds.cli.GenericCli;
import org.apache.hadoop.hdds.cli.HddsVersionProvider; import org.apache.hadoop.hdds.cli.HddsVersionProvider;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -35,21 +38,29 @@ public class Gateway extends GenericCli {
private static final Logger LOG = LoggerFactory.getLogger(Gateway.class); private static final Logger LOG = LoggerFactory.getLogger(Gateway.class);
private S3GatewayHttpServer httpServer;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
new Gateway().run(args); new Gateway().run(args);
} }
@Override @Override
public Void call() throws Exception { public Void call() throws Exception {
OzoneConfiguration ozoneConfiguration = createOzoneConfiguration();
OzoneConfigurationHolder.setConfiguration(ozoneConfiguration);
httpServer = new S3GatewayHttpServer(ozoneConfiguration, "s3gateway");
start(); start();
return null; return null;
} }
public void start() { public void start() throws IOException {
LOG.info("Starting Ozone S3 gateway"); LOG.info("Starting Ozone S3 gateway");
httpServer.start();
} }
public void stop() { public void stop() throws Exception {
LOG.info("Stoping Ozone S3 gateway"); LOG.info("Stopping Ozone S3 gateway");
httpServer.stop();
} }
} }

View File

@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import org.glassfish.jersey.server.ResourceConfig;
/**
* JaxRS resource definition.
*/
public class GatewayApplication extends ResourceConfig {
public GatewayApplication() {
packages("org.apache.hadoop.ozone.s3");
}
}

View File

@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import java.io.IOException;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.client.OzoneClient;
import org.apache.hadoop.ozone.client.OzoneClientFactory;
/**
* This class creates the OzoneClient for the Rest endpoints.
*/
@ApplicationScoped
public class OzoneClientProducer {
private OzoneConfiguration ozoneConfiguration;
@Inject
public OzoneClientProducer(
OzoneConfiguration ozoneConfiguration) {
this.ozoneConfiguration = ozoneConfiguration;
}
@Produces
public OzoneClient createClient() throws IOException {
return OzoneClientFactory.getClient(ozoneConfiguration);
}
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import javax.enterprise.inject.Produces;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
/**
* Ozone Configuration factory.
* <p>
* As the OzoneConfiguration is created by the CLI application here we inject
* it via a singleton instance to the Jax-RS/CDI instances.
*/
public class OzoneConfigurationHolder {
private static OzoneConfiguration configuration;
@Produces
public OzoneConfiguration configuration() {
return configuration;
}
public static void setConfiguration(
OzoneConfiguration conf) {
OzoneConfigurationHolder.configuration = conf;
}
}

View File

@ -0,0 +1,54 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
/**
* This class contains constants for configuration keys used in S3G.
*/
@InterfaceAudience.Public
@InterfaceStability.Unstable
public final class S3GatewayConfigKeys {
public static final String OZONE_S3G_HTTP_ENABLED_KEY =
"ozone.s3g.http.enabled";
public static final String OZONE_S3G_HTTP_BIND_HOST_KEY =
"ozone.s3g.http-bind-host";
public static final String OZONE_S3G_HTTPS_BIND_HOST_KEY =
"ozone.s3g.https-bind-host";
public static final String OZONE_S3G_HTTP_ADDRESS_KEY =
"ozone.s3g.http-address";
public static final String OZONE_S3G_HTTPS_ADDRESS_KEY =
"ozone.s3g.https-address";
public static final String OZONE_S3G_KEYTAB_FILE =
"ozone.s3g.keytab.file";
public static final String OZONE_S3G_HTTP_BIND_HOST_DEFAULT = "0.0.0.0";
public static final int OZONE_S3G_HTTP_BIND_PORT_DEFAULT = 9878;
public static final int OZONE_S3G_HTTPS_BIND_PORT_DEFAULT = 9879;
public static final String OZONE_S3G_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL =
"ozone.s3g.authentication.kerberos.principal";
/**
* Never constructed.
*/
private S3GatewayConfigKeys() {
}
}

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdds.server.BaseHttpServer;
/**
* S3 Gateway specific configuration keys.
*/
public class S3GatewayHttpServer extends BaseHttpServer {
public S3GatewayHttpServer(Configuration conf,
String name) throws IOException {
super(conf, name);
}
@Override
protected String getHttpAddressKey() {
return S3GatewayConfigKeys.OZONE_S3G_HTTP_ADDRESS_KEY;
}
@Override
protected String getHttpBindHostKey() {
return S3GatewayConfigKeys.OZONE_S3G_HTTP_BIND_HOST_KEY;
}
@Override
protected String getHttpsAddressKey() {
return S3GatewayConfigKeys.OZONE_S3G_HTTPS_ADDRESS_KEY;
}
@Override
protected String getHttpsBindHostKey() {
return S3GatewayConfigKeys.OZONE_S3G_HTTPS_BIND_HOST_KEY;
}
@Override
protected String getBindHostDefault() {
return S3GatewayConfigKeys.OZONE_S3G_HTTP_BIND_HOST_DEFAULT;
}
@Override
protected int getHttpBindPortDefault() {
return S3GatewayConfigKeys.OZONE_S3G_HTTP_BIND_PORT_DEFAULT;
}
@Override
protected int getHttpsBindPortDefault() {
return S3GatewayConfigKeys.OZONE_S3G_HTTPS_BIND_PORT_DEFAULT;
}
@Override
protected String getKeytabFile() {
return S3GatewayConfigKeys.OZONE_S3G_KEYTAB_FILE;
}
@Override
protected String getSpnegoPrincipal() {
return S3GatewayConfigKeys.OZONE_S3G_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL;
}
@Override
protected String getEnabledKey() {
return S3GatewayConfigKeys.OZONE_S3G_HTTP_ENABLED_KEY;
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.bucket;
import javax.ws.rs.DELETE;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import org.apache.hadoop.ozone.s3.EndpointBase;
/**
* Delete a bucket.
*/
@Path("/{volume}/{bucket}")
public class DeleteBucket extends EndpointBase {
@DELETE
@Produces(MediaType.APPLICATION_XML)
public void put(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName) throws IOException {
getVolume(volumeName).deleteBucket(bucketName);
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.bucket;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import org.apache.hadoop.ozone.s3.EndpointBase;
/**
* Create new bucket.
*/
@Path("/{volume}/{bucket}")
public class PutBucket extends EndpointBase {
@PUT
@Produces(MediaType.APPLICATION_XML)
public void put(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName) throws IOException {
getVolume(volumeName).createBucket(bucketName);
}
}

View File

@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Rest endpoint implementation for the bucket specific methods.
*/
@javax.xml.bind.annotation.XmlSchema(
namespace = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", elementFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", prefix = "")})
package org.apache.hadoop.ozone.s3.bucket;

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.commontypes;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
/**
* Directory name ("key prefix") in case of listing.
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class CommonPrefix {
@XmlElement(name = "Prefix")
private String prefix;
public CommonPrefix(String prefix) {
this.prefix = prefix;
}
public CommonPrefix() {
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.commontypes;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
/**
* A converter to convert Instant to standard date string.
*/
public class IsoDateAdapter extends XmlAdapter<String, Instant> {
private DateTimeFormatter iso8861Formatter;
public IsoDateAdapter() {
iso8861Formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mmX")
.withZone(ZoneOffset.UTC);
}
@Override
public Instant unmarshal(String v) throws Exception {
throw new UnsupportedOperationException();
}
@Override
public String marshal(Instant v) throws Exception {
return iso8861Formatter.format(v);
}
}

View File

@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.commontypes;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.time.Instant;
/**
* Metadata object represents one key in the object store.
*/
@XmlAccessorType(XmlAccessType.FIELD)
public class KeyMetadata {
@XmlElement(name = "Key")
private String key; // or the Object Name
@XmlJavaTypeAdapter(IsoDateAdapter.class)
@XmlElement(name = "LastModified")
private Instant lastModified;
@XmlElement(name = "ETag")
private String eTag;
@XmlElement(name = "Size")
private long size;
@XmlElement(name = "StorageClass")
private String storageClass;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Instant getLastModified() {
return lastModified;
}
public void setLastModified(Instant lastModified) {
this.lastModified = lastModified;
}
public String getETag() {
return eTag;
}
public void setETag(String tag) {
this.eTag = tag;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getStorageClass() {
return storageClass;
}
public void setStorageClass(String storageClass) {
this.storageClass = storageClass;
}
}

View File

@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Common classes required for S3 rest API's.
*/
@javax.xml.bind.annotation.XmlSchema(
namespace = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", elementFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", prefix = "")})
package org.apache.hadoop.ozone.s3.commontypes;

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.object;
import javax.ws.rs.DELETE;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.s3.EndpointBase;
/**
* Delete Object rest endpoint.
*/
@Path("/{volume}/{bucket}/{path:.+}")
public class DeleteObject extends EndpointBase {
@DELETE
@Produces(MediaType.APPLICATION_XML)
public Response delete(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName,
@PathParam("path") String keyPath) throws IOException {
OzoneBucket bucket = getBucket(volumeName, bucketName);
bucket.deleteKey(keyPath);
return Response.
ok()
.build();
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.object;
import javax.ws.rs.HEAD;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.OzoneKeyDetails;
import org.apache.hadoop.ozone.s3.EndpointBase;
/**
* Get object info rest endpoint.
*/
@Path("/{volume}/{bucket}/{path:.+}")
public class HeadObject extends EndpointBase {
@HEAD
@Produces(MediaType.APPLICATION_XML)
public Response head(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName,
@PathParam("path") String keyPath,
@HeaderParam("Content-Length") long length,
InputStream body) throws IOException {
OzoneBucket bucket = getBucket(volumeName, bucketName);
OzoneKeyDetails key = bucket.getKey(keyPath);
return Response.
ok()
.header("Content-Length", key.getDataSize())
.build();
}
}

View File

@ -0,0 +1,118 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.object;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.time.Instant;
import java.util.Iterator;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.OzoneKey;
import org.apache.hadoop.ozone.client.OzoneVolume;
import org.apache.hadoop.ozone.s3.EndpointBase;
import org.apache.hadoop.ozone.s3.commontypes.KeyMetadata;
import org.apache.commons.lang3.StringUtils;
/**
* List Object Rest endpoint.
*/
@Path("/{volume}/{bucket}")
public class ListObject extends EndpointBase {
@GET
@Produces(MediaType.APPLICATION_XML)
public ListObjectResponse get(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName,
@QueryParam("delimiter") String delimiter,
@QueryParam("encoding-type") String encodingType,
@QueryParam("marker") String marker,
@DefaultValue("1000") @QueryParam("max-keys") int maxKeys,
@QueryParam("prefix") String prefix,
@Context HttpHeaders hh) throws IOException {
if (delimiter == null) {
delimiter = "/";
}
if (prefix == null) {
prefix = "";
}
OzoneVolume volume = getVolume(volumeName);
OzoneBucket bucket = getBucket(volume, bucketName);
Iterator<? extends OzoneKey> ozoneKeyIterator = bucket.listKeys(prefix);
ListObjectResponse response = new ListObjectResponse();
response.setDelimiter(delimiter);
response.setName(bucketName);
response.setPrefix(prefix);
response.setMarker("");
response.setMaxKeys(1000);
response.setEncodingType("url");
response.setTruncated(false);
String prevDir = null;
while (ozoneKeyIterator.hasNext()) {
OzoneKey next = ozoneKeyIterator.next();
String relativeKeyName = next.getName().substring(prefix.length());
int depth =
StringUtils.countMatches(relativeKeyName, delimiter);
if (prefix.length() > 0 && !prefix.endsWith(delimiter)
&& relativeKeyName.length() > 0) {
response.addPrefix(prefix + "/");
break;
}
if (depth > 0) {
String dirName = relativeKeyName
.substring(0, relativeKeyName.indexOf(delimiter));
if (!dirName.equals(prevDir)) {
response.addPrefix(
prefix + dirName + delimiter);
prevDir = dirName;
}
} else if (relativeKeyName.endsWith(delimiter)) {
response.addPrefix(relativeKeyName);
} else if (relativeKeyName.length() > 0) {
KeyMetadata keyMetadata = new KeyMetadata();
keyMetadata.setKey(next.getName());
keyMetadata.setSize(next.getDataSize());
keyMetadata.setETag("" + next.getModificationTime());
keyMetadata.setStorageClass("STANDARD");
keyMetadata
.setLastModified(Instant.ofEpochMilli(next.getModificationTime()));
response.addKey(keyMetadata);
}
}
return response;
}
}

View File

@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.object;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.ozone.s3.commontypes.CommonPrefix;
import org.apache.hadoop.ozone.s3.commontypes.KeyMetadata;
/**
* Response from the ListObject RPC Call.
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ListBucketResult", namespace = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/")
public class ListObjectResponse {
@XmlElement(name = "Name")
private String name;
@XmlElement(name = "Prefix")
private String prefix;
@XmlElement(name = "Marker")
private String marker;
@XmlElement(name = "MaxKeys")
private int maxKeys;
@XmlElement(name = "Delimiter")
private String delimiter = "/";
@XmlElement(name = "EncodingType")
private String encodingType = "url";
@XmlElement(name = "IsTruncated")
private boolean isTruncated;
@XmlElement(name = "Contents")
private List<KeyMetadata> contents = new ArrayList<>();
@XmlElement(name = "CommonPrefixes")
private List<CommonPrefix> commonPrefixes = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getMarker() {
return marker;
}
public void setMarker(String marker) {
this.marker = marker;
}
public int getMaxKeys() {
return maxKeys;
}
public void setMaxKeys(int maxKeys) {
this.maxKeys = maxKeys;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public String getEncodingType() {
return encodingType;
}
public void setEncodingType(String encodingType) {
this.encodingType = encodingType;
}
public boolean isTruncated() {
return isTruncated;
}
public void setTruncated(boolean truncated) {
isTruncated = truncated;
}
public List<KeyMetadata> getContents() {
return contents;
}
public void setContents(
List<KeyMetadata> contents) {
this.contents = contents;
}
public List<CommonPrefix> getCommonPrefixes() {
return commonPrefixes;
}
public void setCommonPrefixes(
List<CommonPrefix> commonPrefixes) {
this.commonPrefixes = commonPrefixes;
}
public void addKey(KeyMetadata keyMetadata) {
contents.add(keyMetadata);
}
public void addPrefix(String relativeKeyName) {
commonPrefixes.add(new CommonPrefix(relativeKeyName));
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.s3.object;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.io.InputStream;
import org.apache.hadoop.hdds.client.ReplicationFactor;
import org.apache.hadoop.hdds.client.ReplicationType;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.hadoop.ozone.s3.EndpointBase;
/**
* File upload.
*/
@Path("/{volume}/{bucket}/{path:.+}")
public class PutObject extends EndpointBase {
@PUT
@Produces(MediaType.APPLICATION_XML)
public void put(
@PathParam("volume") String volumeName,
@PathParam("bucket") String bucketName,
@PathParam("path") String keyPath,
@HeaderParam("Content-Length") long length,
InputStream body) throws IOException {
OzoneBucket bucket = getBucket(volumeName, bucketName);
OzoneOutputStream output = bucket
.createKey(keyPath, length, ReplicationType.STAND_ALONE,
ReplicationFactor.ONE);
IOUtils.copy(body, output);
output.close();
}
}

View File

@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Rest endpoint implementation for the Object specific methods.
*/
@javax.xml.bind.annotation.XmlSchema(
namespace = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", elementFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
@javax.xml.bind.annotation.XmlNs(namespaceURI = "http://s3.amazonaws"
+ ".com/doc/2006-03-01/", prefix = "")})
package org.apache.hadoop.ozone.s3.object;

View File

@ -0,0 +1,22 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This package contains the top level generic classes of s3 gateway.
*/
package org.apache.hadoop.ozone.s3;

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

View File

@ -0,0 +1,36 @@
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>jaxrs</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.apache.hadoop.ozone.s3.GatewayApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jaxrs</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>
</web-app>

View File

@ -0,0 +1,110 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
/**
* ObjectStore implementation with in-memory state.
*/
public class ObjectStoreStub extends ObjectStore {
public ObjectStoreStub() {
super();
}
private Map<String, OzoneVolumeStub> volumes = new HashMap<>();
@Override
public void createVolume(String volumeName) throws IOException {
createVolume(volumeName,
VolumeArgs.newBuilder()
.setAdmin("root")
.setOwner("root")
.setQuota("" + Integer.MAX_VALUE)
.setAcls(new ArrayList<>()).build());
}
@Override
public void createVolume(String volumeName, VolumeArgs volumeArgs)
throws IOException {
OzoneVolumeStub volume =
new OzoneVolumeStub(volumeName,
volumeArgs.getAdmin(),
volumeArgs.getOwner(),
Long.parseLong(volumeArgs.getQuota()),
System.currentTimeMillis(),
volumeArgs.getAcls());
volumes.put(volumeName, volume);
}
@Override
public OzoneVolume getVolume(String volumeName) throws IOException {
if (volumes.containsKey(volumeName)) {
return volumes.get(volumeName);
} else {
throw new IOException("VOLUME_NOT_FOUND");
}
}
@Override
public Iterator<? extends OzoneVolume> listVolumes(String volumePrefix)
throws IOException {
return volumes.values()
.stream()
.filter(volume -> volume.getName().startsWith(volumePrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public Iterator<? extends OzoneVolume> listVolumes(String volumePrefix,
String prevVolume) throws IOException {
return volumes.values()
.stream()
.filter(volume -> volume.getName().compareTo(prevVolume) > 0)
.filter(volume -> volume.getName().startsWith(volumePrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public Iterator<? extends OzoneVolume> listVolumesByUser(String user,
String volumePrefix, String prevVolume) throws IOException {
return volumes.values()
.stream()
.filter(volume -> volume.getOwner().equals(user))
.filter(volume -> volume.getName().compareTo(prevVolume) < 0)
.filter(volume -> volume.getName().startsWith(volumePrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public void deleteVolume(String volumeName) throws IOException {
volumes.remove(volumeName);
}
}

View File

@ -0,0 +1,143 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.client;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.client.ReplicationFactor;
import org.apache.hadoop.hdds.client.ReplicationType;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.client.io.OzoneInputStream;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
/**
* In-memory ozone bucket for testing.
*/
public class OzoneBucketStub extends OzoneBucket {
private Map<String, OzoneKeyDetails> keyDetails = new HashMap<>();
private Map<String, byte[]> keyContents = new HashMap<>();
/**
* Constructs OzoneBucket instance.
*
* @param volumeName Name of the volume the bucket belongs to.
* @param bucketName Name of the bucket.
* @param acls ACLs associated with the bucket.
* @param storageType StorageType of the bucket.
* @param versioning versioning status of the bucket.
* @param creationTime creation time of the bucket.
*/
public OzoneBucketStub(
String volumeName,
String bucketName,
List<OzoneAcl> acls,
StorageType storageType, Boolean versioning,
long creationTime) {
super(volumeName,
bucketName,
ReplicationFactor.ONE,
ReplicationType.STAND_ALONE,
acls,
storageType,
versioning,
creationTime);
}
@Override
public OzoneOutputStream createKey(String key, long size) throws IOException {
return createKey(key, size, ReplicationType.STAND_ALONE,
ReplicationFactor.ONE);
}
@Override
public OzoneOutputStream createKey(String key, long size,
ReplicationType type, ReplicationFactor factor) throws IOException {
ByteArrayOutputStream byteArrayOutputStream =
new ByteArrayOutputStream((int) size) {
@Override
public void close() throws IOException {
keyContents.put(key, toByteArray());
keyDetails.put(key, new OzoneKeyDetails(
getVolumeName(),
getName(),
key,
size,
System.currentTimeMillis(),
System.currentTimeMillis(),
new ArrayList<>()
));
super.close();
}
};
return new OzoneOutputStream(byteArrayOutputStream);
}
@Override
public OzoneInputStream readKey(String key) throws IOException {
return new OzoneInputStream(new ByteArrayInputStream(keyContents.get(key)));
}
@Override
public OzoneKeyDetails getKey(String key) throws IOException {
return keyDetails.get(key);
}
@Override
public Iterator<? extends OzoneKey> listKeys(String keyPrefix) {
return keyDetails.values()
.stream()
.filter(key -> key.getName().startsWith(keyPrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public Iterator<? extends OzoneKey> listKeys(String keyPrefix,
String prevKey) {
return keyDetails.values()
.stream()
.filter(key -> key.getName().compareTo(prevKey) > 0)
.filter(key -> key.getName().startsWith(keyPrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public void deleteKey(String key) throws IOException {
keyDetails.remove(key);
}
@Override
public void renameKey(String fromKeyName, String toKeyName)
throws IOException {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.client;
import java.io.IOException;
/**
* In-memory OzoneClient for testing.
*/
public class OzoneClientStub extends OzoneClient {
public OzoneClientStub() {
super(new ObjectStoreStub());
}
@Override
public void close() throws IOException {
//NOOP.
}
}

View File

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.client;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.ozone.OzoneAcl;
/**
* Ozone volume with in-memory state for testing.
*/
public class OzoneVolumeStub extends OzoneVolume {
private Map<String, OzoneBucketStub> buckets = new HashMap<>();
public OzoneVolumeStub(String name, String admin, String owner,
long quotaInBytes,
long creationTime, List<OzoneAcl> acls) {
super(name, admin, owner, quotaInBytes, creationTime, acls);
}
@Override
public void createBucket(String bucketName) throws IOException {
createBucket(bucketName, new BucketArgs.Builder()
.setStorageType(StorageType.DEFAULT)
.setVersioning(false)
.build());
}
@Override
public void createBucket(String bucketName, BucketArgs bucketArgs)
throws IOException {
buckets.put(bucketName, new OzoneBucketStub(
getName(),
bucketName,
bucketArgs.getAcls(),
bucketArgs.getStorageType(),
bucketArgs.getVersioning(),
System.currentTimeMillis()));
}
@Override
public OzoneBucket getBucket(String bucketName) throws IOException {
return buckets.get(bucketName);
}
@Override
public Iterator<? extends OzoneBucket> listBuckets(String bucketPrefix) {
return buckets.values()
.stream()
.filter(bucket -> bucket.getName().startsWith(bucketPrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public Iterator<? extends OzoneBucket> listBuckets(String bucketPrefix,
String prevBucket) {
return buckets.values()
.stream()
.filter(bucket -> bucket.getName().compareTo(prevBucket) > 0)
.filter(bucket -> bucket.getName().startsWith(bucketPrefix))
.collect(Collectors.toList())
.iterator();
}
@Override
public void deleteBucket(String bucketName) throws IOException {
buckets.remove(bucketName);
}
}

View File

@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* In-memory OzoneClient implementation to test REST endpoints.
*/
package org.apache.hadoop.ozone.client;

View File

@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.s3.bucket;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.apache.hadoop.ozone.s3.object.ListObjectResponse;
import org.junit.Test;
/**
* Testing JAXB serialization.
*/
public class TestBucketResponse {
@Test
public void serialize() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(ListObjectResponse.class);
context.createMarshaller().marshal(new ListObjectResponse(), System.out);
}
}

View File

@ -0,0 +1,113 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.s3.bucket;
import java.io.IOException;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.OzoneClient;
import org.apache.hadoop.ozone.client.OzoneClientStub;
import org.apache.hadoop.ozone.s3.object.ListObject;
import org.apache.hadoop.ozone.s3.object.ListObjectResponse;
import org.junit.Assert;
import org.junit.Test;
/**
* Testing basic object list browsing.
*/
public class TestGetBucket {
@Test
public void listRoot() throws IOException {
ListObject getBucket = new ListObject();
OzoneClient client = createClientWithKeys("file1", "dir1/file2");
getBucket.setClient(client);
ListObjectResponse getBucketResponse =
getBucket.get("vol1", "b1", "/", null, null, 100, "", null);
Assert.assertEquals(1, getBucketResponse.getCommonPrefixes().size());
Assert.assertEquals("dir1/",
getBucketResponse.getCommonPrefixes().get(0).getPrefix());
Assert.assertEquals(1, getBucketResponse.getContents().size());
Assert.assertEquals("file1",
getBucketResponse.getContents().get(0).getKey());
}
@Test
public void listDir() throws IOException {
ListObject getBucket = new ListObject();
OzoneClient client = createClientWithKeys("dir1/file2", "dir1/dir2/file2");
getBucket.setClient(client);
ListObjectResponse getBucketResponse =
getBucket.get("vol1", "b1", "/", null, null, 100, "dir1", null);
Assert.assertEquals(1, getBucketResponse.getCommonPrefixes().size());
Assert.assertEquals("dir1/",
getBucketResponse.getCommonPrefixes().get(0).getPrefix());
Assert.assertEquals(0, getBucketResponse.getContents().size());
}
@Test
public void listSubDir() throws IOException {
ListObject getBucket = new ListObject();
OzoneClient ozoneClient =
createClientWithKeys("dir1/file2", "dir1/dir2/file2");
getBucket.setClient(ozoneClient);
ListObjectResponse getBucketResponse =
getBucket.get("vol1", "b1", "/", null, null, 100, "dir1/", null);
Assert.assertEquals(1, getBucketResponse.getCommonPrefixes().size());
Assert.assertEquals("dir1/dir2/",
getBucketResponse.getCommonPrefixes().get(0).getPrefix());
Assert.assertEquals(1, getBucketResponse.getContents().size());
Assert.assertEquals("dir1/file2",
getBucketResponse.getContents().get(0).getKey());
}
private OzoneClient createClientWithKeys(String... keys) throws IOException {
OzoneClient client = new OzoneClientStub();
client.getObjectStore().createVolume("vol1");
client.getObjectStore().getVolume("vol1").createBucket("b1");
OzoneBucket bucket =
client.getObjectStore().getVolume("vol1").getBucket("b1");
for (String key : keys) {
bucket.createKey(key, 0).close();
}
return client;
}
}

View File

@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Unit tests for the bucket related rest endpoints.
*/
package org.apache.hadoop.ozone.s3.bucket;

View File

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.hadoop.ozone.s3.object;
import java.io.IOException;
import org.apache.hadoop.ozone.client.OzoneBucket;
import org.apache.hadoop.ozone.client.OzoneClient;
import org.apache.hadoop.ozone.client.OzoneClientStub;
import org.junit.Assert;
import org.junit.Test;
/**
* Test delete object.
*/
public class TestDeleteObject {
@Test
public void delete() throws IOException {
//GIVEN
OzoneClient client = new OzoneClientStub();
client.getObjectStore().createVolume("vol1");
client.getObjectStore().getVolume("vol1").createBucket("b1");
OzoneBucket bucket =
client.getObjectStore().getVolume("vol1").getBucket("b1");
bucket.createKey("key1", 0).close();
DeleteObject rest = new DeleteObject();
rest.setClient(client);
//WHEN
rest.delete("vol1", "b1", "key1");
//THEN
Assert.assertFalse("Bucket Should not contain any key after delete",
bucket.listKeys("").hasNext());
}
}

View File

@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Unit tests for the object related rest endpoints.
*/
package org.apache.hadoop.ozone.s3.object;