Skip to content

Commit 1f92fb5

Browse files
committed
HBASE-22271 Implement grant/revoke/delete table acls/delete namespace acls in Procedure
1 parent ada772a commit 1f92fb5

35 files changed

+1240
-854
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/client/Admin.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,14 +2140,47 @@ void cloneTableSchema(TableName tableName, TableName newTableName, boolean prese
21402140
* permissions.
21412141
* @throws IOException if a remote or network exception occurs
21422142
*/
2143-
void grant(UserPermission userPermission, boolean mergeExistingPermissions) throws IOException;
2143+
default void grant(UserPermission userPermission, boolean mergeExistingPermissions)
2144+
throws IOException {
2145+
get(grantAsync(userPermission, mergeExistingPermissions));
2146+
}
2147+
2148+
/**
2149+
* Grants user specific permissions but does not block. You can use Future.get(long, TimeUnit) to
2150+
* wait on the operation to complete. It may throw ExecutionException if there was an error while
2151+
* executing the operation or TimeoutException in case the wait timeout was not long enough to
2152+
* allow the operation to complete.
2153+
* @param userPermission user name and the specific permission
2154+
* @param mergeExistingPermissions If set to false, later granted permissions will override
2155+
* previous granted permissions. otherwise, it'll merge with previous granted
2156+
* permissions.
2157+
* @throws IOException if a remote or network exception occurs
2158+
* @return the result of the async creation. You can use Future.get(long, TimeUnit) to wait on the
2159+
* operation to complete.
2160+
*/
2161+
Future<Void> grantAsync(UserPermission userPermission, boolean mergeExistingPermissions)
2162+
throws IOException;
21442163

21452164
/**
21462165
* Revokes user specific permissions
21472166
* @param userPermission user name and the specific permission
21482167
* @throws IOException if a remote or network exception occurs
21492168
*/
2150-
void revoke(UserPermission userPermission) throws IOException;
2169+
default void revoke(UserPermission userPermission) throws IOException {
2170+
get(revokeAsync(userPermission));
2171+
}
2172+
2173+
/**
2174+
* Revokes user specific permissions but does not block. You can use Future.get(long, TimeUnit) to
2175+
* wait on the operation to complete. It may throw ExecutionException if there was an error while
2176+
* executing the operation or TimeoutException in case the wait timeout was not long enough to
2177+
* allow the operation to complete.
2178+
* @param userPermission user name and the specific permission
2179+
* @throws IOException if a remote or network exception occurs
2180+
* @return the result of the async creation. You can use Future.get(long, TimeUnit) to wait on the
2181+
* operation to complete.
2182+
*/
2183+
Future<Void> revokeAsync(UserPermission userPermission) throws IOException;
21512184

21522185
/**
21532186
* Get the global/namespace/table permissions for user

hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3837,30 +3837,71 @@ protected SpaceQuotaSnapshot rpcCall() throws Exception {
38373837
});
38383838
}
38393839

3840+
@InterfaceAudience.Private
3841+
@InterfaceStability.Evolving
3842+
private class UpdatePermissionFuture extends ProcedureFuture<Void> {
3843+
private final UserPermission userPermission;
3844+
private final Supplier<String> getOperation;
3845+
3846+
public UpdatePermissionFuture(HBaseAdmin admin, UserPermission userPermission, Long procId,
3847+
Supplier<String> getOperation) {
3848+
super(admin, procId);
3849+
this.userPermission = userPermission;
3850+
this.getOperation = getOperation;
3851+
}
3852+
3853+
@Override
3854+
public String toString() {
3855+
return "Operation: " + getOperation.get() + ", userPermission: " + userPermission;
3856+
}
3857+
}
3858+
3859+
@InterfaceAudience.Private
3860+
@InterfaceStability.Evolving
3861+
private class GrantFuture extends UpdatePermissionFuture {
3862+
private final boolean mergeExistingPermissions;
3863+
3864+
public GrantFuture(HBaseAdmin admin, UserPermission userPermission,
3865+
boolean mergeExistingPermissions, Long procId, Supplier<String> getOperation) {
3866+
super(admin, userPermission, procId, getOperation);
3867+
this.mergeExistingPermissions = mergeExistingPermissions;
3868+
}
3869+
3870+
@Override
3871+
public String toString() {
3872+
return super.toString() + ", mergeExistingPermissions: " + mergeExistingPermissions;
3873+
}
3874+
}
3875+
38403876
@Override
3841-
public void grant(UserPermission userPermission, boolean mergeExistingPermissions)
3877+
public Future<Void> grantAsync(UserPermission userPermission, boolean mergeExistingPermissions)
38423878
throws IOException {
3843-
executeCallable(new MasterCallable<Void>(getConnection(), getRpcControllerFactory()) {
3844-
@Override
3845-
protected Void rpcCall() throws Exception {
3846-
GrantRequest req =
3847-
ShadedAccessControlUtil.buildGrantRequest(userPermission, mergeExistingPermissions);
3848-
this.master.grant(getRpcController(), req);
3849-
return null;
3850-
}
3851-
});
3879+
AccessControlProtos.GrantResponse response =
3880+
executeCallable(new MasterCallable<AccessControlProtos.GrantResponse>(getConnection(),
3881+
getRpcControllerFactory()) {
3882+
@Override
3883+
protected AccessControlProtos.GrantResponse rpcCall() throws Exception {
3884+
GrantRequest req =
3885+
ShadedAccessControlUtil.buildGrantRequest(userPermission, mergeExistingPermissions);
3886+
return this.master.grant(getRpcController(), req);
3887+
}
3888+
});
3889+
return new GrantFuture(this, userPermission, mergeExistingPermissions, response.getProcId(),
3890+
() -> "GRANT");
38523891
}
38533892

38543893
@Override
3855-
public void revoke(UserPermission userPermission) throws IOException {
3856-
executeCallable(new MasterCallable<Void>(getConnection(), getRpcControllerFactory()) {
3857-
@Override
3858-
protected Void rpcCall() throws Exception {
3859-
RevokeRequest req = ShadedAccessControlUtil.buildRevokeRequest(userPermission);
3860-
this.master.revoke(getRpcController(), req);
3861-
return null;
3862-
}
3863-
});
3894+
public Future<Void> revokeAsync(UserPermission userPermission) throws IOException {
3895+
AccessControlProtos.RevokeResponse response =
3896+
executeCallable(new MasterCallable<AccessControlProtos.RevokeResponse>(getConnection(),
3897+
getRpcControllerFactory()) {
3898+
@Override
3899+
protected AccessControlProtos.RevokeResponse rpcCall() throws Exception {
3900+
RevokeRequest req = ShadedAccessControlUtil.buildRevokeRequest(userPermission);
3901+
return this.master.revoke(getRpcController(), req);
3902+
}
3903+
});
3904+
return new UpdatePermissionFuture(this, userPermission, response.getProcId(), () -> "REVOKE");
38643905
}
38653906

38663907
@Override

hbase-client/src/main/java/org/apache/hadoop/hbase/client/RawAsyncHBaseAdmin.java

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3832,20 +3832,18 @@ public CompletableFuture<SpaceQuotaSnapshot> getCurrentSpaceQuotaSnapshot(TableN
38323832
@Override
38333833
public CompletableFuture<Void> grant(UserPermission userPermission,
38343834
boolean mergeExistingPermissions) {
3835-
return this.<Void> newMasterCaller()
3836-
.action((controller, stub) -> this.<GrantRequest, GrantResponse, Void> call(controller,
3837-
stub, ShadedAccessControlUtil.buildGrantRequest(userPermission, mergeExistingPermissions),
3838-
(s, c, req, done) -> s.grant(c, req, done), resp -> null))
3839-
.call();
3835+
return this.<GrantRequest, GrantResponse> procedureCall(
3836+
ShadedAccessControlUtil.buildGrantRequest(userPermission, mergeExistingPermissions),
3837+
(s, c, req, done) -> s.grant(c, req, done), (resp) -> resp.getProcId(),
3838+
new GrantProcedureBiConsumer(userPermission, mergeExistingPermissions));
38403839
}
38413840

38423841
@Override
38433842
public CompletableFuture<Void> revoke(UserPermission userPermission) {
3844-
return this.<Void> newMasterCaller()
3845-
.action((controller, stub) -> this.<RevokeRequest, RevokeResponse, Void> call(controller,
3846-
stub, ShadedAccessControlUtil.buildRevokeRequest(userPermission),
3847-
(s, c, req, done) -> s.revoke(c, req, done), resp -> null))
3848-
.call();
3843+
return this.<RevokeRequest, RevokeResponse> procedureCall(
3844+
ShadedAccessControlUtil.buildRevokeRequest(userPermission),
3845+
(s, c, req, done) -> s.revoke(c, req, done), (resp) -> resp.getProcId(),
3846+
new RevokeProcedureBiConsumer(userPermission));
38493847
}
38503848

38513849
@Override
@@ -3873,4 +3871,58 @@ public CompletableFuture<List<Boolean>> hasUserPermissions(String userName,
38733871
resp -> resp.getHasUserPermissionList()))
38743872
.call();
38753873
}
3874+
3875+
private static abstract class UpdatePermissionProcedureBiConsumer extends ProcedureBiConsumer {
3876+
protected final UserPermission userPermission;
3877+
3878+
UpdatePermissionProcedureBiConsumer(UserPermission userPermission) {
3879+
this.userPermission = userPermission;
3880+
}
3881+
3882+
abstract String getOperationType();
3883+
3884+
String getDescription() {
3885+
return "Operation: " + getOperationType() + ", UserPermission: " + userPermission;
3886+
}
3887+
3888+
@Override
3889+
void onFinished() {
3890+
LOG.info(getDescription() + " completed");
3891+
}
3892+
3893+
@Override
3894+
void onError(Throwable error) {
3895+
LOG.info(getDescription() + " failed with " + error.getMessage());
3896+
}
3897+
}
3898+
3899+
private static class RevokeProcedureBiConsumer extends UpdatePermissionProcedureBiConsumer {
3900+
RevokeProcedureBiConsumer(UserPermission userPermission) {
3901+
super(userPermission);
3902+
}
3903+
3904+
@Override
3905+
String getOperationType() {
3906+
return "REVOKE";
3907+
}
3908+
}
3909+
3910+
private static class GrantProcedureBiConsumer extends UpdatePermissionProcedureBiConsumer {
3911+
protected final boolean mergeExistingPermissions;
3912+
3913+
GrantProcedureBiConsumer(UserPermission userPermission, boolean mergeExistingPermissions) {
3914+
super(userPermission);
3915+
this.mergeExistingPermissions = mergeExistingPermissions;
3916+
}
3917+
3918+
@Override
3919+
String getDescription() {
3920+
return super.getDescription() + ", mergeExistingPermissions: " + mergeExistingPermissions;
3921+
}
3922+
3923+
@Override
3924+
String getOperationType() {
3925+
return "GRANT";
3926+
}
3927+
}
38763928
}

hbase-procedure/src/main/java/org/apache/hadoop/hbase/procedure2/LockedResourceType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@
2222

2323
@InterfaceAudience.Private
2424
public enum LockedResourceType {
25-
SERVER, NAMESPACE, TABLE, REGION, PEER, META
25+
SERVER, NAMESPACE, TABLE, REGION, PEER, META, ACL
2626
}

hbase-protocol-shaded/src/main/protobuf/AccessControl.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,15 @@ message GrantRequest {
9090
}
9191

9292
message GrantResponse {
93+
optional uint64 proc_id = 1;
9394
}
9495

9596
message RevokeRequest {
9697
required UserPermission user_permission = 1;
9798
}
9899

99100
message RevokeResponse {
101+
optional uint64 proc_id = 1;
100102
}
101103

102104
message GetUserPermissionsRequest {

hbase-protocol-shaded/src/main/protobuf/MasterProcedure.proto

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ option java_generic_services = true;
2424
option java_generate_equals_and_hash = true;
2525
option optimize_for = SPEED;
2626

27+
import "AccessControl.proto";
2728
import "HBase.proto";
2829
import "RPC.proto";
2930
import "Snapshot.proto";
@@ -607,4 +608,20 @@ enum SplitWALState{
607608
ACQUIRE_SPLIT_WAL_WORKER = 1;
608609
DISPATCH_WAL_TO_WORKER = 2;
609610
RELEASE_SPLIT_WORKER = 3;
610-
}
611+
}
612+
613+
enum UpdatePermissionState {
614+
UPDATE_PERMISSION_STORAGE = 1;
615+
UPDATE_PERMISSION_CACHE_ON_RS = 2;
616+
POST_UPDATE_PERMISSION = 3;
617+
}
618+
619+
message UpdatePermissionStateData {
620+
required ServerName target_server = 1;
621+
required string entry = 2;
622+
}
623+
624+
message UpdatePermissionRemoteStateData {
625+
required ServerName target_server = 1;
626+
required string entry = 2;
627+
}

hbase-server/src/main/java/org/apache/hadoop/hbase/executor/EventType.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,14 @@ public enum EventType {
294294
*
295295
* RS_REPLAY_SYNC_REPLICATION_WAL
296296
*/
297-
RS_REPLAY_SYNC_REPLICATION_WAL(85, ExecutorType.RS_REPLAY_SYNC_REPLICATION_WAL);
297+
RS_REPLAY_SYNC_REPLICATION_WAL(85, ExecutorType.RS_REPLAY_SYNC_REPLICATION_WAL),
298+
299+
/**
300+
* RS refresh permission cache.<br>
301+
*
302+
* RS_REFRESH_PERMISSION_CACHE
303+
*/
304+
RS_REFRESH_PERMISSION_CACHE(86, ExecutorType.RS_REFRESH_PERMISSION_CACHE);
298305

299306
private final int code;
300307
private final ExecutorType executor;

hbase-server/src/main/java/org/apache/hadoop/hbase/executor/ExecutorType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public enum ExecutorType {
5050
RS_REFRESH_PEER(31),
5151
RS_REPLAY_SYNC_REPLICATION_WAL(32),
5252
RS_SWITCH_RPC_THROTTLE(33),
53-
RS_IN_MEMORY_COMPACTION(34);
53+
RS_IN_MEMORY_COMPACTION(34),
54+
RS_REFRESH_PERMISSION_CACHE(35);
5455

5556
ExecutorType(int value) {
5657
}

hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Map;
3333
import java.util.Map.Entry;
34+
import java.util.Optional;
3435
import java.util.Set;
3536
import java.util.stream.Collectors;
3637
import org.apache.hadoop.conf.Configuration;
@@ -52,7 +53,6 @@
5253
import org.apache.hadoop.hbase.client.RegionInfo;
5354
import org.apache.hadoop.hbase.client.RegionInfoBuilder;
5455
import org.apache.hadoop.hbase.client.Result;
55-
import org.apache.hadoop.hbase.client.Table;
5656
import org.apache.hadoop.hbase.client.TableDescriptor;
5757
import org.apache.hadoop.hbase.client.TableState;
5858
import org.apache.hadoop.hbase.client.VersionInfoUtil;
@@ -77,6 +77,7 @@
7777
import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
7878
import org.apache.hadoop.hbase.master.procedure.MasterProcedureUtil;
7979
import org.apache.hadoop.hbase.master.procedure.MasterProcedureUtil.NonceProcedureRunnable;
80+
import org.apache.hadoop.hbase.master.procedure.ProcedurePrepareLatch;
8081
import org.apache.hadoop.hbase.master.procedure.ServerCrashProcedure;
8182
import org.apache.hadoop.hbase.mob.MobUtils;
8283
import org.apache.hadoop.hbase.procedure.MasterProcedureManager;
@@ -107,6 +108,7 @@
107108
import org.apache.hadoop.hbase.security.access.Permission.Action;
108109
import org.apache.hadoop.hbase.security.access.PermissionStorage;
109110
import org.apache.hadoop.hbase.security.access.ShadedAccessControlUtil;
111+
import org.apache.hadoop.hbase.security.access.UpdatePermissionProcedure;
110112
import org.apache.hadoop.hbase.security.access.UserPermission;
111113
import org.apache.hadoop.hbase.security.visibility.VisibilityController;
112114
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
@@ -2727,14 +2729,13 @@ public GrantResponse grant(RpcController controller, GrantRequest request)
27272729
if (master.cpHost != null) {
27282730
master.cpHost.preGrant(perm, mergeExistingPermissions);
27292731
}
2730-
try (Table table = master.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) {
2731-
PermissionStorage.addUserPermission(getConfiguration(), perm, table,
2732-
mergeExistingPermissions);
2733-
}
2734-
if (master.cpHost != null) {
2735-
master.cpHost.postGrant(perm, mergeExistingPermissions);
2736-
}
2737-
return GrantResponse.getDefaultInstance();
2732+
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(2, 2);
2733+
UpdatePermissionProcedure procedure = new UpdatePermissionProcedure(
2734+
UpdatePermissionProcedure.UpdatePermissionType.GRANT, master.getServerName(),
2735+
Optional.of(perm), Optional.of(mergeExistingPermissions), Optional.empty(), latch);
2736+
long procId = master.getMasterProcedureExecutor().submitProcedure(procedure);
2737+
latch.await();
2738+
return GrantResponse.newBuilder().setProcId(procId).build();
27382739
} catch (IOException ioe) {
27392740
throw new ServiceException(ioe);
27402741
}
@@ -2749,13 +2750,13 @@ public RevokeResponse revoke(RpcController controller, RevokeRequest request)
27492750
if (master.cpHost != null) {
27502751
master.cpHost.preRevoke(userPermission);
27512752
}
2752-
try (Table table = master.getConnection().getTable(PermissionStorage.ACL_TABLE_NAME)) {
2753-
PermissionStorage.removeUserPermission(master.getConfiguration(), userPermission, table);
2754-
}
2755-
if (master.cpHost != null) {
2756-
master.cpHost.postRevoke(userPermission);
2757-
}
2758-
return RevokeResponse.getDefaultInstance();
2753+
ProcedurePrepareLatch latch = ProcedurePrepareLatch.createLatch(2, 2);
2754+
UpdatePermissionProcedure procedure = new UpdatePermissionProcedure(
2755+
UpdatePermissionProcedure.UpdatePermissionType.REVOKE, master.getServerName(),
2756+
Optional.of(userPermission), Optional.empty(), Optional.empty(), latch);
2757+
long procId = master.getMasterProcedureExecutor().submitProcedure(procedure);
2758+
latch.await();
2759+
return RevokeResponse.newBuilder().setProcId(procId).build();
27592760
} catch (IOException ioe) {
27602761
throw new ServiceException(ioe);
27612762
}

0 commit comments

Comments
 (0)