mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-22 18:41:37 +00:00
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:
parent
f3157af1db
commit
82e6534e9c
@ -7,6 +7,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -16,21 +18,22 @@ const QemuImg = "linuxkit/qemu:17f052263d63c8a2b641ad91c589edcbb8a18c82"
|
|||||||
|
|
||||||
// QemuConfig contains the config for Qemu
|
// QemuConfig contains the config for Qemu
|
||||||
type QemuConfig struct {
|
type QemuConfig struct {
|
||||||
Prefix string
|
Prefix string
|
||||||
ISO bool
|
ISO bool
|
||||||
UEFI bool
|
UEFI bool
|
||||||
Kernel bool
|
Kernel bool
|
||||||
GUI bool
|
GUI bool
|
||||||
DiskPath string
|
DiskPath string
|
||||||
DiskSize string
|
DiskSize string
|
||||||
FWPath string
|
FWPath string
|
||||||
Arch string
|
Arch string
|
||||||
CPUs string
|
CPUs string
|
||||||
Memory string
|
Memory string
|
||||||
KVM bool
|
KVM bool
|
||||||
Containerized bool
|
Containerized bool
|
||||||
QemuBinPath string
|
QemuBinPath string
|
||||||
QemuImgPath string
|
QemuImgPath string
|
||||||
|
PublishedPorts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func runQemu(args []string) {
|
func runQemu(args []string) {
|
||||||
@ -60,6 +63,9 @@ func runQemu(args []string) {
|
|||||||
qemuCPUs := qemuFlags.String("cpus", "1", "Number of CPUs")
|
qemuCPUs := qemuFlags.String("cpus", "1", "Number of CPUs")
|
||||||
qemuMem := qemuFlags.String("mem", "1024", "Amount of memory in MB")
|
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 {
|
if err := qemuFlags.Parse(args); err != nil {
|
||||||
log.Fatal("Unable to parse args")
|
log.Fatal("Unable to parse args")
|
||||||
}
|
}
|
||||||
@ -78,17 +84,18 @@ func runQemu(args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config := QemuConfig{
|
config := QemuConfig{
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
ISO: *qemuIso,
|
ISO: *qemuIso,
|
||||||
UEFI: *qemuUEFI,
|
UEFI: *qemuUEFI,
|
||||||
Kernel: *qemuKernel,
|
Kernel: *qemuKernel,
|
||||||
GUI: *qemuGUI,
|
GUI: *qemuGUI,
|
||||||
DiskPath: *qemuDiskPath,
|
DiskPath: *qemuDiskPath,
|
||||||
DiskSize: *qemuDiskSize,
|
DiskSize: *qemuDiskSize,
|
||||||
FWPath: *qemuFWPath,
|
FWPath: *qemuFWPath,
|
||||||
Arch: *qemuArch,
|
Arch: *qemuArch,
|
||||||
CPUs: *qemuCPUs,
|
CPUs: *qemuCPUs,
|
||||||
Memory: *qemuMem,
|
Memory: *qemuMem,
|
||||||
|
PublishedPorts: publishFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
config, qemuArgs := buildQemuCmdline(config)
|
config, qemuArgs := buildQemuCmdline(config)
|
||||||
@ -159,6 +166,14 @@ func runQemuContainer(config QemuConfig, args []string) error {
|
|||||||
dockerArgs = append(dockerArgs, "--device", "/dev/kvm")
|
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")
|
dockerPath, err := exec.LookPath("docker")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to find docker in the $PATH")
|
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 {
|
if config.GUI != true {
|
||||||
qemuArgs = append(qemuArgs, "-nographic")
|
qemuArgs = append(qemuArgs, "-nographic")
|
||||||
}
|
}
|
||||||
@ -285,3 +309,96 @@ func buildPath(prefix string, postfix string) string {
|
|||||||
}
|
}
|
||||||
return path
|
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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user