Added parser for VMware Fusion's networking file. Replaced VmwareDriver's NetmapConfPath with a NetworkMapperInterface in order to handle the differences between VMware Fusion and the rest of the VMware suite.
This commit is contained in:
parent
069d00f70b
commit
b2fec18b1e
|
@ -274,7 +274,10 @@ type VmwareDriver struct {
|
||||||
DhcpLeasesPath func(string) string
|
DhcpLeasesPath func(string) string
|
||||||
DhcpConfPath func(string) string
|
DhcpConfPath func(string) string
|
||||||
VmnetnatConfPath func(string) string
|
VmnetnatConfPath func(string) string
|
||||||
NetmapConfPath func() string
|
|
||||||
|
/// This method returns an object with the NetworkNameMapper interface
|
||||||
|
/// that maps network to device and vice-versa.
|
||||||
|
NetworkMapper func() (NetworkNameMapper, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *VmwareDriver) GuestAddress(state multistep.StateBag) (string, error) {
|
func (d *VmwareDriver) GuestAddress(state multistep.StateBag) (string, error) {
|
||||||
|
@ -304,12 +307,8 @@ func (d *VmwareDriver) GuestAddress(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
func (d *VmwareDriver) GuestIP(state multistep.StateBag) (string, error) {
|
func (d *VmwareDriver) GuestIP(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
// read netmap config
|
// grab network mapper
|
||||||
pathNetmap := d.NetmapConfPath()
|
netmap, err := d.NetworkMapper()
|
||||||
if _, err := os.Stat(pathNetmap); err != nil {
|
|
||||||
return "", fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
|
||||||
}
|
|
||||||
netmap, err := ReadNetmapConfig(pathNetmap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -401,12 +400,8 @@ func (d *VmwareDriver) GuestIP(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
|
func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
// parse network<->device mapping
|
// grab mapper for converting network<->device
|
||||||
pathNetmap := d.NetmapConfPath()
|
netmap, err := d.NetworkMapper()
|
||||||
if _, err := os.Stat(pathNetmap); err != nil {
|
|
||||||
return "", fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
|
||||||
}
|
|
||||||
netmap, err := ReadNetmapConfig(pathNetmap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -471,12 +466,8 @@ func (d *VmwareDriver) HostAddress(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
|
func (d *VmwareDriver) HostIP(state multistep.StateBag) (string, error) {
|
||||||
|
|
||||||
// parse network<->device mapping
|
// grab mapper for converting network<->device
|
||||||
pathNetmap := d.NetmapConfPath()
|
netmap, err := d.NetworkMapper()
|
||||||
if _, err := os.Stat(pathNetmap); err != nil {
|
|
||||||
return "", fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
|
||||||
}
|
|
||||||
netmap, err := ReadNetmapConfig(pathNetmap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,9 +152,19 @@ func (d *Fusion5Driver) Verify() error {
|
||||||
d.VmwareDriver.VmnetnatConfPath = func(device string) string {
|
d.VmwareDriver.VmnetnatConfPath = func(device string) string {
|
||||||
return filepath.Join(libpath, device, "nat.conf")
|
return filepath.Join(libpath, device, "nat.conf")
|
||||||
}
|
}
|
||||||
d.VmwareDriver.NetmapConfPath = func() string {
|
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
|
||||||
// FIXME: Suggested by @phekmat. This will need another parser to be implemented.
|
pathNetworking := filepath.Join(libpath, "networking")
|
||||||
return filepath.Join(libpath, "networking")
|
if _, err := os.Stat(pathNetworking); err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not find networking conf file: %s", pathNetworking)
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := os.Open(pathNetworking)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
return ReadNetworkingConfig(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -78,9 +78,19 @@ func (d *Fusion6Driver) Verify() error {
|
||||||
d.VmwareDriver.VmnetnatConfPath = func(device string) string {
|
d.VmwareDriver.VmnetnatConfPath = func(device string) string {
|
||||||
return filepath.Join(libpath, device, "nat.conf")
|
return filepath.Join(libpath, device, "nat.conf")
|
||||||
}
|
}
|
||||||
d.VmwareDriver.NetmapConfPath = func() string {
|
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
|
||||||
// FIXME: Suggested by @phekmat. This will need another parser to be implemented.
|
pathNetworking := filepath.Join(libpath, "networking")
|
||||||
return filepath.Join(libpath, "networking")
|
if _, err := os.Stat(pathNetworking); err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not find networking conf file: %s", pathNetworking)
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := os.Open(pathNetworking)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
return ReadNetworkingConfig(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return compareVersions(matches[1], VMWARE_FUSION_VERSION, "Fusion Professional")
|
return compareVersions(matches[1], VMWARE_FUSION_VERSION, "Fusion Professional")
|
||||||
|
|
|
@ -92,6 +92,20 @@ type DriverMock struct {
|
||||||
VerifyErr error
|
VerifyErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NetworkMapperMock struct {
|
||||||
|
NameIntoDeviceCalled int
|
||||||
|
DeviceIntoNameCalled int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m NetworkMapperMock) NameIntoDevice(name string) (string, error) {
|
||||||
|
m.NameIntoDeviceCalled += 1
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
func (m NetworkMapperMock) DeviceIntoName(device string) (string, error) {
|
||||||
|
m.DeviceIntoNameCalled += 1
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DriverMock) Clone(dst string, src string) error {
|
func (d *DriverMock) Clone(dst string, src string) error {
|
||||||
d.CloneCalled = true
|
d.CloneCalled = true
|
||||||
d.CloneDst = dst
|
d.CloneDst = dst
|
||||||
|
@ -247,8 +261,8 @@ func (d *DriverMock) GetVmwareDriver() VmwareDriver {
|
||||||
state.VmnetnatConfPath = func(string) string {
|
state.VmnetnatConfPath = func(string) string {
|
||||||
return "/path/to/vmnetnat.conf"
|
return "/path/to/vmnetnat.conf"
|
||||||
}
|
}
|
||||||
state.NetmapConfPath = func() string {
|
state.NetworkMapper = func() (NetworkNameMapper, error) {
|
||||||
return "/path/to/netmap.conf"
|
return NetworkMapperMock{}, nil
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,11 @@ package common
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -1053,6 +1056,11 @@ func (e *DhcpConfiguration) HostByName(host string) (configDeclaration, error) {
|
||||||
/*** Network Map */
|
/*** Network Map */
|
||||||
type NetworkMap []map[string]string
|
type NetworkMap []map[string]string
|
||||||
|
|
||||||
|
type NetworkNameMapper interface {
|
||||||
|
NameIntoDevice(string) (string, error)
|
||||||
|
DeviceIntoName(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
func ReadNetworkMap(fd *os.File) (NetworkMap, error) {
|
func ReadNetworkMap(fd *os.File) (NetworkMap, error) {
|
||||||
|
|
||||||
fromfile, eof := consumeFile(fd)
|
fromfile, eof := consumeFile(fd)
|
||||||
|
@ -1066,16 +1074,16 @@ func ReadNetworkMap(fd *os.File) (NetworkMap, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *NetworkMap) NameIntoDevice(name string) (string, error) {
|
func (e NetworkMap) NameIntoDevice(name string) (string, error) {
|
||||||
for _, val := range *e {
|
for _, val := range e {
|
||||||
if strings.ToLower(val["name"]) == strings.ToLower(name) {
|
if strings.ToLower(val["name"]) == strings.ToLower(name) {
|
||||||
return val["device"], nil
|
return val["device"], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("Network name not found : %v", name)
|
return "", fmt.Errorf("Network name not found : %v", name)
|
||||||
}
|
}
|
||||||
func (e *NetworkMap) DeviceIntoName(device string) (string, error) {
|
func (e NetworkMap) DeviceIntoName(device string) (string, error) {
|
||||||
for _, val := range *e {
|
for _, val := range e {
|
||||||
if strings.ToLower(val["device"]) == strings.ToLower(device) {
|
if strings.ToLower(val["device"]) == strings.ToLower(device) {
|
||||||
return val["name"], nil
|
return val["name"], nil
|
||||||
}
|
}
|
||||||
|
@ -1091,7 +1099,836 @@ func (e *NetworkMap) repr() string {
|
||||||
return strings.Join(result, "\n")
|
return strings.Join(result, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** main */
|
/*** parser for VMware Fusion's networking file */
|
||||||
|
func tokenizeNetworkingConfig(eof sentinelSignaller, in chan byte) chan string {
|
||||||
|
var ch byte
|
||||||
|
var state string
|
||||||
|
var repeat_newline bool
|
||||||
|
|
||||||
|
out := make(chan string)
|
||||||
|
go func(out chan string) {
|
||||||
|
for reading := true; reading; {
|
||||||
|
select {
|
||||||
|
case <-eof:
|
||||||
|
reading = false
|
||||||
|
|
||||||
|
case ch = <-in:
|
||||||
|
switch ch {
|
||||||
|
case '\r':
|
||||||
|
fallthrough
|
||||||
|
case '\t':
|
||||||
|
fallthrough
|
||||||
|
case ' ':
|
||||||
|
if len(state) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out <- state
|
||||||
|
state = ""
|
||||||
|
case '\n':
|
||||||
|
if repeat_newline {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(state) > 0 {
|
||||||
|
out <- state
|
||||||
|
}
|
||||||
|
out <- string(ch)
|
||||||
|
state = ""
|
||||||
|
repeat_newline = true
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
state += string(ch)
|
||||||
|
}
|
||||||
|
repeat_newline = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(state) > 0 {
|
||||||
|
out <- state
|
||||||
|
}
|
||||||
|
}(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitNetworkingConfig(eof sentinelSignaller, in chan string) chan []string {
|
||||||
|
var out chan []string
|
||||||
|
|
||||||
|
out = make(chan []string)
|
||||||
|
go func(out chan []string) {
|
||||||
|
row := make([]string, 0)
|
||||||
|
for reading := true; reading; {
|
||||||
|
select {
|
||||||
|
case <-eof:
|
||||||
|
reading = false
|
||||||
|
|
||||||
|
case tk := <-in:
|
||||||
|
switch tk {
|
||||||
|
case "\n":
|
||||||
|
if len(row) > 0 {
|
||||||
|
out <- row
|
||||||
|
}
|
||||||
|
row = make([]string, 0)
|
||||||
|
default:
|
||||||
|
row = append(row, tk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(row) > 0 {
|
||||||
|
out <- row
|
||||||
|
}
|
||||||
|
}(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All token types in networking file.
|
||||||
|
// VERSION token
|
||||||
|
type networkingVERSION struct {
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func networkingReadVersion(row []string) (*networkingVERSION, error) {
|
||||||
|
if len(row) != 1 {
|
||||||
|
return nil, fmt.Errorf("Unexpected format for VERSION entry : %v", row)
|
||||||
|
}
|
||||||
|
res := &networkingVERSION{value: row[0]}
|
||||||
|
if !res.Valid() {
|
||||||
|
return nil, fmt.Errorf("Unexpected format for VERSION entry : %v", row)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVERSION) Repr() string {
|
||||||
|
if !s.Valid() {
|
||||||
|
return fmt.Sprintf("VERSION{INVALID=\"%v\"}", s.value)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("VERSION{%f}", s.Number())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVERSION) Valid() bool {
|
||||||
|
tokens := strings.SplitN(s.value, "=", 2)
|
||||||
|
if len(tokens) != 2 || tokens[0] != "VERSION" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens = strings.Split(tokens[1], ",")
|
||||||
|
if len(tokens) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range tokens {
|
||||||
|
_, err := strconv.ParseUint(t, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVERSION) Number() float64 {
|
||||||
|
var result float64
|
||||||
|
tokens := strings.SplitN(s.value, "=", 2)
|
||||||
|
tokens = strings.Split(tokens[1], ",")
|
||||||
|
|
||||||
|
integer, err := strconv.ParseUint(tokens[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
integer = 0
|
||||||
|
}
|
||||||
|
result = float64(integer)
|
||||||
|
|
||||||
|
mantissa, err := strconv.ParseUint(tokens[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
denomination := math.Pow(10.0, float64(len(tokens[1])))
|
||||||
|
return result + (float64(mantissa) / denomination)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VNET_X token
|
||||||
|
type networkingVNET struct {
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVNET) Valid() bool {
|
||||||
|
if strings.ToUpper(s.value) != s.value {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tokens := strings.SplitN(s.value, "_", 3)
|
||||||
|
if len(tokens) != 3 || tokens[0] != "VNET" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err := strconv.ParseUint(tokens[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVNET) Number() int {
|
||||||
|
tokens := strings.SplitN(s.value, "_", 3)
|
||||||
|
res, err := strconv.Atoi(tokens[1])
|
||||||
|
if err != nil {
|
||||||
|
return ^int(0)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVNET) Option() string {
|
||||||
|
tokens := strings.SplitN(s.value, "_", 3)
|
||||||
|
if len(tokens) == 3 {
|
||||||
|
return tokens[2]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingVNET) Repr() string {
|
||||||
|
if !s.Valid() {
|
||||||
|
tokens := strings.SplitN(s.value, "_", 3)
|
||||||
|
return fmt.Sprintf("VNET{INVALID=%v}", tokens)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("VNET{%d} %s", s.Number(), s.Option())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface name
|
||||||
|
type networkingInterface struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s networkingInterface) Interface() (*net.Interface, error) {
|
||||||
|
return net.InterfaceByName(s.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// networking command entry types
|
||||||
|
type networkingCommandEntry_answer struct {
|
||||||
|
vnet networkingVNET
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_remove_answer struct {
|
||||||
|
vnet networkingVNET
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_add_nat_portfwd struct {
|
||||||
|
vnet int
|
||||||
|
protocol string
|
||||||
|
port int
|
||||||
|
target_host net.IP
|
||||||
|
target_port int
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_remove_nat_portfwd struct {
|
||||||
|
vnet int
|
||||||
|
protocol string
|
||||||
|
port int
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_add_dhcp_mac_to_ip struct {
|
||||||
|
vnet int
|
||||||
|
mac net.HardwareAddr
|
||||||
|
ip net.IP
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_remove_dhcp_mac_to_ip struct {
|
||||||
|
vnet int
|
||||||
|
mac net.HardwareAddr
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_add_bridge_mapping struct {
|
||||||
|
intf networkingInterface
|
||||||
|
vnet int
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_remove_bridge_mapping struct {
|
||||||
|
intf networkingInterface
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_add_nat_prefix struct {
|
||||||
|
vnet int
|
||||||
|
prefix int
|
||||||
|
}
|
||||||
|
type networkingCommandEntry_remove_nat_prefix struct {
|
||||||
|
vnet int
|
||||||
|
prefix int
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkingCommandEntry struct {
|
||||||
|
entry interface{}
|
||||||
|
answer *networkingCommandEntry_answer
|
||||||
|
remove_answer *networkingCommandEntry_remove_answer
|
||||||
|
add_nat_portfwd *networkingCommandEntry_add_nat_portfwd
|
||||||
|
remove_nat_portfwd *networkingCommandEntry_remove_nat_portfwd
|
||||||
|
add_dhcp_mac_to_ip *networkingCommandEntry_add_dhcp_mac_to_ip
|
||||||
|
remove_dhcp_mac_to_ip *networkingCommandEntry_remove_dhcp_mac_to_ip
|
||||||
|
add_bridge_mapping *networkingCommandEntry_add_bridge_mapping
|
||||||
|
remove_bridge_mapping *networkingCommandEntry_remove_bridge_mapping
|
||||||
|
add_nat_prefix *networkingCommandEntry_add_nat_prefix
|
||||||
|
remove_nat_prefix *networkingCommandEntry_remove_nat_prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e networkingCommandEntry) Name() string {
|
||||||
|
switch e.entry.(type) {
|
||||||
|
case networkingCommandEntry_answer:
|
||||||
|
return "answer"
|
||||||
|
case networkingCommandEntry_remove_answer:
|
||||||
|
return "remove_answer"
|
||||||
|
case networkingCommandEntry_add_nat_portfwd:
|
||||||
|
return "add_nat_portfwd"
|
||||||
|
case networkingCommandEntry_remove_nat_portfwd:
|
||||||
|
return "remove_nat_portfwd"
|
||||||
|
case networkingCommandEntry_add_dhcp_mac_to_ip:
|
||||||
|
return "add_dhcp_mac_to_ip"
|
||||||
|
case networkingCommandEntry_remove_dhcp_mac_to_ip:
|
||||||
|
return "remove_dhcp_mac_to_ip"
|
||||||
|
case networkingCommandEntry_add_bridge_mapping:
|
||||||
|
return "add_bridge_mapping"
|
||||||
|
case networkingCommandEntry_remove_bridge_mapping:
|
||||||
|
return "remove_bridge_mapping"
|
||||||
|
case networkingCommandEntry_add_nat_prefix:
|
||||||
|
return "add_nat_prefix"
|
||||||
|
case networkingCommandEntry_remove_nat_prefix:
|
||||||
|
return "remove_nat_prefix"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e networkingCommandEntry) Entry() reflect.Value {
|
||||||
|
this := reflect.ValueOf(e)
|
||||||
|
switch e.entry.(type) {
|
||||||
|
case networkingCommandEntry_answer:
|
||||||
|
return reflect.Indirect(this.FieldByName("answer"))
|
||||||
|
case networkingCommandEntry_remove_answer:
|
||||||
|
return reflect.Indirect(this.FieldByName("remove_answer"))
|
||||||
|
case networkingCommandEntry_add_nat_portfwd:
|
||||||
|
return reflect.Indirect(this.FieldByName("add_nat_portfwd"))
|
||||||
|
case networkingCommandEntry_remove_nat_portfwd:
|
||||||
|
return reflect.Indirect(this.FieldByName("remove_nat_portfwd"))
|
||||||
|
case networkingCommandEntry_add_dhcp_mac_to_ip:
|
||||||
|
return reflect.Indirect(this.FieldByName("add_dhcp_mac_to_ip"))
|
||||||
|
case networkingCommandEntry_remove_dhcp_mac_to_ip:
|
||||||
|
return reflect.Indirect(this.FieldByName("remove_dhcp_mac_to_ip"))
|
||||||
|
case networkingCommandEntry_add_bridge_mapping:
|
||||||
|
return reflect.Indirect(this.FieldByName("add_bridge_mapping"))
|
||||||
|
case networkingCommandEntry_remove_bridge_mapping:
|
||||||
|
return reflect.Indirect(this.FieldByName("remove_bridge_mapping"))
|
||||||
|
case networkingCommandEntry_add_nat_prefix:
|
||||||
|
return reflect.Indirect(this.FieldByName("add_nat_prefix"))
|
||||||
|
case networkingCommandEntry_remove_nat_prefix:
|
||||||
|
return reflect.Indirect(this.FieldByName("remove_nat_prefix"))
|
||||||
|
}
|
||||||
|
return reflect.Value{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e networkingCommandEntry) Repr() string {
|
||||||
|
var result map[string]interface{}
|
||||||
|
result = make(map[string]interface{})
|
||||||
|
|
||||||
|
entryN, entry := e.Name(), e.Entry()
|
||||||
|
entryT := entry.Type()
|
||||||
|
for i := 0; i < entry.NumField(); i++ {
|
||||||
|
fld, fldT := entry.Field(i), entryT.Field(i)
|
||||||
|
result[fldT.Name] = fld
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s -> %v", entryN, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// networking command entry parsers
|
||||||
|
func parseNetworkingCommand_answer(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 2 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
|
||||||
|
}
|
||||||
|
vnet := networkingVNET{value: row[0]}
|
||||||
|
if !vnet.Valid() {
|
||||||
|
return nil, fmt.Errorf("Invalid format for VNET.")
|
||||||
|
}
|
||||||
|
value := row[1]
|
||||||
|
|
||||||
|
result := networkingCommandEntry_answer{vnet: vnet, value: value}
|
||||||
|
return &networkingCommandEntry{entry: result, answer: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_remove_answer(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 1 {
|
||||||
|
return nil, fmt.Errorf("Expected %d argument. Received %d.", 1, len(row))
|
||||||
|
}
|
||||||
|
vnet := networkingVNET{value: row[0]}
|
||||||
|
if !vnet.Valid() {
|
||||||
|
return nil, fmt.Errorf("Invalid format for VNET.")
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_remove_answer{vnet: vnet}
|
||||||
|
return &networkingCommandEntry{entry: result, remove_answer: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_add_nat_portfwd(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 5 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 5, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol := strings.ToLower(row[1])
|
||||||
|
if !(protocol == "tcp" || protocol == "udp") {
|
||||||
|
return nil, fmt.Errorf("Expected \"tcp\" or \"udp\" for second argument. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
sport, err := strconv.Atoi(row[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse third argument as an integer. : %v", row[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
dest := net.ParseIP(row[3])
|
||||||
|
if dest == nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse fourth argument as an IPv4 address. : %v", row[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
dport, err := strconv.Atoi(row[4])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse fifth argument as an integer. : %v", row[4])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_add_nat_portfwd{vnet: vnet - 1, protocol: protocol, port: sport, target_host: dest, target_port: dport}
|
||||||
|
return &networkingCommandEntry{entry: result, add_nat_portfwd: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_remove_nat_portfwd(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 3 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 3, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol := strings.ToLower(row[1])
|
||||||
|
if !(protocol == "tcp" || protocol == "udp") {
|
||||||
|
return nil, fmt.Errorf("Expected \"tcp\" or \"udp\" for second argument. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
sport, err := strconv.Atoi(row[2])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse third argument as an integer. : %v", row[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_remove_nat_portfwd{vnet: vnet - 1, protocol: protocol, port: sport}
|
||||||
|
return &networkingCommandEntry{entry: result, remove_nat_portfwd: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_add_dhcp_mac_to_ip(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 3 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 3, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
mac, err := net.ParseMAC(row[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse second argument as hwaddr. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
ip := net.ParseIP(row[2])
|
||||||
|
if ip != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse third argument as ipv4. : %v", row[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_add_dhcp_mac_to_ip{vnet: vnet - 1, mac: mac, ip: ip}
|
||||||
|
return &networkingCommandEntry{entry: result, add_dhcp_mac_to_ip: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_remove_dhcp_mac_to_ip(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 2 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
mac, err := net.ParseMAC(row[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse second argument as hwaddr. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_remove_dhcp_mac_to_ip{vnet: vnet - 1, mac: mac}
|
||||||
|
return &networkingCommandEntry{entry: result, remove_dhcp_mac_to_ip: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_add_bridge_mapping(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 2 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
|
||||||
|
}
|
||||||
|
intf := networkingInterface{name: row[0]}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse second argument as an integer. : %v", row[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_add_bridge_mapping{intf: intf, vnet: vnet - 1}
|
||||||
|
return &networkingCommandEntry{entry: result, add_bridge_mapping: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_remove_bridge_mapping(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 1 {
|
||||||
|
return nil, fmt.Errorf("Expected %d argument. Received %d.", 1, len(row))
|
||||||
|
}
|
||||||
|
intf := networkingInterface{name: row[0]}
|
||||||
|
/*
|
||||||
|
number, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
result := networkingCommandEntry_remove_bridge_mapping{intf: intf}
|
||||||
|
return &networkingCommandEntry{entry: result, remove_bridge_mapping: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_add_nat_prefix(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 2 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(row[1], "/") {
|
||||||
|
return nil, fmt.Errorf("Expected second argument to begin with \"/\". : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, err := strconv.Atoi(row[1][1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse prefix out of second argument. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_add_nat_prefix{vnet: vnet - 1, prefix: prefix}
|
||||||
|
return &networkingCommandEntry{entry: result, add_nat_prefix: &result}, nil
|
||||||
|
}
|
||||||
|
func parseNetworkingCommand_remove_nat_prefix(row []string) (*networkingCommandEntry, error) {
|
||||||
|
if len(row) != 2 {
|
||||||
|
return nil, fmt.Errorf("Expected %d arguments. Received only %d.", 2, len(row))
|
||||||
|
}
|
||||||
|
|
||||||
|
vnet, err := strconv.Atoi(row[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse first argument as an integer. : %v", row[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(row[1], "/") {
|
||||||
|
return nil, fmt.Errorf("Expected second argument to begin with \"/\". : %v", row[1])
|
||||||
|
}
|
||||||
|
prefix, err := strconv.Atoi(row[1][1:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to parse prefix out of second argument. : %v", row[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
result := networkingCommandEntry_remove_nat_prefix{vnet: vnet - 1, prefix: prefix}
|
||||||
|
return &networkingCommandEntry{entry: result, remove_nat_prefix: &result}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkingCommandParser struct {
|
||||||
|
command string
|
||||||
|
callback func([]string) (*networkingCommandEntry, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var NetworkingCommandParsers = []networkingCommandParser{
|
||||||
|
/* DictRecordParseFunct */ {command: "answer", callback: parseNetworkingCommand_answer},
|
||||||
|
/* DictRecordParseFunct */ {command: "remove_answer", callback: parseNetworkingCommand_remove_answer},
|
||||||
|
/* NatFwdRecordParseFunct */ {command: "add_nat_portfwd", callback: parseNetworkingCommand_add_nat_portfwd},
|
||||||
|
/* NatFwdRecordParseFunct */ {command: "remove_nat_portfwd", callback: parseNetworkingCommand_remove_nat_portfwd},
|
||||||
|
/* DhcpMacRecordParseFunct */ {command: "add_dhcp_mac_to_ip", callback: parseNetworkingCommand_add_dhcp_mac_to_ip},
|
||||||
|
/* DhcpMacRecordParseFunct */ {command: "remove_dhcp_mac_to_ip", callback: parseNetworkingCommand_remove_dhcp_mac_to_ip},
|
||||||
|
/* BridgeMappingRecordParseFunct */ {command: "add_bridge_mapping", callback: parseNetworkingCommand_add_bridge_mapping},
|
||||||
|
/* BridgeMappingRecordParseFunct */ {command: "remove_bridge_mapping", callback: parseNetworkingCommand_remove_bridge_mapping},
|
||||||
|
/* NatPrefixRecordParseFunct */ {command: "add_nat_prefix", callback: parseNetworkingCommand_add_nat_prefix},
|
||||||
|
/* NatPrefixRecordParseFunct */ {command: "remove_nat_prefix", callback: parseNetworkingCommand_remove_nat_prefix},
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetworkingParserByCommand(command string) *func([]string) (*networkingCommandEntry, error) {
|
||||||
|
for _, p := range NetworkingCommandParsers {
|
||||||
|
if p.command == command {
|
||||||
|
return &p.callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNetworkingConfig(eof sentinelSignaller, rows chan []string) chan networkingCommandEntry {
|
||||||
|
var out chan networkingCommandEntry
|
||||||
|
|
||||||
|
out = make(chan networkingCommandEntry)
|
||||||
|
go func(in chan []string, out chan networkingCommandEntry) {
|
||||||
|
for reading := true; reading; {
|
||||||
|
select {
|
||||||
|
case <-eof:
|
||||||
|
reading = false
|
||||||
|
case row := <-in:
|
||||||
|
if len(row) >= 1 {
|
||||||
|
parser := NetworkingParserByCommand(row[0])
|
||||||
|
if parser == nil {
|
||||||
|
log.Printf("Invalid command : %v", row)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
callback := *parser
|
||||||
|
entry, err := callback(row[1:])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Unable to parse command : %v %v", err, row)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out <- *entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(rows, out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkingConfig struct {
|
||||||
|
answer map[int]map[string]string
|
||||||
|
nat_portfwd map[int]map[string]string
|
||||||
|
dhcp_mac_to_ip map[int]map[string]net.IP
|
||||||
|
//bridge_mapping map[net.Interface]uint64 // XXX: we don't need the actual interface for anything but informing the user.
|
||||||
|
bridge_mapping map[string]int
|
||||||
|
nat_prefix map[int][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c NetworkingConfig) repr() string {
|
||||||
|
return fmt.Sprintf("answer -> %v\nnat_portfwd -> %v\ndhcp_mac_to_ip -> %v\nbridge_mapping -> %v\nnat_prefix -> %v", c.answer, c.nat_portfwd, c.dhcp_mac_to_ip, c.bridge_mapping, c.nat_prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenNetworkingConfig(eof sentinelSignaller, in chan networkingCommandEntry) NetworkingConfig {
|
||||||
|
var result NetworkingConfig
|
||||||
|
var vmnet int
|
||||||
|
|
||||||
|
result.answer = make(map[int]map[string]string)
|
||||||
|
result.nat_portfwd = make(map[int]map[string]string)
|
||||||
|
result.dhcp_mac_to_ip = make(map[int]map[string]net.IP)
|
||||||
|
result.bridge_mapping = make(map[string]int)
|
||||||
|
result.nat_prefix = make(map[int][]int)
|
||||||
|
|
||||||
|
for reading := true; reading; {
|
||||||
|
select {
|
||||||
|
case <-eof:
|
||||||
|
reading = false
|
||||||
|
case e := <-in:
|
||||||
|
switch e.entry.(type) {
|
||||||
|
case networkingCommandEntry_answer:
|
||||||
|
vnet := e.answer.vnet
|
||||||
|
answers, exists := result.answer[vnet.Number()]
|
||||||
|
if !exists {
|
||||||
|
answers = make(map[string]string)
|
||||||
|
result.answer[vnet.Number()] = answers
|
||||||
|
}
|
||||||
|
answers[vnet.Option()] = e.answer.value
|
||||||
|
case networkingCommandEntry_remove_answer:
|
||||||
|
vnet := e.remove_answer.vnet
|
||||||
|
answers, exists := result.answer[vnet.Number()]
|
||||||
|
if exists {
|
||||||
|
delete(answers, vnet.Option())
|
||||||
|
} else {
|
||||||
|
log.Printf("Unable to remove answer %s as specified by `remove_answer`.\n", vnet.Repr())
|
||||||
|
}
|
||||||
|
case networkingCommandEntry_add_nat_portfwd:
|
||||||
|
vmnet = e.add_nat_portfwd.vnet
|
||||||
|
protoport := fmt.Sprintf("%s/%d", e.add_nat_portfwd.protocol, e.add_nat_portfwd.port)
|
||||||
|
target := fmt.Sprintf("%s:%d", e.add_nat_portfwd.target_host, e.add_nat_portfwd.target_port)
|
||||||
|
portfwds, exists := result.nat_portfwd[vmnet]
|
||||||
|
if !exists {
|
||||||
|
portfwds = make(map[string]string)
|
||||||
|
result.nat_portfwd[vmnet] = portfwds
|
||||||
|
}
|
||||||
|
portfwds[protoport] = target
|
||||||
|
case networkingCommandEntry_remove_nat_portfwd:
|
||||||
|
vmnet = e.remove_nat_portfwd.vnet
|
||||||
|
protoport := fmt.Sprintf("%s/%d", e.remove_nat_portfwd.protocol, e.remove_nat_portfwd.port)
|
||||||
|
portfwds, exists := result.nat_portfwd[vmnet]
|
||||||
|
if exists {
|
||||||
|
delete(portfwds, protoport)
|
||||||
|
} else {
|
||||||
|
log.Printf("Unable to remove nat port-forward %s from interface %s%d as requested by `remove_nat_portfwd`.\n", protoport, NetworkingInterfacePrefix, vmnet)
|
||||||
|
}
|
||||||
|
case networkingCommandEntry_add_dhcp_mac_to_ip:
|
||||||
|
vmnet = e.add_dhcp_mac_to_ip.vnet
|
||||||
|
dhcpmacs, exists := result.dhcp_mac_to_ip[vmnet]
|
||||||
|
if !exists {
|
||||||
|
dhcpmacs = make(map[string]net.IP)
|
||||||
|
result.dhcp_mac_to_ip[vmnet] = dhcpmacs
|
||||||
|
}
|
||||||
|
dhcpmacs[e.add_dhcp_mac_to_ip.mac.String()] = e.add_dhcp_mac_to_ip.ip
|
||||||
|
case networkingCommandEntry_remove_dhcp_mac_to_ip:
|
||||||
|
vmnet = e.remove_dhcp_mac_to_ip.vnet
|
||||||
|
dhcpmacs, exists := result.dhcp_mac_to_ip[vmnet]
|
||||||
|
if exists {
|
||||||
|
delete(dhcpmacs, e.remove_dhcp_mac_to_ip.mac.String())
|
||||||
|
} else {
|
||||||
|
log.Printf("Unable to remove dhcp_mac_to_ip entry %v from interface %s%d as specified by `remove_dhcp_mac_to_ip`.\n", e.remove_dhcp_mac_to_ip, NetworkingInterfacePrefix, vmnet)
|
||||||
|
}
|
||||||
|
case networkingCommandEntry_add_bridge_mapping:
|
||||||
|
intf := e.add_bridge_mapping.intf
|
||||||
|
if _, err := intf.Interface(); err != nil {
|
||||||
|
log.Printf("Interface \"%s\" as specified by `add_bridge_mapping` was not found on the current platform. This is a non-critical error. Ignoring.", intf.name)
|
||||||
|
}
|
||||||
|
result.bridge_mapping[intf.name] = e.add_bridge_mapping.vnet
|
||||||
|
case networkingCommandEntry_remove_bridge_mapping:
|
||||||
|
intf := e.remove_bridge_mapping.intf
|
||||||
|
if _, err := intf.Interface(); err != nil {
|
||||||
|
log.Printf("Interface \"%s\" as specified by `remove_bridge_mapping` was not found on the current platform. This is a non-critical error. Ignoring.", intf.name)
|
||||||
|
}
|
||||||
|
delete(result.bridge_mapping, intf.name)
|
||||||
|
case networkingCommandEntry_add_nat_prefix:
|
||||||
|
vmnet = e.add_nat_prefix.vnet
|
||||||
|
_, exists := result.nat_prefix[vmnet]
|
||||||
|
if exists {
|
||||||
|
result.nat_prefix[vmnet] = append(result.nat_prefix[vmnet], e.add_nat_prefix.prefix)
|
||||||
|
} else {
|
||||||
|
result.nat_prefix[vmnet] = []int{e.add_nat_prefix.prefix}
|
||||||
|
}
|
||||||
|
case networkingCommandEntry_remove_nat_prefix:
|
||||||
|
vmnet = e.remove_nat_prefix.vnet
|
||||||
|
prefixes, exists := result.nat_prefix[vmnet]
|
||||||
|
if exists {
|
||||||
|
for index := 0; index < len(prefixes); index++ {
|
||||||
|
if prefixes[index] == e.remove_nat_prefix.prefix {
|
||||||
|
result.nat_prefix[vmnet] = append(prefixes[:index], prefixes[index+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Printf("Unable to remove nat prefix /%d from interface %s%d as specified by `remove_nat_prefix`.\n", e.remove_nat_prefix.prefix, NetworkingInterfacePrefix, vmnet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for networking file
|
||||||
|
func ReadNetworkingConfig(fd *os.File) (NetworkingConfig, error) {
|
||||||
|
// start piecing together different parts of the file
|
||||||
|
fromfile, eof := consumeFile(fd)
|
||||||
|
tokenized := tokenizeNetworkingConfig(eof, fromfile)
|
||||||
|
rows := splitNetworkingConfig(eof, tokenized)
|
||||||
|
entries := parseNetworkingConfig(eof, rows)
|
||||||
|
|
||||||
|
// parse the version
|
||||||
|
parsed_version, err := networkingReadVersion(<-rows)
|
||||||
|
if err != nil {
|
||||||
|
return NetworkingConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that it's 1.0 since that's all we support.
|
||||||
|
version := parsed_version.Number()
|
||||||
|
if version != 1.0 {
|
||||||
|
return NetworkingConfig{}, fmt.Errorf("Expected version %f of networking file. Received version %f.", 1.0, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to a configuration
|
||||||
|
result := flattenNetworkingConfig(eof, entries)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// netmapper interface
|
||||||
|
type NetworkingType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NetworkingType_HOSTONLY = iota + 1
|
||||||
|
NetworkingType_NAT
|
||||||
|
NetworkingType_BRIDGED
|
||||||
|
)
|
||||||
|
|
||||||
|
func networkingConfig_InterfaceTypes(config NetworkingConfig) map[int]NetworkingType {
|
||||||
|
var result map[int]NetworkingType
|
||||||
|
result = make(map[int]NetworkingType)
|
||||||
|
|
||||||
|
// defaults
|
||||||
|
result[0] = NetworkingType_BRIDGED
|
||||||
|
result[1] = NetworkingType_HOSTONLY
|
||||||
|
result[8] = NetworkingType_NAT
|
||||||
|
|
||||||
|
// walk through config collecting bridged interfaces
|
||||||
|
for _, vmnet := range config.bridge_mapping {
|
||||||
|
result[vmnet] = NetworkingType_BRIDGED
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk through answers finding out which ones are nat versus hostonly
|
||||||
|
for vmnet, table := range config.answer {
|
||||||
|
// everything should be defined as a virtual adapter...
|
||||||
|
if table["VIRTUAL_ADAPTER"] == "yes" {
|
||||||
|
|
||||||
|
// validate that the VNET entry contains everything we expect it to
|
||||||
|
_, subnetQ := table["HOSTONLY_SUBNET"]
|
||||||
|
_, netmaskQ := table["HOSTONLY_NETMASK"]
|
||||||
|
if !(subnetQ && netmaskQ) {
|
||||||
|
log.Printf("Interface %s%d is missing some expected keys (HOSTONLY_SUBNET, HOSTONLY_NETMASK). This is non-critical. Ignoring..", NetworkingInterfacePrefix, vmnet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// distinguish between nat or hostonly
|
||||||
|
if table["NAT"] == "yes" {
|
||||||
|
result[vmnet] = NetworkingType_NAT
|
||||||
|
} else {
|
||||||
|
result[vmnet] = NetworkingType_HOSTONLY
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's not a virtual_adapter, then it must be an alias (really a bridge).
|
||||||
|
} else {
|
||||||
|
result[vmnet] = NetworkingType_BRIDGED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func networkingConfig_NamesToVmnet(config NetworkingConfig) map[NetworkingType][]int {
|
||||||
|
types := networkingConfig_InterfaceTypes(config)
|
||||||
|
|
||||||
|
// now sort the keys
|
||||||
|
var keys []int
|
||||||
|
for vmnet := range types {
|
||||||
|
keys = append(keys, vmnet)
|
||||||
|
}
|
||||||
|
sort.Ints(keys)
|
||||||
|
|
||||||
|
// build result dictionary
|
||||||
|
var result map[NetworkingType][]int
|
||||||
|
result = make(map[NetworkingType][]int)
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
t := types[keys[i]]
|
||||||
|
result[t] = append(result[t], keys[i])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const NetworkingInterfacePrefix = "vmnet"
|
||||||
|
|
||||||
|
func (e NetworkingConfig) NameIntoDevice(name string) (string, error) {
|
||||||
|
netmapper := networkingConfig_NamesToVmnet(e)
|
||||||
|
name = strings.ToLower(name)
|
||||||
|
|
||||||
|
var vmnet int
|
||||||
|
if name == "hostonly" && len(netmapper[NetworkingType_HOSTONLY]) > 0 {
|
||||||
|
vmnet = netmapper[NetworkingType_HOSTONLY][0]
|
||||||
|
} else if name == "nat" && len(netmapper[NetworkingType_NAT]) > 0 {
|
||||||
|
vmnet = netmapper[NetworkingType_NAT][0]
|
||||||
|
} else if name == "bridged" && len(netmapper[NetworkingType_BRIDGED]) > 0 {
|
||||||
|
vmnet = netmapper[NetworkingType_BRIDGED][0]
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("Network name not found : %v", name)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s%d", NetworkingInterfacePrefix, vmnet), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e NetworkingConfig) DeviceIntoName(device string) (string, error) {
|
||||||
|
types := networkingConfig_InterfaceTypes(e)
|
||||||
|
|
||||||
|
lowerdevice := strings.ToLower(device)
|
||||||
|
if !strings.HasPrefix(lowerdevice, NetworkingInterfacePrefix) {
|
||||||
|
return device, nil
|
||||||
|
}
|
||||||
|
vmnet, err := strconv.Atoi(lowerdevice[len(NetworkingInterfacePrefix):])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
network := types[vmnet]
|
||||||
|
switch network {
|
||||||
|
case NetworkingType_HOSTONLY:
|
||||||
|
return "hostonly", nil
|
||||||
|
case NetworkingType_NAT:
|
||||||
|
return "nat", nil
|
||||||
|
case NetworkingType_BRIDGED:
|
||||||
|
return "bridged", nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("Unable to determine network type for device %s%d.", NetworkingInterfacePrefix, vmnet)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** generic async file reader */
|
||||||
func consumeFile(fd *os.File) (chan byte, sentinelSignaller) {
|
func consumeFile(fd *os.File) (chan byte, sentinelSignaller) {
|
||||||
fromfile := make(chan byte)
|
fromfile := make(chan byte)
|
||||||
eof := make(sentinelSignaller)
|
eof := make(sentinelSignaller)
|
||||||
|
|
|
@ -196,8 +196,19 @@ func (d *Player5Driver) Verify() error {
|
||||||
return playerVmnetnatConfPath(device)
|
return playerVmnetnatConfPath(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.VmwareDriver.NetmapConfPath = func() string {
|
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
|
||||||
return playerNetmapConfPath()
|
pathNetmap := playerNetmapConfPath()
|
||||||
|
if _, err := os.Stat(pathNetmap); err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := os.Open(pathNetmap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
return ReadNetworkMap(fd)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,8 +157,19 @@ func (d *Workstation9Driver) Verify() error {
|
||||||
return workstationVmnetnatConfPath(device)
|
return workstationVmnetnatConfPath(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.VmwareDriver.NetmapConfPath = func() string {
|
d.VmwareDriver.NetworkMapper = func() (NetworkNameMapper, error) {
|
||||||
return workstationNetmapConfPath()
|
pathNetmap := workstationNetmapConfPath()
|
||||||
|
if _, err := os.Stat(pathNetmap); err != nil {
|
||||||
|
return nil, fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := os.Open(pathNetmap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
|
||||||
|
return ReadNetworkMap(fd)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,16 +373,8 @@ func (s *stepCreateVMX) Run(_ context.Context, state multistep.StateBag) multist
|
||||||
driver := state.Get("driver").(vmwcommon.Driver).GetVmwareDriver()
|
driver := state.Get("driver").(vmwcommon.Driver).GetVmwareDriver()
|
||||||
|
|
||||||
// read netmap config
|
// read netmap config
|
||||||
pathNetmap := driver.NetmapConfPath()
|
netmap, err := driver.NetworkMapper()
|
||||||
if _, err := os.Stat(pathNetmap); err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Could not find netmap conf file: %s", pathNetmap)
|
|
||||||
state.Put("error", err)
|
|
||||||
ui.Error(err.Error())
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
netmap, res := vmwcommon.ReadNetmapConfig(pathNetmap)
|
|
||||||
if res != nil {
|
|
||||||
err := fmt.Errorf("Unable to read netmap conf file: %s: %v", pathNetmap, res)
|
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
|
|
Loading…
Reference in New Issue