HBASE-15132 Master region merge RPC should authorize user request
This commit is contained in:
parent
772f30fe2a
commit
6ed3c759d0
|
@ -53,6 +53,16 @@ public abstract class BaseMasterAndRegionObserver extends BaseRegionObserver
|
||||||
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
|
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preCreateTableHandler(
|
public void preCreateTableHandler(
|
||||||
final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
|
|
@ -64,6 +64,16 @@ public class BaseMasterObserver implements MasterObserver {
|
||||||
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
|
HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
|
public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
TableName tableName) throws IOException {
|
TableName tableName) throws IOException {
|
||||||
|
|
|
@ -1217,4 +1217,25 @@ public interface MasterObserver extends Coprocessor {
|
||||||
*/
|
*/
|
||||||
void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
final String namespace, final Quotas quotas) throws IOException;
|
final String namespace, final Quotas quotas) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before dispatching region merge request.
|
||||||
|
* It can't bypass the default action, e.g., ctx.bypass() won't have effect.
|
||||||
|
* @param ctx coprocessor environment
|
||||||
|
* @param regionA first region to be merged
|
||||||
|
* @param regionB second region to be merged
|
||||||
|
* @throws IOException if an error occurred on the coprocessor
|
||||||
|
*/
|
||||||
|
public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called after dispatching the region merge request.
|
||||||
|
* @param c coprocessor environment
|
||||||
|
* @param regionA first region to be merged
|
||||||
|
* @param regionB second region to be merged
|
||||||
|
* @throws IOException if an error occurred on the coprocessor
|
||||||
|
*/
|
||||||
|
void postDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> c,
|
||||||
|
final HRegionInfo regionA, final HRegionInfo regionB) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -729,6 +729,28 @@ public class MasterCoprocessorHost
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void preDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
|
||||||
|
throws IOException {
|
||||||
|
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
|
||||||
|
@Override
|
||||||
|
public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
|
||||||
|
throws IOException {
|
||||||
|
oserver.preDispatchMerge(ctx, regionInfoA, regionInfoB);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postDispatchMerge(final HRegionInfo regionInfoA, final HRegionInfo regionInfoB)
|
||||||
|
throws IOException {
|
||||||
|
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
|
||||||
|
@Override
|
||||||
|
public void call(MasterObserver oserver, ObserverContext<MasterCoprocessorEnvironment> ctx)
|
||||||
|
throws IOException {
|
||||||
|
oserver.postDispatchMerge(ctx, regionInfoA, regionInfoB);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public boolean preBalance() throws IOException {
|
public boolean preBalance() throws IOException {
|
||||||
return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
|
return execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -514,8 +514,8 @@ public class MasterRpcServices extends RSRpcServices
|
||||||
"Unable to merge regions not online " + regionStateA + ", " + regionStateB));
|
"Unable to merge regions not online " + regionStateA + ", " + regionStateB));
|
||||||
}
|
}
|
||||||
|
|
||||||
HRegionInfo regionInfoA = regionStateA.getRegion();
|
final HRegionInfo regionInfoA = regionStateA.getRegion();
|
||||||
HRegionInfo regionInfoB = regionStateB.getRegion();
|
final HRegionInfo regionInfoB = regionStateB.getRegion();
|
||||||
if (regionInfoA.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID ||
|
if (regionInfoA.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID ||
|
||||||
regionInfoB.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID) {
|
regionInfoB.getReplicaId() != HRegionInfo.DEFAULT_REPLICA_ID) {
|
||||||
throw new ServiceException(new MergeRegionException("Can't merge non-default replicas"));
|
throw new ServiceException(new MergeRegionException("Can't merge non-default replicas"));
|
||||||
|
@ -524,6 +524,11 @@ public class MasterRpcServices extends RSRpcServices
|
||||||
throw new ServiceException(new MergeRegionException(
|
throw new ServiceException(new MergeRegionException(
|
||||||
"Unable to merge a region to itself " + regionInfoA + ", " + regionInfoB));
|
"Unable to merge a region to itself " + regionInfoA + ", " + regionInfoB));
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
master.cpHost.preDispatchMerge(regionInfoA, regionInfoB);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ServiceException(ioe);
|
||||||
|
}
|
||||||
|
|
||||||
if (!forcible && !HRegionInfo.areAdjacent(regionInfoA, regionInfoB)) {
|
if (!forcible && !HRegionInfo.areAdjacent(regionInfoA, regionInfoB)) {
|
||||||
throw new ServiceException(new MergeRegionException(
|
throw new ServiceException(new MergeRegionException(
|
||||||
|
@ -535,6 +540,7 @@ public class MasterRpcServices extends RSRpcServices
|
||||||
|
|
||||||
try {
|
try {
|
||||||
master.dispatchMergingRegions(regionInfoA, regionInfoB, forcible);
|
master.dispatchMergingRegions(regionInfoA, regionInfoB, forcible);
|
||||||
|
master.cpHost.postDispatchMerge(regionInfoA, regionInfoB);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new ServiceException(ioe);
|
throw new ServiceException(ioe);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2529,6 +2529,13 @@ public class AccessController extends BaseMasterAndRegionObserver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
requirePermission("mergeRegions", regionA.getTable(), null, null,
|
||||||
|
Action.ADMIN);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx, Region regionA,
|
public void preMerge(ObserverContext<RegionServerCoprocessorEnvironment> ctx, Region regionA,
|
||||||
Region regionB) throws IOException {
|
Region regionB) throws IOException {
|
||||||
|
|
|
@ -25,6 +25,7 @@ import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
@ -44,6 +45,9 @@ import org.apache.hadoop.hbase.ProcedureInfo;
|
||||||
import org.apache.hadoop.hbase.ServerName;
|
import org.apache.hadoop.hbase.ServerName;
|
||||||
import org.apache.hadoop.hbase.TableName;
|
import org.apache.hadoop.hbase.TableName;
|
||||||
import org.apache.hadoop.hbase.client.Admin;
|
import org.apache.hadoop.hbase.client.Admin;
|
||||||
|
import org.apache.hadoop.hbase.client.Connection;
|
||||||
|
import org.apache.hadoop.hbase.client.ConnectionFactory;
|
||||||
|
import org.apache.hadoop.hbase.client.HTable;
|
||||||
import org.apache.hadoop.hbase.client.RegionLocator;
|
import org.apache.hadoop.hbase.client.RegionLocator;
|
||||||
import org.apache.hadoop.hbase.client.Table;
|
import org.apache.hadoop.hbase.client.Table;
|
||||||
import org.apache.hadoop.hbase.master.AssignmentManager;
|
import org.apache.hadoop.hbase.master.AssignmentManager;
|
||||||
|
@ -167,6 +171,8 @@ public class TestMasterObserver {
|
||||||
private boolean postGetTableDescriptorsCalled;
|
private boolean postGetTableDescriptorsCalled;
|
||||||
private boolean postGetTableNamesCalled;
|
private boolean postGetTableNamesCalled;
|
||||||
private boolean preGetTableNamesCalled;
|
private boolean preGetTableNamesCalled;
|
||||||
|
private boolean preDispatchMergeCalled;
|
||||||
|
private boolean postDispatchMergeCalled;
|
||||||
|
|
||||||
public void enableBypass(boolean bypass) {
|
public void enableBypass(boolean bypass) {
|
||||||
this.bypass = bypass;
|
this.bypass = bypass;
|
||||||
|
@ -249,6 +255,24 @@ public class TestMasterObserver {
|
||||||
postGetTableDescriptorsCalled = false;
|
postGetTableDescriptorsCalled = false;
|
||||||
postGetTableNamesCalled = false;
|
postGetTableNamesCalled = false;
|
||||||
preGetTableNamesCalled = false;
|
preGetTableNamesCalled = false;
|
||||||
|
preDispatchMergeCalled = false;
|
||||||
|
postDispatchMergeCalled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
preDispatchMergeCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
|
||||||
|
HRegionInfo regionA, HRegionInfo regionB) throws IOException {
|
||||||
|
postDispatchMergeCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasDispatchMergeCalled() {
|
||||||
|
return preDispatchMergeCalled && postDispatchMergeCalled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1347,10 +1371,12 @@ public class TestMasterObserver {
|
||||||
// create a table
|
// create a table
|
||||||
HTableDescriptor htd = new HTableDescriptor(tableName);
|
HTableDescriptor htd = new HTableDescriptor(tableName);
|
||||||
htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
|
htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
|
||||||
Admin admin = UTIL.getHBaseAdmin();
|
try(Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
|
||||||
|
Admin admin = connection.getAdmin()) {
|
||||||
tableCreationLatch = new CountDownLatch(1);
|
tableCreationLatch = new CountDownLatch(1);
|
||||||
admin.createTable(htd);
|
admin.createTable(htd, Arrays.copyOfRange(HBaseTestingUtility.KEYS,
|
||||||
|
1, HBaseTestingUtility.KEYS.length));
|
||||||
|
|
||||||
// preCreateTable can't bypass default action.
|
// preCreateTable can't bypass default action.
|
||||||
assertTrue("Test table should be created", cp.wasCreateTableCalled());
|
assertTrue("Test table should be created", cp.wasCreateTableCalled());
|
||||||
tableCreationLatch.await();
|
tableCreationLatch.await();
|
||||||
|
@ -1359,6 +1385,14 @@ public class TestMasterObserver {
|
||||||
assertTrue("Table create handler should be called.",
|
assertTrue("Table create handler should be called.",
|
||||||
cp.wasCreateTableHandlerCalled());
|
cp.wasCreateTableHandlerCalled());
|
||||||
|
|
||||||
|
RegionLocator regionLocator = connection.getRegionLocator(htd.getTableName());
|
||||||
|
List<HRegionLocation> regions = regionLocator.getAllRegionLocations();
|
||||||
|
|
||||||
|
admin.mergeRegions(regions.get(0).getRegionInfo().getEncodedNameAsBytes(),
|
||||||
|
regions.get(1).getRegionInfo().getEncodedNameAsBytes(), true);
|
||||||
|
assertTrue("Coprocessor should have been called on region merge",
|
||||||
|
cp.wasDispatchMergeCalled());
|
||||||
|
|
||||||
tableCreationLatch = new CountDownLatch(1);
|
tableCreationLatch = new CountDownLatch(1);
|
||||||
admin.disableTable(tableName);
|
admin.disableTable(tableName);
|
||||||
assertTrue(admin.isTableDisabled(tableName));
|
assertTrue(admin.isTableDisabled(tableName));
|
||||||
|
@ -1497,6 +1531,7 @@ public class TestMasterObserver {
|
||||||
assertTrue("Delete table handler should be called.",
|
assertTrue("Delete table handler should be called.",
|
||||||
cp.wasDeleteTableHandlerCalled());
|
cp.wasDeleteTableHandlerCalled());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test (timeout=180000)
|
@Test (timeout=180000)
|
||||||
public void testSnapshotOperations() throws Exception {
|
public void testSnapshotOperations() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue