1+ /**
2+ * Licensed to the Apache Software Foundation (ASF) under one
3+ * or more contributor license agreements. See the NOTICE file
4+ * distributed with this work for additional information
5+ * regarding copyright ownership. The ASF licenses this file
6+ * to you under the Apache License, Version 2.0 (the
7+ * "License"); you may not use this file except in compliance
8+ * with the License. You may obtain a copy of the License at
9+ * <p>
10+ * http://www.apache.org/licenses/LICENSE-2.0
11+ * <p>
12+ * Unless required by applicable law or agreed to in writing, software
13+ * distributed under the License is distributed on an "AS IS" BASIS,
14+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+ * See the License for the specific language governing permissions and
16+ * limitations under the License.
17+ */
18+
19+ package org .apache .hadoop .ozone .om .request .s3 .bucket ;
20+
21+ import java .io .IOException ;
22+ import java .util .HashMap ;
23+ import java .util .Map ;
24+
25+ import com .google .common .base .Optional ;
26+ import org .slf4j .Logger ;
27+ import org .slf4j .LoggerFactory ;
28+
29+ import org .apache .hadoop .ozone .OzoneConsts ;
30+ import org .apache .hadoop .ozone .audit .OMAction ;
31+ import org .apache .hadoop .ozone .om .OMMetadataManager ;
32+ import org .apache .hadoop .ozone .om .OMMetrics ;
33+ import org .apache .hadoop .ozone .om .OzoneManager ;
34+ import org .apache .hadoop .ozone .om .exceptions .OMException ;
35+ import org .apache .hadoop .ozone .om .request .volume .OMVolumeRequest ;
36+ import org .apache .hadoop .ozone .om .response .OMClientResponse ;
37+ import org .apache .hadoop .ozone .om .response .s3 .bucket .S3BucketDeleteResponse ;
38+ import org .apache .hadoop .ozone .protocol .proto .OzoneManagerProtocolProtos ;
39+ import org .apache .hadoop .ozone .protocol .proto .OzoneManagerProtocolProtos
40+ .OMRequest ;
41+ import org .apache .hadoop .ozone .protocol .proto .OzoneManagerProtocolProtos
42+ .OMResponse ;
43+ import org .apache .hadoop .ozone .protocol .proto .OzoneManagerProtocolProtos
44+ .S3DeleteBucketRequest ;
45+ import org .apache .hadoop .ozone .security .acl .IAccessAuthorizer ;
46+ import org .apache .hadoop .ozone .security .acl .OzoneObj ;
47+ import org .apache .hadoop .utils .db .cache .CacheKey ;
48+ import org .apache .hadoop .utils .db .cache .CacheValue ;
49+
50+ import static org .apache .hadoop .ozone .OzoneConsts .S3_BUCKET_MAX_LENGTH ;
51+ import static org .apache .hadoop .ozone .OzoneConsts .S3_BUCKET_MIN_LENGTH ;
52+ import static org .apache .hadoop .ozone .om .lock .OzoneManagerLock .Resource .BUCKET_LOCK ;
53+ import static org .apache .hadoop .ozone .om .lock .OzoneManagerLock .Resource .S3_BUCKET_LOCK ;
54+
55+ /**
56+ * Handle Create S3Bucket request.
57+ */
58+ public class S3BucketDeleteRequest extends OMVolumeRequest {
59+
60+ private static final Logger LOG =
61+ LoggerFactory .getLogger (S3BucketDeleteRequest .class );
62+
63+ public S3BucketDeleteRequest (OMRequest omRequest ) {
64+ super (omRequest );
65+ }
66+
67+ public OMRequest preExecute (OzoneManager ozoneManager ) throws IOException {
68+ S3DeleteBucketRequest s3DeleteBucketRequest =
69+ getOmRequest ().getDeleteS3BucketRequest ();
70+
71+ // TODO: Do we need to enforce the bucket rules in this code path?
72+ // https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
73+
74+ // For now only checked the length.
75+ int bucketLength = s3DeleteBucketRequest .getS3BucketName ().length ();
76+ if (bucketLength < S3_BUCKET_MIN_LENGTH ||
77+ bucketLength >= S3_BUCKET_MAX_LENGTH ) {
78+ throw new OMException ("S3BucketName must be at least 3 and not more " +
79+ "than 63 characters long" ,
80+ OMException .ResultCodes .S3_BUCKET_INVALID_LENGTH );
81+ }
82+
83+ return getOmRequest ().toBuilder ().setUserInfo (getUserInfo ()).build ();
84+
85+ }
86+
87+ @ Override
88+ public OMClientResponse validateAndUpdateCache (OzoneManager ozoneManager ,
89+ long transactionLogIndex ) {
90+ S3DeleteBucketRequest s3DeleteBucketRequest =
91+ getOmRequest ().getDeleteS3BucketRequest ();
92+
93+ String s3BucketName = s3DeleteBucketRequest .getS3BucketName ();
94+
95+ OMResponse .Builder omResponse = OMResponse .newBuilder ().setCmdType (
96+ OzoneManagerProtocolProtos .Type .DeleteS3Bucket ).setStatus (
97+ OzoneManagerProtocolProtos .Status .OK ).setSuccess (true );
98+
99+ OMMetrics omMetrics = ozoneManager .getMetrics ();
100+ omMetrics .incNumS3BucketDeletes ();
101+ IOException exception = null ;
102+ boolean acquiredS3Lock = false ;
103+ boolean acquiredBucketLock = false ;
104+ String volumeName = null ;
105+ OMMetadataManager omMetadataManager = ozoneManager .getMetadataManager ();
106+ try {
107+ // check Acl
108+ if (ozoneManager .getAclsEnabled ()) {
109+ checkAcls (ozoneManager , OzoneObj .ResourceType .BUCKET ,
110+ OzoneObj .StoreType .S3 , IAccessAuthorizer .ACLType .DELETE , null ,
111+ s3BucketName , null );
112+ }
113+
114+ acquiredS3Lock = omMetadataManager .getLock ().acquireLock (S3_BUCKET_LOCK ,
115+ s3BucketName );
116+
117+ String s3Mapping = omMetadataManager .getS3Table ().get (s3BucketName );
118+
119+ if (s3Mapping == null ) {
120+ throw new OMException ("S3Bucket " + s3BucketName + " not found" ,
121+ OMException .ResultCodes .S3_BUCKET_NOT_FOUND );
122+ } else {
123+ volumeName = getOzoneVolumeName (s3Mapping );
124+
125+ acquiredBucketLock =
126+ omMetadataManager .getLock ().acquireLock (BUCKET_LOCK , volumeName ,
127+ s3BucketName );
128+
129+ String bucketKey = omMetadataManager .getBucketKey (volumeName ,
130+ s3BucketName );
131+
132+ // Update bucket table cache and s3 table cache.
133+ omMetadataManager .getBucketTable ().addCacheEntry (
134+ new CacheKey <>(bucketKey ),
135+ new CacheValue <>(Optional .absent (), transactionLogIndex ));
136+ omMetadataManager .getS3Table ().addCacheEntry (
137+ new CacheKey <>(s3BucketName ),
138+ new CacheValue <>(Optional .absent (), transactionLogIndex ));
139+ }
140+ } catch (IOException ex ) {
141+ exception = ex ;
142+ } finally {
143+ if (acquiredBucketLock ) {
144+ omMetadataManager .getLock ().releaseLock (BUCKET_LOCK , volumeName ,
145+ s3BucketName );
146+ }
147+ if (acquiredS3Lock ) {
148+ omMetadataManager .getLock ().releaseLock (S3_BUCKET_LOCK , s3BucketName );
149+ }
150+ }
151+
152+ // Performing audit logging outside of the lock.
153+ auditLog (ozoneManager .getAuditLogger (),
154+ buildAuditMessage (OMAction .DELETE_S3_BUCKET ,
155+ buildAuditMap (s3BucketName ), exception ,
156+ getOmRequest ().getUserInfo ()));
157+
158+ if (exception == null ) {
159+ // Decrement s3 bucket and ozone bucket count. As S3 bucket is mapped to
160+ // ozonevolume/ozone bucket.
161+ LOG .debug ("S3Bucket {} successfully deleted" , s3BucketName );
162+ omMetrics .decNumS3Buckets ();
163+ omMetrics .decNumBuckets ();
164+ omResponse .setDeleteS3BucketResponse (
165+ OzoneManagerProtocolProtos .S3DeleteBucketResponse .newBuilder ());
166+ return new S3BucketDeleteResponse (s3BucketName , volumeName ,
167+ omResponse .build ());
168+ } else {
169+ LOG .error ("S3Bucket Deletion failed for S3Bucket:{}" , s3BucketName ,
170+ exception );
171+ omMetrics .incNumS3BucketDeleteFails ();
172+ return new S3BucketDeleteResponse (null , null ,
173+ createErrorOMResponse (omResponse , exception ));
174+ }
175+ }
176+
177+ /**
178+ * Extract volumeName from s3Mapping.
179+ * @param s3Mapping
180+ * @return volumeName
181+ * @throws IOException
182+ */
183+ private String getOzoneVolumeName (String s3Mapping ) throws IOException {
184+ return s3Mapping .split ("/" )[0 ];
185+ }
186+
187+ private Map <String , String > buildAuditMap (String s3BucketName ) {
188+ Map <String , String > auditMap = new HashMap <>();
189+ auditMap .put (s3BucketName , OzoneConsts .S3_BUCKET );
190+ return auditMap ;
191+ }
192+
193+ }
0 commit comments