Port forwarding in qemu runner

Example usage:
	linuxkit run qemu -publish 1111:1111/udp -publish 8081:80/tcp example

Signed-off-by: Lorenzo Fontana <lo@linux.com>
This commit is contained in:
Lorenzo Fontana 2017-04-26 02:34:57 +02:00
parent f3157af1db
commit 82e6534e9c

View File

@ -7,6 +7,8 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
log "github.com/Sirupsen/logrus"
)
@ -31,6 +33,7 @@ type QemuConfig struct {
Containerized bool
QemuBinPath string
QemuImgPath string
PublishedPorts []string
}
func runQemu(args []string) {
@ -60,6 +63,9 @@ func runQemu(args []string) {
qemuCPUs := qemuFlags.String("cpus", "1", "Number of CPUs")
qemuMem := qemuFlags.String("mem", "1024", "Amount of memory in MB")
publishFlags := multipleFlag{}
qemuFlags.Var(&publishFlags, "publish", "Publish a vm's port(s) to the host (default [])")
if err := qemuFlags.Parse(args); err != nil {
log.Fatal("Unable to parse args")
}
@ -89,6 +95,7 @@ func runQemu(args []string) {
Arch: *qemuArch,
CPUs: *qemuCPUs,
Memory: *qemuMem,
PublishedPorts: publishFlags,
}
config, qemuArgs := buildQemuCmdline(config)
@ -159,6 +166,14 @@ func runQemuContainer(config QemuConfig, args []string) error {
dockerArgs = append(dockerArgs, "--device", "/dev/kvm")
}
if config.PublishedPorts != nil && len(config.PublishedPorts) > 0 {
forwardings, err := buildDockerForwardings(config.PublishedPorts)
if err != nil {
return err
}
dockerArgs = append(dockerArgs, forwardings...)
}
dockerPath, err := exec.LookPath("docker")
if err != nil {
return fmt.Errorf("Unable to find docker in the $PATH")
@ -271,6 +286,15 @@ func buildQemuCmdline(config QemuConfig) (QemuConfig, []string) {
}
}
if config.PublishedPorts != nil && len(config.PublishedPorts) > 0 {
forwardings, err := buildQemuForwardings(config.PublishedPorts, config.Containerized)
if err != nil {
log.Error(err)
}
qemuArgs = append(qemuArgs, "-net", forwardings)
qemuArgs = append(qemuArgs, "-net", "nic")
}
if config.GUI != true {
qemuArgs = append(qemuArgs, "-nographic")
}
@ -285,3 +309,96 @@ func buildPath(prefix string, postfix string) string {
}
return path
}
type multipleFlag []string
type publishedPorts struct {
guest int
host int
protocol string
}
func (f *multipleFlag) String() string {
return "A multiple flag is a type of flag that can be repeated any number of times"
}
func (f *multipleFlag) Set(value string) error {
*f = append(*f, value)
return nil
}
func splitPublish(publish string) (publishedPorts, error) {
p := publishedPorts{}
slice := strings.Split(publish, ":")
if len(slice) < 2 {
return p, fmt.Errorf("Unable to parse the ports to be published, should be in format <host>:<guest> or <host>:<guest>/<tcp|udp>")
}
hostPort, err := strconv.Atoi(slice[0])
if err != nil {
return p, fmt.Errorf("The provided hostPort can't be converted to int")
}
right := strings.Split(slice[1], "/")
protocol := "tcp"
if len(right) == 2 {
protocol = strings.TrimSpace(strings.ToLower(right[1]))
}
if protocol != "tcp" && protocol != "udp" {
return p, fmt.Errorf("Provided protocol is not valid, valid options are: udp and tcp")
}
guestPort, err := strconv.Atoi(right[0])
if err != nil {
return p, fmt.Errorf("The provided guestPort can't be converted to int")
}
if hostPort < 1 || hostPort > 65535 {
return p, fmt.Errorf("Invalid hostPort: %d", hostPort)
}
if guestPort < 1 || guestPort > 65535 {
return p, fmt.Errorf("Invalid guestPort: %d", guestPort)
}
p.guest = guestPort
p.host = hostPort
p.protocol = protocol
return p, nil
}
func buildQemuForwardings(publishFlags multipleFlag, containerized bool) (string, error) {
forwardings := "user"
for _, publish := range publishFlags {
p, err := splitPublish(publish)
if err != nil {
return "", err
}
hostPort := p.host
guestPort := p.guest
if containerized {
hostPort = guestPort
}
forwardings = fmt.Sprintf("%s,hostfwd=%s::%d-:%d", forwardings, p.protocol, hostPort, guestPort)
}
return forwardings, nil
}
func buildDockerForwardings(publishedPorts []string) ([]string, error) {
pmap := []string{}
for _, port := range publishedPorts {
s, err := splitPublish(port)
if err != nil {
return nil, err
}
pmap = append(pmap, "-p", fmt.Sprintf("%d:%d/%s", s.host, s.guest, s.protocol))
}
return pmap, nil
}