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