Merge pull request #149 from crawford/network

feat(network): Add support for blind interfaces, support for hwaddress, and bug fixes
This commit is contained in:
Alex Crawford 2014-06-20 17:53:37 -07:00
commit 8eb0636034
6 changed files with 406 additions and 144 deletions

View File

@ -0,0 +1,27 @@
#Debian Interfaces#
**WARNING**: This option is EXPERIMENTAL and may change or be removed at any
point.
There is basic support for converting from a Debian network configuration to
networkd unit files. The -convert-netconf=debian option is used to activate
this feature.
#convert-netconf#
Default: ""
Read the network config provided in cloud-drive and translate it from the
specified format into networkd unit files (requires the -from-configdrive
flag). Currently only supports "debian" which provides support for a small
subset of the [Debian network configuration]
(https://wiki.debian.org/NetworkConfiguration). These options include:
- interface config methods
- static
- address/netmask
- gateway
- hwaddress
- dns-nameservers
- dhcp
- hwaddress
- manual
- loopback
- vlan_raw_device
- bond-slaves

View File

@ -7,15 +7,23 @@ import (
type InterfaceGenerator interface { type InterfaceGenerator interface {
Name() string Name() string
Filename() string
Netdev() string Netdev() string
Link() string Link() string
Network() string Network() string
} }
type networkInterface interface {
InterfaceGenerator
Children() []networkInterface
setConfigDepth(int)
}
type logicalInterface struct { type logicalInterface struct {
name string name string
config configMethod config configMethod
children []InterfaceGenerator children []networkInterface
configDepth int
} }
func (i *logicalInterface) Network() string { func (i *logicalInterface) Network() string {
@ -48,6 +56,22 @@ func (i *logicalInterface) Network() string {
return config return config
} }
func (i *logicalInterface) Link() string {
return ""
}
func (i *logicalInterface) Filename() string {
return fmt.Sprintf("%02x-%s", i.configDepth, i.name)
}
func (i *logicalInterface) Children() []networkInterface {
return i.children
}
func (i *logicalInterface) setConfigDepth(depth int) {
i.configDepth = depth
}
type physicalInterface struct { type physicalInterface struct {
logicalInterface logicalInterface
} }
@ -60,10 +84,6 @@ func (p *physicalInterface) Netdev() string {
return "" return ""
} }
func (p *physicalInterface) Link() string {
return ""
}
type bondInterface struct { type bondInterface struct {
logicalInterface logicalInterface
slaves []string slaves []string
@ -77,10 +97,6 @@ func (b *bondInterface) Netdev() string {
return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name) return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
} }
func (b *bondInterface) Link() string {
return ""
}
type vlanInterface struct { type vlanInterface struct {
logicalInterface logicalInterface
id int id int
@ -92,102 +108,146 @@ func (v *vlanInterface) Name() string {
} }
func (v *vlanInterface) Netdev() string { func (v *vlanInterface) Netdev() string {
return fmt.Sprintf("[NetDev]\nKind=vlan\nName=%s\n\n[VLAN]\nId=%d\n", v.name, v.id) config := fmt.Sprintf("[NetDev]\nKind=vlan\nName=%s\n", v.name)
} switch c := v.config.(type) {
case configMethodStatic:
func (v *vlanInterface) Link() string { if c.hwaddress != nil {
return "" config += fmt.Sprintf("MACAddress=%s\n", c.hwaddress)
}
case configMethodDHCP:
if c.hwaddress != nil {
config += fmt.Sprintf("MACAddress=%s\n", c.hwaddress)
}
}
config += fmt.Sprintf("\n[VLAN]\nId=%d\n", v.id)
return config
} }
func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
bondStanzas := make(map[string]*stanzaInterface) interfaceMap := createInterfaces(stanzas)
physicalStanzas := make(map[string]*stanzaInterface) linkAncestors(interfaceMap)
vlanStanzas := make(map[string]*stanzaInterface) markConfigDepths(interfaceMap)
for _, iface := range stanzas {
switch iface.kind {
case interfaceBond:
bondStanzas[iface.name] = iface
case interfacePhysical:
physicalStanzas[iface.name] = iface
case interfaceVLAN:
vlanStanzas[iface.name] = iface
}
}
physicals := make(map[string]*physicalInterface) interfaces := make([]InterfaceGenerator, 0, len(interfaceMap))
for _, p := range physicalStanzas { for _, iface := range interfaceMap {
if _, ok := p.configMethod.(configMethodLoopback); ok { interfaces = append(interfaces, iface)
continue
}
physicals[p.name] = &physicalInterface{
logicalInterface{
name: p.name,
config: p.configMethod,
children: []InterfaceGenerator{},
},
}
}
bonds := make(map[string]*bondInterface)
for _, b := range bondStanzas {
bonds[b.name] = &bondInterface{
logicalInterface{
name: b.name,
config: b.configMethod,
children: []InterfaceGenerator{},
},
b.options["slaves"],
}
}
vlans := make(map[string]*vlanInterface)
for _, v := range vlanStanzas {
var rawDevice string
id, _ := strconv.Atoi(v.options["id"][0])
if device := v.options["raw_device"]; len(device) == 1 {
rawDevice = device[0]
}
vlans[v.name] = &vlanInterface{
logicalInterface{
name: v.name,
config: v.configMethod,
children: []InterfaceGenerator{},
},
id,
rawDevice,
}
}
for _, vlan := range vlans {
if physical, ok := physicals[vlan.rawDevice]; ok {
physical.children = append(physical.children, vlan)
}
if bond, ok := bonds[vlan.rawDevice]; ok {
bond.children = append(bond.children, vlan)
}
}
for _, bond := range bonds {
for _, slave := range bond.slaves {
if physical, ok := physicals[slave]; ok {
physical.children = append(physical.children, bond)
}
if pBond, ok := bonds[slave]; ok {
pBond.children = append(pBond.children, bond)
}
}
}
interfaces := make([]InterfaceGenerator, 0, len(physicals)+len(bonds)+len(vlans))
for _, physical := range physicals {
interfaces = append(interfaces, physical)
}
for _, bond := range bonds {
interfaces = append(interfaces, bond)
}
for _, vlan := range vlans {
interfaces = append(interfaces, vlan)
} }
return interfaces return interfaces
} }
func createInterfaces(stanzas []*stanzaInterface) map[string]networkInterface {
interfaceMap := make(map[string]networkInterface)
for _, iface := range stanzas {
switch iface.kind {
case interfaceBond:
interfaceMap[iface.name] = &bondInterface{
logicalInterface{
name: iface.name,
config: iface.configMethod,
children: []networkInterface{},
},
iface.options["slaves"],
}
for _, slave := range iface.options["slaves"] {
if _, ok := interfaceMap[slave]; !ok {
interfaceMap[slave] = &physicalInterface{
logicalInterface{
name: slave,
config: configMethodManual{},
children: []networkInterface{},
},
}
}
}
case interfacePhysical:
if _, ok := iface.configMethod.(configMethodLoopback); ok {
continue
}
interfaceMap[iface.name] = &physicalInterface{
logicalInterface{
name: iface.name,
config: iface.configMethod,
children: []networkInterface{},
},
}
case interfaceVLAN:
var rawDevice string
id, _ := strconv.Atoi(iface.options["id"][0])
if device := iface.options["raw_device"]; len(device) == 1 {
rawDevice = device[0]
if _, ok := interfaceMap[rawDevice]; !ok {
interfaceMap[rawDevice] = &physicalInterface{
logicalInterface{
name: rawDevice,
config: configMethodManual{},
children: []networkInterface{},
},
}
}
}
interfaceMap[iface.name] = &vlanInterface{
logicalInterface{
name: iface.name,
config: iface.configMethod,
children: []networkInterface{},
},
id,
rawDevice,
}
}
}
return interfaceMap
}
func linkAncestors(interfaceMap map[string]networkInterface) {
for _, iface := range interfaceMap {
switch i := iface.(type) {
case *vlanInterface:
if parent, ok := interfaceMap[i.rawDevice]; ok {
switch p := parent.(type) {
case *physicalInterface:
p.children = append(p.children, iface)
case *bondInterface:
p.children = append(p.children, iface)
}
}
case *bondInterface:
for _, slave := range i.slaves {
if parent, ok := interfaceMap[slave]; ok {
switch p := parent.(type) {
case *physicalInterface:
p.children = append(p.children, iface)
case *bondInterface:
p.children = append(p.children, iface)
}
}
}
}
}
}
func markConfigDepths(interfaceMap map[string]networkInterface) {
rootInterfaceMap := make(map[string]networkInterface)
for k, v := range interfaceMap {
rootInterfaceMap[k] = v
}
for _, iface := range interfaceMap {
for _, child := range iface.Children() {
delete(rootInterfaceMap, child.Name())
}
}
for _, iface := range rootInterfaceMap {
setDepth(iface, 0)
}
}
func setDepth(iface networkInterface, depth int) {
iface.setConfigDepth(depth)
for _, child := range iface.Children() {
setDepth(child, depth+1)
}
}

View File

@ -30,7 +30,7 @@ func TestPhysicalInterfaceLink(t *testing.T) {
func TestPhysicalInterfaceNetwork(t *testing.T) { func TestPhysicalInterfaceNetwork(t *testing.T) {
p := physicalInterface{logicalInterface{ p := physicalInterface{logicalInterface{
name: "testname", name: "testname",
children: []InterfaceGenerator{ children: []networkInterface{
&bondInterface{ &bondInterface{
logicalInterface{ logicalInterface{
name: "testbond1", name: "testbond1",
@ -96,7 +96,7 @@ func TestBondInterfaceNetwork(t *testing.T) {
logicalInterface{ logicalInterface{
name: "testname", name: "testname",
config: configMethodDHCP{}, config: configMethodDHCP{},
children: []InterfaceGenerator{ children: []networkInterface{
&bondInterface{ &bondInterface{
logicalInterface{ logicalInterface{
name: "testbond1", name: "testbond1",
@ -143,16 +143,26 @@ func TestVLANInterfaceName(t *testing.T) {
} }
func TestVLANInterfaceNetdev(t *testing.T) { func TestVLANInterfaceNetdev(t *testing.T) {
v := vlanInterface{logicalInterface{name: "testname"}, 1, ""} for _, tt := range []struct {
netdev := `[NetDev] i vlanInterface
Kind=vlan l string
Name=testname }{
{
[VLAN] vlanInterface{logicalInterface{name: "testname"}, 1, ""},
Id=1 "[NetDev]\nKind=vlan\nName=testname\n\n[VLAN]\nId=1\n",
` },
if v.Netdev() != netdev { {
t.FailNow() vlanInterface{logicalInterface{name: "testname", config: configMethodStatic{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
"[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
},
{
vlanInterface{logicalInterface{name: "testname", config: configMethodDHCP{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
"[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
},
} {
if tt.i.Netdev() != tt.l {
t.Fatalf("bad netdev config (%q): got %q, want %q", tt.i, tt.i.Netdev(), tt.l)
}
} }
} }
@ -224,6 +234,80 @@ func TestBuildInterfacesLo(t *testing.T) {
} }
} }
func TestBuildInterfacesBlindBond(t *testing.T) {
stanzas := []*stanzaInterface{
{
name: "bond0",
kind: interfaceBond,
auto: false,
configMethod: configMethodManual{},
options: map[string][]string{
"slaves": []string{"eth0"},
},
},
}
interfaces := buildInterfaces(stanzas)
bond0 := &bondInterface{
logicalInterface{
name: "bond0",
config: configMethodManual{},
children: []networkInterface{},
configDepth: 1,
},
[]string{"eth0"},
}
eth0 := &physicalInterface{
logicalInterface{
name: "eth0",
config: configMethodManual{},
children: []networkInterface{bond0},
configDepth: 0,
},
}
expect := []InterfaceGenerator{bond0, eth0}
if !reflect.DeepEqual(interfaces, expect) {
t.FailNow()
}
}
func TestBuildInterfacesBlindVLAN(t *testing.T) {
stanzas := []*stanzaInterface{
{
name: "vlan0",
kind: interfaceVLAN,
auto: false,
configMethod: configMethodManual{},
options: map[string][]string{
"id": []string{"0"},
"raw_device": []string{"eth0"},
},
},
}
interfaces := buildInterfaces(stanzas)
vlan0 := &vlanInterface{
logicalInterface{
name: "vlan0",
config: configMethodManual{},
children: []networkInterface{},
configDepth: 1,
},
0,
"eth0",
}
eth0 := &physicalInterface{
logicalInterface{
name: "eth0",
config: configMethodManual{},
children: []networkInterface{vlan0},
configDepth: 0,
},
}
expect := []InterfaceGenerator{eth0, vlan0}
if !reflect.DeepEqual(interfaces, expect) {
t.FailNow()
}
}
func TestBuildInterfaces(t *testing.T) { func TestBuildInterfaces(t *testing.T) {
stanzas := []*stanzaInterface{ stanzas := []*stanzaInterface{
&stanzaInterface{ &stanzaInterface{
@ -275,43 +359,48 @@ func TestBuildInterfaces(t *testing.T) {
interfaces := buildInterfaces(stanzas) interfaces := buildInterfaces(stanzas)
vlan1 := &vlanInterface{ vlan1 := &vlanInterface{
logicalInterface{ logicalInterface{
name: "vlan1", name: "vlan1",
config: configMethodManual{}, config: configMethodManual{},
children: []InterfaceGenerator{}, children: []networkInterface{},
configDepth: 2,
}, },
1, 1,
"bond0", "bond0",
} }
vlan0 := &vlanInterface{ vlan0 := &vlanInterface{
logicalInterface{ logicalInterface{
name: "vlan0", name: "vlan0",
config: configMethodManual{}, config: configMethodManual{},
children: []InterfaceGenerator{}, children: []networkInterface{},
configDepth: 1,
}, },
0, 0,
"eth0", "eth0",
} }
bond1 := &bondInterface{ bond1 := &bondInterface{
logicalInterface{ logicalInterface{
name: "bond1", name: "bond1",
config: configMethodManual{}, config: configMethodManual{},
children: []InterfaceGenerator{}, children: []networkInterface{},
configDepth: 2,
}, },
[]string{"bond0"}, []string{"bond0"},
} }
bond0 := &bondInterface{ bond0 := &bondInterface{
logicalInterface{ logicalInterface{
name: "bond0", name: "bond0",
config: configMethodManual{}, config: configMethodManual{},
children: []InterfaceGenerator{vlan1, bond1}, children: []networkInterface{bond1, vlan1},
configDepth: 1,
}, },
[]string{"eth0"}, []string{"eth0"},
} }
eth0 := &physicalInterface{ eth0 := &physicalInterface{
logicalInterface{ logicalInterface{
name: "eth0", name: "eth0",
config: configMethodManual{}, config: configMethodManual{},
children: []InterfaceGenerator{vlan0, bond0}, children: []networkInterface{bond0, vlan0},
configDepth: 0,
}, },
} }
expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1} expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1}
@ -319,3 +408,19 @@ func TestBuildInterfaces(t *testing.T) {
t.FailNow() t.FailNow()
} }
} }
func TestFilename(t *testing.T) {
for _, tt := range []struct {
i logicalInterface
f string
}{
{logicalInterface{name: "iface", configDepth: 0}, "00-iface"},
{logicalInterface{name: "iface", configDepth: 9}, "09-iface"},
{logicalInterface{name: "iface", configDepth: 10}, "0a-iface"},
{logicalInterface{name: "iface", configDepth: 53}, "35-iface"},
} {
if tt.i.Filename() != tt.f {
t.Fatalf("bad filename (%q): got %q, want %q", tt.i, tt.i.Filename(), tt.f)
}
}
}

View File

@ -40,13 +40,16 @@ type configMethodStatic struct {
address net.IPNet address net.IPNet
nameservers []net.IP nameservers []net.IP
routes []route routes []route
hwaddress net.HardwareAddr
} }
type configMethodLoopback struct{} type configMethodLoopback struct{}
type configMethodManual struct{} type configMethodManual struct{}
type configMethodDHCP struct{} type configMethodDHCP struct {
hwaddress net.HardwareAddr
}
func parseStanzas(lines []string) (stanzas []stanza, err error) { func parseStanzas(lines []string) (stanzas []stanza, err error) {
rawStanzas, err := splitStanzas(lines) rawStanzas, err := splitStanzas(lines)
@ -96,7 +99,7 @@ func splitStanzas(lines []string) ([][]string, error) {
} else if curStanza != nil { } else if curStanza != nil {
curStanza = append(curStanza, line) curStanza = append(curStanza, line)
} else { } else {
return nil, fmt.Errorf("missing stanza start '%s'", line) return nil, fmt.Errorf("missing stanza start %q", line)
} }
} }
@ -142,7 +145,7 @@ func parseStanza(rawStanza []string) (stanza, error) {
case "iface": case "iface":
return parseInterfaceStanza(attributes, rawStanza[1:]) return parseInterfaceStanza(attributes, rawStanza[1:])
default: default:
return nil, fmt.Errorf("unknown stanza '%s'", kind) return nil, fmt.Errorf("unknown stanza %q", kind)
} }
} }
@ -204,7 +207,7 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
} }
} }
if config.address.IP == nil || config.address.Mask == nil { if config.address.IP == nil || config.address.Mask == nil {
return nil, fmt.Errorf("malformed static network config for '%s'", iface) return nil, fmt.Errorf("malformed static network config for %q", iface)
} }
if gateways, ok := optionMap["gateway"]; ok { if gateways, ok := optionMap["gateway"]; ok {
if len(gateways) == 1 { if len(gateways) == 1 {
@ -217,6 +220,11 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
}) })
} }
} }
if hwaddress, err := parseHwaddress(optionMap, iface); err == nil {
config.hwaddress = hwaddress
} else {
return nil, err
}
for _, nameserver := range optionMap["dns-nameservers"] { for _, nameserver := range optionMap["dns-nameservers"] {
config.nameservers = append(config.nameservers, net.ParseIP(nameserver)) config.nameservers = append(config.nameservers, net.ParseIP(nameserver))
} }
@ -245,9 +253,15 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
case "manual": case "manual":
conf = configMethodManual{} conf = configMethodManual{}
case "dhcp": case "dhcp":
conf = configMethodDHCP{} config := configMethodDHCP{}
if hwaddress, err := parseHwaddress(optionMap, iface); err == nil {
config.hwaddress = hwaddress
} else {
return nil, err
}
conf = config
default: default:
return nil, fmt.Errorf("invalid config method '%s'", confMethod) return nil, fmt.Errorf("invalid config method %q", confMethod)
} }
if _, ok := optionMap["vlan_raw_device"]; ok { if _, ok := optionMap["vlan_raw_device"]; ok {
@ -265,6 +279,19 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
return parsePhysicalStanza(iface, conf, attributes, optionMap) return parsePhysicalStanza(iface, conf, attributes, optionMap)
} }
func parseHwaddress(options map[string][]string, iface string) (net.HardwareAddr, error) {
if hwaddress, ok := options["hwaddress"]; ok && len(hwaddress) == 2 {
switch hwaddress[0] {
case "ether":
if address, err := net.ParseMAC(hwaddress[1]); err == nil {
return address, nil
}
return nil, fmt.Errorf("malformed hwaddress option for %q", iface)
}
}
return nil, nil
}
func parseBondStanza(iface string, conf configMethod, attributes []string, options map[string][]string) (*stanzaInterface, error) { func parseBondStanza(iface string, conf configMethod, attributes []string, options map[string][]string) (*stanzaInterface, error) {
options["slaves"] = options["bond-slaves"] options["slaves"] = options["bond-slaves"]
return &stanzaInterface{name: iface, kind: interfaceBond, configMethod: conf, options: options}, nil return &stanzaInterface{name: iface, kind: interfaceBond, configMethod: conf, options: options}, nil
@ -282,11 +309,11 @@ func parseVLANStanza(iface string, conf configMethod, attributes []string, optio
} else if strings.HasPrefix(iface, "vlan") { } else if strings.HasPrefix(iface, "vlan") {
id = strings.TrimPrefix(iface, "vlan") id = strings.TrimPrefix(iface, "vlan")
} else { } else {
return nil, fmt.Errorf("malformed vlan name %s", iface) return nil, fmt.Errorf("malformed vlan name %q", iface)
} }
if _, err := strconv.Atoi(id); err != nil { if _, err := strconv.Atoi(id); err != nil {
return nil, fmt.Errorf("malformed vlan name %s", iface) return nil, fmt.Errorf("malformed vlan name %q", iface)
} }
options["id"] = []string{id} options["id"] = []string{id}
options["raw_device"] = options["vlan_raw_device"] options["raw_device"] = options["vlan_raw_device"]

View File

@ -42,6 +42,8 @@ func TestBadParseInterfaceStanza(t *testing.T) {
{[]string{"eth", "inet", "static"}, []string{"netmask 255.255.255.0"}, "malformed static network config"}, {[]string{"eth", "inet", "static"}, []string{"netmask 255.255.255.0"}, "malformed static network config"},
{[]string{"eth", "inet", "static"}, []string{"address invalid", "netmask 255.255.255.0"}, "malformed static network config"}, {[]string{"eth", "inet", "static"}, []string{"address invalid", "netmask 255.255.255.0"}, "malformed static network config"},
{[]string{"eth", "inet", "static"}, []string{"address 192.168.1.100", "netmask invalid"}, "malformed static network config"}, {[]string{"eth", "inet", "static"}, []string{"address 192.168.1.100", "netmask invalid"}, "malformed static network config"},
{[]string{"eth", "inet", "static"}, []string{"address 192.168.1.100", "netmask 255.255.255.0", "hwaddress ether NotAnAddress"}, "malformed hwaddress option"},
{[]string{"eth", "inet", "dhcp"}, []string{"hwaddress ether NotAnAddress"}, "malformed hwaddress option"},
} { } {
_, err := parseInterfaceStanza(tt.in, tt.opts) _, err := parseInterfaceStanza(tt.in, tt.opts)
if err == nil || !strings.HasPrefix(err.Error(), tt.e) { if err == nil || !strings.HasPrefix(err.Error(), tt.e) {
@ -407,7 +409,46 @@ func TestParseInterfaceStanzaOptions(t *testing.T) {
} }
} }
func TestParseInterfaceStazaBond(t *testing.T) { func TestParseInterfaceStanzaHwaddress(t *testing.T) {
for _, tt := range []struct {
attr []string
opt []string
hw net.HardwareAddr
}{
{
[]string{"mybond", "inet", "dhcp"},
[]string{},
nil,
},
{
[]string{"mybond", "inet", "dhcp"},
[]string{"hwaddress ether 00:01:02:03:04:05"},
net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}),
},
{
[]string{"mybond", "inet", "static"},
[]string{"hwaddress ether 00:01:02:03:04:05", "address 192.168.1.100", "netmask 255.255.255.0"},
net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}),
},
} {
iface, err := parseInterfaceStanza(tt.attr, tt.opt)
if err != nil {
t.Fatalf("error in parseInterfaceStanza (%q, %q): %q", tt.attr, tt.opt, err)
}
switch c := iface.configMethod.(type) {
case configMethodStatic:
if !reflect.DeepEqual(c.hwaddress, tt.hw) {
t.Fatalf("bad hwaddress (%q, %q): got %q, want %q", tt.attr, tt.opt, c.hwaddress, tt.hw)
}
case configMethodDHCP:
if !reflect.DeepEqual(c.hwaddress, tt.hw) {
t.Fatalf("bad hwaddress (%q, %q): got %q, want %q", tt.attr, tt.opt, c.hwaddress, tt.hw)
}
}
}
}
func TestParseInterfaceStanzaBond(t *testing.T) {
iface, err := parseInterfaceStanza([]string{"mybond", "inet", "manual"}, []string{"bond-slaves eth"}) iface, err := parseInterfaceStanza([]string{"mybond", "inet", "manual"}, []string{"bond-slaves eth"})
if err != nil { if err != nil {
t.FailNow() t.FailNow()
@ -417,7 +458,7 @@ func TestParseInterfaceStazaBond(t *testing.T) {
} }
} }
func TestParseInterfaceStazaVLANName(t *testing.T) { func TestParseInterfaceStanzaVLANName(t *testing.T) {
iface, err := parseInterfaceStanza([]string{"eth0.1", "inet", "manual"}, nil) iface, err := parseInterfaceStanza([]string{"eth0.1", "inet", "manual"}, nil)
if err != nil { if err != nil {
t.FailNow() t.FailNow()
@ -427,7 +468,7 @@ func TestParseInterfaceStazaVLANName(t *testing.T) {
} }
} }
func TestParseInterfaceStazaVLANOption(t *testing.T) { func TestParseInterfaceStanzaVLANOption(t *testing.T) {
iface, err := parseInterfaceStanza([]string{"vlan1", "inet", "manual"}, []string{"vlan_raw_device eth"}) iface, err := parseInterfaceStanza([]string{"vlan1", "inet", "manual"}, []string{"vlan_raw_device eth"})
if err != nil { if err != nil {
t.FailNow() t.FailNow()

View File

@ -36,7 +36,9 @@ func downNetworkInterfaces(interfaces []network.InterfaceGenerator) error {
sysInterfaceMap := make(map[string]*net.Interface) sysInterfaceMap := make(map[string]*net.Interface)
if systemInterfaces, err := net.Interfaces(); err == nil { if systemInterfaces, err := net.Interfaces(); err == nil {
for _, iface := range systemInterfaces { for _, iface := range systemInterfaces {
sysInterfaceMap[iface.Name] = &iface // Need a copy of the interface so we can take the address
temp := iface
sysInterfaceMap[temp.Name] = &temp
} }
} else { } else {
return err return err
@ -64,15 +66,15 @@ func restartNetworkd() error {
func WriteNetworkdConfigs(interfaces []network.InterfaceGenerator) error { func WriteNetworkdConfigs(interfaces []network.InterfaceGenerator) error {
for _, iface := range interfaces { for _, iface := range interfaces {
filename := path.Join(runtimeNetworkPath, fmt.Sprintf("%s.netdev", iface.Name())) filename := path.Join(runtimeNetworkPath, fmt.Sprintf("%s.netdev", iface.Filename()))
if err := writeConfig(filename, iface.Netdev()); err != nil { if err := writeConfig(filename, iface.Netdev()); err != nil {
return err return err
} }
filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.link", iface.Name())) filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.link", iface.Filename()))
if err := writeConfig(filename, iface.Link()); err != nil { if err := writeConfig(filename, iface.Link()); err != nil {
return err return err
} }
filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.network", iface.Name())) filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.network", iface.Filename()))
if err := writeConfig(filename, iface.Network()); err != nil { if err := writeConfig(filename, iface.Network()); err != nil {
return err return err
} }