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.client; 019 020import java.io.IOException; 021import java.nio.file.Files; 022import java.nio.file.Path; 023import java.nio.file.Paths; 024import java.nio.file.StandardCopyOption; 025import org.apache.hadoop.hbase.HBaseTestingUtility; 026import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030/** 031 * Base class to test Configuration Update logic. It wraps up things needed to test configuration 032 * change and provides utility methods for test cluster setup, updating/restoring configuration 033 * file. 034 */ 035public abstract class AbstractTestUpdateConfiguration { 036 private static final Logger LOG = LoggerFactory.getLogger(AbstractTestUpdateConfiguration.class); 037 038 private static final String SERVER_CONFIG = "hbase-site.xml"; 039 private static final String OVERRIDE_SERVER_CONFIG = "override-hbase-site.xml"; 040 private static final String BACKUP_SERVER_CONFIG = "backup-hbase-site.xml"; 041 042 private static Path configFileUnderTestDataDir; 043 private static Path overrideConfigFileUnderTestDataDir; 044 private static Path backupConfigFileUnderTestDataDir; 045 046 protected static void setUpConfigurationFiles(final HBaseTestingUtility testUtil) 047 throws Exception { 048 // Before this change, the test will update hbase-site.xml under target/test-classes and 049 // trigger a config reload. Since target/test-classes/hbase-site.xml is being used by 050 // other testing cases at the same time, this update will break other testing cases so it will 051 // be flakey in nature. 052 // To avoid this, the change is to make target/test-classes/hbase-site.xml immutable. A new 053 // hbase-site.xml will be created under its test data directory, i.e, 054 // hbase-server/target/test-data/UUID, this new file will be added as a resource for the 055 // config, new update will be applied to this new file and only visible to this specific test 056 // case. The target/test-classes/hbase-site.xml will not be changed during the test. 057 058 String absoluteDataPath = testUtil.getDataTestDir().toString(); 059 060 // Create test-data directories. 061 Files.createDirectories(Paths.get(absoluteDataPath)); 062 063 // Copy hbase-site.xml from target/test-class to target/test-data/UUID directory. 064 Path configFile = Paths.get("target", "test-classes", SERVER_CONFIG); 065 configFileUnderTestDataDir = Paths.get(absoluteDataPath, SERVER_CONFIG); 066 Files.copy(configFile, configFileUnderTestDataDir); 067 068 // Copy override config file overrider-hbase-site.xml from target/test-class to 069 // target/test-data/UUID directory. 070 Path overrideConfigFile = Paths.get("target", "test-classes", OVERRIDE_SERVER_CONFIG); 071 overrideConfigFileUnderTestDataDir = Paths.get(absoluteDataPath, OVERRIDE_SERVER_CONFIG); 072 Files.copy(overrideConfigFile, overrideConfigFileUnderTestDataDir); 073 074 backupConfigFileUnderTestDataDir = Paths.get(absoluteDataPath, BACKUP_SERVER_CONFIG); 075 076 // Add the new custom config file to Configuration 077 testUtil.getConfiguration().addResource(testUtil.getDataTestDir(SERVER_CONFIG)); 078 } 079 080 protected static void addResourceToRegionServerConfiguration(final HBaseTestingUtility testUtil) { 081 // When RegionServer is created in MiniHBaseCluster, it uses HBaseConfiguration.create(conf) of 082 // the master Configuration. The create() just copies config params over, it does not do 083 // a clone for a historic reason. Properties such as resources are lost during this process. 084 // Exposing a new method in HBaseConfiguration causes confusion. Instead, the new hbase-site.xml 085 // under test-data directory is added to RegionServer's configuration as a workaround. 086 for (RegionServerThread rsThread : testUtil.getMiniHBaseCluster().getRegionServerThreads()) { 087 rsThread.getRegionServer().getConfiguration() 088 .addResource(testUtil.getDataTestDir(SERVER_CONFIG)); 089 } 090 } 091 092 /** 093 * Replace the hbase-site.xml file under this test's data directory with the content of the 094 * override-hbase-site.xml file. Stashes the current existing file so that it can be restored 095 * using {@link #restoreHBaseSiteXML()}. 096 * @throws IOException if an I/O error occurs 097 */ 098 protected final void replaceHBaseSiteXML() throws IOException { 099 LOG.info("Replace hbase config {} with {}", configFileUnderTestDataDir, 100 overrideConfigFileUnderTestDataDir); 101 // make a backup of hbase-site.xml 102 Files.copy(configFileUnderTestDataDir, backupConfigFileUnderTestDataDir, 103 StandardCopyOption.REPLACE_EXISTING); 104 // update hbase-site.xml by overwriting it 105 Files.copy(overrideConfigFileUnderTestDataDir, configFileUnderTestDataDir, 106 StandardCopyOption.REPLACE_EXISTING); 107 } 108 109 /** 110 * Restores the hbase-site.xml file that was stashed by a previous call to 111 * {@link #replaceHBaseSiteXML()}. 112 * @throws IOException if an I/O error occurs 113 */ 114 protected final void restoreHBaseSiteXML() throws IOException { 115 LOG.info("Restore hbase config {} with {}", configFileUnderTestDataDir, 116 backupConfigFileUnderTestDataDir); 117 // restore hbase-site.xml 118 Files.copy(backupConfigFileUnderTestDataDir, configFileUnderTestDataDir, 119 StandardCopyOption.REPLACE_EXISTING); 120 } 121}