File Coverage

OpenQA/Qemu/DriveDevice.pm
Criterion Covered Total %
statement 98 102 96.0
total 98 102 96.0


line stmt code
1   # Copyright 2018-2021 SUSE LLC
2   # SPDX-License-Identifier: GPL-2.0-or-later
3    
4   =head2 OpenQA::Qemu::DriveDevice
5    
6   The device which the SUT sees. The data on the device depends on the block dev
7   chain pointed to by 'drive'.
8    
9   =cut
10    
11   use Mojo::Base 'OpenQA::Qemu::MutParams', -signatures;
12 16  
  16  
  16  
13   use OpenQA::Qemu::DrivePath;
14 16  
  16  
  16  
15   use constant DEVICE_POSTFIX => '-device';
16 16 use constant QEMU_IMAGE_FORMAT => 'qcow2';
  16  
  16  
17 16  
  16  
  16  
18   use Exporter 'import';
19 16 our @EXPORT_OK = qw(QEMU_IMAGE_FORMAT);
  16  
  16  
20    
21   =head3 drive
22    
23   The 'active layer' block device, that is, the top block device in a block
24   device chain. It is called 'drive' to reflect QEMU's naming.
25    
26   =cut
27   has 'drive';
28    
29   =head3 model
30    
31   The type of device QEMU should emulate e.g. scsi-hd. See 'qemu-kvm -device
32   help'.
33    
34   =cut
35   has 'model';
36    
37   =head3 paths
38    
39   The connections to this device (multipath). Should be of type
40   OpenQA::Qemu::DrivePath. If left empty, QEMU will decide what to do.
41    
42   =cut
43   has paths => sub { return []; };
44    
45   =head3 bootindex
46    
47   The boot priority of this device. Zero has highest priority. Bootindex is not
48   supported by some firmwares and settings.
49    
50   =cut
51   has 'bootindex';
52    
53   =head3 serial
54    
55   The serial number of the drive
56    
57   =cut
58   has 'serial';
59   has 'id';
60   has last_overlay_id => 0;
61    
62   =head3 num_queues
63    
64   The number of I/O queues of the drive, esp. for NVMe devices
65    
66   =cut
67   has 'num_queues';
68    
69    
70 134  
  134  
  134  
  134  
71   # For multipath
72 79  
  79  
  79  
  79  
73   my @cmdln = ();
74   my $paths = @{$self->paths} < 1 ? [OpenQA::Qemu::DrivePath->new()] : $self->paths;
75 79 my $pathn = scalar @$paths;
  79  
  79  
  79  
  79  
  79  
76    
77 67 # First create params which tell QEMU where the drive content is and what
  67  
  67  
78 67 # format it is using
79 67 push(@cmdln, $self->drive->gen_cmdline());
  67  
80 67  
81   # Then tell QEMU how to emulate the drive device
82   for my $path (@$paths) {
83   my @params = ($self->model,
84 67 'id=' . $self->_gen_node_name($pathn, $path->id),
85   'drive=' . $self->drive->node_name);
86    
87 67 push(@params, 'share-rw=true') if $pathn > 1;
88 75  
89   if (defined $path->controller) {
90   push(@params, 'bus=' . $path->controller->id . '.0');
91   }
92 75 # Configure bootindex only for first path
93   $self->_push_ifdef(\@params, 'bootindex=', $self->bootindex) if (!$path->id || $path->id eq 'path0');
94 75 $self->_push_ifdef(\@params, 'serial=', $self->serial);
95 16 $self->_push_ifdef(\@params, 'num_queues=', $self->num_queues) if (($self->num_queues // -1) != -1);
96   push(@cmdln, ('-device', join(',', @params)));
97   }
98 75  
99 75 return @cmdln;
100 75 }
101 75  
102    
103   # By compressing we are making the images self contained, i.e. they are
104 67 # portable by not requiring backing files referencing the openQA instance.
105   # Compressing takes longer but the transfer takes shorter amount of time.
106   my $compress = $qemu_compress_qcow;
107 44 my @cmd = qw(convert);
  44  
  44  
  44  
108   push @cmd, qw(-c) if $compress;
109 10 push @cmd, ('-O', QEMU_IMAGE_FORMAT, $self->drive->file, "$img_dir/$name");
  10  
  10  
  10  
  10  
  10  
110   return \@cmd;
111   }
112    
113 10  
114 10 my $overlay = $self->drive;
115 10  
116 10 while (defined $overlay) {
117 10 $sub->($overlay);
118   $overlay = $overlay->backing_file;
119   }
120 28 }
  28  
  28  
  28  
121    
122 59 my @overlays = ();
  59  
  59  
  59  
123 59 my @paths = map { $_->_to_map() } @{$self->paths};
124    
125 59 $self->for_each_overlay(sub ($ol) {
126 344 push(@overlays, $ol->_to_map());
127 344 });
128    
129   return {drives => \@overlays,
130   model => $self->model,
131 29 paths => \@paths,
  29  
  29  
132 29 bootindex => $self->bootindex,
133 29 serial => $self->serial,
  8  
  29  
134   id => $self->id,
135 174 num_queues => $self->num_queues};
  174  
  174  
136 174 }
137 29  
138   my $drive = OpenQA::Qemu::BlockDev->new()->_from_map($map->{drives}, $snap_conf);
139 29 my @paths = map {
140   OpenQA::Qemu::DrivePath->new()->_from_map($_, $cont_conf)
141   } @{$map->{paths}};
142    
143   return $self->drive($drive)
144   ->model($map->{model})
145   ->paths(\@paths)
146   ->bootindex($map->{bootindex})
147   ->serial($map->{serial})
148 22 ->id($map->{id})
  22  
  22  
  22  
  22  
  22  
149 22 ->num_queues($map->{num_queues});
150   }
151 8  
152 22  
  22  
153   1;