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 */
018 package org.apache.hadoop.hdfs;
019
020 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_DEFAULT;
021 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY;
022 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_PROXY_PROVIDER_KEY_PREFIX;
023 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_DEFAULT;
024 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_KEY;
025 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_DEFAULT;
026 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_KEY;
027 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_KEY;
028 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_DEFAULT;
029
030 import java.io.IOException;
031 import java.lang.reflect.Constructor;
032 import java.lang.reflect.InvocationHandler;
033 import java.lang.reflect.Proxy;
034 import java.net.InetSocketAddress;
035 import java.net.URI;
036 import java.util.HashMap;
037 import java.util.Map;
038 import java.util.concurrent.TimeUnit;
039 import java.util.concurrent.atomic.AtomicBoolean;
040
041 import org.apache.commons.logging.Log;
042 import org.apache.commons.logging.LogFactory;
043 import org.apache.hadoop.conf.Configuration;
044 import org.apache.hadoop.hdfs.DFSClient.Conf;
045 import org.apache.hadoop.hdfs.protocol.AlreadyBeingCreatedException;
046 import org.apache.hadoop.hdfs.protocol.ClientProtocol;
047 import org.apache.hadoop.hdfs.protocol.HdfsConstants;
048 import org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB;
049 import org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB;
050 import org.apache.hadoop.hdfs.protocolPB.JournalProtocolPB;
051 import org.apache.hadoop.hdfs.protocolPB.JournalProtocolTranslatorPB;
052 import org.apache.hadoop.hdfs.protocolPB.NamenodeProtocolPB;
053 import org.apache.hadoop.hdfs.protocolPB.NamenodeProtocolTranslatorPB;
054 import org.apache.hadoop.hdfs.server.namenode.ha.AbstractNNFailoverProxyProvider;
055 import org.apache.hadoop.hdfs.server.namenode.ha.WrappedFailoverProxyProvider;
056 import org.apache.hadoop.hdfs.server.namenode.NameNode;
057 import org.apache.hadoop.hdfs.server.namenode.SafeModeException;
058 import org.apache.hadoop.hdfs.server.protocol.JournalProtocol;
059 import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol;
060 import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols;
061 import org.apache.hadoop.io.Text;
062 import org.apache.hadoop.io.retry.DefaultFailoverProxyProvider;
063 import org.apache.hadoop.io.retry.FailoverProxyProvider;
064 import org.apache.hadoop.io.retry.LossyRetryInvocationHandler;
065 import org.apache.hadoop.io.retry.RetryPolicies;
066 import org.apache.hadoop.io.retry.RetryPolicy;
067 import org.apache.hadoop.io.retry.RetryProxy;
068 import org.apache.hadoop.io.retry.RetryUtils;
069 import org.apache.hadoop.ipc.ProtobufRpcEngine;
070 import org.apache.hadoop.ipc.RPC;
071 import org.apache.hadoop.ipc.RemoteException;
072 import org.apache.hadoop.net.NetUtils;
073 import org.apache.hadoop.security.RefreshUserMappingsProtocol;
074 import org.apache.hadoop.security.SecurityUtil;
075 import org.apache.hadoop.security.UserGroupInformation;
076 import org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol;
077 import org.apache.hadoop.security.protocolPB.RefreshAuthorizationPolicyProtocolClientSideTranslatorPB;
078 import org.apache.hadoop.security.protocolPB.RefreshAuthorizationPolicyProtocolPB;
079 import org.apache.hadoop.security.protocolPB.RefreshUserMappingsProtocolClientSideTranslatorPB;
080 import org.apache.hadoop.security.protocolPB.RefreshUserMappingsProtocolPB;
081 import org.apache.hadoop.ipc.RefreshCallQueueProtocol;
082 import org.apache.hadoop.ipc.protocolPB.RefreshCallQueueProtocolPB;
083 import org.apache.hadoop.ipc.protocolPB.RefreshCallQueueProtocolClientSideTranslatorPB;
084 import org.apache.hadoop.tools.GetUserMappingsProtocol;
085 import org.apache.hadoop.tools.protocolPB.GetUserMappingsProtocolClientSideTranslatorPB;
086 import org.apache.hadoop.tools.protocolPB.GetUserMappingsProtocolPB;
087
088 import com.google.common.annotations.VisibleForTesting;
089 import com.google.common.base.Preconditions;
090
091 /**
092 * Create proxy objects to communicate with a remote NN. All remote access to an
093 * NN should be funneled through this class. Most of the time you'll want to use
094 * {@link NameNodeProxies#createProxy(Configuration, URI, Class)}, which will
095 * create either an HA- or non-HA-enabled client proxy as appropriate.
096 */
097 public class NameNodeProxies {
098
099 private static final Log LOG = LogFactory.getLog(NameNodeProxies.class);
100
101 /**
102 * Wrapper for a client proxy as well as its associated service ID.
103 * This is simply used as a tuple-like return type for
104 * {@link NameNodeProxies#createProxy} and
105 * {@link NameNodeProxies#createNonHAProxy}.
106 */
107 public static class ProxyAndInfo<PROXYTYPE> {
108 private final PROXYTYPE proxy;
109 private final Text dtService;
110 private final InetSocketAddress address;
111
112 public ProxyAndInfo(PROXYTYPE proxy, Text dtService,
113 InetSocketAddress address) {
114 this.proxy = proxy;
115 this.dtService = dtService;
116 this.address = address;
117 }
118
119 public PROXYTYPE getProxy() {
120 return proxy;
121 }
122
123 public Text getDelegationTokenService() {
124 return dtService;
125 }
126
127 public InetSocketAddress getAddress() {
128 return address;
129 }
130 }
131
132 /**
133 * Creates the namenode proxy with the passed protocol. This will handle
134 * creation of either HA- or non-HA-enabled proxy objects, depending upon
135 * if the provided URI is a configured logical URI.
136 *
137 * @param conf the configuration containing the required IPC
138 * properties, client failover configurations, etc.
139 * @param nameNodeUri the URI pointing either to a specific NameNode
140 * or to a logical nameservice.
141 * @param xface the IPC interface which should be created
142 * @return an object containing both the proxy and the associated
143 * delegation token service it corresponds to
144 * @throws IOException if there is an error creating the proxy
145 **/
146 @SuppressWarnings("unchecked")
147 public static <T> ProxyAndInfo<T> createProxy(Configuration conf,
148 URI nameNodeUri, Class<T> xface) throws IOException {
149 return createProxy(conf, nameNodeUri, xface, null);
150 }
151
152 /**
153 * Creates the namenode proxy with the passed protocol. This will handle
154 * creation of either HA- or non-HA-enabled proxy objects, depending upon
155 * if the provided URI is a configured logical URI.
156 *
157 * @param conf the configuration containing the required IPC
158 * properties, client failover configurations, etc.
159 * @param nameNodeUri the URI pointing either to a specific NameNode
160 * or to a logical nameservice.
161 * @param xface the IPC interface which should be created
162 * @param fallbackToSimpleAuth set to true or false during calls to indicate if
163 * a secure client falls back to simple auth
164 * @return an object containing both the proxy and the associated
165 * delegation token service it corresponds to
166 * @throws IOException if there is an error creating the proxy
167 **/
168 @SuppressWarnings("unchecked")
169 public static <T> ProxyAndInfo<T> createProxy(Configuration conf,
170 URI nameNodeUri, Class<T> xface, AtomicBoolean fallbackToSimpleAuth)
171 throws IOException {
172 AbstractNNFailoverProxyProvider<T> failoverProxyProvider =
173 createFailoverProxyProvider(conf, nameNodeUri, xface, true,
174 fallbackToSimpleAuth);
175
176 if (failoverProxyProvider == null) {
177 // Non-HA case
178 return createNonHAProxy(conf, NameNode.getAddress(nameNodeUri), xface,
179 UserGroupInformation.getCurrentUser(), true, fallbackToSimpleAuth);
180 } else {
181 // HA case
182 Conf config = new Conf(conf);
183 T proxy = (T) RetryProxy.create(xface, failoverProxyProvider,
184 RetryPolicies.failoverOnNetworkException(
185 RetryPolicies.TRY_ONCE_THEN_FAIL, config.maxFailoverAttempts,
186 config.maxRetryAttempts, config.failoverSleepBaseMillis,
187 config.failoverSleepMaxMillis));
188
189 Text dtService;
190 if (failoverProxyProvider.useLogicalURI()) {
191 dtService = HAUtil.buildTokenServiceForLogicalUri(nameNodeUri,
192 HdfsConstants.HDFS_URI_SCHEME);
193 } else {
194 dtService = SecurityUtil.buildTokenService(
195 NameNode.getAddress(nameNodeUri));
196 }
197 return new ProxyAndInfo<T>(proxy, dtService,
198 NameNode.getAddress(nameNodeUri));
199 }
200 }
201
202 /**
203 * Generate a dummy namenode proxy instance that utilizes our hacked
204 * {@link LossyRetryInvocationHandler}. Proxy instance generated using this
205 * method will proactively drop RPC responses. Currently this method only
206 * support HA setup. null will be returned if the given configuration is not
207 * for HA.
208 *
209 * @param config the configuration containing the required IPC
210 * properties, client failover configurations, etc.
211 * @param nameNodeUri the URI pointing either to a specific NameNode
212 * or to a logical nameservice.
213 * @param xface the IPC interface which should be created
214 * @param numResponseToDrop The number of responses to drop for each RPC call
215 * @param fallbackToSimpleAuth set to true or false during calls to indicate if
216 * a secure client falls back to simple auth
217 * @return an object containing both the proxy and the associated
218 * delegation token service it corresponds to. Will return null of the
219 * given configuration does not support HA.
220 * @throws IOException if there is an error creating the proxy
221 */
222 @SuppressWarnings("unchecked")
223 public static <T> ProxyAndInfo<T> createProxyWithLossyRetryHandler(
224 Configuration config, URI nameNodeUri, Class<T> xface,
225 int numResponseToDrop, AtomicBoolean fallbackToSimpleAuth)
226 throws IOException {
227 Preconditions.checkArgument(numResponseToDrop > 0);
228 AbstractNNFailoverProxyProvider<T> failoverProxyProvider =
229 createFailoverProxyProvider(config, nameNodeUri, xface, true,
230 fallbackToSimpleAuth);
231
232 if (failoverProxyProvider != null) { // HA case
233 int delay = config.getInt(
234 DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_KEY,
235 DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_DEFAULT);
236 int maxCap = config.getInt(
237 DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_KEY,
238 DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_DEFAULT);
239 int maxFailoverAttempts = config.getInt(
240 DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY,
241 DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_DEFAULT);
242 int maxRetryAttempts = config.getInt(
243 DFS_CLIENT_RETRY_MAX_ATTEMPTS_KEY,
244 DFS_CLIENT_RETRY_MAX_ATTEMPTS_DEFAULT);
245 InvocationHandler dummyHandler = new LossyRetryInvocationHandler<T>(
246 numResponseToDrop, failoverProxyProvider,
247 RetryPolicies.failoverOnNetworkException(
248 RetryPolicies.TRY_ONCE_THEN_FAIL, maxFailoverAttempts,
249 Math.max(numResponseToDrop + 1, maxRetryAttempts), delay,
250 maxCap));
251
252 T proxy = (T) Proxy.newProxyInstance(
253 failoverProxyProvider.getInterface().getClassLoader(),
254 new Class[] { xface }, dummyHandler);
255 Text dtService;
256 if (failoverProxyProvider.useLogicalURI()) {
257 dtService = HAUtil.buildTokenServiceForLogicalUri(nameNodeUri,
258 HdfsConstants.HDFS_URI_SCHEME);
259 } else {
260 dtService = SecurityUtil.buildTokenService(
261 NameNode.getAddress(nameNodeUri));
262 }
263 return new ProxyAndInfo<T>(proxy, dtService,
264 NameNode.getAddress(nameNodeUri));
265 } else {
266 LOG.warn("Currently creating proxy using " +
267 "LossyRetryInvocationHandler requires NN HA setup");
268 return null;
269 }
270 }
271
272 /**
273 * Creates an explicitly non-HA-enabled proxy object. Most of the time you
274 * don't want to use this, and should instead use {@link NameNodeProxies#createProxy}.
275 *
276 * @param conf the configuration object
277 * @param nnAddr address of the remote NN to connect to
278 * @param xface the IPC interface which should be created
279 * @param ugi the user who is making the calls on the proxy object
280 * @param withRetries certain interfaces have a non-standard retry policy
281 * @return an object containing both the proxy and the associated
282 * delegation token service it corresponds to
283 * @throws IOException
284 */
285 @SuppressWarnings("unchecked")
286 public static <T> ProxyAndInfo<T> createNonHAProxy(
287 Configuration conf, InetSocketAddress nnAddr, Class<T> xface,
288 UserGroupInformation ugi, boolean withRetries) throws IOException {
289 return createNonHAProxy(conf, nnAddr, xface, ugi, withRetries, null);
290 }
291
292 /**
293 * Creates an explicitly non-HA-enabled proxy object. Most of the time you
294 * don't want to use this, and should instead use {@link NameNodeProxies#createProxy}.
295 *
296 * @param conf the configuration object
297 * @param nnAddr address of the remote NN to connect to
298 * @param xface the IPC interface which should be created
299 * @param ugi the user who is making the calls on the proxy object
300 * @param withRetries certain interfaces have a non-standard retry policy
301 * @param fallbackToSimpleAuth - set to true or false during this method to
302 * indicate if a secure client falls back to simple auth
303 * @return an object containing both the proxy and the associated
304 * delegation token service it corresponds to
305 * @throws IOException
306 */
307 @SuppressWarnings("unchecked")
308 public static <T> ProxyAndInfo<T> createNonHAProxy(
309 Configuration conf, InetSocketAddress nnAddr, Class<T> xface,
310 UserGroupInformation ugi, boolean withRetries,
311 AtomicBoolean fallbackToSimpleAuth) throws IOException {
312 Text dtService = SecurityUtil.buildTokenService(nnAddr);
313
314 T proxy;
315 if (xface == ClientProtocol.class) {
316 proxy = (T) createNNProxyWithClientProtocol(nnAddr, conf, ugi,
317 withRetries, fallbackToSimpleAuth);
318 } else if (xface == JournalProtocol.class) {
319 proxy = (T) createNNProxyWithJournalProtocol(nnAddr, conf, ugi);
320 } else if (xface == NamenodeProtocol.class) {
321 proxy = (T) createNNProxyWithNamenodeProtocol(nnAddr, conf, ugi,
322 withRetries);
323 } else if (xface == GetUserMappingsProtocol.class) {
324 proxy = (T) createNNProxyWithGetUserMappingsProtocol(nnAddr, conf, ugi);
325 } else if (xface == RefreshUserMappingsProtocol.class) {
326 proxy = (T) createNNProxyWithRefreshUserMappingsProtocol(nnAddr, conf, ugi);
327 } else if (xface == RefreshAuthorizationPolicyProtocol.class) {
328 proxy = (T) createNNProxyWithRefreshAuthorizationPolicyProtocol(nnAddr,
329 conf, ugi);
330 } else if (xface == RefreshCallQueueProtocol.class) {
331 proxy = (T) createNNProxyWithRefreshCallQueueProtocol(nnAddr, conf, ugi);
332 } else {
333 String message = "Unsupported protocol found when creating the proxy " +
334 "connection to NameNode: " +
335 ((xface != null) ? xface.getClass().getName() : "null");
336 LOG.error(message);
337 throw new IllegalStateException(message);
338 }
339
340 return new ProxyAndInfo<T>(proxy, dtService, nnAddr);
341 }
342
343 private static JournalProtocol createNNProxyWithJournalProtocol(
344 InetSocketAddress address, Configuration conf, UserGroupInformation ugi)
345 throws IOException {
346 JournalProtocolPB proxy = (JournalProtocolPB) createNameNodeProxy(address,
347 conf, ugi, JournalProtocolPB.class);
348 return new JournalProtocolTranslatorPB(proxy);
349 }
350
351 private static RefreshAuthorizationPolicyProtocol
352 createNNProxyWithRefreshAuthorizationPolicyProtocol(InetSocketAddress address,
353 Configuration conf, UserGroupInformation ugi) throws IOException {
354 RefreshAuthorizationPolicyProtocolPB proxy = (RefreshAuthorizationPolicyProtocolPB)
355 createNameNodeProxy(address, conf, ugi, RefreshAuthorizationPolicyProtocolPB.class);
356 return new RefreshAuthorizationPolicyProtocolClientSideTranslatorPB(proxy);
357 }
358
359 private static RefreshUserMappingsProtocol
360 createNNProxyWithRefreshUserMappingsProtocol(InetSocketAddress address,
361 Configuration conf, UserGroupInformation ugi) throws IOException {
362 RefreshUserMappingsProtocolPB proxy = (RefreshUserMappingsProtocolPB)
363 createNameNodeProxy(address, conf, ugi, RefreshUserMappingsProtocolPB.class);
364 return new RefreshUserMappingsProtocolClientSideTranslatorPB(proxy);
365 }
366
367 private static RefreshCallQueueProtocol
368 createNNProxyWithRefreshCallQueueProtocol(InetSocketAddress address,
369 Configuration conf, UserGroupInformation ugi) throws IOException {
370 RefreshCallQueueProtocolPB proxy = (RefreshCallQueueProtocolPB)
371 createNameNodeProxy(address, conf, ugi, RefreshCallQueueProtocolPB.class);
372 return new RefreshCallQueueProtocolClientSideTranslatorPB(proxy);
373 }
374
375 private static GetUserMappingsProtocol createNNProxyWithGetUserMappingsProtocol(
376 InetSocketAddress address, Configuration conf, UserGroupInformation ugi)
377 throws IOException {
378 GetUserMappingsProtocolPB proxy = (GetUserMappingsProtocolPB)
379 createNameNodeProxy(address, conf, ugi, GetUserMappingsProtocolPB.class);
380 return new GetUserMappingsProtocolClientSideTranslatorPB(proxy);
381 }
382
383 private static NamenodeProtocol createNNProxyWithNamenodeProtocol(
384 InetSocketAddress address, Configuration conf, UserGroupInformation ugi,
385 boolean withRetries) throws IOException {
386 NamenodeProtocolPB proxy = (NamenodeProtocolPB) createNameNodeProxy(
387 address, conf, ugi, NamenodeProtocolPB.class);
388 if (withRetries) { // create the proxy with retries
389 RetryPolicy timeoutPolicy = RetryPolicies.exponentialBackoffRetry(5, 200,
390 TimeUnit.MILLISECONDS);
391 Map<String, RetryPolicy> methodNameToPolicyMap
392 = new HashMap<String, RetryPolicy>();
393 methodNameToPolicyMap.put("getBlocks", timeoutPolicy);
394 methodNameToPolicyMap.put("getAccessKeys", timeoutPolicy);
395 NamenodeProtocol translatorProxy =
396 new NamenodeProtocolTranslatorPB(proxy);
397 return (NamenodeProtocol) RetryProxy.create(
398 NamenodeProtocol.class, translatorProxy, methodNameToPolicyMap);
399 } else {
400 return new NamenodeProtocolTranslatorPB(proxy);
401 }
402 }
403
404 private static ClientProtocol createNNProxyWithClientProtocol(
405 InetSocketAddress address, Configuration conf, UserGroupInformation ugi,
406 boolean withRetries, AtomicBoolean fallbackToSimpleAuth)
407 throws IOException {
408 RPC.setProtocolEngine(conf, ClientNamenodeProtocolPB.class, ProtobufRpcEngine.class);
409
410 final RetryPolicy defaultPolicy =
411 RetryUtils.getDefaultRetryPolicy(
412 conf,
413 DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_ENABLED_KEY,
414 DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_ENABLED_DEFAULT,
415 DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_SPEC_KEY,
416 DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_SPEC_DEFAULT,
417 SafeModeException.class);
418
419 final long version = RPC.getProtocolVersion(ClientNamenodeProtocolPB.class);
420 ClientNamenodeProtocolPB proxy = RPC.getProtocolProxy(
421 ClientNamenodeProtocolPB.class, version, address, ugi, conf,
422 NetUtils.getDefaultSocketFactory(conf),
423 org.apache.hadoop.ipc.Client.getTimeout(conf), defaultPolicy,
424 fallbackToSimpleAuth).getProxy();
425
426 if (withRetries) { // create the proxy with retries
427
428 RetryPolicy createPolicy = RetryPolicies
429 .retryUpToMaximumCountWithFixedSleep(5,
430 HdfsConstants.LEASE_SOFTLIMIT_PERIOD, TimeUnit.MILLISECONDS);
431
432 Map<Class<? extends Exception>, RetryPolicy> remoteExceptionToPolicyMap
433 = new HashMap<Class<? extends Exception>, RetryPolicy>();
434 remoteExceptionToPolicyMap.put(AlreadyBeingCreatedException.class,
435 createPolicy);
436
437 RetryPolicy methodPolicy = RetryPolicies.retryByRemoteException(
438 defaultPolicy, remoteExceptionToPolicyMap);
439 Map<String, RetryPolicy> methodNameToPolicyMap
440 = new HashMap<String, RetryPolicy>();
441
442 methodNameToPolicyMap.put("create", methodPolicy);
443
444 ClientProtocol translatorProxy =
445 new ClientNamenodeProtocolTranslatorPB(proxy);
446 return (ClientProtocol) RetryProxy.create(
447 ClientProtocol.class,
448 new DefaultFailoverProxyProvider<ClientProtocol>(
449 ClientProtocol.class, translatorProxy),
450 methodNameToPolicyMap,
451 defaultPolicy);
452 } else {
453 return new ClientNamenodeProtocolTranslatorPB(proxy);
454 }
455 }
456
457 private static Object createNameNodeProxy(InetSocketAddress address,
458 Configuration conf, UserGroupInformation ugi, Class<?> xface)
459 throws IOException {
460 RPC.setProtocolEngine(conf, xface, ProtobufRpcEngine.class);
461 Object proxy = RPC.getProxy(xface, RPC.getProtocolVersion(xface), address,
462 ugi, conf, NetUtils.getDefaultSocketFactory(conf));
463 return proxy;
464 }
465
466 /** Gets the configured Failover proxy provider's class */
467 @VisibleForTesting
468 public static <T> Class<FailoverProxyProvider<T>> getFailoverProxyProviderClass(
469 Configuration conf, URI nameNodeUri) throws IOException {
470 if (nameNodeUri == null) {
471 return null;
472 }
473 String host = nameNodeUri.getHost();
474
475 String configKey = DFS_CLIENT_FAILOVER_PROXY_PROVIDER_KEY_PREFIX + "."
476 + host;
477 try {
478 @SuppressWarnings("unchecked")
479 Class<FailoverProxyProvider<T>> ret = (Class<FailoverProxyProvider<T>>) conf
480 .getClass(configKey, null, FailoverProxyProvider.class);
481 return ret;
482 } catch (RuntimeException e) {
483 if (e.getCause() instanceof ClassNotFoundException) {
484 throw new IOException("Could not load failover proxy provider class "
485 + conf.get(configKey) + " which is configured for authority "
486 + nameNodeUri, e);
487 } else {
488 throw e;
489 }
490 }
491 }
492
493 /** Creates the Failover proxy provider instance*/
494 @VisibleForTesting
495 public static <T> AbstractNNFailoverProxyProvider<T> createFailoverProxyProvider(
496 Configuration conf, URI nameNodeUri, Class<T> xface, boolean checkPort,
497 AtomicBoolean fallbackToSimpleAuth) throws IOException {
498 Class<FailoverProxyProvider<T>> failoverProxyProviderClass = null;
499 AbstractNNFailoverProxyProvider<T> providerNN;
500 Preconditions.checkArgument(
501 xface.isAssignableFrom(NamenodeProtocols.class),
502 "Interface %s is not a NameNode protocol", xface);
503 try {
504 // Obtain the class of the proxy provider
505 failoverProxyProviderClass = getFailoverProxyProviderClass(conf,
506 nameNodeUri);
507 if (failoverProxyProviderClass == null) {
508 return null;
509 }
510 // Create a proxy provider instance.
511 Constructor<FailoverProxyProvider<T>> ctor = failoverProxyProviderClass
512 .getConstructor(Configuration.class, URI.class, Class.class);
513 FailoverProxyProvider<T> provider = ctor.newInstance(conf, nameNodeUri,
514 xface);
515
516 // If the proxy provider is of an old implementation, wrap it.
517 if (!(provider instanceof AbstractNNFailoverProxyProvider)) {
518 providerNN = new WrappedFailoverProxyProvider<T>(provider);
519 } else {
520 providerNN = (AbstractNNFailoverProxyProvider<T>)provider;
521 }
522 } catch (Exception e) {
523 String message = "Couldn't create proxy provider " + failoverProxyProviderClass;
524 if (LOG.isDebugEnabled()) {
525 LOG.debug(message, e);
526 }
527 if (e.getCause() instanceof IOException) {
528 throw (IOException) e.getCause();
529 } else {
530 throw new IOException(message, e);
531 }
532 }
533
534 // Check the port in the URI, if it is logical.
535 if (checkPort && providerNN.useLogicalURI()) {
536 int port = nameNodeUri.getPort();
537 if (port > 0 && port != NameNode.DEFAULT_PORT) {
538 // Throwing here without any cleanup is fine since we have not
539 // actually created the underlying proxies yet.
540 throw new IOException("Port " + port + " specified in URI "
541 + nameNodeUri + " but host '" + nameNodeUri.getHost()
542 + "' is a logical (HA) namenode"
543 + " and does not use port information.");
544 }
545 }
546 providerNN.setFallbackToSimpleAuth(fallbackToSimpleAuth);
547 return providerNN;
548 }
549
550 }