From c6025e11953d55c3709cf98d411de4753bef14da Mon Sep 17 00:00:00 2001 From: Balazs Meszaros Date: Wed, 7 Jan 2026 15:42:08 +0100 Subject: [PATCH 1/2] HBASE-29764 Make client connection headers accessible inside co-processors --- .../hbase/coprocessor/CoprocessorHost.java | 67 ++++++++++++------- .../hbase/coprocessor/ObserverContext.java | 20 ++++-- .../coprocessor/ObserverContextImpl.java | 22 +++--- .../coprocessor/ObserverRpcCallContext.java | 44 ++++++++++++ .../ObserverRpcCallContextImpl.java | 44 ++++++++++++ .../apache/hadoop/hbase/ipc/RpcServer.java | 10 +++ .../hbase/master/MasterCoprocessorHost.java | 9 ++- .../regionserver/RegionCoprocessorHost.java | 16 ++++- .../security/access/AccessController.java | 3 +- .../SnapshotScannerHDFSAclController.java | 3 +- 10 files changed, 195 insertions(+), 43 deletions(-) create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContext.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContextImpl.java diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java index d98d809e893f..3aca2e04b8d2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java @@ -27,7 +27,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.UUID; -import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import org.apache.hadoop.conf.Configuration; @@ -492,20 +491,6 @@ protected void handleCoprocessorThrowable(final E env, final Throwable e) throws } } - /** - * Used to limit legacy handling to once per Coprocessor class per classloader. - */ - private static final Set> legacyWarning = - new ConcurrentSkipListSet<>(new Comparator>() { - @Override - public int compare(Class c1, Class c2) { - if (c1.equals(c2)) { - return 0; - } - return c1.getName().compareTo(c2.getName()); - } - }); - /** * Implementations defined function to get an observer of type {@code O} from a coprocessor of * type {@code C}. Concrete implementations of CoprocessorHost define one getter for each observer @@ -521,22 +506,45 @@ private abstract class ObserverOperation extends ObserverContextImpl { ObserverGetter observerGetter; ObserverOperation(ObserverGetter observerGetter) { - this(observerGetter, null); + this(observerGetter, (ObserverRpcCallContext) null); } ObserverOperation(ObserverGetter observerGetter, User user) { - this(observerGetter, user, false); + this(observerGetter, createRpcCallContext(user), false); + } + + ObserverOperation(ObserverGetter observerGetter, ObserverRpcCallContext rpcCallContext) { + this(observerGetter, rpcCallContext, false); } ObserverOperation(ObserverGetter observerGetter, boolean bypassable) { - this(observerGetter, null, bypassable); + this(observerGetter, (ObserverRpcCallContext) null, bypassable); } ObserverOperation(ObserverGetter observerGetter, User user, boolean bypassable) { - super(user != null ? user : RpcServer.getRequestUser().orElse(null), bypassable); + this(observerGetter, createRpcCallContext(user), bypassable); + } + + ObserverOperation(ObserverGetter observerGetter, ObserverRpcCallContext rpcCallContext, + boolean bypassable) { + super(rpcCallContext != null ? rpcCallContext : createRpcCallContext(), bypassable); this.observerGetter = observerGetter; } + private static ObserverRpcCallContext createRpcCallContext() { + return RpcServer.getRequestUser() + .map(user -> new ObserverRpcCallContextImpl(user, RpcServer.getConnectionAttributes())) + .orElse(null); + } + + private static ObserverRpcCallContext createRpcCallContext(User user) { + if (user == null) { + return null; + } else { + return new ObserverRpcCallContextImpl(user, RpcServer.getConnectionAttributes()); + } + } + abstract void callObserver() throws IOException; protected void postEnvCall() { @@ -557,11 +565,21 @@ public ObserverOperationWithoutResult(ObserverGetter observerGetter, User super(observerGetter, user); } + public ObserverOperationWithoutResult(ObserverGetter observerGetter, + ObserverRpcCallContext rpcCallContext) { + super(observerGetter, rpcCallContext); + } + public ObserverOperationWithoutResult(ObserverGetter observerGetter, User user, boolean bypassable) { super(observerGetter, user, bypassable); } + public ObserverOperationWithoutResult(ObserverGetter observerGetter, + ObserverRpcCallContext rpcCallContext, boolean bypassable) { + super(observerGetter, rpcCallContext, bypassable); + } + /** * In case of coprocessors which have many kinds of observers (for eg, {@link RegionCoprocessor} * has BulkLoadObserver, RegionObserver, etc), some implementations may not need all observers, @@ -590,13 +608,14 @@ public ObserverOperationWithResult(ObserverGetter observerGetter, R result this(observerGetter, result, null, bypassable); } - public ObserverOperationWithResult(ObserverGetter observerGetter, R result, User user) { - this(observerGetter, result, user, false); + public ObserverOperationWithResult(ObserverGetter observerGetter, R result, + ObserverRpcCallContext rpcCallContext) { + this(observerGetter, result, rpcCallContext, false); } - private ObserverOperationWithResult(ObserverGetter observerGetter, R result, User user, - boolean bypassable) { - super(observerGetter, user, bypassable); + private ObserverOperationWithResult(ObserverGetter observerGetter, R result, + ObserverRpcCallContext rpcCallContext, boolean bypassable) { + super(observerGetter, rpcCallContext, bypassable); this.result = result; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContext.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContext.java index c0fd791bcef8..e18f9aee6ef2 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContext.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContext.java @@ -70,10 +70,20 @@ public interface ObserverContext { void bypass(); /** - * Returns the active user for the coprocessor call. If an explicit {@code User} instance was - * provided to the constructor, that will be returned, otherwise if we are in the context of an - * RPC call, the remote user is used. May not be present if the execution is outside of an RPC - * context. + * Returns the {@link ObserverRpcCallContext} of an RPC call. May not be present if the execution + * is outside an RPC context. + * @return the context. */ - Optional getCaller(); + Optional getRpcCallContext(); + + /** + * Returns the active user for the coprocessor call. May not be present if the execution is + * outside an RPC context. + * @return the {@link User}. + * @deprecated will be removed in 4.0.0. Use {@link #getRpcCallContext()} instead. + */ + @Deprecated + default Optional getCaller() { + return getRpcCallContext().map(ObserverRpcCallContext::getUser); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContextImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContextImpl.java index a3a4a93005c0..5c878fdca8cc 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContextImpl.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverContextImpl.java @@ -17,6 +17,7 @@ */ package org.apache.hadoop.hbase.coprocessor; +import java.util.Map; import java.util.Optional; import org.apache.hadoop.hbase.CoprocessorEnvironment; import org.apache.hadoop.hbase.ipc.RpcServer; @@ -35,14 +36,14 @@ public class ObserverContextImpl implements Ob * Is this operation bypassable? */ private final boolean bypassable; - private final User caller; + private final ObserverRpcCallContext rpcCallContext; - public ObserverContextImpl(User caller) { - this(caller, false); + public ObserverContextImpl(ObserverRpcCallContext rpcCallContext) { + this(rpcCallContext, false); } - public ObserverContextImpl(User caller, boolean bypassable) { - this.caller = caller; + public ObserverContextImpl(ObserverRpcCallContext rpcCallContext, boolean bypassable) { + this.rpcCallContext = rpcCallContext; this.bypassable = bypassable; } @@ -83,8 +84,8 @@ public boolean shouldBypass() { } @Override - public Optional getCaller() { - return Optional.ofNullable(caller); + public Optional getRpcCallContext() { + return Optional.ofNullable(rpcCallContext); } /** @@ -98,8 +99,13 @@ public Optional getCaller() { @Deprecated // TODO: Remove this method, ObserverContext should not depend on RpcServer public static ObserverContext createAndPrepare(E env) { - ObserverContextImpl ctx = new ObserverContextImpl<>(RpcServer.getRequestUser().orElse(null)); + Optional user = RpcServer.getRequestUser(); + ObserverRpcCallContext rpcCallContext = + user.map(value -> new ObserverRpcCallContextImpl(value, Map.of())).orElse(null); + + ObserverContextImpl ctx = new ObserverContextImpl<>(rpcCallContext); ctx.prepare(env); + return ctx; } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContext.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContext.java new file mode 100644 index 000000000000..c5dc11969b40 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContext.java @@ -0,0 +1,44 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.hbase.coprocessor; + +import java.util.Map; +import org.apache.hadoop.hbase.HBaseInterfaceAudience; +import org.apache.hadoop.hbase.security.User; +import org.apache.yetus.audience.InterfaceAudience; +import org.apache.yetus.audience.InterfaceStability; + +/** + * RPC Call parameters for coprocessor context. + */ +@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC) +@InterfaceStability.Evolving +public interface ObserverRpcCallContext { + /** + * Returns the active user for the coprocessor call. + * @return the {@link User}, it must not be {@code null}. + */ + User getUser(); + + /** + * Returns the connection attributes for the coprocessor call. These parameters are passed by the + * client through {@code ConnectionHeader} protobuf. + * @return the attributes, it must not be {@code null}. + */ + Map getAttributes(); +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContextImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContextImpl.java new file mode 100644 index 000000000000..1979474922df --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/ObserverRpcCallContextImpl.java @@ -0,0 +1,44 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.hbase.coprocessor; + +import java.util.Map; +import java.util.Objects; +import org.apache.hadoop.hbase.security.User; +import org.apache.yetus.audience.InterfaceAudience; + +@InterfaceAudience.Private +public class ObserverRpcCallContextImpl implements ObserverRpcCallContext { + private final User user; + private final Map attributes; + + public ObserverRpcCallContextImpl(User user, Map attributes) { + this.user = Objects.requireNonNull(user, "user must not be null."); + this.attributes = Objects.requireNonNull(attributes, "attributes must not be null."); + } + + @Override + public User getUser() { + return user; + } + + @Override + public Map getAttributes() { + return attributes; + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java index 3fec4aa8da0d..189803f9e011 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/ipc/RpcServer.java @@ -799,6 +799,16 @@ public static Optional getRequestUser() { return ctx.isPresent() ? ctx.get().getRequestUser() : Optional.empty(); } + /** + * Returns the RPC connection attributes for the current RPC request. These attributes are sent by + * the client when initiating a new connection to the HBase server. The attributes are sent in + * {@code ConnectionHeader.attribute} protobuf message. + * @return the attribute map. It will be empty if the method is called outside of an RPC context. + */ + public static Map getConnectionAttributes() { + return getCurrentCall().map(RpcCall::getConnectionAttributes).orElse(Map.of()); + } + /** * The number of open RPC conections * @return the number of open rpc connections diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java index e3d269973f8f..ac183026eec3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterCoprocessorHost.java @@ -45,6 +45,7 @@ import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.MasterObserver; import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor; +import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContext; import org.apache.hadoop.hbase.master.locking.LockProcedure; import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; import org.apache.hadoop.hbase.metrics.MetricRegistry; @@ -202,8 +203,12 @@ public MasterObserverOperation(User user) { super(masterObserverGetter, user); } - public MasterObserverOperation(User user, boolean bypassable) { - super(masterObserverGetter, user, bypassable); + public MasterObserverOperation(ObserverRpcCallContext rpcCallContext) { + super(masterObserverGetter, rpcCallContext); + } + + public MasterObserverOperation(ObserverRpcCallContext rpcCallContext, boolean bypassable) { + super(masterObserverGetter, rpcCallContext, bypassable); } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java index b300496e1d7c..bc27dde57dc7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java @@ -58,6 +58,8 @@ import org.apache.hadoop.hbase.coprocessor.HasRegionServerServices; import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor; import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContext; +import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContextImpl; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.RegionObserver; @@ -500,13 +502,22 @@ public RegionObserverOperationWithoutResult(User user) { super(regionObserverGetter, user); } + public RegionObserverOperationWithoutResult(ObserverRpcCallContext rpcCallContext) { + super(regionObserverGetter, rpcCallContext); + } + public RegionObserverOperationWithoutResult(boolean bypassable) { - super(regionObserverGetter, null, bypassable); + super(regionObserverGetter, (ObserverRpcCallContext) null, bypassable); } public RegionObserverOperationWithoutResult(User user, boolean bypassable) { super(regionObserverGetter, user, bypassable); } + + public RegionObserverOperationWithoutResult(ObserverRpcCallContext rpcCallContext, + boolean bypassable) { + super(regionObserverGetter, rpcCallContext, bypassable); + } } abstract class BulkLoadObserverOperation @@ -677,8 +688,9 @@ public InternalScanner preCompact(final HStore store, final InternalScanner scan if (coprocEnvironments.isEmpty()) { return defaultResult; } + ObserverRpcCallContext rpcCallContext = new ObserverRpcCallContextImpl(user, Map.of()); return execOperationWithResult(new ObserverOperationWithResult( - regionObserverGetter, defaultResult, user) { + regionObserverGetter, defaultResult, rpcCallContext) { @Override public InternalScanner call(RegionObserver observer) throws IOException { InternalScanner scanner = diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index d03670543438..3b45e0175cc3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -81,6 +81,7 @@ import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.MasterObserver; import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContext; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.RegionObserver; @@ -2342,7 +2343,7 @@ public void preSwitchExceedThrottleQuota(ObserverContext ctx) throws IOException { // for non-rpc handling, fallback to system user - Optional optionalUser = ctx.getCaller(); + Optional optionalUser = ctx.getRpcCallContext().map(ObserverRpcCallContext::getUser); if (optionalUser.isPresent()) { return optionalUser.get(); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/SnapshotScannerHDFSAclController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/SnapshotScannerHDFSAclController.java index f4e4a4a9ffb3..a71c62313349 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/SnapshotScannerHDFSAclController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/SnapshotScannerHDFSAclController.java @@ -53,6 +53,7 @@ import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.MasterObserver; import org.apache.hadoop.hbase.coprocessor.ObserverContext; +import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContext; import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.security.User; import org.apache.hadoop.hbase.security.UserProvider; @@ -579,7 +580,7 @@ private boolean needHandleTableHdfsAcl(TableDescriptor tableDescriptor, String o private User getActiveUser(ObserverContext ctx) throws IOException { // for non-rpc handling, fallback to system user - Optional optionalUser = ctx.getCaller(); + Optional optionalUser = ctx.getRpcCallContext().map(ObserverRpcCallContext::getUser); if (optionalUser.isPresent()) { return optionalUser.get(); } From 6d28baf55daac007a95f015aa4dab6e2bf7eb8cb Mon Sep 17 00:00:00 2001 From: Balazs Meszaros Date: Thu, 8 Jan 2026 10:42:14 +0100 Subject: [PATCH 2/2] unit test fix --- .../hadoop/hbase/coprocessor/CoprocessorHost.java | 12 +++++++++++- .../hbase/regionserver/RegionCoprocessorHost.java | 4 +--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java index 3aca2e04b8d2..3d5897c0a056 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java @@ -605,7 +605,11 @@ public ObserverOperationWithResult(ObserverGetter observerGetter, R result public ObserverOperationWithResult(ObserverGetter observerGetter, R result, boolean bypassable) { - this(observerGetter, result, null, bypassable); + this(observerGetter, result, (ObserverRpcCallContext) null, bypassable); + } + + public ObserverOperationWithResult(ObserverGetter observerGetter, R result, User user) { + this(observerGetter, result, user, false); } public ObserverOperationWithResult(ObserverGetter observerGetter, R result, @@ -613,6 +617,12 @@ public ObserverOperationWithResult(ObserverGetter observerGetter, R result this(observerGetter, result, rpcCallContext, false); } + public ObserverOperationWithResult(ObserverGetter observerGetter, R result, User user, + boolean bypassable) { + super(observerGetter, user, bypassable); + this.result = result; + } + private ObserverOperationWithResult(ObserverGetter observerGetter, R result, ObserverRpcCallContext rpcCallContext, boolean bypassable) { super(observerGetter, rpcCallContext, bypassable); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java index bc27dde57dc7..edeb2993d77d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionCoprocessorHost.java @@ -59,7 +59,6 @@ import org.apache.hadoop.hbase.coprocessor.MetricsCoprocessor; import org.apache.hadoop.hbase.coprocessor.ObserverContext; import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContext; -import org.apache.hadoop.hbase.coprocessor.ObserverRpcCallContextImpl; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.coprocessor.RegionObserver; @@ -688,9 +687,8 @@ public InternalScanner preCompact(final HStore store, final InternalScanner scan if (coprocEnvironments.isEmpty()) { return defaultResult; } - ObserverRpcCallContext rpcCallContext = new ObserverRpcCallContextImpl(user, Map.of()); return execOperationWithResult(new ObserverOperationWithResult( - regionObserverGetter, defaultResult, rpcCallContext) { + regionObserverGetter, defaultResult, user) { @Override public InternalScanner call(RegionObserver observer) throws IOException { InternalScanner scanner =