diff --git a/client/driver/qemu.go b/client/driver/qemu.go index f51907f75..153051c3c 100644 --- a/client/driver/qemu.go +++ b/client/driver/qemu.go @@ -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 diff --git a/client/driver/qemu_test.go b/client/driver/qemu_test.go index 543bf247b..cecca4357 100644 --- a/client/driver/qemu_test.go +++ b/client/driver/qemu_test.go @@ -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,