001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.security.access; 019 020import static org.apache.hadoop.hbase.HConstants.HBASE_CLIENT_RETRIES_NUMBER; 021import static org.junit.jupiter.api.Assertions.assertThrows; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.io.IOException; 025import java.util.concurrent.TimeUnit; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.HBaseTestingUtil; 028import org.apache.hadoop.hbase.HConstants; 029import org.apache.hadoop.hbase.SingleProcessHBaseCluster; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.client.Admin; 032import org.apache.hadoop.hbase.client.Connection; 033import org.apache.hadoop.hbase.client.ConnectionFactory; 034import org.apache.hadoop.hbase.client.Put; 035import org.apache.hadoop.hbase.client.Table; 036import org.apache.hadoop.hbase.master.HMaster; 037import org.apache.hadoop.hbase.regionserver.HRegionServer; 038import org.apache.hadoop.hbase.testclassification.LargeTests; 039import org.apache.hadoop.hbase.testclassification.SecurityTests; 040import org.apache.hadoop.hbase.util.Bytes; 041import org.junit.jupiter.api.AfterEach; 042import org.junit.jupiter.api.BeforeEach; 043import org.junit.jupiter.api.Tag; 044import org.junit.jupiter.api.Test; 045import org.junit.jupiter.api.Timeout; 046 047@Tag(SecurityTests.TAG) 048@Tag(LargeTests.TAG) 049@SuppressWarnings("deprecation") 050public class TestReadOnlyControllerFlush { 051 052 private final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 053 private static final TableName TEST_TABLE = TableName.valueOf("read_only_flush_test_table"); 054 private static final byte[] TEST_FAMILY = Bytes.toBytes("read_only_flush_col_fam"); 055 private static HRegionServer hRegionServer; 056 private static HMaster hMaster; 057 private static Configuration conf; 058 private static Connection connection; 059 private static SingleProcessHBaseCluster cluster; 060 061 private static Table testTable; 062 063 @BeforeEach 064 public void beforeClass() throws Exception { 065 conf = TEST_UTIL.getConfiguration(); 066 067 // Shorten the run time of failed unit tests by limiting retries and the session timeout 068 // threshold 069 conf.setInt(HBASE_CLIENT_RETRIES_NUMBER, 1); 070 conf.setInt(HConstants.ZK_SESSION_TIMEOUT, 1000); 071 072 // Set up test class with Read-Only mode disabled so a table can be created 073 conf.setBoolean(HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY, false); 074 075 try { 076 // Start the test cluster 077 cluster = TEST_UTIL.startMiniCluster(1); 078 079 hMaster = cluster.getMaster(); 080 hRegionServer = cluster.getRegionServerThreads().get(0).getRegionServer(); 081 connection = ConnectionFactory.createConnection(conf); 082 083 // Create a test table and insert a row so the memstore has data to flush 084 testTable = TEST_UTIL.createTable(TEST_TABLE, TEST_FAMILY); 085 Put put = new Put(Bytes.toBytes("row1")); 086 put.addColumn(TEST_FAMILY, null, Bytes.toBytes("value1")); 087 testTable.put(put); 088 } catch (Exception e) { 089 disableReadOnlyMode(); 090 TEST_UTIL.deleteTable(TEST_TABLE); 091 if (connection != null) { 092 connection.close(); 093 } 094 TEST_UTIL.shutdownMiniCluster(); 095 throw new RuntimeException(e); 096 } 097 } 098 099 @AfterEach 100 public void afterClass() throws Exception { 101 if (connection != null) { 102 connection.close(); 103 } 104 TEST_UTIL.shutdownMiniCluster(); 105 } 106 107 private static void enableReadOnlyMode() { 108 SecureTestUtil.enableReadOnlyMode(conf, hMaster, hRegionServer); 109 } 110 111 private static void disableReadOnlyMode() { 112 SecureTestUtil.disableReadOnlyMode(conf, hMaster, hRegionServer); 113 } 114 115 @Test 116 public void testFlushTableWithReadOnlyDisabled() throws IOException { 117 disableReadOnlyMode(); 118 try (Admin admin = TEST_UTIL.getAdmin()) { 119 admin.flush(TEST_TABLE); 120 } 121 } 122 123 @Test 124 @Timeout(value = 60, unit = TimeUnit.SECONDS) 125 public void testCannotFlushTableWithReadOnlyEnabled() throws IOException { 126 enableReadOnlyMode(); 127 try (Admin admin = TEST_UTIL.getAdmin()) { 128 IOException exception = assertThrows(IOException.class, () -> { 129 admin.flush(TEST_TABLE); 130 }); 131 assertTrue(exception.getMessage().contains("Operation not allowed in Read-Only Mode")); 132 } 133 } 134}