143 lines
4.6 KiB
Go
143 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
type FirewallRule struct {
|
|
Type string `yaml:"type"`
|
|
Action string `yaml:"action"`
|
|
Protocol string `yaml:"protocol"`
|
|
Dport string `yaml:"dport"`
|
|
Sport string `yaml:"sport"`
|
|
Source string `yaml:"source"`
|
|
Dest string `yaml:"dest"`
|
|
Comment string `yaml:"comment"`
|
|
}
|
|
|
|
type Config struct {
|
|
ImageURL string `yaml:"image_url"`
|
|
VMName string `yaml:"vm_name"`
|
|
VMID int `yaml:"vm_id"`
|
|
Storage string `yaml:"storage"`
|
|
Memory int `yaml:"memory"`
|
|
Cores int `yaml:"cores"`
|
|
DiskSize string `yaml:"disk_size"`
|
|
Bridge string `yaml:"bridge"`
|
|
VlanTag int `yaml:"vlan_tag"`
|
|
SSHKey string `yaml:"ssh_key"`
|
|
ProxmoxHost string `yaml:"proxmox_host"`
|
|
ProxmoxUser string `yaml:"proxmox_user"`
|
|
ProxmoxPass string `yaml:"proxmox_pass"`
|
|
GuestAgent bool `yaml:"guest_agent"`
|
|
Firewall bool `yaml:"firewall"`
|
|
FirewallRules []FirewallRule `yaml:"firewall_rules"`
|
|
}
|
|
|
|
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 or local file path")
|
|
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", "", "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)")
|
|
flag.StringVar(&config.Bridge, "bridge", "vmbr0", "Network bridge")
|
|
flag.IntVar(&config.VlanTag, "vlan-tag", 0, "VLAN tag (optional, 0 = no VLAN)")
|
|
flag.StringVar(&config.SSHKey, "ssh-key", "", "SSH public key file path")
|
|
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", true, "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 {
|
|
fmt.Fprintf(os.Stderr, "Batch error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("\nAll templates created successfully!")
|
|
return
|
|
}
|
|
if configFile != "" {
|
|
if err := loadConfigFile(configFile, config); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error loading config file: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
if config.ImageURL == "" {
|
|
fmt.Println("Error: -image-url is required")
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
if config.ProxmoxHost == "" {
|
|
fmt.Println("Error: -proxmox-host is required")
|
|
flag.Usage()
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err := run(config); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
fmt.Println("Template created successfully!")
|
|
}
|
|
|
|
func run(config *Config) error {
|
|
if config.VMID == 0 {
|
|
fmt.Println("Auto-finding available VM ID starting from 10000...")
|
|
vmid, err := findAvailableVMID(config)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to find available VM ID: %w", err)
|
|
}
|
|
config.VMID = vmid
|
|
fmt.Printf("Found available VM ID: %d\n", vmid)
|
|
}
|
|
|
|
fmt.Printf("Creating template %s (ID: %d) on Proxmox host %s\n", config.VMName, config.VMID, config.ProxmoxHost)
|
|
|
|
if err := downloadOrCopyImage(config); err != nil {
|
|
return fmt.Errorf("failed to prepare image: %w", err)
|
|
}
|
|
|
|
if err := customizeImage(config); err != nil {
|
|
return fmt.Errorf("failed to customize image: %w", err)
|
|
}
|
|
|
|
if err := createProxmoxVM(config); err != nil {
|
|
return fmt.Errorf("failed to create Proxmox template: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|