Skip to content

Commit b6e74b8

Browse files
committed
Add Validate method to VirtioDevice interface
- Use the newly added method to validate the devices - Error out when qcow2 image is detected in block device validation
1 parent 97c5364 commit b6e74b8

File tree

4 files changed

+99
-14
lines changed

4 files changed

+99
-14
lines changed

cmd/vfkit/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ func newVMConfiguration(opts *cmdline.Options) (*config.VirtualMachine, error) {
104104
return nil, err
105105
}
106106

107+
if err := vmConfig.ValidateDevices(); err != nil {
108+
return nil, err
109+
}
110+
107111
if err := vmConfig.AddIgnitionFileFromCmdLine(opts.IgnitionPath); err != nil {
108112
return nil, fmt.Errorf("failed to add ignition file: %w", err)
109113
}

pkg/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,15 @@ func (vm *VirtualMachine) AddIgnitionFileFromCmdLine(cmdlineOpts string) error {
250250
return nil
251251
}
252252

253+
func (vm *VirtualMachine) ValidateDevices() error {
254+
for _, device := range vm.Devices {
255+
if err := device.Validate(); err != nil {
256+
return err
257+
}
258+
}
259+
return nil
260+
}
261+
253262
func TimeSyncNew(vsockPort uint) (VMComponent, error) {
254263

255264
if vsockPort > math.MaxUint32 {

pkg/config/config_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package config
22

33
import (
4+
"os"
5+
"os/exec"
6+
"path/filepath"
47
"testing"
58

69
"github.com/stretchr/testify/assert"
@@ -44,3 +47,23 @@ func TestNetworkBlockDevice_NoDevice(t *testing.T) {
4447
nbdItem := vm.NetworkBlockDevice("nbd2")
4548
require.Nil(t, nbdItem)
4649
}
50+
51+
func TestVirtualMachine_ValidateBlockDevices(t *testing.T) {
52+
vm := &VirtualMachine{}
53+
54+
tmpDir := t.TempDir()
55+
imagePath := filepath.Join(tmpDir, "disk.qcow2")
56+
size := "1G"
57+
58+
cmd := exec.Command("qemu-img", "create", "-f", "qcow2", imagePath, size)
59+
err := cmd.Run()
60+
require.NoError(t, err)
61+
62+
dev, err := VirtioBlkNew(imagePath)
63+
require.NoError(t, err)
64+
vm.Devices = append(vm.Devices, dev)
65+
defer os.Remove(imagePath)
66+
67+
err = vm.ValidateDevices()
68+
require.Error(t, err)
69+
}

pkg/config/virtio.go

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import (
1111
)
1212

1313
// The VirtioDevice interface is an interface which is implemented by all virtio devices.
14-
type VirtioDevice VMComponent
14+
type VirtioDevice interface {
15+
VMComponent
16+
Validate() error
17+
}
1518

1619
const (
1720
// Possible values for VirtioInput.InputType
@@ -140,6 +143,10 @@ func (v *VirtioBalloon) ToCmdLine() ([]string, error) {
140143
return []string{"--device", "virtio-balloon"}, nil
141144
}
142145

146+
func (v *VirtioBalloon) Validate() error {
147+
return nil
148+
}
149+
143150
type option struct {
144151
key string
145152
value string
@@ -230,7 +237,7 @@ func VirtioSerialNewStdio() (VirtioDevice, error) {
230237
}, nil
231238
}
232239

233-
func (dev *VirtioSerial) validate() error {
240+
func (dev *VirtioSerial) Validate() error {
234241
if dev.LogFile != "" && dev.UsesStdio {
235242
return fmt.Errorf("'logFilePath' and 'stdio' cannot be set at the same time")
236243
}
@@ -242,7 +249,7 @@ func (dev *VirtioSerial) validate() error {
242249
}
243250

244251
func (dev *VirtioSerial) ToCmdLine() ([]string, error) {
245-
if err := dev.validate(); err != nil {
252+
if err := dev.Validate(); err != nil {
246253
return nil, err
247254
}
248255
if dev.UsesStdio {
@@ -267,7 +274,7 @@ func (dev *VirtioSerial) FromOptions(options []option) error {
267274
}
268275
}
269276

270-
return dev.validate()
277+
return dev.Validate()
271278
}
272279

273280
// VirtioInputNew creates a new input device for the virtual machine.
@@ -277,14 +284,14 @@ func VirtioInputNew(inputType string) (VirtioDevice, error) {
277284
dev := &VirtioInput{
278285
InputType: inputType,
279286
}
280-
if err := dev.validate(); err != nil {
287+
if err := dev.Validate(); err != nil {
281288
return nil, err
282289
}
283290

284291
return dev, nil
285292
}
286293

287-
func (dev *VirtioInput) validate() error {
294+
func (dev *VirtioInput) Validate() error {
288295
if dev.InputType != VirtioInputPointingDevice && dev.InputType != VirtioInputKeyboardDevice {
289296
return fmt.Errorf("unknown option for virtio-input devices: %s", dev.InputType)
290297
}
@@ -293,7 +300,7 @@ func (dev *VirtioInput) validate() error {
293300
}
294301

295302
func (dev *VirtioInput) ToCmdLine() ([]string, error) {
296-
if err := dev.validate(); err != nil {
303+
if err := dev.Validate(); err != nil {
297304
return nil, err
298305
}
299306

@@ -312,7 +319,7 @@ func (dev *VirtioInput) FromOptions(options []option) error {
312319
return fmt.Errorf("unknown option for virtio-input devices: %s", option.key)
313320
}
314321
}
315-
return dev.validate()
322+
return dev.Validate()
316323
}
317324

318325
// VirtioGPUNew creates a new gpu device for the virtual machine.
@@ -328,7 +335,7 @@ func VirtioGPUNew() (VirtioDevice, error) {
328335
}, nil
329336
}
330337

331-
func (dev *VirtioGPU) validate() error {
338+
func (dev *VirtioGPU) Validate() error {
332339
if dev.Height < 1 || dev.Width < 1 {
333340
return fmt.Errorf("invalid dimensions for virtio-gpu device resolution: %dx%d", dev.Width, dev.Height)
334341
}
@@ -337,7 +344,7 @@ func (dev *VirtioGPU) validate() error {
337344
}
338345

339346
func (dev *VirtioGPU) ToCmdLine() ([]string, error) {
340-
if err := dev.validate(); err != nil {
347+
if err := dev.Validate(); err != nil {
341348
return nil, err
342349
}
343350

@@ -371,7 +378,7 @@ func (dev *VirtioGPU) FromOptions(options []option) error {
371378
dev.Height = defaultVirtioGPUResolutionHeight
372379
}
373380

374-
return dev.validate()
381+
return dev.Validate()
375382
}
376383

377384
// VirtioNetNew creates a new network device for the virtual machine. It will
@@ -407,7 +414,7 @@ func (dev *VirtioNet) SetUnixSocketPath(path string) {
407414
dev.Nat = false
408415
}
409416

410-
func (dev *VirtioNet) validate() error {
417+
func (dev *VirtioNet) Validate() error {
411418
if dev.Nat && dev.Socket != nil {
412419
return fmt.Errorf("'nat' and 'fd' cannot be set at the same time")
413420
}
@@ -425,7 +432,7 @@ func (dev *VirtioNet) validate() error {
425432
}
426433

427434
func (dev *VirtioNet) ToCmdLine() ([]string, error) {
428-
if err := dev.validate(); err != nil {
435+
if err := dev.Validate(); err != nil {
429436
return nil, err
430437
}
431438

@@ -474,7 +481,7 @@ func (dev *VirtioNet) FromOptions(options []option) error {
474481
}
475482
}
476483

477-
return dev.validate()
484+
return dev.Validate()
478485
}
479486

480487
// VirtioRngNew creates a new random number generator device to feed entropy
@@ -494,6 +501,10 @@ func (dev *VirtioRng) FromOptions(options []option) error {
494501
return nil
495502
}
496503

504+
func (dev *VirtioRng) Validate() error {
505+
return nil
506+
}
507+
497508
func nvmExpressControllerNewEmpty() *NVMExpressController {
498509
return &NVMExpressController{
499510
DiskStorageConfig: DiskStorageConfig{
@@ -551,6 +562,24 @@ func (dev *VirtioBlk) FromOptions(options []option) error {
551562
return dev.DiskStorageConfig.FromOptions(unhandledOpts)
552563
}
553564

565+
func (dev *VirtioBlk) Validate() error {
566+
imgPath := dev.ImagePath
567+
file, err := os.Open(imgPath)
568+
if err != nil {
569+
return fmt.Errorf("failed to open file %s: %v", imgPath, err)
570+
}
571+
defer file.Close()
572+
header := make([]byte, 4)
573+
_, err = file.Read(header)
574+
if err != nil {
575+
return fmt.Errorf("failed to read the header of file %s: %v", imgPath, err)
576+
}
577+
if string(header) == "QFI\xfb" {
578+
return fmt.Errorf("vfkit does not support qcow2 image format")
579+
}
580+
return nil
581+
}
582+
554583
func (dev *VirtioBlk) ToCmdLine() ([]string, error) {
555584
cmdLine, err := dev.DiskStorageConfig.ToCmdLine()
556585
if err != nil {
@@ -618,6 +647,10 @@ func (dev *VirtioVsock) FromOptions(options []option) error {
618647
return nil
619648
}
620649

650+
func (dev *VirtioVsock) Validate() error {
651+
return nil
652+
}
653+
621654
// VirtioFsNew creates a new virtio-fs device for file sharing. It will share
622655
// the directory at sharedDir with the virtual machine. This directory can be
623656
// mounted in the VM using `mount -t virtiofs mountTag /some/dir`
@@ -655,6 +688,10 @@ func (dev *VirtioFs) FromOptions(options []option) error {
655688
return nil
656689
}
657690

691+
func (dev *VirtioFs) Validate() error {
692+
return nil
693+
}
694+
658695
// RosettaShareNew RosettaShare creates a new rosetta share for running x86_64 binaries on M1 machines.
659696
// It will share a directory containing the linux rosetta binaries with the
660697
// virtual machine. This directory can be mounted in the VM using `mount -t
@@ -700,6 +737,10 @@ func (dev *RosettaShare) FromOptions(options []option) error {
700737
return nil
701738
}
702739

740+
func (dev *RosettaShare) Validate() error {
741+
return nil
742+
}
743+
703744
func networkBlockDeviceNewEmpty() *NetworkBlockDevice {
704745
return &NetworkBlockDevice{
705746
NetworkBlockStorageConfig: NetworkBlockStorageConfig{
@@ -778,6 +819,10 @@ func (nbd *NetworkBlockDevice) FromOptions(options []option) error {
778819
return nbd.NetworkBlockStorageConfig.FromOptions(unhandledOpts)
779820
}
780821

822+
func (nbd *NetworkBlockDevice) Validate() error {
823+
return nil
824+
}
825+
781826
type USBMassStorage struct {
782827
DiskStorageConfig
783828
}
@@ -851,6 +896,10 @@ func (config *DiskStorageConfig) FromOptions(options []option) error {
851896
return nil
852897
}
853898

899+
func (config *DiskStorageConfig) Validate() error {
900+
return nil
901+
}
902+
854903
func (config *NetworkBlockStorageConfig) ToCmdLine() ([]string, error) {
855904
if config.URI == "" {
856905
return nil, fmt.Errorf("%s devices need the uri to a remote block device", config.DevName)

0 commit comments

Comments
 (0)