Skip to content

Commit dcf0031

Browse files
authored
Auto select network iface when not provided (#1579)
1 parent ec5d537 commit dcf0031

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

cmd/installer/cli/install2.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,17 @@ type Install2CmdFlags struct {
3131
dataDir string
3232
licenseFile string
3333
localArtifactMirrorPort int
34-
networkInterface string
3534
assumeYes bool
3635
overrides string
3736
privateCAs []string
3837
skipHostPreflights bool
3938
ignoreHostPreflights bool
4039
configValues string
4140

41+
networkInterface string
42+
isAutoSelectedNetworkInterface bool
43+
autoSelectNetworkInterfaceErr error
44+
4245
license *kotsv1beta1.License
4346
proxy *ecv1beta1.ProxySpec
4447

@@ -88,6 +91,17 @@ func Install2Cmd(ctx context.Context, name string) *cobra.Command {
8891
flags.podCIDR = pod
8992
flags.serviceCIDR = svc
9093

94+
// if a network interface flag was not provided, attempt to discover it
95+
if flags.networkInterface == "" {
96+
autoInterface, err := determineBestNetworkInterface()
97+
if err != nil {
98+
flags.autoSelectNetworkInterfaceErr = err
99+
} else {
100+
flags.isAutoSelectedNetworkInterface = true
101+
flags.networkInterface = autoInterface
102+
}
103+
}
104+
91105
// validate the the license is indeed a license file
92106
l, err := helpers.ParseLicense(flags.licenseFile)
93107
if err != nil {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
apimachinerynet "k8s.io/apimachinery/pkg/util/net"
8+
)
9+
10+
var (
11+
ErrNoAutoInterface = fmt.Errorf("no auto interface found")
12+
ErrBestInterfaceWas6 = fmt.Errorf("best interface was IPv6")
13+
ErrCannotDetermineInterfaceName = fmt.Errorf("cannot determine interface name")
14+
)
15+
16+
// determineBestNetworkInterface attempts to determine the best network interface to use for the cluster.
17+
func determineBestNetworkInterface() (string, error) {
18+
iface, err := apimachinerynet.ChooseHostInterface()
19+
20+
if err != nil || iface == nil {
21+
return "", ErrNoAutoInterface
22+
}
23+
24+
if iface.To4() == nil {
25+
return "", ErrBestInterfaceWas6
26+
}
27+
28+
ifaceName, err := findInterfaceNameByIP(iface)
29+
if err != nil {
30+
return "", ErrCannotDetermineInterfaceName
31+
}
32+
33+
return ifaceName, nil
34+
}
35+
36+
func findInterfaceNameByIP(ip net.IP) (string, error) {
37+
interfaces, err := net.Interfaces()
38+
if err != nil {
39+
return "", fmt.Errorf("failed to list interfaces: %v", err)
40+
}
41+
42+
for _, iface := range interfaces {
43+
addrs, err := iface.Addrs()
44+
if err != nil {
45+
return "", fmt.Errorf("failed to get addresses for interface %s: %v", iface.Name, err)
46+
}
47+
48+
for _, addr := range addrs {
49+
var ifaceIP net.IP
50+
switch v := addr.(type) {
51+
case *net.IPNet:
52+
ifaceIP = v.IP
53+
case *net.IPAddr:
54+
ifaceIP = v.IP
55+
}
56+
57+
if ifaceIP != nil && ifaceIP.Equal(ip) {
58+
return iface.Name, nil
59+
}
60+
}
61+
}
62+
63+
return "", fmt.Errorf("no interface found for IP %s", ip)
64+
}

0 commit comments

Comments
 (0)