Skip to content

Commit

Permalink
Add file.go and temporary file creation to enable multi instance VM l…
Browse files Browse the repository at this point in the history
…aunch

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
  • Loading branch information
darkodraskovic committed Aug 15, 2023
1 parent 0b38e94 commit b3ad784
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 18 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ sudo apt update
sudo apt install qemu-kvm
```

Create `img` directory in `cmd/manager`.
Create `img` directory in `cmd/manager`. Create `tmp` directory in `cmd/manager`.

### focal-server-cloudimg-amd64.img

Expand All @@ -50,8 +50,7 @@ MANAGER_QEMU_OVMF_CODE_FILE=/usr/share/OVMF/OVMF_CODE.fd

sudo find / -name OVMF_VARS.fd
# => /usr/share/OVMF/OVMF_VARS.fd
cp /usr/share/OVMF/OVMF_VARS.fd .
MANAGER_QEMU_OVMF_VARS_FILE=img/OVMF_VARS.fd
MANAGER_QEMU_OVMF_VARS_FILE=/usr/share/OVMF/OVMF_VARS.fd
```

## Run
Expand All @@ -74,10 +73,14 @@ Manager will start an HTTP server on port `9021`, and a gRPC server on port `700

### Create QEMU virtual machine (VM)

To create an instance of VM, run

```sh
curl -sSi -X GET http://localhost:9021/qemu
```

You should be able to create multiple instances by reruning the command.

### Verifying VM launch

NB: To verify that the manager successfully launched the VM, you need to open two terminals on the same machine. In one terminal, you need to launch `go run main.go` (with the environment variables of choice) and in the other, you can run the verification commands.
Expand Down
11 changes: 5 additions & 6 deletions cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,6 @@ func main() {
logger.Fatal(fmt.Sprintf("failed to load %s QEMU configuration : %s", svcName, err))
}

// exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
// if err != nil {
// logger.Fatal(fmt.Sprintf("failed to generate executable and arguments: %v", err))
// }
// logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))

//SVC
svc := newService(libvirtConn, agentClient, logger, tracer, qemuCfg)

Expand Down Expand Up @@ -151,6 +145,11 @@ func main() {
if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
}

err = internal.DeleteFilesInDir("tmp/")
if err != nil {
logger.Error(fmt.Sprintf("%s", err))
}
}

func newService(libvirtConn *libvirt.Libvirt, agent agent.AgentServiceClient, logger logger.Logger, tracer trace.Tracer, qemuCfg qemu.Config) manager.Service {
Expand Down
44 changes: 44 additions & 0 deletions internal/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package internal

import (
"io"
"os"
"path/filepath"
)

func CopyFile(srcPath, dstPath string) error {
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()

dst, err := os.Create(dstPath)
if err != nil {
return err
}
defer dst.Close()

_, err = io.Copy(dst, src)
if err != nil {
return err
}

return nil
}

func DeleteFilesInDir(dirPath string) error {
files, err := filepath.Glob(filepath.Join(dirPath, "*"))
if err != nil {
return err
}

for _, file := range files {
err := os.Remove(file)
if err != nil {
return err
}
}

return nil
}
16 changes: 8 additions & 8 deletions manager/qemu/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ type OVMFVarsConfig struct {
If string `env:"OVMF_VARS_IF" envDefault:"pflash"`
Format string `env:"OVMF_VARS_FORMAT" envDefault:"raw"`
Unit int `env:"OVMF_VARS_UNIT" envDefault:"1"`
File string `env:"OVMF_VARS_FILE" envDefault:"img/OVMF_VARS.fd"`
File string `env:"OVMF_VARS_FILE" envDefault:"/usr/share/OVMF/OVMF_VARS.fd"`
}

type NetDevConfig struct {
ID string `env:"NETDEV_ID" envDefault:"vmnic"`
HostFwd1 string `env:"HOST_FWD_1" envDefault:"2222"`
GuestFwd1 string `env:"GUEST_FWD_1" envDefault:"22"`
HostFwd2 string `env:"HOST_FWD_2" envDefault:"9301"`
GuestFwd2 string `env:"GUEST_FWD_2" envDefault:"9031"`
HostFwd3 string `env:"HOST_FWD_3" envDefault:"7020"`
GuestFwd3 string `env:"GUEST_FWD_3" envDefault:"7002"`
HostFwd1 int `env:"HOST_FWD_1" envDefault:"2222"`
GuestFwd1 int `env:"GUEST_FWD_1" envDefault:"22"`
HostFwd2 int `env:"HOST_FWD_2" envDefault:"9301"`
GuestFwd2 int `env:"GUEST_FWD_2" envDefault:"9031"`
HostFwd3 int `env:"HOST_FWD_3" envDefault:"7020"`
GuestFwd3 int `env:"GUEST_FWD_3" envDefault:"7002"`
}

type VirtioNetPciConfig struct {
Expand Down Expand Up @@ -150,7 +150,7 @@ func constructQemuArgs(config Config) []string {

// network
args = append(args, "-netdev",
fmt.Sprintf("user,id=%s,hostfwd=tcp::%s-:%s,hostfwd=tcp::%s-:%s,hostfwd=tcp::%s-:%s",
fmt.Sprintf("user,id=%s,hostfwd=tcp::%d-:%d,hostfwd=tcp::%d-:%d,hostfwd=tcp::%d-:%d",
config.NetDevConfig.ID,
config.NetDevConfig.HostFwd1, config.NetDevConfig.GuestFwd1,
config.NetDevConfig.HostFwd2, config.NetDevConfig.GuestFwd2,
Expand Down
30 changes: 29 additions & 1 deletion manager/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import (

"github.com/digitalocean/go-libvirt"
"github.com/ultravioletrs/agent/agent"
"github.com/ultravioletrs/manager/internal"
"github.com/ultravioletrs/manager/manager/qemu"

"github.com/gofrs/uuid"
)

const firmwareVars = "OVMF_VARS"
const qcow2Img = "focal-server-cloudimg-amd64"

var (
// ErrMalformedEntity indicates malformed entity specification (e.g.
// invalid username or password).
Expand Down Expand Up @@ -89,6 +93,7 @@ func (ms *managerService) CreateLibvirtDomain(ctx context.Context, poolXML, volX
}

func (ms *managerService) CreateQemuVM(ctx context.Context) (*exec.Cmd, error) {
// create unique emu device identifiers
id, err := uuid.NewV4()
if err != nil {
return &exec.Cmd{}, err
Expand All @@ -99,15 +104,38 @@ func (ms *managerService) CreateQemuVM(ctx context.Context) (*exec.Cmd, error) {
qemuCfg.VirtioScsiPciConfig.ID = fmt.Sprintf("%s-%s", qemuCfg.VirtioScsiPciConfig.ID, id)
qemuCfg.SevConfig.ID = fmt.Sprintf("%s-%s", qemuCfg.SevConfig.ID, id)

exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
// copy firmware vars file
srcFile := qemuCfg.OVMFVarsConfig.File
dstFile := fmt.Sprintf("tmp/%s-%s.fd", firmwareVars, id)
err = internal.CopyFile(srcFile, dstFile)
if err != nil {
return &exec.Cmd{}, err
}
qemuCfg.OVMFVarsConfig.File = dstFile

// copy qcow2 img file
srcFile = qemuCfg.DiskImgConfig.File
dstFile = fmt.Sprintf("tmp/%s-%s.img", qcow2Img, id)
err = internal.CopyFile(srcFile, dstFile)
if err != nil {
return &exec.Cmd{}, err
}
qemuCfg.DiskImgConfig.File = dstFile

exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
if err != nil {
return &exec.Cmd{}, err
}
cmd, err := qemu.RunQemuVM(exe, args)
if err != nil {
return cmd, err
}

// different VM guests can't forward ports to the same ports on the same host
ms.qemuCfg.NetDevConfig.HostFwd1++
ms.qemuCfg.NetDevConfig.HostFwd2++
ms.qemuCfg.NetDevConfig.HostFwd3++

return cmd, nil
}

Expand Down

0 comments on commit b3ad784

Please sign in to comment.