View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.accumulo.core.client;
18  
19  import java.io.IOException;
20  import java.nio.ByteBuffer;
21  import java.util.Collections;
22  import java.util.List;
23  import java.util.UUID;
24  
25  import org.apache.accumulo.core.Constants;
26  import org.apache.accumulo.core.client.impl.ConnectorImpl;
27  import org.apache.accumulo.core.client.impl.MasterClient;
28  import org.apache.accumulo.core.conf.AccumuloConfiguration;
29  import org.apache.accumulo.core.conf.Property;
30  import org.apache.accumulo.core.file.FileUtil;
31  import org.apache.accumulo.core.master.thrift.MasterClientService.Client;
32  import org.apache.accumulo.core.security.CredentialHelper;
33  import org.apache.accumulo.core.security.thrift.AuthInfo;
34  import org.apache.accumulo.core.security.thrift.Credential;
35  import org.apache.accumulo.core.security.thrift.ThriftSecurityException;
36  import org.apache.accumulo.core.security.tokens.PasswordToken;
37  import org.apache.accumulo.core.security.tokens.SecurityToken;
38  import org.apache.accumulo.core.util.ArgumentChecker;
39  import org.apache.accumulo.core.util.ByteBufferUtil;
40  import org.apache.accumulo.core.util.CachedConfiguration;
41  import org.apache.accumulo.core.util.OpTimer;
42  import org.apache.accumulo.core.util.TextUtil;
43  import org.apache.accumulo.core.util.ThriftUtil;
44  import org.apache.accumulo.core.zookeeper.ZooUtil;
45  import org.apache.accumulo.fate.zookeeper.ZooCache;
46  import org.apache.hadoop.fs.FileStatus;
47  import org.apache.hadoop.fs.FileSystem;
48  import org.apache.hadoop.fs.Path;
49  import org.apache.hadoop.io.Text;
50  import org.apache.log4j.Level;
51  import org.apache.log4j.Logger;
52  import org.apache.thrift.TException;
53  import org.apache.thrift.transport.TTransportException;
54  
55  /**
56   * <p>
57   * An implementation of instance that looks in zookeeper to find information needed to connect to an instance of accumulo.
58   * 
59   * <p>
60   * The advantage of using zookeeper to obtain information about accumulo is that zookeeper is highly available, very responsive, and supports caching.
61   * 
62   * <p>
63   * Because it is possible for multiple instances of accumulo to share a single set of zookeeper servers, all constructors require an accumulo instance name.
64   * 
65   * If you do not know the instance names then run accumulo org.apache.accumulo.server.util.ListInstances on an accumulo server.
66   * 
67   */
68  
69  public class ZooKeeperInstance implements Instance {
70    
71    private static final Logger log = Logger.getLogger(ZooKeeperInstance.class);
72    
73    private String instanceId = null;
74    private String instanceName = null;
75    
76    private ZooCache zooCache;
77    
78    private String zooKeepers;
79    
80    private int zooKeepersSessionTimeOut;
81    
82    /**
83     * 
84     * @param instanceName
85     *          The name of specific accumulo instance. This is set at initialization time.
86     * @param zooKeepers
87     *          A comma separated list of zoo keeper server locations. Each location can contain an optional port, of the format host:port.
88     */
89    
90    public ZooKeeperInstance(String instanceName, String zooKeepers) {
91      this(instanceName, zooKeepers, (int) AccumuloConfiguration.getDefaultConfiguration().getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
92    }
93    
94    /**
95     * 
96     * @param instanceName
97     *          The name of specific accumulo instance. This is set at initialization time.
98     * @param zooKeepers
99     *          A comma separated list of zoo keeper server locations. Each location can contain an optional port, of the format host:port.
100    * @param sessionTimeout
101    *          zoo keeper session time out in milliseconds.
102    */
103   
104   public ZooKeeperInstance(String instanceName, String zooKeepers, int sessionTimeout) {
105     ArgumentChecker.notNull(instanceName, zooKeepers);
106     this.instanceName = instanceName;
107     this.zooKeepers = zooKeepers;
108     this.zooKeepersSessionTimeOut = sessionTimeout;
109     zooCache = ZooCache.getInstance(zooKeepers, sessionTimeout);
110     getInstanceID();
111   }
112   
113   /**
114    * 
115    * @param instanceId
116    *          The UUID that identifies the accumulo instance you want to connect to.
117    * @param zooKeepers
118    *          A comma separated list of zoo keeper server locations. Each location can contain an optional port, of the format host:port.
119    */
120   
121   public ZooKeeperInstance(UUID instanceId, String zooKeepers) {
122     this(instanceId, zooKeepers, (int) AccumuloConfiguration.getDefaultConfiguration().getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
123   }
124   
125   /**
126    * 
127    * @param instanceId
128    *          The UUID that identifies the accumulo instance you want to connect to.
129    * @param zooKeepers
130    *          A comma separated list of zoo keeper server locations. Each location can contain an optional port, of the format host:port.
131    * @param sessionTimeout
132    *          zoo keeper session time out in milliseconds.
133    */
134   
135   public ZooKeeperInstance(UUID instanceId, String zooKeepers, int sessionTimeout) {
136     ArgumentChecker.notNull(instanceId, zooKeepers);
137     this.instanceId = instanceId.toString();
138     this.zooKeepers = zooKeepers;
139     this.zooKeepersSessionTimeOut = sessionTimeout;
140     zooCache = ZooCache.getInstance(zooKeepers, sessionTimeout);
141   }
142   
143   @Override
144   public String getInstanceID() {
145     if (instanceId == null) {
146       // want the instance id to be stable for the life of this instance object,
147       // so only get it once
148       String instanceNamePath = Constants.ZROOT + Constants.ZINSTANCES + "/" + instanceName;
149       byte[] iidb = zooCache.get(instanceNamePath);
150       if (iidb == null) {
151         throw new RuntimeException("Instance name " + instanceName
152             + " does not exist in zookeeper.  Run \"accumulo org.apache.accumulo.server.util.ListInstances\" to see a list.");
153       }
154       instanceId = new String(iidb);
155     }
156     
157     if (zooCache.get(Constants.ZROOT + "/" + instanceId) == null) {
158       if (instanceName == null)
159         throw new RuntimeException("Instance id " + instanceId + " does not exist in zookeeper");
160       throw new RuntimeException("Instance id " + instanceId + " pointed to by the name " + instanceName + " does not exist in zookeeper");
161     }
162     
163     return instanceId;
164   }
165   
166   @Override
167   public List<String> getMasterLocations() {
168     String masterLocPath = ZooUtil.getRoot(this) + Constants.ZMASTER_LOCK;
169     
170     OpTimer opTimer = new OpTimer(log, Level.TRACE).start("Looking up master location in zoocache.");
171     byte[] loc = ZooUtil.getLockData(zooCache, masterLocPath);
172     opTimer.stop("Found master at " + (loc == null ? null : new String(loc)) + " in %DURATION%");
173     
174     if (loc == null) {
175       return Collections.emptyList();
176     }
177     
178     return Collections.singletonList(new String(loc));
179   }
180   
181   @Override
182   public String getRootTabletLocation() {
183     String zRootLocPath = ZooUtil.getRoot(this) + Constants.ZROOT_TABLET_LOCATION;
184     
185     OpTimer opTimer = new OpTimer(log, Level.TRACE).start("Looking up root tablet location in zookeeper.");
186     byte[] loc = zooCache.get(zRootLocPath);
187     opTimer.stop("Found root tablet at " + (loc == null ? null : new String(loc)) + " in %DURATION%");
188     
189     if (loc == null) {
190       return null;
191     }
192     
193     return new String(loc).split("\\|")[0];
194   }
195   
196   @Override
197   public String getInstanceName() {
198     if (instanceName == null)
199       instanceName = lookupInstanceName(zooCache, UUID.fromString(getInstanceID()));
200     
201     return instanceName;
202   }
203   
204   @Override
205   public String getZooKeepers() {
206     return zooKeepers;
207   }
208   
209   @Override
210   public int getZooKeepersSessionTimeOut() {
211     return zooKeepersSessionTimeOut;
212   }
213   
214   @Override
215   public Connector getConnector(String user, CharSequence pass) throws AccumuloException, AccumuloSecurityException {
216     return getConnector(user, TextUtil.getBytes(new Text(pass.toString())));
217   }
218   
219   @Override
220   public Connector getConnector(String user, ByteBuffer pass) throws AccumuloException, AccumuloSecurityException {
221     return getConnector(user, ByteBufferUtil.toBytes(pass));
222   }
223   
224   // Suppress deprecation, ConnectorImpl is deprecated to warn clients against using.
225   @Override
226   public Connector getConnector(String principal, SecurityToken token) throws AccumuloException, AccumuloSecurityException {
227     return getConnector(CredentialHelper.create(principal, token, getInstanceID()));
228   }
229   
230   @SuppressWarnings("deprecation")
231   public Connector getConnector(Credential credential) throws AccumuloException, AccumuloSecurityException {
232     return new ConnectorImpl(this, credential);
233   }
234   
235   @Override
236   public Connector getConnector(String principal, byte[] pass) throws AccumuloException, AccumuloSecurityException {
237     return getConnector(principal, new PasswordToken().setPassword(pass));
238   }
239   
240   private AccumuloConfiguration conf = null;
241   
242   @Override
243   public AccumuloConfiguration getConfiguration() {
244     if (conf == null)
245       conf = AccumuloConfiguration.getDefaultConfiguration();
246     return conf;
247   }
248   
249   @Override
250   public void setConfiguration(AccumuloConfiguration conf) {
251     this.conf = conf;
252   }
253   
254   /**
255    * @deprecated Use {@link #lookupInstanceName(org.apache.accumulo.fate.zookeeper.ZooCache, UUID)} instead
256    */
257   @Deprecated
258   public static String lookupInstanceName(org.apache.accumulo.core.zookeeper.ZooCache zooCache, UUID instanceId) {
259     return lookupInstanceName((ZooCache) zooCache, instanceId);
260   }
261   
262   /**
263    * Given a zooCache and instanceId, look up the instance name.
264    * 
265    * @param zooCache
266    * @param instanceId
267    * @return the instance name
268    */
269   public static String lookupInstanceName(ZooCache zooCache, UUID instanceId) {
270     ArgumentChecker.notNull(zooCache, instanceId);
271     for (String name : zooCache.getChildren(Constants.ZROOT + Constants.ZINSTANCES)) {
272       String instanceNamePath = Constants.ZROOT + Constants.ZINSTANCES + "/" + name;
273       UUID iid = UUID.fromString(new String(zooCache.get(instanceNamePath)));
274       if (iid.equals(instanceId)) {
275         return name;
276       }
277     }
278     return null;
279   }
280   
281   // To be moved to server code. Only lives here to support the Accumulo Shell
282   @Deprecated
283   public static String getInstanceIDFromHdfs(Path instanceDirectory) {
284     try {
285       FileSystem fs = FileUtil.getFileSystem(CachedConfiguration.getInstance(), AccumuloConfiguration.getSiteConfiguration());
286       FileStatus[] files = fs.listStatus(instanceDirectory);
287       log.debug("Trying to read instance id from " + instanceDirectory);
288       if (files == null || files.length == 0) {
289         log.error("unable obtain instance id at " + instanceDirectory);
290         throw new RuntimeException("Accumulo not initialized, there is no instance id at " + instanceDirectory);
291       } else if (files.length != 1) {
292         log.error("multiple potential instances in " + instanceDirectory);
293         throw new RuntimeException("Accumulo found multiple possible instance ids in " + instanceDirectory);
294       } else {
295         String result = files[0].getPath().getName();
296         return result;
297       }
298     } catch (IOException e) {
299       throw new RuntimeException("Accumulo not initialized, there is no instance id at " + instanceDirectory, e);
300     }
301   }
302   
303   @Override
304   public Connector getConnector(AuthInfo auth) throws AccumuloException, AccumuloSecurityException {
305     return getConnector(auth.user, auth.password);
306   }
307   
308   @Override
309   public String getAuthenticatorClassName() throws AccumuloException {
310     Client client = null;
311     try {
312       client = MasterClient.getConnectionWithRetry(this);
313       return client.getAuthenticatorClassName();
314     } catch (TTransportException e) {
315       throw new AccumuloException(e);
316     } catch (ThriftSecurityException e) {
317       throw new AccumuloException(e);
318     } catch (TException e) {
319       throw new AccumuloException(e);
320     } finally {
321       if (client != null) {
322         ThriftUtil.returnClient(client);
323       }
324     }
325   }
326   
327 }