/*
* Copyright 2012 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.appinfo;
import com.google.inject.ProvidedBy;
import com.netflix.appinfo.AmazonInfo.MetaDataKey;
import com.netflix.appinfo.providers.CloudInstanceConfigProvider;
import com.netflix.discovery.CommonConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Singleton;
/**
* An {@link InstanceInfo} configuration for AWS cloud deployments.
*
* <p>
* The information required for registration with eureka by a combination of
* user-supplied values as well as querying AWS instance metadata.An utility
* class {@link AmazonInfo} helps in retrieving AWS specific values. Some of
* that information including <em>availability zone</em> is used for determining
* which eureka server to communicate to.
* </p>
*
* @author Karthik Ranganathan
*
*/
@Singleton
@ProvidedBy(CloudInstanceConfigProvider.class)
public class CloudInstanceConfig extends PropertiesInstanceConfig implements RefreshableInstanceConfig {
private static final Logger logger = LoggerFactory.getLogger(CloudInstanceConfig.class);
private static final String[] DEFAULT_AWS_ADDRESS_RESOLUTION_ORDER = new String[] {
MetaDataKey.publicHostname.name(),
MetaDataKey.localIpv4.name()
};
private final AmazonInfoConfig amazonInfoConfig;
private final RefreshableAmazonInfoProvider amazonInfoHolder;
public CloudInstanceConfig() {
this(CommonConstants.DEFAULT_CONFIG_NAMESPACE);
}
public CloudInstanceConfig(String namespace) {
this(namespace, new Archaius1AmazonInfoConfig(namespace), null, true);
}
/* visible for testing */ CloudInstanceConfig(AmazonInfo info) {
this(CommonConstants.DEFAULT_CONFIG_NAMESPACE, new Archaius1AmazonInfoConfig(CommonConstants.DEFAULT_CONFIG_NAMESPACE), info, false);
}
/* visible for testing */ CloudInstanceConfig(String namespace, AmazonInfoConfig amazonInfoConfig, AmazonInfo initialInfo, boolean eagerInit) {
super(namespace);
this.amazonInfoConfig = amazonInfoConfig;
if (eagerInit) {
RefreshableAmazonInfoProvider.FallbackAddressProvider fallbackAddressProvider =
new RefreshableAmazonInfoProvider.FallbackAddressProvider() {
@Override
public String getFallbackIp() {
return CloudInstanceConfig.super.getIpAddress();
}
@Override
public String getFallbackHostname() {
return CloudInstanceConfig.super.getHostName(false);
}
};
this.amazonInfoHolder = new RefreshableAmazonInfoProvider(amazonInfoConfig, fallbackAddressProvider);
} else {
this.amazonInfoHolder = new RefreshableAmazonInfoProvider(initialInfo, amazonInfoConfig);
}
}
/**
* @deprecated use {@link #resolveDefaultAddress(boolean)}
*/
@Deprecated
public String resolveDefaultAddress() {
return this.resolveDefaultAddress(true);
}
@Override
public String resolveDefaultAddress(boolean refresh) {
// In this method invocation data center info will be refreshed.
String result = getHostName(refresh);
for (String name : getDefaultAddressResolutionOrder()) {
try {
AmazonInfo.MetaDataKey key = AmazonInfo.MetaDataKey.valueOf(name);
String address = amazonInfoHolder.get().get(key);
if (address != null && !address.isEmpty()) {
result = address;
break;
}
} catch (Exception e) {
logger.error("failed to resolve default address for key {}, skipping", name, e);
}
}
return result;
}
@Override
public String getHostName(boolean refresh) {
if (refresh) {
amazonInfoHolder.refresh();
}
return amazonInfoHolder.get().get(MetaDataKey.publicHostname);
}
@Override
public String getIpAddress() {
String ipAddr = amazonInfoHolder.get().get(MetaDataKey.localIpv4);
return ipAddr == null ? super.getIpAddress() : ipAddr;
}
@Override
public DataCenterInfo getDataCenterInfo() {
return amazonInfoHolder.get();
}
@Override
public String[] getDefaultAddressResolutionOrder() {
String[] order = super.getDefaultAddressResolutionOrder();
return (order.length == 0) ? DEFAULT_AWS_ADDRESS_RESOLUTION_ORDER : order;
}
/**
* @deprecated 2016-09-07
*
* Refresh instance info - currently only used when in AWS cloud
* as a public ip can change whenever an EIP is associated or dissociated.
*/
@Deprecated
public synchronized void refreshAmazonInfo() {
amazonInfoHolder.refresh();
}
/**
* @deprecated 2016-09-07
*/
@Deprecated
/* visible for testing */ static boolean shouldUpdate(AmazonInfo newInfo, AmazonInfo oldInfo) {
return RefreshableAmazonInfoProvider.shouldUpdate(newInfo, oldInfo);
}
}