Many minor fixes/improvements
This commit is contained in:
parent
443dbf684c
commit
a47b4fc0ec
9 changed files with 53 additions and 39 deletions
|
|
@ -88,7 +88,7 @@ func (bc *BuildContext) BuildWithInterruptHandler() error {
|
||||||
defer func() {
|
defer func() {
|
||||||
err := bc.vi.Cancel()
|
err := bc.vi.Cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.logger.Error("Failed to cancel VM context", "error", err)
|
bc.logger.Error("Failed to cancel VM context", "error", err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ func (bc *BuildContext) BuildWithInterruptHandler() error {
|
||||||
|
|
||||||
err := bc.vi.Cancel()
|
err := bc.vi.Cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Warn("Failed to cancel VM context", "error", err)
|
lg.Warn("Failed to cancel VM context", "error", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ var rootCmd = &cobra.Command{
|
||||||
|
|
||||||
bc, err := builder.NewBuildContext(slog.With("caller", "build-context"), baseISOPath, outImagePath, vmDebugFlag)
|
bc, err := builder.NewBuildContext(slog.With("caller", "build-context"), baseISOPath, outImagePath, vmDebugFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to create a new build context", "error", err)
|
slog.Error("Failed to create a new build context", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bc.BuildWithInterruptHandler()
|
err = bc.BuildWithInterruptHandler()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to build an image", "error", err)
|
slog.Error("Failed to build an image", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,16 @@ var lsCmd = &cobra.Command{
|
||||||
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
||||||
lsblkOut, err := fm.Lsblk()
|
lsblkOut, err := fm.Lsblk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to list block devices in the VM", "error", err)
|
slog.Error("Failed to list block devices in the VM", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print(string(lsblkOut))
|
if len(lsblkOut) == 0 {
|
||||||
|
fmt.Printf("<empty lsblk output>\n")
|
||||||
|
} else {
|
||||||
|
fmt.Print(string(lsblkOut))
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}, nil, false))
|
}, nil, false))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ func Execute() {
|
||||||
|
|
||||||
var vmDebugFlag bool
|
var vmDebugFlag bool
|
||||||
var unrestrictedNetworkingFlag bool
|
var unrestrictedNetworkingFlag bool
|
||||||
|
var vmMemAllocFlag uint64
|
||||||
|
|
||||||
|
// TODO: Version command.
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, nil)))
|
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, nil)))
|
||||||
|
|
@ -34,6 +37,7 @@ func init() {
|
||||||
rootCmd.AddCommand(runCmd)
|
rootCmd.AddCommand(runCmd)
|
||||||
rootCmd.AddCommand(shellCmd)
|
rootCmd.AddCommand(shellCmd)
|
||||||
|
|
||||||
rootCmd.PersistentFlags().BoolVar(&vmDebugFlag, "vmdebug", false, "Enable VM debug mode. This will open an accessible VM monitor. You can log in with root user and no password.")
|
rootCmd.PersistentFlags().BoolVar(&vmDebugFlag, "vmdebug", false, "Enables the VM debug mode. This will open an accessible VM monitor. You can log in with root user and no password.")
|
||||||
rootCmd.PersistentFlags().BoolVar(&unrestrictedNetworkingFlag, "unrestricted-networking", false, "Enable unrestricted networking. This will allow the VM to connect to the internet.")
|
rootCmd.PersistentFlags().BoolVar(&unrestrictedNetworkingFlag, "unrestricted-networking", false, "Enables unrestricted networking. This will allow the VM to connect to the internet.")
|
||||||
|
rootCmd.PersistentFlags().Uint64Var(&vmMemAllocFlag, "vm-mem-alloc", 512, "Specifies the VM memory allocation in KiB")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
cmd/run.go
10
cmd/run.go
|
|
@ -24,7 +24,7 @@ var runCmd = &cobra.Command{
|
||||||
|
|
||||||
networkSharePort, err := getClosestAvailPortWithSubsequent(9000, 10)
|
networkSharePort, err := getClosestAvailPortWithSubsequent(9000, 10)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get closest available host port for network file share", "error", err)
|
slog.Error("Failed to get closest available host port for network file share", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,18 +46,20 @@ var runCmd = &cobra.Command{
|
||||||
// TODO: `slog` library prints entire stack traces for errors which makes reading errors challenging.
|
// TODO: `slog` library prints entire stack traces for errors which makes reading errors challenging.
|
||||||
|
|
||||||
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
||||||
|
slog.Info("Mounting the device", "dev", vmMountDevName, "fs", fsType, "luks", luksFlag)
|
||||||
|
|
||||||
err := fm.Mount(vmMountDevName, vm.MountOptions{
|
err := fm.Mount(vmMountDevName, vm.MountOptions{
|
||||||
FSType: fsType,
|
FSType: fsType,
|
||||||
LUKS: luksFlag,
|
LUKS: luksFlag,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to mount the disk inside the VM", "error", err)
|
slog.Error("Failed to mount the disk inside the VM", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
sharePWD, err := password.Generate(16, 10, 0, false, false)
|
sharePWD, err := password.Generate(16, 10, 0, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to generate ephemeral password for network file share", "error", err)
|
slog.Error("Failed to generate ephemeral password for network file share", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,7 +69,7 @@ var runCmd = &cobra.Command{
|
||||||
|
|
||||||
err = fm.StartFTP([]byte(sharePWD), networkSharePort+1, ftpPassivePortCount)
|
err = fm.StartFTP([]byte(sharePWD), networkSharePort+1, ftpPassivePortCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to start FTP server", "error", err)
|
slog.Error("Failed to start FTP server", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
18
cmd/shell.go
18
cmd/shell.go
|
|
@ -32,7 +32,7 @@ var shellCmd = &cobra.Command{
|
||||||
|
|
||||||
fpr, err := vm.ParsePortForwardString(fp)
|
fpr, err := vm.ParsePortForwardString(fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to parse port forward string", "index", i, "value", fp, "error", err)
|
slog.Error("Failed to parse port forward string", "index", i, "value", fp, "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ var shellCmd = &cobra.Command{
|
||||||
os.Exit(runVM(passthroughArg, func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
os.Exit(runVM(passthroughArg, func(ctx context.Context, i *vm.VM, fm *vm.FileManager) int {
|
||||||
sc, err := i.DialSSH()
|
sc, err := i.DialSSH()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to dial VM SSH", "error", err)
|
slog.Error("Failed to dial VM SSH", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ var shellCmd = &cobra.Command{
|
||||||
|
|
||||||
sess, err := sc.NewSession()
|
sess, err := sc.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to create new VM SSH session", "error", err)
|
slog.Error("Failed to create new VM SSH session", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,14 +59,14 @@ var shellCmd = &cobra.Command{
|
||||||
termFD := int(os.Stdin.Fd())
|
termFD := int(os.Stdin.Fd())
|
||||||
termState, err := term.MakeRaw(termFD)
|
termState, err := term.MakeRaw(termFD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to make raw terminal", "error", err)
|
slog.Error("Failed to make raw terminal", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := term.Restore(termFD, termState)
|
err := term.Restore(termFD, termState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to restore terminal", "error", err)
|
slog.Error("Failed to restore terminal", "error", err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ var shellCmd = &cobra.Command{
|
||||||
|
|
||||||
termWidth, termHeight, err := term.GetSize(termFDGetSize)
|
termWidth, termHeight, err := term.GetSize(termFDGetSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to get terminal size", "error", err)
|
slog.Error("Failed to get terminal size", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ var shellCmd = &cobra.Command{
|
||||||
|
|
||||||
err = sess.RequestPty(term, termHeight, termWidth, termModes)
|
err = sess.RequestPty(term, termHeight, termWidth, termModes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to request VM SSH pty", "error", err)
|
slog.Error("Failed to request VM SSH pty", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,7 +105,7 @@ var shellCmd = &cobra.Command{
|
||||||
|
|
||||||
err = sess.Shell()
|
err = sess.Shell()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Start VM SSH shell", "error", err)
|
slog.Error("Start VM SSH shell", "error", err.Error())
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,7 +114,7 @@ var shellCmd = &cobra.Command{
|
||||||
go func() {
|
go func() {
|
||||||
err = sess.Wait()
|
err = sess.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to wait for VM SSH session to finish", "error", err)
|
slog.Error("Failed to wait for VM SSH session to finish", "error", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
doneCh <- struct{}{}
|
doneCh <- struct{}{}
|
||||||
|
|
|
||||||
16
cmd/utils.go
16
cmd/utils.go
|
|
@ -40,7 +40,7 @@ func doUSBRootCheck() {
|
||||||
|
|
||||||
ok, err := checkIfRoot()
|
ok, err := checkIfRoot()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to check whether the command is ran by root", "error", err)
|
slog.Error("Failed to check whether the command is ran by root", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,6 +64,8 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
SnapshotMode: true,
|
SnapshotMode: true,
|
||||||
}},
|
}},
|
||||||
|
|
||||||
|
MemoryAlloc: vmMemAllocFlag,
|
||||||
|
|
||||||
USBDevices: passthroughConfig,
|
USBDevices: passthroughConfig,
|
||||||
ExtraPortForwardingRules: forwardPortsRules,
|
ExtraPortForwardingRules: forwardPortsRules,
|
||||||
|
|
||||||
|
|
@ -74,7 +76,7 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
// TODO: Alpine image should be downloaded from somewhere.
|
// TODO: Alpine image should be downloaded from somewhere.
|
||||||
vi, err := vm.NewVM(slog.Default().With("caller", "vm"), vmCfg)
|
vi, err := vm.NewVM(slog.Default().With("caller", "vm"), vmCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to create vm instance", "error", err)
|
slog.Error("Failed to create vm instance", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,7 +117,7 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
|
|
||||||
err := vi.Cancel()
|
err := vi.Cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg.Warn("Failed to cancel VM context", "error", err)
|
lg.Warn("Failed to cancel VM context", "error", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -130,12 +132,12 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
err = fmt.Errorf("operation canceled by user")
|
err = fmt.Errorf("operation canceled by user")
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Error("Failed to start the VM", "error", err)
|
slog.Error("Failed to start the VM", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
case <-vi.SSHUpNotifyChan():
|
case <-vi.SSHUpNotifyChan():
|
||||||
err := fm.Init()
|
err := fm.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to initialize File Manager", "error", err)
|
slog.Error("Failed to initialize File Manager", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +145,7 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
|
|
||||||
err = vi.Cancel()
|
err = vi.Cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to cancel VM context", "error", err)
|
slog.Error("Failed to cancel VM context", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,7 +154,7 @@ func runVM(passthroughArg string, fn func(context.Context, *vm.VM, *vm.FileManag
|
||||||
select {
|
select {
|
||||||
case err := <-runErrCh:
|
case err := <-runErrCh:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to run the VM", "error", err)
|
slog.Error("Failed to run the VM", "error", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,6 @@ func (fm *FileManager) Init() error {
|
||||||
|
|
||||||
defer func() { _ = sc.Close() }()
|
defer func() { _ = sc.Close() }()
|
||||||
|
|
||||||
_, err = runSSHCmd(sc, "apk add util-linux lvm2")
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "install utilities")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = runSSHCmd(sc, "vgchange -ay")
|
_, err = runSSHCmd(sc, "vgchange -ay")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "run vgchange cmd")
|
return errors.Wrap(err, "run vgchange cmd")
|
||||||
|
|
@ -110,7 +105,7 @@ func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string) error {
|
||||||
return errors.Wrap(err, "start cryptsetup luksopen cmd")
|
return errors.Wrap(err, "start cryptsetup luksopen cmd")
|
||||||
}
|
}
|
||||||
|
|
||||||
lg.Info("Attempting to open LUKS device")
|
lg.Info("Attempting to open a LUKS device")
|
||||||
|
|
||||||
_, err = os.Stderr.Write([]byte("Enter Password: "))
|
_, err = os.Stderr.Write([]byte("Enter Password: "))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -140,6 +135,10 @@ func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string) error {
|
||||||
|
|
||||||
err = sess.Wait()
|
err = sess.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if strings.Contains(stderrBuf.String(), "Not enough available memory to open a keyslot.") {
|
||||||
|
fm.logger.Warn("Detected not enough memory to open a LUKS device, please allocate more memory using --vm-mem-alloc flag.")
|
||||||
|
}
|
||||||
|
|
||||||
return utils.WrapErrWithLog(err, "wait for cryptsetup luksopen cmd to finish", stderrBuf.String())
|
return utils.WrapErrWithLog(err, "wait for cryptsetup luksopen cmd to finish", stderrBuf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,11 +267,11 @@ pasv_address=127.0.0.1
|
||||||
go func() {
|
go func() {
|
||||||
_, err = stdinPipe.Write(pwd)
|
_, err = stdinPipe.Write(pwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fm.vm.logger.Error("Failed to write FTP password to passwd stdin", "error", err)
|
fm.vm.logger.Error("Failed to write FTP password to passwd stdin", "error", err.Error())
|
||||||
}
|
}
|
||||||
_, err = stdinPipe.Write(pwd)
|
_, err = stdinPipe.Write(pwd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fm.vm.logger.Error("Failed to write repeated FTP password to passwd stdin", "error", err)
|
fm.vm.logger.Error("Failed to write repeated FTP password to passwd stdin", "error", err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
||||||
8
vm/vm.go
8
vm/vm.go
|
|
@ -61,6 +61,8 @@ type VMConfig struct {
|
||||||
CdromImagePath string
|
CdromImagePath string
|
||||||
Drives []DriveConfig
|
Drives []DriveConfig
|
||||||
|
|
||||||
|
MemoryAlloc uint64 // In KiB.
|
||||||
|
|
||||||
USBDevices []USBDevicePassthroughConfig
|
USBDevices []USBDevicePassthroughConfig
|
||||||
ExtraPortForwardingRules []PortForwardingRule
|
ExtraPortForwardingRules []PortForwardingRule
|
||||||
|
|
||||||
|
|
@ -84,7 +86,7 @@ func NewVM(logger *slog.Logger, cfg VMConfig) (*VM, error) {
|
||||||
|
|
||||||
// TODO: Configurable memory allocation
|
// TODO: Configurable memory allocation
|
||||||
|
|
||||||
cmdArgs := []string{"-serial", "stdio", "-m", "2048", "-smp", fmt.Sprint(runtime.NumCPU())}
|
cmdArgs := []string{"-serial", "stdio", "-m", fmt.Sprint(cfg.MemoryAlloc), "-smp", fmt.Sprint(runtime.NumCPU())}
|
||||||
|
|
||||||
baseCmd := "qemu-system"
|
baseCmd := "qemu-system"
|
||||||
|
|
||||||
|
|
@ -319,14 +321,14 @@ func (vm *VM) Cancel() error {
|
||||||
sc, err := vm.DialSSH()
|
sc, err := vm.DialSSH()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, ErrSSHUnavailable) {
|
if !errors.Is(err, ErrSSHUnavailable) {
|
||||||
vm.logger.Warn("Failed to dial VM SSH to do graceful shutdown", "error", err)
|
vm.logger.Warn("Failed to dial VM SSH to do graceful shutdown", "error", err.Error())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vm.logger.Warn("Sending poweroff command to the VM")
|
vm.logger.Warn("Sending poweroff command to the VM")
|
||||||
_, err = runSSHCmd(sc, "poweroff")
|
_, err = runSSHCmd(sc, "poweroff")
|
||||||
_ = sc.Close()
|
_ = sc.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
vm.logger.Warn("Could not power off the VM safely", "error", err)
|
vm.logger.Warn("Could not power off the VM safely", "error", err.Error())
|
||||||
} else {
|
} else {
|
||||||
vm.logger.Info("Shutting the VM down safely")
|
vm.logger.Info("Shutting the VM down safely")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue