| /** |
| * 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.volume; |
| |
| import java.io.IOException; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import com.google.common.base.Preconditions; |
| import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import org.apache.hadoop.ozone.audit.OMAction; |
| import org.apache.hadoop.ozone.om.response.volume.OMVolumeCreateResponse; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; |
| import org.apache.hadoop.ozone.om.OMMetrics; |
| import org.apache.hadoop.ozone.om.OMMetadataManager; |
| import org.apache.hadoop.ozone.om.OzoneManager; |
| import org.apache.hadoop.ozone.om.exceptions.OMException; |
| import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; |
| import org.apache.hadoop.ozone.om.response.OMClientResponse; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos |
| .CreateVolumeRequest; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos |
| .CreateVolumeResponse; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos |
| .OMRequest; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos |
| .OMResponse; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos |
| .VolumeInfo; |
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UserVolumeInfo; |
| import org.apache.hadoop.util.Time; |
| |
| import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS_WILDCARD; |
| import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK; |
| import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.USER_LOCK; |
| |
| /** |
| * Handles volume create request. |
| */ |
| public class OMVolumeCreateRequest extends OMVolumeRequest { |
| private static final Logger LOG = |
| LoggerFactory.getLogger(OMVolumeCreateRequest.class); |
| |
| public OMVolumeCreateRequest(OMRequest omRequest) { |
| super(omRequest); |
| } |
| |
| @Override |
| public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { |
| |
| VolumeInfo volumeInfo = |
| getOmRequest().getCreateVolumeRequest().getVolumeInfo(); |
| |
| // Set creation time |
| VolumeInfo updatedVolumeInfo = |
| volumeInfo.toBuilder().setCreationTime(Time.now()).build(); |
| |
| |
| return getOmRequest().toBuilder().setCreateVolumeRequest( |
| CreateVolumeRequest.newBuilder().setVolumeInfo(updatedVolumeInfo)) |
| .setUserInfo(getUserInfo()) |
| .build(); |
| |
| } |
| |
| @Override |
| public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, |
| long transactionLogIndex, |
| OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) { |
| |
| CreateVolumeRequest createVolumeRequest = |
| getOmRequest().getCreateVolumeRequest(); |
| Preconditions.checkNotNull(createVolumeRequest); |
| VolumeInfo volumeInfo = createVolumeRequest.getVolumeInfo(); |
| |
| OMMetrics omMetrics = ozoneManager.getMetrics(); |
| omMetrics.incNumVolumeCreates(); |
| |
| String volume = volumeInfo.getVolume(); |
| String owner = volumeInfo.getOwnerName(); |
| |
| OMResponse.Builder omResponse = OMResponse.newBuilder().setCmdType( |
| OzoneManagerProtocolProtos.Type.CreateVolume).setStatus( |
| OzoneManagerProtocolProtos.Status.OK).setSuccess(true); |
| |
| OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager(); |
| |
| // Doing this here, so we can do protobuf conversion outside of lock. |
| boolean acquiredVolumeLock = false; |
| boolean acquiredUserLock = false; |
| IOException exception = null; |
| OMClientResponse omClientResponse = null; |
| OmVolumeArgs omVolumeArgs = null; |
| Map<String, String> auditMap = new HashMap<>(); |
| Collection<String> ozAdmins = ozoneManager.getOzoneAdmins(); |
| try { |
| omVolumeArgs = OmVolumeArgs.getFromProtobuf(volumeInfo); |
| // when you create a volume, we set both Object ID and update ID to the |
| // same ratis transaction ID. The Object ID will never change, but update |
| // ID will be set to transactionID each time we update the object. |
| omVolumeArgs.setUpdateID(transactionLogIndex); |
| omVolumeArgs.setObjectID(transactionLogIndex); |
| auditMap = omVolumeArgs.toAuditMap(); |
| |
| // check Acl |
| if (ozoneManager.getAclsEnabled()) { |
| if (!ozAdmins.contains(OZONE_ADMINISTRATORS_WILDCARD) && |
| !ozAdmins.contains(getUserInfo().getUserName())) { |
| throw new OMException("Only admin users are authorized to create " + |
| "Ozone volumes. User: " + getUserInfo().getUserName(), |
| OMException.ResultCodes.PERMISSION_DENIED); |
| } |
| } |
| |
| UserVolumeInfo volumeList = null; |
| |
| // acquire lock. |
| acquiredVolumeLock = omMetadataManager.getLock().acquireWriteLock( |
| VOLUME_LOCK, volume); |
| |
| acquiredUserLock = omMetadataManager.getLock().acquireWriteLock(USER_LOCK, |
| owner); |
| |
| String dbVolumeKey = omMetadataManager.getVolumeKey(volume); |
| |
| OmVolumeArgs dbVolumeArgs = |
| omMetadataManager.getVolumeTable().get(dbVolumeKey); |
| |
| if (dbVolumeArgs == null) { |
| String dbUserKey = omMetadataManager.getUserKey(owner); |
| volumeList = omMetadataManager.getUserTable().get(dbUserKey); |
| volumeList = addVolumeToOwnerList(volumeList, volume, owner, |
| ozoneManager.getMaxUserVolumeCount(), transactionLogIndex); |
| createVolume(omMetadataManager, omVolumeArgs, volumeList, dbVolumeKey, |
| dbUserKey, transactionLogIndex); |
| |
| omResponse.setCreateVolumeResponse(CreateVolumeResponse.newBuilder() |
| .build()); |
| omClientResponse = new OMVolumeCreateResponse(omVolumeArgs, volumeList, |
| omResponse.build()); |
| LOG.debug("volume:{} successfully created", omVolumeArgs.getVolume()); |
| } else { |
| LOG.debug("volume:{} already exists", omVolumeArgs.getVolume()); |
| throw new OMException("Volume already exists", |
| OMException.ResultCodes.VOLUME_ALREADY_EXISTS); |
| } |
| |
| } catch (IOException ex) { |
| exception = ex; |
| omClientResponse = new OMVolumeCreateResponse(null, null, |
| createErrorOMResponse(omResponse, exception)); |
| } finally { |
| if (omClientResponse != null) { |
| omClientResponse.setFlushFuture( |
| ozoneManagerDoubleBufferHelper.add(omClientResponse, |
| transactionLogIndex)); |
| } |
| if (acquiredUserLock) { |
| omMetadataManager.getLock().releaseWriteLock(USER_LOCK, owner); |
| } |
| if (acquiredVolumeLock) { |
| omMetadataManager.getLock().releaseWriteLock(VOLUME_LOCK, volume); |
| } |
| } |
| |
| // Performing audit logging outside of the lock. |
| auditLog(ozoneManager.getAuditLogger(), |
| buildAuditMessage(OMAction.CREATE_VOLUME, auditMap, exception, |
| getOmRequest().getUserInfo())); |
| |
| // return response after releasing lock. |
| if (exception == null) { |
| LOG.info("created volume:{} for user:{}", volume, owner); |
| omMetrics.incNumVolumes(); |
| } else { |
| LOG.error("Volume creation failed for user:{} volume:{}", owner, |
| volume, exception); |
| omMetrics.incNumVolumeCreateFails(); |
| } |
| return omClientResponse; |
| } |
| } |
| |
| |