1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.security.access;
20
21 import static org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint.Consumer;
22 import static org.junit.Assert.assertEquals;
23
24 import com.google.common.collect.Multimap;
25 import java.io.IOException;
26 import java.nio.ByteBuffer;
27 import java.util.Arrays;
28 import java.util.Deque;
29 import java.util.HashSet;
30 import java.util.Set;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.atomic.AtomicReference;
33
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.hadoop.conf.Configuration;
36 import org.apache.hadoop.fs.Path;
37 import org.apache.hadoop.hbase.Cell;
38 import org.apache.hadoop.hbase.DoNotRetryIOException;
39 import org.apache.hadoop.hbase.HBaseConfiguration;
40 import org.apache.hadoop.hbase.HBaseTestingUtility;
41 import org.apache.hadoop.hbase.HColumnDescriptor;
42 import org.apache.hadoop.hbase.HTableDescriptor;
43 import org.apache.hadoop.hbase.TableName;
44 import org.apache.hadoop.hbase.client.Connection;
45 import org.apache.hadoop.hbase.client.Get;
46 import org.apache.hadoop.hbase.client.Put;
47 import org.apache.hadoop.hbase.client.Result;
48 import org.apache.hadoop.hbase.client.Table;
49 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
50 import org.apache.hadoop.hbase.io.compress.Compression;
51 import org.apache.hadoop.hbase.io.crypto.Encryption;
52 import org.apache.hadoop.hbase.io.hfile.CacheConfig;
53 import org.apache.hadoop.hbase.io.hfile.HFile;
54 import org.apache.hadoop.hbase.io.hfile.HFileContext;
55 import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder;
56 import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
57 import org.apache.hadoop.hbase.regionserver.HStore;
58 import org.apache.hadoop.hbase.regionserver.Region;
59 import org.apache.hadoop.hbase.regionserver.StoreFile;
60 import org.apache.hadoop.hbase.testclassification.MediumTests;
61 import org.apache.hadoop.hbase.util.Bytes;
62 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
63 import org.apache.hadoop.hbase.util.Threads;
64 import org.junit.AfterClass;
65 import org.junit.Assert;
66 import org.junit.BeforeClass;
67 import org.junit.Test;
68 import org.junit.experimental.categories.Category;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72
73
74
75 @Category(MediumTests.class)
76 public class TestSecureBulkLoadEndpoint {
77
78 private static final Logger LOG =
79 LoggerFactory.getLogger(TestSecureBulkLoadEndpoint.class);
80
81 private static TableName TABLE = TableName.valueOf(Bytes.toBytes("TestSecureBulkLoadManager"));
82 private static byte[] FAMILY = Bytes.toBytes("family");
83 private static byte[] COLUMN = Bytes.toBytes("column");
84 private static byte[] key1 = Bytes.toBytes("row1");
85 private static byte[] key2 = Bytes.toBytes("row2");
86 private static byte[] key3 = Bytes.toBytes("row3");
87 private static byte[] value1 = Bytes.toBytes("t1");
88 private static byte[] value3 = Bytes.toBytes("t3");
89 private static byte[] SPLIT_ROWKEY = key2;
90
91 private Thread ealierBulkload;
92 private Thread laterBulkload;
93
94 protected final static HBaseTestingUtility testUtil = new HBaseTestingUtility();
95 private static Configuration conf = testUtil.getConfiguration();
96
97 @BeforeClass
98 public static void setUp() throws Exception {
99 conf.set(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,SecureBulkLoadEndpoint.class.getName());
100 testUtil.startMiniCluster();
101 }
102
103 @AfterClass
104 public static void tearDown() throws Exception {
105 testUtil.shutdownMiniCluster();
106 testUtil.cleanupTestDir();
107 }
108
109 @Test
110 public void testFileSystemsWithoutPermissionSupport() {
111 final Configuration emptyConf = new Configuration(false);
112 final Configuration defaultConf = HBaseConfiguration.create();
113
114 final Set<String> expectedDefaultIgnoredSchemes = new HashSet<>(
115 Arrays.asList(
116 StringUtils.split(SecureBulkLoadEndpoint.FS_WITHOUT_SUPPORT_PERMISSION_DEFAULT, ',')));
117
118 final SecureBulkLoadEndpoint endpoint = new SecureBulkLoadEndpoint();
119
120
121 Set<String> defaultIgnoredSchemes = endpoint.getFileSystemSchemesWithoutPermissionSupport(
122 emptyConf);
123 assertEquals(defaultIgnoredSchemes, expectedDefaultIgnoredSchemes);
124
125
126 defaultIgnoredSchemes = endpoint.getFileSystemSchemesWithoutPermissionSupport(defaultConf);
127 assertEquals(defaultIgnoredSchemes, expectedDefaultIgnoredSchemes);
128
129 defaultConf.set(SecureBulkLoadEndpoint.FS_WITHOUT_SUPPORT_PERMISSION_KEY, "foo,bar");
130 defaultIgnoredSchemes = endpoint.getFileSystemSchemesWithoutPermissionSupport(defaultConf);
131 assertEquals(defaultIgnoredSchemes, new HashSet<String>(Arrays.asList("foo", "bar")));
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145 @Test
146 public void testForRaceCondition() throws Exception {
147
148 testUtil.createTable(TABLE,FAMILY,Bytes.toByteArrays(SPLIT_ROWKEY));
149 testUtil.waitUntilAllRegionsAssigned(TABLE);
150
151 Consumer<Region> fsCreatedListener = new Consumer<Region>() {
152 @Override
153 public void accept(Region hRegion) {
154 if (hRegion.getRegionInfo().containsRow(key3)) {
155 Threads.shutdown(ealierBulkload);
156 }
157 }
158 };
159 SecureBulkLoadEndpoint.setFsCreatedListener(fsCreatedListener);
160
161
162 Path rootdir = testUtil.getMiniHBaseCluster().getRegionServerThreads().get(0)
163 .getRegionServer().getFileSystem().getHomeDirectory();
164 final Path dir1 = new Path(rootdir, "dir1");
165 prepareHFile(dir1, key1, value1);
166 final Path dir2 = new Path(rootdir, "dir2");
167 prepareHFile(dir2, key3, value3);
168
169
170 final AtomicReference<Throwable> t1Exception = new AtomicReference<>();
171 final AtomicReference<Throwable> t2Exception = new AtomicReference<>();
172 ealierBulkload = new Thread(new Runnable() {
173 @Override
174 public void run() {
175 try {
176 doBulkloadWithoutRetry(dir1);
177 } catch (Exception e) {
178 LOG.error("bulk load failed .",e);
179 t1Exception.set(e);
180 }
181 }
182 });
183 laterBulkload = new Thread(new Runnable() {
184 @Override
185 public void run() {
186 try {
187 doBulkloadWithoutRetry(dir2);
188 } catch (Exception e) {
189 LOG.error("bulk load failed .",e);
190 t2Exception.set(e);
191 }
192 }
193 });
194 ealierBulkload.start();
195 laterBulkload.start();
196 Threads.shutdown(ealierBulkload);
197 Threads.shutdown(laterBulkload);
198 Assert.assertNull(t1Exception.get());
199 Assert.assertNull(t2Exception.get());
200
201
202 Get get1 = new Get(key1);
203 Get get3 = new Get(key3);
204 Table t = testUtil.getConnection().getTable(TABLE);
205 Result r = t.get(get1);
206 Assert.assertArrayEquals(r.getValue(FAMILY, COLUMN), value1);
207 r = t.get(get3);
208 Assert.assertArrayEquals(r.getValue(FAMILY, COLUMN), value3);
209
210 }
211
212
213
214
215
216
217
218
219
220
221
222 class MyExceptionToAvoidRetry extends DoNotRetryIOException {
223 }
224
225 private void doBulkloadWithoutRetry(Path dir) throws Exception {
226 Connection connection = testUtil.getConnection();
227 LoadIncrementalHFiles h = new LoadIncrementalHFiles(conf) {
228 @Override
229 protected void bulkLoadPhase(final Table table, final Connection conn,
230 ExecutorService pool, Deque<LoadQueueItem> queue,
231 final Multimap<ByteBuffer, LoadQueueItem> regionGroups) throws IOException {
232 super.bulkLoadPhase(table, conn, pool, queue, regionGroups);
233 throw new MyExceptionToAvoidRetry();
234 }
235 };
236 try {
237 h.doBulkLoad(dir, testUtil.getHBaseAdmin(), connection.getTable(TABLE),
238 connection.getRegionLocator(TABLE));
239 Assert.fail("MyExceptionToAvoidRetry is expected");
240 } catch (MyExceptionToAvoidRetry e) {
241 }
242 }
243
244 private void prepareHFile(Path dir, byte[] key, byte[] value) throws Exception {
245 HTableDescriptor desc = testUtil.getHBaseAdmin().getTableDescriptor(TABLE);
246 HColumnDescriptor family = desc.getFamily(FAMILY);
247 Compression.Algorithm compression = HFile.DEFAULT_COMPRESSION_ALGORITHM;
248
249 CacheConfig writerCacheConf = new CacheConfig(conf, family);
250 writerCacheConf.setCacheDataOnWrite(false);
251 HFileContext hFileContext = new HFileContextBuilder()
252 .withIncludesMvcc(false)
253 .withIncludesTags(true)
254 .withCompression(compression)
255 .withCompressTags(family.isCompressTags())
256 .withChecksumType(HStore.getChecksumType(conf))
257 .withBytesPerCheckSum(HStore.getBytesPerChecksum(conf))
258 .withBlockSize(family.getBlocksize())
259 .withHBaseCheckSum(true)
260 .withDataBlockEncoding(family.getDataBlockEncoding())
261 .withEncryptionContext(Encryption.Context.NONE)
262 .withCreateTime(EnvironmentEdgeManager.currentTime())
263 .build();
264 StoreFile.WriterBuilder builder =
265 new StoreFile.WriterBuilder(conf, writerCacheConf, dir.getFileSystem(conf))
266 .withOutputDir(new Path(dir, family.getNameAsString()))
267 .withBloomType(family.getBloomFilterType())
268 .withMaxKeyCount(Integer.MAX_VALUE)
269 .withFileContext(hFileContext);
270 StoreFile.Writer writer = builder.build();
271
272 Put put = new Put(key);
273 put.addColumn(FAMILY, COLUMN, value);
274 for (Cell c : put.get(FAMILY, COLUMN)) {
275 writer.append(c);
276 }
277
278 writer.close();
279 }
280
281 }