feat(network): Add support for blind interfaces
It is valid for an interface to reference another, otherwise undeclared, interface (i.e. a bond enslaves eth0 without eth0 having its own iface stanza). In order to associate the two interfaces, the undeclared interface needs to be implicitly created so that it can be referenced by the other. This adds the capability to forward-declare interfaces in addition to cleaning up the process a little bit.
This commit is contained in:
parent
cf1ffad533
commit
159f4a2c7c
@ -100,93 +100,98 @@ func (v *vlanInterface) Link() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
||||||
bondStanzas := make(map[string]*stanzaInterface)
|
interfaceMap := make(map[string]InterfaceGenerator)
|
||||||
physicalStanzas := make(map[string]*stanzaInterface)
|
|
||||||
vlanStanzas := make(map[string]*stanzaInterface)
|
|
||||||
for _, iface := range stanzas {
|
for _, iface := range stanzas {
|
||||||
switch iface.kind {
|
switch iface.kind {
|
||||||
case interfaceBond:
|
case interfaceBond:
|
||||||
bondStanzas[iface.name] = iface
|
interfaceMap[iface.name] = &bondInterface{
|
||||||
case interfacePhysical:
|
logicalInterface{
|
||||||
physicalStanzas[iface.name] = iface
|
name: iface.name,
|
||||||
case interfaceVLAN:
|
config: iface.configMethod,
|
||||||
vlanStanzas[iface.name] = iface
|
children: []InterfaceGenerator{},
|
||||||
|
},
|
||||||
|
iface.options["slaves"],
|
||||||
|
}
|
||||||
|
for _, slave := range iface.options["slaves"] {
|
||||||
|
if _, ok := interfaceMap[slave]; !ok {
|
||||||
|
interfaceMap[slave] = &physicalInterface{
|
||||||
|
logicalInterface{
|
||||||
|
name: slave,
|
||||||
|
config: configMethodManual{},
|
||||||
|
children: []InterfaceGenerator{},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
physicals := make(map[string]*physicalInterface)
|
case interfacePhysical:
|
||||||
for _, p := range physicalStanzas {
|
if _, ok := iface.configMethod.(configMethodLoopback); ok {
|
||||||
if _, ok := p.configMethod.(configMethodLoopback); ok {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
physicals[p.name] = &physicalInterface{
|
interfaceMap[iface.name] = &physicalInterface{
|
||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: p.name,
|
name: iface.name,
|
||||||
config: p.configMethod,
|
config: iface.configMethod,
|
||||||
children: []InterfaceGenerator{},
|
children: []InterfaceGenerator{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bonds := make(map[string]*bondInterface)
|
case interfaceVLAN:
|
||||||
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
|
var rawDevice string
|
||||||
id, _ := strconv.Atoi(v.options["id"][0])
|
id, _ := strconv.Atoi(iface.options["id"][0])
|
||||||
if device := v.options["raw_device"]; len(device) == 1 {
|
if device := iface.options["raw_device"]; len(device) == 1 {
|
||||||
rawDevice = device[0]
|
rawDevice = device[0]
|
||||||
}
|
if _, ok := interfaceMap[rawDevice]; !ok {
|
||||||
vlans[v.name] = &vlanInterface{
|
interfaceMap[rawDevice] = &physicalInterface{
|
||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: v.name,
|
name: rawDevice,
|
||||||
config: v.configMethod,
|
config: configMethodManual{},
|
||||||
|
children: []InterfaceGenerator{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interfaceMap[iface.name] = &vlanInterface{
|
||||||
|
logicalInterface{
|
||||||
|
name: iface.name,
|
||||||
|
config: iface.configMethod,
|
||||||
children: []InterfaceGenerator{},
|
children: []InterfaceGenerator{},
|
||||||
},
|
},
|
||||||
id,
|
id,
|
||||||
rawDevice,
|
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 _, iface := range interfaceMap {
|
||||||
for _, slave := range bond.slaves {
|
switch i := iface.(type) {
|
||||||
if physical, ok := physicals[slave]; ok {
|
case *vlanInterface:
|
||||||
physical.children = append(physical.children, bond)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if pBond, ok := bonds[slave]; ok {
|
|
||||||
pBond.children = append(pBond.children, bond)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaces := make([]InterfaceGenerator, 0, len(physicals)+len(bonds)+len(vlans))
|
interfaces := make([]InterfaceGenerator, 0, len(interfaceMap))
|
||||||
for _, physical := range physicals {
|
for _, iface := range interfaceMap {
|
||||||
interfaces = append(interfaces, physical)
|
interfaces = append(interfaces, iface)
|
||||||
}
|
|
||||||
for _, bond := range bonds {
|
|
||||||
interfaces = append(interfaces, bond)
|
|
||||||
}
|
|
||||||
for _, vlan := range vlans {
|
|
||||||
interfaces = append(interfaces, vlan)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return interfaces
|
return interfaces
|
||||||
|
@ -224,6 +224,76 @@ 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: []InterfaceGenerator{},
|
||||||
|
},
|
||||||
|
[]string{"eth0"},
|
||||||
|
}
|
||||||
|
eth0 := &physicalInterface{
|
||||||
|
logicalInterface{
|
||||||
|
name: "eth0",
|
||||||
|
config: configMethodManual{},
|
||||||
|
children: []InterfaceGenerator{bond0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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: []InterfaceGenerator{},
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
"eth0",
|
||||||
|
}
|
||||||
|
eth0 := &physicalInterface{
|
||||||
|
logicalInterface{
|
||||||
|
name: "eth0",
|
||||||
|
config: configMethodManual{},
|
||||||
|
children: []InterfaceGenerator{vlan0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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{
|
||||||
@ -303,7 +373,7 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "bond0",
|
name: "bond0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{vlan1, bond1},
|
children: []InterfaceGenerator{bond1, vlan1},
|
||||||
},
|
},
|
||||||
[]string{"eth0"},
|
[]string{"eth0"},
|
||||||
}
|
}
|
||||||
@ -311,7 +381,7 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "eth0",
|
name: "eth0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{vlan0, bond0},
|
children: []InterfaceGenerator{bond0, vlan0},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1}
|
expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1}
|
||||||
|
Loading…
Reference in New Issue
Block a user