File Coverage

consoles/sshVirtsh.pm
Criterion Covered Total %
statement 345 434 79.4
total 345 434 79.4


line stmt code
1   # Copyright 2009-2013 Bernhard M. Wiedemann
2   # Copyright 2012-2021 SUSE LLC
3   # SPDX-License-Identifier: GPL-2.0-or-later
4    
5    
6   use Mojo::Base 'consoles::sshXtermVt', -signatures;
7 2 use autodie ':all';
  2  
  2  
8 2 require IPC::System::Simple;
  2  
  2  
9   use XML::LibXML;
10 2 use File::Temp 'tempfile';
  2  
  2  
11 2 use File::Basename;
  2  
  2  
12 2 use Mojo::JSON qw(decode_json);
  2  
  2  
13 2  
  2  
  2  
14   use backend::svirt;
15 2  
  2  
  2  
16   has [qw(instance name vmm_family vmm_type)];
17    
18   my $self = $class->SUPER::new($testapi_console, $args);
19 8  
  8  
  8  
  8  
  8  
20 8 $self->instance($bmwqemu::vars{VIRSH_INSTANCE} // 1);
21   # default name
22 8 $self->name("openQA-SUT-" . $self->instance);
23   $self->vmm_family($bmwqemu::vars{VIRSH_VMM_FAMILY} // 'kvm');
24 8 $self->vmm_type($bmwqemu::vars{VIRSH_VMM_TYPE} // 'hvm');
25 8  
26 8 return $self;
27   }
28 8  
29   my $args = $self->{args};
30    
31 0 # initialize SSH console(s)
  0  
  0  
32 0 $self->_init_ssh($args);
33    
34   # start Xvnc
35 0 $self->SUPER::activate;
36    
37   $self->_init_xml();
38 0 }
39    
40 0 # initializes the SSH credentials, $domain is used to distinguish between the
41   # regular SSH and the one to the VMware server
42   $self->{ssh_credentials} = {
43   default => {
44   hostname => $args->{hostname} || die('we need a hostname to ssh to'),
45 5 username => $args->{username},
  5  
  5  
  5  
46   password => $args->{password},
47   }
48   };
49   if ($self->vmm_family eq 'vmware') {
50   $self->{ssh_credentials}->{sshVMwareServer} =
51   {
52 5 hostname => $bmwqemu::vars{VMWARE_HOST} || die('Need variable VMWARE_HOST'),
53 5 password => $bmwqemu::vars{VMWARE_PASSWORD} || die('Need variable VMWARE_PASSWORD'),
54   username => 'root',
55   };
56   }
57 3 }
58    
59   $domain //= 'default';
60   die("Unknown ssh credentials domain $domain") unless (exists($self->{ssh_credentials}->{$domain}));
61   return %{$self->{ssh_credentials}->{$domain}};
62   }
63 59  
  59  
  59  
  59  
64 59 # creates an XML document to configure the libvirt domain
65 59 # (see https://libvirt.org/formatdomain.html for the specification of that config file)
66 59 my $instance = $self->instance;
  59  
67   my $doc = $self->{domainxml} = XML::LibXML::Document->new;
68   my $root = $doc->createElement('domain');
69   $root->setAttribute(type => $self->vmm_family);
70   $doc->setDocumentElement($root);
71 7  
  7  
  7  
  7  
72 7 my $elem;
73 7 $elem = $doc->createElement('name');
74 7 $elem->appendTextNode($self->name);
75 7 $root->appendChild($elem);
76 7  
77   my $openqa_hostname = $bmwqemu::vars{OPENQA_HOSTNAME} // 'no-webui-set';
78 7 $elem = $doc->createElement('description');
79 7 $elem->appendTextNode("openQA WebUI: $openqa_hostname ($instance): ");
80 7 $elem->appendTextNode($bmwqemu::vars{NAME} // '0-no-scenario');
81 7 $root->appendChild($elem);
82    
83 7 $elem = $doc->createElement('memory');
84 7 $elem->appendTextNode($bmwqemu::vars{QEMURAM} or die 'Need variable QEMURAM');
85 7 $elem->setAttribute(unit => 'MiB');
86 7 $root->appendChild($elem);
87 7  
88   $elem = $doc->createElement('vcpu');
89 7 $elem->appendTextNode($bmwqemu::vars{QEMUCPUS} or die 'Need variable QEMUCPUS');
90 7 $root->appendChild($elem);
91 7  
92 7 my $os = $doc->createElement('os');
93   $root->appendChild($os);
94 7  
95 7 $elem = $doc->createElement('type');
96 7 $elem->appendTextNode($self->vmm_type);
97   $os->appendChild($elem);
98 7  
99 7 # Following 'features' are required for VM to correctly shutdown
100   my $features = $doc->createElement('features');
101 7 $root->appendChild($features);
102 7 $elem = $doc->createElement('acpi');
103 7 $features->appendChild($elem);
104   $elem = $doc->createElement('apic');
105   $features->appendChild($elem);
106 7 $elem = $doc->createElement('pae');
107 7 $features->appendChild($elem);
108 7  
109 7 if ($self->vmm_family eq 'xen' and $self->vmm_type eq 'linux') {
110 7 $elem = $doc->createElement('kernel');
111 7 $elem->appendTextNode('/usr/lib/grub2/x86_64-xen/grub.xen');
112 7 $os->appendChild($elem);
113 7 }
114    
115 7 # The root of all problems is this: Xen closes VNC and serial console connections
116 0 # on reboot. Unlike KVM. So, to know when we are restarting if we are in the
117 0 # state before, or after restart we have to configure libvirt to destroy
118 0 # (i.e. turn off) the VM. Then we have to explicitly start it define_and_start.
119   # Even if KVM does not need this, from test code POV it's convenient to have it.
120   if ($self->vmm_family eq 'xen' || $self->vmm_family eq 'kvm') {
121   $elem = $doc->createElement('on_reboot');
122   $elem->appendTextNode('destroy');
123   $root->appendChild($elem);
124   }
125    
126 7 if ($bmwqemu::vars{UEFI} and $bmwqemu::vars{ARCH} eq 'x86_64' and !$bmwqemu::vars{BIOS} and $bmwqemu::vars{VIRSH_VMM_FAMILY} ne 'hyperv') {
127 4 foreach my $firmware (@bmwqemu::ovmf_locations) {
128 4 if (!$self->run_cmd("test -e $firmware")) {
129 4 $bmwqemu::vars{BIOS} = $firmware;
130   $elem = $doc->createElement('loader');
131   $elem->appendTextNode($firmware);
132 7 $os->appendChild($elem);
133 2 last;
134 5 }
135 1 }
136 1 if (!$bmwqemu::vars{BIOS}) {
137 1 # We know this won't go well.
138 1 my $virsh_hostname = $bmwqemu::vars{VIRSH_HOSTNAME} // '';
139 1 die "No UEFI firmware can be found on hypervisor '$virsh_hostname'. Please specify BIOS or UEFI_BIOS or install an appropriate package.";
140   }
141   }
142 2  
143   $self->{devices_element} = $doc->createElement('devices');
144 1 $root->appendChild($self->{devices_element});
145 1  
146   return;
147   }
148    
149 6 # allows to add and remove elements in the domain XML
150 6 # - add text node:
151   # change_domain_element(funny => guy => 'hello');
152 6 # - remove node:
153   # change_domain_element(funny => guy => undef);
154   # - set attributes:
155   # change_domain_element(funny => guy => { hello => 'world' });
156   my $doc = $self->{domainxml};
157   my $elem = $doc->getElementsByTagName('domain')->[0];
158    
159   while (@args > 1) {
160   my $parent = $elem;
161   my $tag_name = shift @args;
162 0 $elem = $parent->getElementsByTagName($tag_name)->[0];
  0  
  0  
  0  
163 0 # create it if not existent
164 0 if (!$elem) {
165   $elem = $doc->createElement($tag_name);
166 0 $parent->appendChild($elem);
167 0 }
168 0 }
169 0 my $tag = $args[0];
170   if (!$tag) {
171 0 # for undef delete the node
172 0 $elem->unbindNode();
173 0 }
174   else {
175   if (ref($tag) eq 'HASH') {
176 0 # for hashes set the attributes
177 0 while (my ($key, $value) = each %$tag) {
178   $elem->setAttribute($key => $value);
179 0 }
180   }
181   else {
182 0 $elem->appendTextNode($tag);
183   }
184 0 }
185 0  
186   return;
187   }
188    
189 0 # adds the serial console used for the serial log
190   my $doc = $self->{domainxml};
191   my $devices = $self->{devices_element};
192    
193 0 my $console = $doc->createElement($args->{pty_dev} || backend::svirt::SERIAL_CONSOLE_DEFAULT_DEVICE);
194   $console->setAttribute(type => $args->{pty_dev_type} || 'pty');
195   $devices->appendChild($console);
196    
197 2 my $elem = $doc->createElement('target');
  2  
  2  
  2  
198 2 if ($args->{target_type}) {
199 2 $elem->setAttribute(type => $args->{target_type});
200   }
201 2 $elem->setAttribute(port => $args->{target_port});
202 2 $console->appendChild($elem);
203 2  
204   if ($args->{protocol_type}) {
205 2 my $elem = $doc->createElement('protocol');
206 2 $elem->setAttribute(type => $args->{protocol_type});
207 0 $console->appendChild($elem);
208   }
209 2  
210 2 if ($args->{source}) {
211   my $elem = $doc->createElement('source');
212 2 $elem->setAttribute(mode => 'bind');
213 0 $elem->setAttribute(host => '0.0.0.0');
214 0 $elem->setAttribute(service => $bmwqemu::vars{VMWARE_SERIAL_PORT});
215 0 $console->appendChild($elem);
216   }
217    
218 2 return;
219 0 }
220 0  
221 0 # this is an equivalent of QEMU's '-vnc' option for tests where we watch
222 0 # the system from boot on (e.g. JeOS)
223 0 my $doc = $self->{domainxml};
224   my $devices = $self->{devices_element};
225    
226 2 my $graphics = $doc->createElement('graphics');
227   $graphics->setAttribute(type => 'vnc');
228   $graphics->setAttribute(port => $args->{port});
229   $graphics->setAttribute(autoport => 'no');
230   $graphics->setAttribute(listen => '0.0.0.0');
231 1 $graphics->setAttribute(sharePolicy => 'force-shared');
  1  
  1  
  1  
232 1 if (my $vnc_password = $testapi::password) {
233 1 $graphics->setAttribute(passwd => $vnc_password);
234   }
235 1 $devices->appendChild($graphics);
236 1  
237 1 my $elem = $doc->createElement('listen');
238 1 $elem->setAttribute(type => 'address');
239 1 $elem->setAttribute(address => '0.0.0.0');
240 1 $graphics->appendChild($elem);
241 1  
242 0 return;
243   }
244 1  
245   my $doc = $self->{domainxml};
246 1 my $devices = $self->{devices_element};
247 1  
248 1 my $input = $doc->createElement('input');
249 1 $input->setAttribute(type => $args->{type});
250   $input->setAttribute(bus => $args->{bus});
251 1 $devices->appendChild($input);
252    
253   return;
254 0 }
  0  
  0  
  0  
255 0  
256 0 # network stuff
257   my $doc = $self->{domainxml};
258 0 my $devices = $self->{devices_element};
259 0  
260 0 my $type = delete $args->{type};
261 0 my $interface = $doc->createElement('interface');
262   $interface->setAttribute(type => $type);
263 0 $devices->appendChild($interface);
264    
265   for my $key (keys %$args) {
266   my $elem = $doc->createElement($key);
267 0 my $value = $args->{$key};
  0  
  0  
  0  
268 0 for my $attr (keys %$value) {
269 0 $elem->setAttribute($attr => $value->{$attr});
270   }
271 0 $interface->appendChild($elem);
272 0 }
273 0  
274 0 return;
275   }
276 0  
277 0 my $size = $args->{size} || '20G';
278 0 if ($self->vmm_family eq 'vmware') {
279 0 my $vmware_disk_path = $vmware_openqa_datastore . $file;
280 0 # Power VM off, delete it's disk image, and create it again.
281   # Than wait for some time for the VM to *really* turn off.
282 0 my $cmd =
283   "( set -x; vmid=\$(vim-cmd vmsvc/getallvms | awk \'/$name/ { print \$1 }\');" .
284   'if [ $vmid ]; then ' .
285 0 'vim-cmd vmsvc/power.off $vmid;' .
286   'vim-cmd vmsvc/destroy $vmid;' .
287   'fi;' .
288 22 "vmkfstools -v1 -U $vmware_disk_path;" .
  22  
  22  
  22  
  22  
  22  
  22  
  22  
289 22 "vmkfstools -v1 -c $size --diskformat thin $vmware_disk_path; sleep 10 ) 2>&1";
290 22 my $retval = $self->run_cmd($cmd, domain => 'sshVMwareServer');
291 6 die "Can't create VMware image $vmware_disk_path" if $retval;
292   }
293   else {
294 6 $file = $basedir . $file;
295   my $bucket = 5;
296   # Avoid qemu-img's failure to get a write lock to be the reason for a job to fail
297   while (1) {
298   my ($ret, $stdout, $stderr) = $self->run_cmd("qemu-img create $file $size -f qcow2", wantarray => 1);
299   if ($stderr =~ /lock/i) {
300   $bucket--;
301   die "Too many attempts to format HDD" unless $bucket;
302 6 bmwqemu::diag("Resource is still not free, waiting a bit more. $bucket attempts left");
303 6 sleep 5;
304   next;
305   }
306 16 last unless $ret;
307 16 }
308   }
309 16 return $file;
310 24 }
311 24  
312 9 # If the file exists, make sure someone else is not copying it there right now,
313 9 # otherwise copy image from NFS datastore.
314 8 my $nfs_dir = $backingfile ? 'hdd' : 'iso';
315 8 my $vmware_nfs_datastore = $bmwqemu::vars{VMWARE_NFS_DATASTORE} or die 'Need variable VMWARE_NFS_DATASTORE';
316 8 my $cmd =
317   "if test -e $vmware_openqa_datastore$file_basename; then " .
318 15 "while lsof | grep 'cp.*$file_basename'; do " .
319   "echo File $file_basename is being copied by other process, sleeping for 60 seconds; sleep 60;" .
320   'done;' .
321 21 'else ' .
322   "cp /vmfs/volumes/$vmware_nfs_datastore/$nfs_dir/$file_basename $vmware_openqa_datastore;" .
323   'fi;';
324 2 my $retval = $self->run_cmd($cmd, domain => 'sshVMwareServer');
  2  
  2  
  2  
  2  
  2  
  2  
  2  
  2  
325   die "Can't copy VMware image $file_basename" if $retval;
326   return unless $backingfile;
327 2 # Power VM off, delete it's disk image, and create it again.
328 2 # Than wait for some time for the VM to *really* turn off.
329 2 $cmd =
330   "( set -x; vmid=\$(vim-cmd vmsvc/getallvms | awk \'/$name/ { print \$1 }\');" .
331   'if [ $vmid ]; then ' .
332   'vim-cmd vmsvc/power.off $vmid;' .
333   'fi;' .
334   "vmkfstools -v1 -U $vmware_disk_path_thinfile;" .
335   "vmkfstools -v1 -i $vmware_disk_path --diskformat thin $vmware_disk_path_thinfile; sleep 10 ) 2>&1";
336   $retval = $self->run_cmd($cmd, domain => 'sshVMwareServer');
337 2 die "Can't create thin VMware image" if $retval;
338 2 }
339 2  
340   $self->run_cmd(sprintf("rsync -av '$file' '$basedir/%s'", $file_basename)) && die 'rsync failed';
341   if ($file_basename =~ /(.*)\.xz$/) {
342 1 $self->run_cmd(sprintf("nice ionice unxz -f -k '$basedir/%s'", $file_basename)) unless -e "$basedir$1";
343   $file_basename = $1;
344   }
345   }
346    
347   # Copy image to VM host
348   die 'No file given' unless $args->{file};
349 1 my $file_basename = basename($args->{file});
350 1 my $backingfile = $args->{backingfile};
351   my $vmware_disk_path = $vmware_openqa_datastore . $file_basename;
352   my $vmware_disk_path_thinfile = $vmware_disk_path =~ s/\.vmdk/_${name}_thinfile\.vmdk/r;
353 8 if ($cdrom || $backingfile) {
  8  
  8  
  8  
  8  
  8  
354 8 if ($self->vmm_family eq 'vmware') {
355 8 $self->_copy_image_vmware($name, $backingfile, $file_basename, $vmware_openqa_datastore, $vmware_disk_path, $vmware_disk_path_thinfile);
356 1 }
357 1 else {
358   $self->_copy_image_else($args->{file}, $file_basename, $basedir);
359   }
360   }
361 15  
  15  
  15  
  15  
  15  
  15  
  15  
  15  
  15  
362   # e.g. cdrom
363 15 return ($self->vmm_family eq 'vmware' ? '' : $basedir) . $file_basename unless $backingfile;
364 13  
365 13 if ($self->vmm_family eq 'vmware') {
366 13 $file = basename($vmware_disk_path_thinfile);
367 13 }
368 13 else {
369 10 $file = $basedir . $file;
370 2 # requested expected value in GBs, if there is any passed as an argument
371   my $size = $args->{size} // 0;
372   # expected value in Bytes
373 8 my (undef, $json) = $self->run_cmd("qemu-img info --output=json $args->{file}", wantarray => 1);
374   my $image_vsize = decode_json($json)->{'virtual-size'};
375   $size = (($size * 1024 * 1024 * 1024) <= $image_vsize) ? $image_vsize : $size . 'G';
376   $self->run_cmd(sprintf("qemu-img create '${file}' -f qcow2 -b '$basedir/%s' ${size}", $file_basename))
377   && die 'qemu-img create with backing file failed';
378 13 }
379   return $file;
380 5 }
381 1  
382   my $elem = $doc->createElement('driver');
383   $elem->setAttribute(name => 'qemu');
384 4 if ($cdrom) {
385   $elem->setAttribute(type => 'raw');
386 4 }
387   else {
388 4 $elem->setAttribute(type => 'qcow2');
389 4 $elem->setAttribute(cache => 'unsafe');
390 4 }
391 4 return $elem;
392   }
393    
394 5 return ("sd$dev_id", 'scsi') if $cdrom && $vmm_family eq 'xen';
395   return ("xvd$dev_id", 'xen') if $vmm_family eq 'xen';
396   return ("hd$dev_id", 'ide') if $vmm_family eq 'vmware';
397 25 return ("hd$dev_id", 'ide') if $cdrom && $vmm_family eq 'kvm';
  25  
  25  
  25  
398 25 return ("vd$dev_id", 'virtio') if $vmm_family eq 'kvm';
399 25 return (undef, undef);
400 25 }
401 4  
402   my $elem = $doc->createElement('boot');
403   $elem->setAttribute(order => $bootorder);
404 21 return $elem;
405 21 }
406    
407 25 my $cdrom = $args->{cdrom};
408   my $name = $self->name;
409   my $file = $name . $args->{dev_id} . ($self->vmm_family eq 'vmware' ? '.vmdk' : '.img');
410 34 my $basedir = '/var/lib/libvirt/images/';
  34  
  34  
  34  
  34  
411 34 my $vmware_datastore = $bmwqemu::vars{VMWARE_DATASTORE} // '';
412 33 my $vmware_openqa_datastore = "/vmfs/volumes/$vmware_datastore/openQA/";
413 22 if ($args->{create}) {
414 13 $file = $self->_create_disk($args, $vmware_openqa_datastore, $file, $name, $basedir);
415 10 }
416 0 else {
417   $file = $self->_copy_image_to_vm_host($args, $vmware_openqa_datastore, $file, $name, $basedir, $cdrom);
418   }
419 2  
  2  
  2  
  2  
420 2 my $doc = $self->{domainxml};
421 2 my $devices = $self->{devices_element};
422 2  
423   my $disk = $doc->createElement('disk');
424   $disk->setAttribute(type => 'file');
425 37 $disk->setAttribute(device => $cdrom ? 'cdrom' : 'disk');
  37  
  37  
  37  
426 37 $devices->appendChild($disk);
427 37  
428 37 # there's no <driver> property on VMware
429 37 $disk->appendChild(_driver_elem($doc, $cdrom)) if $self->vmm_family ne 'vmware';
430 37 my ($dev_type, $bus_type) = _handle_disk_type($self->vmm_family, $cdrom, $args->{dev_id});
431 37 my $elem = $doc->createElement('target');
432 37 $elem->setAttribute(dev => $dev_type);
433 22 $elem->setAttribute(bus => $bus_type);
434   $disk->appendChild($elem);
435    
436 15 $elem = $doc->createElement('source');
437   $file =~ s/\.xz$//;
438   $elem->setAttribute(file => $self->vmm_family eq 'vmware' ? "[$vmware_datastore] openQA/$file" : $file);
439 34 $disk->appendChild($elem);
440 34  
441   if (my $bootorder = $args->{bootorder}) { $disk->appendChild(_bootorder_elem($doc, $bootorder)) }
442 34 return;
443 34 }
444 34  
445 34 my $virsh = 'virsh';
446   $virsh .= ' ' . $bmwqemu::vars{VMWARE_REMOTE_VMM} if $bmwqemu::vars{VMWARE_REMOTE_VMM};
447   return $virsh;
448 34 }
449 34  
450 34 $self->run_cmd(virsh() . " suspend " . $self->name) && die "Can't suspend VM ";
451 34 bmwqemu::diag "VM " . $self->name . " suspended";
452 34 }
453 34  
454   $self->run_cmd(virsh() . " resume " . $self->name) && die "Can't resume VM ";
455 34 bmwqemu::diag "VM " . $self->name . " resumed";
456 34 }
457 34  
458 34  
459   my $remote_vmm = "";
460 34 if ($self->vmm_family eq 'vmware') {
  2  
461 34 my ($fh, $libvirtauthfilename) = File::Temp::tempfile(DIR => "/tmp/");
462    
463   # The libvirt esx driver supports connection over HTTP(S) only. When
464 0 # asked to authenticate we provide the password via 'authfile'.
  0  
465 0 $self->run_cmd(
466 0 "cat > $libvirtauthfilename <<__END
467 0 [credentials-vmware]
468   username=" . ($bmwqemu::vars{VMWARE_USERNAME} or die 'Need variable VMWARE_USERNAME') . "
469   password=" . ($bmwqemu::vars{VMWARE_PASSWORD} or die 'Need variable VMWARE_PASSWORD') . "
470 0 [auth-esx-" . ($bmwqemu::vars{VMWARE_HOST} or die 'Need variable VMWARE_HOST') . "]
  0  
  0  
471 0 credentials=vmware
472 0 __END"
473   );
474   my $user = $bmwqemu::vars{VMWARE_USERNAME} or die 'Need variable VMWARE_USERNAME';
475 0 my $host = $bmwqemu::vars{VMWARE_HOST} or die 'Need variable VMWARE_HOST';
  0  
  0  
476 0 $remote_vmm = "-c esx://$user\@$host/?no_verify=1\\&authfile=$libvirtauthfilename ";
477 0 $bmwqemu::vars{VMWARE_REMOTE_VMM} = $remote_vmm;
478   }
479    
480 0 my $instance = $self->instance;
  0  
  0  
  0  
481   my $xmldata = $self->{domainxml}->toString(2);
482 1 my $xmlfilename = "/var/lib/libvirt/images/" . $self->name . ".xml";
  1  
  1  
483 1 my $ret;
484 1 bmwqemu::diag("Creating libvirt configuration file $xmlfilename:\n$xmldata");
485 1 my ($ssh, $chan) = $self->backend->run_ssh("cat > $xmlfilename", $self->get_ssh_credentials(), keep_open => 1);
486   # scp_put is unfortunately unreliable (RT#61771)
487   $chan->write($xmldata) || $ssh->die_with_error();
488   $chan->send_eof();
489   $chan->close();
490    
491   # shut down possibly running previous test (just to be sure) - ignore errors
492   # just making sure we continue after the command finished
493   my $ignore = ' |& grep -v "\(failed to get domain\|Domain not found\)"';
494 1 $self->run_cmd("virsh $remote_vmm destroy " . $self->name . $ignore);
495   $self->run_cmd("virsh $remote_vmm undefine --snapshots-metadata " . $self->name . $ignore);
496    
497   # define the new domain
498 1 $self->run_cmd("virsh $remote_vmm define $xmlfilename") && die "virsh define failed";
499 1 if ($self->vmm_family eq 'vmware') {
500 1 $self->run_cmd('echo bios.bootDelay = \"10000\" >> /vmfs/volumes/datastore1/openQA/' . $self->name . '.vmx', domain => 'sshVMwareServer');
501 1 }
502    
503   $ret = $self->run_cmd("virsh $remote_vmm start " . $self->name . ' 2> >(tee /tmp/os-autoinst-' . $self->name . '-stderr.log >&2)');
504 1 bmwqemu::diag("Dump actually used libvirt configuration file " . ($ret ? "(broken)" : "(working)"));
505 1 $self->run_cmd("virsh $remote_vmm dumpxml " . $self->name);
506 1 die "virsh start failed" if $ret;
507 1  
508 1 $self->backend->start_serial_grab($self->name);
509 1  
510   return;
511 1 }
512 1  
513 1 $args = {name => $args} unless ref $args;
514    
515   my $name = $args->{name};
516   $self->name($name) if $name;
517 1 $self->backend->start_serial_grab($self->name);
518 1  
519 1 # Setting SVIRT_KEEP_VM_RUNNING variable prevents destruction of a perhaps valuable VM
520   # outside of openQA. Set 'stop_vm' argument should the VM be destroyed at the end.
521   $bmwqemu::vars{SVIRT_KEEP_VM_RUNNING} = 1 unless $args->{stop_vm};
522 1 }
523 1  
524 1  
525    
526    
527 1 =head2 run_cmd
528 1  
529 1 $ret = $svirt->run_cmd($cmd [, domain => 'default'] [, wantarray => 0 ]);
530 1  
531   With C<<wantarray => 1 >> you will receive a list containing I<exitcode>,
532 1 I<stdout> and I<stderr>.
533    
534 1 ($ret, $stdout, $stderr) = $svirt->run_cmd($cmd, wantarray => 1);
535    
536    
537 3 Execute the command via SSH on given C<domain> by default it is the host given
  3  
  3  
  3  
538 3 on C<activate()>, normally the libvirt host defined via C<VIRSH_HOSTNAME>,
539   C<VIRSH_USERNAME> and C<VIRSH_PASSWORD>.
540 3 The second domain B<sshVMwareServer> is available if C<VIRSH_VMM_FAMILY> is
541 3 B<vmware> and defined via C<VMWARE_HOST>, C<VMWARE_PASSWORD> and 'root' as
542 3 username.
543   For further arguments see C<baseclass:run_ssh_cmd()>.
544   =cut
545   my %credentials = $self->get_ssh_credentials($args{domain});
546 3 delete $args{domain};
547   return $self->backend->run_ssh_cmd($cmd, %credentials, %args);
548   }
549 1  
  1  
  1  
  1  
550   =head2 get_cmd_output
551 1  
  1  
  1  
  1  
552   $stdout = $svirt->get_cmd_output($cmd , $args = {domain => 'default', wantarray => 0});
553    
554   With C<<wantarray => 1>> the function will return a reference to a list which
555   contains I<stdout> and I<stderr>.
556   This function is B<deprecated>, you should use C<<$svirt->run_cmd()>> instead.
557   =cut
558   my (undef, $stdout, $stderr) = $self->backend->run_ssh_cmd($cmd, $self->get_ssh_credentials($args->{domain}), wantarray => 1);
559   return $args->{wantarray} ? [$stdout, $stderr] : $stdout;
560   }
561    
562   1;