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.hdfs; 019 020import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_DEFAULT; 021import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY; 022import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_PROXY_PROVIDER_KEY_PREFIX; 023import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_DEFAULT; 024import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_KEY; 025import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_DEFAULT; 026import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_KEY; 027import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_KEY; 028import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_DEFAULT; 029 030import java.io.IOException; 031import java.lang.reflect.Constructor; 032import java.lang.reflect.InvocationHandler; 033import java.lang.reflect.Proxy; 034import java.net.InetSocketAddress; 035import java.net.URI; 036import java.util.HashMap; 037import java.util.Map; 038import java.util.concurrent.TimeUnit; 039import java.util.concurrent.atomic.AtomicBoolean; 040 041import org.apache.commons.logging.Log; 042import org.apache.commons.logging.LogFactory; 043import org.apache.hadoop.conf.Configuration; 044import org.apache.hadoop.hdfs.DFSClient.Conf; 045import org.apache.hadoop.hdfs.protocol.AlreadyBeingCreatedException; 046import org.apache.hadoop.hdfs.protocol.ClientProtocol; 047import org.apache.hadoop.hdfs.protocol.HdfsConstants; 048import org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB; 049import org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB; 050import org.apache.hadoop.hdfs.protocolPB.JournalProtocolPB; 051import org.apache.hadoop.hdfs.protocolPB.JournalProtocolTranslatorPB; 052import org.apache.hadoop.hdfs.protocolPB.NamenodeProtocolPB; 053import org.apache.hadoop.hdfs.protocolPB.NamenodeProtocolTranslatorPB; 054import org.apache.hadoop.hdfs.server.namenode.ha.AbstractNNFailoverProxyProvider; 055import org.apache.hadoop.hdfs.server.namenode.ha.WrappedFailoverProxyProvider; 056import org.apache.hadoop.hdfs.server.namenode.NameNode; 057import org.apache.hadoop.hdfs.server.namenode.SafeModeException; 058import org.apache.hadoop.hdfs.server.protocol.JournalProtocol; 059import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol; 060import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocols; 061import org.apache.hadoop.io.Text; 062import org.apache.hadoop.io.retry.DefaultFailoverProxyProvider; 063import org.apache.hadoop.io.retry.FailoverProxyProvider; 064import org.apache.hadoop.io.retry.LossyRetryInvocationHandler; 065import org.apache.hadoop.io.retry.RetryPolicies; 066import org.apache.hadoop.io.retry.RetryPolicy; 067import org.apache.hadoop.io.retry.RetryProxy; 068import org.apache.hadoop.io.retry.RetryUtils; 069import org.apache.hadoop.ipc.ProtobufRpcEngine; 070import org.apache.hadoop.ipc.RPC; 071import org.apache.hadoop.ipc.RemoteException; 072import org.apache.hadoop.net.NetUtils; 073import org.apache.hadoop.security.RefreshUserMappingsProtocol; 074import org.apache.hadoop.security.SecurityUtil; 075import org.apache.hadoop.security.UserGroupInformation; 076import org.apache.hadoop.security.authorize.RefreshAuthorizationPolicyProtocol; 077import org.apache.hadoop.security.protocolPB.RefreshAuthorizationPolicyProtocolClientSideTranslatorPB; 078import org.apache.hadoop.security.protocolPB.RefreshAuthorizationPolicyProtocolPB; 079import org.apache.hadoop.security.protocolPB.RefreshUserMappingsProtocolClientSideTranslatorPB; 080import org.apache.hadoop.security.protocolPB.RefreshUserMappingsProtocolPB; 081import org.apache.hadoop.ipc.RefreshCallQueueProtocol; 082import org.apache.hadoop.ipc.protocolPB.RefreshCallQueueProtocolPB; 083import org.apache.hadoop.ipc.protocolPB.RefreshCallQueueProtocolClientSideTranslatorPB; 084import org.apache.hadoop.tools.GetUserMappingsProtocol; 085import org.apache.hadoop.tools.protocolPB.GetUserMappingsProtocolClientSideTranslatorPB; 086import org.apache.hadoop.tools.protocolPB.GetUserMappingsProtocolPB; 087 088import com.google.common.annotations.VisibleForTesting; 089import 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 */ 097public 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}