blob: 306527f2a4fcd8df44bd11f2e72ae53abdddffa4 [file] [log] [blame]
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.request;
import java.io.IOException;
import java.net.InetAddress;
import java.util.LinkedHashMap;
import java.util.Map;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.ipc.ProtobufRpcEngine;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.audit.AuditAction;
import org.apache.hadoop.ozone.audit.AuditEventStatus;
import org.apache.hadoop.ozone.audit.AuditLogger;
import org.apache.hadoop.ozone.audit.AuditMessage;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.OMRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.OMResponse;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.security.UserGroupInformation;
import javax.annotation.Nonnull;
/**
* OMClientRequest provides methods which every write OM request should
* implement.
*/
public abstract class OMClientRequest implements RequestAuditor {
private OMRequest omRequest;
public OMClientRequest(OMRequest omRequest) {
Preconditions.checkNotNull(omRequest);
this.omRequest = omRequest;
}
/**
* Perform pre-execute steps on a OMRequest.
*
* Called from the RPC context, and generates a OMRequest object which has
* all the information that will be either persisted
* in RocksDB or returned to the caller once this operation
* is executed.
*
* @return OMRequest that will be serialized and handed off to Ratis for
* consensus.
*/
public OMRequest preExecute(OzoneManager ozoneManager)
throws IOException {
omRequest = getOmRequest().toBuilder().setUserInfo(getUserInfo()).build();
return omRequest;
}
/**
* Validate the OMRequest and update the cache.
* This step should verify that the request can be executed, perform
* any authorization steps and update the in-memory cache.
* This step does not persist the changes to the database.
*
* @return the response that will be returned to the client.
*/
public abstract OMClientResponse validateAndUpdateCache(
OzoneManager ozoneManager, long transactionLogIndex,
OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper);
@VisibleForTesting
public OMRequest getOmRequest() {
return omRequest;
}
/**
* Get User information which needs to be set in the OMRequest object.
* @return User Info.
*/
public OzoneManagerProtocolProtos.UserInfo getUserInfo() {
UserGroupInformation user = ProtobufRpcEngine.Server.getRemoteUser();
InetAddress remoteAddress = ProtobufRpcEngine.Server.getRemoteIp();
OzoneManagerProtocolProtos.UserInfo.Builder userInfo =
OzoneManagerProtocolProtos.UserInfo.newBuilder();
// Added not null checks, as in UT's these values might be null.
if (user != null) {
userInfo.setUserName(user.getUserName());
}
if (remoteAddress != null) {
userInfo.setRemoteAddress(remoteAddress.getHostAddress()).build();
}
return userInfo.build();
}
/**
* Check Acls of ozone object.
* @param ozoneManager
* @param resType
* @param storeType
* @param aclType
* @param vol
* @param bucket
* @param key
* @throws IOException
*/
public void checkAcls(OzoneManager ozoneManager,
OzoneObj.ResourceType resType,
OzoneObj.StoreType storeType, IAccessAuthorizer.ACLType aclType,
String vol, String bucket, String key) throws IOException {
ozoneManager.checkAcls(resType, storeType, aclType, vol, bucket, key,
createUGI(), getRemoteAddress());
}
/**
* Return UGI object created from OMRequest userInfo. If userInfo is not
* set, returns null.
* @return UserGroupInformation.
*/
@VisibleForTesting
public UserGroupInformation createUGI() {
if (omRequest.hasUserInfo() &&
!StringUtils.isBlank(omRequest.getUserInfo().getUserName())) {
return UserGroupInformation.createRemoteUser(
omRequest.getUserInfo().getUserName());
} else {
// This will never happen, as for every OM request preExecute, we
// should add userInfo.
return null;
}
}
/**
* Return InetAddress created from OMRequest userInfo. If userInfo is not
* set, returns null.
* @return InetAddress
* @throws IOException
*/
@VisibleForTesting
public InetAddress getRemoteAddress() throws IOException {
if (omRequest.hasUserInfo()) {
return InetAddress.getByName(omRequest.getUserInfo()
.getRemoteAddress());
} else {
return null;
}
}
/**
* Set parameters needed for return error response to client.
* @param omResponse
* @param ex - IOException
* @return error response need to be returned to client - OMResponse.
*/
protected OMResponse createErrorOMResponse(
@Nonnull OMResponse.Builder omResponse, @Nonnull IOException ex) {
omResponse.setSuccess(false);
if (ex.getMessage() != null) {
omResponse.setMessage(ex.getMessage());
}
omResponse.setStatus(OzoneManagerRatisUtils.exceptionToResponseStatus(ex));
return omResponse.build();
}
/**
* Log the auditMessage.
* @param auditLogger
* @param auditMessage
*/
protected void auditLog(AuditLogger auditLogger, AuditMessage auditMessage) {
auditLogger.logWrite(auditMessage);
}
@Override
public AuditMessage buildAuditMessage(AuditAction op,
Map< String, String > auditMap, Throwable throwable,
OzoneManagerProtocolProtos.UserInfo userInfo) {
return new AuditMessage.Builder()
.setUser(userInfo != null ? userInfo.getUserName() : null)
.atIp(userInfo != null ? userInfo.getRemoteAddress() : null)
.forOperation(op.getAction())
.withParams(auditMap)
.withResult(throwable != null ? AuditEventStatus.FAILURE.toString() :
AuditEventStatus.SUCCESS.toString())
.withException(throwable)
.build();
}
@Override
public Map<String, String> buildVolumeAuditMap(String volume) {
Map<String, String> auditMap = new LinkedHashMap<>();
auditMap.put(OzoneConsts.VOLUME, volume);
return auditMap;
}
}