1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.regionserver.wal;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23
24 import java.util.List;
25 import java.util.concurrent.atomic.AtomicLong;
26
27 import org.apache.commons.io.IOUtils;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.commons.logging.impl.Log4JLogger;
31 import org.apache.hadoop.conf.Configuration;
32 import org.apache.hadoop.fs.FSDataInputStream;
33 import org.apache.hadoop.fs.FileSystem;
34 import org.apache.hadoop.fs.Path;
35 import org.apache.hadoop.hbase.HBaseTestingUtility;
36 import org.apache.hadoop.hbase.HColumnDescriptor;
37 import org.apache.hadoop.hbase.HConstants;
38 import org.apache.hadoop.hbase.HRegionInfo;
39 import org.apache.hadoop.hbase.HTableDescriptor;
40 import org.apache.hadoop.hbase.KeyValue;
41 import org.apache.hadoop.hbase.MediumTests;
42 import org.apache.hadoop.hbase.TableName;
43 import org.apache.hadoop.hbase.io.crypto.KeyProviderForTesting;
44 import org.apache.hadoop.hbase.util.Bytes;
45 import org.apache.log4j.Level;
46
47 import org.junit.BeforeClass;
48 import org.junit.Test;
49 import org.junit.experimental.categories.Category;
50
51 @Category(MediumTests.class)
52 public class TestSecureHLog {
53 static final Log LOG = LogFactory.getLog(TestSecureHLog.class);
54 static {
55 ((Log4JLogger)LogFactory.getLog("org.apache.hadoop.hbase.regionserver.wal"))
56 .getLogger().setLevel(Level.ALL);
57 };
58 static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
59
60 @BeforeClass
61 public static void setUpBeforeClass() throws Exception {
62 Configuration conf = TEST_UTIL.getConfiguration();
63 conf.set(HConstants.CRYPTO_KEYPROVIDER_CONF_KEY, KeyProviderForTesting.class.getName());
64 conf.set(HConstants.CRYPTO_MASTERKEY_NAME_CONF_KEY, "hbase");
65 conf.setClass("hbase.regionserver.hlog.reader.impl", SecureProtobufLogReader.class,
66 HLog.Reader.class);
67 conf.setClass("hbase.regionserver.hlog.writer.impl", SecureProtobufLogWriter.class,
68 HLog.Writer.class);
69 conf.setBoolean(HConstants.ENABLE_WAL_ENCRYPTION, true);
70 }
71
72 @Test
73 public void testSecureHLog() throws Exception {
74 TableName tableName = TableName.valueOf("TestSecureHLog");
75 HTableDescriptor htd = new HTableDescriptor(tableName);
76 htd.addFamily(new HColumnDescriptor(tableName.getName()));
77 HRegionInfo regioninfo = new HRegionInfo(tableName,
78 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, false);
79 final int total = 10;
80 final byte[] row = Bytes.toBytes("row");
81 final byte[] family = Bytes.toBytes("family");
82 final byte[] value = Bytes.toBytes("Test value");
83 FileSystem fs = TEST_UTIL.getTestFileSystem();
84 Path logDir = TEST_UTIL.getDataTestDir("log");
85 final AtomicLong sequenceId = new AtomicLong(1);
86
87
88 HLog wal = new FSHLog(fs, TEST_UTIL.getDataTestDir(), logDir.toString(),
89 TEST_UTIL.getConfiguration());
90 for (int i = 0; i < total; i++) {
91 WALEdit kvs = new WALEdit();
92 kvs.add(new KeyValue(row, family, Bytes.toBytes(i), value));
93 wal.append(regioninfo, tableName, kvs, System.currentTimeMillis(), htd, sequenceId);
94 }
95 final Path walPath = ((FSHLog) wal).computeFilename();
96 wal.close();
97
98
99 long length = fs.getFileStatus(walPath).getLen();
100 FSDataInputStream in = fs.open(walPath);
101 byte[] fileData = new byte[(int)length];
102 IOUtils.readFully(in, fileData);
103 in.close();
104 assertFalse("Cells appear to be plaintext", Bytes.contains(fileData, value));
105
106
107 HLog.Reader reader = HLogFactory.createReader(TEST_UTIL.getTestFileSystem(), walPath,
108 TEST_UTIL.getConfiguration());
109 int count = 0;
110 HLog.Entry entry = new HLog.Entry();
111 while (reader.next(entry) != null) {
112 count++;
113 List<KeyValue> kvs = entry.getEdit().getKeyValues();
114 assertTrue("Should be one KV per WALEdit", kvs.size() == 1);
115 for (KeyValue kv: kvs) {
116 byte[] thisRow = kv.getRow();
117 assertTrue("Incorrect row", Bytes.equals(thisRow, row));
118 byte[] thisFamily = kv.getFamily();
119 assertTrue("Incorrect family", Bytes.equals(thisFamily, family));
120 byte[] thisValue = kv.getValue();
121 assertTrue("Incorrect value", Bytes.equals(thisValue, value));
122 }
123 }
124 assertEquals("Should have read back as many KVs as written", total, count);
125 reader.close();
126 }
127
128 }