Skip to content

Commit 217e748

Browse files
HDDS-1973. Implement OM RenewDelegationToken request to use Cache and DoubleBuffer. (#1316)
1 parent 93595fe commit 217e748

File tree

6 files changed

+262
-4
lines changed

6 files changed

+262
-4
lines changed

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,30 @@ public synchronized long renewToken(Token<OzoneTokenIdentifier> token,
251251
}
252252

253253
long renewTime = Math.min(id.getMaxDate(), now + getTokenRenewInterval());
254-
try {
255-
addToTokenStore(id, token.getPassword(), renewTime);
256-
} catch (IOException e) {
257-
LOG.error("Unable to update token " + id.getSequenceNumber(), e);
254+
255+
// For HA ratis will take care of updating.
256+
// This will be removed, when HA/Non-HA code is merged.
257+
if (!isRatisEnabled) {
258+
try {
259+
addToTokenStore(id, token.getPassword(), renewTime);
260+
} catch (IOException e) {
261+
LOG.error("Unable to update token " + id.getSequenceNumber(), e);
262+
}
258263
}
259264
return renewTime;
260265
}
261266

267+
public void updateRenewToken(Token<OzoneTokenIdentifier> token,
268+
OzoneTokenIdentifier ozoneTokenIdentifier, long expiryTime) {
269+
//TODO: Instead of having in-memory map inside this class, we can use
270+
// cache from table and make this table cache clean up policy NEVER. In
271+
// this way, we don't need to maintain seperate in-memory map. To do this
272+
// work we need to merge HA/Non-HA code.
273+
TokenInfo tokenInfo = new TokenInfo(expiryTime, token.getPassword(),
274+
ozoneTokenIdentifier.getTrackingId());
275+
currentTokens.put(ozoneTokenIdentifier, tokenInfo);
276+
}
277+
262278
/**
263279
* Cancel a token by removing it from store and cache.
264280
*

hadoop-ozone/common/src/main/proto/OzoneManagerProtocol.proto

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ message OMRequest {
143143
optional hadoop.common.RenewDelegationTokenRequestProto renewDelegationTokenRequest= 62;
144144
optional hadoop.common.CancelDelegationTokenRequestProto cancelDelegationTokenRequest = 63;
145145
optional UpdateGetDelegationTokenRequest updateGetDelegationTokenRequest = 64;
146+
optional UpdateRenewDelegationTokenRequest updatedRenewDelegationTokenRequest = 65;
146147

147148
optional GetFileStatusRequest getFileStatusRequest = 70;
148149
optional CreateDirectoryRequest createDirectoryRequest = 71;
@@ -317,6 +318,17 @@ message UpdateGetDelegationTokenRequest {
317318
required GetDelegationTokenResponseProto getDelegationTokenResponse = 1;
318319
}
319320

321+
/**
322+
This will be used during OM HA, once leader renews token, sends this
323+
request via ratis to persist to OM DB. This request will be internally used
324+
by OM for replicating renewed token information across a quorum of OMs.
325+
*/
326+
message UpdateRenewDelegationTokenRequest {
327+
required hadoop.common.RenewDelegationTokenRequestProto
328+
renewDelegationTokenRequest = 1;
329+
required RenewDelegationTokenResponseProto renewDelegationTokenResponse = 2;
330+
}
331+
320332
/**
321333
Creates a volume
322334
*/

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@
4646
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadAbortRequest;
4747
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCommitPartRequest;
4848
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCompleteRequest;
49+
import org.apache.hadoop.ozone.om.request.security.OMCancelDelegationTokenRequest;
4950
import org.apache.hadoop.ozone.om.request.security.OMGetDelegationTokenRequest;
51+
import org.apache.hadoop.ozone.om.request.security.OMRenewDelegationTokenRequest;
5052
import org.apache.hadoop.ozone.om.request.volume.OMVolumeCreateRequest;
5153
import org.apache.hadoop.ozone.om.request.volume.OMVolumeDeleteRequest;
5254
import org.apache.hadoop.ozone.om.request.volume.OMVolumeSetOwnerRequest;
@@ -136,6 +138,10 @@ public static OMClientRequest createClientRequest(OMRequest omRequest) {
136138
return getOMAclRequest(omRequest);
137139
case GetDelegationToken:
138140
return new OMGetDelegationTokenRequest(omRequest);
141+
case CancelDelegationToken:
142+
return new OMCancelDelegationTokenRequest(omRequest);
143+
case RenewDelegationToken:
144+
return new OMRenewDelegationTokenRequest(omRequest);
139145
default:
140146
// TODO: will update once all request types are implemented.
141147
return null;
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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.security;
20+
21+
import java.io.IOException;
22+
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
import com.google.common.base.Optional;
27+
import org.apache.hadoop.ozone.om.OMMetadataManager;
28+
import org.apache.hadoop.ozone.om.OzoneManager;
29+
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
30+
import org.apache.hadoop.ozone.om.request.OMClientRequest;
31+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
32+
import org.apache.hadoop.ozone.om.response.security.OMRenewDelegationTokenResponse;
33+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
34+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
35+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
36+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenewDelegationTokenResponseProto;
37+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UpdateRenewDelegationTokenRequest;
38+
import org.apache.hadoop.ozone.protocolPB.OMPBHelper;
39+
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
40+
import org.apache.hadoop.security.proto.SecurityProtos.RenewDelegationTokenRequestProto;
41+
import org.apache.hadoop.security.token.Token;
42+
import org.apache.hadoop.utils.db.cache.CacheKey;
43+
import org.apache.hadoop.utils.db.cache.CacheValue;
44+
45+
/**
46+
* Handle RenewDelegationToken Request.
47+
*/
48+
public class OMRenewDelegationTokenRequest extends OMClientRequest {
49+
50+
private static final Logger LOG =
51+
LoggerFactory.getLogger(OMRenewDelegationTokenRequest.class);
52+
53+
public OMRenewDelegationTokenRequest(OMRequest omRequest) {
54+
super(omRequest);
55+
}
56+
57+
@Override
58+
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
59+
RenewDelegationTokenRequestProto renewDelegationTokenRequest =
60+
getOmRequest().getRenewDelegationTokenRequest();
61+
62+
// Call OM to renew token
63+
long renewTime = ozoneManager.renewDelegationToken(
64+
OMPBHelper.convertToDelegationToken(
65+
renewDelegationTokenRequest.getToken()));
66+
67+
RenewDelegationTokenResponseProto.Builder renewResponse =
68+
RenewDelegationTokenResponseProto.newBuilder();
69+
70+
renewResponse.setResponse(org.apache.hadoop.security.proto.SecurityProtos
71+
.RenewDelegationTokenResponseProto.newBuilder()
72+
.setNewExpiryTime(renewTime));
73+
74+
75+
// Client issues RenewDelegationToken request, when received by OM leader
76+
// it will renew the token. Original RenewDelegationToken request is
77+
// converted to UpdateRenewDelegationToken request with the token and renew
78+
// information. This updated request will be submitted to Ratis. In this
79+
// way delegation token renewd by leader, will be replicated across all
80+
// OMs. With this approach, original RenewDelegationToken request from
81+
// client does not need any proto changes.
82+
83+
// Create UpdateRenewDelegationTokenRequest with original request and
84+
// expiry time.
85+
OMRequest.Builder omRequest = OMRequest.newBuilder()
86+
.setUserInfo(getUserInfo())
87+
.setUpdatedRenewDelegationTokenRequest(
88+
UpdateRenewDelegationTokenRequest.newBuilder()
89+
.setRenewDelegationTokenRequest(renewDelegationTokenRequest)
90+
.setRenewDelegationTokenResponse(renewResponse))
91+
.setCmdType(getOmRequest().getCmdType())
92+
.setClientId(getOmRequest().getClientId());
93+
94+
if (getOmRequest().hasTraceID()) {
95+
omRequest.setTraceID(getOmRequest().getTraceID());
96+
}
97+
98+
return omRequest.build();
99+
}
100+
101+
@Override
102+
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
103+
long transactionLogIndex,
104+
OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
105+
106+
UpdateRenewDelegationTokenRequest updateRenewDelegationTokenRequest =
107+
getOmRequest().getUpdatedRenewDelegationTokenRequest();
108+
109+
Token<OzoneTokenIdentifier> ozoneTokenIdentifierToken =
110+
OMPBHelper.convertToDelegationToken(updateRenewDelegationTokenRequest
111+
.getRenewDelegationTokenRequest().getToken());
112+
113+
long renewTime = updateRenewDelegationTokenRequest
114+
.getRenewDelegationTokenResponse().getResponse().getNewExpiryTime();
115+
116+
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
117+
118+
OMClientResponse omClientResponse = null;
119+
OMResponse.Builder omResponse =
120+
OMResponse.newBuilder()
121+
.setCmdType(OzoneManagerProtocolProtos.Type.RenewDelegationToken)
122+
.setStatus(OzoneManagerProtocolProtos.Status.OK)
123+
.setSuccess(true);
124+
try {
125+
126+
OzoneTokenIdentifier ozoneTokenIdentifier =
127+
ozoneTokenIdentifierToken.decodeIdentifier();
128+
129+
// Update in memory map of token.
130+
ozoneManager.getDelegationTokenMgr()
131+
.updateRenewToken(ozoneTokenIdentifierToken, ozoneTokenIdentifier,
132+
renewTime);
133+
134+
// Update Cache.
135+
omMetadataManager.getDelegationTokenTable().addCacheEntry(
136+
new CacheKey<>(ozoneTokenIdentifier),
137+
new CacheValue<>(Optional.of(renewTime), transactionLogIndex));
138+
139+
omClientResponse =
140+
new OMRenewDelegationTokenResponse(ozoneTokenIdentifier, renewTime,
141+
omResponse.setRenewDelegationTokenResponse(
142+
updateRenewDelegationTokenRequest
143+
.getRenewDelegationTokenResponse()).build());
144+
} catch (IOException ex) {
145+
LOG.error("Error in Updating Renew DelegationToken {}",
146+
ozoneTokenIdentifierToken, ex);
147+
omClientResponse = new OMRenewDelegationTokenResponse(null, -1L,
148+
createErrorOMResponse(omResponse, ex));
149+
} finally {
150+
if (omClientResponse != null) {
151+
omClientResponse.setFlushFuture(
152+
ozoneManagerDoubleBufferHelper.add(omClientResponse,
153+
transactionLogIndex));
154+
}
155+
}
156+
157+
if (LOG.isDebugEnabled()) {
158+
LOG.debug("Updated renew delegation token in-memory map: {} with expiry" +
159+
" time {}", ozoneTokenIdentifierToken, renewTime);
160+
}
161+
162+
return omClientResponse;
163+
}
164+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.response.security;
20+
21+
import org.apache.hadoop.ozone.om.OMMetadataManager;
22+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
23+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
24+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
25+
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
26+
import org.apache.hadoop.utils.db.BatchOperation;
27+
import org.apache.hadoop.utils.db.Table;
28+
29+
import javax.annotation.Nonnull;
30+
import javax.annotation.Nullable;
31+
import java.io.IOException;
32+
33+
/**
34+
* Handle response for RenewDelegationToken request.
35+
*/
36+
public class OMRenewDelegationTokenResponse extends OMClientResponse {
37+
38+
private OzoneTokenIdentifier ozoneTokenIdentifier;
39+
private long renewTime = -1L;
40+
41+
public OMRenewDelegationTokenResponse(
42+
@Nullable OzoneTokenIdentifier ozoneTokenIdentifier,
43+
long renewTime, @Nonnull OMResponse omResponse) {
44+
super(omResponse);
45+
this.ozoneTokenIdentifier = ozoneTokenIdentifier;
46+
this.renewTime = renewTime;
47+
}
48+
49+
@Override
50+
public void addToDBBatch(OMMetadataManager omMetadataManager,
51+
BatchOperation batchOperation) throws IOException {
52+
Table table = omMetadataManager.getDelegationTokenTable();
53+
if (getOMResponse().getStatus() == OzoneManagerProtocolProtos.Status.OK) {
54+
table.putWithBatch(batchOperation, ozoneTokenIdentifier, renewTime);
55+
}
56+
}
57+
}
58+

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerHARequestHandlerImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ public OMResponse handleApplyTransaction(OMRequest omRequest,
7575
case RemoveAcl:
7676
case SetAcl:
7777
case GetDelegationToken:
78+
case CancelDelegationToken:
79+
case RenewDelegationToken:
7880
//TODO: We don't need to pass transactionID, this will be removed when
7981
// complete write requests is changed to new model. And also we can
8082
// return OMClientResponse, then adding to doubleBuffer can be taken

0 commit comments

Comments
 (0)