HDDS-606. Create delete s3Bucket. Contributed by Bharat Viswanadham.

This commit is contained in:
Bharat Viswanadham 2018-10-12 13:58:53 -07:00
parent 56b18b9df1
commit 8ae8a5004f
15 changed files with 247 additions and 0 deletions

View File

@ -94,6 +94,15 @@ public class ObjectStore {
proxy.createS3Bucket(userName, s3BucketName); proxy.createS3Bucket(userName, s3BucketName);
} }
/**
* Deletes an s3 bucket and removes mapping of Ozone volume/bucket.
* @param bucketName - S3 Bucket Name.
* @throws IOException in case the bucket cannot be deleted.
*/
public void deleteS3Bucket(String bucketName) throws IOException {
proxy.deleteS3Bucket(bucketName);
}
/** /**
* Returns the Ozone Namespace for the S3Bucket. It will return the * Returns the Ozone Namespace for the S3Bucket. It will return the
* OzoneVolume/OzoneBucketName. * OzoneVolume/OzoneBucketName.

View File

@ -330,6 +330,14 @@ public interface ClientProtocol {
*/ */
void createS3Bucket(String userName, String s3BucketName) throws IOException; void createS3Bucket(String userName, String s3BucketName) throws IOException;
/**
* Deletes an s3 bucket and removes mapping of Ozone volume/bucket.
* @param bucketName - S3 Bucket Name.
* @throws IOException in case the bucket cannot be deleted.
*/
void deleteS3Bucket(String bucketName) throws IOException;
/** /**
* Returns the Ozone Namespace for the S3Bucket. It will return the * Returns the Ozone Namespace for the S3Bucket. It will return the
* OzoneVolume/OzoneBucketName. * OzoneVolume/OzoneBucketName.

View File

@ -827,6 +827,13 @@ public class RestClient implements ClientProtocol {
"support this operation."); "support this operation.");
} }
@Override
public void deleteS3Bucket(String s3BucketName)
throws IOException {
throw new UnsupportedOperationException("Ozone REST protocol does not " +
"support this operation.");
}
@Override @Override
public String getOzoneBucketMapping(String s3BucketName) throws IOException { public String getOzoneBucketMapping(String s3BucketName) throws IOException {
throw new UnsupportedOperationException("Ozone REST protocol does not " + throw new UnsupportedOperationException("Ozone REST protocol does not " +

View File

@ -579,6 +579,14 @@ public class RpcClient implements ClientProtocol {
ozoneManagerClient.createS3Bucket(userName, s3BucketName); ozoneManagerClient.createS3Bucket(userName, s3BucketName);
} }
@Override
public void deleteS3Bucket(String s3BucketName)
throws IOException {
Preconditions.checkArgument(Strings.isNotBlank(s3BucketName), "bucket " +
"name cannot be null or empty.");
ozoneManagerClient.deleteS3Bucket(s3BucketName);
}
@Override @Override
public String getOzoneBucketMapping(String s3BucketName) throws IOException { public String getOzoneBucketMapping(String s3BucketName) throws IOException {
Preconditions.checkArgument(Strings.isNotBlank(s3BucketName), "bucket " + Preconditions.checkArgument(Strings.isNotBlank(s3BucketName), "bucket " +

View File

@ -264,6 +264,13 @@ public interface OzoneManagerProtocol {
*/ */
void createS3Bucket(String userName, String s3BucketName) throws IOException; void createS3Bucket(String userName, String s3BucketName) throws IOException;
/**
* Delets an S3 bucket inside Ozone manager and deletes the mapping.
* @param s3BucketName - S3 bucket Name.
* @throws IOException in case the bucket cannot be deleted.
*/
void deleteS3Bucket(String s3BucketName) throws IOException;
/** /**
* Returns the Ozone Namespace for the S3Bucket. It will return the * Returns the Ozone Namespace for the S3Bucket. It will return the
* OzoneVolume/OzoneBucketName. * OzoneVolume/OzoneBucketName.

View File

@ -118,6 +118,10 @@ import org.apache.hadoop.ozone.protocol.proto
.OzoneManagerProtocolProtos.S3BucketRequest; .OzoneManagerProtocolProtos.S3BucketRequest;
import org.apache.hadoop.ozone.protocol.proto import org.apache.hadoop.ozone.protocol.proto
.OzoneManagerProtocolProtos.S3BucketResponse; .OzoneManagerProtocolProtos.S3BucketResponse;
import org.apache.hadoop.ozone.protocol.proto
.OzoneManagerProtocolProtos.S3DeleteBucketRequest;
import org.apache.hadoop.ozone.protocol.proto
.OzoneManagerProtocolProtos.S3DeleteBucketResponse;
import org.apache.hadoop.ozone.protocol.proto import org.apache.hadoop.ozone.protocol.proto
.OzoneManagerProtocolProtos.S3BucketInfoRequest; .OzoneManagerProtocolProtos.S3BucketInfoRequest;
import org.apache.hadoop.ozone.protocol.proto import org.apache.hadoop.ozone.protocol.proto
@ -795,6 +799,25 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
} }
@Override
public void deleteS3Bucket(String s3BucketName) throws IOException {
S3DeleteBucketRequest request = S3DeleteBucketRequest.newBuilder()
.setS3BucketName(s3BucketName)
.build();
final S3DeleteBucketResponse resp;
try {
resp = rpcProxy.deleteS3Bucket(NULL_RPC_CONTROLLER, request);
} catch (ServiceException e) {
throw ProtobufHelper.getRemoteException(e);
}
if(resp.getStatus() != Status.OK) {
throw new IOException("Creating S3 bucket failed, error: "
+ resp.getStatus());
}
}
@Override @Override
public String getOzoneBucketMapping(String s3BucketName) public String getOzoneBucketMapping(String s3BucketName)
throws IOException { throws IOException {

View File

@ -381,6 +381,14 @@ message S3BucketInfoResponse {
optional string ozoneMapping = 2; optional string ozoneMapping = 2;
} }
message S3DeleteBucketRequest {
required string s3bucketName = 1;
}
message S3DeleteBucketResponse {
required Status status = 1;
}
/** /**
The OM service that takes care of Ozone namespace. The OM service that takes care of Ozone namespace.
@ -506,6 +514,9 @@ service OzoneManagerService {
rpc createS3Bucket(S3BucketRequest) rpc createS3Bucket(S3BucketRequest)
returns(S3BucketResponse); returns(S3BucketResponse);
rpc deleteS3Bucket(S3DeleteBucketRequest)
returns(S3DeleteBucketResponse);
/** /**
Gets the Ozone Mapping information for the S3Bucket. Gets the Ozone Mapping information for the S3Bucket.
*/ */

View File

@ -45,6 +45,7 @@ import org.apache.hadoop.ozone.client.rest.OzoneException;
import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys;
import org.apache.hadoop.hdds.scm.protocolPB. import org.apache.hadoop.hdds.scm.protocolPB.
StorageContainerLocationProtocolClientSideTranslatorPB; StorageContainerLocationProtocolClientSideTranslatorPB;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.util.Time; import org.apache.hadoop.util.Time;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
@ -215,6 +216,33 @@ public class TestOzoneRpcClient {
Assert.assertTrue(volume.getCreationTime() >= currentTime); Assert.assertTrue(volume.getCreationTime() >= currentTime);
} }
@Test
public void testDeleteS3Bucket()
throws IOException, OzoneException {
long currentTime = Time.now();
String userName = "ozone1";
String bucketName = UUID.randomUUID().toString();
store.createS3Bucket(userName, bucketName);
String volumeName = store.getOzoneVolumeName(bucketName);
OzoneVolume volume = store.getVolume(volumeName);
OzoneBucket bucket = volume.getBucket(bucketName);
Assert.assertEquals(bucketName, bucket.getName());
Assert.assertTrue(bucket.getCreationTime() >= currentTime);
Assert.assertTrue(volume.getCreationTime() >= currentTime);
store.deleteS3Bucket(bucketName);
thrown.expect(IOException.class);
store.getOzoneVolumeName(bucketName);
}
@Test
public void testDeleteS3NonExistingBucket() {
try {
store.deleteS3Bucket(UUID.randomUUID().toString());
} catch (IOException ex) {
GenericTestUtils.assertExceptionContains("NOT_FOUND", ex);
}
}
@Test @Test
public void testCreateS3BucketMapping() public void testCreateS3BucketMapping()
throws IOException, OzoneException { throws IOException, OzoneException {

View File

@ -1140,6 +1140,15 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
s3BucketManager.createS3Bucket(userName, s3BucketName); s3BucketManager.createS3Bucket(userName, s3BucketName);
} }
@Override
/**
* {@inheritDoc}
*/
public void deleteS3Bucket(String s3BucketName)
throws IOException {
s3BucketManager.deleteS3Bucket(s3BucketName);
}
@Override @Override
/** /**
* {@inheritDoc} * {@inheritDoc}

View File

@ -33,6 +33,13 @@ public interface S3BucketManager {
*/ */
void createS3Bucket(String userName, String bucketName) throws IOException; void createS3Bucket(String userName, String bucketName) throws IOException;
/**
* Deletes an s3 bucket and removes mapping of Ozone volume/bucket.
* @param bucketName - S3 Bucket Name.
* @throws IOException in case the bucket cannot be deleted.
*/
void deleteS3Bucket(String bucketName) throws IOException;
/** /**
* Returns the Ozone volume/bucket where the S3 Bucket points to. * Returns the Ozone volume/bucket where the S3 Bucket points to.
* @param s3BucketName - S3 Bucket Name * @param s3BucketName - S3 Bucket Name

View File

@ -127,6 +127,30 @@ public class S3BucketManagerImpl implements S3BucketManager {
} }
} }
@Override
public void deleteS3Bucket(String bucketName) throws IOException {
Preconditions.checkArgument(
Strings.isNotBlank(bucketName), "Bucket name cannot be null or empty");
omMetadataManager.getLock().acquireS3Lock(bucketName);
try {
byte[] bucket = bucketName.getBytes(StandardCharsets.UTF_8);
byte[] map = omMetadataManager.getS3Table().get(bucket);
if (map == null) {
throw new OMException("No such S3 bucket. " + bucketName,
OMException.ResultCodes.S3_BUCKET_NOT_FOUND);
}
bucketManager.deleteBucket(getOzoneVolumeName(bucketName), bucketName);
omMetadataManager.getS3Table().delete(bucket);
} catch(IOException ex) {
throw ex;
} finally {
omMetadataManager.getLock().releaseS3Lock(bucketName);
}
}
private String formatOzoneVolumeName(String userName) { private String formatOzoneVolumeName(String userName) {
return String.format("s3%s", userName); return String.format("s3%s", userName);
} }
@ -202,4 +226,5 @@ public class S3BucketManagerImpl implements S3BucketManager {
String mapping = getOzoneBucketMapping(s3BucketName); String mapping = getOzoneBucketMapping(s3BucketName);
return mapping.split("/")[1]; return mapping.split("/")[1];
} }
} }

View File

@ -97,6 +97,10 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.S3BucketRequest; .S3BucketRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.S3BucketResponse; .S3BucketResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.S3DeleteBucketRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.S3DeleteBucketResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.ServiceListRequest; .ServiceListRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
@ -596,6 +600,20 @@ public class OzoneManagerProtocolServerSideTranslatorPB implements
return resp.build(); return resp.build();
} }
@Override
public S3DeleteBucketResponse deleteS3Bucket(RpcController controller,
S3DeleteBucketRequest request) throws
ServiceException {
S3DeleteBucketResponse.Builder resp = S3DeleteBucketResponse.newBuilder();
try {
impl.deleteS3Bucket(request.getS3BucketName());
resp.setStatus(Status.OK);
} catch (IOException e) {
resp.setStatus(exceptionToResponseStatus(e));
}
return resp.build();
}
@Override @Override
public S3BucketInfoResponse getS3Bucketinfo(RpcController controller, public S3BucketInfoResponse getS3Bucketinfo(RpcController controller,
S3BucketInfoRequest request) throws ServiceException { S3BucketInfoRequest request) throws ServiceException {

View File

@ -75,6 +75,24 @@ public class TestS3BucketManager {
} }
@Test
public void testDeleteS3Bucket() throws IOException {
S3BucketManager s3BucketManager = new S3BucketManagerImpl(conf, metaMgr,
volumeManager, bucketManager);
s3BucketManager.createS3Bucket("ozone", "s3bucket");
// This call should have created a ozone volume called s3ozone and bucket
// called s3ozone/s3bucket.
Assert.assertNotNull(volumeManager.getVolumeInfo("s3ozone"));
Assert.assertNotNull(bucketManager.getBucketInfo("s3ozone", "s3bucket"));
s3BucketManager.deleteS3Bucket("s3bucket");
//Deleting non existing bucket should throw.
thrown.expect(IOException.class);
s3BucketManager.deleteS3Bucket("s3bucket");
}
@Test @Test
public void testGetS3BucketMapping() throws IOException { public void testGetS3BucketMapping() throws IOException {
S3BucketManager s3BucketManager = new S3BucketManagerImpl(conf, metaMgr, S3BucketManager s3BucketManager = new S3BucketManagerImpl(conf, metaMgr,

View File

@ -107,6 +107,49 @@ public class EndpointBase {
return "/"+location; return "/"+location;
} }
/**
* Deletes an s3 bucket and removes mapping of Ozone volume/bucket.
* @param s3BucketName - S3 Bucket Name.
* @throws IOException in case the bucket cannot be deleted.
*/
public void deleteS3Bucket(String s3BucketName)
throws IOException {
client.getObjectStore().deleteS3Bucket(s3BucketName);
}
/**
* Returns the Ozone Namespace for the S3Bucket. It will return the
* OzoneVolume/OzoneBucketName.
* @param s3BucketName - S3 Bucket Name.
* @return String - The Ozone canonical name for this s3 bucket. This
* string is useful for mounting an OzoneFS.
* @throws IOException - Error is throw if the s3bucket does not exist.
*/
public String getOzoneBucketMapping(String s3BucketName) throws IOException {
return client.getObjectStore().getOzoneBucketMapping(s3BucketName);
}
/**
* Returns the corresponding Ozone volume given an S3 Bucket.
* @param s3BucketName - S3Bucket Name.
* @return String - Ozone Volume name.
* @throws IOException - Throws if the s3Bucket does not exist.
*/
public String getOzoneVolumeName(String s3BucketName) throws IOException {
return client.getObjectStore().getOzoneVolumeName(s3BucketName);
}
/**
* Returns the corresponding Ozone bucket name for the given S3 bucket.
* @param s3BucketName - S3Bucket Name.
* @return String - Ozone bucket Name.
* @throws IOException - Throws if the s3bucket does not exist.
*/
public String getOzoneBucketName(String s3BucketName) throws IOException {
return client.getObjectStore().getOzoneBucketName(s3BucketName);
}
@VisibleForTesting @VisibleForTesting
public void setClient(OzoneClient ozoneClient) { public void setClient(OzoneClient ozoneClient) {
this.client = ozoneClient; this.client = ozoneClient;

View File

@ -36,6 +36,7 @@ public class ObjectStoreStub extends ObjectStore {
} }
private Map<String, OzoneVolumeStub> volumes = new HashMap<>(); private Map<String, OzoneVolumeStub> volumes = new HashMap<>();
private Map<String, String> bucketVolumeMap = new HashMap<>();
@Override @Override
public void createVolume(String volumeName) throws IOException { public void createVolume(String volumeName) throws IOException {
@ -107,4 +108,29 @@ public class ObjectStoreStub extends ObjectStore {
public void deleteVolume(String volumeName) throws IOException { public void deleteVolume(String volumeName) throws IOException {
volumes.remove(volumeName); volumes.remove(volumeName);
} }
@Override
public void createS3Bucket(String userName, String s3BucketName) throws
IOException {
bucketVolumeMap.put(s3BucketName, "s3"+userName+"/"+s3BucketName);
}
@Override
public void deleteS3Bucket(String s3BucketName) throws
IOException {
bucketVolumeMap.remove(s3BucketName);
}
@Override
public String getOzoneBucketMapping(String s3BucketName) throws IOException {
return bucketVolumeMap.get(s3BucketName);
}
@Override
public String getOzoneVolumeName(String s3BucketName) throws IOException {
return bucketVolumeMap.get(s3BucketName).split("/")[0];
}
@Override
public String getOzoneBucketName(String s3BucketName) throws IOException {
return bucketVolumeMap.get(s3BucketName).split("/")[1];
}
} }