diff options
Diffstat (limited to 'libvirt')
-rw-r--r-- | libvirt/domain_def.go | 29 | ||||
-rw-r--r-- | libvirt/resource_libvirt_domain.go | 49 | ||||
-rw-r--r-- | libvirt/utils_domain_def.go | 50 | ||||
-rw-r--r-- | libvirt/utils_libvirt.go | 15 | ||||
-rw-r--r-- | libvirt/utils_libvirt_test.go | 96 |
5 files changed, 228 insertions, 11 deletions
diff --git a/libvirt/domain_def.go b/libvirt/domain_def.go index 250fc642..1ade1f5a 100644 --- a/libvirt/domain_def.go +++ b/libvirt/domain_def.go @@ -1,9 +1,9 @@ package libvirt import ( + libvirt "github.com/libvirt/libvirt-go" + libvirtxml "github.com/libvirt/libvirt-go-xml" "os" - - "github.com/libvirt/libvirt-go-xml" ) func newFilesystemDef() libvirtxml.DomainFilesystem { @@ -20,7 +20,9 @@ func newDomainDef() libvirtxml.Domain { domainDef := libvirtxml.Domain{ OS: &libvirtxml.DomainOS{ Type: &libvirtxml.DomainOSType{ - Type: "hvm", + Type: "hvm", + Arch: "x86_64", + Machine: "pc", }, }, Memory: &libvirtxml.DomainMemory{ @@ -75,3 +77,24 @@ func newDomainDef() libvirtxml.Domain { return domainDef } + +func newDomainDefForConnection(virConn *libvirt.Connect) (libvirtxml.Domain, error) { + d := newDomainDef() + caps, err := getHostCapabilities(virConn) + if err != nil { + return d, err + } + guest, err := getGuestForArchType(caps, d.OS.Type.Arch, d.OS.Type.Type) + if err != nil { + return d, err + } + + d.Devices.Emulator = guest.Arch.Emulator + + canonicalmachine, err := getCanonicalMachineName(caps, d.OS.Type.Arch, d.OS.Type.Type, d.OS.Type.Machine) + if err != nil { + return d, err + } + d.OS.Type.Machine = canonicalmachine + return d, nil +} diff --git a/libvirt/resource_libvirt_domain.go b/libvirt/resource_libvirt_domain.go index 571b7359..64bdabe4 100644 --- a/libvirt/resource_libvirt_domain.go +++ b/libvirt/resource_libvirt_domain.go @@ -148,12 +148,14 @@ func resourceLibvirtDomain() *schema.Resource { Required: false, }, "machine": &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, Optional: true, + Default: "pc", }, "arch": &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, Optional: true, + Default: "x86_64", }, "boot_device": &schema.Schema{ Type: schema.TypeList, @@ -163,6 +165,11 @@ func resourceLibvirtDomain() *schema.Resource { Schema: bootDeviceSchema(), }, }, + "emulator": &schema.Schema{ + Type: schema.TypeString, + Default: "/usr/bin/qemu-system-x86_64", + Optional: true, + }, }, } } @@ -208,8 +215,10 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("The libvirt connection was nil.") } - domainDef := newDomainDef() - + domainDef, err := newDomainDefForConnection(virConn) + if err != nil { + return err + } if name, ok := d.GetOk("name"); ok { domainDef.Name = name.(string) } @@ -270,7 +279,8 @@ func resourceLibvirtDomainCreate(d *schema.ResourceData, meta interface{}) error domainDef.OS.Type.Arch = d.Get("arch").(string) domainDef.OS.Type.Machine = d.Get("machine").(string) - + domainDef.Devices.Emulator = d.Get("emulator").(string) + if firmware, ok := d.GetOk("firmware"); ok { firmwareFile := firmware.(string) if _, err := os.Stat(firmwareFile); os.IsNotExist(err) { @@ -814,7 +824,11 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] read: obtained XML desc for domain:\n%s", xmlDesc) - domainDef := newDomainDef() + domainDef, err := newDomainDefForConnection(virConn) + if err != nil { + return err + } + err = xml.Unmarshal([]byte(xmlDesc), &domainDef) if err != nil { return fmt.Errorf("Error reading libvirt domain XML description: %s", err) @@ -831,7 +845,24 @@ func resourceLibvirtDomainRead(d *schema.ResourceData, meta interface{}) error { d.Set("firmware", domainDef.OS.Loader) d.Set("nvram", domainDef.OS.NVRam) d.Set("cpu", domainDef.CPU) + d.Set("arch", domainDef.OS.Type.Arch) d.Set("autostart", autostart) + d.Set("arch", domainDef.OS.Type.Arch) + + caps, err := getHostCapabilities(virConn) + if err != nil { + return err + } + machine, err := getOriginalMachineName(caps, domainDef.OS.Type.Arch, domainDef.OS.Type.Type, + domainDef.OS.Type.Machine) + if err != nil { + return err + } + d.Set("machine", machine) + + // Emulator is the same as the default don't set it in domainDef + // or it will show as changed + d.Set("emulator", domainDef.Devices.Emulator) running, err := isDomainRunning(*domain) if err != nil { @@ -1012,7 +1043,11 @@ func resourceLibvirtDomainDelete(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("Error retrieving libvirt domain XML description: %s", err) } - domainDef := newDomainDef() + domainDef, err := newDomainDefForConnection(virConn) + if err != nil { + return err + } + err = xml.Unmarshal([]byte(xmlDesc), &domainDef) if err != nil { return fmt.Errorf("Error reading libvirt domain XML description: %s", err) diff --git a/libvirt/utils_domain_def.go b/libvirt/utils_domain_def.go new file mode 100644 index 00000000..2f7f74a6 --- /dev/null +++ b/libvirt/utils_domain_def.go @@ -0,0 +1,50 @@ +package libvirt + +import ( + "fmt" + libvirtxml "github.com/libvirt/libvirt-go-xml" + "log" +) + +func getGuestForArchType(caps libvirtxml.Caps, arch string, virttype string) (libvirtxml.CapsGuest, error) { + for _, guest := range caps.Guests { + log.Printf("[TRACE] Checking for %s/%s against %s/%s\n", arch, virttype, guest.Arch.Name, guest.OSType) + if guest.Arch.Name == arch && guest.OSType == virttype { + log.Printf("[DEBUG] Found %d machines in guest for %s/%s", len(guest.Arch.Machines), arch, virttype) + return guest, nil + } + } + return libvirtxml.CapsGuest{}, fmt.Errorf("[DEBUG] Could not find any guests for architecure type %s/%s", virttype, arch) +} + +func getCanonicalMachineName(caps libvirtxml.Caps, arch string, virttype string, targetmachine string) (string, error) { + guest, err := getGuestForArchType(caps, arch, virttype) + if err != nil { + return "", err + } + + for _, machine := range guest.Arch.Machines { + if machine.Name == targetmachine { + if machine.Canonical != nil { + return *machine.Canonical, nil + } + return machine.Name, nil + } + } + return "", fmt.Errorf("[WARN] Cannot find machine type %s for %s/%s in %v", targetmachine, virttype, arch, caps) +} + + +func getOriginalMachineName(caps libvirtxml.Caps, arch string, virttype string, targetmachine string) (string, error) { + guest, err := getGuestForArchType(caps, arch, virttype) + if err != nil { + return "", err + } + + for _, machine := range guest.Arch.Machines { + if machine.Canonical != nil && *machine.Canonical == targetmachine { + return machine.Name, nil + } + } + return targetmachine, nil // There wasn't a canonical mapping to this +} diff --git a/libvirt/utils_libvirt.go b/libvirt/utils_libvirt.go index cc86b1ec..22816769 100644 --- a/libvirt/utils_libvirt.go +++ b/libvirt/utils_libvirt.go @@ -5,7 +5,7 @@ import ( "log" libvirt "github.com/libvirt/libvirt-go" - "github.com/libvirt/libvirt-go-xml" + libvirtxml "github.com/libvirt/libvirt-go-xml" ) func getHostXMLDesc(ip, mac, name string) string { @@ -68,3 +68,16 @@ func getHostArchitecture(virConn *libvirt.Connect) (string, error) { return capabilities.Host.CPU.Arch, nil } + +func getHostCapabilities(virConn *libvirt.Connect) (libvirtxml.Caps, error) { + // We should perhaps think of storing this on the connect object + // on first call to avoid the back and forth + caps := libvirtxml.Caps{} + capsXML, err := virConn.GetCapabilities() + if err != nil { + return caps, err + } + xml.Unmarshal([]byte(capsXML), &caps) + log.Printf("[TRACE] Capabilities of host \n %+v", caps) + return caps, nil +} diff --git a/libvirt/utils_libvirt_test.go b/libvirt/utils_libvirt_test.go index fa76cd84..38d90136 100644 --- a/libvirt/utils_libvirt_test.go +++ b/libvirt/utils_libvirt_test.go @@ -3,8 +3,11 @@ package libvirt import ( "encoding/xml" "testing" + "time" + libvirt "github.com/libvirt/libvirt-go" "github.com/libvirt/libvirt-go-xml" + "os" ) func TestGetHostXMLDesc(t *testing.T) { @@ -32,3 +35,96 @@ func TestGetHostXMLDesc(t *testing.T) { t.Errorf("expected name %s, got %s", name, dd.Name) } } + +func connect(t *testing.T) *libvirt.Connect { + conn, err := libvirt.NewConnect(os.Getenv("LIBVIRT_DEFAULT_URI")) + if err != nil { + t.Fatal(err) + } + + return conn +} + +func TestGetHostArchitecture(t *testing.T) { + + conn := connect(t) + defer conn.Close() + + arch, err := getHostArchitecture(conn) + + if err != nil { + t.Errorf("error %v", err) + } + + t.Logf("[DEBUG] arch - %s", arch) + + if arch == "" { + t.Errorf("arch is blank.") + } +} + +func TestGetCanonicalMachineName(t *testing.T) { + + conn := connect(t) + defer conn.Close() + arch := "x86_64" + virttype := "hvm" + machine := "pc" + + caps,err := getHostCapabilities(conn) + if err != nil { + t.Error(err) + } + + name, err := getCanonicalMachineName(caps, arch, virttype, machine) + + if err != nil { + t.Errorf("Could not get canonical name for %s/%s", arch, machine) + return + } + + t.Logf("Canonical name for %s/%s = %s", arch, machine, name) +} + +func TestGetOriginalMachineName(t *testing.T) { + conn := connect(t) + defer conn.Close() + arch := "x86_64" + virttype := "hvm" + machine := "pc" + + caps,err := getHostCapabilities(conn) + if err != nil { + t.Error(err) + } + + canonname, err := getCanonicalMachineName(caps, arch, virttype, machine) + if err != nil { + t.Error(err) + } + reversename, err := getOriginalMachineName(caps, arch, virttype, canonname) + if err != nil { + t.Error(err) + } + if reversename != machine { + t.Errorf("Cannot reverse canonical machine lookup") + } + + t.Logf("Reverse canonical lookup for %s is %s which matches %s", canonname, reversename, machine) +} + +func TestGetHostCapabilties(t *testing.T) { + start := time.Now() + conn := connect(t) + defer conn.Close() + caps,err := getHostCapabilities(conn) + if err != nil { + t.Errorf("Can't get host capabilties") + } + if caps.Host.UUID == "" { + t.Errorf("Host has no UUID!") + } + + elapsed := time.Since(start) + t.Logf("[DEBUG] Get host capabilites took %s", elapsed) +} |