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.zookeeper; 019 020import static org.junit.Assert.assertNotNull; 021import static org.junit.Assert.assertNull; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.util.List; 027import org.apache.hadoop.conf.Configuration; 028import org.apache.hadoop.hbase.Abortable; 029import org.apache.hadoop.hbase.HBaseClassTestRule; 030import org.apache.hadoop.hbase.HBaseZKTestingUtility; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.testclassification.ZKTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.apache.hadoop.hbase.util.Threads; 035import org.apache.zookeeper.CreateMode; 036import org.apache.zookeeper.KeeperException; 037import org.apache.zookeeper.ZooDefs; 038import org.apache.zookeeper.ZooKeeper; 039import org.apache.zookeeper.data.ACL; 040import org.apache.zookeeper.data.Stat; 041import org.junit.AfterClass; 042import org.junit.BeforeClass; 043import org.junit.ClassRule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 050 051@Category({ ZKTests.class, MediumTests.class }) 052public class TestZKUtil { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestZKUtil.class); 057 058 private static final Logger LOG = LoggerFactory.getLogger(TestZKUtil.class); 059 060 private static HBaseZKTestingUtility UTIL = new HBaseZKTestingUtility(); 061 062 private static ZKWatcher ZKW; 063 064 @BeforeClass 065 public static void setUp() throws Exception { 066 UTIL.startMiniZKCluster().getClientPort(); 067 ZKW = new ZKWatcher(new Configuration(UTIL.getConfiguration()), TestZKUtil.class.getName(), 068 new WarnOnlyAbortable()); 069 070 } 071 072 @AfterClass 073 public static void tearDown() throws IOException { 074 Closeables.close(ZKW, true); 075 UTIL.shutdownMiniZKCluster(); 076 UTIL.cleanupTestDir(); 077 } 078 079 /** 080 * Create a znode with data 081 */ 082 @Test 083 public void testCreateWithParents() throws KeeperException, InterruptedException { 084 byte[] expectedData = new byte[] { 1, 2, 3 }; 085 ZKUtil.createWithParents(ZKW, "/l1/l2/l3/l4/testCreateWithParents", expectedData); 086 byte[] data = ZKUtil.getData(ZKW, "/l1/l2/l3/l4/testCreateWithParents"); 087 assertTrue(Bytes.equals(expectedData, data)); 088 ZKUtil.deleteNodeRecursively(ZKW, "/l1"); 089 090 ZKUtil.createWithParents(ZKW, "/testCreateWithParents", expectedData); 091 data = ZKUtil.getData(ZKW, "/testCreateWithParents"); 092 assertTrue(Bytes.equals(expectedData, data)); 093 ZKUtil.deleteNodeRecursively(ZKW, "/testCreateWithParents"); 094 } 095 096 /** 097 * Create a bunch of znodes in a hierarchy, try deleting one that has childs (it will fail), then 098 * delete it recursively, then delete the last znode 099 */ 100 @Test 101 public void testZNodeDeletes() throws Exception { 102 ZKUtil.createWithParents(ZKW, "/l1/l2/l3/l4"); 103 try { 104 ZKUtil.deleteNode(ZKW, "/l1/l2"); 105 fail("We should not be able to delete if znode has childs"); 106 } catch (KeeperException ex) { 107 assertNotNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2/l3/l4", null)); 108 } 109 ZKUtil.deleteNodeRecursively(ZKW, "/l1/l2"); 110 // make sure it really is deleted 111 assertNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2/l3/l4", null)); 112 113 // do the same delete again and make sure it doesn't crash 114 ZKUtil.deleteNodeRecursively(ZKW, "/l1/l2"); 115 116 ZKUtil.deleteNode(ZKW, "/l1"); 117 assertNull(ZKUtil.getDataNoWatch(ZKW, "/l1/l2", null)); 118 } 119 120 /** 121 * A test for HBASE-3238 122 * @throws IOException A connection attempt to zk failed 123 * @throws InterruptedException One of the non ZKUtil actions was interrupted 124 * @throws KeeperException Any of the zookeeper connections had a KeeperException 125 */ 126 @Test 127 public void testCreateSilentIsReallySilent() 128 throws InterruptedException, KeeperException, IOException { 129 Configuration c = UTIL.getConfiguration(); 130 131 String aclZnode = "/aclRoot"; 132 String quorumServers = ZKConfig.getZKQuorumServersString(c); 133 int sessionTimeout = 5 * 1000; // 5 seconds 134 ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance); 135 zk.addAuthInfo("digest", "hbase:rox".getBytes()); 136 137 // Save the previous ACL 138 Stat s = null; 139 List<ACL> oldACL = null; 140 while (true) { 141 try { 142 s = new Stat(); 143 oldACL = zk.getACL("/", s); 144 break; 145 } catch (KeeperException e) { 146 switch (e.code()) { 147 case CONNECTIONLOSS: 148 case SESSIONEXPIRED: 149 case OPERATIONTIMEOUT: 150 LOG.warn("Possibly transient ZooKeeper exception", e); 151 Threads.sleep(100); 152 break; 153 default: 154 throw e; 155 } 156 } 157 } 158 159 // I set this acl after the attempted creation of the cluster home node. 160 // Add retries in case of retryable zk exceptions. 161 while (true) { 162 try { 163 zk.setACL("/", ZooDefs.Ids.CREATOR_ALL_ACL, -1); 164 break; 165 } catch (KeeperException e) { 166 switch (e.code()) { 167 case CONNECTIONLOSS: 168 case SESSIONEXPIRED: 169 case OPERATIONTIMEOUT: 170 LOG.warn("Possibly transient ZooKeeper exception: " + e); 171 Threads.sleep(100); 172 break; 173 default: 174 throw e; 175 } 176 } 177 } 178 179 while (true) { 180 try { 181 zk.create(aclZnode, null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT); 182 break; 183 } catch (KeeperException e) { 184 switch (e.code()) { 185 case CONNECTIONLOSS: 186 case SESSIONEXPIRED: 187 case OPERATIONTIMEOUT: 188 LOG.warn("Possibly transient ZooKeeper exception: " + e); 189 Threads.sleep(100); 190 break; 191 default: 192 throw e; 193 } 194 } 195 } 196 zk.close(); 197 ZKUtil.createAndFailSilent(ZKW, aclZnode); 198 199 // Restore the ACL 200 ZooKeeper zk3 = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance); 201 zk3.addAuthInfo("digest", "hbase:rox".getBytes()); 202 try { 203 zk3.setACL("/", oldACL, -1); 204 } finally { 205 zk3.close(); 206 } 207 } 208 209 /** 210 * Test should not fail with NPE when getChildDataAndWatchForNewChildren invoked with wrongNode 211 */ 212 @Test 213 @SuppressWarnings("deprecation") 214 public void testGetChildDataAndWatchForNewChildrenShouldNotThrowNPE() throws Exception { 215 ZKUtil.getChildDataAndWatchForNewChildren(ZKW, "/wrongNode"); 216 } 217 218 private static class WarnOnlyAbortable implements Abortable { 219 220 @Override 221 public void abort(String why, Throwable e) { 222 LOG.warn("ZKWatcher received abort, ignoring. Reason: " + why); 223 if (LOG.isDebugEnabled()) { 224 LOG.debug(e.toString(), e); 225 } 226 } 227 228 @Override 229 public boolean isAborted() { 230 return false; 231 } 232 } 233}