/* * Copyright 2015 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.discovery.shared.resolver; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.netflix.appinfo.AmazonInfo; import com.netflix.appinfo.DataCenterInfo; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.shared.resolver.aws.AwsEndpoint; import com.netflix.discovery.shared.transport.EurekaTransportConfig; import com.netflix.discovery.util.SystemUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Tomasz Bak */ public final class ResolverUtils { private static final Logger logger = LoggerFactory.getLogger(ResolverUtils.class); private static final String LOCAL_IPV4_ADDRESS = SystemUtil.getServerIPv4(); private static final Pattern ZONE_RE = Pattern.compile("(txt\\.)?([^.]+).*"); private ResolverUtils() { } /** * @return returns two element array with first item containing list of endpoints from client's zone, * and in the second list all the remaining ones */ public static List<AwsEndpoint>[] splitByZone(List<AwsEndpoint> eurekaEndpoints, String myZone) { if (eurekaEndpoints.isEmpty()) { return new List[]{Collections.emptyList(), Collections.emptyList()}; } if (myZone == null) { return new List[]{Collections.emptyList(), new ArrayList<>(eurekaEndpoints)}; } List<AwsEndpoint> myZoneList = new ArrayList<>(eurekaEndpoints.size()); List<AwsEndpoint> remainingZonesList = new ArrayList<>(eurekaEndpoints.size()); for (AwsEndpoint endpoint : eurekaEndpoints) { if (myZone.equalsIgnoreCase(endpoint.getZone())) { myZoneList.add(endpoint); } else { remainingZonesList.add(endpoint); } } return new List[]{myZoneList, remainingZonesList}; } public static String extractZoneFromHostName(String hostName) { Matcher matcher = ZONE_RE.matcher(hostName); if (matcher.matches()) { return matcher.group(2); } return null; } /** * Randomize server list using local IPv4 address hash as a seed. * * @return a copy of the original list with elements in the random order */ public static <T extends EurekaEndpoint> List<T> randomize(List<T> list) { List<T> randomList = new ArrayList<>(list); if (randomList.size() < 2) { return randomList; } Random random = new Random(LOCAL_IPV4_ADDRESS.hashCode()); int last = randomList.size() - 1; for (int i = 0; i < last; i++) { int pos = random.nextInt(randomList.size() - i); if (pos != i) { Collections.swap(randomList, i, pos); } } return randomList; } /** * @return true if both list are the same, possibly in a different order */ public static <T extends EurekaEndpoint> boolean identical(List<T> firstList, List<T> secondList) { if (firstList.size() != secondList.size()) { return false; } HashSet<T> compareSet = new HashSet<>(firstList); compareSet.removeAll(secondList); return compareSet.isEmpty(); } public static AwsEndpoint instanceInfoToEndpoint(EurekaClientConfig clientConfig, EurekaTransportConfig transportConfig, InstanceInfo instanceInfo) { String zone = null; DataCenterInfo dataCenterInfo = instanceInfo.getDataCenterInfo(); if (dataCenterInfo instanceof AmazonInfo) { zone = ((AmazonInfo) dataCenterInfo).get(AmazonInfo.MetaDataKey.availabilityZone); } String networkAddress; if (transportConfig.applicationsResolverUseIp()) { if (instanceInfo.getDataCenterInfo() instanceof AmazonInfo) { networkAddress = ((AmazonInfo) instanceInfo.getDataCenterInfo()).get(AmazonInfo.MetaDataKey.localIpv4); } else { networkAddress = instanceInfo.getIPAddr(); } } else { networkAddress = instanceInfo.getHostName(); } if (networkAddress == null) { // final check logger.error("Cannot resolve InstanceInfo {} to a proper resolver endpoint, skipping", instanceInfo); return null; } return new AwsEndpoint( networkAddress, instanceInfo.getPort(), false, clientConfig.getEurekaServerURLContext(), clientConfig.getRegion(), zone ); } }