Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,34 @@
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
import org.apache.hadoop.ozone.om.helpers.S3VolumeContext;
import org.apache.hadoop.ozone.om.helpers.TenantInfoList;
import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue;
import org.apache.hadoop.ozone.om.helpers.TenantUserList;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;
import org.apache.hadoop.ozone.om.protocol.S3Auth;
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.security.UserGroupInformation;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import org.apache.hadoop.security.token.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* ObjectStore class is responsible for the client operations that can be
* performed on Ozone Object Store.
*/
public class ObjectStore {

private static final Logger LOG =
LoggerFactory.getLogger(ObjectStore.class);

private final ConfigurationSource conf;
/**
* The proxy used for connecting to the cluster and perform
* client operations.
Expand All @@ -71,6 +80,7 @@ public class ObjectStore {
* @param proxy ClientProtocol proxy.
*/
public ObjectStore(ConfigurationSource conf, ClientProtocol proxy) {
this.conf = conf;
this.proxy = TracingUtil.createProxy(proxy, ClientProtocol.class, conf);
this.listCacheSize = HddsClientUtils.getListCacheSize(conf);
defaultS3Volume = HddsClientUtils.getDefaultS3VolumeName(conf);
Expand All @@ -79,7 +89,7 @@ public ObjectStore(ConfigurationSource conf, ClientProtocol proxy) {
@VisibleForTesting
protected ObjectStore() {
// For the unit test
OzoneConfiguration conf = new OzoneConfiguration();
this.conf = new OzoneConfiguration();
proxy = null;
defaultS3Volume = HddsClientUtils.getDefaultS3VolumeName(conf);
}
Expand Down Expand Up @@ -154,7 +164,25 @@ public OzoneVolume getVolume(String volumeName) throws IOException {
}

public OzoneVolume getS3Volume() throws IOException {
return proxy.getS3VolumeDetails();
final S3VolumeContext resp = proxy.getS3VolumeContext();

S3Auth s3Auth = proxy.getThreadLocalS3Auth();
// Update user principal if needed to be used for KMS client
if (s3Auth != null) {
// Update userPrincipal field with the value returned from OM. So that
// in multi-tenancy, KMS client can use the correct identity
// (instead of using accessId) to communicate with KMS.
LOG.debug("Updating S3Auth.userPrincipal to {}", resp.getUserPrincipal());
s3Auth.setUserPrincipal(resp.getUserPrincipal());
proxy.setTheadLocalS3Auth(s3Auth);
}

OmVolumeArgs volume = resp.getOmVolumeArgs();
return proxy.buildOzoneVolume(volume);
}

public S3VolumeContext getS3VolumeContext() throws IOException {
return proxy.getS3VolumeContext();
}

public S3SecretValue getS3Secret(String kerberosID) throws IOException {
Expand Down Expand Up @@ -207,8 +235,9 @@ public void createTenant(String tenantId, TenantArgs tenantArgs)
* Delete a tenant.
* @param tenantId tenant name.
* @throws IOException
* @return DeleteTenantInfo
*/
public DeleteTenantResponse deleteTenant(String tenantId) throws IOException {
public DeleteTenantInfo deleteTenant(String tenantId) throws IOException {
return proxy.deleteTenant(tenantId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,19 @@
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo;
import org.apache.hadoop.ozone.om.helpers.OmMultipartInfo;
import org.apache.hadoop.ozone.om.helpers.OmMultipartUploadCompleteInfo;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
import org.apache.hadoop.ozone.om.helpers.S3VolumeContext;
import org.apache.hadoop.ozone.om.helpers.TenantInfoList;
import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue;
import org.apache.hadoop.ozone.om.helpers.TenantUserList;
import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
import org.apache.hadoop.ozone.om.protocol.S3Auth;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo;
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
Expand Down Expand Up @@ -124,11 +126,13 @@ OzoneVolume getVolumeDetails(String volumeName)
throws IOException;

/**
* @return The {@link OzoneVolume} that should be used to for this S3
* request based on its access ID.
* @return Raw GetS3VolumeContextResponse.
* S3Auth won't be updated with actual userPrincipal by this call.
* @throws IOException
*/
OzoneVolume getS3VolumeDetails() throws IOException;
S3VolumeContext getS3VolumeContext() throws IOException;

OzoneVolume buildOzoneVolume(OmVolumeArgs volume);

/**
* Checks if a Volume exists and the user with a role specified has access
Expand Down Expand Up @@ -609,8 +613,9 @@ S3SecretValue setS3Secret(String accessId, String secretKey)
* Delete a tenant.
* @param tenantId tenant name.
* @throws IOException
* @return DeleteTenantInfo
*/
DeleteTenantResponse deleteTenant(String tenantId) throws IOException;
DeleteTenantInfo deleteTenant(String tenantId) throws IOException;

/**
* Assign a user to a tenant.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo;
import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.om.helpers.OmDeleteKeys;
Expand All @@ -104,6 +105,7 @@
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
import org.apache.hadoop.ozone.om.helpers.S3VolumeContext;
import org.apache.hadoop.ozone.om.helpers.ServiceInfo;
import org.apache.hadoop.ozone.om.helpers.ServiceInfoEx;
import org.apache.hadoop.ozone.om.helpers.TenantInfoList;
Expand All @@ -115,7 +117,6 @@
import org.apache.hadoop.ozone.om.protocolPB.OmTransportFactory;
import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerClientProtocol;
import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerProtocolClientSideTranslatorPB;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo;
import org.apache.hadoop.ozone.security.GDPRSymmetricKey;
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
Expand Down Expand Up @@ -437,12 +438,11 @@ public OzoneVolume getVolumeDetails(String volumeName)
}

@Override
public OzoneVolume getS3VolumeDetails() throws IOException {
OmVolumeArgs volume = ozoneManagerClient.getS3Volume();
return buildOzoneVolume(volume);
public S3VolumeContext getS3VolumeContext() throws IOException {
return ozoneManagerClient.getS3VolumeContext();
}

private OzoneVolume buildOzoneVolume(OmVolumeArgs volume) {
public OzoneVolume buildOzoneVolume(OmVolumeArgs volume) {
return new OzoneVolume(
conf,
this,
Expand Down Expand Up @@ -770,7 +770,7 @@ public void createTenant(String tenantId, TenantArgs tenantArgs)
* {@inheritDoc}
*/
@Override
public DeleteTenantResponse deleteTenant(String tenantId) throws IOException {
public DeleteTenantInfo deleteTenant(String tenantId) throws IOException {
Preconditions.checkArgument(Strings.isNotBlank(tenantId),
"tenantId cannot be null or empty.");
return ozoneManagerClient.deleteTenant(tenantId);
Expand Down Expand Up @@ -1062,8 +1062,10 @@ private KeyProvider.KeyVersion getDEK(FileEncryptionInfo feInfo)
UserGroupInformation loginUser = UserGroupInformation.getLoginUser();
UserGroupInformation proxyUser;
if (getThreadLocalS3Auth() != null) {
String userPrincipal = getThreadLocalS3Auth().getUserPrincipal();
Preconditions.checkNotNull(userPrincipal);
UserGroupInformation s3gUGI = UserGroupInformation.createRemoteUser(
getThreadLocalS3Auth().getAccessID());
userPrincipal);
proxyUser = UserGroupInformation.createProxyUser(
s3gUGI.getShortUserName(), loginUser);
decrypted = proxyUser.doAs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public static boolean isReadOnly(
case ListMultipartUploads:
case FinalizeUpgradeProgress:
case PrepareStatus:
case GetS3Volume:
case GetS3VolumeContext:
case ListTenant:
case TenantGetUserInfo:
case TenantListUser:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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.om.helpers;

import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;

/**
* A class that encapsulates DeleteTenantResponse protobuf message.
*/
public class DeleteTenantInfo {

/**
* Volume name associated to the deleted tenant.
*/
private final String volumeName;

/**
* Reference count remaining of the volume associated to the deleted tenant.
*/
private final long volRefCount;

public DeleteTenantInfo(String volumeName, long volRefCount) {
this.volumeName = volumeName;
this.volRefCount = volRefCount;
}

public String getVolumeName() {
return volumeName;
}

public long getVolRefCount() {
return volRefCount;
}

public static DeleteTenantInfo fromProtobuf(DeleteTenantResponse resp) {
return new DeleteTenantInfo(resp.getVolumeName(), resp.getVolRefCount());
}

public DeleteTenantResponse getProtobuf() {
return DeleteTenantResponse.newBuilder()
.setVolumeName(volumeName)
.setVolRefCount(volRefCount)
.build();
}

public static DeleteTenantInfo.Builder newBuilder() {
return new DeleteTenantInfo.Builder();
}

/**
* Builder for TenantDeleted.
*/
@SuppressWarnings("checkstyle:hiddenfield")
public static final class Builder {
private String volumeName;
private long volRefCount;

private Builder() {
}

public Builder setVolumeName(String volumeName) {
this.volumeName = volumeName;
return this;
}

public Builder setVolRefCount(long volRefCount) {
this.volRefCount = volRefCount;
return this;
}

public DeleteTenantInfo build() {
return new DeleteTenantInfo(volumeName, volRefCount);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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.om.helpers;

import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextResponse;

/**
* A class that encapsulates GetS3VolumeContextResponse protobuf message.
*/
public class S3VolumeContext {

/**
* Various volume arguments.
*/
private final OmVolumeArgs omVolumeArgs;

/**
* Piggybacked username (principal) response.
* To be used for client-side operations involving KMS like getDEK().
*/
private final String userPrincipal;

public S3VolumeContext(OmVolumeArgs omVolumeArgs, String userPrincipal) {
this.omVolumeArgs = omVolumeArgs;
this.userPrincipal = userPrincipal;
}

public OmVolumeArgs getOmVolumeArgs() {
return omVolumeArgs;
}

public String getUserPrincipal() {
return userPrincipal;
}

public static S3VolumeContext fromProtobuf(GetS3VolumeContextResponse resp) {
return new S3VolumeContext(
OmVolumeArgs.getFromProtobuf(resp.getVolumeInfo()),
resp.getUserPrincipal());
}

public GetS3VolumeContextResponse getProtobuf() {
return GetS3VolumeContextResponse.newBuilder()
.setVolumeInfo(omVolumeArgs.getProtobuf())
.setUserPrincipal(userPrincipal)
.build();
}

public static S3VolumeContext.Builder newBuilder() {
return new S3VolumeContext.Builder();
}

/**
* Builder for S3VolumeContext.
*/
@SuppressWarnings("checkstyle:hiddenfield")
public static final class Builder {
private OmVolumeArgs omVolumeArgs;
private String userPrincipal;

private Builder() {
}

public Builder setOmVolumeArgs(OmVolumeArgs omVolumeArgs) {
this.omVolumeArgs = omVolumeArgs;
return this;
}

public Builder setUserPrincipal(String userPrincipal) {
this.userPrincipal = userPrincipal;
return this;
}

public S3VolumeContext build() {
return new S3VolumeContext(omVolumeArgs, userPrincipal);
}
}
}
Loading