1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertNull;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.conf.Configuration;
33  import org.apache.hadoop.hbase.client.Get;
34  import org.apache.hadoop.hbase.client.HBaseAdmin;
35  import org.apache.hadoop.hbase.client.HConnection;
36  import org.apache.hadoop.hbase.client.HConnectionManager;
37  import org.apache.hadoop.hbase.client.HTable;
38  import org.apache.hadoop.hbase.client.Put;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.zookeeper.ZKConfig;
41  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
42  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
43  import org.apache.zookeeper.CreateMode;
44  import org.apache.zookeeper.KeeperException;
45  import org.apache.zookeeper.ZooDefs;
46  import org.apache.zookeeper.ZooKeeper;
47  import org.apache.zookeeper.ZooKeeper.States;
48  import org.junit.AfterClass;
49  import org.junit.Assert;
50  import org.junit.Before;
51  import org.junit.BeforeClass;
52  import org.junit.Test;
53  
54  public class TestZooKeeper {
55    private final Log LOG = LogFactory.getLog(this.getClass());
56  
57    private final static HBaseTestingUtility
58        TEST_UTIL = new HBaseTestingUtility();
59  
60    /**
61     * @throws java.lang.Exception
62     */
63    @BeforeClass
64    public static void setUpBeforeClass() throws Exception {
65      // Test we can first start the ZK cluster by itself
66      TEST_UTIL.startMiniZKCluster();
67      TEST_UTIL.getConfiguration().setBoolean("dfs.support.append", true);
68      TEST_UTIL.startMiniCluster(2);
69    }
70  
71    /**
72     * @throws java.lang.Exception
73     */
74    @AfterClass
75    public static void tearDownAfterClass() throws Exception {
76      TEST_UTIL.shutdownMiniCluster();
77    }
78  
79    /**
80     * @throws java.lang.Exception
81     */
82    @Before
83    public void setUp() throws Exception {
84      TEST_UTIL.ensureSomeRegionServersAvailable(2);
85    }
86  
87    /**
88     * See HBASE-1232 and http://wiki.apache.org/hadoop/ZooKeeper/FAQ#4.
89     * @throws IOException
90     * @throws InterruptedException
91     */
92    @Test
93    public void testClientSessionExpired()
94    throws IOException, InterruptedException {
95      LOG.info("testClientSessionExpired");
96      Configuration c = new Configuration(TEST_UTIL.getConfiguration());
97      new HTable(c, HConstants.META_TABLE_NAME);
98      String quorumServers = ZKConfig.getZKQuorumServersString(c);
99      int sessionTimeout = 5 * 1000; // 5 seconds
100     HConnection connection = HConnectionManager.getConnection(c);
101     ZooKeeperWatcher connectionZK = connection.getZooKeeperWatcher();
102     long sessionID = connectionZK.getRecoverableZooKeeper().getSessionId();
103     byte[] password = connectionZK.getRecoverableZooKeeper().getSessionPasswd();
104     ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout,
105         EmptyWatcher.instance, sessionID, password);
106     LOG.info("Session timeout=" + zk.getSessionTimeout() +
107       ", original=" + sessionTimeout +
108       ", id=" + zk.getSessionId());
109     zk.close();
110 
111     Thread.sleep(sessionTimeout * 3L);
112 
113     // provoke session expiration by doing something with ZK
114     ZKUtil.dump(connectionZK);
115 
116     // Check that the old ZK connection is closed, means we did expire
117     System.err.println("ZooKeeper should have timed out");
118     String state = connectionZK.getRecoverableZooKeeper().getState().toString();
119     LOG.info("state=" + connectionZK.getRecoverableZooKeeper().getState());
120     Assert.assertTrue(connectionZK.getRecoverableZooKeeper().getState().
121       equals(States.CLOSED));
122 
123     // Check that the client recovered
124     ZooKeeperWatcher newConnectionZK = connection.getZooKeeperWatcher();
125     LOG.info("state=" + newConnectionZK.getRecoverableZooKeeper().getState());
126     Assert.assertTrue(newConnectionZK.getRecoverableZooKeeper().getState().equals(
127       States.CONNECTED));
128   }
129   
130   @Test
131   public void testRegionServerSessionExpired() throws Exception {
132     LOG.info("Starting testRegionServerSessionExpired");
133     int metaIndex = TEST_UTIL.getMiniHBaseCluster().getServerWithMeta();
134     TEST_UTIL.expireRegionServerSession(metaIndex);
135     testSanity();
136   }
137 
138   @Test
139   public void testMasterSessionExpired() throws Exception {
140     LOG.info("Starting testMasterSessionExpired");
141     TEST_UTIL.expireMasterSession();
142     testSanity();
143   }
144 
145   /**
146    * Make sure we can use the cluster
147    * @throws Exception
148    */
149   public void testSanity() throws Exception{
150     HBaseAdmin admin =
151       new HBaseAdmin(new Configuration(TEST_UTIL.getConfiguration()));
152     String tableName = "test"+System.currentTimeMillis();
153     HTableDescriptor desc = new HTableDescriptor(tableName);
154     HColumnDescriptor family = new HColumnDescriptor("fam");
155     desc.addFamily(family);
156     LOG.info("Creating table " + tableName);
157     admin.createTable(desc);
158 
159     HTable table =
160       new HTable(new Configuration(TEST_UTIL.getConfiguration()), tableName);
161     Put put = new Put(Bytes.toBytes("testrow"));
162     put.add(Bytes.toBytes("fam"),
163         Bytes.toBytes("col"), Bytes.toBytes("testdata"));
164     LOG.info("Putting table " + tableName);
165     table.put(put);
166 
167   }
168 
169   @Test
170   public void testMultipleZK() {
171     try {
172       HTable localMeta =
173         new HTable(new Configuration(TEST_UTIL.getConfiguration()), HConstants.META_TABLE_NAME);
174       Configuration otherConf = new Configuration(TEST_UTIL.getConfiguration());
175       otherConf.set(HConstants.ZOOKEEPER_QUORUM, "127.0.0.1");
176       HTable ipMeta = new HTable(otherConf, HConstants.META_TABLE_NAME);
177 
178       // dummy, just to open the connection
179       localMeta.exists(new Get(HConstants.LAST_ROW));
180       ipMeta.exists(new Get(HConstants.LAST_ROW));
181 
182       // make sure they aren't the same
183       assertFalse(HConnectionManager.getConnection(localMeta.getConfiguration()).getZooKeeperWatcher()
184           == HConnectionManager.getConnection(otherConf).getZooKeeperWatcher());
185       assertFalse(HConnectionManager.getConnection(localMeta.getConfiguration())
186           .getZooKeeperWatcher().getQuorum().equals(HConnectionManager
187               .getConnection(otherConf).getZooKeeperWatcher().getQuorum()));
188     } catch (Exception e) {
189       e.printStackTrace();
190       fail();
191     }
192   }
193 
194   /**
195    * Create a bunch of znodes in a hierarchy, try deleting one that has childs
196    * (it will fail), then delete it recursively, then delete the last znode
197    * @throws Exception
198    */
199   @Test
200   public void testZNodeDeletes() throws Exception {
201     ZooKeeperWatcher zkw = new ZooKeeperWatcher(
202       new Configuration(TEST_UTIL.getConfiguration()), 
203       TestZooKeeper.class.getName(), null);
204     ZKUtil.createWithParents(zkw, "/l1/l2/l3/l4");
205     try {
206       ZKUtil.deleteNode(zkw, "/l1/l2");
207       fail("We should not be able to delete if znode has childs");
208     } catch (KeeperException ex) {
209       assertNotNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
210     }
211     ZKUtil.deleteNodeRecursively(zkw, "/l1/l2");
212     assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2/l3/l4", null));
213     ZKUtil.deleteNode(zkw, "/l1");
214     assertNull(ZKUtil.getDataNoWatch(zkw, "/l1/l2", null));
215   }
216 
217   @Test
218   public void testClusterKey() throws Exception {
219     testKey("server", "2181", "hbase");
220     testKey("server1,server2,server3", "2181", "hbase");
221     try {
222       ZKUtil.transformClusterKey("2181:hbase");
223     } catch (IOException ex) {
224       // OK
225     }
226   }
227 
228   private void testKey(String ensemble, String port, String znode)
229       throws IOException {
230     Configuration conf = new Configuration();
231     String key = ensemble+":"+port+":"+znode;
232     String[] parts = ZKUtil.transformClusterKey(key);
233     assertEquals(ensemble, parts[0]);
234     assertEquals(port, parts[1]);
235     assertEquals(znode, parts[2]);
236     ZKUtil.applyClusterKeyToConf(conf, key);
237     assertEquals(parts[0], conf.get(HConstants.ZOOKEEPER_QUORUM));
238     assertEquals(parts[1], conf.get("hbase.zookeeper.property.clientPort"));
239     assertEquals(parts[2], conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT));
240     String reconstructedKey = ZKUtil.getZooKeeperClusterKey(conf);
241     assertEquals(key, reconstructedKey);
242   }
243 
244   /**
245    * A test for HBASE-3238
246    * @throws IOException A connection attempt to zk failed
247    * @throws InterruptedException One of the non ZKUtil actions was interrupted
248    * @throws KeeperException Any of the zookeeper connections had a
249    * KeeperException
250    */
251   @Test
252   public void testCreateSilentIsReallySilent() throws InterruptedException,
253       KeeperException, IOException {
254     Configuration c = TEST_UTIL.getConfiguration();
255 
256     String aclZnode = "/aclRoot";
257     String quorumServers = ZKConfig.getZKQuorumServersString(c);
258     int sessionTimeout = 5 * 1000; // 5 seconds
259     ZooKeeper zk = new ZooKeeper(quorumServers, sessionTimeout, EmptyWatcher.instance);
260     zk.addAuthInfo("digest", "hbase:rox".getBytes());
261 
262     // Assumes the  root of the ZooKeeper space is writable as it creates a node
263     // wherever the cluster home is defined.
264     ZooKeeperWatcher zk2 = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
265         "testMasterAddressManagerFromZK",
266         null);
267 
268     // I set this acl after the attempted creation of the cluster home node.
269     zk.setACL("/", ZooDefs.Ids.CREATOR_ALL_ACL, -1);
270     zk.create(aclZnode, null, ZooDefs.Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
271     zk.close();
272 
273     ZKUtil.createAndFailSilent(zk2, aclZnode);
274  }
275 }