Qemu driver takes a port_map to configure host to guest port forwarding

This commit is contained in:
Alex Dadgar
2015-11-17 20:54:53 -08:00
parent 9db262f161
commit c6c896bbea
2 changed files with 34 additions and 38 deletions

View File

@@ -6,7 +6,6 @@ import (
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"time"
@@ -33,10 +32,10 @@ type QemuDriver struct {
}
type QemuDriverConfig struct {
ArtifactSource string `mapstructure:"artifact_source"`
Checksum string `mapstructure:"checksum"`
Accelerator string `mapstructure:"accelerator"`
GuestPorts string `mapstructure:"guest_ports"`
ArtifactSource string `mapstructure:"artifact_source"`
Checksum string `mapstructure:"checksum"`
Accelerator string `mapstructure:"accelerator"`
PortMap []map[string]int `mapstructure:"port_map"` // A map of host port labels and to guest ports.
}
// qemuHandle is returned from Start/Open as a handle to the PID
@@ -82,6 +81,11 @@ func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
return nil, err
}
if len(driverConfig.PortMap) > 1 {
return nil, fmt.Errorf("Only one port_map block is allowed in the qemu driver config")
}
// Get the image source
source, ok := task.Config["artifact_source"]
if !ok || source == "" {
@@ -138,42 +142,31 @@ func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle,
// the outside world to be able to reach it. VMs ran without port mappings can
// still reach out to the world, but without port mappings it is effectively
// firewalled
if len(task.Resources.Networks) > 0 {
// TODO: Consolidate these into map of host/guest port when we have HCL
// Note: Host port must be open and available
// Get and split guest ports. The guest_ports configuration must match up with
// the Reserved ports in the Task Resources
// Users can supply guest_hosts as a list of posts to map on the guest vm.
// These map 1:1 with the requested Reserved Ports from the hostmachine.
ports := strings.Split(driverConfig.GuestPorts, ",")
if len(ports) == 0 {
return nil, fmt.Errorf("[ERR] driver.qemu: Error parsing required Guest Ports")
}
// TODO: support more than a single, default Network
if len(ports) != len(task.Resources.Networks[0].ReservedPorts) {
return nil, fmt.Errorf("[ERR] driver.qemu: Error matching Guest Ports with Reserved ports")
}
// Loop through the reserved ports and construct the hostfwd string, to map
protocols := []string{"udp", "tcp"}
if len(task.Resources.Networks) > 0 && len(driverConfig.PortMap) == 1 {
// Loop through the port map and construct the hostfwd string, to map
// reserved ports to the ports listenting in the VM
// Ex:
// hostfwd=tcp::22000-:22,hostfwd=tcp::80-:8080
reservedPorts := task.Resources.Networks[0].ReservedPorts
var forwarding string
for i, p := range ports {
forwarding = fmt.Sprintf("%s,hostfwd=tcp::%s-:%s", forwarding, strconv.Itoa(reservedPorts[i].Value), p)
// Ex: hostfwd=tcp::22000-:22,hostfwd=tcp::80-:8080
var forwarding []string
taskPorts := task.Resources.Networks[0].MapLabelToValues()
for label, guest := range driverConfig.PortMap[0] {
host, ok := taskPorts[label]
if !ok {
return nil, fmt.Errorf("Unknown port label %q", label)
}
for _, p := range protocols {
forwarding = append(forwarding, fmt.Sprintf("hostfwd=%s::%d-:%d", p, host, guest))
}
}
if "" == forwarding {
return nil, fmt.Errorf("[ERR] driver.qemu: Error constructing port forwarding")
if len(forwarding) != 0 {
args = append(args,
"-netdev",
fmt.Sprintf("user,id=user.0%s", strings.Join(forwarding, ",")),
"-device", "virtio-net,netdev=user.0",
)
}
args = append(args,
"-netdev",
fmt.Sprintf("user,id=user.0%s", forwarding),
"-device", "virtio-net,netdev=user.0",
)
}
// If using KVM, add optimization args

View File

@@ -41,7 +41,10 @@ func TestQemuDriver_StartOpen_Wait(t *testing.T) {
"artifact_source": "https://dl.dropboxusercontent.com/u/47675/jar_thing/linux-0.2.img",
"checksum": "sha256:a5e836985934c3392cbbd9b26db55a7d35a8d7ae1deb7ca559dd9c0159572544",
"accelerator": "tcg",
"guest_ports": "22,8080",
"port_map": []map[string]int{{
"main": 22,
"web": 8080,
}},
},
Resources: &structs.Resources{
CPU: 500,