Merge branch 'upstream'
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
@@ -23,26 +22,18 @@ import (
|
||||
"github.com/vtolstov/cloudinit/datasource/metadata/digitalocean"
|
||||
)
|
||||
|
||||
func ProcessDigitalOceanNetconf(config []byte) ([]InterfaceGenerator, error) {
|
||||
func ProcessDigitalOceanNetconf(config digitalocean.Metadata) ([]InterfaceGenerator, error) {
|
||||
log.Println("Processing DigitalOcean network config")
|
||||
if len(config) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var cfg digitalocean.Metadata
|
||||
if err := json.Unmarshal(config, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Parsing nameservers")
|
||||
nameservers, err := parseNameservers(cfg.DNS)
|
||||
nameservers, err := parseNameservers(config.DNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("Parsed %d nameservers\n", len(nameservers))
|
||||
|
||||
log.Println("Parsing interfaces")
|
||||
generators, err := parseInterfaces(cfg.Interfaces, nameservers)
|
||||
generators, err := parseInterfaces(config.Interfaces, nameservers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,9 +43,9 @@ func ProcessDigitalOceanNetconf(config []byte) ([]InterfaceGenerator, error) {
|
||||
return generators, nil
|
||||
}
|
||||
|
||||
func parseNameservers(cfg digitalocean.DNS) ([]net.IP, error) {
|
||||
nameservers := make([]net.IP, 0, len(cfg.Nameservers))
|
||||
for _, ns := range cfg.Nameservers {
|
||||
func parseNameservers(config digitalocean.DNS) ([]net.IP, error) {
|
||||
nameservers := make([]net.IP, 0, len(config.Nameservers))
|
||||
for _, ns := range config.Nameservers {
|
||||
if ip := net.ParseIP(ns); ip == nil {
|
||||
return nil, fmt.Errorf("could not parse %q as nameserver IP address", ns)
|
||||
} else {
|
||||
@@ -64,16 +55,16 @@ func parseNameservers(cfg digitalocean.DNS) ([]net.IP, error) {
|
||||
return nameservers, nil
|
||||
}
|
||||
|
||||
func parseInterfaces(cfg digitalocean.Interfaces, nameservers []net.IP) ([]InterfaceGenerator, error) {
|
||||
generators := make([]InterfaceGenerator, 0, len(cfg.Public)+len(cfg.Private))
|
||||
for _, iface := range cfg.Public {
|
||||
func parseInterfaces(config digitalocean.Interfaces, nameservers []net.IP) ([]InterfaceGenerator, error) {
|
||||
generators := make([]InterfaceGenerator, 0, len(config.Public)+len(config.Private))
|
||||
for _, iface := range config.Public {
|
||||
if generator, err := parseInterface(iface, nameservers, true); err == nil {
|
||||
generators = append(generators, &physicalInterface{*generator})
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, iface := range cfg.Private {
|
||||
for _, iface := range config.Private {
|
||||
if generator, err := parseInterface(iface, []net.IP{}, false); err == nil {
|
||||
generators = append(generators, &physicalInterface{*generator})
|
||||
} else {
|
||||
@@ -135,6 +126,28 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute
|
||||
})
|
||||
}
|
||||
}
|
||||
if iface.AnchorIPv4 != nil {
|
||||
var ip, mask net.IP
|
||||
if ip = net.ParseIP(iface.AnchorIPv4.IPAddress); ip == nil {
|
||||
return nil, fmt.Errorf("could not parse %q as anchor IPv4 address", iface.AnchorIPv4.IPAddress)
|
||||
}
|
||||
if mask = net.ParseIP(iface.AnchorIPv4.Netmask); mask == nil {
|
||||
return nil, fmt.Errorf("could not parse %q as anchor IPv4 mask", iface.AnchorIPv4.Netmask)
|
||||
}
|
||||
addresses = append(addresses, net.IPNet{
|
||||
IP: ip,
|
||||
Mask: net.IPMask(mask),
|
||||
})
|
||||
|
||||
if useRoute {
|
||||
routes = append(routes, route{
|
||||
destination: net.IPNet{
|
||||
IP: net.IPv4zero,
|
||||
Mask: net.IPMask(net.IPv4zero),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
hwaddr, err := net.ParseMAC(iface.MAC)
|
||||
if err != nil {
|
||||
|
@@ -52,6 +52,14 @@ func TestParseNameservers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func mkInvalidMAC() error {
|
||||
if isGo15 {
|
||||
return &net.AddrError{Err: "invalid MAC address", Addr: "bad"}
|
||||
} else {
|
||||
return errors.New("invalid MAC address: bad")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseInterface(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
cfg digitalocean.Interface
|
||||
@@ -64,7 +72,7 @@ func TestParseInterface(t *testing.T) {
|
||||
cfg: digitalocean.Interface{
|
||||
MAC: "bad",
|
||||
},
|
||||
err: errors.New("invalid MAC address: bad"),
|
||||
err: mkInvalidMAC(),
|
||||
},
|
||||
{
|
||||
cfg: digitalocean.Interface{
|
||||
@@ -250,6 +258,70 @@ func TestParseInterface(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
cfg: digitalocean.Interface{
|
||||
MAC: "01:23:45:67:89:AB",
|
||||
AnchorIPv4: &digitalocean.Address{
|
||||
IPAddress: "bad",
|
||||
Netmask: "255.255.0.0",
|
||||
},
|
||||
},
|
||||
nss: []net.IP{},
|
||||
err: errors.New("could not parse \"bad\" as anchor IPv4 address"),
|
||||
},
|
||||
{
|
||||
cfg: digitalocean.Interface{
|
||||
MAC: "01:23:45:67:89:AB",
|
||||
AnchorIPv4: &digitalocean.Address{
|
||||
IPAddress: "1.2.3.4",
|
||||
Netmask: "bad",
|
||||
},
|
||||
},
|
||||
nss: []net.IP{},
|
||||
err: errors.New("could not parse \"bad\" as anchor IPv4 mask"),
|
||||
},
|
||||
{
|
||||
cfg: digitalocean.Interface{
|
||||
MAC: "01:23:45:67:89:AB",
|
||||
IPv4: &digitalocean.Address{
|
||||
IPAddress: "1.2.3.4",
|
||||
Netmask: "255.255.0.0",
|
||||
Gateway: "5.6.7.8",
|
||||
},
|
||||
AnchorIPv4: &digitalocean.Address{
|
||||
IPAddress: "7.8.9.10",
|
||||
Netmask: "255.255.0.0",
|
||||
},
|
||||
},
|
||||
useRoute: true,
|
||||
nss: []net.IP{},
|
||||
iface: &logicalInterface{
|
||||
hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}),
|
||||
config: configMethodStatic{
|
||||
addresses: []net.IPNet{
|
||||
{
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Mask: net.IPMask(net.ParseIP("255.255.0.0")),
|
||||
},
|
||||
{
|
||||
IP: net.ParseIP("7.8.9.10"),
|
||||
Mask: net.IPMask(net.ParseIP("255.255.0.0")),
|
||||
},
|
||||
},
|
||||
nameservers: []net.IP{},
|
||||
routes: []route{
|
||||
{
|
||||
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
|
||||
gateway: net.ParseIP("5.6.7.8"),
|
||||
},
|
||||
{
|
||||
destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
iface, err := parseInterface(tt.cfg, tt.nss, tt.useRoute)
|
||||
if !errorsEqual(tt.err, err) {
|
||||
@@ -337,13 +409,13 @@ func TestParseInterfaces(t *testing.T) {
|
||||
cfg: digitalocean.Interfaces{
|
||||
Public: []digitalocean.Interface{{MAC: "bad"}},
|
||||
},
|
||||
err: errors.New("invalid MAC address: bad"),
|
||||
err: mkInvalidMAC(),
|
||||
},
|
||||
{
|
||||
cfg: digitalocean.Interfaces{
|
||||
Private: []digitalocean.Interface{{MAC: "bad"}},
|
||||
},
|
||||
err: errors.New("invalid MAC address: bad"),
|
||||
err: mkInvalidMAC(),
|
||||
},
|
||||
} {
|
||||
ifaces, err := parseInterfaces(tt.cfg, tt.nss)
|
||||
@@ -358,27 +430,37 @@ func TestParseInterfaces(t *testing.T) {
|
||||
|
||||
func TestProcessDigitalOceanNetconf(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
cfg string
|
||||
cfg digitalocean.Metadata
|
||||
ifaces []InterfaceGenerator
|
||||
err error
|
||||
}{
|
||||
{
|
||||
cfg: ``,
|
||||
},
|
||||
{
|
||||
cfg: `{"dns":{"nameservers":["bad"]}}`,
|
||||
cfg: digitalocean.Metadata{
|
||||
DNS: digitalocean.DNS{
|
||||
Nameservers: []string{"bad"},
|
||||
},
|
||||
},
|
||||
err: errors.New("could not parse \"bad\" as nameserver IP address"),
|
||||
},
|
||||
{
|
||||
cfg: `{"interfaces":{"public":[{"ipv4":{"ip_address":"bad"}}]}}`,
|
||||
cfg: digitalocean.Metadata{
|
||||
Interfaces: digitalocean.Interfaces{
|
||||
Public: []digitalocean.Interface{
|
||||
digitalocean.Interface{
|
||||
IPv4: &digitalocean.Address{
|
||||
IPAddress: "bad",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
err: errors.New("could not parse \"bad\" as IPv4 address"),
|
||||
},
|
||||
{
|
||||
cfg: `{}`,
|
||||
ifaces: []InterfaceGenerator{},
|
||||
},
|
||||
} {
|
||||
ifaces, err := ProcessDigitalOceanNetconf([]byte(tt.cfg))
|
||||
ifaces, err := ProcessDigitalOceanNetconf(tt.cfg)
|
||||
if !errorsEqual(tt.err, err) {
|
||||
t.Fatalf("bad error (%q): want %q, got %q", tt.cfg, tt.err, err)
|
||||
}
|
||||
|
@@ -130,7 +130,17 @@ type bondInterface struct {
|
||||
}
|
||||
|
||||
func (b *bondInterface) Netdev() string {
|
||||
return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
|
||||
config := fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
|
||||
if b.hwaddr != nil {
|
||||
config += fmt.Sprintf("MACAddress=%s\n", b.hwaddr.String())
|
||||
}
|
||||
|
||||
config += fmt.Sprintf("\n[Bond]\n")
|
||||
for _, name := range sortedKeys(b.options) {
|
||||
config += fmt.Sprintf("%s=%s\n", name, b.options[name])
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
func (b *bondInterface) Type() string {
|
||||
|
@@ -52,7 +52,7 @@ func TestInterfaceGenerators(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "testname",
|
||||
netdev: "[NetDev]\nKind=bond\nName=testname\n",
|
||||
netdev: "[NetDev]\nKind=bond\nName=testname\n\n[Bond]\n",
|
||||
network: "[Match]\nName=testname\n\n[Network]\nBond=testbond1\nVLAN=testvlan1\nVLAN=testvlan2\nDHCP=true\n",
|
||||
kind: "bond",
|
||||
iface: &bondInterface{logicalInterface: logicalInterface{
|
||||
|
5
network/is_go15_false_test.go
Normal file
5
network/is_go15_false_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// +build !go1.5
|
||||
|
||||
package network
|
||||
|
||||
const isGo15 = false
|
5
network/is_go15_true_test.go
Normal file
5
network/is_go15_true_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// +build go1.5
|
||||
|
||||
package network
|
||||
|
||||
const isGo15 = true
|
127
network/packet.go
Normal file
127
network/packet.go
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/packet"
|
||||
)
|
||||
|
||||
func ProcessPacketNetconf(netdata packet.NetworkData) ([]InterfaceGenerator, error) {
|
||||
var nameservers []net.IP
|
||||
if netdata.DNS != nil {
|
||||
nameservers = netdata.DNS
|
||||
} else {
|
||||
nameservers = append(nameservers, net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4"))
|
||||
}
|
||||
|
||||
generators, err := parseNetwork(netdata, nameservers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return generators, nil
|
||||
}
|
||||
|
||||
func parseNetwork(netdata packet.NetworkData, nameservers []net.IP) ([]InterfaceGenerator, error) {
|
||||
var interfaces []InterfaceGenerator
|
||||
var addresses []net.IPNet
|
||||
var routes []route
|
||||
for _, netblock := range netdata.Netblocks {
|
||||
addresses = append(addresses, net.IPNet{
|
||||
IP: netblock.Address,
|
||||
Mask: net.IPMask(netblock.Netmask),
|
||||
})
|
||||
if netblock.Public == false {
|
||||
routes = append(routes, route{
|
||||
destination: net.IPNet{
|
||||
IP: net.IPv4(10, 0, 0, 0),
|
||||
Mask: net.IPv4Mask(255, 0, 0, 0),
|
||||
},
|
||||
gateway: netblock.Gateway,
|
||||
})
|
||||
} else {
|
||||
if netblock.AddressFamily == 4 {
|
||||
routes = append(routes, route{
|
||||
destination: net.IPNet{
|
||||
IP: net.IPv4zero,
|
||||
Mask: net.IPMask(net.IPv4zero),
|
||||
},
|
||||
gateway: netblock.Gateway,
|
||||
})
|
||||
} else {
|
||||
routes = append(routes, route{
|
||||
destination: net.IPNet{
|
||||
IP: net.IPv6zero,
|
||||
Mask: net.IPMask(net.IPv6zero),
|
||||
},
|
||||
gateway: netblock.Gateway,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bond := bondInterface{
|
||||
logicalInterface: logicalInterface{
|
||||
name: "bond0",
|
||||
config: configMethodStatic{
|
||||
addresses: addresses,
|
||||
nameservers: nameservers,
|
||||
routes: routes,
|
||||
},
|
||||
},
|
||||
options: map[string]string{
|
||||
"Mode": "802.3ad",
|
||||
"LACPTransmitRate": "fast",
|
||||
"MIIMonitorSec": ".2",
|
||||
"UpDelaySec": ".2",
|
||||
"DownDelaySec": ".2",
|
||||
},
|
||||
}
|
||||
|
||||
for _, iface := range netdata.Interfaces {
|
||||
if iface.Name != "chassis0" && iface.Name != "ipmi0" {
|
||||
bond.slaves = append(bond.slaves, iface.Name)
|
||||
if iface.Name == "enp1s0f0" {
|
||||
bond.hwaddr, _ = net.ParseMAC(iface.Mac)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, iface := range netdata.Interfaces {
|
||||
if iface.Name != "chassis0" && iface.Name != "ipmi0" {
|
||||
p := physicalInterface{
|
||||
logicalInterface: logicalInterface{
|
||||
name: iface.Name,
|
||||
config: configMethodStatic{
|
||||
nameservers: nameservers,
|
||||
},
|
||||
children: []networkInterface{&bond},
|
||||
},
|
||||
}
|
||||
|
||||
if iface.Name == "enp1s0f0" {
|
||||
p.configDepth = 20
|
||||
}
|
||||
|
||||
interfaces = append(interfaces, &p)
|
||||
}
|
||||
}
|
||||
|
||||
interfaces = append(interfaces, &bond)
|
||||
|
||||
return interfaces, nil
|
||||
}
|
174
network/vmware.go
Normal file
174
network/vmware.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
func ProcessVMwareNetconf(config map[string]string) ([]InterfaceGenerator, error) {
|
||||
log.Println("Processing VMware network config")
|
||||
|
||||
log.Println("Parsing nameservers")
|
||||
var nameservers []net.IP
|
||||
for i := 0; ; i++ {
|
||||
if ipStr, ok := config[fmt.Sprintf("dns.server.%d", i)]; ok {
|
||||
if ip := net.ParseIP(ipStr); ip != nil {
|
||||
nameservers = append(nameservers, ip)
|
||||
} else {
|
||||
return nil, fmt.Errorf("invalid nameserver: %q", ipStr)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Printf("Parsed %d nameservers", len(nameservers))
|
||||
|
||||
var interfaces []InterfaceGenerator
|
||||
for i := 0; ; i++ {
|
||||
var addresses []net.IPNet
|
||||
var routes []route
|
||||
var err error
|
||||
var dhcp bool
|
||||
iface := &physicalInterface{}
|
||||
|
||||
log.Printf("Proccessing interface %d", i)
|
||||
|
||||
log.Println("Processing DHCP")
|
||||
if dhcp, err = processDHCPConfig(config, fmt.Sprintf("interface.%d.", i)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Processing addresses")
|
||||
if as, err := processAddressConfig(config, fmt.Sprintf("interface.%d.", i)); err == nil {
|
||||
addresses = append(addresses, as...)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Processing routes")
|
||||
if rs, err := processRouteConfig(config, fmt.Sprintf("interface.%d.", i)); err == nil {
|
||||
routes = append(routes, rs...)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if mac, ok := config[fmt.Sprintf("interface.%d.mac", i)]; ok {
|
||||
log.Printf("Parsing interface %d MAC address: %q", i, mac)
|
||||
if hwaddr, err := net.ParseMAC(mac); err == nil {
|
||||
iface.hwaddr = hwaddr
|
||||
} else {
|
||||
return nil, fmt.Errorf("error while parsing MAC address: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if name, ok := config[fmt.Sprintf("interface.%d.name", i)]; ok {
|
||||
log.Printf("Parsing interface %d name: %q", i, name)
|
||||
iface.name = name
|
||||
}
|
||||
|
||||
if len(addresses) > 0 || len(routes) > 0 {
|
||||
iface.config = configMethodStatic{
|
||||
hwaddress: iface.hwaddr,
|
||||
addresses: addresses,
|
||||
nameservers: nameservers,
|
||||
routes: routes,
|
||||
}
|
||||
} else if dhcp {
|
||||
iface.config = configMethodDHCP{
|
||||
hwaddress: iface.hwaddr,
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
interfaces = append(interfaces, iface)
|
||||
}
|
||||
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
func processAddressConfig(config map[string]string, prefix string) (addresses []net.IPNet, err error) {
|
||||
for a := 0; ; a++ {
|
||||
prefix := fmt.Sprintf("%sip.%d.", prefix, a)
|
||||
|
||||
addressStr, ok := config[prefix+"address"]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
ip, network, err := net.ParseCIDR(addressStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid address: %q", addressStr)
|
||||
}
|
||||
addresses = append(addresses, net.IPNet{
|
||||
IP: ip,
|
||||
Mask: network.Mask,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func processRouteConfig(config map[string]string, prefix string) (routes []route, err error) {
|
||||
for r := 0; ; r++ {
|
||||
prefix := fmt.Sprintf("%sroute.%d.", prefix, r)
|
||||
|
||||
gatewayStr, gok := config[prefix+"gateway"]
|
||||
destinationStr, dok := config[prefix+"destination"]
|
||||
if gok && !dok {
|
||||
return nil, fmt.Errorf("missing destination key")
|
||||
} else if !gok && dok {
|
||||
return nil, fmt.Errorf("missing gateway key")
|
||||
} else if !gok && !dok {
|
||||
break
|
||||
}
|
||||
|
||||
gateway := net.ParseIP(gatewayStr)
|
||||
if gateway == nil {
|
||||
return nil, fmt.Errorf("invalid gateway: %q", gatewayStr)
|
||||
}
|
||||
|
||||
_, destination, err := net.ParseCIDR(destinationStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
routes = append(routes, route{
|
||||
destination: *destination,
|
||||
gateway: gateway,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func processDHCPConfig(config map[string]string, prefix string) (dhcp bool, err error) {
|
||||
dhcpStr, ok := config[prefix+"dhcp"]
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch dhcpStr {
|
||||
case "yes":
|
||||
return true, nil
|
||||
case "no":
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("invalid DHCP option: %q", dhcpStr)
|
||||
}
|
||||
}
|
361
network/vmware_test.go
Normal file
361
network/vmware_test.go
Normal file
@@ -0,0 +1,361 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mustParseMac(mac net.HardwareAddr, err error) net.HardwareAddr {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return mac
|
||||
}
|
||||
|
||||
func TestProcessVMwareNetconf(t *testing.T) {
|
||||
tests := []struct {
|
||||
config map[string]string
|
||||
|
||||
interfaces []InterfaceGenerator
|
||||
err error
|
||||
}{
|
||||
{},
|
||||
{
|
||||
config: map[string]string{
|
||||
"interface.0.dhcp": "yes",
|
||||
},
|
||||
interfaces: []InterfaceGenerator{
|
||||
&physicalInterface{logicalInterface{
|
||||
config: configMethodDHCP{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"interface.0.mac": "00:11:22:33:44:55",
|
||||
"interface.0.dhcp": "yes",
|
||||
},
|
||||
interfaces: []InterfaceGenerator{
|
||||
&physicalInterface{logicalInterface{
|
||||
hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")),
|
||||
config: configMethodDHCP{hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55"))},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"interface.0.name": "eth0",
|
||||
"interface.0.dhcp": "yes",
|
||||
},
|
||||
interfaces: []InterfaceGenerator{
|
||||
&physicalInterface{logicalInterface{
|
||||
name: "eth0",
|
||||
config: configMethodDHCP{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"interface.0.mac": "00:11:22:33:44:55",
|
||||
"interface.0.ip.0.address": "10.0.0.100/24",
|
||||
"interface.0.route.0.gateway": "10.0.0.1",
|
||||
"interface.0.route.0.destination": "0.0.0.0/0",
|
||||
},
|
||||
interfaces: []InterfaceGenerator{
|
||||
&physicalInterface{logicalInterface{
|
||||
hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")),
|
||||
config: configMethodStatic{
|
||||
hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")),
|
||||
addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}},
|
||||
// I realize how upset you must be that I am shoving an IPMask into an IP. This is because net.IPv4zero is
|
||||
// actually a magic IPv6 address which ruins our equality check. What's that? Just use IP::Equal()? I'd rather
|
||||
// DeepEqual just handle that for me, but until Go gets operator overloading, we are stuck with this.
|
||||
routes: []route{route{
|
||||
destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)},
|
||||
gateway: net.ParseIP("10.0.0.1")},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"dns.server.0": "1.2.3.4",
|
||||
"dns.server.1": "5.6.7.8",
|
||||
"interface.0.mac": "00:11:22:33:44:55",
|
||||
"interface.0.ip.0.address": "10.0.0.100/24",
|
||||
"interface.0.ip.1.address": "10.0.0.101/24",
|
||||
"interface.0.route.0.gateway": "10.0.0.1",
|
||||
"interface.0.route.0.destination": "0.0.0.0/0",
|
||||
"interface.1.name": "eth0",
|
||||
"interface.1.ip.0.address": "10.0.1.100/24",
|
||||
"interface.1.route.0.gateway": "10.0.1.1",
|
||||
"interface.1.route.0.destination": "0.0.0.0/0",
|
||||
"interface.2.dhcp": "yes",
|
||||
"interface.2.mac": "00:11:22:33:44:77",
|
||||
},
|
||||
interfaces: []InterfaceGenerator{
|
||||
&physicalInterface{logicalInterface{
|
||||
hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")),
|
||||
config: configMethodStatic{
|
||||
hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")),
|
||||
addresses: []net.IPNet{
|
||||
net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)},
|
||||
net.IPNet{IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)},
|
||||
},
|
||||
routes: []route{route{
|
||||
destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)},
|
||||
gateway: net.ParseIP("10.0.0.1")},
|
||||
},
|
||||
nameservers: []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("5.6.7.8")},
|
||||
},
|
||||
}},
|
||||
&physicalInterface{logicalInterface{
|
||||
name: "eth0",
|
||||
config: configMethodStatic{
|
||||
addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.1.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}},
|
||||
routes: []route{route{
|
||||
destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)},
|
||||
gateway: net.ParseIP("10.0.1.1")},
|
||||
},
|
||||
nameservers: []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("5.6.7.8")},
|
||||
},
|
||||
}},
|
||||
&physicalInterface{logicalInterface{
|
||||
hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:77")),
|
||||
config: configMethodDHCP{hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:77"))},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
config: map[string]string{"dns.server.0": "test dns"},
|
||||
err: errors.New(`invalid nameserver: "test dns"`),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
interfaces, err := ProcessVMwareNetconf(tt.config)
|
||||
if !reflect.DeepEqual(tt.err, err) {
|
||||
t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.interfaces, interfaces) {
|
||||
t.Errorf("bad interfaces (#%d): want %#v, got %#v", i, tt.interfaces, interfaces)
|
||||
for _, iface := range tt.interfaces {
|
||||
t.Logf(" want: %#v", iface)
|
||||
}
|
||||
for _, iface := range interfaces {
|
||||
t.Logf(" got: %#v", iface)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessAddressConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
config map[string]string
|
||||
prefix string
|
||||
|
||||
addresses []net.IPNet
|
||||
err error
|
||||
}{
|
||||
{},
|
||||
|
||||
// static - ipv4
|
||||
{
|
||||
config: map[string]string{
|
||||
"ip.0.address": "10.0.0.100/24",
|
||||
},
|
||||
|
||||
addresses: []net.IPNet{{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"this.is.a.prefix.ip.0.address": "10.0.0.100/24",
|
||||
},
|
||||
prefix: "this.is.a.prefix.",
|
||||
|
||||
addresses: []net.IPNet{{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"ip.0.address": "10.0.0.100/24",
|
||||
"ip.1.address": "10.0.0.101/24",
|
||||
"ip.2.address": "10.0.0.102/24",
|
||||
},
|
||||
|
||||
addresses: []net.IPNet{
|
||||
{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)},
|
||||
{IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)},
|
||||
{IP: net.ParseIP("10.0.0.102"), Mask: net.CIDRMask(24, net.IPv4len*8)},
|
||||
},
|
||||
},
|
||||
|
||||
// static - ipv6
|
||||
{
|
||||
config: map[string]string{
|
||||
"ip.0.address": "fe00::100/64",
|
||||
},
|
||||
|
||||
addresses: []net.IPNet{{IP: net.ParseIP("fe00::100"), Mask: net.IPMask(net.CIDRMask(64, net.IPv6len*8))}},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"ip.0.address": "fe00::100/64",
|
||||
"ip.1.address": "fe00::101/64",
|
||||
"ip.2.address": "fe00::102/64",
|
||||
},
|
||||
|
||||
addresses: []net.IPNet{
|
||||
{IP: net.ParseIP("fe00::100"), Mask: net.CIDRMask(64, net.IPv6len*8)},
|
||||
{IP: net.ParseIP("fe00::101"), Mask: net.CIDRMask(64, net.IPv6len*8)},
|
||||
{IP: net.ParseIP("fe00::102"), Mask: net.CIDRMask(64, net.IPv6len*8)},
|
||||
},
|
||||
},
|
||||
|
||||
// invalid
|
||||
{
|
||||
config: map[string]string{
|
||||
"ip.0.address": "test address",
|
||||
},
|
||||
|
||||
err: errors.New(`invalid address: "test address"`),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
addresses, err := processAddressConfig(tt.config, tt.prefix)
|
||||
if !reflect.DeepEqual(tt.err, err) {
|
||||
t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.addresses, addresses) {
|
||||
t.Errorf("bad addresses (#%d): want %#v, got %#v", i, tt.addresses, addresses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessRouteConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
config map[string]string
|
||||
prefix string
|
||||
|
||||
routes []route
|
||||
err error
|
||||
}{
|
||||
{},
|
||||
|
||||
{
|
||||
config: map[string]string{
|
||||
"route.0.gateway": "10.0.0.1",
|
||||
"route.0.destination": "0.0.0.0/0",
|
||||
},
|
||||
|
||||
routes: []route{{destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"this.is.a.prefix.route.0.gateway": "10.0.0.1",
|
||||
"this.is.a.prefix.route.0.destination": "0.0.0.0/0",
|
||||
},
|
||||
prefix: "this.is.a.prefix.",
|
||||
|
||||
routes: []route{{destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}},
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"route.0.gateway": "fe00::1",
|
||||
"route.0.destination": "::/0",
|
||||
},
|
||||
|
||||
routes: []route{{destination: net.IPNet{IP: net.IPv6zero, Mask: net.IPMask(net.IPv6zero)}, gateway: net.ParseIP("fe00::1")}},
|
||||
},
|
||||
|
||||
// invalid
|
||||
{
|
||||
config: map[string]string{
|
||||
"route.0.gateway": "test gateway",
|
||||
"route.0.destination": "0.0.0.0/0",
|
||||
},
|
||||
|
||||
err: errors.New(`invalid gateway: "test gateway"`),
|
||||
},
|
||||
{
|
||||
config: map[string]string{
|
||||
"route.0.gateway": "10.0.0.1",
|
||||
"route.0.destination": "test destination",
|
||||
},
|
||||
|
||||
err: &net.ParseError{Type: "CIDR address", Text: "test destination"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
routes, err := processRouteConfig(tt.config, tt.prefix)
|
||||
if !reflect.DeepEqual(tt.err, err) {
|
||||
t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.routes, routes) {
|
||||
t.Errorf("bad routes (#%d): want %#v, got %#v", i, tt.routes, routes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessDHCPConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
config map[string]string
|
||||
prefix string
|
||||
|
||||
dhcp bool
|
||||
err error
|
||||
}{
|
||||
{},
|
||||
|
||||
// prefix
|
||||
{config: map[string]string{"this.is.a.prefix.mac": ""}, prefix: "this.is.a.prefix.", dhcp: false},
|
||||
{config: map[string]string{"this.is.a.prefix.dhcp": "yes"}, prefix: "this.is.a.prefix.", dhcp: true},
|
||||
|
||||
// dhcp
|
||||
{config: map[string]string{"dhcp": "yes"}, dhcp: true},
|
||||
{config: map[string]string{"dhcp": "no"}, dhcp: false},
|
||||
|
||||
// invalid
|
||||
{config: map[string]string{"dhcp": "blah"}, err: errors.New(`invalid DHCP option: "blah"`)},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
dhcp, err := processDHCPConfig(tt.config, tt.prefix)
|
||||
if !reflect.DeepEqual(tt.err, err) {
|
||||
t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err)
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if tt.dhcp != dhcp {
|
||||
t.Errorf("bad dhcp (#%d): want %v, got %v", i, tt.dhcp, dhcp)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user