Fix multiple bugs with host-only adapterss

Signed-off-by: David Gageot <david@gageot.net>
This commit is contained in:
David Gageot 2016-01-11 09:03:11 +01:00
parent f5ba0f7420
commit 8553dd2d6c
3 changed files with 229 additions and 124 deletions

View File

@ -5,16 +5,20 @@ import (
"fmt"
"net"
"regexp"
"strconv"
"strings"
"time"
"github.com/docker/machine/libmachine/log"
)
const (
buggyNetmask = "0f000000"
dhcpPrefix = "HostInterfaceNetworking-"
)
var (
reHostonlyInterfaceCreated = regexp.MustCompile(`Interface '(.+)' was successfully created`)
errNewHostOnlyInterfaceNotVisible = errors.New("The host-only interface we just created is not visible. This is a well known bug of VirtualBox. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue")
reHostOnlyAdapterCreated = regexp.MustCompile(`Interface '(.+)' was successfully created`)
errNewHostOnlyAdapterNotVisible = errors.New("The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue")
)
// Host-only network.
@ -23,7 +27,6 @@ type hostOnlyNetwork struct {
GUID string
DHCP bool
IPv4 net.IPNet
IPv6 net.IPNet
HwAddr net.HardwareAddr
Medium string
Status string
@ -32,17 +35,8 @@ type hostOnlyNetwork struct {
// Save changes the configuration of the host-only network.
func (n *hostOnlyNetwork) Save(vbox VBoxManager) error {
if n.IPv4.IP != nil && n.IPv4.Mask != nil {
if err := vbox.vbm("hostonlyif", "ipconfig", n.Name, "--ip", n.IPv4.IP.String(), "--netmask", net.IP(n.IPv4.Mask).String()); err != nil {
return err
}
}
if n.IPv6.IP != nil && n.IPv6.Mask != nil {
prefixLen, _ := n.IPv6.Mask.Size()
if err := vbox.vbm("hostonlyif", "ipconfig", n.Name, "--ipv6", n.IPv6.IP.String(), "--netmasklengthv6", fmt.Sprintf("%d", prefixLen)); err != nil {
return err
}
if err := n.SaveIPv4(vbox); err != nil {
return err
}
if n.DHCP {
@ -52,23 +46,34 @@ func (n *hostOnlyNetwork) Save(vbox VBoxManager) error {
return nil
}
// createHostonlyNet creates a new host-only network.
func createHostonlyNet(vbox VBoxManager) (*hostOnlyNetwork, error) {
// SaveIPv4 changes the ipv4 configuration of the host-only network.
func (n *hostOnlyNetwork) SaveIPv4(vbox VBoxManager) error {
if n.IPv4.IP != nil && n.IPv4.Mask != nil {
if err := vbox.vbm("hostonlyif", "ipconfig", n.Name, "--ip", n.IPv4.IP.String(), "--netmask", net.IP(n.IPv4.Mask).String()); err != nil {
return err
}
}
return nil
}
// createHostonlyAdapter creates a new host-only network.
func createHostonlyAdapter(vbox VBoxManager) (*hostOnlyNetwork, error) {
out, err := vbox.vbmOut("hostonlyif", "create")
if err != nil {
return nil, err
}
res := reHostonlyInterfaceCreated.FindStringSubmatch(string(out))
res := reHostOnlyAdapterCreated.FindStringSubmatch(string(out))
if res == nil {
return nil, errors.New("failed to create hostonly interface")
return nil, errors.New("Failed to create host-only adapter")
}
return &hostOnlyNetwork{Name: res[1]}, nil
}
// listHostOnlyNetworks gets all host-only networks in a map keyed by HostonlyNet.NetworkName.
func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error) {
// listHostOnlyAdapters gets all host-only adapters in a map keyed by NetworkName.
func listHostOnlyAdapters(vbox VBoxManager) (map[string]*hostOnlyNetwork, error) {
out, err := vbox.vbmOut("list", "hostonlyifs")
if err != nil {
return nil, err
@ -90,14 +95,6 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
n.IPv4.IP = net.ParseIP(val)
case "NetworkMask":
n.IPv4.Mask = parseIPv4Mask(val)
case "IPV6Address":
n.IPv6.IP = net.ParseIP(val)
case "IPV6NetworkMaskPrefixLength":
l, err := strconv.ParseUint(val, 10, 8)
if err != nil {
return err
}
n.IPv6.Mask = net.CIDRMask(int(l), net.IPv6len*8)
case "HardwareAddress":
mac, err := net.ParseMAC(val)
if err != nil {
@ -112,13 +109,13 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
n.NetworkName = val
if _, present := byName[n.NetworkName]; present {
return fmt.Errorf("VirtualBox is configured with multiple host-only interfaces with the same name %q. Please remove one.", n.NetworkName)
return fmt.Errorf("VirtualBox is configured with multiple host-only adapters with the same name %q. Please remove one.", n.NetworkName)
}
byName[n.NetworkName] = n
if len(n.IPv4.IP) != 0 {
if _, present := byIP[n.IPv4.IP.String()]; present {
return fmt.Errorf("VirtualBox is configured with multiple host-only interfaces with the same IP %q. Please remove one.", n.IPv4.IP)
return fmt.Errorf("VirtualBox is configured with multiple host-only adapters with the same IP %q. Please remove one.", n.IPv4.IP)
}
byIP[n.IPv4.IP.String()] = n
}
@ -135,65 +132,87 @@ func listHostOnlyNetworks(vbox VBoxManager) (map[string]*hostOnlyNetwork, error)
return byName, nil
}
func getHostOnlyNetwork(nets map[string]*hostOnlyNetwork, hostIP net.IP, netmask net.IPMask) *hostOnlyNetwork {
func getHostOnlyAdapter(nets map[string]*hostOnlyNetwork, hostIP net.IP, netmask net.IPMask) *hostOnlyNetwork {
for _, n := range nets {
// Second part of this conditional handles a race where
// VirtualBox returns us the incorrect netmask value for the
// newly created interface.
// newly created adapter.
if hostIP.Equal(n.IPv4.IP) &&
(netmask.String() == n.IPv4.Mask.String() || n.IPv4.Mask.String() == buggyNetmask) {
log.Debugf("Found: %s", n.Name)
return n
}
}
log.Debug("Not found")
return nil
}
func getOrCreateHostOnlyNetwork(hostIP net.IP, netmask net.IPMask, dhcpIP net.IP, dhcpLowerIP net.IP, dhcpUpperIP net.IP, vbox VBoxManager) (*hostOnlyNetwork, error) {
nets, err := listHostOnlyNetworks(vbox)
func getOrCreateHostOnlyNetwork(hostIP net.IP, netmask net.IPMask, vbox VBoxManager) (*hostOnlyNetwork, error) {
nets, err := listHostOnlyAdapters(vbox)
if err != nil {
return nil, err
}
hostOnlyNet := getHostOnlyNetwork(nets, hostIP, netmask)
if hostOnlyNet != nil {
return hostOnlyNet, nil
hostOnlyAdapter := getHostOnlyAdapter(nets, hostIP, netmask)
if hostOnlyAdapter != nil {
return hostOnlyAdapter, nil
}
// No existing host-only interface found. Create a new one.
hostOnlyNet, err = createHostonlyNet(vbox)
// No existing host-only adapter found. Create a new one.
hostOnlyAdapter, err = createHostonlyAdapter(vbox)
if err != nil {
// Sometimes the host-only adapter fails to create. See https://www.virtualbox.org/ticket/14040
// BUT, it is created in fact! So let's wait until it appears last in the list
log.Warnf("Creating a new host-only adapter produced an error: %s", err)
log.Warn("This is a known VirtualBox bug. Let's try to recover anyway...")
hostOnlyAdapter, err = waitForNewHostOnlyNetwork(nets, vbox)
if err != nil {
return nil, err
}
log.Warnf("Found a new host-only adapter: %q", hostOnlyAdapter.Name)
}
hostOnlyAdapter.IPv4.IP = hostIP
hostOnlyAdapter.IPv4.Mask = netmask
if err := hostOnlyAdapter.Save(vbox); err != nil {
return nil, err
}
// Check that the adapter still exists.
// Sometimes, Vbox says it created it but then it cannot be found...
nets, err = listHostOnlyAdapters(vbox)
if err != nil {
return nil, err
}
hostOnlyNet.IPv4.IP = hostIP
hostOnlyNet.IPv4.Mask = netmask
if err := hostOnlyNet.Save(vbox); err != nil {
return nil, err
found := getHostOnlyAdapter(nets, hostIP, netmask)
if found == nil {
return nil, errNewHostOnlyAdapterNotVisible
}
dhcp := dhcpServer{}
dhcp.IPv4.IP = dhcpIP
dhcp.IPv4.Mask = netmask
dhcp.LowerIP = dhcpLowerIP
dhcp.UpperIP = dhcpUpperIP
dhcp.Enabled = true
if err := addHostonlyDHCP(hostOnlyNet.Name, dhcp, vbox); err != nil {
return nil, err
return hostOnlyAdapter, nil
}
func waitForNewHostOnlyNetwork(oldNets map[string]*hostOnlyNetwork, vbox VBoxManager) (*hostOnlyNetwork, error) {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
newNets, err := listHostOnlyAdapters(vbox)
if err != nil {
return nil, err
}
for name, latestNet := range newNets {
if _, present := oldNets[name]; !present {
return latestNet, nil
}
}
}
// Check that the interface really exists.
// Sometimes, Vbox says it created the interface but then it cannot be found...
nets, err = listHostOnlyNetworks(vbox)
if err != nil {
return nil, err
}
hostOnlyNet = getHostOnlyNetwork(nets, hostIP, netmask)
if hostOnlyNet == nil {
return nil, errNewHostOnlyInterfaceNotVisible
}
return hostOnlyNet, nil
return nil, errors.New("Failed to find a new host-only adapter")
}
// DHCP server info.
@ -205,22 +224,57 @@ type dhcpServer struct {
Enabled bool
}
func addDHCPServer(kind, name string, d dhcpServer, vbox VBoxManager) error {
command := "modify"
// On some platforms (OSX), creating a hostonlyinterface adds a default dhcpserver
// While on others (Windows?) it does not.
dhcps, err := getDHCPServers(vbox)
// removeOrphanDHCPServers removed the DHCP servers linked to no host-only adapter
func removeOrphanDHCPServers(vbox VBoxManager) error {
dhcps, err := listDHCPServers(vbox)
if err != nil {
return err
}
if _, ok := dhcps[name]; !ok {
command = "add"
if len(dhcps) == 0 {
return nil
}
nets, err := listHostOnlyAdapters(vbox)
if err != nil {
return err
}
for name := range dhcps {
if strings.HasPrefix(name, dhcpPrefix) {
if _, present := nets[name]; !present {
if err := vbox.vbm("dhcpserver", "remove", "--netname", name); err != nil {
log.Warnf("Unable to remove orphan dhcp server %q: %s", name, err)
}
}
}
}
return nil
}
// addHostOnlyDHCPServer adds a DHCP server to a host-only network.
func addHostOnlyDHCPServer(ifname string, d dhcpServer, vbox VBoxManager) error {
name := dhcpPrefix + ifname
dhcps, err := listDHCPServers(vbox)
if err != nil {
return err
}
// On some platforms (OSX), creating a host-only adapter adds a default dhcpserver,
// while on others (Windows?) it does not.
command := "add"
if dhcp, ok := dhcps[name]; ok {
command = "modify"
if (dhcp.IPv4.IP.Equal(d.IPv4.IP)) && (dhcp.IPv4.Mask.String() == d.IPv4.Mask.String()) && (dhcp.LowerIP.Equal(d.LowerIP)) && (dhcp.UpperIP.Equal(d.UpperIP)) && dhcp.Enabled {
// dhcp is up to date
return nil
}
}
args := []string{"dhcpserver", command,
kind, name,
"--netname", name,
"--ip", d.IPv4.IP.String(),
"--netmask", net.IP(d.IPv4.Mask).String(),
"--lowerip", d.LowerIP.String(),
@ -235,13 +289,8 @@ func addDHCPServer(kind, name string, d dhcpServer, vbox VBoxManager) error {
return vbox.vbm(args...)
}
// addHostonlyDHCP adds a DHCP server to a host-only network.
func addHostonlyDHCP(ifname string, d dhcpServer, vbox VBoxManager) error {
return addDHCPServer("--netname", "HostInterfaceNetworking-"+ifname, d, vbox)
}
// getDHCPServers gets all DHCP server settings in a map keyed by DHCP.NetworkName.
func getDHCPServers(vbox VBoxManager) (map[string]*dhcpServer, error) {
// listDHCPServers lists all DHCP server settings in a map keyed by DHCP.NetworkName.
func listDHCPServers(vbox VBoxManager) (map[string]*dhcpServer, error) {
out, err := vbox.vbmOut("list", "dhcpservers")
if err != nil {
return nil, err

View File

@ -80,7 +80,7 @@ func TestGetHostOnlyNetworkHappy(t *testing.T) {
"HostInterfaceNetworking-vboxnet0": expectedHostOnlyNetwork,
}
n := getHostOnlyNetwork(vboxNets, ip, ipnet.Mask)
n := getHostOnlyAdapter(vboxNets, ip, ipnet.Mask)
if !reflect.DeepEqual(n, expectedHostOnlyNetwork) {
t.Fatalf("Expected result of calling getHostOnlyNetwork to be the same as expected but it was not:\nexpected: %+v\nactual: %+v\n", expectedHostOnlyNetwork, n)
}
@ -107,7 +107,7 @@ func TestGetHostOnlyNetworkNotFound(t *testing.T) {
"HostInterfaceNetworking-vboxnet0": vboxNet,
}
n := getHostOnlyNetwork(vboxNets, ip, ipnet.Mask)
n := getHostOnlyAdapter(vboxNets, ip, ipnet.Mask)
if n != nil {
t.Fatalf("Expected vbox net to be nil but it has a value: %+v\n", n)
}
@ -136,7 +136,7 @@ func TestGetHostOnlyNetworkWindows10Bug(t *testing.T) {
// The Mask that we are passing in will be the "legitimate" mask, so it
// must differ from the magic buggy mask.
n := getHostOnlyNetwork(vboxNets, ip, net.IPMask(net.ParseIP("255.255.255.0").To4()))
n := getHostOnlyAdapter(vboxNets, ip, net.IPMask(net.ParseIP("255.255.255.0").To4()))
if !reflect.DeepEqual(n, expectedHostOnlyNetwork) {
t.Fatalf("Expected result of calling getHostOnlyNetwork to be the same as expected but it was not:\nexpected: %+v\nactual: %+v\n", expectedHostOnlyNetwork, n)
}
@ -148,7 +148,7 @@ func TestListHostOnlyNetworks(t *testing.T) {
stdOut: stdOutOneHostOnlyNetwork,
}
nets, err := listHostOnlyNetworks(vbox)
nets, err := listHostOnlyAdapters(vbox)
assert.Equal(t, 1, len(nets))
assert.NoError(t, err)
@ -161,7 +161,6 @@ func TestListHostOnlyNetworks(t *testing.T) {
assert.False(t, net.DHCP)
assert.Equal(t, "192.168.99.1", net.IPv4.IP.String())
assert.Equal(t, "ffffff00", net.IPv4.Mask.String())
assert.Empty(t, net.IPv6.IP)
assert.Equal(t, "0a:00:27:00:00:00", net.HwAddr.String())
assert.Equal(t, "Ethernet", net.Medium)
assert.Equal(t, "Up", net.Status)
@ -174,7 +173,7 @@ func TestListTwoHostOnlyNetworks(t *testing.T) {
stdOut: stdOutTwoHostOnlyNetwork,
}
nets, err := listHostOnlyNetworks(vbox)
nets, err := listHostOnlyAdapters(vbox)
assert.Equal(t, 2, len(nets))
assert.NoError(t, err)
@ -187,7 +186,6 @@ func TestListTwoHostOnlyNetworks(t *testing.T) {
assert.False(t, net.DHCP)
assert.Equal(t, "169.254.37.187", net.IPv4.IP.String())
assert.Equal(t, "ffffff00", net.IPv4.Mask.String())
assert.Empty(t, net.IPv6.IP)
assert.Equal(t, "0a:00:27:00:00:01", net.HwAddr.String())
assert.Equal(t, "Ethernet", net.Medium)
assert.Equal(t, "Up", net.Status)
@ -203,7 +201,7 @@ Name: vboxnet1
VBoxNetworkName: HostInterfaceNetworking-vboxnet1`,
}
nets, err := listHostOnlyNetworks(vbox)
nets, err := listHostOnlyAdapters(vbox)
assert.Equal(t, 2, len(nets))
assert.NoError(t, err)
@ -223,7 +221,7 @@ func TestGetHostOnlyNetwork(t *testing.T) {
stdOut: stdOutOneHostOnlyNetwork,
}
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), nil, nil, nil, vbox)
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), vbox)
assert.NotNil(t, net)
assert.Equal(t, "HostInterfaceNetworking-vboxnet0", net.NetworkName)
@ -243,10 +241,10 @@ NetworkMask: 255.255.255.0
VBoxNetworkName: HostInterfaceNetworking-vboxnet1`,
}
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), nil, nil, nil, vbox)
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), vbox)
assert.Nil(t, net)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only interfaces with the same IP "192.168.99.1". Please remove one.`)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only adapters with the same IP "192.168.99.1". Please remove one.`)
}
func TestFailIfTwoNetworksHaveSameName(t *testing.T) {
@ -258,10 +256,10 @@ Name: vboxnet0
VBoxNetworkName: HostInterfaceNetworking-vboxnet0`,
}
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), nil, nil, nil, vbox)
net, err := getOrCreateHostOnlyNetwork(net.ParseIP("192.168.99.1"), parseIPv4Mask("255.255.255.0"), vbox)
assert.Nil(t, net)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only interfaces with the same name "HostInterfaceNetworking-vboxnet0". Please remove one.`)
assert.EqualError(t, err, `VirtualBox is configured with multiple host-only adapters with the same name "HostInterfaceNetworking-vboxnet0". Please remove one.`)
}
func TestGetDHCPServers(t *testing.T) {
@ -270,7 +268,7 @@ func TestGetDHCPServers(t *testing.T) {
stdOut: stdOutListTwoDHCPServers,
}
servers, err := getDHCPServers(vbox)
servers, err := listDHCPServers(vbox)
assert.Equal(t, 2, len(servers))
assert.NoError(t, err)

View File

@ -229,7 +229,7 @@ func (d *Driver) PreCreateCheck() error {
}
// Check that Host-only interfaces are ok
if _, err = listHostOnlyNetworks(d.VBoxManager); err != nil {
if _, err = listHostOnlyAdapters(d.VBoxManager); err != nil {
return err
}
@ -270,7 +270,7 @@ func (d *Driver) Create() error {
return err
}
log.Infof("Creating VirtualBox VM...")
log.Info("Creating VirtualBox VM...")
// import b2d VM if requested
if d.Boot2DockerImportVM != "" {
@ -379,10 +379,6 @@ func (d *Driver) Create() error {
return err
}
if err := d.setupHostOnlyNetwork(d.MachineName); err != nil {
return err
}
if err := d.vbm("storagectl", d.MachineName,
"--name", "SATA",
"--add", "sata",
@ -442,6 +438,7 @@ func (d *Driver) Create() error {
}
}
log.Info("Starting the VM...")
return d.Start()
}
@ -466,9 +463,10 @@ func (d *Driver) Start() error {
return err
}
var hostOnlyAdapter *hostOnlyNetwork
if s == state.Stopped {
// check network to re-create if needed
if err := d.setupHostOnlyNetwork(d.MachineName); err != nil {
if hostOnlyAdapter, err = d.setupHostOnlyNetwork(d.MachineName); err != nil {
return fmt.Errorf("Error setting up host only network on machine start: %s", err)
}
}
@ -479,8 +477,10 @@ func (d *Driver) Start() error {
if err != nil {
return err
}
if err := d.vbm("startvm", d.MachineName, "--type", "headless"); err != nil {
return err
// TODO: We could capture the last lines of the vbox log
return fmt.Errorf("Unable to start the VM: %s", err)
}
case state.Paused:
if err := d.vbm("controlvm", d.MachineName, "resume", "--type", "headless"); err != nil {
@ -501,6 +501,55 @@ func (d *Driver) Start() error {
return ErrMustEnableVTX
}
log.Infof("Waiting for an IP...")
if err := d.waitForIP(); err != nil {
return err
}
if hostOnlyAdapter == nil {
return nil
}
// Check that the host-only adapter we just created can still be found
// Sometimes it is corrupted after the VM is started.
nets, err := listHostOnlyAdapters(d.VBoxManager)
if err != nil {
return err
}
ip, network, err := parseAndValidateCIDR(d.HostOnlyCIDR)
if err != nil {
return err
}
hostOnlyNet := getHostOnlyAdapter(nets, ip, network.Mask)
if hostOnlyNet != nil {
// OK, we found a valid host-only adapter
return nil
}
// This happens a lot on windows. The adapter has an invalid IP and the VM has the same IP
log.Warn("The host-only adapter is corrupted. Let's stop the VM, fix the host-only adapter and restart the VM")
if err := d.Stop(); err != nil {
return err
}
// We have to be sure the host-only adapter is not used by the VM
time.Sleep(5 * time.Second)
log.Debugf("Fixing %+v...", hostOnlyAdapter)
if err := hostOnlyAdapter.SaveIPv4(d.VBoxManager); err != nil {
return err
}
// We have to be sure the adapter is updated before starting the VM
time.Sleep(5 * time.Second)
if err := d.vbm("startvm", d.MachineName, "--type", "headless"); err != nil {
return fmt.Errorf("Unable to start the VM: %s", err)
}
log.Infof("Waiting for an IP...")
return d.waitForIP()
}
@ -593,8 +642,7 @@ func (d *Driver) Remove() error {
}
func (d *Driver) GetState() (state.State, error) {
stdout, stderr, err := d.vbmOutErr("showvminfo", d.MachineName,
"--machinereadable")
stdout, stderr, err := d.vbmOutErr("showvminfo", d.MachineName, "--machinereadable")
if err != nil {
if reMachineNotFound.FindString(stderr) != "" {
return state.Error, ErrMachineNotExist
@ -671,7 +719,7 @@ func (d *Driver) generateDiskImage(size int) error {
return createDiskImage(d.diskPath(), size, tarBuf)
}
func (d *Driver) setupHostOnlyNetwork(machineName string) error {
func (d *Driver) setupHostOnlyNetwork(machineName string) (*hostOnlyNetwork, error) {
hostOnlyCIDR := d.HostOnlyCIDR
// This is to assist in migrating from version 0.2 to 0.3 format
@ -682,38 +730,48 @@ func (d *Driver) setupHostOnlyNetwork(machineName string) error {
ip, network, err := parseAndValidateCIDR(hostOnlyCIDR)
if err != nil {
return err
return nil, err
}
log.Debugf("Searching for hostonly interface for IPv4: %s and Mask: %s", ip, network.Mask)
hostOnlyAdapter, err := getOrCreateHostOnlyNetwork(ip, network.Mask, d.VBoxManager)
if err != nil {
return nil, err
}
log.Debug("Removing orphan DHCP servers...")
if err := removeOrphanDHCPServers(d.VBoxManager); err != nil {
return nil, err
}
dhcpAddr, err := getRandomIPinSubnet(ip)
if err != nil {
return err
return nil, err
}
log.Debugf("Adding/Modifying DHCP server %q...", dhcpAddr)
nAddr := network.IP.To4()
lowerDHCPIP := net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(100))
upperDHCPIP := net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(254))
log.Debugf("using %s for dhcp address", dhcpAddr)
hostOnlyNetwork, err := getOrCreateHostOnlyNetwork(
ip,
network.Mask,
dhcpAddr,
lowerDHCPIP,
upperDHCPIP,
d.VBoxManager,
)
if err != nil {
return err
dhcp := dhcpServer{}
dhcp.IPv4.IP = dhcpAddr
dhcp.IPv4.Mask = network.Mask
dhcp.LowerIP = net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(100))
dhcp.UpperIP = net.IPv4(nAddr[0], nAddr[1], nAddr[2], byte(254))
dhcp.Enabled = true
if err := addHostOnlyDHCPServer(hostOnlyAdapter.Name, dhcp, d.VBoxManager); err != nil {
return nil, err
}
return d.vbm("modifyvm", machineName,
if err := d.vbm("modifyvm", machineName,
"--nic2", "hostonly",
"--nictype2", d.HostOnlyNicType,
"--nicpromisc2", d.HostOnlyPromiscMode,
"--hostonlyadapter2", hostOnlyNetwork.Name,
"--cableconnected2", "on")
"--hostonlyadapter2", hostOnlyAdapter.Name,
"--cableconnected2", "on"); err != nil {
return nil, err
}
return hostOnlyAdapter, nil
}
func parseAndValidateCIDR(hostOnlyCIDR string) (net.IP, *net.IPNet, error) {