Skip to content

Commit 55578c7

Browse files
committed
Add domain package
The domain package helps to abstract and builds a libvirt domain. Signed-off-by: Alice Frosi <[email protected]>
1 parent 4719084 commit 55578c7

File tree

3 files changed

+245
-0
lines changed

3 files changed

+245
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ require (
188188
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
189189
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
190190
gopkg.in/yaml.v3 v3.0.1 // indirect
191+
libvirt.org/go/libvirtxml v1.9008.0
191192
sigs.k8s.io/yaml v1.4.0 // indirect
192193
tags.cncf.io/container-device-interface v0.6.2 // indirect
193194
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
760760
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
761761
libvirt.org/go/libvirt v1.10002.0 h1:ZFQsv1G8HE8SYhLBqaOuxze6+f00x96khLwn54aWJnI=
762762
libvirt.org/go/libvirt v1.10002.0/go.mod h1:1WiFE8EjZfq+FCVog+rvr1yatKbKZ9FaFMZgEqxEJqQ=
763+
libvirt.org/go/libvirtxml v1.9008.0 h1:xo2U9SqUsufTFtbyjiqs6oDdF329cvtRdqttWN7eojk=
764+
libvirt.org/go/libvirtxml v1.9008.0/go.mod h1:7Oq2BLDstLr/XtoQD8Fr3mfDNrzlI3utYKySXF2xkng=
763765
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
764766
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
765767
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

pkg/vm/domain/domain.go

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package domain
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"os/exec"
8+
9+
"github.com/sirupsen/logrus"
10+
"libvirt.org/go/libvirtxml"
11+
)
12+
13+
type DomainOption func(d *libvirtxml.Domain)
14+
15+
const (
16+
MemoryMemfd = "memfd"
17+
MemoryAccessModeShared = "shared"
18+
)
19+
20+
type DiskDriverType string
21+
22+
func (d DiskDriverType) String() string {
23+
return string(d)
24+
}
25+
26+
const (
27+
DiskDriverQCOW2 DiskDriverType = "qcow2"
28+
DiskDriverRaw DiskDriverType = "raw"
29+
)
30+
31+
type DiskBus string
32+
33+
func (b DiskBus) String() string {
34+
return string(b)
35+
}
36+
37+
const (
38+
DiskBusSCSI DiskBus = "scsi"
39+
DiskBusVirtio DiskBus = "virtio"
40+
)
41+
42+
func NewDomain(opts ...DomainOption) *libvirtxml.Domain {
43+
domain := &libvirtxml.Domain{}
44+
for _, f := range opts {
45+
f(domain)
46+
}
47+
48+
return domain
49+
}
50+
51+
func WithName(name string) DomainOption {
52+
return func(d *libvirtxml.Domain) {
53+
d.Name = name
54+
}
55+
}
56+
57+
func WithMemory(memory uint) DomainOption {
58+
return func(d *libvirtxml.Domain) {
59+
d.Memory = &libvirtxml.DomainMemory{
60+
Value: memory,
61+
Unit: "MiB",
62+
}
63+
}
64+
}
65+
66+
func WithMemoryBackingForVirtiofs() DomainOption {
67+
return func(d *libvirtxml.Domain) {
68+
d.MemoryBacking = &libvirtxml.DomainMemoryBacking{
69+
MemorySource: &libvirtxml.DomainMemorySource{Type: MemoryMemfd},
70+
MemoryAccess: &libvirtxml.DomainMemoryAccess{Mode: MemoryAccessModeShared},
71+
}
72+
}
73+
}
74+
75+
func WithCPUHostModel() DomainOption {
76+
return func(d *libvirtxml.Domain) {
77+
d.CPU = &libvirtxml.DomainCPU{
78+
Mode: "host-model",
79+
}
80+
}
81+
}
82+
83+
func WithVCPUs(cpus uint) DomainOption {
84+
return func(d *libvirtxml.Domain) {
85+
d.VCPU = &libvirtxml.DomainVCPU{Value: cpus}
86+
}
87+
}
88+
89+
func allocateDevices(d *libvirtxml.Domain) {
90+
if d.Devices == nil {
91+
d.Devices = &libvirtxml.DomainDeviceList{}
92+
}
93+
}
94+
95+
func WithFilesystem(source, target string) DomainOption {
96+
return func(d *libvirtxml.Domain) {
97+
allocateDevices(d)
98+
d.Devices.Filesystems = append(d.Devices.Filesystems, libvirtxml.DomainFilesystem{
99+
Driver: &libvirtxml.DomainFilesystemDriver{
100+
Type: "virtiofs",
101+
},
102+
Source: &libvirtxml.DomainFilesystemSource{
103+
Mount: &libvirtxml.DomainFilesystemSourceMount{
104+
Dir: source,
105+
},
106+
},
107+
Target: &libvirtxml.DomainFilesystemTarget{
108+
Dir: target,
109+
},
110+
})
111+
}
112+
}
113+
114+
func WithDisk(path, serial, dev string, diskType DiskDriverType, bus DiskBus) DomainOption {
115+
return func(d *libvirtxml.Domain) {
116+
allocateDevices(d)
117+
d.Devices.Disks = append(d.Devices.Disks, libvirtxml.DomainDisk{
118+
Device: "disk",
119+
Driver: &libvirtxml.DomainDiskDriver{
120+
Name: "qemu",
121+
Type: diskType.String(),
122+
},
123+
Source: &libvirtxml.DomainDiskSource{
124+
File: &libvirtxml.DomainDiskSourceFile{
125+
File: path,
126+
},
127+
},
128+
Target: &libvirtxml.DomainDiskTarget{
129+
Bus: bus.String(),
130+
Dev: dev,
131+
},
132+
Serial: serial,
133+
})
134+
}
135+
}
136+
137+
func WithSerialConsole() DomainOption {
138+
return func(d *libvirtxml.Domain) {
139+
allocateDevices(d)
140+
d.Devices.Consoles = append(d.Devices.Consoles, libvirtxml.DomainConsole{
141+
Source: &libvirtxml.DomainChardevSource{Pty: &libvirtxml.DomainChardevSourcePty{}},
142+
Target: &libvirtxml.DomainConsoleTarget{
143+
Type: "serial",
144+
},
145+
})
146+
147+
}
148+
}
149+
150+
func WithInterface(mac, model string) DomainOption {
151+
return func(d *libvirtxml.Domain) {
152+
allocateDevices(d)
153+
d.Devices.Interfaces = append(d.Devices.Interfaces, libvirtxml.DomainInterface{
154+
Source: &libvirtxml.DomainInterfaceSource{
155+
User: &libvirtxml.DomainInterfaceSourceUser{},
156+
},
157+
MAC: &libvirtxml.DomainInterfaceMAC{
158+
Address: mac,
159+
},
160+
Model: &libvirtxml.DomainInterfaceModel{
161+
Type: model,
162+
},
163+
})
164+
}
165+
}
166+
167+
func WithVSOCK(cid uint) DomainOption {
168+
return func(d *libvirtxml.Domain) {
169+
allocateDevices(d)
170+
d.Devices.VSock = &libvirtxml.DomainVSock{
171+
Model: "virtio",
172+
CID: &libvirtxml.DomainVSockCID{
173+
Address: fmt.Sprintf("%d", cid),
174+
},
175+
}
176+
}
177+
}
178+
179+
func WithUUID(uuid string) DomainOption {
180+
return func(d *libvirtxml.Domain) {
181+
d.UUID = uuid
182+
}
183+
}
184+
185+
func WithKVM() DomainOption {
186+
return func(d *libvirtxml.Domain) {
187+
d.Type = "kvm"
188+
}
189+
}
190+
191+
func WithOS() DomainOption {
192+
// TODO: fix this for multiarch
193+
return func(d *libvirtxml.Domain) {
194+
d.OS = &libvirtxml.DomainOS{
195+
Type: &libvirtxml.DomainOSType{
196+
Arch: "x86_64",
197+
Machine: "q35",
198+
Type: "hvm",
199+
},
200+
}
201+
}
202+
}
203+
204+
type diskInfo struct {
205+
Format string `json:"format"`
206+
BackingFile string `json:"backing-filename"`
207+
ActualSize int64 `json:"actual-size"`
208+
VirtualSize int64 `json:"virtual-size"`
209+
}
210+
211+
func GetDiskInfo(imagePath string) (DiskDriverType, error) {
212+
path, err := exec.LookPath("qemu-img")
213+
if err != nil {
214+
return "", fmt.Errorf("qemu-img not found: %v\n", err)
215+
}
216+
217+
args := []string{"info", imagePath, "--output", "json"}
218+
cmd := exec.Command(path, args...)
219+
logrus.Debugf("Execute: %s", cmd.String())
220+
stderr, err := cmd.StderrPipe()
221+
if err != nil {
222+
return "", fmt.Errorf("failed to get stderr for qemu-img command: %v", err)
223+
}
224+
out, err := cmd.Output()
225+
if err != nil {
226+
errout, _ := io.ReadAll(stderr)
227+
return "", fmt.Errorf("failed to invoke qemu-img: %v: %s", err, errout)
228+
}
229+
info := &diskInfo{}
230+
err = json.Unmarshal(out, info)
231+
if err != nil {
232+
return "", fmt.Errorf("failed to parse disk info: %v", err)
233+
}
234+
switch info.Format {
235+
case "qcow2":
236+
return DiskDriverQCOW2, nil
237+
case "raw":
238+
return DiskDriverRaw, nil
239+
default:
240+
return "", fmt.Errorf("Unsupported format: %s", info.Format)
241+
}
242+
}

0 commit comments

Comments
 (0)