HBASE-11344 Hide row keys and such from the web UIs

This commit is contained in:
Devaraj Das 2014-07-02 13:07:11 -07:00
parent 15831cefd5
commit 9f8d1876a0
7 changed files with 210 additions and 11 deletions

View File

@ -261,4 +261,13 @@
<Bug pattern="FE_FLOATING_POINT_EQUALITY"/>
</Match>
<Match>
<Class name="org.apache.hadoop.hbase.HRegionInfo"/>
<Or>
<Method name="getEndKeyForDisplay"/>
<Method name="getStartKeyForDisplay"/>
</Or>
<Bug pattern="MS_EXPOSE_REP"/>
</Match>
</FindBugsFilter>

View File

@ -33,9 +33,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.KeyValue.KVComparator;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
@ -220,6 +222,9 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
// Current TableName
private TableName tableName = null;
final static String DISPLAY_KEYS_KEY = "hbase.display.keys";
public final static byte[] HIDDEN_END_KEY = Bytes.toBytes("hidden-end-key");
public final static byte[] HIDDEN_START_KEY = Bytes.toBytes("hidden-start-key");
/** HRegionInfo for first meta region */
public static final HRegionInfo FIRST_META_REGIONINFO =
@ -1122,6 +1127,104 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
return ProtobufUtil.toDelimitedByteArray(convert());
}
/**
* Get the descriptive name as {@link RegionState} does it but with hidden
* startkey optionally
* @param state
* @param conf
* @return descriptive string
*/
public static String getDescriptiveNameFromRegionStateForDisplay(RegionState state,
Configuration conf) {
if (conf.getBoolean(DISPLAY_KEYS_KEY, true)) return state.toDescriptiveString();
String descriptiveStringFromState = state.toDescriptiveString();
int idx = descriptiveStringFromState.lastIndexOf(" state=");
String regionName = getRegionNameAsStringForDisplay(state.getRegion(), conf);
return regionName + descriptiveStringFromState.substring(idx);
}
/**
* Get the end key for display. Optionally hide the real end key.
* @param hri
* @param conf
* @return the endkey
*/
public static byte[] getEndKeyForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey) return hri.getEndKey();
return HIDDEN_END_KEY;
}
/**
* Get the start key for display. Optionally hide the real start key.
* @param hri
* @param conf
* @return the startkey
*/
public static byte[] getStartKeyForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey) return hri.getStartKey();
return HIDDEN_START_KEY;
}
/**
* Get the region name for display. Optionally hide the start key.
* @param hri
* @param conf
* @return region name as String
*/
public static String getRegionNameAsStringForDisplay(HRegionInfo hri, Configuration conf) {
return Bytes.toStringBinary(getRegionNameForDisplay(hri, conf));
}
/**
* Get the region name for display. Optionally hide the start key.
* @param hri
* @param conf
* @return region name bytes
*/
public static byte[] getRegionNameForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey || hri.getTable().equals(TableName.META_TABLE_NAME)) {
return hri.getRegionName();
} else {
// create a modified regionname with the startkey replaced but preserving
// the other parts including the encodedname.
try {
byte[][]regionNameParts = parseRegionName(hri.getRegionName());
regionNameParts[1] = HIDDEN_START_KEY; //replace the real startkey
int len = 0;
// get the total length
for (byte[] b : regionNameParts) {
len += b.length;
}
byte[] encodedRegionName =
Bytes.toBytes(encodeRegionName(hri.getRegionName()));
len += encodedRegionName.length;
//allocate some extra bytes for the delimiters and the last '.'
byte[] modifiedName = new byte[len + regionNameParts.length + 1];
int lengthSoFar = 0;
int loopCount = 0;
for (byte[] b : regionNameParts) {
System.arraycopy(b, 0, modifiedName, lengthSoFar, b.length);
lengthSoFar += b.length;
if (loopCount++ == 2) modifiedName[lengthSoFar++] = REPLICA_ID_DELIMITER;
else modifiedName[lengthSoFar++] = HConstants.DELIMITER;
}
// replace the last comma with '.'
modifiedName[lengthSoFar - 1] = ENC_SEPARATOR;
System.arraycopy(encodedRegionName, 0, modifiedName, lengthSoFar,
encodedRegionName.length);
lengthSoFar += encodedRegionName.length;
modifiedName[lengthSoFar] = ENC_SEPARATOR;
return modifiedName;
} catch (IOException e) {
//LOG.warn("Encountered exception " + e);
throw new RuntimeException(e);
}
}
}
/**
* Extract a HRegionInfo and ServerName from catalog table {@link Result}.
* @param r Result to pull from

View File

@ -836,6 +836,13 @@ possible configurations would overwhelm and obscure the important.
When false (the default), the client will not allow the fallback to SIMPLE
authentication, and will abort the connection.</description>
</property>
<property>
<name>hbase.display.keys</name>
<value>true</value>
<description>When this is set to true the webUI and such will display all start/end keys
as part of the table details, region names, etc. When this is set to false,
the keys are hidden.</description>
</property>
<property>
<name>hbase.coprocessor.region.classes</name>
<value></value>

View File

@ -85,7 +85,9 @@ if (toRemove > 0) {
<%else>
<tr>
</%if>
<td><% entry.getKey() %></td><td><% entry.getValue().toDescriptiveString() %></td>
<td><% entry.getKey() %></td><td>
<% HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(
entry.getValue(), conf) %></td>
<td><% (currentTime - entry.getValue().getStamp()) %> </td></tr>
</%for>
<tr BGCOLOR="#D7DF01"> <td>Total number of Regions in Transition for more than <% ritThreshold %> milliseconds</td><td> <% numOfRITOverThreshold %></td><td></td>

View File

@ -93,9 +93,12 @@
<%for HRegionInfo r: onlineRegions %>
<tr>
<td><% r.getRegionNameAsString() %></td>
<td><% Bytes.toStringBinary(r.getStartKey()) %></td>
<td><% Bytes.toStringBinary(r.getEndKey()) %></td>
<td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<td><% Bytes.toStringBinary(HRegionInfo.getStartKeyForDisplay(r,
regionServer.getConfiguration())) %></td>
<td><% Bytes.toStringBinary(HRegionInfo.getEndKeyForDisplay(r,
regionServer.getConfiguration())) %></td>
<td><% r.getReplicaId() %></td>
</tr>
</%for>
@ -119,7 +122,8 @@
<%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java>
<td><% r.getRegionNameAsString() %></td>
<td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %>
<td><% load.getReadRequestsCount() %></td>
<td><% load.getWriteRequestsCount() %></td>
@ -151,7 +155,8 @@
<%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java>
<td><% r.getRegionNameAsString() %></td>
<td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %>
<td><% load.getStores() %></td>
<td><% load.getStorefiles() %></td>
@ -189,7 +194,8 @@
((float) load.getCurrentCompactedKVs() / load.getTotalCompactingKVs())) + "%";
}
</%java>
<td><% r.getRegionNameAsString() %></td>
<td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %>
<td><% load.getTotalCompactingKVs() %></td>
<td><% load.getCurrentCompactedKVs() %></td>
@ -216,7 +222,8 @@
<%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java>
<td><% r.getRegionNameAsString() %></td>
<td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %>
<td><% load.getMemstoreSizeMB() %>m</td>
</%if>

View File

@ -283,7 +283,8 @@
}
%>
<tr>
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getRegionName())) %></td>
<td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getRegionNameForDisplay(regionInfo,
conf))) %></td>
<%
if (addr != null) {
String url = "//" + addr.getHostname() + ":" + master.getRegionServerInfoPort(addr) + "/";
@ -298,8 +299,10 @@
<%
}
%>
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getStartKey())) %></td>
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getEndKey())) %></td>
<td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getStartKeyForDisplay(regionInfo,
conf))) %></td>
<td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getEndKeyForDisplay(regionInfo,
conf))) %></td>
<td><%= req%></td>
<%
if (withReplica) {

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestingUtility;
@ -34,10 +35,12 @@ import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.MD5Hash;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@ -254,6 +257,71 @@ public class TestHRegionInfo {
assertEquals(expectedHri, convertedHri);
}
@Test
public void testRegionDetailsForDisplay() throws IOException {
byte[] startKey = new byte[] {0x01, 0x01, 0x02, 0x03};
byte[] endKey = new byte[] {0x01, 0x01, 0x02, 0x04};
Configuration conf = new Configuration();
conf.setBoolean("hbase.display.keys", false);
HRegionInfo h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey);
checkEquality(h, conf);
// check HRIs with non-default replicaId
h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey, false,
System.currentTimeMillis(), 1);
checkEquality(h, conf);
Assert.assertArrayEquals(HRegionInfo.HIDDEN_END_KEY,
HRegionInfo.getEndKeyForDisplay(h, conf));
Assert.assertArrayEquals(HRegionInfo.HIDDEN_START_KEY,
HRegionInfo.getStartKeyForDisplay(h, conf));
RegionState state = new RegionState(h, RegionState.State.OPEN);
String descriptiveNameForDisplay =
HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf);
checkDescriptiveNameEquality(descriptiveNameForDisplay,state.toDescriptiveString(), startKey);
conf.setBoolean("hbase.display.keys", true);
Assert.assertArrayEquals(endKey, HRegionInfo.getEndKeyForDisplay(h, conf));
Assert.assertArrayEquals(startKey, HRegionInfo.getStartKeyForDisplay(h, conf));
Assert.assertEquals(state.toDescriptiveString(),
HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf));
}
private void checkDescriptiveNameEquality(String descriptiveNameForDisplay, String origDesc,
byte[] startKey) {
// except for the "hidden-start-key" substring everything else should exactly match
String firstPart = descriptiveNameForDisplay.substring(0,
descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)));
String secondPart = descriptiveNameForDisplay.substring(
descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)) +
HRegionInfo.HIDDEN_START_KEY.length);
String firstPartOrig = origDesc.substring(0,
origDesc.indexOf(Bytes.toStringBinary(startKey)));
String secondPartOrig = origDesc.substring(
origDesc.indexOf(Bytes.toStringBinary(startKey)) +
Bytes.toStringBinary(startKey).length());
assert(firstPart.equals(firstPartOrig));
assert(secondPart.equals(secondPartOrig));
}
private void checkEquality(HRegionInfo h, Configuration conf) throws IOException {
byte[] modifiedRegionName = HRegionInfo.getRegionNameForDisplay(h, conf);
byte[][] modifiedRegionNameParts = HRegionInfo.parseRegionName(modifiedRegionName);
byte[][] regionNameParts = HRegionInfo.parseRegionName(h.getRegionName());
//same number of parts
assert(modifiedRegionNameParts.length == regionNameParts.length);
for (int i = 0; i < regionNameParts.length; i++) {
// all parts should match except for [1] where in the modified one,
// we should have "hidden_start_key"
if (i != 1) {
Assert.assertArrayEquals(regionNameParts[i], modifiedRegionNameParts[i]);
} else {
Assert.assertNotEquals(regionNameParts[i][0], modifiedRegionNameParts[i][0]);
Assert.assertArrayEquals(modifiedRegionNameParts[1],
HRegionInfo.getStartKeyForDisplay(h, conf));
}
}
}
}