vcenter

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 1, 2025 License: MIT Imports: 34 Imported by: 0

README

vcenter - PowerCLI-inspired Go API for VMware vCenter

A user-friendly Go library for VMware vCenter, inspired by PowerCLI. This package wraps govmomi and provides a simpler, more intuitive API for common vCenter operations.

Features

  • Easy Authentication

    • Username/password with session caching
    • Windows SSPI/Kerberos (single sign-on)
    • Automatic session management via go-vcenter-auth
  • VM Management

    • Clone VMs from templates
    • Windows and Linux customization (domain join, static IP, multi-NIC)
    • CPU and memory configuration
    • Power operations (on/off/restart)
    • Delete and unregister VMs
    • Get detailed VM information
    • Support for datastore clusters (Storage DRS)
  • Guest Customization

    • Windows Sysprep with domain join or workgroup
    • Linux customization
    • Multi-NIC support with per-adapter IP configuration
    • MachineObjectOU for AD placement
    • Autologon support
    • Reliable customization completion detection (hostname-based)
  • Snapshot Operations

    • Create, delete, revert snapshots
    • List all snapshots
    • Get current snapshot
    • Delete all snapshots
  • Excel-based VM Provisioning

    • Create Excel templates with dropdowns and validation
    • Validate Excel files before deployment
    • Convert Excel to JSON for automation pipelines
    • Multi-NIC, multi-disk support in Excel format
  • Configuration & Secrets Management

    • JSON configuration files with validation
    • Encrypted credential storage (AES-256-GCM + Argon2)
    • Multiple key sources (environment variable, file, direct)
    • Password-based encryption for simpler workflows
  • Inventory Scanning

    • Scan vCenter for all assets (templates, clusters, networks, etc.)
    • Per-datacenter or flattened global lists
    • Perfect for populating Excel dropdowns dynamically
  • Disk Management

    • Add new disks
    • Extend existing disks
    • Remove disks
  • Network Management

    • Add network adapters
    • Change network on existing adapters
  • CD/DVD Operations

    • Mount/unmount ISO files
    • Connect/disconnect CD/DVD drives
  • Guest Operations (requires VMware Tools)

    • File upload/download
    • Script execution
    • Directory operations

Installation

go get github.com/skabbio1976/vcenter

Quick Start

Full examples: See the examples/ directory for complete, runnable code.

Connect with SSPI (Windows)

Full example: examples/01-connect-sspi/

package main

import (
    "context"
    "log"

    "github.com/skabbio1976/vcenter"
)

func main() {
    ctx := context.Background()

    // Connect with Windows integrated auth (SSPI)
    client, err := vcenter.ConnectWithSSPI(
        ctx,
        "vcenter.example.com",
        true,          // insecure (skip TLS verification)
        "Datacenter1", // datacenter name
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Logout(ctx)

    log.Println("Connected to vCenter!")
}
Connect with username/password

Full example: examples/02-connect-password/

config := vcenter.ConnectConfig{
    Host:       "vcenter.example.com",
    Username:   "administrator@vsphere.local",
    Password:   "password",
    Insecure:   true,
    Datacenter: "Datacenter1",
}

client, err := vcenter.ConnectWithPassword(ctx, config)
if err != nil {
    log.Fatal(err)
}
defer client.Logout(ctx)

Exported Types and Functions

Types
Type Description
NetworkAdapter Network adapter configuration for multi-NIC customization
WindowsCustomizationConfig All settings for Windows customization (domain, IP, autologon, etc.)
LinuxCustomizationConfig All settings for Linux customization
ServerRequest Structured VM request with full configuration
SnapshotInfo Snapshot metadata
VMInfo Detailed VM information
NetworkInfo Network adapter information
ExcelValidValues Dropdown values for Excel template
ExcelVMConfig VM configuration parsed from Excel
VCenterConfig JSON configuration for vCenter connection and defaults
Credential Single credential entry (server, username, password)
CredentialStore Encrypted credential storage
KeySource Key source for encryption (env, file, or direct)
VCenterInventory Scanned vCenter assets (templates, clusters, networks, etc.)
InventoryOptions Options for ScanVCenter (include/exclude sections)
Customization Functions
Function Description
NewWindowsCustomization(cfg) Create Windows customization spec (supports all scenarios)
NewLinuxCustomization(cfg) Create Linux customization spec (supports all scenarios)
Clone Functions
Function Description
CloneVM() Clone VM without customization (powered off)
CloneVMWithCustomization() Clone VM with customization (powers on)
CloneFromRequest() Clone from ServerRequest with correct operation order
Wait Functions
Function Description
WaitForCustomization() Wait for guest customization to complete (hostname-based detection)
WaitForTools() Wait for VMware Tools to be ready
WaitForIP() Wait for VM to get a routable IP address
Power Functions
Function Description
PowerOnVM() Power on a VM
PowerOffVM() Power off a VM
RestartVM() Restart a VM (graceful or hard)
Disk Functions
Function Description
AddDisk() Add a new disk to VM
ExtendDisk() Extend existing disk
RemoveDisk() Remove disk from VM
Network Functions
Function Description
AddNetworkAdapter() Add network adapter
ChangeNetwork() Change network on adapter
Snapshot Functions
Function Description
CreateSnapshot() Create snapshot
DeleteSnapshot() Delete snapshot
ListSnapshots() List all snapshots
RevertToSnapshot() Revert to snapshot
DeleteAllSnapshots() Delete all snapshots
GetCurrentSnapshot() Get current snapshot
Excel Functions
Function Description
CreateExcelTemplate() Create Excel template with dropdowns and validation
ValidateExcel() Validate Excel file before deployment
ExcelToJSON() Convert Excel rows to JSON (individual files + combined)
DefaultExcelValidValues() Get default dropdown values
Configuration Functions
Function Description
LoadVCenterConfig() Load configuration from JSON file
CreateVCenterConfigTemplate() Create config template with comments
EnsureConfigFile() Create config if it doesn't exist
DefaultVCenterConfig() Get default configuration values
Secrets/Credential Functions
Function Description
NewCredentialStore() Create empty credential store
LoadEncryptedCredentialStore() Load encrypted credentials with KeySource
LoadEncryptedCredentialStoreWithPassword() Load credentials with password
GenerateEncryptionKey() Generate random 32-byte hex key
KeySourceEnv() Use environment variable as key
KeySourceFile() Use file contents as key
KeySourceDirect() Use string directly as key
EncryptString() / DecryptString() Encrypt/decrypt strings
Inventory Functions
Function Description
ScanVCenter() Scan vCenter for all assets
VCenterInventory.ToFlat() Flatten per-datacenter maps to global lists
Other Functions
Function Description
GetVM() Find VM by name
GetVMInfo() Get detailed VM info
SetVMResources() Change CPU/memory
DeleteVM() Delete VM
UnregisterVM() Unregister VM
MountISO() / UnmountISO() ISO operations
ConnectCDROM() / DisconnectCDROM() CD/DVD operations
Guest Operations Functions (requires VMware Tools)
Function Description
UploadFileToVM() Upload file to guest OS
DownloadFileFromVM() Download file from guest OS
UploadDirectoryToVM() Upload entire directory (zip → upload → extract)
DownloadDirectoryFromVM() Download entire directory (zip → download → extract)
RunScriptOnVM() Execute script/program on guest OS
UploadAndRunScript() Upload and execute script (convenience)

Examples

Clone a VM

Full example: examples/03-simple-clone/

vm, err := vcenter.CloneVM(
    ctx,
    client.Client,
    "Windows-2022-Template", // template name
    "WebServer01",           // new VM name
    "Datacenter1",           // datacenter
    "datastore1",            // datastore
    "Resources",             // resource pool
    "WebServers",            // folder (or "" for default)
)
if err != nil {
    log.Fatal(err)
}

log.Printf("VM cloned: %s\n", vm.Name())
Clone with Windows customization (domain join, DHCP)

Full example: examples/04-clone-with-customization/

// Create customization spec for domain join with DHCP
customization := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:   "WebServer01",
    AdminPassword:  "localAdminPassword",
    Timezone:       85, // W. Europe Standard Time
    Domain:         "example.com",
    DomainUser:     "administrator@example.com",
    DomainPassword: "domainPassword",
    GlobalDNS:      []string{"192.168.1.1"},
    DNSSuffixes:    []string{"example.com"},
})

// Clone VM with customization
vm, err := vcenter.CloneVMWithCustomization(
    ctx,
    client.Client,
    "Windows-2022-Template",
    "WebServer01",
    "Datacenter1",
    "datastore1",
    "Resources",
    "WebServers",
    customization,
)
if err != nil {
    log.Fatal(err)
}

// Wait for customization to complete (recommended!)
err = vcenter.WaitForCustomization(ctx, vm, 15*time.Minute)
if err != nil {
    log.Printf("Warning: Customization timeout: %v\n", err)
}

log.Printf("VM ready! IP: check with GetVMInfo()")
Clone with static IP

Full example: examples/05-clone-static-ip/

customization := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:   "DBServer01",
    AdminPassword:  "localAdminPassword",
    Timezone:       85,
    Domain:         "example.com",
    DomainUser:     "administrator@example.com",
    DomainPassword: "domainPassword",
    // Static IP via Adapters
    Adapters: []vcenter.NetworkAdapter{{
        IPAddress:  "192.168.1.100",
        SubnetMask: "255.255.255.0",
        Gateway:    "192.168.1.1",
        DNSServers: []string{"192.168.1.1"},
    }},
    GlobalDNS:   []string{"192.168.1.1"},
    DNSSuffixes: []string{"example.com"},
})

vm, err := vcenter.CloneVMWithCustomization(ctx, client.Client,
    "Windows-2022-Template", "DBServer01", "Datacenter1",
    "datastore1", "Resources", "", customization)
Clone with multi-NIC configuration
customization := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:   "AppServer01",
    AdminPassword:  "localAdminPassword",
    Timezone:       85,
    Domain:         "example.com",
    DomainUser:     "administrator@example.com",
    DomainPassword: "domainPassword",
    MachineObjectOU: "OU=Servers,DC=example,DC=com", // Place in specific OU
    // Multiple network adapters
    Adapters: []vcenter.NetworkAdapter{
        {
            Network:    "Production-VLAN100",
            IPAddress:  "10.1.1.50",
            SubnetMask: "255.255.255.0",
            Gateway:    "10.1.1.1",
            DNSServers: []string{"10.1.1.10"},
        },
        {
            Network:    "Management-VLAN200",
            IPAddress:  "10.2.1.50",
            SubnetMask: "255.255.255.0",
            Gateway:    "10.2.1.1",
        },
    },
    GlobalDNS:      []string{"10.1.1.10"},
    DNSSuffixes:    []string{"example.com"},
    AutologonCount: 1, // Auto-login once for post-install scripts
})
Clone standalone Windows (workgroup, no domain)
customization := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:  "TestServer01",
    AdminPassword: "localAdminPassword",
    Timezone:      85,
    // No Domain = joins WORKGROUP
    Adapters: []vcenter.NetworkAdapter{{
        IPAddress:  "192.168.1.200",
        SubnetMask: "255.255.255.0",
        Gateway:    "192.168.1.1",
    }},
})

Full example: examples/10-server-request/

req := vcenter.ServerRequest{
    Name:     "AppServer01",
    Template: "Windows-2022-Template",
    CPUs:     4,
    MemoryGB: 16,
    // Multiple disks (D:, E:, F:, ...)
    DisksGB: []int{100, 200}, // D: 100GB, E: 200GB
    // Multi-NIC
    Adapters: []vcenter.NetworkAdapter{
        {IPAddress: "192.168.1.101", SubnetMask: "255.255.255.0", Gateway: "192.168.1.1"},
        {IPAddress: "10.0.0.101", SubnetMask: "255.255.255.0", Gateway: "10.0.0.1"},
    },
    Domain:          "example.com",
    MachineObjectOU: "OU=AppServers,DC=example,DC=com",
    DNSServers:      []string{"192.168.1.1", "192.168.1.2"},
    DNSSuffixes:     []string{"example.com"},
    AutologonCount:  1,
}

// CloneFromRequest implements the CORRECT operation order:
// 1. Clone with powerOn=false
// 2. Add disks (VM off)
// 3. Set CPU/memory (VM off)
// 4. Power on (triggers customization)
// 5. WaitForCustomization
vm, err := vcenter.CloneFromRequest(
    ctx,
    client.Client,
    req,
    "Datacenter1",
    "datastore1",
    "Resources",
    "AppServers",
    "administrator@example.com",
    "domainPassword",
    "localAdminPassword",
    85, // timezone
)
Linux customization
// Linux with DHCP
customization := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname:    "webserver01",
    Domain:      "example.com",
    GlobalDNS:   []string{"192.168.1.1"},
    DNSSuffixes: []string{"example.com"},
})

// Linux with static IP
customization := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname: "webserver02",
    Domain:   "example.com",
    Adapters: []vcenter.NetworkAdapter{{
        IPAddress:  "192.168.1.150",
        SubnetMask: "255.255.255.0",
        Gateway:    "192.168.1.1",
    }},
    GlobalDNS:   []string{"192.168.1.1"},
    DNSSuffixes: []string{"example.com"},
})

// Linux multi-NIC
customization := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname: "appserver01",
    Domain:   "example.com",
    Adapters: []vcenter.NetworkAdapter{
        {IPAddress: "10.1.1.20", SubnetMask: "255.255.255.0", Gateway: "10.1.1.1"},
        {IPAddress: "10.2.1.20", SubnetMask: "255.255.255.0", Gateway: "10.2.1.1"},
    },
    GlobalDNS: []string{"10.1.1.1"},
})

vm, err := vcenter.CloneVMWithCustomization(
    ctx, client.Client,
    "Ubuntu-22.04-Template", "webserver01",
    "Datacenter1", "datastore1", "Resources", "",
    customization,
)
Clone multiple VMs in parallel (using goroutines)

Full example: examples/06-batch-clone/

The API does not provide batch functions by design - you control your own concurrency:

requests := []vcenter.ServerRequest{
    {Name: "Web01", Template: "Windows-2022-Template", CPUs: 2, MemoryGB: 4, Domain: "example.com"},
    {Name: "Web02", Template: "Windows-2022-Template", CPUs: 2, MemoryGB: 4, Domain: "example.com"},
    {Name: "Web03", Template: "Windows-2022-Template", CPUs: 2, MemoryGB: 4, Domain: "example.com"},
}

var wg sync.WaitGroup
results := make([]error, len(requests))

for i, req := range requests {
    wg.Add(1)
    go func(idx int, r vcenter.ServerRequest) {
        defer wg.Done()
        _, err := vcenter.CloneFromRequest(ctx, client.Client, r,
            "Datacenter1", "datastore1", "Resources", "WebServers",
            "administrator@example.com", "domainPassword", "localAdminPassword", 85)
        results[idx] = err
    }(i, req)
}

wg.Wait()

for i, err := range results {
    if err != nil {
        log.Printf("Failed: %s: %v\n", requests[i].Name, err)
    } else {
        log.Printf("Success: %s\n", requests[i].Name)
    }
}
Power operations

Full example: examples/07-bulk-power/

vm, err := vcenter.GetVM(ctx, client.Client, "WebServer01", "Datacenter1")
if err != nil {
    log.Fatal(err)
}

err = vcenter.PowerOnVM(ctx, vm)
err = vcenter.PowerOffVM(ctx, vm)
err = vcenter.RestartVM(ctx, vm) // Graceful with Tools, otherwise hard reset
Disk management

Full example: examples/08-disk-operations/

err = vcenter.AddDisk(ctx, vm, 100, "datastore1")    // Add 100GB disk
err = vcenter.ExtendDisk(ctx, vm, "Hard disk 2", 200) // Extend to 200GB
err = vcenter.RemoveDisk(ctx, vm, "Hard disk 3")      // Remove disk
Network management

Full example: examples/09-network-operations/

err = vcenter.AddNetworkAdapter(ctx, vm, "Production-VLAN100")
err = vcenter.ChangeNetwork(ctx, vm, "Network adapter 1", "DMZ-VLAN200")
Change CPU and memory
err = vcenter.SetVMResources(ctx, vm, 4, 8192) // 4 CPUs, 8GB RAM
Snapshot operations
err = vcenter.CreateSnapshot(ctx, vm, "Before Update", "Snapshot before updates", false, true)
snapshots, err := vcenter.ListSnapshots(ctx, vm)
err = vcenter.RevertToSnapshot(ctx, vm, "Before Update", false)
err = vcenter.DeleteSnapshot(ctx, vm, "Before Update", false, true)
err = vcenter.DeleteAllSnapshots(ctx, vm, true)
current, err := vcenter.GetCurrentSnapshot(ctx, vm)
Get detailed VM information
info, err := vcenter.GetVMInfo(ctx, vm)
fmt.Printf("VM: %s\n", info.Name)
fmt.Printf("Power State: %s\n", info.PowerState)
fmt.Printf("CPUs: %d\n", info.CPUCount)
fmt.Printf("Memory: %.2f GB\n", info.MemoryGB)
fmt.Printf("IP Address: %s\n", info.GuestIPAddress)
fmt.Printf("Hostname: %s\n", info.GuestHostname)
Delete or unregister VM
err = vcenter.DeleteVM(ctx, vm, true, false)  // Delete VM and files
err = vcenter.UnregisterVM(ctx, vm)           // Unregister only (keep files)
err = vcenter.DeleteVM(ctx, vm, true, true)   // Force delete powered-on VM
CD/DVD operations
err = vcenter.MountISO(ctx, vm, "ISOs/windows.iso", "datastore1", true)
err = vcenter.UnmountISO(ctx, vm, true)
err = vcenter.ConnectCDROM(ctx, vm)
err = vcenter.DisconnectCDROM(ctx, vm)
Using Datastore Clusters (Storage DRS)

All clone functions automatically detect datastore clusters and use Storage DRS:

// Works with both regular datastores and datastore clusters
vm, err := vcenter.CloneVM(ctx, client.Client,
    "Windows-2022-Template", "WebServer01",
    "Datacenter1", "Production-DatastoreCluster", // <- datastore cluster
    "Resources", "WebServers")

Excel-based VM Provisioning

Full example: examples/11-config-and-excel/

Create professional Excel templates for VM requests, validate them, and convert to JSON for automation:

Create Excel template
// Create template with default dropdown values
err := vcenter.CreateExcelTemplate("vm_requests.xlsx", nil)

// Or customize the dropdown values
values := vcenter.DefaultExcelValidValues()
values.Templates = []string{"Win2022-Prod", "Win2022-Dev", "Ubuntu2204"}
values.PortGroups = []string{"VLAN-100-Prod", "VLAN-200-Dev", "VLAN-300-Mgmt"}
values.Domains = []string{"prod.example.com", "dev.example.com"}

err := vcenter.CreateExcelTemplate("vm_requests.xlsx", &values)

The template includes:

  • VM Requests sheet with all columns (VM name, template, network, CPU, memory, disks, domain, etc.)
  • Valid Values sheet with dropdown source data
  • Instruktioner sheet with usage instructions
  • Data validation dropdowns in key columns
  • Example rows to guide users
Validate Excel before deployment
// Basic validation
valid, messages, err := vcenter.ValidateExcel("vm_requests.xlsx", nil, false)
if !valid {
    for _, msg := range messages {
        log.Println(msg)
    }
}

// Strict validation (warnings become errors)
valid, messages, err := vcenter.ValidateExcel("vm_requests.xlsx", nil, true)

Validates:

  • Required columns exist
  • No duplicate VM names
  • Valid CPU/memory values
  • Network configuration (IP requires subnet + gateway)
  • Disk provisioning values (thin/thick)
Convert Excel to JSON
// Parse Excel and write JSON files
configs, err := vcenter.ExcelToJSON("vm_requests.xlsx", "output/")
// Creates:
//   output/DC-PROD-01.json
//   output/SQL-PROD-01.json
//   output/_all_vms.json (combined)

// Or just parse without writing files
configs, err := vcenter.ExcelToJSON("vm_requests.xlsx", "")
for _, cfg := range configs {
    log.Printf("VM: %s, Template: %s, CPUs: %d\n",
        cfg.VMName, cfg.Template, cfg.Hardware.NumCPUs)
}
Excel columns
Column Description Example
vm_name VM name DC-PROD-01
template Template name Windows2022-Template
datacenter Datacenter DC-Stockholm
compute_cluster Compute cluster Prod-Cluster
storage_cluster Storage cluster (or datastore) VSAN-Cluster-01
folder VM folder path Production/Infrastructure
port_group_1 First NIC network VLAN-100-Prod
ip_1 IP (or "DHCP") 10.20.30.10
subnet_mask_1 Subnet mask 255.255.255.0
gateway_1 Default gateway 10.20.30.1
dns_servers_1 DNS (semicolon-separated) 10.20.1.10;10.20.1.11
port_group_2/3 Additional NICs (optional)
num_cpus CPU count 4
memory_mb Memory in MB 8192
disk_gb Extra disks (semicolon-separated) 50;100;200
disk_provisioning thin or thick thin
server_role Server role DC, SQL, Web
hostname Computer name DC-PROD-01
domain Domain to join corp.example.com
domain_join_user Domain join account svc_domainjoin
ou_path AD OU path OU=Servers,DC=corp,DC=com
autologon_count Auto-login count 3
timezone Windows timezone W. Europe Standard Time
run_once_commands Post-install commands powershell.exe -File setup.ps1

Configuration Management

Create and load configuration
// Create a config template (with helpful comments)
err := vcenter.CreateVCenterConfigTemplate("vcenter_config.json")

// Or ensure config exists (creates if missing)
created, err := vcenter.EnsureConfigFile("vcenter_config.json")
if created {
    log.Println("Created new config template - please edit it")
}

// Load configuration
cfg, err := vcenter.LoadVCenterConfig("vcenter_config.json")
if err != nil {
    log.Fatal(err)
}

// Use with ConnectWithPassword
client, err := vcenter.ConnectWithPassword(ctx, vcenter.ConnectConfig{
    Host:       cfg.VCenter,
    Username:   cfg.Username,
    Password:   cfg.Password,
    Insecure:   !cfg.VerifySSL,
    Datacenter: cfg.Datacenter,
})
Configuration file format
{
  "vcenter": "vcenter.example.com",
  "username": "administrator@vsphere.local",
  "password": "your-password",
  "datacenter": "Datacenter",
  "cluster": "Compute-Cluster",
  "resource_pool": "Resources",
  "storage_cluster": "VSAN-Cluster-01",
  "folder": "Production/Servers",
  "domain_user": "svc_domainjoin@corp.example.com",
  "domain_password": "DomainPassword",
  "admin_password": "LocalAdminPassword",
  "timezone": 85,
  "verify_ssl": false
}

Secrets Management

Secure credential storage with AES-256-GCM encryption and Argon2 key derivation.

Store credentials encrypted
// Create credential store
store := vcenter.NewCredentialStore()
store.AddCredential("production", vcenter.Credential{
    Server:   "vcenter-prod.example.com",
    Username: "administrator@vsphere.local",
    Password: "SuperSecretPassword",
    Insecure: false,
})
store.AddCredential("development", vcenter.Credential{
    Server:   "vcenter-dev.example.com",
    Username: "admin@vsphere.local",
    Password: "DevPassword",
    Insecure: true,
})

// Option 1: Encrypt with generated key (store key securely!)
key, _ := vcenter.GenerateEncryptionKey()
err := store.SaveEncrypted("credentials.enc", vcenter.KeySourceDirect(key))
fmt.Printf("Encryption key (save this securely): %s\n", key)

// Option 2: Encrypt with environment variable
os.Setenv("VCENTER_KEY", "your-secret-key")
err := store.SaveEncrypted("credentials.enc", vcenter.KeySourceEnv("VCENTER_KEY"))

// Option 3: Encrypt with key from file
err := store.SaveEncrypted("credentials.enc", vcenter.KeySourceFile("/path/to/keyfile"))

// Option 4: Simple password-based encryption
err := store.SaveEncryptedWithPassword("credentials.enc", "master-password")
Load encrypted credentials
// Load with KeySource
store, err := vcenter.LoadEncryptedCredentialStore("credentials.enc",
    vcenter.KeySourceEnv("VCENTER_KEY"))

// Or with password
store, err := vcenter.LoadEncryptedCredentialStoreWithPassword("credentials.enc",
    "master-password")

// Get specific credential
cred, ok := store.GetCredential("production")
if ok {
    client, err := vcenter.ConnectWithPassword(ctx, vcenter.ConnectConfig{
        Host:       cred.Server,
        Username:   cred.Username,
        Password:   cred.Password,
        Insecure:   cred.Insecure,
        Datacenter: "Datacenter1",
    })
}

// List all credential names
names := store.ListNames() // ["development", "production"]
Encrypt individual strings
// Encrypt sensitive data
encrypted, err := vcenter.EncryptString("secret-data", vcenter.KeySourceEnv("MY_KEY"))

// Decrypt
decrypted, err := vcenter.DecryptString(encrypted, vcenter.KeySourceEnv("MY_KEY"))

// Or with password
encrypted, err := vcenter.EncryptStringWithPassword("secret-data", "password")
decrypted, err := vcenter.DecryptStringWithPassword(encrypted, "password")

Inventory Scanning

Scan vCenter for all available assets - perfect for populating Excel dropdowns dynamically.

Scan all assets
// Scan everything
inventory, err := vcenter.ScanVCenter(ctx, client.Client, vcenter.InventoryOptions{})
if err != nil {
    log.Fatal(err)
}

// Access per-datacenter
for _, dc := range inventory.Datacenters {
    fmt.Printf("Datacenter: %s\n", dc)
    fmt.Printf("  Templates: %v\n", inventory.Templates[dc])
    fmt.Printf("  Clusters: %v\n", inventory.ComputeClusters[dc])
    fmt.Printf("  Storage Clusters: %v\n", inventory.StorageClusters[dc])
    fmt.Printf("  Datastores: %v\n", inventory.Datastores[dc])
    fmt.Printf("  Port Groups: %v\n", inventory.PortGroups[dc])
    fmt.Printf("  Folders: %v\n", inventory.Folders[dc])
}
Flatten to global lists
// Get unique values across all datacenters
flat := inventory.ToFlat()

fmt.Println("All templates:", flat["templates"])
fmt.Println("All port groups:", flat["port_groups"])
fmt.Println("All clusters:", flat["compute_clusters"])
Selective scanning
// Skip expensive operations
falseVal := false
inventory, err := vcenter.ScanVCenter(ctx, client.Client, vcenter.InventoryOptions{
    IncludeTemplates:  &falseVal, // Skip template scan
    IncludeFolders:    &falseVal, // Skip folder scan
    IncludeDatastores: nil,       // nil = include (default)
})
Generate Excel template from live vCenter
// Scan vCenter
inventory, _ := vcenter.ScanVCenter(ctx, client.Client, vcenter.InventoryOptions{})
flat := inventory.ToFlat()

// Create Excel with real values from vCenter
values := vcenter.ExcelValidValues{
    Templates:       flat["templates"],
    Datacenters:     flat["datacenters"],
    ComputeClusters: flat["compute_clusters"],
    StorageClusters: flat["storage_clusters"],
    Datastores:      flat["datastores"],
    PortGroups:      flat["port_groups"],
    // Keep defaults for other fields
    Domains:         []string{"corp.example.com", "dev.example.com"},
    Timezones:       []string{"W. Europe Standard Time", "UTC"},
    CPUOptions:      []int{2, 4, 8, 16},
    MemoryOptions:   []int{4096, 8192, 16384, 32768},
    DiskOptions:     []int{50, 100, 200, 500},
}

err := vcenter.CreateExcelTemplate("vm_requests.xlsx", &values)
Inventory structure
type VCenterInventory struct {
    Datacenters     []string            // ["DC-Stockholm", "DC-Göteborg"]
    ComputeClusters map[string][]string // {"DC-Stockholm": ["Prod-Cluster", "Dev-Cluster"]}
    StorageClusters map[string][]string // {"DC-Stockholm": ["VSAN-Cluster-01"]}
    Datastores      map[string][]string // {"DC-Stockholm": ["datastore1", "datastore2"]}
    Templates       map[string][]string // {"DC-Stockholm": ["Win2022-Template", "Ubuntu-Template"]}
    Folders         map[string][]string // {"DC-Stockholm": ["Production/Web", "Production/DB"]}
    PortGroups      map[string][]string // {"DC-Stockholm": ["VLAN-100", "VLAN-200"]}
}

Guest Operations (Post-Deployment Configuration)

Full example: examples/12-guest-operations/

Execute scripts and transfer files on VMs via VMware Tools - perfect for post-deployment configuration.

Upload file to VM
err := vcenter.UploadFileToVM(ctx, vm,
    "Administrator", "password",
    "/local/config.xml",           // local path
    "C:\\temp\\config.xml",        // remote path on VM
    true,                          // overwrite if exists
)
Download file from VM
err := vcenter.DownloadFileFromVM(ctx, vm,
    "Administrator", "password",
    "C:\\logs\\install.log",       // remote path on VM
    "/local/install.log",          // local path
)
Run script on VM
// Run PowerShell script (don't wait)
pid, err := vcenter.RunScriptOnVM(ctx, vm,
    "Administrator", "password",
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    []string{"-File", "C:\\temp\\setup.ps1"},
    "",     // working directory (optional)
    false,  // don't wait for completion
)

// Run and wait for completion
pid, err := vcenter.RunScriptOnVM(ctx, vm,
    "Administrator", "password",
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    []string{"-ExecutionPolicy", "Bypass", "-File", "C:\\temp\\setup.ps1"},
    "C:\\temp",  // working directory
    true,        // wait for completion (5 min timeout)
)

// Linux example
pid, err := vcenter.RunScriptOnVM(ctx, vm,
    "root", "password",
    "/bin/bash",
    []string{"/tmp/setup.sh"},
    "/tmp",
    true,
)
Upload and run script (convenience function)
// Upload local script and execute it
pid, err := vcenter.UploadAndRunScript(ctx, vm,
    "Administrator", "password",
    "/local/scripts/install-app.ps1",   // local script
    "C:\\temp\\install-app.ps1",        // remote destination
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    []string{"-ExecutionPolicy", "Bypass", "-File", "C:\\temp\\install-app.ps1"},
    true,  // wait for completion
)
Upload/download entire directories

Much faster than file-by-file transfer - uses zip compression (single HTTP request).

// Upload directory to Windows VM
err := vcenter.UploadDirectoryToVM(ctx, vm,
    "Administrator", "password",
    "/local/app-configs",       // local directory
    "C:\\App\\configs",         // remote destination
    true,                       // isWindows
)

// Upload directory to Linux VM
err := vcenter.UploadDirectoryToVM(ctx, vm,
    "root", "password",
    "/local/app-configs",
    "/opt/app/configs",
    false,  // isWindows = false for Linux
)

// Download directory from Windows VM
err := vcenter.DownloadDirectoryFromVM(ctx, vm,
    "Administrator", "password",
    "C:\\App\\logs",            // remote directory
    "/local/collected-logs",    // local destination
    true,
)

// Download directory from Linux VM
err := vcenter.DownloadDirectoryFromVM(ctx, vm,
    "root", "password",
    "/var/log/app",
    "/local/collected-logs",
    false,
)

How it works:

  • Upload: zip locally → upload zip → extract with PowerShell/unzip → delete zip
  • Download: zip on guest → download zip → extract locally → delete remote zip
  • Performance: 100+ files in one HTTP request vs 100+ separate requests
Complete post-deployment workflow
// After WaitForCustomization completes...
err := vcenter.WaitForCustomization(ctx, vm, 15*time.Minute)
if err != nil {
    log.Fatal(err)
}

// Upload configuration files
err = vcenter.UploadFileToVM(ctx, vm, "Administrator", adminPass,
    "configs/app.config", "C:\\App\\app.config", true)

// Run installation script
pid, err := vcenter.UploadAndRunScript(ctx, vm,
    "Administrator", adminPass,
    "scripts/install.ps1", "C:\\temp\\install.ps1",
    "powershell.exe",
    []string{"-ExecutionPolicy", "Bypass", "-File", "C:\\temp\\install.ps1"},
    true,
)

// Download logs for verification
err = vcenter.DownloadFileFromVM(ctx, vm, "Administrator", adminPass,
    "C:\\temp\\install.log", "logs/"+vmName+"_install.log")

WaitForCustomization - The Important Function

WaitForCustomization detects when Windows Sysprep or Linux customization is complete by checking:

  1. Hostname matches VM name (before sysprep: WIN-XXXXXXX, after: configured name)
  2. Valid IP address (not link-local 169.254.x.x)
  3. VMware Tools running

This is more reliable than event-based monitoring and works for both domain-joined and standalone VMs.

// Always use after CloneVMWithCustomization
err = vcenter.WaitForCustomization(ctx, vm, 15*time.Minute)
if err != nil {
    log.Printf("Customization may still be running: %v", err)
}

Error Handling

var notFoundErr *vcenter.NotFoundError
if errors.As(err, &notFoundErr) {
    log.Printf("Resource not found: %s\n", notFoundErr)
}

var validationErr *vcenter.ValidationError
if errors.As(err, &validationErr) {
    log.Printf("Validation error on field %s: %s\n", validationErr.Field, validationErr.Message)
}

Windows Timezone IDs

Common timezone IDs for Windows customization:

  • 4 - Eastern Standard Time (EST)
  • 20 - Central Standard Time
  • 35 - Mountain Standard Time
  • 85 - W. Europe Standard Time (Stockholm, Berlin, Paris)
  • 105 - Pacific Standard Time (PST)
  • 220 - UTC

Full list: https://docs.microsoft.com/en-us/previous-versions/windows/embedded/ms912391(v=winembedded.11)

License

MIT License - See LICENSE file for details.

Contributing

Pull requests are welcome! For major changes, please open an issue first.

Credits

Documentation

Overview

Package vcenter provides a user-friendly Go API for VMware vCenter, inspired by PowerCLI. The package wraps govmomi and offers:

  • Easy authentication with both username/password and Windows SSPI
  • Session caching for better performance
  • PowerCLI-like functions for VM management
  • Batch operations for parallel VM management
  • Disk and network management
  • Windows VM customization with domain join

Installation

go get github.com/skabbio1976/vcenter

Example - Connect with SSPI (Windows)

ctx := context.Background()
client, err := vcenter.ConnectWithSSPI(ctx, "vcenter.example.com", true, "Datacenter1")
if err != nil {
    log.Fatal(err)
}
defer client.Logout(ctx)

Example - Connect with username/password

config := vcenter.ConnectConfig{
    Host:       "vcenter.example.com",
    Username:   "administrator@vsphere.local",
    Password:   "password",
    Insecure:   true,
    Datacenter: "Datacenter1",
}
client, err := vcenter.ConnectWithPassword(ctx, config)
if err != nil {
    log.Fatal(err)
}
defer client.Logout(ctx)

Example - Clone a VM

vm, err := vcenter.CloneVM(
    ctx,
    client.Client,
    "Windows-Template",
    "NewVM",
    "Datacenter1",
    "datastore1",
    "Resources",
    "",
)
if err != nil {
    log.Fatal(err)
}

Example - Clone with Windows customization

customization := vcenter.NewWindowsCustomization(
    "WebServer01",
    "example.com",
    "administrator@example.com",
    "domainpass",
    "adminpass",
    85, // W. Europe Standard Time
    []string{"192.168.1.1"},
    []string{"example.com"},
)

vm, err := vcenter.CloneVMWithCustomization(
    ctx, client.Client, "Windows-Template", "WebServer01",
    "Datacenter1", "datastore1", "Resources", "",
    customization,
)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddDisk

func AddDisk(ctx context.Context, vm *object.VirtualMachine, sizeGB int, datastoreName string) error

AddDisk adds a new disk to a virtual machine.

The disk is created as thin provisioned VMDK on the specified datastore. The VM can be running during the operation (hot-add, if supported by VM).

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object to add disk to
  • sizeGB: Disk size in GB (e.g. 100 for 100GB)
  • datastoreName: The name of the datastore where the disk should be created

Returns nil on success, otherwise an error.

Example:

err := vcenter.AddDisk(ctx, vm, 100, "datastore1") // Add 100GB disk

func AddNetworkAdapter

func AddNetworkAdapter(ctx context.Context, vm *object.VirtualMachine, networkName string) error

AddNetworkAdapter adds a new network adapter to a virtual machine.

The network adapter is created as VMXNET3 (VMware paravirtualized adapter). The VM can be running during the operation (hot-add, if supported by VM).

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • networkName: The name of the network/port group to connect to

Returns nil on success, otherwise a NotFoundError or OperationError.

Example:

err := vcenter.AddNetworkAdapter(ctx, vm, "Production-VLAN100")

func ChangeNetwork

func ChangeNetwork(ctx context.Context, vm *object.VirtualMachine, adapterLabel string, newNetworkName string) error

ChangeNetwork changes the network on an existing network adapter.

The network adapter is identified by its label (e.g. "Network adapter 1"). The VM can be running during the operation.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • adapterLabel: The name/label of the network adapter (e.g. "Network adapter 1")
  • newNetworkName: The name of the new network/port group

Returns nil on success, otherwise a NotFoundError or OperationError.

Example:

err := vcenter.ChangeNetwork(ctx, vm, "Network adapter 1", "DMZ-VLAN200")

func CloneFromRequest

func CloneFromRequest(ctx context.Context, client *govmomi.Client, req ServerRequest, datacenter, datastore, resourcePool, folder string, domainUser, domainPassword, adminPassword string, timezone int) (*object.VirtualMachine, error)

CloneFromRequest clones a virtual machine based on a ServerRequest struct.

The function implements the CORRECT operation order for VM cloning with customization:

  1. Clone VM with powerOn=false (customization attached but doesn't run yet)
  2. Add extra disks while VM is powered off (safe operation)
  3. Change CPU/memory while VM is powered off (safe operation)
  4. Power on VM (this triggers guest customization/sysprep)
  5. Wait for customization to complete using WaitForCustomization

This order is critical because:

  • Sysprep only runs when the VM boots for the first time after clone
  • Modifying hardware while powered off is safer
  • Logging in before sysprep completes can break the installation

Parameters:

  • ctx: Context for timeout and cancellation
  • client: govmomi.Client for vCenter connection
  • req: ServerRequest with all VM configuration
  • datacenter: The name of the datacenter
  • datastore: The name of the datastore or datastore cluster
  • resourcePool: The name of the resource pool
  • folder: The name of the VM folder (empty for default)
  • domainUser: Domain admin for domain join
  • domainPassword: Password for domain admin
  • adminPassword: Local admin password
  • timezone: Windows timezone ID

Returns the newly created VM or a ValidationError/OperationError.

Example:

req := vcenter.ServerRequest{
    Name:     "WebServer01",
    Template: "Win2022-Template",
    CPUs:     4,
    MemoryGB: 8,
    Domain:   "example.com",
    Adapters: []vcenter.NetworkAdapter{
        {IPAddress: "192.168.1.100", SubnetMask: "255.255.255.0", Gateway: "192.168.1.1"},
    },
    DNSServers:      []string{"192.168.1.1"},
    MachineObjectOU: "OU=Servers,DC=example,DC=com",
}
vm, err := vcenter.CloneFromRequest(ctx, client, req, "DC1",
    "datastore1", "Resources", "", "admin@example.com",
    "domainpass", "adminpass", 85)

func CloneVM

func CloneVM(
	ctx context.Context,
	client *govmomi.Client,
	templateName string,
	vmName string,
	datacenter string,
	datastore string,
	resourcePool string,
	folder string,
) (*object.VirtualMachine, error)

CloneVM clones a virtual machine from a template.

The function creates a new VM based on the specified template and places it in the specified datacenter, datastore, and resource pool. The VM is created powered off by default.

Parameters:

  • ctx: Context for timeout and cancellation
  • client: govmomi.Client for vCenter connection
  • templateName: The name of the template to clone from
  • vmName: The name of the new VM
  • datacenter: The name of the datacenter
  • datastore: The name of the datastore or datastore cluster where the VM should be created
  • resourcePool: The name of the resource pool (e.g. "Resources")
  • folder: The name of the VM folder (empty string for default VM folder)

Returns the newly created VM (powered off) or an error if cloning fails.

Example:

vm, err := vcenter.CloneVM(ctx, client, "Win2022-Template", "WebServer01",
    "DC1", "datastore1", "Resources", "WebServers")

func CloneVMWithCustomization

func CloneVMWithCustomization(
	ctx context.Context,
	client *govmomi.Client,
	templateName string,
	vmName string,
	datacenter string,
	datastore string,
	resourcePool string,
	folder string,
	customization *types.CustomizationSpec,
) (*object.VirtualMachine, error)

CloneVMWithCustomization clones a virtual machine with Windows/Linux customization.

The function clones a VM from a template and applies customizations such as computer name, domain join, IP configuration, and timezone. The VM is started automatically after cloning so that customization can run.

NOTE: For proper customization with additional disks or resource changes, use CloneFromRequest instead which implements the correct operation order.

Parameters:

  • ctx: Context for timeout and cancellation
  • client: govmomi.Client for vCenter connection
  • templateName: The name of the template to clone from
  • vmName: The name of the new VM
  • datacenter: The name of the datacenter
  • datastore: The name of the datastore or datastore cluster where the VM should be created
  • resourcePool: The name of the resource pool
  • folder: The name of the VM folder (empty string for default)
  • customization: CustomizationSpec with all Windows/Linux settings

Returns the newly created VM or an error.

Example:

customization := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{...})
vm, err := vcenter.CloneVMWithCustomization(ctx, client,
    "Win2022-Template", "WebServer01", "DC1", "datastore1",
    "Resources", "", customization)

func ConnectCDROM

func ConnectCDROM(ctx context.Context, vm *object.VirtualMachine) error

ConnectCDROM connects a VM's CD/DVD drive.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns nil on success, otherwise an error.

Example:

// Connect CD/DVD drive
err := vcenter.ConnectCDROM(ctx, vm)

func CreateExcelTemplate

func CreateExcelTemplate(path string, values *ExcelValidValues) error

CreateExcelTemplate writes an Excel workbook replicating the Python helper.

func CreateSnapshot

func CreateSnapshot(ctx context.Context, vm *object.VirtualMachine, snapshotName string, description string, memory bool, quiesce bool) error

CreateSnapshot creates a snapshot of a virtual machine.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • snapshotName: Name for the snapshot
  • description: Optional description for the snapshot
  • memory: Include VM memory in snapshot (default: false) If true, creates a snapshot of the VM's memory state Useful for capturing running state but increases snapshot size
  • quiesce: Quiesce filesystem before snapshot (default: false) Requires VMware Tools to be running Ensures filesystem consistency by flushing buffers

Returns nil on success, otherwise an error.

Example:

// Simple disk-only snapshot
err := vcenter.CreateSnapshot(ctx, vm, "Before Update", "", false, false)

// Quiesced snapshot (requires VMware Tools)
err := vcenter.CreateSnapshot(ctx, vm, "Consistent Backup",
    "Pre-maintenance backup", false, true)

func CreateVCenterConfigTemplate

func CreateVCenterConfigTemplate(path string) error

CreateVCenterConfigTemplate writes a human-friendly configuration template with warnings/comments.

func DecryptString

func DecryptString(encrypted string, ks KeySource) (string, error)

DecryptString decrypts text produced by EncryptString.

func DecryptStringWithPassword

func DecryptStringWithPassword(encrypted string, password string) (string, error)

DecryptStringWithPassword decrypts payload encrypted with EncryptStringWithPassword.

func DeleteAllSnapshots

func DeleteAllSnapshots(ctx context.Context, vm *object.VirtualMachine, consolidate bool) error

DeleteAllSnapshots deletes all snapshots for a virtual machine.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • consolidate: Consolidate disk files after removal (default: true)

Returns nil on success, otherwise an error.

Example:

err := vcenter.DeleteAllSnapshots(ctx, vm, true)

func DeleteSnapshot

func DeleteSnapshot(ctx context.Context, vm *object.VirtualMachine, snapshotName string, removeChildren bool, consolidate bool) error

DeleteSnapshot deletes a snapshot by name.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • snapshotName: Name of the snapshot to delete
  • removeChildren: Also remove child snapshots (default: false) If false, children are preserved and promoted
  • consolidate: Consolidate disk files after removal (default: true) Merges snapshot deltas back into parent disk

Returns nil on success, otherwise an error.

Example:

// Delete single snapshot, keep children
err := vcenter.DeleteSnapshot(ctx, vm, "Before Update", false, true)

// Delete snapshot and all children
err := vcenter.DeleteSnapshot(ctx, vm, "Old Backup", true, true)

func DeleteVM

func DeleteVM(ctx context.Context, vm *object.VirtualMachine, deleteFromDisk bool, force bool) error

DeleteVM deletes a virtual machine.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • deleteFromDisk: If true, destroy VM and delete all files from disk. If false, only unregister from inventory (default: true)
  • force: Allow deletion of powered-on VMs or VMs with snapshots (default: false)

Returns nil on success, otherwise an error.

Example:

// Delete VM and remove all files
err := vcenter.DeleteVM(ctx, vm, true, false)

// Unregister VM but keep files on datastore
err := vcenter.DeleteVM(ctx, vm, false, false)

// Force delete a powered-on VM
err := vcenter.DeleteVM(ctx, vm, true, true)

func DisconnectCDROM

func DisconnectCDROM(ctx context.Context, vm *object.VirtualMachine) error

DisconnectCDROM disconnects a VM's CD/DVD drive.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns nil on success, otherwise an error.

Example:

// Disconnect CD/DVD drive
err := vcenter.DisconnectCDROM(ctx, vm)

func DownloadDirectoryFromVM

func DownloadDirectoryFromVM(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, remoteDir string, localDir string, isWindows bool) error

DownloadDirectoryFromVM downloads an entire directory from a VM by zipping it on the guest, downloading the zip, and extracting locally.

This is much faster than downloading files one by one. Works on both Windows and Linux guests.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS
  • guestPassword: Password for guest OS user
  • remoteDir: Directory on guest OS to download
  • localDir: Local destination directory
  • isWindows: True for Windows guest, false for Linux

Returns nil on success, otherwise an error.

Example:

err := vcenter.DownloadDirectoryFromVM(ctx, vm, "Administrator", "password",
    "C:\\App\\logs", "/local/logs", true)

func DownloadFileFromVM

func DownloadFileFromVM(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, remoteFilePath string, localFilePath string) error

DownloadFileFromVM downloads a file from a virtual machine via VMware Tools.

The VM must be powered on and have VMware Tools running.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS (e.g., "Administrator")
  • guestPassword: Password for guest OS user
  • remoteFilePath: Source path on guest OS (e.g., "C:\\temp\\file.txt")
  • localFilePath: Destination path on local machine

Returns nil on success, otherwise an error.

Example:

err := vcenter.DownloadFileFromVM(ctx, vm, "Administrator", "password",
    "C:\\temp\\log.txt", "/local/log.txt")

func EncryptString

func EncryptString(plaintext string, ks KeySource) (string, error)

EncryptString encrypts plaintext using AES-256-GCM with a KeySource-derived key.

func EncryptStringWithPassword

func EncryptStringWithPassword(plaintext string, password string) (string, error)

EncryptStringWithPassword is a simpler variant that derives the key from a master password.

func EnsureConfigFile

func EnsureConfigFile(path string) (created bool, err error)

EnsureConfigFile ensures that a config exists at path, creating a template if needed.

func ExtendDisk

func ExtendDisk(ctx context.Context, vm *object.VirtualMachine, diskLabel string, newSizeGB int) error

ExtendDisk extends an existing disk to a new size.

The disk is identified by its label (e.g. "Hard disk 2"). The new size must be larger than the current size. The VM can be running during the operation.

NOTE: This only extends the disk in vSphere. You need to manually extend the partition in the guest operating system afterwards.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • diskLabel: The name/label of the disk (e.g. "Hard disk 2")
  • newSizeGB: New size in GB (must be larger than current)

Returns nil on success, otherwise a ValidationError or OperationError.

Example:

err := vcenter.ExtendDisk(ctx, vm, "Hard disk 2", 200) // Extend to 200GB

func GenerateEncryptionKey

func GenerateEncryptionKey() (string, error)

GenerateEncryptionKey returns a random 32-byte hex-encoded key.

func GetVM

func GetVM(ctx context.Context, client *govmomi.Client, vmName string, datacenter string) (*object.VirtualMachine, error)

GetVM finds a virtual machine based on name.

If datacenter is empty, search is performed in all datacenters.

Parameters:

  • ctx: Context for timeout and cancellation
  • client: govmomi.Client for vCenter connection
  • vmName: The name of the VM to find
  • datacenter: The name of the datacenter (empty string to search everywhere)

Returns the VirtualMachine object or a NotFoundError.

Example:

vm, err := vcenter.GetVM(ctx, client, "WebServer01", "DC1")

func MountISO

func MountISO(ctx context.Context, vm *object.VirtualMachine, isoPath string, datastoreName string, connect bool) error

MountISO mounts an ISO file to a VM's CD/DVD drive.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • isoPath: Path to ISO file on datastore (e.g., "ISOs/ubuntu-22.04.iso")
  • datastoreName: Name of datastore containing the ISO (if empty, uses VM's datastore)
  • connect: Connect the CD/DVD drive after mounting (default: true)

Returns nil on success, otherwise an error.

Example:

// Mount ISO from specific datastore
err := vcenter.MountISO(ctx, vm, "ISOs/windows.iso", "datastore1", true)

// Mount ISO from VM's datastore
err := vcenter.MountISO(ctx, vm, "ISOs/ubuntu.iso", "", true)

func NewLinuxCustomization

func NewLinuxCustomization(cfg LinuxCustomizationConfig) *types.CustomizationSpec

NewLinuxCustomization creates a Linux customization spec from a config struct.

This function supports all Linux customization scenarios:

  • DHCP configuration
  • Static IP configuration
  • Single or multiple network adapters

Example - Simple DHCP:

spec := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname: "webserver01",
    Domain:   "example.com",
})

Example - Static IP:

spec := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname: "webserver01",
    Domain:   "example.com",
    Adapters: []vcenter.NetworkAdapter{{
        IPAddress:  "192.168.1.100",
        SubnetMask: "255.255.255.0",
        Gateway:    "192.168.1.1",
    }},
    GlobalDNS:   []string{"192.168.1.1"},
    DNSSuffixes: []string{"example.com"},
})

Example - Multi-NIC:

spec := vcenter.NewLinuxCustomization(vcenter.LinuxCustomizationConfig{
    Hostname: "appserver01",
    Domain:   "example.com",
    Adapters: []vcenter.NetworkAdapter{
        {IPAddress: "10.1.1.20", SubnetMask: "255.255.255.0", Gateway: "10.1.1.1"},
        {IPAddress: "10.2.1.20", SubnetMask: "255.255.255.0", Gateway: "10.2.1.1"},
    },
    GlobalDNS: []string{"10.1.1.1"},
})

func NewWindowsCustomization

func NewWindowsCustomization(cfg WindowsCustomizationConfig) *types.CustomizationSpec

NewWindowsCustomization creates a Windows customization spec from a config struct.

This function replaces the older separate functions and supports all scenarios:

  • Domain join with DHCP
  • Domain join with static IP
  • Workgroup (standalone) with DHCP
  • Workgroup (standalone) with static IP
  • Single or multiple network adapters
  • MachineObjectOU for specific OU placement
  • Autologon for post-install scripts

Example - Domain join with DHCP:

spec := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:  "WebServer01",
    AdminPassword: "SecurePass123!",
    Timezone:      85,
    Domain:        "example.com",
    DomainUser:    "admin@example.com",
    DomainPassword: "DomainPass!",
    GlobalDNS:     []string{"192.168.1.1", "192.168.1.2"},
    DNSSuffixes:   []string{"example.com"},
})

Example - Standalone with static IP:

spec := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:  "TestServer",
    AdminPassword: "SecurePass123!",
    Timezone:      85,
    Adapters: []vcenter.NetworkAdapter{{
        IPAddress:  "192.168.1.100",
        SubnetMask: "255.255.255.0",
        Gateway:    "192.168.1.1",
        DNSServers: []string{"192.168.1.1"},
    }},
})

Example - Multi-NIC configuration:

spec := vcenter.NewWindowsCustomization(vcenter.WindowsCustomizationConfig{
    ComputerName:  "WebServer01",
    AdminPassword: "SecurePass123!",
    Timezone:      85,
    Domain:        "example.com",
    DomainUser:    "admin@example.com",
    DomainPassword: "DomainPass!",
    Adapters: []vcenter.NetworkAdapter{
        {Network: "Production", IPAddress: "10.1.1.10", SubnetMask: "255.255.255.0", Gateway: "10.1.1.1"},
        {Network: "Management", IPAddress: "10.2.1.10", SubnetMask: "255.255.255.0", Gateway: "10.2.1.1"},
    },
    GlobalDNS:   []string{"10.1.1.1"},
    DNSSuffixes: []string{"example.com"},
})

func PowerOffVM

func PowerOffVM(ctx context.Context, vm *object.VirtualMachine) error

PowerOffVM powers off a virtual machine.

This is a "hard" power off (equivalent to pulling the power cable). For graceful shutdown, use guest.Shutdown() instead.

Returns nil on success, otherwise an error.

Example:

err := vcenter.PowerOffVM(ctx, vm)

func PowerOnVM

func PowerOnVM(ctx context.Context, vm *object.VirtualMachine) error

PowerOnVM powers on a virtual machine.

The function waits until the power-on operation is complete.

Returns nil on success, otherwise an error.

Example:

err := vcenter.PowerOnVM(ctx, vm)

func RemoveDisk

func RemoveDisk(ctx context.Context, vm *object.VirtualMachine, diskLabel string) error

RemoveDisk removes a disk from a virtual machine.

Both the disk from the VM configuration and the VMDK file are permanently deleted. The VM can be running during the operation (hot-remove, if supported by VM).

WARNING: This permanently deletes data!

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • diskLabel: The name/label of the disk to remove (e.g. "Hard disk 2")

Returns nil on success, otherwise a NotFoundError or OperationError.

Example:

err := vcenter.RemoveDisk(ctx, vm, "Hard disk 2")

func RestartVM

func RestartVM(ctx context.Context, vm *object.VirtualMachine) error

RestartVM restarts a virtual machine.

The function first attempts a graceful restart using VMware Tools (RebootGuest). If that fails, a hard reset is performed instead.

Returns nil on success, otherwise an error.

Example:

err := vcenter.RestartVM(ctx, vm)

func RevertToSnapshot

func RevertToSnapshot(ctx context.Context, vm *object.VirtualMachine, snapshotName string, suppressPowerOn bool) error

RevertToSnapshot reverts VM to a specific snapshot.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • snapshotName: Name of the snapshot to revert to
  • suppressPowerOn: Don't power on VM after revert (default: false) If false, VM will power on if it was on when snapshot was taken

Returns nil on success, otherwise an error.

Example:

// Revert to snapshot
err := vcenter.RevertToSnapshot(ctx, vm, "Before Update", false)

// Revert but keep VM powered off
err := vcenter.RevertToSnapshot(ctx, vm, "Clean State", true)

func RunScriptOnVM

func RunScriptOnVM(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, scriptPath string, scriptArgs []string, workingDirectory string, waitForCompletion bool) (int64, error)

RunScriptOnVM executes a script on a virtual machine via VMware Tools.

The VM must be powered on and have VMware Tools running.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS (e.g., "Administrator")
  • guestPassword: Password for guest OS user
  • scriptPath: Full path to script on guest OS (e.g., "C:\\temp\\script.ps1")
  • scriptArgs: Arguments to pass to script
  • workingDirectory: Optional working directory for script execution
  • waitForCompletion: Wait for script to complete (default: false)

Returns the process ID and error.

Example:

pid, err := vcenter.RunScriptOnVM(ctx, vm, "Administrator", "password",
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    []string{"-File", "C:\\temp\\script.ps1"}, "", false)

func SetVMResources

func SetVMResources(ctx context.Context, vm *object.VirtualMachine, numCPUs int32, memoryMB int64) error

SetVMResources changes CPU and memory on a virtual machine.

The VM needs to be powered off to change these resources (depending on VM configuration).

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object to modify
  • numCPUs: Number of CPUs (e.g. 2, 4, 8)
  • memoryMB: Memory in MB (e.g. 4096 for 4GB, 8192 for 8GB)

Returns nil on success, otherwise an error.

Example:

err := vcenter.SetVMResources(ctx, vm, 4, 8192) // 4 CPU, 8GB RAM

func UnmountISO

func UnmountISO(ctx context.Context, vm *object.VirtualMachine, disconnect bool) error

UnmountISO unmounts ISO from a VM's CD/DVD drive.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • disconnect: Disconnect the CD/DVD drive after unmounting (default: true)

Returns nil on success, otherwise an error.

Example:

// Unmount ISO and disconnect drive
err := vcenter.UnmountISO(ctx, vm, true)

// Unmount but keep drive connected
err := vcenter.UnmountISO(ctx, vm, false)

func UnregisterVM

func UnregisterVM(ctx context.Context, vm *object.VirtualMachine) error

UnregisterVM unregisters a virtual machine from inventory without deleting files.

This is a convenience function that calls DeleteVM with deleteFromDisk=false.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns nil on success, otherwise an error.

Example:

// Unregister VM (keep files on datastore)
err := vcenter.UnregisterVM(ctx, vm)

func UploadAndRunScript

func UploadAndRunScript(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, localScriptPath string, remoteScriptPath string, interpreterPath string, scriptArgs []string, waitForCompletion bool) (int64, error)

UploadAndRunScript uploads a script to VM and executes it (helper function).

This is a convenience function that combines UploadFileToVM and RunScriptOnVM into a single operation.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS
  • guestPassword: Password for guest OS user
  • localScriptPath: Local script file path
  • remoteScriptPath: Destination path on guest OS
  • interpreterPath: Path to interpreter (e.g., "powershell.exe" or "/bin/bash")
  • scriptArgs: Optional list of additional arguments
  • waitForCompletion: Wait for script to complete (default: true)

Returns the process ID and error.

Example:

// PowerShell script on Windows
pid, err := vcenter.UploadAndRunScript(ctx, vm, "Administrator", "password",
    "/local/setup.ps1", "C:\\temp\\setup.ps1",
    "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    []string{"-ExecutionPolicy", "Bypass", "-File", "C:\\temp\\setup.ps1"}, true)

func UploadDirectoryToVM

func UploadDirectoryToVM(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, localDir string, remoteDir string, isWindows bool) error

UploadDirectoryToVM uploads an entire directory to a VM by zipping it locally, uploading the zip, extracting on the guest, and cleaning up.

This is much faster than uploading files one by one (single HTTP request vs many). Works on both Windows and Linux guests.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS
  • guestPassword: Password for guest OS user
  • localDir: Local directory to upload
  • remoteDir: Destination directory on guest OS
  • isWindows: True for Windows guest, false for Linux

Returns nil on success, otherwise an error.

Example:

err := vcenter.UploadDirectoryToVM(ctx, vm, "Administrator", "password",
    "/local/configs", "C:\\App\\configs", true)

func UploadFileToVM

func UploadFileToVM(ctx context.Context, vm *object.VirtualMachine, guestUsername string, guestPassword string, localFilePath string, remoteFilePath string, overwrite bool) error

UploadFileToVM uploads a file to a virtual machine via VMware Tools.

The VM must be powered on and have VMware Tools running.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object
  • guestUsername: Username for guest OS (e.g., "Administrator")
  • guestPassword: Password for guest OS user
  • localFilePath: Local file path to upload
  • remoteFilePath: Destination path on guest OS (e.g., "C:\\temp\\script.ps1")
  • overwrite: Overwrite existing file (default: true)

Returns nil on success, otherwise an error.

Example:

err := vcenter.UploadFileToVM(ctx, vm, "Administrator", "password",
    "/local/script.ps1", "C:\\temp\\script.ps1", true)

func ValidateExcel

func ValidateExcel(path string, cfg *VCenterConfig, strict bool) (bool, []string, error)

ValidateExcel performs similar validation checks as the Python implementation.

func WaitForCustomization

func WaitForCustomization(ctx context.Context, vm *object.VirtualMachine, timeout time.Duration) error

WaitForCustomization waits for VM guest customization (Windows Sysprep) to complete.

The function detects customization completion by checking three conditions:

  1. Hostname matches: The VM's hostname starts with the VM name (before sysprep: WIN-XXXXXXX, after: the name we configured)
  2. Valid IP address: Not a link-local address (169.254.x.x)
  3. VMware Tools running: Guest tools are operational

This approach is more reliable than event-based monitoring because:

  • Events can be missed or delayed in vCenter
  • Hostname change is a deterministic marker that sysprep completed
  • Works for both domain-joined and standalone VMs

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object to monitor
  • timeout: Max time to wait (recommended: 10-15 minutes)

Returns nil when customization completes, otherwise a timeout error.

Example:

// After cloning with customization
err := vcenter.WaitForCustomization(ctx, vm, 10*time.Minute)
if err != nil {
    log.Printf("Customization failed: %v", err)
}
fmt.Println("VM is ready - customization complete!")

func WaitForIP

func WaitForIP(ctx context.Context, vm *object.VirtualMachine, timeout time.Duration) (string, error)

WaitForIP waits until the VM gets a routable IP address.

The function polls the VM every 2 seconds until an IP address is found or timeout is reached. Requires that VMware Tools is installed and running in the guest system.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object to wait for
  • timeout: Max time to wait (e.g. 5*time.Minute)

Returns the IP address or a timeout error.

Example:

ip, err := vcenter.WaitForIP(ctx, vm, 5*time.Minute)
fmt.Printf("VM IP: %s\n", ip)

func WaitForTools

func WaitForTools(ctx context.Context, vm *object.VirtualMachine) error

WaitForTools waits for VMware Tools to become ready.

The function polls the VM every 2 seconds until VMware Tools is running. Max wait time is 5 minutes.

Returns nil when Tools are ready, otherwise a timeout error.

Example:

err := vcenter.WaitForTools(ctx, vm)
if err == nil {
    // VMware Tools are now ready to use
}

Types

type Client

type Client struct {
	*govmomi.Client
	// contains filtered or unexported fields
}

Client is a wrapper around govmomi.Client with cached datacenter and helper functions

func ConnectWithPassword

func ConnectWithPassword(ctx context.Context, config ConnectConfig) (*Client, error)

ConnectWithPassword connects to vCenter with username/password Uses go-vcenter-auth for session caching and automatic reconnection

func ConnectWithSSPI

func ConnectWithSSPI(ctx context.Context, host string, insecure bool, datacenter string) (*Client, error)

ConnectWithSSPI connects to vCenter with Windows SSPI/Kerberos authentication This only works on Windows and uses the logged-in user's credentials Returns ErrSSPINotSupported on non-Windows platforms

func ConnectWithURL

func ConnectWithURL(ctx context.Context, urlStr string, insecure bool, datacenter string) (*Client, error)

ConnectWithURL connects to vCenter with a complete URL (including credentials) Uses standard govmomi without go-vcenter-auth

func (*Client) GetDatacenter

func (c *Client) GetDatacenter() *object.Datacenter

GetDatacenter returns the cached datacenter

func (*Client) GetDatacenterName

func (c *Client) GetDatacenterName() string

GetDatacenterName returns the name of the cached datacenter

func (*Client) GetFinder

func (c *Client) GetFinder() *find.Finder

GetFinder returns a finder for the cached datacenter If no datacenter is cached, a new finder is created without datacenter context

func (*Client) Logout

func (c *Client) Logout(ctx context.Context) error

Logout logs out from vCenter and closes the client

func (*Client) SetDatacenter

func (c *Client) SetDatacenter(ctx context.Context, datacenterName string) error

SetDatacenter sets the datacenter for the client and caches the finder

type ConfigurationError

type ConfigurationError struct {
	Message string
}

ConfigurationError is returned when configuration is invalid

func (*ConfigurationError) Error

func (e *ConfigurationError) Error() string

type ConnectConfig

type ConnectConfig struct {
	Host       string
	Username   string
	Password   string
	Insecure   bool
	Datacenter string
}

ConnectConfig contains configuration for connecting to vCenter

type Credential

type Credential struct {
	Server   string `json:"server"`
	Username string `json:"username"`
	Password string `json:"password"`
	Insecure bool   `json:"insecure"`
}

Credential mirrors the Python structure for credential entries.

type CredentialStore

type CredentialStore struct {
	Credentials map[string]Credential `json:"credentials"`
}

CredentialStore stores multiple credentials and can serialize plain or encrypted JSON.

func LoadEncryptedCredentialStore

func LoadEncryptedCredentialStore(path string, ks KeySource) (*CredentialStore, error)

LoadEncryptedCredentialStore decrypts and parses credentials using a KeySource.

func LoadEncryptedCredentialStoreWithPassword

func LoadEncryptedCredentialStoreWithPassword(path string, password string) (*CredentialStore, error)

LoadEncryptedCredentialStoreWithPassword decrypts credentials produced by SaveEncryptedWithPassword.

func LoadPlaintextCredentialStore

func LoadPlaintextCredentialStore(path string) (*CredentialStore, error)

LoadPlaintextCredentialStore reads credentials without encryption.

func NewCredentialStore

func NewCredentialStore() *CredentialStore

NewCredentialStore creates an empty credential store.

func (*CredentialStore) AddCredential

func (s *CredentialStore) AddCredential(name string, cred Credential)

AddCredential adds or overwrites a credential.

func (*CredentialStore) GetCredential

func (s *CredentialStore) GetCredential(name string) (Credential, bool)

GetCredential fetches a credential by name.

func (*CredentialStore) ListNames

func (s *CredentialStore) ListNames() []string

ListNames returns credential names sorted alphabetically.

func (*CredentialStore) SaveEncrypted

func (s *CredentialStore) SaveEncrypted(path string, ks KeySource) error

SaveEncrypted saves credentials encrypted with a KeySource-derived key.

func (*CredentialStore) SaveEncryptedWithPassword

func (s *CredentialStore) SaveEncryptedWithPassword(path string, password string) error

SaveEncryptedWithPassword encrypts using a human-friendly master password workflow.

func (*CredentialStore) SavePlaintext

func (s *CredentialStore) SavePlaintext(path string) error

SavePlaintext writes the credential store as JSON (use only for initial setup).

type ExcelCustomization

type ExcelCustomization struct {
	Hostname            string          `json:"hostname,omitempty"`
	Domain              string          `json:"domain,omitempty"`
	DomainJoin          ExcelDomainJoin `json:"domain_join"`
	AdminPasswordSecret string          `json:"admin_password_secret"`
	Autologon           struct {
		Enabled  bool   `json:"enabled"`
		Count    int    `json:"count"`
		Username string `json:"username"`
	} `json:"autologon"`
	RunOnceCommands []string `json:"run_once_commands,omitempty"`
	Timezone        string   `json:"timezone,omitempty"`
}

ExcelCustomization matches the JSON structure from py-vcenter.

type ExcelDomainJoin

type ExcelDomainJoin struct {
	Username       string `json:"username,omitempty"`
	PasswordSecret string `json:"password_secret,omitempty"`
	OUPath         string `json:"ou_path,omitempty"`
}

ExcelDomainJoin describes domain join configuration.

type ExcelHardware

type ExcelHardware struct {
	NumCPUs          int    `json:"num_cpus"`
	MemoryMB         int    `json:"memory_mb"`
	DiskGB           []int  `json:"disk_gb,omitempty"`
	DiskProvisioning string `json:"disk_provisioning"`
	ServerRole       string `json:"server_role,omitempty"`
}

ExcelHardware describes VM hardware overrides.

type ExcelNetworkAdapter

type ExcelNetworkAdapter struct {
	PortGroup  string   `json:"port_group"`
	IPAddress  string   `json:"ip_address,omitempty"`
	SubnetMask string   `json:"subnet_mask,omitempty"`
	Gateway    string   `json:"gateway,omitempty"`
	DNSServers []string `json:"dns_servers,omitempty"`
}

ExcelNetworkAdapter mirrors JSON output from the Python module.

type ExcelVMConfig

type ExcelVMConfig struct {
	Template        string                `json:"template"`
	VMName          string                `json:"vm_name"`
	Datacenter      string                `json:"datacenter,omitempty"`
	Cluster         string                `json:"cluster,omitempty"`
	StorageCluster  string                `json:"storage_cluster,omitempty"`
	Datastore       string                `json:"datastore,omitempty"`
	ResourcePool    string                `json:"resource_pool,omitempty"`
	Folder          string                `json:"folder,omitempty"`
	NetworkAdapters []ExcelNetworkAdapter `json:"network_adapters"`
	Hardware        ExcelHardware         `json:"hardware"`
	Customization   ExcelCustomization    `json:"customization"`
}

ExcelVMConfig encapsulates one VM definition parsed from Excel.

func ExcelToJSON

func ExcelToJSON(path string, outputDir string) ([]ExcelVMConfig, error)

ExcelToJSON converts Excel rows into ExcelVMConfig list and optionally writes JSON files.

type ExcelValidValues

type ExcelValidValues struct {
	Templates        []string
	Datacenters      []string
	ComputeClusters  []string
	StorageClusters  []string
	Datastores       []string
	PortGroups       []string
	SubnetMasks      []string
	Domains          []string
	Timezones        []string
	CPUOptions       []int
	MemoryOptions    []int
	DiskOptions      []int
	ServerRoles      []string
	DiskProvisioning []string
}

ExcelValidValues defines dropdown entries for the template.

func DefaultExcelValidValues

func DefaultExcelValidValues() ExcelValidValues

DefaultExcelValidValues mirrors the defaults from py-vcenter.

type InventoryOptions

type InventoryOptions struct {
	IncludeTemplates  *bool
	IncludeFolders    *bool
	IncludeDatastores *bool
}

InventoryOptions controls the scope of ScanVCenter. Nil values fall back to True so you can selectively disable sections.

type KeySource

type KeySource struct {
	// contains filtered or unexported fields
}

KeySource represents where to fetch the master secret used for encryption.

func KeySourceDirect

func KeySourceDirect(secret string) KeySource

KeySourceDirect uses the provided string as the secret.

func KeySourceEnv

func KeySourceEnv(name string) KeySource

KeySourceEnv uses an environment variable.

func KeySourceFile

func KeySourceFile(path string) KeySource

KeySourceFile reads key bytes from a file (trimmed).

type LinuxCustomizationConfig

type LinuxCustomizationConfig struct {
	Hostname string // Required: Linux hostname
	Domain   string // Domain name (optional)

	// Network settings
	Adapters    []NetworkAdapter // Network adapters (empty = one DHCP adapter)
	GlobalDNS   []string         // Global DNS servers
	DNSSuffixes []string         // DNS search suffixes
}

LinuxCustomizationConfig contains all settings for Linux VM customization. Supports DHCP, static IP, single NIC, and multi-NIC configurations.

type NetworkAdapter

type NetworkAdapter struct {
	Network    string   `json:"network"`               // Port group/network name
	IPAddress  string   `json:"ip_address,omitempty"`  // Empty = DHCP
	SubnetMask string   `json:"subnet_mask,omitempty"` // Required if IPAddress is set
	Gateway    string   `json:"gateway,omitempty"`     // Required if IPAddress is set
	DNSServers []string `json:"dns_servers,omitempty"` // Per-adapter DNS servers (optional)
}

NetworkAdapter describes the configuration for a network adapter during customization. Used in multi-NIC scenarios where each adapter can have different IP settings.

type NetworkInfo

type NetworkInfo struct {
	Label       string
	MACAddress  string
	Network     string
	Connected   bool
	AdapterType string
	IPAddresses []string
}

NetworkInfo contains network adapter information

type NotFoundError

type NotFoundError struct {
	ResourceType string
	Name         string
}

NotFoundError is returned when a resource is not found

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type OperationError

type OperationError struct {
	Operation string
	Err       error
}

OperationError is returned when a vCenter operation fails

func (*OperationError) Error

func (e *OperationError) Error() string

func (*OperationError) Unwrap

func (e *OperationError) Unwrap() error

type ServerRequest

type ServerRequest struct {
	Name     string `json:"name"`
	Template string `json:"template"`
	CPUs     int32  `json:"cpus"`
	MemoryGB int    `json:"memory_gb"`

	// Disks - list of disk sizes in GB (for additional disks: D:, E:, F:, etc.)
	DisksGB          []int  `json:"disks_gb,omitempty"`
	DiskProvisioning string `json:"disk_provisioning,omitempty"` // thin, thick, or eagerzeroed

	// Network adapters (empty = single DHCP adapter with legacy IP fields)
	Adapters []NetworkAdapter `json:"adapters,omitempty"`

	// Legacy single-NIC fields (used if Adapters is empty)
	IPAddress  string `json:"ip_address,omitempty"`
	SubnetMask string `json:"subnet_mask,omitempty"`
	Gateway    string `json:"gateway,omitempty"`

	// Domain settings (optional - empty = workgroup)
	Domain          string `json:"domain,omitempty"`
	MachineObjectOU string `json:"machine_object_ou,omitempty"` // OU for computer object

	// DNS settings
	DNSServers  []string `json:"dns_servers,omitempty"`
	DNSSuffixes []string `json:"dns_suffixes,omitempty"`

	// Autologon (0 = disabled)
	AutologonCount int `json:"autologon_count,omitempty"`

	// Deprecated: Use DisksGB instead. Kept for backwards compatibility.
	DiskGB int `json:"disk_gb,omitempty"`
}

ServerRequest represents a server order with all necessary configuration. Supports multi-NIC, multiple disks, MachineObjectOU, and autologon.

func (*ServerRequest) Validate

func (r *ServerRequest) Validate() error

Validate validates ServerRequest and returns a ValidationError if something is wrong

type SnapshotInfo

type SnapshotInfo struct {
	Name        string
	Description string
	CreateTime  string
	State       string
	ID          int32
	Level       int
}

SnapshotInfo contains information about a VM snapshot

func GetCurrentSnapshot

func GetCurrentSnapshot(ctx context.Context, vm *object.VirtualMachine) (*SnapshotInfo, error)

GetCurrentSnapshot gets the current snapshot (the one the VM is currently on).

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns a SnapshotInfo object or nil if no current snapshot.

Example:

current, err := vcenter.GetCurrentSnapshot(ctx, vm)
if current != nil {
    fmt.Printf("Current snapshot: %s\n", current.Name)
}

func ListSnapshots

func ListSnapshots(ctx context.Context, vm *object.VirtualMachine) ([]SnapshotInfo, error)

ListSnapshots lists all snapshots for a virtual machine.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns a list of SnapshotInfo objects containing snapshot details.

Example:

snapshots, err := vcenter.ListSnapshots(ctx, vm)
for _, snap := range snapshots {
    fmt.Printf("%s: %s\n", snap.Name, snap.CreateTime)
}

type VCenterConfig

type VCenterConfig struct {
	VCenter        string `json:"vcenter"`
	Username       string `json:"username"`
	Password       string `json:"password"`
	Datacenter     string `json:"datacenter"`
	Cluster        string `json:"cluster,omitempty"`
	ResourcePool   string `json:"resource_pool,omitempty"`
	StorageCluster string `json:"storage_cluster,omitempty"`
	Datastore      string `json:"datastore,omitempty"`
	Folder         string `json:"folder,omitempty"`
	DomainUser     string `json:"domain_user,omitempty"`
	DomainPassword string `json:"domain_password,omitempty"`
	AdminPassword  string `json:"admin_password,omitempty"`
	Timezone       int    `json:"timezone,omitempty"`
	VerifySSL      bool   `json:"verify_ssl"`
}

VCenterConfig represents the JSON structure used by excel/automation workflows. It matches the schema documented in py-vcenter's vcenter_config.json example file.

func DefaultVCenterConfig

func DefaultVCenterConfig() VCenterConfig

DefaultVCenterConfig returns a filled configuration struct that mirrors the Python example template.

func LoadVCenterConfig

func LoadVCenterConfig(path string) (VCenterConfig, error)

LoadVCenterConfig reads a JSON file and parses it into VCenterConfig.

func MustLoadVCenterConfig

func MustLoadVCenterConfig(path string) VCenterConfig

MustLoadVCenterConfig is a helper that panics on error. Intended for tests/examples only.

func (*VCenterConfig) MergeWithDefaults

func (cfg *VCenterConfig) MergeWithDefaults(defaults VCenterConfig)

MergeWithDefaults overlays blank fields in cfg with values from defaults (non-destructive).

func (VCenterConfig) Save

func (cfg VCenterConfig) Save(path string) error

Save writes the configuration as JSON to the given file path.

func (VCenterConfig) Validate

func (cfg VCenterConfig) Validate() error

Validate performs minimal sanity checks before persisting/using the configuration. Username and password are optional here since they can be provided via credentials file or SSPI.

type VCenterInventory

type VCenterInventory struct {
	Datacenters     []string
	ComputeClusters map[string][]string
	StorageClusters map[string][]string
	Datastores      map[string][]string
	Templates       map[string][]string
	Folders         map[string][]string
	PortGroups      map[string][]string
}

VCenterInventory mirrors the structure exposed by py-vcenter.inventory.VCenterInventory.

func ScanVCenter

func ScanVCenter(ctx context.Context, client *govmomi.Client, opts InventoryOptions) (*VCenterInventory, error)

ScanVCenter collects datacenters, clusters, templates, folders, and networks similar to the Python API.

func (*VCenterInventory) ToFlat

func (inv *VCenterInventory) ToFlat() map[string][]string

ToFlat flattens per-datacenter maps into unique global lists.

type VMInfo

type VMInfo struct {
	Name              string
	PowerState        string
	CPUCount          int32
	CPUCoresPerSocket int32
	CPUSockets        int32
	MemoryMB          int64
	MemoryGB          float64
	Folder            string
	GuestOS           string
	GuestOSFullName   string
	GuestHostname     string
	GuestIPAddress    string
	Networks          []NetworkInfo
	Domain            string
	ToolsStatus       string
	ToolsVersion      string
	UUID              string
	InstanceUUID      string
	Datastore         string
	ResourcePool      string
	Annotation        string
}

VMInfo contains detailed information about a virtual machine

func GetVMInfo

func GetVMInfo(ctx context.Context, vm *object.VirtualMachine) (*VMInfo, error)

GetVMInfo gets detailed information about a virtual machine.

Returns comprehensive information about the VM including hardware configuration, network settings, guest OS details, and current state.

Parameters:

  • ctx: Context for timeout and cancellation
  • vm: VirtualMachine object

Returns a VMInfo struct with VM information.

Example:

vm, _ := vcenter.GetVM(ctx, client, "WebServer01", "")
info, err := vcenter.GetVMInfo(ctx, vm)
fmt.Printf("VM: %s\n", info.Name)
fmt.Printf("CPUs: %d (%d sockets)\n", info.CPUCount, info.CPUSockets)
fmt.Printf("Memory: %.2f GB\n", info.MemoryGB)
fmt.Printf("IP: %s\n", info.GuestIPAddress)
for _, net := range info.Networks {
    fmt.Printf("  Network: %s - %v\n", net.Network, net.IPAddresses)
}

type ValidationError

type ValidationError struct {
	Field   string
	Message string
}

ValidationError is returned when input validation fails

func (*ValidationError) Error

func (e *ValidationError) Error() string

type WindowsCustomizationConfig

type WindowsCustomizationConfig struct {
	ComputerName  string // Required: Windows computer name (max 15 chars)
	AdminPassword string // Required: Local administrator password

	// Timezone - Windows timezone ID (e.g., 85 for W. Europe, 110 for Pacific)
	Timezone int

	// Domain join settings (optional - if Domain is empty, joins WORKGROUP)
	Domain          string // AD domain to join (e.g., "example.com")
	DomainUser      string // Domain admin user (e.g., "admin@example.com")
	DomainPassword  string // Password for domain admin
	MachineObjectOU string // OU for computer object (e.g., "OU=Servers,DC=example,DC=com")

	// Network settings
	Adapters    []NetworkAdapter // Network adapters (empty = one DHCP adapter)
	GlobalDNS   []string         // Global DNS servers
	DNSSuffixes []string         // DNS search suffixes

	// Autologon settings
	AutologonCount int // Number of auto-logons (0 = disabled)
}

WindowsCustomizationConfig contains all settings for Windows VM customization. This unified config supports all scenarios: domain join, workgroup, DHCP, static IP, single NIC, and multi-NIC configurations.

Directories

Path Synopsis
examples
01-connect-sspi command
03-simple-clone command
06-batch-clone command
07-bulk-power command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL