Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bosh-virtualbox-cpi/cpi/vms.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package cpi

import (
"github.com/cloudfoundry/bosh-cpi-go/apiv1"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
apiv1 "github.com/cloudfoundry/bosh-cpi-go/apiv1"

bstem "bosh-virtualbox-cpi/stemcell"
bvm "bosh-virtualbox-cpi/vm"
Expand Down
142 changes: 122 additions & 20 deletions src/bosh-virtualbox-cpi/vm/network/add_host_only.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,40 @@ package network
import (
"bosh-virtualbox-cpi/driver"
"fmt"
"net"
"regexp"
)

var (
createdHostOnlyMatch = regexp.MustCompile(`Interface '(.+)' was successfully created`)
createdHostOnlyMatch = regexp.MustCompile(`Interface '(.+)' was successfully created`)
createdHostOnlyNetMatch = regexp.MustCompile(`Name: vboxnet0`)
)

func (n Networks) AddHostOnly(name, gateway, netmask string) (bool, error) {
// VB does not allow naming host-only networks, exit if it's not the first one
systemInfo, err := n.NewSystemInfo()
if err != nil {
return false, err
}

// VB does not allow naming host-only networks inside version <= 6 , exit if it's not the first one
if len(name) > 0 && name != "vboxnet0" {
return false, nil
}

createdName, err := n.createHostOnly()
var createdName string
if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
createdName, err = n.createHostOnly(gateway, netmask)
} else {
createdName, err = n.createHostOnly("", "")
}

if err != nil {
return true, err
}

if len(name) > 0 && createdName != name {
n.cleanUpPartialHostOnlyCreate(createdName)
return true, fmt.Errorf("Expected created host-only network '%s' to have name '%s'", createdName, name)
return true, fmt.Errorf("expected created host-only network '%s' to have name '%s'", createdName, name)
}

err = n.configureHostOnly(createdName, gateway, netmask)
Expand All @@ -35,40 +48,129 @@ func (n Networks) AddHostOnly(name, gateway, netmask string) (bool, error) {
return true, nil
}

func (n Networks) createHostOnly() (string, error) {
output, err := n.driver.Execute("hostonlyif", "create")
func (n Networks) createHostOnly(gateway, netmask string) (string, error) {
systemInfo, err := n.NewSystemInfo()
if err != nil {
return "", err
}

matches := createdHostOnlyMatch.FindStringSubmatch(output)
if len(matches) != 2 {
panic(fmt.Sprintf("Internal inconsistency: Expected len(%s matches) == 2:", createdHostOnlyMatch))
var matches []string
var errorMessage string
var matchesLen int

if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
addr := net.ParseIP(netmask).To4()
subnetFirstIP := &net.IPNet{
IP: net.ParseIP(gateway),
Mask: net.IPv4Mask(addr[0], addr[1], addr[2], addr[3]),
}
cidrRange, _ := net.IPv4Mask(addr[0], addr[1], addr[2], addr[3]).Size()
_, subnet, err := net.ParseCIDR(fmt.Sprintf("%s/%v", gateway, cidrRange))

lowerIp, errGetFirstIP := systemInfo.GetFirstIP(subnetFirstIP)
if errGetFirstIP != nil {
return "", errGetFirstIP
}
upperIp, errGetLastIP := systemInfo.GetLastIP(subnet)
if errGetLastIP != nil {
return "", errGetLastIP
}

args := []string{"hostonlynet",
"add", fmt.Sprintf("--name=%s", "vboxnet0"),
fmt.Sprintf("--netmask=%s", netmask), fmt.Sprintf("--lower-ip=%s", lowerIp.String()),
fmt.Sprintf("--upper-ip=%s", upperIp.String()), "--disable"}

// The output of the hostonlynet interface creation is empty. We need another solution to handle and verify the
// VboxManage creation.
_, err = n.driver.ExecuteComplex(args, driver.ExecuteOpts{})
if err != nil {
return "", err
}

args = []string{"list", "hostonlynets"}
output, err := n.driver.ExecuteComplex(args, driver.ExecuteOpts{})
if err != nil {
return "", err
}

matches = createdHostOnlyNetMatch.FindStringSubmatch(output)
//Define the return value of the created Host only Adapter. We're only creating one adapter,
//so we can also define the used name hard coded.
if len(matches) == 1 {
matches[0] = "vboxnet0"
}

errorMessage = fmt.Sprintf(
"Internal inconsistency: Expected len(%s matches) == 1:",
createdHostOnlyNetMatch,
)
matchesLen = 1
} else {
args := []string{"hostonlyif", "create"}
output, err := n.driver.ExecuteComplex(args, driver.ExecuteOpts{})
if err != nil {
return "", err
}
matches = createdHostOnlyMatch.FindStringSubmatch(output)
errorMessage = fmt.Sprintf(
"Internal inconsistency: Expected len(%s matches) == 2:",
createdHostOnlyMatch,
)
matchesLen = 2
}

return matches[1], nil
if len(matches) != matchesLen {
panic(errorMessage)
}

return matches[matchesLen-1], nil
}

func (n Networks) configureHostOnly(name, gateway, netmask string) error {
args := []string{"hostonlyif", "ipconfig", name}

if len(gateway) > 0 {
args = append(args, []string{"--ip", gateway, "--netmask", netmask}...)
} else {
args = append(args, "--dhcp")
systemInfo, err := n.NewSystemInfo()
if err != nil {
return err
}

_, err := n.driver.ExecuteComplex(args, driver.ExecuteOpts{})
if systemInfo.IsMacOSXVBoxSpecial6or7Case() == false {
args := []string{"hostonlyif", "ipconfig", name}

return err
if len(gateway) > 0 {
args = append(args, []string{"--ip", gateway, "--netmask", netmask}...)
} else {
args = append(args, "--dhcp")
}

_, err := n.driver.ExecuteComplex(args, driver.ExecuteOpts{})

return err
} else {
return nil
}
}

func (n Networks) cleanUpPartialHostOnlyCreate(name string) {
_, err := n.driver.ExecuteComplex([]string{
systemInfo, err := n.NewSystemInfo()
if err != nil {
n.logger.Error("vm.network.SystemInfo",
"Failed to get the SystemInfo: %s", err)
}

args := []string{
"hostonlyif",
"remove",
name,
}, driver.ExecuteOpts{})
}
if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
args = []string{
"hostonlynet",
"remove",
fmt.Sprintf("--name=%s", name),
}
}

_, err = n.driver.ExecuteComplex(args, driver.ExecuteOpts{})
if err != nil {
n.logger.Error("vm.network.Networks",
"Failed to clean up partially created host-only network '%s': %s", name, err)
Expand Down
33 changes: 24 additions & 9 deletions src/bosh-virtualbox-cpi/vm/network/host_only.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package network

import (
"bosh-virtualbox-cpi/driver"
"fmt"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
"net"

"bosh-virtualbox-cpi/driver"
"os"
)

type HostOnly struct {
Expand All @@ -26,20 +27,34 @@ func (n HostOnly) Description() string {
return fmt.Sprintf("Host-only network '%s' (gw %s netmask %s)", n.name, n.ipAddress, n.networkMask)
}

func (n HostOnly) IsEnabled() bool { return n.status == "Up" }
func (n HostOnly) IsEnabled() bool {
return n.status == "Up" || n.status == "Enabled"
}

func (n HostOnly) EnabledDescription() string { return "have status 'Up'" }
func (n HostOnly) EnabledDescription() string {
return fmt.Sprintf("have status '%s'", n.status)
}

func (n HostOnly) Enable() error {
args := []string{"hostonlyif", "ipconfig", n.name}
logger := boshlog.NewWriterLogger(boshlog.LevelDebug, os.Stderr)
systemInfo, err := Networks{driver: n.driver, logger: logger}.NewSystemInfo()
if err != nil {
return err
}

if len(n.ipAddress) > 0 {
args = append(args, []string{"--ip", n.ipAddress, "--netmask", n.networkMask}...)
var finalArgs []string
if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
finalArgs = []string{"hostonlynet", "modify", fmt.Sprintf("--name=%s", n.name), "--enable"}
} else {
args = append(args, "--dhcp")
args := []string{"hostonlyif", "ipconfig", n.name}
if len(n.ipAddress) > 0 {
finalArgs = append(args, []string{"--ip", n.ipAddress, "--netmask", n.networkMask}...)
} else {
finalArgs = append(args, "--dhcp")
}
}

_, err := n.driver.Execute(args...)
_, err = n.driver.ExecuteComplex(finalArgs, driver.ExecuteOpts{})

return err
}
Expand Down
37 changes: 31 additions & 6 deletions src/bosh-virtualbox-cpi/vm/network/networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package network

import (
"fmt"
"os"
"regexp"
"strings"

Expand Down Expand Up @@ -42,7 +43,7 @@ func (n Networks) AddNATNetwork(name string) error {
}

func (n Networks) NATNetworks() ([]Network, error) {
output, err := n.driver.Execute("list", "natnetworks")
output, err := n.driver.Execute("list", "--long", "natnetworks")
if err != nil {
return nil, err
}
Expand All @@ -66,9 +67,9 @@ func (n Networks) NATNetworks() ([]Network, error) {

switch matches[1] {
// does not include all keys
case "NetworkName":
case "NetworkName", "Name":
net.name = matches[2]
case "DHCP Enabled":
case "DHCP Enabled", "DHCP Server":
net.dhcpEnabled, err = n.toBool(matches[2])
case "Network":
net.network = matches[2]
Expand Down Expand Up @@ -145,13 +146,22 @@ func (n Networks) BridgedNetworks() ([]Network, error) {
}

func (n Networks) HostOnlys() ([]Network, error) {
output, err := n.driver.Execute("list", "hostonlyifs")
systemInfo, err := n.NewSystemInfo()
if err != nil {
return nil, err
}

var nets []Network
commandName := "hostonlyifs"
if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
commandName = "hostonlynets"
}

output, err := n.driver.Execute("list", fmt.Sprintf("%s", commandName))
if err != nil {
return nil, err
}

var nets []Network
for _, netChunk := range n.outputChunks(output) {
net := HostOnly{driver: n.driver}

Expand All @@ -171,10 +181,14 @@ func (n Networks) HostOnlys() ([]Network, error) {
net.dhcp, err = n.toBool(matches[2])
case "IPAddress":
net.ipAddress = matches[2]
case "LowerIP":
net.ipAddress = matches[2]
case "NetworkMask":
net.networkMask = matches[2]
case "Status":
net.status = matches[2]
case "State":
net.status = matches[2]
}

if err != nil {
Expand All @@ -198,7 +212,18 @@ func (n Networks) outputChunks(output string) []string {
if output == "" {
return nil
}
return strings.Split(output, "\n\n")

logger := boshlog.NewWriterLogger(boshlog.LevelDebug, os.Stderr)
systemInfo, err := Networks{driver: n.driver, logger: logger}.NewSystemInfo()
if err != nil {
return nil
}
if systemInfo.IsMacOSXVBoxSpecial6or7Case() {
output = strings.Replace(output, "\n\n", "\n", -1)
}

outputChunks := strings.Split(output, "\n\n")
return outputChunks
}

func (n Networks) toBool(s string) (bool, error) {
Expand Down
Loading