From 36fa9644b4966f4a594c9113413fae9b9e79b8cd Mon Sep 17 00:00:00 2001 From: Othman Hendy Suseno Date: Sat, 15 Nov 2025 10:47:22 +0700 Subject: [PATCH] Add option to list storage --- README.md | 8 ++++--- go.mod | 2 +- go.sum | 1 + main.go | 22 +++++++++++++++++--- proxmox.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e9cfc31..5c6ee7f 100644 --- a/README.md +++ b/README.md @@ -160,18 +160,20 @@ proxmox-cloud-image -batch batch.txt | `-image-url` | - | URL cloud image (required) | | `-vm-name` | cloud-vm | Nama template | | `-vm-id` | 0 | Template ID (0 = auto-find dari 10000+) | -| `-storage` | local-lvm | Nama storage Proxmox | +| `-storage` | auto-detect | Nama storage Proxmox (auto-detect jika kosong) | | `-memory` | 2048 | Memory dalam MB | | `-cores` | 2 | Jumlah CPU cores | | `-disk-size` | 20G | Ukuran disk | | `-bridge` | vmbr0 | Network bridge | | `-vlan-tag` | 0 | VLAN tag (0 = no VLAN) | +| `-guest-agent` | false | Enable QEMU guest agent | +| `-firewall` | false | Enable firewall | | `-ssh-key` | - | Path ke SSH public key | | `-proxmox-host` | - | IP/hostname Proxmox (required) | | `-proxmox-user` | root@pam | Proxmox user | | `-proxmox-pass` | - | Proxmox password | -| `-guest-agent` | false | Enable QEMU Guest Agent | -| `-firewall` | false | Enable Proxmox firewall | +| `-list-storage` | - | List semua storage yang tersedia | +| `-ls` | - | Shorthand untuk `-list-storage` | ## How It Works diff --git a/go.mod b/go.mod index a12b2b3..bdbe56c 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/othman/proxmox-cloud-image go 1.22.2 -require gopkg.in/yaml.v3 v3.0.1 // indirect +require gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 4bc0337..a62c313 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 1c91efc..227de26 100644 --- a/main.go +++ b/main.go @@ -28,13 +28,16 @@ func main() { config := &Config{} var configFile string var batchFile string + var listStorage bool flag.StringVar(&configFile, "config", "", "Config file path (YAML)") flag.StringVar(&batchFile, "batch", "", "Batch file with multiple config paths (one per line)") + flag.BoolVar(&listStorage, "list-storage", false, "List available storage on Proxmox host") + flag.BoolVar(&listStorage, "ls", false, "List available storage on Proxmox host (shorthand)") flag.StringVar(&config.ImageURL, "image-url", "", "Cloud image URL to download") flag.StringVar(&config.VMName, "vm-name", "cloud-vm", "VM name") flag.IntVar(&config.VMID, "vm-id", 0, "VM ID (0 = auto-find from 10000+)") - flag.StringVar(&config.Storage, "storage", "local-lvm", "Proxmox storage name") + flag.StringVar(&config.Storage, "storage", "", "Proxmox storage name (auto-detect if empty)") flag.IntVar(&config.Memory, "memory", 2048, "Memory in MB") flag.IntVar(&config.Cores, "cores", 2, "CPU cores") flag.StringVar(&config.DiskSize, "disk-size", "20G", "Disk size (e.g., 20G)") @@ -44,9 +47,24 @@ func main() { flag.StringVar(&config.ProxmoxHost, "proxmox-host", "", "Proxmox host (e.g., 192.168.1.100)") flag.StringVar(&config.ProxmoxUser, "proxmox-user", "root@pam", "Proxmox user") flag.StringVar(&config.ProxmoxPass, "proxmox-pass", "", "Proxmox password") + flag.BoolVar(&config.GuestAgent, "guest-agent", false, "Enable QEMU guest agent") + flag.BoolVar(&config.Firewall, "firewall", false, "Enable firewall") flag.Parse() + // Handle storage listing + if listStorage || flag.Lookup("ls").Value.(flag.Getter).Get().(bool) { + if config.ProxmoxHost == "" { + fmt.Println("Error: -proxmox-host is required for storage listing") + os.Exit(1) + } + if err := listAvailableStorage(config); err != nil { + fmt.Fprintf(os.Stderr, "Error listing storage: %v\n", err) + os.Exit(1) + } + return + } + // Batch mode if batchFile != "" { if err := runBatch(batchFile); err != nil { @@ -56,8 +74,6 @@ func main() { fmt.Println("\nAll templates created successfully!") return } - - // Single config mode if configFile != "" { if err := loadConfigFile(configFile, config); err != nil { fmt.Fprintf(os.Stderr, "Error loading config file: %v\n", err) diff --git a/proxmox.go b/proxmox.go index fda166e..04c6f3c 100644 --- a/proxmox.go +++ b/proxmox.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "encoding/json" "fmt" "os" "os/exec" @@ -236,3 +237,63 @@ func createProxmoxVM(config *Config) error { return nil } + +func listAvailableStorage(config *Config) error { + fmt.Printf("Detecting available storage on %s...\n", config.ProxmoxHost) + + sshCmd := func(args ...string) *exec.Cmd { + fullArgs := []string{ + "-o", "StrictHostKeyChecking=no", + "-o", "UserKnownHostsFile=/dev/null", + fmt.Sprintf("%s@%s", strings.Split(config.ProxmoxUser, "@")[0], config.ProxmoxHost), + } + fullArgs = append(fullArgs, args...) + return exec.Command("ssh", fullArgs...) + } + + cmd := sshCmd("pvesm", "status", "--output-format", "json") + var stdout bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to get storage status: %w", err) + } + + // Parse JSON output + var storageList []map[string]interface{} + if err := json.Unmarshal(stdout.Bytes(), &storageList); err != nil { + return fmt.Errorf("failed to parse storage status: %w", err) + } + + fmt.Println("\nAvailable storage:") + fmt.Println("================") + + found := false + for _, storage := range storageList { + nameVal, ok := storage["storage"] + if !ok { + continue + } + name, _ := nameVal.(string) + + typeVal, _ := storage["type"] + typeStr, _ := typeVal.(string) + + activeVal, _ := storage["active"] + activeFloat, _ := activeVal.(float64) + + if activeFloat == 1 { + fmt.Printf("- %s (%s) - ACTIVE\n", name, typeStr) + found = true + } + } + + if !found { + fmt.Println("No active storage found!") + fmt.Println("\nManual check:") + fmt.Println(" ssh root@your-proxmox 'pvesm status'") + } + + return nil +}