Add root check and prettier tables

This commit is contained in:
markmental 2025-12-15 16:01:02 -05:00
commit d404c25219

100
main.go
View file

@ -54,6 +54,13 @@ var osImages = map[string]OSImage{
}, },
} }
func requireRoot() {
if os.Geteuid() != 0 {
fmt.Fprintln(os.Stderr, "mnmivm must be run as root. Try: `sudo mnmivm` or login as the root user")
os.Exit(1)
}
}
func ensureDirs() { func ensureDirs() {
for _, d := range []string{imageDir, vmDirBase} { for _, d := range []string{imageDir, vmDirBase} {
if err := os.MkdirAll(d, 0755); err != nil { if err := os.MkdirAll(d, 0755); err != nil {
@ -176,6 +183,64 @@ disable_root: true
} }
} }
func renderBoxTable(headers []string, rows [][]string) {
colWidths := make([]int, len(headers))
// compute column widths
for i, h := range headers {
colWidths[i] = len(h)
}
for _, row := range rows {
for i, cell := range row {
if len(cell) > colWidths[i] {
colWidths[i] = len(cell)
}
}
}
// helpers
repeat := func(s string, n int) string {
return strings.Repeat(s, n)
}
drawRow := func(left, mid, right string) {
fmt.Print(left)
for i, w := range colWidths {
fmt.Print(repeat("─", w+2))
if i < len(colWidths)-1 {
fmt.Print(mid)
}
}
fmt.Println(right)
}
// top border
drawRow("┌", "┬", "┐")
// header row
fmt.Print("│")
for i, h := range headers {
fmt.Printf(" %-*s │", colWidths[i], h)
}
fmt.Println()
// header separator
drawRow("├", "┼", "┤")
// data rows
for _, row := range rows {
fmt.Print("│")
for i, cell := range row {
fmt.Printf(" %-*s │", colWidths[i], cell)
}
fmt.Println()
}
// bottom border
drawRow("└", "┴", "┘")
}
func createVM(name, osName, pubKeyPath string) { func createVM(name, osName, pubKeyPath string) {
if _, ok := osImages[osName]; !ok { if _, ok := osImages[osName]; !ok {
panic("unsupported OS: " + osName) panic("unsupported OS: " + osName)
@ -298,9 +363,16 @@ func vmRunning(name string) bool {
func listVMs() { func listVMs() {
entries, _ := os.ReadDir(vmDirBase) entries, _ := os.ReadDir(vmDirBase)
fmt.Printf("%-12s %-8s %-8s %-16s %-16s %s\n", headers := []string{
"NAME", "STATE", "OS", "SSH", "VNC", "PUBKEY") "NAME",
fmt.Println(strings.Repeat("-", 90)) "STATE",
"OS",
"SSH",
"VNC",
"PUBKEY",
}
rows := [][]string{}
for _, e := range entries { for _, e := range entries {
name := e.Name() name := e.Name()
@ -312,6 +384,7 @@ func listVMs() {
} }
osName := readFileTrim(filepath.Join(dir, "os.name")) osName := readFileTrim(filepath.Join(dir, "os.name"))
sshPort := readFileTrim(filepath.Join(dir, "ssh.port")) sshPort := readFileTrim(filepath.Join(dir, "ssh.port"))
vncPort := readFileTrim(filepath.Join(dir, "vnc.port")) vncPort := readFileTrim(filepath.Join(dir, "vnc.port"))
@ -325,12 +398,27 @@ func listVMs() {
vnc = "0.0.0.0:" + vncPort vnc = "0.0.0.0:" + vncPort
} }
fmt.Printf("%-12s %-8s %-8s %-16s %-16s %s\n", rows = append(rows, []string{
name, state, osName, ssh, vnc, vmPubKeyPath(name)) name,
} state,
osName,
ssh,
vnc,
vmPubKeyPath(name),
})
} }
if len(rows) == 0 {
fmt.Println("No VMs found.")
return
}
renderBoxTable(headers, rows)
}
func main() { func main() {
requireRoot()
if len(os.Args) < 2 { if len(os.Args) < 2 {
usage() usage()
} }