Skip to content

Commit

Permalink
Merge pull request #1513 from Netflix/feature/eni-eips
Browse files Browse the repository at this point in the history
Add support for EIPs associated with secondary ENIs
  • Loading branch information
drobertduke committed Nov 13, 2023
2 parents efc1cf6 + f4b1fa2 commit bae5c36
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 6 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ allprojects {
// test deps
jetty_version = '7.2.0.v20101020'
junit_version = '4.11'
mockitoVersion = '1.10.19'
mockitoVersion = '3.4.0'
mockserverVersion = '3.9.2'
}
}
Expand Down
2 changes: 1 addition & 1 deletion eureka-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dependencies {
testCompile project(':eureka-test-utils')
testCompile "junit:junit:${junit_version}"
testCompile 'org.mortbay.jetty:jetty:6.1H.22'
testCompile "org.mockito:mockito-core:${mockitoVersion}"
testCompile "org.mockito:mockito-inline:${mockitoVersion}"
testCompile "org.mock-server:mockserver-netty:${mockserverVersion}"
testCompile "com.netflix.governator:governator:${governatorVersion}"
testCompile "com.github.tomakehurst:wiremock-jre8:2.25.1"
Expand Down
43 changes: 43 additions & 0 deletions eureka-client/src/main/java/com/netflix/appinfo/AmazonInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
Expand Down Expand Up @@ -63,6 +64,32 @@ public enum MetaDataKey {
availabilityZone("availability-zone", "placement/"),
publicHostname("public-hostname"),
publicIpv4("public-ipv4"),
// macs declared above public-ipv4s so will be found before publicIpv4s (where it is needed)
macs("macs", "network/interfaces/") {
@Override
public String read(InputStream inputStream) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String toReturn;
try {
toReturn = br.lines().collect(Collectors.joining("\n"));
} finally {
br.close();
}

return toReturn;
}
},
// Because we stop reading the body returned by IMDS after the first newline,
// publicIPv4s will only contain the first IPv4 address returned in the body of the
// URL for a given MAC, despite IMDS being able to return multiple addresses under
// that key (separated by \n). The first IPv4 address is always the one attached to
// the interface and is the only address that should be registered for this instance.
publicIpv4s("public-ipv4s", "network/interfaces/macs/") {
@Override
public URL getURL(String prepend, String mac) throws MalformedURLException {
return new URL(AWS_METADATA_URL + this.path + mac + "/" + this.name);
}
},
ipv6("ipv6"),
spotTerminationTime("termination-time", "spot/"),
spotInstanceAction("instance-action", "spot/"),
Expand Down Expand Up @@ -200,10 +227,26 @@ public AmazonInfo autoBuild(String namespace) {
int numOfRetries = config.getNumRetries();
while (numOfRetries-- > 0) {
try {
if (key == MetaDataKey.publicIpv4s) {
// macs should be read before publicIpv4s due to declaration order
String[] macs = result.metadata.get(MetaDataKey.macs.getName()).split("\n");
for (String mac : macs) {
URL url = key.getURL(null, mac);
String publicIpv4s = AmazonInfoUtils.readEc2MetadataUrl(key, url, config.getConnectTimeout(), config.getReadTimeout());

if (publicIpv4s != null) {
result.metadata.put(key.getName(), publicIpv4s);
break;
}
}
break;
}

String mac = null;
if (key == MetaDataKey.vpcId) {
mac = result.metadata.get(MetaDataKey.mac.getName()); // mac should be read before vpcId due to declaration order
}

URL url = key.getURL(null, mac);
String value = AmazonInfoUtils.readEc2MetadataUrl(key, url, config.getConnectTimeout(), config.getReadTimeout());
if (value != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ private String getPrivateIpv4Addr() {
}
private String getPublicIpv4Addr() {
String publicIpv4Addr = amazonInfoHolder.get().get(MetaDataKey.publicIpv4);
if (publicIpv4Addr == null) {
// publicIpv4s is named as a plural to not conflict with the existing publicIpv4 key. In AmazonInfo.java,
// we filter out for the first found IPv4 address in any of the network interface IMDS keys. If it exists,
// the value for MetaDataKey.publicIpv4s will always be a string with at most 1 public IPv4 address.
publicIpv4Addr = amazonInfoHolder.get().get(MetaDataKey.publicIpv4s);
}
return publicIpv4Addr == null ? super.getIpAddress() : publicIpv4Addr;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;

import com.netflix.discovery.internal.util.AmazonInfoUtils;
import org.junit.Test;

import org.mockito.MockedStatic;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mockStatic;

import static org.junit.Assert.assertEquals;


/**
* @author David Liu
*/
Expand Down Expand Up @@ -34,4 +46,85 @@ public void testExtractAccountId() throws Exception {

assertEquals("1111111111", accountId);
}

@Test
public void testExtractMacs_SingleMac() throws Exception {
String body = "0d:c2:9a:3c:18:2b";

InputStream inputStream = new ByteArrayInputStream(body.getBytes());
String macs = AmazonInfo.MetaDataKey.macs.read(inputStream);

assertEquals("0d:c2:9a:3c:18:2b", macs);
}

@Test
public void testExtractMacs_MultipleMacs() throws Exception {
String body = "0d:c2:9a:3c:18:2b\n4c:31:99:7e:26:d6";

InputStream inputStream = new ByteArrayInputStream(body.getBytes());
String macs = AmazonInfo.MetaDataKey.macs.read(inputStream);

assertEquals("0d:c2:9a:3c:18:2b\n4c:31:99:7e:26:d6", macs);
}

@Test
public void testExtractPublicIPv4s_SingleAddress() throws Exception {
String body = "10.0.0.1";

InputStream inputStream = new ByteArrayInputStream(body.getBytes());
String publicIPv4s = AmazonInfo.MetaDataKey.publicIpv4s.read(inputStream);

assertEquals("10.0.0.1", publicIPv4s);
}

@Test
public void testExtractPublicIPv4s_MultipleAddresses() throws Exception {
String body = "10.0.0.1\n10.0.0.2";

InputStream inputStream = new ByteArrayInputStream(body.getBytes());
String publicIPv4s = AmazonInfo.MetaDataKey.publicIpv4s.read(inputStream);

assertEquals("10.0.0.1", publicIPv4s);
}

@Test
public void testAutoBuild() throws Exception {
try (MockedStatic<AmazonInfoUtils> mockUtils = mockStatic(AmazonInfoUtils.class)) {
mockUtils.when(
() -> AmazonInfoUtils.readEc2MetadataUrl(any(AmazonInfo.MetaDataKey.class), any(URL.class), anyInt(), anyInt())
).thenReturn(null);

mockUtils.when(
() -> AmazonInfoUtils.readEc2MetadataUrl(any(AmazonInfo.MetaDataKey.class), any(URL.class), anyInt(), anyInt())
).thenReturn(null);

URL macsUrl = AmazonInfo.MetaDataKey.macs.getURL(null, null);
mockUtils.when(
() -> AmazonInfoUtils.readEc2MetadataUrl(eq(AmazonInfo.MetaDataKey.macs), eq(macsUrl), anyInt(), anyInt())
).thenReturn("0d:c2:9a:3c:18:2b\n4c:31:99:7e:26:d6");

URL firstMacPublicIPv4sUrl = AmazonInfo.MetaDataKey.publicIpv4s.getURL(null, "0d:c2:9a:3c:18:2b");
mockUtils.when(
() -> AmazonInfoUtils.readEc2MetadataUrl(eq(AmazonInfo.MetaDataKey.publicIpv4s), eq(firstMacPublicIPv4sUrl), anyInt(), anyInt())
).thenReturn(null);

URL secondMacPublicIPv4sUrl = AmazonInfo.MetaDataKey.publicIpv4s.getURL(null, "4c:31:99:7e:26:d6");
mockUtils.when(
() -> AmazonInfoUtils.readEc2MetadataUrl(eq(AmazonInfo.MetaDataKey.publicIpv4s), eq(secondMacPublicIPv4sUrl), anyInt(), anyInt())
).thenReturn("10.0.0.1");

AmazonInfoConfig config = mock(AmazonInfoConfig.class);
when(config.getNamespace()).thenReturn("test_namespace");
when(config.getConnectTimeout()).thenReturn(10);
when(config.getNumRetries()).thenReturn(1);
when(config.getReadTimeout()).thenReturn(10);
when(config.shouldLogAmazonMetadataErrors()).thenReturn(false);
when(config.shouldValidateInstanceId()).thenReturn(false);
when(config.shouldFailFastOnFirstLoad()).thenReturn(false);

AmazonInfo info = AmazonInfo.Builder.newBuilder().withAmazonInfoConfig(config).autoBuild("test_namespace");

assertEquals("10.0.0.1", info.get(AmazonInfo.MetaDataKey.publicIpv4s));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ public void testBroadcastPublicIpv4Address() {
assertEquals(instanceInfo.getIPAddr(), config.getIpAddress());
}

@Test
public void testBroadcastPublicIpv4Address_usingPublicIpv4s() {
AmazonInfo info = (AmazonInfo) instanceInfo.getDataCenterInfo();
info.getMetadata().remove(AmazonInfo.MetaDataKey.publicIpv4.getName());
info.getMetadata().put(AmazonInfo.MetaDataKey.publicIpv4s.getName(), "10.0.0.1");

config = createConfig(info);

assertEquals("10.0.0.1", config.getIpAddress());
}

private CloudInstanceConfig createConfig(AmazonInfo info) {

return new CloudInstanceConfig(info) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void testOnDemandUpdateRateLimiting() throws Throwable {
assertTrue(replicator.onDemandUpdate());
Thread.sleep(10); // give some time for execution
assertFalse(replicator.onDemandUpdate());
Thread.sleep(10);
Thread.sleep(1000);

verify(discoveryClient, times(2)).refreshInstanceInfo();
verify(discoveryClient, times(1)).register();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ public void testForceGzip() throws Exception {
@Test
public void testForceGzipOtherHeader() throws Exception {
noneGzipRequest();
when(request.getHeader("Test")).thenReturn("ok");
when(request.getHeaders("Test")).thenReturn(new Enumeration() {
private int c = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ public static ReplicationInstance newReplicationInstanceOf(Action action, Instan
instance.getAppName(),
instance.getId(),
System.currentTimeMillis(),
InstanceStatus.OUT_OF_SERVICE.name(),
null,
InstanceStatus.OUT_OF_SERVICE.name(),
null,
action
);
Expand All @@ -109,8 +109,8 @@ public static ReplicationInstance newReplicationInstanceOf(Action action, Instan
instance.getAppName(),
instance.getId(),
System.currentTimeMillis(),
InstanceStatus.OUT_OF_SERVICE.name(),
null,
InstanceStatus.UP.name(),
null,
action
);
Expand Down

0 comments on commit bae5c36

Please sign in to comment.