/* * 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.eureka; import javax.annotation.Nullable; import javax.inject.Singleton; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import com.netflix.config.ConfigurationManager; import com.netflix.config.DynamicBooleanProperty; import com.netflix.config.DynamicIntProperty; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; import com.netflix.config.DynamicStringSetProperty; import com.netflix.eureka.aws.AwsBindingStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * A default implementation of eureka server configuration as required by * {@link EurekaServerConfig}. * * <p> * The information required for configuring eureka server is provided in a * configuration file.The configuration file is searched for in the classpath * with the name specified by the property <em>eureka.server.props</em> and with * the suffix <em>.properties</em>. If the property is not specified, * <em>eureka-server.properties</em> is assumed as the default.The properties * that are looked up uses the <em>namespace</em> passed on to this class. * </p> * * <p> * If the <em>eureka.environment</em> property is specified, additionally * <em>eureka-server-<eureka.environment>.properties</em> is loaded in addition * to <em>eureka-server.properties</em>. * </p> * * @author Karthik Ranganathan * */ @Singleton public class DefaultEurekaServerConfig implements EurekaServerConfig { private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment"; private static final String TEST = "test"; private static final String EUREKA_ENVIRONMENT = "eureka.environment"; private static final Logger logger = LoggerFactory .getLogger(DefaultEurekaServerConfig.class); private static final DynamicPropertyFactory configInstance = com.netflix.config.DynamicPropertyFactory .getInstance(); private static final DynamicStringProperty EUREKA_PROPS_FILE = DynamicPropertyFactory .getInstance().getStringProperty("eureka.server.props", "eureka-server"); private static final int TIME_TO_WAIT_FOR_REPLICATION = 30000; private String namespace = "eureka."; // These counters are checked for each HTTP request. Instantiating them per request like for the other // properties would be too costly. private final DynamicStringSetProperty rateLimiterPrivilegedClients = new DynamicStringSetProperty(namespace + "rateLimiter.privilegedClients", Collections.<String>emptySet()); private final DynamicBooleanProperty rateLimiterEnabled = configInstance.getBooleanProperty(namespace + "rateLimiter.enabled", false); private final DynamicBooleanProperty rateLimiterThrottleStandardClients = configInstance.getBooleanProperty(namespace + "rateLimiter.throttleStandardClients", false); private final DynamicIntProperty rateLimiterBurstSize = configInstance.getIntProperty(namespace + "rateLimiter.burstSize", 10); private final DynamicIntProperty rateLimiterRegistryFetchAverageRate = configInstance.getIntProperty(namespace + "rateLimiter.registryFetchAverageRate", 500); private final DynamicIntProperty rateLimiterFullFetchAverageRate = configInstance.getIntProperty(namespace + "rateLimiter.fullFetchAverageRate", 100); private final DynamicStringProperty listAutoScalingGroupsRoleName = configInstance.getStringProperty(namespace + "listAutoScalingGroupsRoleName", "ListAutoScalingGroups"); public DefaultEurekaServerConfig() { init(); } public DefaultEurekaServerConfig(String namespace) { this.namespace = namespace; init(); } private void init() { String env = ConfigurationManager.getConfigInstance().getString( EUREKA_ENVIRONMENT, TEST); ConfigurationManager.getConfigInstance().setProperty( ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env); String eurekaPropsFile = EUREKA_PROPS_FILE.get(); try { // ConfigurationManager // .loadPropertiesFromResources(eurekaPropsFile); ConfigurationManager .loadCascadedPropertiesFromResources(eurekaPropsFile); } catch (IOException e) { logger.warn( "Cannot find the properties specified : {}. This may be okay if there are other environment " + "specific properties or the configuration is installed with a different mechanism.", eurekaPropsFile); } } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#getAWSAccessId() */ @Override public String getAWSAccessId() { String aWSAccessId = configInstance.getStringProperty( namespace + "awsAccessId", null).get(); if (null != aWSAccessId) { return aWSAccessId.trim(); } else { return null; } } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#getAWSAccessId() */ @Override public String getAWSSecretKey() { String aWSSecretKey = configInstance.getStringProperty( namespace + "awsSecretKey", null).get(); if (null != aWSSecretKey) { return aWSSecretKey.trim(); } else { return null; } } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#getEIPBindRebindRetries() */ @Override public int getEIPBindRebindRetries() { return configInstance.getIntProperty( namespace + "eipBindRebindRetries", 3).get(); } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#getEIPBindingRetryInterval() */ @Override public int getEIPBindingRetryIntervalMsWhenUnbound() { return configInstance.getIntProperty( namespace + "eipBindRebindRetryIntervalMsWhenUnbound", (1 * 60 * 1000)).get(); } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#getEIPBindingRetryInterval() */ @Override public int getEIPBindingRetryIntervalMs() { return configInstance.getIntProperty( namespace + "eipBindRebindRetryIntervalMs", (5 * 60 * 1000)).get(); } /* * (non-Javadoc) * * @see com.netflix.eureka.EurekaServerConfig#shouldEnableSelfPreservation() */ @Override public boolean shouldEnableSelfPreservation() { return configInstance.getBooleanProperty( namespace + "enableSelfPreservation", true).get(); } /* * (non-Javadoc) * * @see * com.netflix.eureka.EurekaServerConfig#getPeerEurekaNodesUpdateInterval() */ @Override public int getPeerEurekaNodesUpdateIntervalMs() { return configInstance .getIntProperty(namespace + "peerEurekaNodesUpdateIntervalMs", (10 * 60 * 1000)).get(); } @Override public int getRenewalThresholdUpdateIntervalMs() { return configInstance.getIntProperty( namespace + "renewalThresholdUpdateIntervalMs", (15 * 60 * 1000)).get(); } @Override public double getRenewalPercentThreshold() { return configInstance.getDoubleProperty( namespace + "renewalPercentThreshold", 0.85).get(); } @Override public boolean shouldEnableReplicatedRequestCompression() { return configInstance.getBooleanProperty( namespace + "enableReplicatedRequestCompression", false).get(); } @Override public int getNumberOfReplicationRetries() { return configInstance.getIntProperty( namespace + "numberOfReplicationRetries", 5).get(); } @Override public int getPeerEurekaStatusRefreshTimeIntervalMs() { return configInstance.getIntProperty( namespace + "peerEurekaStatusRefreshTimeIntervalMs", (30 * 1000)).get(); } @Override public int getWaitTimeInMsWhenSyncEmpty() { return configInstance.getIntProperty( namespace + "waitTimeInMsWhenSyncEmpty", (1000 * 60 * 5)).get(); } @Override public int getPeerNodeConnectTimeoutMs() { return configInstance.getIntProperty( namespace + "peerNodeConnectTimeoutMs", 200).get(); } @Override public int getPeerNodeReadTimeoutMs() { return configInstance.getIntProperty( namespace + "peerNodeReadTimeoutMs", 200).get(); } @Override public int getPeerNodeTotalConnections() { return configInstance.getIntProperty( namespace + "peerNodeTotalConnections", 1000).get(); } @Override public int getPeerNodeTotalConnectionsPerHost() { return configInstance.getIntProperty( namespace + "peerNodeTotalConnectionsPerHost", 500).get(); } @Override public int getPeerNodeConnectionIdleTimeoutSeconds() { return configInstance.getIntProperty( namespace + "peerNodeConnectionIdleTimeoutSeconds", 30).get(); } @Override public long getRetentionTimeInMSInDeltaQueue() { return configInstance.getLongProperty( namespace + "retentionTimeInMSInDeltaQueue", (3 * 60 * 1000)) .get(); } @Override public long getDeltaRetentionTimerIntervalInMs() { return configInstance.getLongProperty( namespace + "deltaRetentionTimerIntervalInMs", (30 * 1000)) .get(); } @Override public long getEvictionIntervalTimerInMs() { return configInstance.getLongProperty( namespace + "evictionIntervalTimerInMs", (60 * 1000)).get(); } @Override public int getASGQueryTimeoutMs() { return configInstance.getIntProperty(namespace + "asgQueryTimeoutMs", 300).get(); } @Override public long getASGUpdateIntervalMs() { return configInstance.getIntProperty(namespace + "asgUpdateIntervalMs", (5 * 60 * 1000)).get(); } @Override public long getASGCacheExpiryTimeoutMs() { return configInstance.getIntProperty(namespace + "asgCacheExpiryTimeoutMs", (10 * 60 * 1000)).get(); // defaults to longer than the asg update interval } @Override public long getResponseCacheAutoExpirationInSeconds() { return configInstance.getIntProperty( namespace + "responseCacheAutoExpirationInSeconds", 180).get(); } @Override public long getResponseCacheUpdateIntervalMs() { return configInstance.getIntProperty( namespace + "responseCacheUpdateIntervalMs", (30 * 1000)).get(); } @Override public boolean shouldUseReadOnlyResponseCache() { return configInstance.getBooleanProperty( namespace + "shouldUseReadOnlyResponseCache", true).get(); } @Override public boolean shouldDisableDelta() { return configInstance.getBooleanProperty(namespace + "disableDelta", false).get(); } @Override public long getMaxIdleThreadInMinutesAgeForStatusReplication() { return configInstance .getLongProperty( namespace + "maxIdleThreadAgeInMinutesForStatusReplication", 10).get(); } @Override public int getMinThreadsForStatusReplication() { return configInstance.getIntProperty( namespace + "minThreadsForStatusReplication", 1).get(); } @Override public int getMaxThreadsForStatusReplication() { return configInstance.getIntProperty( namespace + "maxThreadsForStatusReplication", 1).get(); } @Override public int getMaxElementsInStatusReplicationPool() { return configInstance.getIntProperty( namespace + "maxElementsInStatusReplicationPool", 10000).get(); } @Override public boolean shouldSyncWhenTimestampDiffers() { return configInstance.getBooleanProperty( namespace + "syncWhenTimestampDiffers", true).get(); } @Override public int getRegistrySyncRetries() { return configInstance.getIntProperty( namespace + "numberRegistrySyncRetries", 5).get(); } @Override public long getRegistrySyncRetryWaitMs() { return configInstance.getIntProperty( namespace + "registrySyncRetryWaitMs", 30 * 1000).get(); } @Override public int getMaxElementsInPeerReplicationPool() { return configInstance.getIntProperty( namespace + "maxElementsInPeerReplicationPool", 10000).get(); } @Override public long getMaxIdleThreadAgeInMinutesForPeerReplication() { return configInstance.getIntProperty( namespace + "maxIdleThreadAgeInMinutesForPeerReplication", 15) .get(); } @Override public int getMinThreadsForPeerReplication() { return configInstance.getIntProperty( namespace + "minThreadsForPeerReplication", 5).get(); } @Override public int getMaxThreadsForPeerReplication() { return configInstance.getIntProperty( namespace + "maxThreadsForPeerReplication", 20).get(); } @Override public int getMaxTimeForReplication() { return configInstance.getIntProperty( namespace + "maxTimeForReplication", TIME_TO_WAIT_FOR_REPLICATION).get(); } @Override public boolean shouldPrimeAwsReplicaConnections() { return configInstance.getBooleanProperty( namespace + "primeAwsReplicaConnections", true).get(); } @Override public boolean shouldDisableDeltaForRemoteRegions() { return configInstance.getBooleanProperty( namespace + "disableDeltaForRemoteRegions", false).get(); } @Override public int getRemoteRegionConnectTimeoutMs() { return configInstance.getIntProperty( namespace + "remoteRegionConnectTimeoutMs", 1000).get(); } @Override public int getRemoteRegionReadTimeoutMs() { return configInstance.getIntProperty( namespace + "remoteRegionReadTimeoutMs", 1000).get(); } @Override public int getRemoteRegionTotalConnections() { return configInstance.getIntProperty( namespace + "remoteRegionTotalConnections", 1000).get(); } @Override public int getRemoteRegionTotalConnectionsPerHost() { return configInstance.getIntProperty( namespace + "remoteRegionTotalConnectionsPerHost", 500).get(); } @Override public int getRemoteRegionConnectionIdleTimeoutSeconds() { return configInstance.getIntProperty( namespace + "remoteRegionConnectionIdleTimeoutSeconds", 30) .get(); } @Override public boolean shouldGZipContentFromRemoteRegion() { return configInstance.getBooleanProperty( namespace + "remoteRegion.gzipContent", true).get(); } /** * Expects a property with name: [eureka-namespace].remoteRegionUrlsWithName and a value being a comma separated * list of region name & remote url pairs, separated with a ";". <br/> * So, if you wish to specify two regions with name region1 & region2, the property value will be: <PRE> eureka.remoteRegionUrlsWithName=region1;http://region1host/eureka/v2,region2;http://region2host/eureka/v2 </PRE> * The above property will result in the following map: <PRE> region1->"http://region1host/eureka/v2" region2->"http://region2host/eureka/v2" </PRE> * @return A map of region name to remote region URL parsed from the property specified above. If there is no * property available, then an empty map is returned. */ @Override public Map<String, String> getRemoteRegionUrlsWithName() { String propName = namespace + "remoteRegionUrlsWithName"; String remoteRegionUrlWithNameString = configInstance.getStringProperty(propName, null).get(); if (null == remoteRegionUrlWithNameString) { return Collections.emptyMap(); } String[] remoteRegionUrlWithNamePairs = remoteRegionUrlWithNameString.split(","); Map<String, String> toReturn = new HashMap<String, String>(remoteRegionUrlWithNamePairs.length); final String pairSplitChar = ";"; for (String remoteRegionUrlWithNamePair : remoteRegionUrlWithNamePairs) { String[] pairSplit = remoteRegionUrlWithNamePair.split(pairSplitChar); if (pairSplit.length < 2) { logger.error("Error reading eureka remote region urls from property {}. " + "Invalid entry {} for remote region url. The entry must contain region name and url " + "separated by a {}. Ignoring this entry.", new String[]{propName, remoteRegionUrlWithNamePair, pairSplitChar}); } else { String regionName = pairSplit[0]; String regionUrl = pairSplit[1]; if (pairSplit.length > 2) { StringBuilder regionUrlAssembler = new StringBuilder(); for (int i = 1; i < pairSplit.length; i++) { if (regionUrlAssembler.length() != 0) { regionUrlAssembler.append(pairSplitChar); } regionUrlAssembler.append(pairSplit[i]); } regionUrl = regionUrlAssembler.toString(); } toReturn.put(regionName, regionUrl); } } return toReturn; } @Override public String[] getRemoteRegionUrls() { String remoteRegionUrlString = configInstance.getStringProperty( namespace + "remoteRegionUrls", null).get(); String[] remoteRegionUrl = null; if (remoteRegionUrlString != null) { remoteRegionUrl = remoteRegionUrlString.split(","); } return remoteRegionUrl; } @Nullable @Override public Set<String> getRemoteRegionAppWhitelist(@Nullable String regionName) { if (null == regionName) { regionName = "global"; } else { regionName = regionName.trim().toLowerCase(); } DynamicStringProperty appWhiteListProp = configInstance.getStringProperty(namespace + "remoteRegion." + regionName + ".appWhiteList", null); if (null == appWhiteListProp || null == appWhiteListProp.get()) { return null; } else { String appWhiteListStr = appWhiteListProp.get(); String[] whitelistEntries = appWhiteListStr.split(","); return new HashSet<String>(Arrays.asList(whitelistEntries)); } } @Override public int getRemoteRegionRegistryFetchInterval() { return configInstance.getIntProperty( namespace + "remoteRegion.registryFetchIntervalInSeconds", 30) .get(); } @Override public int getRemoteRegionFetchThreadPoolSize() { return configInstance.getIntProperty( namespace + "remoteRegion.fetchThreadPoolSize", 20) .get(); } @Override public String getRemoteRegionTrustStore() { return configInstance.getStringProperty( namespace + "remoteRegion.trustStoreFileName", "").get(); } @Override public String getRemoteRegionTrustStorePassword() { return configInstance.getStringProperty( namespace + "remoteRegion.trustStorePassword", "changeit") .get(); } @Override public boolean disableTransparentFallbackToOtherRegion() { return configInstance.getBooleanProperty(namespace + "remoteRegion.disable.transparent.fallback", false).get(); } @Override public boolean shouldBatchReplication() { return configInstance.getBooleanProperty(namespace + "shouldBatchReplication", false).get(); } @Override public boolean shouldLogIdentityHeaders() { return configInstance.getBooleanProperty(namespace + "auth.shouldLogIdentityHeaders", true).get(); } @Override public String getJsonCodecName() { return configInstance.getStringProperty( namespace + "jsonCodecName", null).get(); } @Override public String getXmlCodecName() { return configInstance.getStringProperty( namespace + "xmlCodecName", null).get(); } @Override public boolean isRateLimiterEnabled() { return rateLimiterEnabled.get(); } @Override public boolean isRateLimiterThrottleStandardClients() { return rateLimiterThrottleStandardClients.get(); } @Override public Set<String> getRateLimiterPrivilegedClients() { return rateLimiterPrivilegedClients.get(); } @Override public int getRateLimiterBurstSize() { return rateLimiterBurstSize.get(); } @Override public int getRateLimiterRegistryFetchAverageRate() { return rateLimiterRegistryFetchAverageRate.get(); } @Override public int getRateLimiterFullFetchAverageRate() { return rateLimiterFullFetchAverageRate.get(); } @Override public String getListAutoScalingGroupsRoleName() { return listAutoScalingGroupsRoleName.get(); } @Override public int getRoute53BindRebindRetries() { return configInstance.getIntProperty( namespace + "route53BindRebindRetries", 3).get(); } @Override public int getRoute53BindingRetryIntervalMs() { return configInstance.getIntProperty( namespace + "route53BindRebindRetryIntervalMs", (5 * 60 * 1000)) .get(); } @Override public long getRoute53DomainTTL() { return configInstance.getLongProperty( namespace + "route53DomainTTL", 30l) .get(); } @Override public AwsBindingStrategy getBindingStrategy() { return AwsBindingStrategy.valueOf(configInstance.getStringProperty(namespace + "awsBindingStrategy", AwsBindingStrategy.EIP.name()).get().toUpperCase()); } @Override public String getExperimental(String name) { return configInstance.getStringProperty(namespace + "experimental." + name, null).get(); } @Override public int getHealthStatusMinNumberOfAvailablePeers() { return configInstance.getIntProperty( namespace + "minAvailableInstancesForPeerReplication", -1).get(); } }