Skip to content

Commit

Permalink
Use libvirt-go-xml struct instead of a string template for domain
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumerose committed Oct 27, 2020
1 parent 71ac779 commit 92225c6
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 124 deletions.
54 changes: 0 additions & 54 deletions pkg/libvirt/constants.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package libvirt

import "fmt"

const (
DriverName = "libvirt"
DriverVersion = "0.12.11"
Expand All @@ -16,56 +14,4 @@ const (
DefaultIOMode = "threads"
DefaultSSHUser = "core"
DefaultSSHPort = 22
DomainTemplate = `<domain type='kvm'>
<name>{{ .DomainName }}</name>
<memory unit='MB'>{{ .Memory }}</memory>
<vcpu placement='static'>{{ .CPU }}</vcpu>
<features><acpi/><apic/><pae/></features>
<cpu mode='host-passthrough'>
<feature policy="disable" name="rdrand"/>
</cpu>
<os>
<type arch='x86_64'>hvm</type>
<boot dev='hd'/>
<bootmenu enable='no'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='{{ .CacheMode }}' io='{{ .IOMode }}' />
<source file='{{ .DiskPath }}'/>
<target dev='vda' bus='virtio'/>
</disk>
<graphics type='vnc' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<console type='pty'></console>
<channel type='pty'>
<target type='virtio' name='org.qemu.guest_agent.0'/>
</channel>
<rng model='virtio'>
<backend model='random'>/dev/urandom</backend>
</rng>
{{- range .ExtraDevices }}
{{ . }}
{{- end }}
</devices>
</domain>`
VSockDevice = `<vsock model='virtio'><cid auto='yes'/></vsock>`
)

func NetworkDevice(networkName string) string {
return fmt.Sprintf(`<interface type='network'>
<mac address='52:fd:fc:07:21:82'/>
<source network='%s'/>
<model type='virtio'/>
</interface>`, networkName)
}
136 changes: 136 additions & 0 deletions pkg/libvirt/domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package libvirt

import (
libvirtxml "github.com/libvirt/libvirt-go-xml"
)

func domainXML(d *Driver) (string, error) {
domain := libvirtxml.Domain{
Type: "kvm",
Name: d.MachineName,
Memory: &libvirtxml.DomainMemory{
Value: uint(d.Memory),
Unit: "MB",
},
VCPU: &libvirtxml.DomainVCPU{
Placement: "static",
Value: uint(d.CPU),
},
Features: &libvirtxml.DomainFeatureList{
ACPI: &libvirtxml.DomainFeature{},
APIC: &libvirtxml.DomainFeatureAPIC{},
PAE: &libvirtxml.DomainFeature{},
},
CPU: &libvirtxml.DomainCPU{
Mode: "host-passthrough",
Features: []libvirtxml.DomainCPUFeature{
{
Policy: "disable",
Name: "rdrand",
},
},
},
OS: &libvirtxml.DomainOS{
Type: &libvirtxml.DomainOSType{
Arch: "x86_64",
Type: "hvm",
},
BootDevices: []libvirtxml.DomainBootDevice{
{
Dev: "hd",
},
},
BootMenu: &libvirtxml.DomainBootMenu{
Enable: "no",
},
},
Clock: &libvirtxml.DomainClock{
Offset: "utc",
},
Devices: &libvirtxml.DomainDeviceList{
Disks: []libvirtxml.DomainDisk{
{
Device: "disk",
Driver: &libvirtxml.DomainDiskDriver{
Name: "qemu",
Type: "qcow2",
Cache: d.CacheMode,
IO: d.IOMode,
},
Source: &libvirtxml.DomainDiskSource{
File: &libvirtxml.DomainDiskSourceFile{
File: d.getDiskImagePath(),
},
},
Target: &libvirtxml.DomainDiskTarget{
Dev: "vda",
Bus: "virtio",
},
},
},
Graphics: []libvirtxml.DomainGraphic{
{
VNC: &libvirtxml.DomainGraphicVNC{
AutoPort: "yes",
Listen: "127.0.0.1",
Listeners: []libvirtxml.DomainGraphicListener{
{
Address: &libvirtxml.DomainGraphicListenerAddress{
Address: "127.0.0.1",
},
},
},
},
},
},
Consoles: []libvirtxml.DomainConsole{
{},
},
Channels: []libvirtxml.DomainChannel{
{
Target: &libvirtxml.DomainChannelTarget{
VirtIO: &libvirtxml.DomainChannelTargetVirtIO{
Name: "org.qemu.guest_agent.0",
},
},
},
},
RNGs: []libvirtxml.DomainRNG{
{
Model: "virtio",
Backend: &libvirtxml.DomainRNGBackend{
Random: &libvirtxml.DomainRNGBackendRandom{
Device: "/dev/urandom",
},
},
},
},
},
}
if d.Network != "" {
domain.Devices.Interfaces = []libvirtxml.DomainInterface{
{
MAC: &libvirtxml.DomainInterfaceMAC{
Address: "52:fd:fc:07:21:82",
},
Source: &libvirtxml.DomainInterfaceSource{
Network: &libvirtxml.DomainInterfaceSourceNetwork{
Network: d.Network,
},
},
Model: &libvirtxml.DomainInterfaceModel{
Type: "virtio",
},
},
}
}
if d.VSock {
domain.Devices.VSock = &libvirtxml.DomainVSock{
Model: "virtio",
CID: &libvirtxml.DomainVSockCID{
Auto: "yes",
},
}
}
return domain.Marshal()
}
74 changes: 35 additions & 39 deletions pkg/libvirt/libvirt_test.go → pkg/libvirt/domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,49 +28,45 @@ func TestTemplating(t *testing.T) {
})

assert.NoError(t, err)
assert.Equal(t, `<domain type='kvm'>
assert.Equal(t, `<domain type="kvm">
<name>domain</name>
<memory unit='MB'>4096</memory>
<vcpu placement='static'>4</vcpu>
<features><acpi/><apic/><pae/></features>
<cpu mode='host-passthrough'>
<feature policy="disable" name="rdrand"/>
</cpu>
<memory unit="MB">4096</memory>
<vcpu placement="static">4</vcpu>
<os>
<type arch='x86_64'>hvm</type>
<boot dev='hd'/>
<bootmenu enable='no'/>
<type arch="x86_64">hvm</type>
<boot dev="hd"></boot>
<bootmenu enable="no"></bootmenu>
</os>
<features>
<acpi/>
<apic/>
<pae/>
<pae></pae>
<acpi></acpi>
<apic></apic>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<cpu mode="host-passthrough">
<feature policy="disable" name="rdrand"></feature>
</cpu>
<clock offset="utc"></clock>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='default' io='threads' />
<source file='machines/domain/domain.test'/>
<target dev='vda' bus='virtio'/>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2" cache="default" io="threads"></driver>
<source file="machines/domain/domain.test"></source>
<target dev="vda" bus="virtio"></target>
</disk>
<graphics type='vnc' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
</graphics>
<console type='pty'></console>
<channel type='pty'>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<interface type="network">
<mac address="52:fd:fc:07:21:82"></mac>
<source network="network"></source>
<model type="virtio"></model>
</interface>
<console></console>
<channel>
<target type="virtio" name="org.qemu.guest_agent.0"></target>
</channel>
<rng model='virtio'>
<backend model='random'>/dev/urandom</backend>
<graphics type="vnc" autoport="yes" listen="127.0.0.1">
<listen type="address" address="127.0.0.1"></listen>
</graphics>
<rng model="virtio">
<backend model="random">/dev/urandom</backend>
</rng>
<interface type='network'>
<mac address='52:fd:fc:07:21:82'/>
<source network='network'/>
<model type='virtio'/>
</interface>
</devices>
</domain>`, xml)
}
Expand All @@ -94,7 +90,7 @@ func TestVSockTemplating(t *testing.T) {
},
})
assert.NoError(t, err)
assert.Regexp(t, `(?s)<devices>(.*?)<vsock model='virtio'><cid auto='yes'/></vsock>(.*?)</devices>`, xml)
assert.Regexp(t, `(?s)<devices>(.*?)<vsock model="virtio">\s*<cid auto="yes">\s*</cid>\s*</vsock>(.*?)</devices>`, xml)
}

func TestNetworkTemplating(t *testing.T) {
Expand All @@ -116,9 +112,9 @@ func TestNetworkTemplating(t *testing.T) {
},
})
assert.NoError(t, err)
assert.Contains(t, xml, `<interface type='network'>
<mac address='52:fd:fc:07:21:82'/>
<source network='crc'/>
<model type='virtio'/>
assert.Contains(t, xml, `<interface type="network">
<mac address="52:fd:fc:07:21:82"></mac>
<source network="crc"></source>
<model type="virtio"></model>
</interface>`)
}
31 changes: 0 additions & 31 deletions pkg/libvirt/libvirt.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package libvirt

import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
Expand All @@ -11,7 +10,6 @@ import (
"os/exec"
"path/filepath"
"strings"
"text/template"
"time"

"github.com/libvirt/libvirt-go"
Expand Down Expand Up @@ -400,35 +398,6 @@ func (d *Driver) Create() error {
return d.Start()
}

func domainXML(d *Driver) (string, error) {
tmpl, err := template.New("domain").Parse(DomainTemplate)
if err != nil {
return "", err
}

config := DomainConfig{
DomainName: d.MachineName,
Memory: d.Memory,
CPU: d.CPU,
CacheMode: d.CacheMode,
IOMode: d.IOMode,
DiskPath: d.getDiskImagePath(),
}
if d.Network != "" {
config.ExtraDevices = append(config.ExtraDevices, NetworkDevice(d.Network))
}
if d.VSock {
config.ExtraDevices = append(config.ExtraDevices, VSockDevice)
}

var xml bytes.Buffer
err = tmpl.Execute(&xml, config)
if err != nil {
return "", err
}
return xml.String(), nil
}

func createImage(src, dst string) error {
start := time.Now()
defer func() {
Expand Down

0 comments on commit 92225c6

Please sign in to comment.