Better VM runtime logic

This commit is contained in:
AlexSSD7 2023-09-02 11:47:58 +01:00
commit 7b5391f4d8
7 changed files with 165 additions and 220 deletions

View file

@ -1,19 +1,16 @@
package cmd
import (
"context"
"fmt"
"os"
"os/signal"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
"log/slog"
"github.com/AlexSSD7/linsk/cmd/runvm"
"github.com/AlexSSD7/linsk/nettap"
"github.com/AlexSSD7/linsk/osspecifics"
"github.com/AlexSSD7/linsk/share"
@ -32,9 +29,7 @@ func createStoreOrExit() *storage.Storage {
return store
}
type runVMFunc func(context.Context, *vm.VM, *vm.FileManager, *share.NetTapRuntimeContext) int
func runVM(passthroughArg string, fn runVMFunc, forwardPortsRules []vm.PortForwardingRule, unrestrictedNetworking bool, withNetTap bool) int {
func runVM(passthroughArg string, fn runvm.RunVMFunc, forwardPortsRules []vm.PortForwardingRule, unrestrictedNetworking bool, withNetTap bool) int {
store := createStoreOrExit()
vmImagePath, err := store.CheckVMImageExists()
@ -197,116 +192,13 @@ func runVM(passthroughArg string, fn runVMFunc, forwardPortsRules []vm.PortForwa
ShowDisplay: vmDebugFlag,
}
return innerRunVM(vmCfg, tapRuntimeCtx, fn)
}
func innerRunVM(vmCfg vm.VMConfig, tapRuntimeCtx *share.NetTapRuntimeContext, fn runVMFunc) int {
vi, err := vm.NewVM(slog.Default().With("caller", "vm"), vmCfg)
if err != nil {
slog.Error("Failed to create vm instance", "error", err.Error())
return 1
}
runErrCh := make(chan error, 1)
var wg sync.WaitGroup
ctx, ctxCancel := context.WithCancel(context.Background())
defer ctxCancel()
interrupt := make(chan os.Signal, 2)
signal.Notify(interrupt, syscall.SIGTERM, syscall.SIGINT)
wg.Add(1)
go func() {
defer wg.Done()
err := vi.Run()
ctxCancel()
runErrCh <- err
}()
go func() {
for i := 0; ; i++ {
select {
case <-ctx.Done():
signal.Reset()
return
case sig := <-interrupt:
lg := slog.With("signal", sig)
switch {
case i == 0:
lg.Warn("Caught interrupt, safely shutting down")
case i < 10:
lg.Warn("Caught subsequent interrupt, please interrupt n more times to panic", "n", 10-i)
default:
panic("force interrupt")
}
err := vi.Cancel()
if err != nil {
lg.Warn("Failed to cancel VM context", "error", err.Error())
}
}
}
}()
fm := vm.NewFileManager(slog.Default().With("caller", "file-manager"), vi)
for {
select {
case err := <-runErrCh:
if err == nil {
err = fmt.Errorf("operation canceled by user")
}
slog.Error("Failed to start the VM", "error", err.Error())
return 1
case <-vi.SSHUpNotifyChan():
err := fm.Init()
if err != nil {
slog.Error("Failed to initialize File Manager", "error", err.Error())
return 1
}
startupFailed := false
if tapRuntimeCtx != nil {
err := vi.ConfigureInterfaceStaticNet(context.Background(), "eth1", tapRuntimeCtx.Net.GuestCIDR)
if err != nil {
slog.Error("Failed to configure tag interface network", "error", err.Error())
startupFailed = true
}
}
var exitCode int
if !startupFailed {
exitCode = fn(ctx, vi, fm, tapRuntimeCtx)
} else {
exitCode = 1
}
err = vi.Cancel()
if err != nil {
slog.Error("Failed to cancel VM context", "error", err.Error())
return 1
}
wg.Wait()
select {
case err := <-runErrCh:
if err != nil {
slog.Error("Failed to run the VM", "error", err.Error())
return 1
}
default:
}
return exitCode
}
}
return runvm.RunVM(vi, true, tapRuntimeCtx, fn)
}
func getDevicePassthroughConfig(val string) (*vm.PassthroughConfig, error) {