mirror of https://github.com/hyperledger/besu
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>pull/1187/head
parent
174e6e29ad
commit
50db46f855
@ -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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue