@ -17,24 +17,25 @@
package org.apache.dolphinscheduler.common.utils ;
import static java.util.Collections.emptyList ;
import org.apache.dolphinscheduler.common.constants.Constants ;
import org.apache.commons.collections4.CollectionUtils ;
import org.apache.commons.lang3.StringUtils ;
import org.apache.http.conn.util.InetAddressUtils ;
import java.io.IOException ;
import java.net.Inet4Address ;
import java.net.Inet6Address ;
import java.net.InetAddress ;
import java.net.NetworkInterface ;
import java.net.SocketException ;
import java.net.UnknownHostException ;
import java.util.ArrayList ;
import java.util.Collections ;
import java.util.Enumeration ;
import java.util.LinkedList ;
import java.util.List ;
import java.util.Objects ;
import java.util.Optional ;
import java.util.stream.Collectors ;
import lombok.extern.slf4j.Slf4j ;
@ -106,7 +107,8 @@ public class NetUtils {
if ( null ! = LOCAL_ADDRESS ) {
return LOCAL_ADDRESS ;
}
return getLocalAddress0 ( ) ;
LOCAL_ADDRESS = getLocalAddress0 ( ) ;
return LOCAL_ADDRESS ;
}
/ * *
@ -115,55 +117,12 @@ public class NetUtils {
* @return first valid local IP
* /
private static synchronized InetAddress getLocalAddress0 ( ) {
if ( null ! = LOCAL_ADDRESS ) {
return LOCAL_ADDRESS ;
List < NetworkInterface > suitableNetworkInterface = findSuitableNetworkInterface ( ) ;
List < InetAddress > suitableInetAddress = findSuitableInetAddress ( suitableNetworkInterface ) ;
if ( CollectionUtils . isEmpty ( suitableInetAddress ) ) {
return null ;
}
InetAddress localAddress = null ;
try {
Optional < NetworkInterface > networkInterface = findNetworkInterface ( ) ;
if ( networkInterface . isPresent ( ) ) {
Enumeration < InetAddress > addresses = networkInterface . get ( ) . getInetAddresses ( ) ;
while ( addresses . hasMoreElements ( ) ) {
Optional < InetAddress > addressOp = toValidAddress ( addresses . nextElement ( ) ) ;
if ( addressOp . isPresent ( ) ) {
try {
if ( addressOp . get ( ) . isReachable ( 200 ) ) {
LOCAL_ADDRESS = addressOp . get ( ) ;
return LOCAL_ADDRESS ;
}
} catch ( IOException e ) {
log . warn ( "test address id reachable io exception" , e ) ;
}
}
}
}
localAddress = InetAddress . getLocalHost ( ) ;
} catch ( UnknownHostException e ) {
log . warn ( "InetAddress get LocalHost exception" , e ) ;
}
Optional < InetAddress > addressOp = toValidAddress ( localAddress ) ;
if ( addressOp . isPresent ( ) ) {
LOCAL_ADDRESS = addressOp . get ( ) ;
}
return LOCAL_ADDRESS ;
}
private static Optional < InetAddress > toValidAddress ( InetAddress address ) {
if ( address instanceof Inet6Address ) {
Inet6Address v6Address = ( Inet6Address ) address ;
if ( isPreferIPV6Address ( ) ) {
InetAddress inetAddress = normalizeV6Address ( v6Address ) ;
log . debug ( "The host prefer ipv6 address, will use ipv6 address: {} directly" , inetAddress ) ;
return Optional . ofNullable ( inetAddress ) ;
}
}
if ( isValidV4Address ( address ) ) {
return Optional . of ( address ) ;
}
log . warn ( "The address of the host is invalid, address: {}" , address ) ;
return Optional . empty ( ) ;
return suitableInetAddress . get ( 0 ) ;
}
private static InetAddress normalizeV6Address ( Inet6Address address ) {
@ -179,9 +138,8 @@ public class NetUtils {
return address ;
}
public static boolean isValidV4Address ( InetAddress address ) {
if ( address = = null | | address . isLoopbackAddress ( ) ) {
protected static boolean isValidV4Address ( InetAddress address ) {
if ( ! ( address instanceof Inet4Address ) ) {
return false ;
}
String name = address . getHostAddress ( ) ;
@ -191,6 +149,17 @@ public class NetUtils {
& & ! address . isLoopbackAddress ( ) ) ;
}
protected static boolean isValidV6Address ( InetAddress address ) {
if ( ! ( address instanceof Inet6Address ) ) {
return false ;
}
String name = address . getHostAddress ( ) ;
return ( name ! = null
& & InetAddressUtils . isIPv6Address ( name )
& & ! address . isAnyLocalAddress ( )
& & ! address . isLoopbackAddress ( ) ) ;
}
/ * *
* Check if an ipv6 address
*
@ -200,79 +169,142 @@ public class NetUtils {
return Boolean . getBoolean ( "java.net.preferIPv6Addresses" ) ;
}
private static boolean isPreferIPV4Address ( ) {
return Boolean . getBoolean ( "java.net.preferIPv4Addresses" ) ;
}
/ * *
* Get the suitable { @link NetworkInterface }
*
* @return If no { @link NetworkInterface } is available , return < code > null < / code >
* /
private static Optional < NetworkInterface > findNetworkInterface ( ) {
List < NetworkInterface > validNetworkInterfaces = emptyList ( ) ;
private static List < NetworkInterface > findSuitableNetworkInterface ( ) {
// Find all network interfaces
List < NetworkInterface > networkInterfaces = Collections . emptyList ( ) ;
try {
validNetworkInterfaces = getValidNetworkInterfaces ( ) ;
networkInterfaces = getAll NetworkInterfaces( ) ;
} catch ( SocketException e ) {
log . warn ( "ValidNetworkInterfaces exception" , e ) ;
}
if ( CollectionUtils . isEmpty ( validNetworkInterfaces ) ) {
log . warn ( "ValidNetworkInterfaces is empty" ) ;
return Optional . empty ( ) ;
}
// Try to specify config NetWork Interface
Optional < NetworkInterface > specifyNetworkInterface =
validNetworkInterfaces . stream ( ) . filter ( NetUtils : : isSpecifyNetworkInterface ) . findFirst ( ) ;
if ( specifyNetworkInterface . isPresent ( ) ) {
log . info ( "Use specified NetworkInterface: {}" , specifyNetworkInterface . get ( ) ) ;
return specifyNetworkInterface ;
// Filter the loopback/virtual/ network interfaces
List < NetworkInterface > validNetworkInterfaces = networkInterfaces
. stream ( )
. filter ( networkInterface - > {
try {
return ! ( networkInterface = = null
| | networkInterface . isLoopback ( )
| | networkInterface . isVirtual ( )
| | ! networkInterface . isUp ( ) ) ;
} catch ( SocketException e ) {
log . warn ( "ValidNetworkInterfaces exception" , e ) ;
return false ;
}
} )
. collect ( Collectors . toList ( ) ) ;
// Use the specified network interface if set
if ( StringUtils . isNotBlank ( specifyNetworkInterfaceName ( ) ) ) {
String specifyNetworkInterfaceName = specifyNetworkInterfaceName ( ) ;
validNetworkInterfaces = validNetworkInterfaces . stream ( )
. filter ( networkInterface - > specifyNetworkInterfaceName . equals ( networkInterface . getDisplayName ( ) ) )
. collect ( Collectors . toList ( ) ) ;
if ( CollectionUtils . isEmpty ( validNetworkInterfaces ) ) {
throw new IllegalArgumentException (
"The specified network interface: " + specifyNetworkInterfaceName + " is not found" ) ;
}
}
return findAddress ( validNetworkInterfaces ) ;
return filterByNetworkPriority ( validNetworkInterfaces ) ;
}
/ * *
* Get the valid { @link NetworkInterface network interfaces }
*
* @throws SocketException SocketException if an I / O error occurs .
* Get the suitable { @link InetAddress }
* /
private static List < NetworkInterface > getValidNetworkInterfaces ( ) throws SocketException {
private static List < InetAddress > findSuitableInetAddress ( List < NetworkInterface > networkInterfaces ) {
if ( CollectionUtils . isEmpty ( networkInterfaces ) ) {
return Collections . emptyList ( ) ;
}
List < InetAddress > allInetAddresses = new LinkedList < > ( ) ;
for ( NetworkInterface networkInterface : networkInterfaces ) {
Enumeration < InetAddress > addresses = networkInterface . getInetAddresses ( ) ;
while ( addresses . hasMoreElements ( ) ) {
allInetAddresses . add ( addresses . nextElement ( ) ) ;
}
}
// Get prefer addresses
List < InetAddress > preferInetAddress = new ArrayList < > ( ) ;
if ( ! isPreferIPV6Address ( ) & & ! isPreferIPV4Address ( ) ) {
// no prefer, will use all addresses
preferInetAddress . addAll ( getIpv4Addresses ( allInetAddresses ) ) ;
preferInetAddress . addAll ( getIpv6Addresses ( allInetAddresses ) ) ;
}
if ( isPreferIPV4Address ( ) ) {
preferInetAddress . addAll ( getIpv4Addresses ( allInetAddresses ) ) ;
}
if ( isPreferIPV6Address ( ) ) {
preferInetAddress . addAll ( getIpv6Addresses ( allInetAddresses ) ) ;
}
// Get reachable addresses
return preferInetAddress . stream ( )
. filter ( inetAddress - > {
try {
return inetAddress . isReachable ( 100 ) ;
} catch ( IOException e ) {
log . warn ( "InetAddress isReachable exception" , e ) ;
return false ;
}
} ) . collect ( Collectors . toList ( ) ) ;
}
private static List < InetAddress > getIpv4Addresses ( List < InetAddress > allInetAddresses ) {
if ( CollectionUtils . isEmpty ( allInetAddresses ) ) {
return Collections . emptyList ( ) ;
}
List < InetAddress > validIpv4Addresses = new ArrayList < > ( ) ;
for ( InetAddress inetAddress : allInetAddresses ) {
if ( isValidV4Address ( inetAddress ) ) {
validIpv4Addresses . add ( inetAddress ) ;
}
}
return validIpv4Addresses ;
}
private static List < InetAddress > getIpv6Addresses ( List < InetAddress > allInetAddresses ) {
if ( CollectionUtils . isEmpty ( allInetAddresses ) ) {
return Collections . emptyList ( ) ;
}
List < InetAddress > validIpv6Addresses = new ArrayList < > ( ) ;
for ( InetAddress inetAddress : allInetAddresses ) {
if ( ! isValidV6Address ( inetAddress ) ) {
continue ;
}
Inet6Address v6Address = ( Inet6Address ) inetAddress ;
InetAddress normalizedV6Address = normalizeV6Address ( v6Address ) ;
validIpv6Addresses . add ( normalizedV6Address ) ;
}
return validIpv6Addresses ;
}
private static List < NetworkInterface > getAllNetworkInterfaces ( ) throws SocketException {
List < NetworkInterface > validNetworkInterfaces = new LinkedList < > ( ) ;
Enumeration < NetworkInterface > interfaces = NetworkInterface . getNetworkInterfaces ( ) ;
while ( interfaces . hasMoreElements ( ) ) {
NetworkInterface networkInterface = interfaces . nextElement ( ) ;
// ignore
if ( ignoreNetworkInterface ( networkInterface ) ) {
log . debug ( "Info NetworkInterface: {}" , networkInterface ) ;
continue ;
}
log . info ( "Found valid NetworkInterface: {}" , networkInterface ) ;
log . info ( "Found NetworkInterface: {}" , networkInterface ) ;
validNetworkInterfaces . add ( networkInterface ) ;
}
return validNetworkInterfaces ;
}
/ * *
* @param networkInterface { @link NetworkInterface }
* @return if the specified { @link NetworkInterface } should be ignored , return < code > true < / code >
* @throws SocketException SocketException if an I / O error occurs .
* /
public static boolean ignoreNetworkInterface ( NetworkInterface networkInterface ) throws SocketException {
return networkInterface = = null
| | networkInterface . isLoopback ( )
| | networkInterface . isVirtual ( )
| | ! networkInterface . isUp ( ) ;
}
private static boolean isSpecifyNetworkInterface ( NetworkInterface networkInterface ) {
String preferredNetworkInterface =
PropertyUtils . getString ( Constants . DOLPHIN_SCHEDULER_NETWORK_INTERFACE_PREFERRED ,
System . getProperty ( Constants . DOLPHIN_SCHEDULER_NETWORK_INTERFACE_PREFERRED ) ) ;
return Objects . equals ( networkInterface . getDisplayName ( ) , preferredNetworkInterface ) ;
private static String specifyNetworkInterfaceName ( ) {
return PropertyUtils . getString (
Constants . DOLPHIN_SCHEDULER_NETWORK_INTERFACE_PREFERRED ,
System . getProperty ( Constants . DOLPHIN_SCHEDULER_NETWORK_INTERFACE_PREFERRED ) ) ;
}
private static Optional < NetworkInterface > findAddress ( List < NetworkInterface > validNetworkInterfaces ) {
private static List < NetworkInterface > filterByNetworkPriority ( List < NetworkInterface > validNetworkInterfaces ) {
if ( CollectionUtils . isEmpty ( validNetworkInterfaces ) ) {
return Optional . empty ( ) ;
return Collections . emptyList ( ) ;
}
String networkPriority = PropertyUtils . getString ( Constants . DOLPHIN_SCHEDULER_NETWORK_PRIORITY_STRATEGY ,
NETWORK_PRIORITY_DEFAULT ) ;
@ -282,28 +314,21 @@ public class NetUtils {
return findAddressByDefaultPolicy ( validNetworkInterfaces ) ;
case NETWORK_PRIORITY_INNER :
log . debug ( "Use inner NetworkInterface acquisition policy" ) ;
return findInnerAddress ( validNetworkInterfaces ) ;
return findInnerAddressNetWorkInterface ( validNetworkInterfaces ) ;
case NETWORK_PRIORITY_OUTER :
log . debug ( "Use outer NetworkInterface acquisition policy" ) ;
return findOuterAddress ( validNetworkInterfaces ) ;
return findOuterAddressNetworkInterface ( validNetworkInterfaces ) ;
default :
log . error ( "There is no matching network card acquisition policy!" ) ;
return Optional . empty ( ) ;
return Collections . emptyList ( ) ;
}
}
private static Optional < NetworkInterface > findAddressByDefaultPolicy ( List < NetworkInterface > validNetworkInterfaces ) {
Optional < NetworkInterface > innerAddress = findInnerAddress ( validNetworkInterfaces ) ;
if ( innerAddress . isPresent ( ) ) {
log . debug ( "Found inner NetworkInterface: {}" , innerAddress . get ( ) ) ;
return innerAddress ;
}
Optional < NetworkInterface > outerAddress = findOuterAddress ( validNetworkInterfaces ) ;
if ( outerAddress . isPresent ( ) ) {
log . debug ( "Found outer NetworkInterface: {}" , outerAddress . get ( ) ) ;
return outerAddress ;
}
return Optional . empty ( ) ;
private static List < NetworkInterface > findAddressByDefaultPolicy ( List < NetworkInterface > validNetworkInterfaces ) {
List < NetworkInterface > allAddress = new ArrayList < > ( ) ;
allAddress . addAll ( findInnerAddressNetWorkInterface ( validNetworkInterfaces ) ) ;
allAddress . addAll ( findOuterAddressNetworkInterface ( validNetworkInterfaces ) ) ;
return allAddress ;
}
/ * *
@ -311,39 +336,40 @@ public class NetUtils {
*
* @return If no { @link NetworkInterface } is available , return < code > null < / code >
* /
private static Optional < NetworkInterface > findInnerAddress ( List < NetworkInterface > validNetworkInterfaces ) {
private static List < NetworkInterface > findInnerAddressNetWorkInterface ( List < NetworkInterface > validNetworkInterfaces ) {
if ( CollectionUtils . isEmpty ( validNetworkInterfaces ) ) {
return Optional . empty ( ) ;
return Collections . emptyList ( ) ;
}
List < NetworkInterface > innerNetworkInterfaces = new ArrayList < > ( ) ;
for ( NetworkInterface ni : validNetworkInterfaces ) {
Enumeration < InetAddress > address = ni . getInetAddresses ( ) ;
while ( address . hasMoreElements ( ) ) {
InetAddress ip = address . nextElement ( ) ;
if ( ip . isSiteLocalAddress ( )
& & ! ip . isLoopbackAddress ( ) ) {
return Optional . of ( ni ) ;
if ( ip . isSiteLocalAddress ( ) & & ! ip . isLoopbackAddress ( ) ) {
innerNetworkInterfaces . add ( ni ) ;
}
}
}
return Optional . empty ( ) ;
return innerNetworkInterfaces ;
}
private static Optional < NetworkInterface > findOuterAddress ( List < NetworkInterface > validNetworkInterfaces ) {
private static List < NetworkInterface > findOuterAddressNetworkInterface ( List < NetworkInterface > validNetworkInterfaces ) {
if ( CollectionUtils . isEmpty ( validNetworkInterfaces ) ) {
return Optional . empty ( ) ;
return Collections . emptyList ( ) ;
}
List < NetworkInterface > outerNetworkInterfaces = new ArrayList < > ( ) ;
for ( NetworkInterface ni : validNetworkInterfaces ) {
Enumeration < InetAddress > address = ni . getInetAddresses ( ) ;
while ( address . hasMoreElements ( ) ) {
InetAddress ip = address . nextElement ( ) ;
if ( ! ip . isSiteLocalAddress ( )
& & ! ip . isLoopbackAddress ( ) ) {
return Optional . of ( ni ) ;
if ( ! ip . isSiteLocalAddress ( ) & & ! ip . isLoopbackAddress ( ) ) {
outerNetworkInterfaces . add ( ni ) ;
}
}
}
return Optional . empty ( ) ;
return outerNetworkInterfaces ;
}
}