mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-07 21:13:56 -05:00
remove k8s NAT method (#8289)
* remove k8s NAT method Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * changelog - update pr number in changelog Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> --------- Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
- k8s (KUBERNETES) Nat method is removed. Use docker or none instead. [#8289](https://github.com/hyperledger/besu/pull/8289)
|
||||||
|
|
||||||
### Upcoming Breaking Changes
|
### Upcoming Breaking Changes
|
||||||
- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge`
|
- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge`
|
||||||
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release. Use docker or none instead.
|
|
||||||
- `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated, use `--Xbonsai-full-flat-db-enabled` instead.
|
- `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated, use `--Xbonsai-full-flat-db-enabled` instead.
|
||||||
- `--Xbonsai-limit-trie-logs-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
- `--Xbonsai-limit-trie-logs-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
||||||
- `--Xbonsai-trie-log-pruning-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
- `--Xbonsai-trie-log-pruning-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
||||||
|
|||||||
@@ -118,8 +118,6 @@ import org.hyperledger.besu.nat.NatService;
|
|||||||
import org.hyperledger.besu.nat.core.NatManager;
|
import org.hyperledger.besu.nat.core.NatManager;
|
||||||
import org.hyperledger.besu.nat.docker.DockerDetector;
|
import org.hyperledger.besu.nat.docker.DockerDetector;
|
||||||
import org.hyperledger.besu.nat.docker.DockerNatManager;
|
import org.hyperledger.besu.nat.docker.DockerNatManager;
|
||||||
import org.hyperledger.besu.nat.kubernetes.KubernetesDetector;
|
|
||||||
import org.hyperledger.besu.nat.kubernetes.KubernetesNatManager;
|
|
||||||
import org.hyperledger.besu.nat.upnp.UpnpNatManager;
|
import org.hyperledger.besu.nat.upnp.UpnpNatManager;
|
||||||
import org.hyperledger.besu.plugin.BesuPlugin;
|
import org.hyperledger.besu.plugin.BesuPlugin;
|
||||||
import org.hyperledger.besu.plugin.data.EnodeURL;
|
import org.hyperledger.besu.plugin.data.EnodeURL;
|
||||||
@@ -170,7 +168,6 @@ public class RunnerBuilder {
|
|||||||
private String p2pListenInterface = NetworkUtility.INADDR_ANY;
|
private String p2pListenInterface = NetworkUtility.INADDR_ANY;
|
||||||
private int p2pListenPort;
|
private int p2pListenPort;
|
||||||
private NatMethod natMethod = NatMethod.AUTO;
|
private NatMethod natMethod = NatMethod.AUTO;
|
||||||
private String natManagerServiceName;
|
|
||||||
private boolean natMethodFallbackEnabled;
|
private boolean natMethodFallbackEnabled;
|
||||||
private EthNetworkConfig ethNetworkConfig;
|
private EthNetworkConfig ethNetworkConfig;
|
||||||
private EthstatsOptions ethstatsOptions;
|
private EthstatsOptions ethstatsOptions;
|
||||||
@@ -313,17 +310,6 @@ public class RunnerBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add Nat manager service name.
|
|
||||||
*
|
|
||||||
* @param natManagerServiceName the nat manager service name
|
|
||||||
* @return the runner builder
|
|
||||||
*/
|
|
||||||
public RunnerBuilder natManagerServiceName(final String natManagerServiceName) {
|
|
||||||
this.natManagerServiceName = natManagerServiceName;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable Nat method fallback.
|
* Enable Nat method fallback.
|
||||||
*
|
*
|
||||||
@@ -1213,15 +1199,13 @@ public class RunnerBuilder {
|
|||||||
final NatMethod detectedNatMethod =
|
final NatMethod detectedNatMethod =
|
||||||
Optional.of(natMethod)
|
Optional.of(natMethod)
|
||||||
.filter(not(isEqual(NatMethod.AUTO)))
|
.filter(not(isEqual(NatMethod.AUTO)))
|
||||||
.orElse(NatService.autoDetectNatMethod(new KubernetesDetector(), new DockerDetector()));
|
.orElse(NatService.autoDetectNatMethod(new DockerDetector()));
|
||||||
switch (detectedNatMethod) {
|
switch (detectedNatMethod) {
|
||||||
case UPNP:
|
case UPNP:
|
||||||
return Optional.of(new UpnpNatManager());
|
return Optional.of(new UpnpNatManager());
|
||||||
case DOCKER:
|
case DOCKER:
|
||||||
return Optional.of(
|
return Optional.of(
|
||||||
new DockerNatManager(p2pAdvertisedHost, p2pListenPort, jsonRpcConfiguration.getPort()));
|
new DockerNatManager(p2pAdvertisedHost, p2pListenPort, jsonRpcConfiguration.getPort()));
|
||||||
case KUBERNETES:
|
|
||||||
return Optional.of(new KubernetesNatManager(natManagerServiceName));
|
|
||||||
case NONE:
|
case NONE:
|
||||||
default:
|
default:
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_
|
|||||||
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
|
import static org.hyperledger.besu.cli.util.CommandLineUtils.isOptionSet;
|
||||||
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
|
import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
|
||||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE;
|
import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE;
|
||||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
|
||||||
|
|
||||||
import org.hyperledger.besu.BesuInfo;
|
import org.hyperledger.besu.BesuInfo;
|
||||||
import org.hyperledger.besu.Runner;
|
import org.hyperledger.besu.Runner;
|
||||||
@@ -1509,22 +1508,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
|||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private void validateNatParams() {
|
private void validateNatParams() {
|
||||||
if (natMethod.equals(NatMethod.KUBERNETES)) {
|
|
||||||
logger.warn("Kubernetes NAT method is deprecated. Please use Docker or UPNP");
|
|
||||||
}
|
|
||||||
if (!unstableNatOptions.getNatManagerServiceName().equals(DEFAULT_BESU_SERVICE_NAME_FILTER)) {
|
|
||||||
logger.warn(
|
|
||||||
"`--Xnat-kube-service-name` and Kubernetes NAT method are deprecated. Please use Docker or UPNP");
|
|
||||||
}
|
|
||||||
if (!(natMethod.equals(NatMethod.AUTO) || natMethod.equals(NatMethod.KUBERNETES))
|
|
||||||
&& !unstableNatOptions
|
|
||||||
.getNatManagerServiceName()
|
|
||||||
.equals(DEFAULT_BESU_SERVICE_NAME_FILTER)) {
|
|
||||||
throw new ParameterException(
|
|
||||||
this.commandLine,
|
|
||||||
"The `--Xnat-kube-service-name` parameter is only used in kubernetes mode. Either remove --Xnat-kube-service-name"
|
|
||||||
+ " or select the KUBERNETES mode (via --nat--method=KUBERNETES)");
|
|
||||||
}
|
|
||||||
if (natMethod.equals(NatMethod.AUTO) && !unstableNatOptions.getNatMethodFallbackEnabled()) {
|
if (natMethod.equals(NatMethod.AUTO) && !unstableNatOptions.getNatMethodFallbackEnabled()) {
|
||||||
throw new ParameterException(
|
throw new ParameterException(
|
||||||
this.commandLine,
|
this.commandLine,
|
||||||
@@ -2264,7 +2247,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
|||||||
.besuController(controller)
|
.besuController(controller)
|
||||||
.p2pEnabled(p2pEnabled)
|
.p2pEnabled(p2pEnabled)
|
||||||
.natMethod(natMethod)
|
.natMethod(natMethod)
|
||||||
.natManagerServiceName(unstableNatOptions.getNatManagerServiceName())
|
|
||||||
.natMethodFallbackEnabled(unstableNatOptions.getNatMethodFallbackEnabled())
|
.natMethodFallbackEnabled(unstableNatOptions.getNatMethodFallbackEnabled())
|
||||||
.discoveryEnabled(peerDiscoveryEnabled)
|
.discoveryEnabled(peerDiscoveryEnabled)
|
||||||
.ethNetworkConfig(ethNetworkConfig)
|
.ethNetworkConfig(ethNetworkConfig)
|
||||||
|
|||||||
@@ -14,21 +14,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.hyperledger.besu.cli.options;
|
package org.hyperledger.besu.cli.options;
|
||||||
|
|
||||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
|
||||||
|
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
|
||||||
/** The Nat Cli options. */
|
/** The Nat Cli options. */
|
||||||
public class NatOptions {
|
public class NatOptions {
|
||||||
|
|
||||||
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
|
|
||||||
@CommandLine.Option(
|
|
||||||
hidden = true,
|
|
||||||
names = {"--Xnat-kube-service-name"},
|
|
||||||
description =
|
|
||||||
"Specify the name of the service that will be used by the nat manager in Kubernetes. (default: ${DEFAULT-VALUE})")
|
|
||||||
private String natManagerServiceName = DEFAULT_BESU_SERVICE_NAME_FILTER;
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
hidden = true,
|
hidden = true,
|
||||||
names = {"--Xnat-method-fallback-enabled"},
|
names = {"--Xnat-method-fallback-enabled"},
|
||||||
@@ -49,15 +39,6 @@ public class NatOptions {
|
|||||||
return new NatOptions();
|
return new NatOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets nat manager service name.
|
|
||||||
*
|
|
||||||
* @return the nat manager service name
|
|
||||||
*/
|
|
||||||
public String getNatManagerServiceName() {
|
|
||||||
return natManagerServiceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether nat method fallback is enabled.
|
* Whether nat method fallback is enabled.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -327,7 +327,6 @@ public abstract class CommandTestAbstract {
|
|||||||
when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder);
|
||||||
when(mockRunnerBuilder.p2pEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.p2pEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
|
||||||
when(mockRunnerBuilder.natMethod(any())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.natMethod(any())).thenReturn(mockRunnerBuilder);
|
||||||
when(mockRunnerBuilder.natManagerServiceName(any())).thenReturn(mockRunnerBuilder);
|
|
||||||
when(mockRunnerBuilder.natMethodFallbackEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.natMethodFallbackEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
|
||||||
when(mockRunnerBuilder.jsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.jsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
|
||||||
when(mockRunnerBuilder.engineJsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
|
when(mockRunnerBuilder.engineJsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ package org.hyperledger.besu.cli;
|
|||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
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.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@@ -47,16 +46,6 @@ public class NatOptionsTest extends CommandTestAbstract {
|
|||||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void natManagerPodNamePropertyDefaultIsBesu() {
|
|
||||||
parseCommand();
|
|
||||||
|
|
||||||
verify(mockRunnerBuilder).natManagerServiceName(eq(DEFAULT_BESU_SERVICE_NAME_FILTER));
|
|
||||||
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
|
||||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void natMethodOptionIsParsedCorrectly() {
|
public void natMethodOptionIsParsedCorrectly() {
|
||||||
|
|
||||||
@@ -75,52 +64,6 @@ public class NatOptionsTest extends CommandTestAbstract {
|
|||||||
parseCommand("--nat-method", "DOCKER");
|
parseCommand("--nat-method", "DOCKER");
|
||||||
verify(mockRunnerBuilder).natMethod(eq(NatMethod.DOCKER));
|
verify(mockRunnerBuilder).natMethod(eq(NatMethod.DOCKER));
|
||||||
|
|
||||||
parseCommand("--nat-method", "KUBERNETES");
|
|
||||||
verify(mockRunnerBuilder).natMethod(eq(NatMethod.KUBERNETES));
|
|
||||||
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
|
||||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void natManagerPodNamePropertyIsCorrectlyUpdated() {
|
|
||||||
final String podName = "besu-updated";
|
|
||||||
parseCommand("--Xnat-kube-service-name", podName);
|
|
||||||
|
|
||||||
verify(mockRunnerBuilder).natManagerServiceName(eq(podName));
|
|
||||||
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
|
||||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void natManagerPodNameCannotBeUsedWithNatDockerMethod() {
|
|
||||||
parseCommand("--nat-method", "DOCKER", "--Xnat-kube-service-name", "besu-updated");
|
|
||||||
Mockito.verifyNoInteractions(mockRunnerBuilder);
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
|
||||||
assertThat(commandErrorOutput.toString(UTF_8))
|
|
||||||
.contains(
|
|
||||||
"The `--Xnat-kube-service-name` parameter is only used in kubernetes mode. Either remove --Xnat-kube-service-name or select the KUBERNETES mode (via --nat--method=KUBERNETES)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void natManagerPodNameCannotBeUsedWithNatNoneMethod() {
|
|
||||||
parseCommand("--nat-method", "NONE", "--Xnat-kube-service-name", "besu-updated");
|
|
||||||
Mockito.verifyNoInteractions(mockRunnerBuilder);
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
|
||||||
assertThat(commandErrorOutput.toString(UTF_8))
|
|
||||||
.contains(
|
|
||||||
"The `--Xnat-kube-service-name` parameter is only used in kubernetes mode. Either remove --Xnat-kube-service-name or select the KUBERNETES mode (via --nat--method=KUBERNETES)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void natMethodFallbackEnabledPropertyIsCorrectlyUpdatedWithKubernetes() {
|
|
||||||
|
|
||||||
parseCommand("--nat-method", "KUBERNETES", "--Xnat-method-fallback-enabled", "false");
|
|
||||||
verify(mockRunnerBuilder).natMethodFallbackEnabled(eq(false));
|
|
||||||
parseCommand("--nat-method", "KUBERNETES", "--Xnat-method-fallback-enabled", "true");
|
|
||||||
verify(mockRunnerBuilder).natMethodFallbackEnabled(eq(true));
|
|
||||||
|
|
||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||||
}
|
}
|
||||||
@@ -167,6 +110,6 @@ public class NatOptionsTest extends CommandTestAbstract {
|
|||||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||||
assertThat(commandErrorOutput.toString(UTF_8))
|
assertThat(commandErrorOutput.toString(UTF_8))
|
||||||
.contains(
|
.contains(
|
||||||
"Invalid value for option '--nat-method': expected one of [UPNP, UPNPP2PONLY, DOCKER, KUBERNETES, AUTO, NONE] (case-insensitive) but was 'invalid'");
|
"Invalid value for option '--nat-method': expected one of [UPNP, UPNPP2PONLY, DOCKER, AUTO, NONE] (case-insensitive) but was 'invalid'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ security-module="localfile"
|
|||||||
identity="PegaSysEng"
|
identity="PegaSysEng"
|
||||||
p2p-enabled=true
|
p2p-enabled=true
|
||||||
nat-method="NONE"
|
nat-method="NONE"
|
||||||
Xnat-kube-service-name="besu"
|
|
||||||
Xnat-method-fallback-enabled=true
|
Xnat-method-fallback-enabled=true
|
||||||
discovery-enabled=false
|
discovery-enabled=false
|
||||||
poa-discovery-retry-bootnodes=true
|
poa-discovery-retry-bootnodes=true
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ dependencies {
|
|||||||
implementation 'com.squareup.okhttp3:okhttp'
|
implementation 'com.squareup.okhttp3:okhttp'
|
||||||
implementation 'org.jupnp:org.jupnp'
|
implementation 'org.jupnp:org.jupnp'
|
||||||
implementation 'org.jupnp:org.jupnp.support'
|
implementation 'org.jupnp:org.jupnp.support'
|
||||||
implementation 'io.kubernetes:client-java'
|
|
||||||
|
|
||||||
// test dependencies.
|
// test dependencies.
|
||||||
testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts')
|
testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts')
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ public enum NatMethod {
|
|||||||
UPNPP2PONLY,
|
UPNPP2PONLY,
|
||||||
/** Docker nat method. */
|
/** Docker nat method. */
|
||||||
DOCKER,
|
DOCKER,
|
||||||
/** Kubernetes nat method. */
|
|
||||||
KUBERNETES,
|
|
||||||
/** Auto nat method. */
|
/** Auto nat method. */
|
||||||
AUTO,
|
AUTO,
|
||||||
/** None nat method. */
|
/** None nat method. */
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 org.hyperledger.besu.nat.NatMethod;
|
|
||||||
import org.hyperledger.besu.nat.core.NatMethodDetector;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/** The Kubernetes detector. */
|
|
||||||
public class KubernetesDetector implements NatMethodDetector {
|
|
||||||
|
|
||||||
// When a Pod runs on a Node, the kubelet adds a set of environment variables for each active
|
|
||||||
// Service.
|
|
||||||
// https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/#environment-variables
|
|
||||||
private static final Optional<String> KUBERNETES_SERVICE_HOST =
|
|
||||||
Optional.ofNullable(System.getenv("KUBERNETES_SERVICE_HOST"));
|
|
||||||
private static final Path KUBERNETES_WATERMARK_FILE = Paths.get("var/run/secrets/kubernetes.io");
|
|
||||||
|
|
||||||
/** Default constructor */
|
|
||||||
public KubernetesDetector() {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<NatMethod> detect() {
|
|
||||||
return KUBERNETES_SERVICE_HOST
|
|
||||||
.map(__ -> NatMethod.KUBERNETES)
|
|
||||||
.or(
|
|
||||||
() ->
|
|
||||||
Files.exists(KUBERNETES_WATERMARK_FILE)
|
|
||||||
? Optional.of(NatMethod.KUBERNETES)
|
|
||||||
: Optional.empty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 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.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import io.kubernetes.client.openapi.ApiClient;
|
|
||||||
import io.kubernetes.client.openapi.Configuration;
|
|
||||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
|
||||||
import io.kubernetes.client.openapi.models.V1Service;
|
|
||||||
import io.kubernetes.client.util.ClientBuilder;
|
|
||||||
import io.kubernetes.client.util.KubeConfig;
|
|
||||||
import io.kubernetes.client.util.authenticators.GCPAuthenticator;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class describes the behavior of the Kubernetes NAT manager. Kubernetes Nat manager add
|
|
||||||
* support for Kubernetes’s NAT implementation when Besu is being run from a Kubernetes cluster
|
|
||||||
*/
|
|
||||||
public class KubernetesNatManager extends AbstractNatManager {
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(KubernetesNatManager.class);
|
|
||||||
|
|
||||||
/** The constant DEFAULT_BESU_SERVICE_NAME_FILTER. */
|
|
||||||
public static final String DEFAULT_BESU_SERVICE_NAME_FILTER = "besu";
|
|
||||||
|
|
||||||
private String internalAdvertisedHost;
|
|
||||||
private final String besuServiceNameFilter;
|
|
||||||
private final List<NatPortMapping> forwardedPorts = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new Kubernetes nat manager.
|
|
||||||
*
|
|
||||||
* @param besuServiceNameFilter the besu service name filter
|
|
||||||
*/
|
|
||||||
public KubernetesNatManager(final String besuServiceNameFilter) {
|
|
||||||
super(NatMethod.KUBERNETES);
|
|
||||||
this.besuServiceNameFilter = besuServiceNameFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStart() throws NatInitializationException {
|
|
||||||
LOG.info("Starting kubernetes NAT manager.");
|
|
||||||
try {
|
|
||||||
|
|
||||||
KubeConfig.registerAuthenticator(new GCPAuthenticator());
|
|
||||||
|
|
||||||
LOG.debug("Trying to update information using Kubernetes client SDK.");
|
|
||||||
final ApiClient client = ClientBuilder.cluster().build();
|
|
||||||
|
|
||||||
// set the global default api-client to the in-cluster one from above
|
|
||||||
Configuration.setDefaultApiClient(client);
|
|
||||||
|
|
||||||
// the CoreV1Api loads default api-client from global configuration.
|
|
||||||
final CoreV1Api api = new CoreV1Api();
|
|
||||||
// invokes the CoreV1Api client
|
|
||||||
final V1Service service =
|
|
||||||
api
|
|
||||||
.listServiceForAllNamespaces(
|
|
||||||
null, null, null, null, null, null, null, null, null, null, null)
|
|
||||||
.getItems()
|
|
||||||
.stream()
|
|
||||||
.filter(
|
|
||||||
v1Service -> v1Service.getMetadata().getName().contains(besuServiceNameFilter))
|
|
||||||
.findFirst()
|
|
||||||
.orElseThrow(() -> new NatInitializationException("Service not found"));
|
|
||||||
updateUsingBesuService(service);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new NatInitializationException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update using besu service. Visible for testing.
|
|
||||||
*
|
|
||||||
* @param service the service
|
|
||||||
* @throws RuntimeException the runtime exception
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
void updateUsingBesuService(final V1Service service) throws RuntimeException {
|
|
||||||
try {
|
|
||||||
LOG.info("Found Besu service: {}", service.getMetadata().getName());
|
|
||||||
|
|
||||||
internalAdvertisedHost =
|
|
||||||
getIpDetector(service)
|
|
||||||
.detectAdvertisedIp()
|
|
||||||
.orElseThrow(
|
|
||||||
() -> new NatInitializationException("Unable to retrieve IP from service"));
|
|
||||||
|
|
||||||
LOG.info("Setting host IP to: {}.", internalAdvertisedHost);
|
|
||||||
|
|
||||||
final String internalHost = queryLocalIPAddress().get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
|
||||||
service
|
|
||||||
.getSpec()
|
|
||||||
.getPorts()
|
|
||||||
.forEach(
|
|
||||||
v1ServicePort -> {
|
|
||||||
try {
|
|
||||||
final NatServiceType natServiceType =
|
|
||||||
NatServiceType.fromString(v1ServicePort.getName());
|
|
||||||
forwardedPorts.add(
|
|
||||||
new NatPortMapping(
|
|
||||||
natServiceType,
|
|
||||||
natServiceType.equals(NatServiceType.DISCOVERY)
|
|
||||||
? NetworkProtocol.UDP
|
|
||||||
: NetworkProtocol.TCP,
|
|
||||||
internalHost,
|
|
||||||
internalAdvertisedHost,
|
|
||||||
v1ServicePort.getPort(),
|
|
||||||
v1ServicePort.getTargetPort().getIntValue()));
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
LOG.warn("Ignored unknown Besu port: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(
|
|
||||||
"Failed update information using pod metadata : " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStop() {
|
|
||||||
LOG.info("Stopping kubernetes NAT manager.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected CompletableFuture<String> retrieveExternalIPAddress() {
|
|
||||||
return CompletableFuture.completedFuture(internalAdvertisedHost);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/** The enum Kubernetes service type. */
|
|
||||||
public enum KubernetesServiceType {
|
|
||||||
/** Cluster ip kubernetes service type. */
|
|
||||||
CLUSTER_IP("ClusterIP"),
|
|
||||||
/** Load balancer kubernetes service type. */
|
|
||||||
LOAD_BALANCER("LoadBalancer"),
|
|
||||||
/** Unknown kubernetes service type. */
|
|
||||||
UNKNOWN("");
|
|
||||||
|
|
||||||
/** The Name. */
|
|
||||||
String name;
|
|
||||||
|
|
||||||
KubernetesServiceType(final String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map KubernetesServiceType from String value.
|
|
||||||
*
|
|
||||||
* @param name the name
|
|
||||||
* @return the kubernetes service type
|
|
||||||
*/
|
|
||||||
public static KubernetesServiceType fromName(final String name) {
|
|
||||||
for (KubernetesServiceType value : values()) {
|
|
||||||
if (value.name.equals(name)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.openapi.models.V1LoadBalancerIngress;
|
|
||||||
import io.kubernetes.client.openapi.models.V1Service;
|
|
||||||
|
|
||||||
/** The Load balancer based detector. */
|
|
||||||
public class LoadBalancerBasedDetector implements IpDetector {
|
|
||||||
|
|
||||||
private final V1Service v1Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiates a new Load balancer based detector.
|
|
||||||
*
|
|
||||||
* @param v1Service the v 1 service
|
|
||||||
*/
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.openapi.models.V1ObjectMeta;
|
|
||||||
import io.kubernetes.client.openapi.models.V1Service;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServicePort;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServiceSpec;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.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;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
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).usingRecursiveComparison().isEqualTo(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).usingRecursiveComparison().isEqualTo(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).usingRecursiveComparison().isEqualTo(expectedMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.openapi.models.V1LoadBalancerIngress;
|
|
||||||
import io.kubernetes.client.openapi.models.V1LoadBalancerStatus;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
|
||||||
import io.kubernetes.client.openapi.models.V1Service;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServicePort;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServiceSpec;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServiceStatus;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public final class KubernetesLoadManagerNatManagerTest {
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void initialize() throws IOException {
|
|
||||||
final V1ServiceStatus v1ServiceStatus =
|
|
||||||
new V1ServiceStatus()
|
|
||||||
.loadBalancer(
|
|
||||||
new V1LoadBalancerStatus()
|
|
||||||
.addIngressItem(new V1LoadBalancerIngress().ip(detectedAdvertisedHost)));
|
|
||||||
when(v1Service.getStatus()).thenReturn(v1ServiceStatus);
|
|
||||||
when(v1Service.getSpec())
|
|
||||||
.thenReturn(
|
|
||||||
new V1ServiceSpec()
|
|
||||||
.type("LoadBalancer")
|
|
||||||
.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).usingRecursiveComparison().isEqualTo(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).usingRecursiveComparison().isEqualTo(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).usingRecursiveComparison().isEqualTo(expectedMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.assertThatThrownBy;
|
|
||||||
import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
|
||||||
import io.kubernetes.client.openapi.models.V1Service;
|
|
||||||
import io.kubernetes.client.openapi.models.V1ServiceSpec;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public final class KubernetesUnknownNatManagerTest {
|
|
||||||
|
|
||||||
@Mock private V1Service v1Service;
|
|
||||||
|
|
||||||
private KubernetesNatManager natManager;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
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
|
|
||||||
public void assertThatNatExceptionIsThrownWithUnknownServiceType() {
|
|
||||||
assertThatThrownBy(() -> natManager.updateUsingBesuService(v1Service))
|
|
||||||
.isInstanceOf(RuntimeException.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -96,8 +96,6 @@ dependencies {
|
|||||||
api 'info.picocli:picocli:4.7.6'
|
api 'info.picocli:picocli:4.7.6'
|
||||||
api 'info.picocli:picocli-codegen:4.7.6'
|
api 'info.picocli:picocli-codegen:4.7.6'
|
||||||
|
|
||||||
api 'io.kubernetes:client-java:21.0.1-legacy'
|
|
||||||
|
|
||||||
api 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.9.0-alpha'
|
api 'io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0:2.9.0-alpha'
|
||||||
api 'io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha'
|
api 'io.opentelemetry.proto:opentelemetry-proto:1.3.2-alpha'
|
||||||
api 'io.opentelemetry.semconv:opentelemetry-semconv:1.28.0-alpha'
|
api 'io.opentelemetry.semconv:opentelemetry-semconv:1.28.0-alpha'
|
||||||
|
|||||||
Reference in New Issue
Block a user