blob: 6c33e9e00fccdb95fd15753d95373c3ccd6b5ceb [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;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
import org.apache.hadoop.security.token.Token;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.DETECTED_LOOP_IN_BUCKET_LINKS;
/**
* Ozone Manager utility class.
*/
public final class OzoneManagerUtils {
private OzoneManagerUtils() {
}
private static final Logger LOG = LoggerFactory
.getLogger(OzoneManagerUtils.class);
/**
* All the client requests are executed through
* OzoneManagerStateMachine#runCommand function and ensures sequential
* execution path.
* Below is the call trace to perform OM client request operation:
* OzoneManagerStateMachine#applyTransaction ->
* OzoneManagerStateMachine#runCommand ->
* OzoneManagerRequestHandler#handleWriteRequest ->
* OzoneManagerRatisUtils#createClientRequest ->
* BucketLayoutAwareOMKeyRequestFactory#createRequest ->
* ...
* OzoneManagerUtils#getBucketLayout ->
* OzoneManagerUtils#getOmBucketInfo ->
* omMetadataManager().getBucketTable().get(buckKey)
*/
private static OmBucketInfo getOmBucketInfo(OMMetadataManager metaMgr,
String volName, String buckName) throws IOException {
String buckKey = metaMgr.getBucketKey(volName, buckName);
return metaMgr.getBucketTable().get(buckKey);
}
/**
* Get bucket layout for the given volume and bucket name.
*
* @param metadataManager OMMetadataManager
* @param volName volume name
* @param buckName bucket name
* @return bucket layout
* @throws IOException
*/
public static BucketLayout getBucketLayout(OMMetadataManager metadataManager,
String volName,
String buckName)
throws IOException {
return getBucketLayout(metadataManager, volName, buckName, new HashSet<>());
}
/**
* Get bucket layout for the given volume and bucket name.
*
* @param metadataManager metadata manager
* @param volName volume name
* @param buckName bucket name
* @return bucket layout
* @throws IOException
*/
private static BucketLayout getBucketLayout(OMMetadataManager metadataManager,
String volName,
String buckName,
Set<Pair<String, String>> visited)
throws IOException {
OmBucketInfo buckInfo = getOmBucketInfo(metadataManager, volName, buckName);
if (buckInfo != null) {
// If this is a link bucket, we fetch the BucketLayout from the
// source bucket.
if (buckInfo.isLink()) {
// Check if this bucket was already visited - to avoid loops
if (!visited.add(Pair.of(volName, buckName))) {
throw new OMException("Detected loop in bucket links. Bucket name: " +
buckName + ", Volume name: " + volName,
DETECTED_LOOP_IN_BUCKET_LINKS);
}
OmBucketInfo sourceBuckInfo =
getOmBucketInfo(metadataManager, buckInfo.getSourceVolume(),
buckInfo.getSourceBucket());
if (sourceBuckInfo != null) {
/** If the source bucket is again a link, we recursively resolve the
* link bucket.
*
* For example:
* buck-link1 -> buck-link2 -> buck-link3 -> buck-src
* buck-src has the actual BucketLayout that will be used by the
* links.
*/
if (sourceBuckInfo.isLink()) {
return getBucketLayout(metadataManager,
sourceBuckInfo.getVolumeName(),
sourceBuckInfo.getBucketName(), visited);
}
return sourceBuckInfo.getBucketLayout();
}
}
return buckInfo.getBucketLayout();
}
if (!metadataManager.getVolumeTable()
.isExist(metadataManager.getVolumeKey(volName))) {
throw new OMException("Volume not found: " + volName,
OMException.ResultCodes.VOLUME_NOT_FOUND);
}
throw new OMException("Bucket not found: " + volName + "/" + buckName,
OMException.ResultCodes.BUCKET_NOT_FOUND);
}
/**
* Resolve bucket layout for a given link bucket's OmBucketInfo.
*
* @param bucketInfo
* @return {@code OmBucketInfo} with
* @throws IOException
*/
public static OmBucketInfo resolveLinkBucketLayout(OmBucketInfo bucketInfo,
OMMetadataManager
metadataManager,
Set<Pair<String,
String>> visited)
throws IOException {
if (bucketInfo.isLink()) {
if (!visited.add(Pair.of(bucketInfo.getVolumeName(),
bucketInfo.getBucketName()))) {
throw new OMException("Detected loop in bucket links. Bucket name: " +
bucketInfo.getBucketName() + ", Volume name: " +
bucketInfo.getVolumeName(),
DETECTED_LOOP_IN_BUCKET_LINKS);
}
String sourceBucketKey = metadataManager
.getBucketKey(bucketInfo.getSourceVolume(),
bucketInfo.getSourceBucket());
OmBucketInfo sourceBucketInfo =
metadataManager.getBucketTable().get(sourceBucketKey);
// If the Link Bucket's source bucket exists, we get its layout.
if (sourceBucketInfo != null) {
/** If the source bucket is again a link, we recursively resolve the
* link bucket.
*
* For example:
* buck-link1 -> buck-link2 -> buck-link3 -> buck-src
* buck-src has the actual BucketLayout that will be used by the links.
*
* Finally - we return buck-link1's OmBucketInfo, with buck-src's
* bucket layout.
*/
if (sourceBucketInfo.isLink()) {
sourceBucketInfo =
resolveLinkBucketLayout(sourceBucketInfo, metadataManager,
visited);
}
OmBucketInfo.Builder buckInfoBuilder = bucketInfo.toBuilder();
buckInfoBuilder.setBucketLayout(sourceBucketInfo.getBucketLayout());
bucketInfo = buckInfoBuilder.build();
}
}
return bucketInfo;
}
/**
* Builds an audit map based on the Delegation Token passed to the method.
* @param token Delegation Token
* @return AuditMap
*/
public static Map<String, String> buildTokenAuditMap(
Token<OzoneTokenIdentifier> token) {
Map<String, String> auditMap = new LinkedHashMap<>();
auditMap.put(OzoneConsts.DELEGATION_TOKEN_KIND,
token.getKind() == null ? "" : token.getKind().toString());
auditMap.put(OzoneConsts.DELEGATION_TOKEN_SERVICE,
token.getService() == null ? "" : token.getService().toString());
return auditMap;
}
}