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; |