File Coverage

lib/Rex/Virtualization/LibVirt/create.pm
Criterion Covered Total %
statement 145 193 75.1
branch 45 114 39.4
condition 12 45 26.6
subroutine 19 19 100.0
pod 0 1 0.0
total 221 372 59.4


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4              
5             package Rex::Virtualization::LibVirt::create;
6              
7 2     2   26 use v5.12.5;
  2         8  
8 2     2   11 use warnings;
  2         4  
  2         81  
9              
10             our $VERSION = '1.14.2.2'; # TRIAL VERSION
11              
12 2     2   11 use Rex::Logger;
  2         4  
  2         14  
13 2     2   59 use Rex::Commands::Gather;
  2         5  
  2         12  
14 2     2   17 use Rex::Hardware;
  2         5  
  2         15  
15 2     2   46 use Rex::Commands::Fs;
  2         4  
  2         12  
16 2     2   14 use Rex::Commands::Run;
  2         4  
  2         11  
17 2     2   13 use Rex::Helper::Run;
  2         7  
  2         137  
18 2     2   13 use Rex::Commands::File;
  2         5  
  2         19  
19 2     2   13 use Rex::File::Parser::Data;
  2         5  
  2         18  
20 2     2   40 use Rex::Template;
  2         12  
  2         17  
21 2     2   65 use Rex::Helper::Path;
  2         5  
  2         133  
22              
23 2     2   19 use XML::Simple;
  2         9410  
  2         15  
24 2     2   154 use Rex::Virtualization::LibVirt::hypervisor;
  2         4  
  2         26  
25              
26 2     2   62 use Data::Dumper;
  2         4  
  2         3939  
27              
28             my $QEMU_IMG;
29             if ( can_run("qemu-img") ) {
30             $QEMU_IMG = "qemu-img";
31             }
32             elsif ( can_run("qemu-img-xen") ) {
33             $QEMU_IMG = "qemu-img-xen";
34             }
35              
36             # read __DATA__ into an array
37             my @data = ;
38              
39             sub execute {
40 2     2 0 9 my ( $class, $name, %opt ) = @_;
41 2         13 my $virt_settings = Rex::Config->get("virtualization");
42             chomp( my $uri =
43 2 50       13 ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" );
44              
45 2         18 my $opts = \%opt;
46 2         6 $opts->{"name"} = $name;
47              
48 2 50       6 unless ($opts) {
49 0         0 die("You have to define the create options!");
50             }
51              
52             ## detect the hypervisor caps
53 2         12 my $hypervisor =
54             Rex::Virtualization::LibVirt::hypervisor->execute('capabilities');
55 2         7 my $virt_type = "unknown";
56              
57 2         11 _set_defaults( $opts, $hypervisor );
58              
59 2 50       9 if ( exists $hypervisor->{"kvm"} ) {
    0          
60 2         5 $virt_type = "kvm";
61             }
62             elsif ( exists $hypervisor->{"xen"} ) {
63 0         0 $virt_type = "xen-" . $opts->{"type"};
64             }
65             else {
66 0         0 die("Hypervisor not supported.");
67             }
68              
69 2         25 my $fp = Rex::File::Parser::Data->new( data => \@data );
70 2         15 my $create_xml = $fp->read("create-${virt_type}.xml");
71              
72 2         29 my $template = Rex::Template->new;
73 2         10 my $parsed_template = $template->parse( $create_xml, $opts );
74              
75 2         12 Rex::Logger::debug($parsed_template);
76              
77             ## create storage devices
78 2         6 for ( @{ $opts->{'storage'} } ) {
  2         9  
79              
80 2 50 33     21 if ( !exists $_->{"template"} && $_->{"size"} && $_->{"type"} eq "file" ) {
    0 33        
      0        
81 2         6 my $size = $_->{'size'};
82 2 50       9 if ( !is_file( $_->{"file"} ) ) {
83 2         19 Rex::Logger::debug("creating storage disk: \"$_->{file}\"");
84 2         19 i_run "$QEMU_IMG create -f $_->{driver_type} '$_->{file}' $size",
85             fail_ok => 1;
86 2 50       2544 if ( $? != 0 ) {
87 0         0 die("Error creating storage disk: $_->{'file'}");
88             }
89             }
90             else {
91 0         0 Rex::Logger::info("$_->{file} already exists. Using this.");
92             }
93             }
94             elsif ( $_->{'template'} && $_->{'type'} eq "file" ) {
95 0         0 Rex::Logger::info(
96             "building domain: \"$opts->{'name'}\" from template: \"$_->{'template'}\""
97             );
98 0         0 Rex::Logger::info("Please wait ...");
99 0         0 i_run
100             "$QEMU_IMG convert -f raw '$_->{template}' -O '$_->{driver_type}' '$_->{file}'",
101             fail_ok => 1;
102 0 0       0 if ( $? != 0 ) {
103 0         0 die(
104             "Error building domain: \"$opts->{'name'}\" from template: \"$_->{'template'}\"\n
105             Template doesn't exist or the qemu-img binary is missing"
106             );
107             }
108             }
109             else {
110 0         0 Rex::Logger::info("$_->{file} already exists. Using this.");
111             }
112             }
113              
114 2         18 Rex::Logger::info("Creating domain: \"$opts->{'name'}\"");
115              
116 2         122 $parsed_template =~ s/[\n\r]//gms;
117              
118 2         20 my $file_name = get_tmp_file;
119              
120 2         18 file "$file_name", content => $parsed_template;
121              
122 2         1625 i_run "virsh -c $uri define '$file_name'", fail_ok => 1;
123 2 50       22 if ( $? != 0 ) {
124 0         0 die("Error defining vm $opts->{name}");
125             }
126 2         13 unlink($file_name);
127              
128 2         44 return;
129             }
130              
131             sub _set_defaults {
132 2     2   7 my ( $opts, $hyper ) = @_;
133              
134 2 50       10 if ( !exists $opts->{"name"} ) {
135 0         0 die("You have to give a name.");
136             }
137              
138 2 50       9 if ( !exists $opts->{"storage"} ) {
139 0         0 die("You have to add at least one storage disk.");
140             }
141              
142 2 50       8 if ( !exists $opts->{"type"} ) {
143              
144 2 50 33     13 if ( exists $opts->{"os"}
      0        
145             && exists $opts->{"os"}->{"kernel"}
146             && !exists $hyper->{"kvm"} )
147             {
148 0         0 $opts->{"type"} = "pvm";
149             }
150             else {
151 2         7 $opts->{"type"} = "hvm";
152             }
153              
154             }
155              
156 2 50       11 if ( !$opts->{"memory"} ) {
157 2         6 $opts->{"memory"} = 512 * 1024;
158             }
159              
160 2 50       7 if ( !$opts->{"cpus"} ) {
161 2         6 $opts->{"cpus"} = 1;
162             }
163              
164 2 50       8 if ( !exists $opts->{"clock"} ) {
165 2         7 $opts->{"clock"} = "utc";
166             }
167              
168 2 50       10 if ( !exists $opts->{"arch"} ) {
169 2 50       8 if ( exists $hyper->{"x86_64"} ) {
170 2         6 $opts->{"arch"} = "x86_64";
171             }
172             else {
173 0         0 $opts->{"arch"} = "i686";
174             }
175             }
176              
177 2 50       8 if ( !exists $opts->{"boot"} ) {
178 2         6 $opts->{"boot"} = "hd";
179             }
180              
181 2 50       9 if ( !exists $opts->{"emulator"} ) {
182 2         7 $opts->{"emulator"} = $hyper->{"emulator"};
183              
184 2 50 33     14 if ( operating_system_is("Debian") && exists $hyper->{"xen"} ) {
185              
186             # fix for debian, because virsh capabilities don't give the correct
187             # emulator.
188 0         0 $opts->{"emulator"} = "/usr/lib/xen-4.0/bin/qemu-dm";
189             }
190              
191             }
192              
193 2 50 33     12 if ( exists $hyper->{"loader"} && !exists $opts->{"loader"} ) {
194 0         0 $opts->{"loader"} = $hyper->{"loader"};
195             }
196              
197 2 50       10 if ( !exists $opts->{"on_poweroff"} ) {
198 2         6 $opts->{"on_poweroff"} = "destroy";
199             }
200              
201 2 50       8 if ( !exists $opts->{"on_reboot"} ) {
202 2         4 $opts->{"on_reboot"} = "restart";
203             }
204              
205 2 50       8 if ( !exists $opts->{"on_crash"} ) {
206 2         7 $opts->{"on_crash"} = "restart";
207             }
208              
209 2 50 33     10 if ( exists $hyper->{"xen"} && $opts->{"type"} eq "pvm" ) {
210              
211 0 0       0 if ( !exists $opts->{"os"}->{"type"} ) {
212 0         0 $opts->{"os"}->{"type"} = "linux";
213             }
214              
215 0 0       0 if ( !exists $opts->{"os"}->{"kernel"} ) {
216 0         0 my %hw = Rex::Hardware->get(qw/ Kernel /);
217              
218 0 0       0 if ( is_redhat() ) {
219             $opts->{"os"}->{"kernel"} =
220 0         0 "/boot/vmlinuz-" . $hw{"Kernel"}->{"kernelrelease"};
221             }
222             else {
223             $opts->{"os"}->{"kernel"} =
224 0         0 "/boot/vmlinuz-" . $hw{"Kernel"}->{"kernelrelease"};
225             }
226             }
227              
228 0 0       0 if ( !exists $opts->{"os"}->{"initrd"} ) {
229 0         0 my %hw = Rex::Hardware->get(qw/ Kernel /);
230              
231 0 0       0 if ( is_redhat() ) {
232             $opts->{"os"}->{"initrd"} =
233 0         0 "/boot/initrd-" . $hw{"Kernel"}->{"kernelrelease"} . ".img";
234             }
235             else {
236             $opts->{"os"}->{"initrd"} =
237 0         0 "/boot/initrd.img-" . $hw{"Kernel"}->{"kernelrelease"};
238             }
239             }
240              
241 0 0       0 if ( !exists $opts->{"os"}->{"cmdline"} ) {
242 0 0       0 my @root_store = grep { $_->{"is_root"} && $_->{"is_root"} == 1 }
243 0         0 @{ $opts->{"storage"} };
  0         0  
244             $opts->{"os"}->{"cmdline"} =
245 0         0 "root=/dev/" . $root_store[0]->{"dev"} . " ro";
246             }
247              
248             }
249              
250 2         13 _set_storage_defaults( $opts, $hyper );
251              
252 2         19 _set_network_defaults( $opts, $hyper );
253              
254             }
255              
256             sub _set_storage_defaults {
257 2     2   7 my ( $opts, $hyper ) = @_;
258              
259 2         6 my $store_letter = "a";
260 2         4 for my $store ( @{ $opts->{"storage"} } ) {
  2         10  
261              
262 2 50       9 if ( !exists $store->{"type"} ) {
263 2         7 $store->{"type"} = "file";
264             }
265              
266 2 100       18 if ( !exists $store->{"driver_type"} ) {
267 1         8 $store->{"driver_type"} = "raw";
268             }
269              
270 2 50 33     14 if ( !exists $store->{"size"} && $store->{"type"} eq "file" ) {
271              
272 2 50       13 if ( $store->{"file"} =~ m/swap/ ) {
273 0         0 $store->{"size"} = "1G";
274             }
275             else {
276 2         7 $store->{"size"} = "10G";
277             }
278              
279             }
280              
281 2 50 33     25 if ( exists $store->{"file"}
      33        
282             && $store->{"file"} =~ m/\.iso$/
283             && !exists $store->{"device"} )
284             {
285 0         0 $store->{"device"} = "cdrom";
286             }
287              
288 2 50       8 if ( !exists $store->{"device"} ) {
289 2         6 $store->{"device"} = "disk";
290             }
291              
292 2 50 33     11 if ( !exists $store->{"dev"} && $store->{"device"} eq "cdrom" ) {
293 0         0 $store->{"dev"} = "hdc";
294             }
295              
296 2 50       7 if ( !exists $store->{"dev"} ) {
297              
298 0 0       0 if ( exists $hyper->{"kvm"} ) {
299 0         0 $store->{"dev"} = "vd${store_letter}";
300             }
301             else {
302 0         0 $store->{"dev"} = "hd${store_letter}";
303             }
304              
305             }
306              
307 2 50       8 if ( !exists $store->{"bus"} ) {
308              
309 2 50 33     12 if ( exists $hyper->{"kvm"} && $store->{"device"} eq "disk" ) {
310 2         6 $store->{"bus"} = "virtio";
311             }
312             else {
313 0         0 $store->{"bus"} = "ide";
314             }
315              
316             }
317              
318 2 50       8 if ( exists $hyper->{"kvm"} ) {
319              
320 2 50 33     15 if ( $store->{"bus"} eq "virtio" && !exists $store->{"address"} ) {
    0 0        
321 2         21 $store->{"address"} = {
322             type => "pci",
323             domain => "0x0000",
324             bus => "0x00",
325             slot => "0x05",
326             function => "0x0",
327             };
328             }
329             elsif ( $store->{"bus"} eq "ide" && !exists $store->{"address"} ) {
330 0         0 $store->{"address"} = {
331             type => "drive",
332             controller => 0,
333             bus => 1,
334             unit => 0,
335             };
336             }
337              
338             }
339              
340 2 50       18 if ( $store->{"device"} eq "cdrom" ) {
341 0         0 $store->{"readonly"} = 1;
342             }
343              
344 2 50       12 if ( is_redhat() ) {
345              
346 0 0       0 if ( !exists $store->{"aio"} ) {
347 0         0 $store->{"aio"} = 1;
348             }
349              
350             }
351              
352 2         8 $store_letter++;
353              
354             }
355              
356             }
357              
358             sub _set_network_defaults {
359 2     2   6 my ( $opts, $hyper ) = @_;
360              
361 2 50       9 if ( !exists $opts->{"network"} ) {
362 2         13 $opts->{"network"} = [
363             {
364             type => "bridge",
365             bridge => "virbr0",
366             },
367             ];
368             }
369              
370 2         5 my $slot = 10;
371              
372 2         4 for my $netdev ( @{ $opts->{"network"} } ) {
  2         9  
373              
374 2 50       8 if ( !exists $netdev->{"type"} ) {
375              
376 0         0 $netdev->{"type"} = "bridge";
377              
378             }
379              
380 2 50       8 if ( !exists $netdev->{"bridge"} ) {
381              
382 0         0 $netdev->{"bridge"} = "virbr0";
383              
384             }
385              
386 2 50       12 if ( exists $hyper->{"kvm"} ) {
387              
388 2 50       6 if ( !exists $netdev->{"model"} ) {
389              
390 2         7 $netdev->{"model"} = "virtio";
391              
392             }
393              
394 2 50       10 if ( !exists $netdev->{"address"} ) {
395              
396 2         34 $netdev->{"address"} = {
397             type => "pci",
398             domain => "0x0000",
399             bus => "0x00",
400             slot => "0x" . sprintf( '%02i', $slot ),
401             function => "0x0",
402             };
403              
404 2         8 $slot++;
405              
406             }
407              
408             }
409              
410             }
411             }
412              
413             1;
414              
415             __DATA__