mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
Add cluster ip for Kubernetes Nat Manager (#1156)
- Add compatibility with ClusterIP services in the kubernetes nat manager - Add new Xnat-method-fallback-enabled flag Signed-off-by: Karim TAAM <karim.t2am@gmail.com>
This commit is contained in:
@@ -33,12 +33,20 @@ public class NatService {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
private static final boolean DEFAULT_FALLBACK_STATUS = true;
|
||||
|
||||
private NatMethod currentNatMethod;
|
||||
private Optional<NatManager> currentNatManager;
|
||||
private final boolean fallbackEnabled;
|
||||
|
||||
public NatService(final Optional<NatManager> natManager) {
|
||||
public NatService(final Optional<NatManager> natManager, final boolean fallbackEnabled) {
|
||||
this.currentNatMethod = retrieveNatMethod(natManager);
|
||||
this.currentNatManager = natManager;
|
||||
this.fallbackEnabled = fallbackEnabled;
|
||||
}
|
||||
|
||||
public NatService(final Optional<NatManager> natManager) {
|
||||
this(natManager, DEFAULT_FALLBACK_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,10 +96,14 @@ public class NatService {
|
||||
getNatManager().orElseThrow().start();
|
||||
} catch (Exception e) {
|
||||
LOG.debug(
|
||||
"Nat manager failed to configure itself automatically due to the following reason "
|
||||
+ e.getMessage()
|
||||
+ ". NONE mode will be used");
|
||||
disableNatManager();
|
||||
"Nat manager failed to configure itself automatically due to the following reason : {}. {}",
|
||||
e.getMessage(),
|
||||
(fallbackEnabled) ? "NONE mode will be used" : "");
|
||||
if (fallbackEnabled) {
|
||||
disableNatManager();
|
||||
} else {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG.info("No NAT environment detected so no service could be started");
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.hyperledger.besu.nat.docker;
|
||||
package org.hyperledger.besu.nat.core;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface IpDetector {
|
||||
|
||||
Optional<String> detectExternalIp();
|
||||
Optional<String> detectAdvertisedIp() throws Exception;
|
||||
}
|
||||
@@ -17,12 +17,13 @@ package org.hyperledger.besu.nat.docker;
|
||||
|
||||
import org.hyperledger.besu.nat.NatMethod;
|
||||
import org.hyperledger.besu.nat.core.AbstractNatManager;
|
||||
import org.hyperledger.besu.nat.core.IpDetector;
|
||||
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
|
||||
import org.hyperledger.besu.nat.core.domain.NatServiceType;
|
||||
import org.hyperledger.besu.nat.core.domain.NetworkProtocol;
|
||||
import org.hyperledger.besu.nat.core.exception.NatInitializationException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -42,11 +43,11 @@ public class DockerNatManager extends AbstractNatManager {
|
||||
|
||||
private final IpDetector ipDetector;
|
||||
|
||||
private final String internalAdvertisedHost;
|
||||
private final int internalP2pPort;
|
||||
private final int internalRpcHttpPort;
|
||||
|
||||
private final List<NatPortMapping> forwardedPorts;
|
||||
private String internalAdvertisedHost;
|
||||
private final List<NatPortMapping> forwardedPorts = new ArrayList<>();
|
||||
|
||||
public DockerNatManager(final String advertisedHost, final int p2pPort, final int rpcHttpPort) {
|
||||
this(new HostBasedIpDetector(), advertisedHost, p2pPort, rpcHttpPort);
|
||||
@@ -62,45 +63,17 @@ public class DockerNatManager extends AbstractNatManager {
|
||||
this.internalAdvertisedHost = advertisedHost;
|
||||
this.internalP2pPort = p2pPort;
|
||||
this.internalRpcHttpPort = rpcHttpPort;
|
||||
this.forwardedPorts = buildForwardedPorts();
|
||||
}
|
||||
|
||||
private List<NatPortMapping> buildForwardedPorts() {
|
||||
try {
|
||||
final String internalHost = queryLocalIPAddress().get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
final String advertisedHost =
|
||||
retrieveExternalIPAddress().get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
return Arrays.asList(
|
||||
new NatPortMapping(
|
||||
NatServiceType.DISCOVERY,
|
||||
NetworkProtocol.UDP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalP2pPort,
|
||||
getExternalPort(internalP2pPort)),
|
||||
new NatPortMapping(
|
||||
NatServiceType.RLPX,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalP2pPort,
|
||||
getExternalPort(internalP2pPort)),
|
||||
new NatPortMapping(
|
||||
NatServiceType.JSON_RPC,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalRpcHttpPort,
|
||||
getExternalPort(internalRpcHttpPort)));
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to create forwarded port list", e);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
protected void doStart() throws NatInitializationException {
|
||||
LOG.info("Starting docker NAT manager.");
|
||||
try {
|
||||
ipDetector.detectAdvertisedIp().ifPresent(ipFound -> internalAdvertisedHost = ipFound);
|
||||
buildForwardedPorts();
|
||||
} catch (Exception e) {
|
||||
throw new NatInitializationException("Unable to retrieve IP from docker");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,10 +83,7 @@ public class DockerNatManager extends AbstractNatManager {
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<String> retrieveExternalIPAddress() {
|
||||
return ipDetector
|
||||
.detectExternalIp()
|
||||
.map(CompletableFuture::completedFuture)
|
||||
.orElse(CompletableFuture.completedFuture(internalAdvertisedHost));
|
||||
return CompletableFuture.completedFuture(internalAdvertisedHost);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,4 +96,38 @@ public class DockerNatManager extends AbstractNatManager {
|
||||
.map(Integer::valueOf)
|
||||
.orElse(defaultValue);
|
||||
}
|
||||
|
||||
private void buildForwardedPorts() {
|
||||
try {
|
||||
final String internalHost = queryLocalIPAddress().get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
final String advertisedHost =
|
||||
retrieveExternalIPAddress().get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
forwardedPorts.add(
|
||||
new NatPortMapping(
|
||||
NatServiceType.DISCOVERY,
|
||||
NetworkProtocol.UDP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalP2pPort,
|
||||
getExternalPort(internalP2pPort)));
|
||||
forwardedPorts.add(
|
||||
new NatPortMapping(
|
||||
NatServiceType.RLPX,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalP2pPort,
|
||||
getExternalPort(internalP2pPort)));
|
||||
forwardedPorts.add(
|
||||
new NatPortMapping(
|
||||
NatServiceType.JSON_RPC,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
advertisedHost,
|
||||
internalRpcHttpPort,
|
||||
getExternalPort(internalRpcHttpPort)));
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to create forwarded port list", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
package org.hyperledger.besu.nat.docker;
|
||||
|
||||
import org.hyperledger.besu.nat.core.IpDetector;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Optional;
|
||||
@@ -24,7 +26,7 @@ public class HostBasedIpDetector implements IpDetector {
|
||||
private static final String HOSTNAME = "HOST_IP";
|
||||
|
||||
@Override
|
||||
public Optional<String> detectExternalIp() {
|
||||
public Optional<String> detectAdvertisedIp() {
|
||||
try {
|
||||
return Optional.of(InetAddress.getByName(HOSTNAME).getHostAddress());
|
||||
} catch (final UnknownHostException e) {
|
||||
|
||||
@@ -17,14 +17,17 @@ package org.hyperledger.besu.nat.kubernetes;
|
||||
|
||||
import org.hyperledger.besu.nat.NatMethod;
|
||||
import org.hyperledger.besu.nat.core.AbstractNatManager;
|
||||
import org.hyperledger.besu.nat.core.IpDetector;
|
||||
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
|
||||
import org.hyperledger.besu.nat.core.domain.NatServiceType;
|
||||
import org.hyperledger.besu.nat.core.domain.NetworkProtocol;
|
||||
import org.hyperledger.besu.nat.core.exception.NatInitializationException;
|
||||
import org.hyperledger.besu.nat.kubernetes.service.KubernetesServiceType;
|
||||
import org.hyperledger.besu.nat.kubernetes.service.LoadBalancerBasedDetector;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -32,7 +35,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import io.kubernetes.client.ApiClient;
|
||||
import io.kubernetes.client.Configuration;
|
||||
import io.kubernetes.client.apis.CoreV1Api;
|
||||
import io.kubernetes.client.models.V1LoadBalancerIngress;
|
||||
import io.kubernetes.client.models.V1Service;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import io.kubernetes.client.util.KubeConfig;
|
||||
@@ -47,15 +49,15 @@ import org.apache.logging.log4j.Logger;
|
||||
public class KubernetesNatManager extends AbstractNatManager {
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
|
||||
public static final String DEFAULT_BESU_POD_NAME_FILTER = "besu";
|
||||
public static final String DEFAULT_BESU_SERVICE_NAME_FILTER = "besu";
|
||||
|
||||
private String internalAdvertisedHost;
|
||||
private final String besuPodNameFilter;
|
||||
private final String besuServiceNameFilter;
|
||||
private final List<NatPortMapping> forwardedPorts = new ArrayList<>();
|
||||
|
||||
public KubernetesNatManager(final String besuPodNameFilter) {
|
||||
public KubernetesNatManager(final String besuServiceNameFilter) {
|
||||
super(NatMethod.KUBERNETES);
|
||||
this.besuPodNameFilter = besuPodNameFilter;
|
||||
this.besuServiceNameFilter = besuServiceNameFilter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,7 +79,8 @@ public class KubernetesNatManager extends AbstractNatManager {
|
||||
final V1Service service =
|
||||
api.listServiceForAllNamespaces(null, null, null, null, null, null, null, null, null)
|
||||
.getItems().stream()
|
||||
.filter(v1Service -> v1Service.getMetadata().getName().contains(besuPodNameFilter))
|
||||
.filter(
|
||||
v1Service -> v1Service.getMetadata().getName().contains(besuServiceNameFilter))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NatInitializationException("Service not found"));
|
||||
updateUsingBesuService(service);
|
||||
@@ -91,21 +94,11 @@ public class KubernetesNatManager extends AbstractNatManager {
|
||||
try {
|
||||
LOG.info("Found Besu service: {}", service.getMetadata().getName());
|
||||
|
||||
final V1LoadBalancerIngress v1LoadBalancerIngress =
|
||||
service.getStatus().getLoadBalancer().getIngress().stream()
|
||||
.filter(
|
||||
v1LoadBalancerIngress1 ->
|
||||
v1LoadBalancerIngress1.getHostname() != null
|
||||
|| v1LoadBalancerIngress1.getIp() != null)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NatInitializationException("Ingress not found"));
|
||||
|
||||
if (v1LoadBalancerIngress.getHostname() != null) {
|
||||
internalAdvertisedHost =
|
||||
InetAddress.getByName(v1LoadBalancerIngress.getHostname()).getHostAddress();
|
||||
} else {
|
||||
internalAdvertisedHost = v1LoadBalancerIngress.getIp();
|
||||
}
|
||||
internalAdvertisedHost =
|
||||
getIpDetector(service)
|
||||
.detectAdvertisedIp()
|
||||
.orElseThrow(
|
||||
() -> new NatInitializationException("Unable to retrieve IP from service"));
|
||||
|
||||
LOG.info("Setting host IP to: {}.", internalAdvertisedHost);
|
||||
|
||||
@@ -152,4 +145,16 @@ public class KubernetesNatManager extends AbstractNatManager {
|
||||
public CompletableFuture<List<NatPortMapping>> getPortMappings() {
|
||||
return CompletableFuture.completedFuture(forwardedPorts);
|
||||
}
|
||||
|
||||
private IpDetector getIpDetector(final V1Service v1Service) throws NatInitializationException {
|
||||
final String serviceType = v1Service.getSpec().getType();
|
||||
switch (KubernetesServiceType.fromName(serviceType)) {
|
||||
case CLUSTER_IP:
|
||||
return () -> Optional.ofNullable(v1Service.getSpec().getClusterIP());
|
||||
case LOAD_BALANCER:
|
||||
return new LoadBalancerBasedDetector(v1Service);
|
||||
default:
|
||||
throw new NatInitializationException(String.format("%s is not implemented", serviceType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.nat.kubernetes.service;
|
||||
|
||||
public enum KubernetesServiceType {
|
||||
CLUSTER_IP("ClusterIP"),
|
||||
LOAD_BALANCER("LoadBalancer"),
|
||||
UNKNOWN("");
|
||||
|
||||
String name;
|
||||
|
||||
KubernetesServiceType(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static KubernetesServiceType fromName(final String name) {
|
||||
for (KubernetesServiceType value : values()) {
|
||||
if (value.name.equals(name)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.nat.kubernetes.service;
|
||||
|
||||
import org.hyperledger.besu.nat.core.IpDetector;
|
||||
import org.hyperledger.besu.nat.core.exception.NatInitializationException;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.kubernetes.client.models.V1LoadBalancerIngress;
|
||||
import io.kubernetes.client.models.V1Service;
|
||||
|
||||
public class LoadBalancerBasedDetector implements IpDetector {
|
||||
|
||||
private final V1Service v1Service;
|
||||
|
||||
public LoadBalancerBasedDetector(final V1Service v1Service) {
|
||||
this.v1Service = v1Service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> detectAdvertisedIp() throws Exception {
|
||||
final V1LoadBalancerIngress v1LoadBalancerIngress =
|
||||
v1Service.getStatus().getLoadBalancer().getIngress().stream()
|
||||
.filter(
|
||||
v1LoadBalancerIngress1 ->
|
||||
v1LoadBalancerIngress1.getHostname() != null
|
||||
|| v1LoadBalancerIngress1.getIp() != null)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NatInitializationException("Ingress not found"));
|
||||
if (v1LoadBalancerIngress.getHostname() != null) {
|
||||
return Optional.ofNullable(
|
||||
InetAddress.getByName(v1LoadBalancerIngress.getHostname()).getHostAddress());
|
||||
} else {
|
||||
return Optional.ofNullable(v1LoadBalancerIngress.getIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.hyperledger.besu.nat;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -41,24 +42,24 @@ public class NatServiceTest {
|
||||
|
||||
@Test
|
||||
public void assertThatGetNatManagerReturnValidManager() {
|
||||
final NatService natService = new NatService(Optional.of(new UpnpNatManager()));
|
||||
final NatService natService = new NatService(Optional.of(new UpnpNatManager()), true);
|
||||
assertThat(natService.getNatMethod()).isEqualTo(NatMethod.UPNP);
|
||||
assertThat(natService.getNatManager()).containsInstanceOf(UpnpNatManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatGetNatManagerNotReturnManagerWhenNatMethodIsNone() {
|
||||
final NatService natService = new NatService(Optional.empty());
|
||||
final NatService natService = new NatService(Optional.empty(), true);
|
||||
assertThat(natService.getNatMethod()).isEqualTo(NatMethod.NONE);
|
||||
assertThat(natService.getNatManager()).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatIsNatEnvironmentReturnCorrectStatus() {
|
||||
final NatService nonNatService = new NatService(Optional.empty());
|
||||
final NatService nonNatService = new NatService(Optional.empty(), true);
|
||||
assertThat(nonNatService.isNatEnvironment()).isFalse();
|
||||
|
||||
final NatService upnpNatService = new NatService(Optional.of(new UpnpNatManager()));
|
||||
final NatService upnpNatService = new NatService(Optional.of(new UpnpNatManager()), true);
|
||||
assertThat(upnpNatService.isNatEnvironment()).isTrue();
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ public class NatServiceTest {
|
||||
.thenReturn(natPortMapping);
|
||||
when(natManager.getNatMethod()).thenReturn(NatMethod.UPNP);
|
||||
|
||||
final NatService natService = new NatService(Optional.of(natManager));
|
||||
final NatService natService = new NatService(Optional.of(natManager), true);
|
||||
|
||||
final Optional<NatPortMapping> portMapping =
|
||||
natService.getPortMapping(natPortMapping.getNatServiceType(), natPortMapping.getProtocol());
|
||||
@@ -88,7 +89,7 @@ public class NatServiceTest {
|
||||
@Test
|
||||
public void assertThatGetPortMappingWorksProperlyWithoutNat() {
|
||||
|
||||
final NatService natService = new NatService(Optional.empty());
|
||||
final NatService natService = new NatService(Optional.empty(), true);
|
||||
|
||||
final Optional<NatPortMapping> portMapping =
|
||||
natService.getPortMapping(NatServiceType.DISCOVERY, NetworkProtocol.TCP);
|
||||
@@ -105,7 +106,7 @@ public class NatServiceTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(externalIp));
|
||||
when(natManager.getNatMethod()).thenReturn(NatMethod.UPNP);
|
||||
|
||||
final NatService natService = new NatService(Optional.of(natManager));
|
||||
final NatService natService = new NatService(Optional.of(natManager), true);
|
||||
|
||||
final String resultIp = natService.queryExternalIPAddress(fallbackExternalIp);
|
||||
|
||||
@@ -119,7 +120,7 @@ public class NatServiceTest {
|
||||
|
||||
final String fallbackExternalIp = "127.0.0.1";
|
||||
|
||||
final NatService natService = new NatService(Optional.empty());
|
||||
final NatService natService = new NatService(Optional.empty(), true);
|
||||
|
||||
final String resultIp = natService.queryExternalIPAddress(fallbackExternalIp);
|
||||
|
||||
@@ -135,7 +136,7 @@ public class NatServiceTest {
|
||||
.thenReturn(CompletableFuture.completedFuture(externalIp));
|
||||
when(natManager.getNatMethod()).thenReturn(NatMethod.UPNP);
|
||||
|
||||
final NatService natService = new NatService(Optional.of(natManager));
|
||||
final NatService natService = new NatService(Optional.of(natManager), true);
|
||||
|
||||
final String resultIp = natService.queryLocalIPAddress(fallbackExternalIp);
|
||||
|
||||
@@ -149,7 +150,7 @@ public class NatServiceTest {
|
||||
|
||||
final String fallbackValue = "1.2.3.4";
|
||||
|
||||
final NatService natService = new NatService(Optional.empty());
|
||||
final NatService natService = new NatService(Optional.empty(), true);
|
||||
|
||||
final String resultIp = natService.queryLocalIPAddress(fallbackValue);
|
||||
|
||||
@@ -176,7 +177,7 @@ public class NatServiceTest {
|
||||
NatServiceType.DISCOVERY, NetworkProtocol.UDP, localIp, externalIp, 1111, 1111));
|
||||
when(natManager.getNatMethod()).thenReturn(NatMethod.UPNP);
|
||||
|
||||
final NatService natService = new NatService(Optional.of(natManager));
|
||||
final NatService natService = new NatService(Optional.of(natManager), true);
|
||||
|
||||
assertThat(natService.getNatMethod()).isEqualTo(NatMethod.UPNP);
|
||||
assertThat(natService.isNatEnvironment()).isTrue();
|
||||
@@ -197,6 +198,24 @@ public class NatServiceTest {
|
||||
assertThat(natService.queryLocalIPAddress(fallbackLocalIp)).isEqualTo(fallbackLocalIp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatManagerSwitchToNoneForInvalidNatEnvironmentIfFallbackDisabled()
|
||||
throws NatInitializationException {
|
||||
|
||||
final NatManager natManager = mock(NatManager.class);
|
||||
doThrow(NatInitializationException.class).when(natManager).start();
|
||||
|
||||
when(natManager.getNatMethod()).thenReturn(NatMethod.UPNP);
|
||||
|
||||
final NatService natService = new NatService(Optional.of(natManager), false);
|
||||
|
||||
assertThat(natService.getNatMethod()).isEqualTo(NatMethod.UPNP);
|
||||
assertThat(natService.isNatEnvironment()).isTrue();
|
||||
assertThat(natService.getNatManager()).contains(natManager);
|
||||
|
||||
assertThatThrownBy(natService::start);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneAutoDetectionWorksWhenAutoDetectThenReturnCorrectNatMethod() {
|
||||
final NatMethod natMethod = NatService.autoDetectNatMethod(() -> Optional.of(NatMethod.UPNP));
|
||||
|
||||
@@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.nat.core.NatManager;
|
||||
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
|
||||
import org.hyperledger.besu.nat.core.domain.NatServiceType;
|
||||
import org.hyperledger.besu.nat.core.domain.NetworkProtocol;
|
||||
@@ -28,6 +29,7 @@ import java.net.UnknownHostException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
@@ -47,7 +49,7 @@ public final class DockerNatManagerTest {
|
||||
@Before
|
||||
public void initialize() throws NatInitializationException {
|
||||
hostBasedIpDetector = mock(HostBasedIpDetector.class);
|
||||
when(hostBasedIpDetector.detectExternalIp()).thenReturn(Optional.of(detectedAdvertisedHost));
|
||||
when(hostBasedIpDetector.detectAdvertisedIp()).thenReturn(Optional.of(detectedAdvertisedHost));
|
||||
natManager = new DockerNatManager(hostBasedIpDetector, advertisedHost, p2pPort, rpcHttpPort);
|
||||
natManager.start();
|
||||
}
|
||||
@@ -61,7 +63,14 @@ public final class DockerNatManagerTest {
|
||||
@Test
|
||||
public void assertThatExternalIPIsEqualToDefaultHostIfIpDetectorCannotRetrieveIP()
|
||||
throws ExecutionException, InterruptedException {
|
||||
when(hostBasedIpDetector.detectExternalIp()).thenReturn(Optional.empty());
|
||||
final NatManager natManager =
|
||||
new DockerNatManager(hostBasedIpDetector, advertisedHost, p2pPort, rpcHttpPort);
|
||||
when(hostBasedIpDetector.detectAdvertisedIp()).thenReturn(Optional.empty());
|
||||
try {
|
||||
natManager.start();
|
||||
} catch (NatInitializationException e) {
|
||||
Assertions.fail(e.getMessage());
|
||||
}
|
||||
assertThat(natManager.queryExternalIPAddress().get()).isEqualTo(advertisedHost);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.nat.kubernetes;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
|
||||
import org.hyperledger.besu.nat.core.domain.NatServiceType;
|
||||
import org.hyperledger.besu.nat.core.domain.NetworkProtocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import io.kubernetes.client.custom.IntOrString;
|
||||
import io.kubernetes.client.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.models.V1Service;
|
||||
import io.kubernetes.client.models.V1ServicePort;
|
||||
import io.kubernetes.client.models.V1ServiceSpec;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class KubernetesClusterIpNatManagerTest {
|
||||
|
||||
private final String detectedAdvertisedHost = "199.45.69.12";
|
||||
|
||||
private final int p2pPort = 1;
|
||||
private final int rpcHttpPort = 2;
|
||||
|
||||
@Mock private V1Service v1Service;
|
||||
|
||||
private KubernetesNatManager natManager;
|
||||
|
||||
@Before
|
||||
public void initialize() throws IOException {
|
||||
|
||||
when(v1Service.getSpec())
|
||||
.thenReturn(
|
||||
new V1ServiceSpec()
|
||||
.type("ClusterIP")
|
||||
.clusterIP(detectedAdvertisedHost)
|
||||
.ports(
|
||||
Arrays.asList(
|
||||
new V1ServicePort()
|
||||
.name(NatServiceType.JSON_RPC.getValue())
|
||||
.port(rpcHttpPort)
|
||||
.targetPort(new IntOrString(rpcHttpPort)),
|
||||
new V1ServicePort()
|
||||
.name(NatServiceType.RLPX.getValue())
|
||||
.port(p2pPort)
|
||||
.targetPort(new IntOrString(p2pPort)),
|
||||
new V1ServicePort()
|
||||
.name(NatServiceType.DISCOVERY.getValue())
|
||||
.port(p2pPort)
|
||||
.targetPort(new IntOrString(p2pPort)))));
|
||||
when(v1Service.getMetadata())
|
||||
.thenReturn(new V1ObjectMeta().name(DEFAULT_BESU_SERVICE_NAME_FILTER));
|
||||
natManager = new KubernetesNatManager(DEFAULT_BESU_SERVICE_NAME_FILTER);
|
||||
try {
|
||||
natManager.start();
|
||||
} catch (Exception ignored) {
|
||||
System.err.println("Ignored missing Kube config file in testing context.");
|
||||
}
|
||||
natManager.updateUsingBesuService(v1Service);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatExternalIPIsEqualToRemoteHost()
|
||||
throws ExecutionException, InterruptedException {
|
||||
|
||||
assertThat(natManager.queryExternalIPAddress().get()).isEqualTo(detectedAdvertisedHost);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatLocalIPIsEqualToLocalHost()
|
||||
throws ExecutionException, InterruptedException, UnknownHostException {
|
||||
final String internalHost = InetAddress.getLocalHost().getHostAddress();
|
||||
assertThat(natManager.queryLocalIPAddress().get()).isEqualTo(internalHost);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatMappingForDiscoveryWorks() throws UnknownHostException {
|
||||
final String internalHost = InetAddress.getLocalHost().getHostAddress();
|
||||
|
||||
final NatPortMapping mapping =
|
||||
natManager.getPortMapping(NatServiceType.DISCOVERY, NetworkProtocol.UDP);
|
||||
|
||||
final NatPortMapping expectedMapping =
|
||||
new NatPortMapping(
|
||||
NatServiceType.DISCOVERY,
|
||||
NetworkProtocol.UDP,
|
||||
internalHost,
|
||||
detectedAdvertisedHost,
|
||||
p2pPort,
|
||||
p2pPort);
|
||||
|
||||
assertThat(mapping).isEqualToComparingFieldByField(expectedMapping);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatMappingForJsonRpcWorks() throws UnknownHostException {
|
||||
final String internalHost = InetAddress.getLocalHost().getHostAddress();
|
||||
|
||||
final NatPortMapping mapping =
|
||||
natManager.getPortMapping(NatServiceType.JSON_RPC, NetworkProtocol.TCP);
|
||||
|
||||
final NatPortMapping expectedMapping =
|
||||
new NatPortMapping(
|
||||
NatServiceType.JSON_RPC,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
detectedAdvertisedHost,
|
||||
rpcHttpPort,
|
||||
rpcHttpPort);
|
||||
|
||||
assertThat(mapping).isEqualToComparingFieldByField(expectedMapping);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatMappingForRlpxWorks() throws UnknownHostException {
|
||||
final String internalHost = InetAddress.getLocalHost().getHostAddress();
|
||||
|
||||
final NatPortMapping mapping =
|
||||
natManager.getPortMapping(NatServiceType.RLPX, NetworkProtocol.TCP);
|
||||
|
||||
final NatPortMapping expectedMapping =
|
||||
new NatPortMapping(
|
||||
NatServiceType.RLPX,
|
||||
NetworkProtocol.TCP,
|
||||
internalHost,
|
||||
detectedAdvertisedHost,
|
||||
p2pPort,
|
||||
p2pPort);
|
||||
|
||||
assertThat(mapping).isEqualToComparingFieldByField(expectedMapping);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
package org.hyperledger.besu.nat.kubernetes;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_POD_NAME_FILTER;
|
||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.nat.core.domain.NatPortMapping;
|
||||
@@ -43,7 +43,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class KubernetesNatManagerTest {
|
||||
public final class KubernetesLoadManagerNatManagerTest {
|
||||
|
||||
private final String detectedAdvertisedHost = "199.45.69.12";
|
||||
|
||||
@@ -67,6 +67,7 @@ public final class KubernetesNatManagerTest {
|
||||
when(v1Service.getSpec())
|
||||
.thenReturn(
|
||||
new V1ServiceSpec()
|
||||
.type("LoadBalancer")
|
||||
.ports(
|
||||
Arrays.asList(
|
||||
new V1ServicePort()
|
||||
@@ -81,8 +82,9 @@ public final class KubernetesNatManagerTest {
|
||||
.name(NatServiceType.DISCOVERY.getValue())
|
||||
.port(p2pPort)
|
||||
.targetPort(new IntOrString(p2pPort)))));
|
||||
when(v1Service.getMetadata()).thenReturn(new V1ObjectMeta().name(DEFAULT_BESU_POD_NAME_FILTER));
|
||||
natManager = new KubernetesNatManager(DEFAULT_BESU_POD_NAME_FILTER);
|
||||
when(v1Service.getMetadata())
|
||||
.thenReturn(new V1ObjectMeta().name(DEFAULT_BESU_SERVICE_NAME_FILTER));
|
||||
natManager = new KubernetesNatManager(DEFAULT_BESU_SERVICE_NAME_FILTER);
|
||||
try {
|
||||
natManager.start();
|
||||
} catch (Exception ignored) {
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright ConsenSys AG.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.nat.kubernetes;
|
||||
|
||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.kubernetes.client.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.models.V1Service;
|
||||
import io.kubernetes.client.models.V1ServiceSpec;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public final class KubernetesUnknownNatManagerTest {
|
||||
|
||||
@Mock private V1Service v1Service;
|
||||
|
||||
private KubernetesNatManager natManager;
|
||||
|
||||
@Before
|
||||
public void initialize() {
|
||||
|
||||
when(v1Service.getSpec()).thenReturn(new V1ServiceSpec().type("Unknown"));
|
||||
when(v1Service.getMetadata())
|
||||
.thenReturn(new V1ObjectMeta().name(DEFAULT_BESU_SERVICE_NAME_FILTER));
|
||||
natManager = new KubernetesNatManager(DEFAULT_BESU_SERVICE_NAME_FILTER);
|
||||
try {
|
||||
natManager.start();
|
||||
} catch (Exception ignored) {
|
||||
System.err.println("Ignored missing Kube config file in testing context.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void assertThatNatExceptionIsThrownWithUnknownServiceType() {
|
||||
natManager.updateUsingBesuService(v1Service);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user