Skip to content

Commit 0a8fafb

Browse files
Merge pull request #5393 from juanluisvaladas/etcd-cplb-4664
Ensure iface.FirstPublicAddress isn't a secondary IP
2 parents 0147fbd + 5a69092 commit 0a8fafb

File tree

4 files changed

+116
-30
lines changed

4 files changed

+116
-30
lines changed

internal/pkg/iface/iface.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -82,19 +82,20 @@ func FirstPublicAddress() (string, error) {
8282
case strings.HasPrefix(i.Name, "cali"):
8383
continue
8484
}
85-
addresses, err := i.Addrs()
85+
86+
addresses, err := interfaceAddrs(i)
8687
if err != nil {
87-
logrus.Warnf("failed to get addresses for interface %s: %s", i.Name, err.Error())
88+
logrus.WithError(err).Warn("Skipping network interface ", i.Name)
8889
continue
8990
}
90-
for _, a := range addresses {
91+
for a := range addresses {
9192
// check the address type and skip if loopback
92-
if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
93-
if ipnet.IP.To4() != nil {
94-
return ipnet.IP.String(), nil
93+
if a != nil && !a.IP.IsLoopback() {
94+
if a.IP.To4() != nil {
95+
return a.IP.String(), nil
9596
}
96-
if ipnet.IP.To16() != nil && ipv6addr == "" {
97-
ipv6addr = ipnet.IP.String()
97+
if a.IP.To16() != nil && ipv6addr == "" {
98+
ipv6addr = a.IP.String()
9899
}
99100
}
100101
}

internal/pkg/iface/iface_linux.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2025 k0s authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package iface
18+
19+
import (
20+
"fmt"
21+
"iter"
22+
"net"
23+
24+
"github.com/vishvananda/netlink"
25+
"golang.org/x/sys/unix"
26+
)
27+
28+
func interfaceAddrs(i net.Interface) (iter.Seq[*net.IPNet], error) {
29+
link, err := netlink.LinkByName(i.Name)
30+
if err != nil {
31+
return nil, fmt.Errorf("failed to get link by name: %w", err)
32+
}
33+
34+
addresses, err := netlink.AddrList(link, netlink.FAMILY_ALL)
35+
if err != nil {
36+
return nil, fmt.Errorf("failed to list IP addresses: %w", err)
37+
}
38+
39+
return func(yield func(*net.IPNet) bool) {
40+
for _, a := range addresses {
41+
// skip secondary addresses. This is to avoid returning VIPs as the public address
42+
// https://github.com/k0sproject/k0s/issues/4664
43+
if a.Flags&unix.IFA_F_SECONDARY != 0 {
44+
continue
45+
}
46+
47+
if a.IPNet != nil {
48+
if !yield(a.IPNet) {
49+
return
50+
}
51+
}
52+
}
53+
}, nil
54+
}

internal/pkg/iface/iface_other.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//go:build !linux
2+
3+
/*
4+
Copyright 2025 k0s authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package iface
20+
21+
import (
22+
"fmt"
23+
"iter"
24+
"net"
25+
)
26+
27+
func interfaceAddrs(i net.Interface) (iter.Seq[*net.IPNet], error) {
28+
addresses, err := i.Addrs()
29+
if err != nil {
30+
return nil, fmt.Errorf("failed to list interface addresses: %w", err)
31+
}
32+
33+
return func(yield func(*net.IPNet) bool) {
34+
for _, a := range addresses {
35+
if ipnet, ok := a.(*net.IPNet); ok && ipnet != nil {
36+
if !yield(ipnet) {
37+
return
38+
}
39+
}
40+
}
41+
}, nil
42+
}

inttest/backup/backup_test.go

+11-22
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,8 @@ func (s *BackupSuite) TestK0sGetsUp() {
7676
s.Require().NoError(s.InitController(1, token, "--config=/tmp/k0s.yaml"))
7777
s.Require().NoError(s.WaitJoinAPI(s.ControllerNode(1)))
7878

79-
err = s.WaitForNodeReady(s.WorkerNode(0), kc)
80-
s.Require().NoError(err)
81-
82-
err = s.WaitForNodeReady(s.WorkerNode(1), kc)
83-
s.Require().NoError(err)
79+
s.Require().NoError(s.WaitForNodeReady(s.WorkerNode(0), kc))
80+
s.Require().NoError(s.WaitForNodeReady(s.WorkerNode(1), kc))
8481

8582
s.AssertSomeKubeSystemPods(kc)
8683

@@ -91,8 +88,6 @@ func (s *BackupSuite) TestK0sGetsUp() {
9188

9289
snapshot := s.makeSnapshot(kc)
9390

94-
s.Require().NoError(err)
95-
9691
s.Require().NoError(s.StopController(s.ControllerNode(0)))
9792
_ = s.StopController(s.ControllerNode(1)) // No error check as k0s might have actually exited since etcd is not really happy
9893

@@ -106,16 +101,10 @@ func (s *BackupSuite) TestK0sGetsUp() {
106101
// Join the second controller as normally
107102
s.Require().NoError(s.InitController(1, "--enable-worker", token))
108103

109-
s.Require().NoError(err)
110-
111-
err = s.WaitForNodeReady(s.WorkerNode(0), kc)
112-
s.Require().NoError(err)
113-
114-
err = s.WaitForNodeReady(s.WorkerNode(1), kc)
115-
s.Require().NoError(err)
104+
s.Require().NoError(s.WaitForNodeReady(s.WorkerNode(0), kc))
105+
s.Require().NoError(s.WaitForNodeReady(s.WorkerNode(1), kc))
116106

117107
snapshotAfterBackup := s.makeSnapshot(kc)
118-
s.Require().NoError(err)
119108
// Matching object UIDs after restore guarantees we got the full state restored
120109
s.Require().Equal(snapshot, snapshotAfterBackup)
121110

@@ -191,7 +180,7 @@ func (s *BackupSuite) takeBackup() error {
191180
}
192181
defer ssh.Disconnect()
193182

194-
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s backup --save-path /root/")
183+
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s backup --debug --save-path /root/")
195184
if !s.NoErrorf(err, "backup failed with output: %s", out) {
196185
return err
197186
}
@@ -206,7 +195,7 @@ func (s *BackupSuite) takeBackupStdout() error {
206195
}
207196
defer ssh.Disconnect()
208197

209-
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s backup --save-path - > backup.tar.gz")
198+
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s backup --debug --save-path - > backup.tar.gz")
210199
if !s.NoErrorf(err, "backup failed with output: %s", out) {
211200
return err
212201
}
@@ -216,7 +205,7 @@ func (s *BackupSuite) takeBackupStdout() error {
216205
return err
217206
}
218207

219-
s.T().Logf("backup taken succesfully with output:\n%s", out)
208+
s.T().Logf("backup taken successfully with output:\n%s", out)
220209
return nil
221210
}
222211

@@ -229,11 +218,11 @@ func (s *BackupSuite) restoreBackup() error {
229218

230219
s.T().Log("restoring controller from file")
231220

232-
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s restore $(ls /root/k0s_backup_*.tar.gz)")
221+
out, err := ssh.ExecWithOutput(s.Context(), "/usr/local/bin/k0s restore --debug $(ls /root/k0s_backup_*.tar.gz)")
233222
if !s.NoErrorf(err, "restore failed with output: %s", out) {
234223
return err
235224
}
236-
s.T().Logf("restored succesfully with output:\n%s", out)
225+
s.T().Logf("restored successfully with output:\n%s", out)
237226

238227
return nil
239228
}
@@ -247,11 +236,11 @@ func (s *BackupSuite) restoreBackupStdin() error {
247236

248237
s.T().Log("restoring controller from stdin")
249238

250-
out, err := ssh.ExecWithOutput(s.Context(), "cat backup.tar.gz | /usr/local/bin/k0s restore -")
239+
out, err := ssh.ExecWithOutput(s.Context(), "cat backup.tar.gz | /usr/local/bin/k0s restore --debug -")
251240
if !s.NoErrorf(err, "restore failed with output: %s", out) {
252241
return err
253242
}
254-
s.T().Logf("restored succesfully with output:\n%s", out)
243+
s.T().Logf("restored successfully with output:\n%s", out)
255244

256245
return nil
257246
}

0 commit comments

Comments
 (0)