Skip to content

Commit 4535525

Browse files
authored
Merge pull request #335 from aojea/tunnel_ingress
Tunnel ingress for gateway should be idempotent
2 parents 506a3b2 + 184cee8 commit 4535525

File tree

6 files changed

+72
-32
lines changed

6 files changed

+72
-32
lines changed

.github/workflows/bats.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,18 @@ jobs:
5252
./_artifacts-custom-network
5353
5454
bats_mac_tests:
55-
runs-on: macos-13
55+
runs-on: macos-15-intel
5656
name: Bats e2e tests on Mac
57-
# Skip until port forwarding works
57+
# Skip until runner does not timeout on kind create cluster
5858
if: false
5959
steps:
6060
- name: Checkout
6161
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
62+
# c.f. https://github.com/actions/runner-images/issues/13358
63+
- name: Work around x86 macOS bug for multiple CPU cores
64+
run: |
65+
sudo defaults -currentHost write /Library/Preferences/com.apple.powerlogd SMCMonitorCadence 0
66+
sudo killall PerfPowerServices || true
6267
- name: Set up environment (download dependencies)
6368
run: |
6469
brew install docker colima
@@ -71,7 +76,6 @@ jobs:
7176
env:
7277
TERM: linux
7378
run: |
74-
bash --version
7579
bash -c "time bats -o _artifacts --trace --formatter tap tests/"
7680
- name: Debug info
7781
if: always()
@@ -84,5 +88,5 @@ jobs:
8488
if: always()
8589
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
8690
with:
87-
name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }}
91+
name: kind-logs-mac-${{ github.run_id }}
8892
path: ./_artifacts

pkg/gateway/envoy.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ func createGateway(clusterName string, nameserver string, localAddress string, l
193193
"--sysctl=net.ipv6.conf.all.forwarding=1",
194194
}...)
195195

196-
if enableTunnel {
196+
if enableTunnel ||
197+
config.DefaultConfig.LoadBalancerConnectivity == config.Portmap {
198+
// Forward the Listener Ports to the host so they are accessible on Mac and Windows
197199
for _, listener := range gateway.Spec.Listeners {
198200
if listener.Protocol == gatewayv1.UDPProtocolType {
199201
args = append(args, fmt.Sprintf("--publish=%d/%s", listener.Port, "udp"))
@@ -202,7 +204,6 @@ func createGateway(clusterName string, nameserver string, localAddress string, l
202204
}
203205
}
204206
}
205-
args = append(args, fmt.Sprintf("--publish=%d/tcp", envoyAdminPort))
206207
args = append(args, "--publish-all")
207208

208209
// Construct the multi-step command

pkg/tunnels/tunnel.go

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,31 +41,49 @@ func (t *TunnelManager) SetupTunnels(containerName string) error {
4141
}
4242

4343
klog.V(0).Infof("setting IPv4 address %s associated to container %s", ipv4, containerName)
44-
output, err := AddIPToLocalInterface(ipv4)
45-
if err != nil {
46-
return fmt.Errorf("error adding IP to local interface: %w - %s", err, output)
44+
// check if the IP is already assigned to the local interface
45+
if !ipOnHost(ipv4) {
46+
output, err := AddIPToLocalInterface(ipv4)
47+
if err != nil {
48+
return fmt.Errorf("error adding IP to local interface: %w - %s", err, output)
49+
}
4750
}
4851

4952
// create tunnel from the ip:svcport to the localhost:portmap
5053
t.mu.Lock()
5154
defer t.mu.Unlock()
55+
_, ok := t.tunnels[containerName]
56+
if !ok {
57+
t.tunnels[containerName] = map[string]*tunnel{}
58+
}
59+
60+
// Reconcile: Remove tunnels that are not in portmaps
61+
for containerPort, tun := range t.tunnels[containerName] {
62+
if _, ok := portmaps[containerPort]; !ok {
63+
klog.V(0).Infof("removing tunnel for %s %s as it is no longer in portmaps", containerName, containerPort)
64+
tun.Stop() // nolint: errcheck
65+
delete(t.tunnels[containerName], containerPort)
66+
}
67+
}
68+
5269
// There is one IP per Service and a tunnel per Service Port
5370
for containerPort, hostPort := range portmaps {
5471
parts := strings.Split(containerPort, "/")
5572
if len(parts) != 2 {
5673
return fmt.Errorf("expected format port/protocol for container port, got %s", containerPort)
5774
}
5875

76+
if _, ok := t.tunnels[containerName][containerPort]; ok {
77+
klog.V(2).Infof("tunnel for %s %s already exists", containerName, containerPort)
78+
continue
79+
}
80+
5981
tun := NewTunnel(ipv4, parts[0], parts[1], "localhost", hostPort)
6082
// TODO check if we can leak tunnels
6183
err = tun.Start()
6284
if err != nil {
6385
return err
6486
}
65-
_, ok := t.tunnels[containerName]
66-
if !ok {
67-
t.tunnels[containerName] = map[string]*tunnel{}
68-
}
6987
t.tunnels[containerName][containerPort] = tun
7088
}
7189
return nil
@@ -88,6 +106,7 @@ func (t *TunnelManager) RemoveTunnels(containerName string) error {
88106
}
89107
tunnel.Stop() // nolint: errcheck
90108
}
109+
delete(t.tunnels, containerName)
91110

92111
klog.V(0).Infof("Removing IPv4 address %s associated to local interface", tunnelIP)
93112
output, err := RemoveIPFromLocalInterface(tunnelIP)
@@ -275,3 +294,29 @@ func (t *tunnel) handleUDPConnection(conn *net.UDPConn) error {
275294

276295
return err
277296
}
297+
298+
func ipOnHost(ip string) bool {
299+
ifaces, err := net.Interfaces()
300+
if err != nil {
301+
return false
302+
}
303+
for _, i := range ifaces {
304+
addrs, err := i.Addrs()
305+
if err != nil {
306+
continue
307+
}
308+
for _, addr := range addrs {
309+
var ipAddr net.IP
310+
switch v := addr.(type) {
311+
case *net.IPNet:
312+
ipAddr = v.IP
313+
case *net.IPAddr:
314+
ipAddr = v.IP
315+
}
316+
if ipAddr != nil && ipAddr.String() == ip {
317+
return true
318+
}
319+
}
320+
}
321+
return false
322+
}

tests/custom-network/setup_suite.bash

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,9 @@ function setup_suite {
1818
--subnet=172.20.0.0/16 $KIND_EXPERIMENTAL_DOCKER_NETWORK
1919

2020
# create cluster
21-
cat <<EOF | kind create cluster \
21+
kind create cluster \
2222
--name $CLUSTER_NAME \
23-
-v7 --wait 1m --retain --config=-
24-
kind: Cluster
25-
apiVersion: kind.x-k8s.io/v1alpha4
26-
nodes:
27-
- role: control-plane
28-
- role: worker
29-
- role: worker
30-
EOF
23+
-v7 --wait 1m --retain --config="$BATS_TEST_DIRNAME/../kind.yaml"
3124

3225
# build & run cloud-provider-kind
3326
cd "$BATS_TEST_DIRNAME"/../.. && make

tests/kind.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Cluster
2+
apiVersion: kind.x-k8s.io/v1alpha4
3+
nodes:
4+
- role: control-plane
5+
- role: worker
6+
- role: worker

tests/setup_suite.bash

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,7 @@ function setup_suite {
1212
rm -rf "$ARTIFACTS_DIR"/*
1313

1414
# create cluster
15-
cat <<EOF | kind create cluster \
16-
--name $CLUSTER_NAME \
17-
-v7 --wait 1m --retain --config=-
18-
kind: Cluster
19-
apiVersion: kind.x-k8s.io/v1alpha4
20-
nodes:
21-
- role: control-plane
22-
- role: worker
23-
- role: worker
24-
EOF
15+
kind create cluster --name $CLUSTER_NAME -v7 --wait 1m --retain --config="$BATS_TEST_DIRNAME/kind.yaml"
2516

2617
cd "$BATS_TEST_DIRNAME"/.. && make
2718
nohup "$BATS_TEST_DIRNAME"/../bin/cloud-provider-kind -v 2 --gateway-channel=standard --enable-log-dumping --logs-dir "$ARTIFACTS_DIR" > "$ARTIFACTS_DIR"/ccm-kind.log 2>&1 &

0 commit comments

Comments
 (0)