Restore server network auto-detection
Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -41,6 +41,7 @@ type WarewulfYaml struct {
|
||||
WWClient *WWClientConf `yaml:"wwclient,omitempty"`
|
||||
|
||||
warewulfconf string
|
||||
autodetected bool
|
||||
}
|
||||
|
||||
// New caches and returns a new [WarewulfYaml] initialized with empty
|
||||
@@ -73,12 +74,12 @@ func Get() *WarewulfYaml {
|
||||
|
||||
// Read populates [WarewulfYaml] with the values from a configuration
|
||||
// file.
|
||||
func (conf *WarewulfYaml) Read(confFileName string) error {
|
||||
func (conf *WarewulfYaml) Read(confFileName string, autodetect bool) error {
|
||||
wwlog.Debug("Reading warewulf.conf from: %s", confFileName)
|
||||
conf.warewulfconf = confFileName
|
||||
if data, err := os.ReadFile(confFileName); err != nil {
|
||||
return err
|
||||
} else if err := conf.Parse(data); err != nil {
|
||||
} else if err := conf.Parse(data, autodetect); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
@@ -86,7 +87,7 @@ func (conf *WarewulfYaml) Read(confFileName string) error {
|
||||
}
|
||||
|
||||
// Parse populates [WarewulfYaml] with the values from a yaml document.
|
||||
func (conf *WarewulfYaml) Parse(data []byte) error {
|
||||
func (conf *WarewulfYaml) Parse(data []byte, autodetect bool) error {
|
||||
// ipxe binaries are merged not overwritten, store defaults separate
|
||||
defIpxe := make(map[string]string)
|
||||
for k, v := range conf.TFTP.IpxeBinaries {
|
||||
@@ -110,6 +111,33 @@ func (conf *WarewulfYaml) Parse(data []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
if autodetect {
|
||||
if conf.Ipaddr == "" {
|
||||
if ip := GetOutboundIP(); ip != nil {
|
||||
conf.Ipaddr = ip.String()
|
||||
conf.autodetected = true
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Netmask == "" {
|
||||
if ip := net.ParseIP(conf.Ipaddr); ip != nil {
|
||||
if network, err := GetIPNetForIP(ip); err == nil {
|
||||
conf.Netmask = net.IP(network.Mask).String()
|
||||
conf.autodetected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Network == "" {
|
||||
if ip := net.ParseIP(conf.Ipaddr); ip != nil {
|
||||
if mask := net.IPMask(net.ParseIP(conf.Netmask)); mask != nil {
|
||||
conf.Network = ip.Mask(mask).String()
|
||||
conf.autodetected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if conf.Ipaddr6 != "" {
|
||||
if _, network, err := net.ParseCIDR(conf.Ipaddr6); err == nil {
|
||||
if conf.Ipv6net == "" {
|
||||
@@ -161,6 +189,10 @@ func (conf *WarewulfYaml) GetWarewulfConf() string {
|
||||
return conf.warewulfconf
|
||||
}
|
||||
|
||||
func (conf *WarewulfYaml) Autodetected() bool {
|
||||
return conf.autodetected
|
||||
}
|
||||
|
||||
func (config *WarewulfYaml) Dump() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
yamlEncoder := yaml.NewEncoder(&buf)
|
||||
|
||||
@@ -385,7 +385,7 @@ tftp:
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
conf := New()
|
||||
err := conf.Parse([]byte(tt.input))
|
||||
err := conf.Parse([]byte(tt.input), false)
|
||||
assert.NoError(t, err)
|
||||
result, err := conf.Dump()
|
||||
assert.NoError(t, err)
|
||||
@@ -405,7 +405,7 @@ func TestInitializedFromFile(t *testing.T) {
|
||||
|
||||
conf := New()
|
||||
assert.False(t, conf.InitializedFromFile())
|
||||
assert.NoError(t, conf.Read(tempWarewulfConf.Name()))
|
||||
assert.NoError(t, conf.Read(tempWarewulfConf.Name(), false))
|
||||
assert.True(t, conf.InitializedFromFile())
|
||||
assert.Equal(t, conf.GetWarewulfConf(), tempWarewulfConf.Name())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,62 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func BoolP(p *bool) bool {
|
||||
return p != nil && *p
|
||||
}
|
||||
|
||||
func GetOutboundIP() net.IP {
|
||||
conn, err := net.Dial("udp", "192.0.2.1:80")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer conn.Close()
|
||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||
return localAddr.IP
|
||||
}
|
||||
|
||||
func GetIPNetForIP(ip net.IP) (*net.IPNet, error) {
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get network interfaces: %v", err)
|
||||
}
|
||||
|
||||
for _, iface := range interfaces {
|
||||
// skip interfaces that are down or not relevant
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue // try next interface
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
// We expect addr to be of type *net.IPNet.
|
||||
var ipNet *net.IPNet
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ipNet = v
|
||||
case *net.IPAddr:
|
||||
// Wrap net.IPAddr in an IPNet with its default mask.
|
||||
ipNet = &net.IPNet{IP: v.IP, Mask: v.IP.DefaultMask()}
|
||||
}
|
||||
|
||||
if ipNet == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if the IP matches (for IPv4, Equal works well)
|
||||
if ipNet.IP.Equal(ip) {
|
||||
return ipNet, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find IPNet for IP %v", ip)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user