~maria-captains/mariadb-tools/trunk

1 by knielsen at knielsen-hq
Import the runvm tool.
1
#! /usr/bin/perl
2
2 by knielsen at knielsen-hq
Add licence header.
3
# runvm: Run a list of commands inside a KVM virtual machine.
4
# Copyright (C) 2009  Kristian Nielsen and Monty Program AB.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with this program; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1 by knielsen at knielsen-hq
Import the runvm tool.
19
20
use strict;
21
use warnings;
22
23
use POSIX;
24
use Socket;
25
26
use Getopt::Long;
27
28
my $ssh_exec= 'ssh';
29
my $kvm_exec= 'kvm';
30
my $qimg_exe= 'qemu-img';
31
32
33
my @cpu_fix;
34
35
my $opt_port= 2222;
36
#my $opt_background= undef;
349.1.1 by Kristian Nielsen
Buildbot: Increase runvm default VM memory to 3GB.
37
my $opt_memory= 3072;
1 by knielsen at knielsen-hq
Import the runvm tool.
38
my $opt_smp= 2;
39
# This workaround (-nx) is needed to boot Ubuntu Jaunty i386 guest on
40
# Jaunty i386 host. For now we just include it everywhere by default,
41
# better safe than sorry.
42
my $opt_cpu= 'qemu32,-nx';
43
my $opt_netdev= 'virtio';
44
#my $opt_shutdown= undef;
45
my $opt_initial_sleep= 15;
46
my $opt_startup_timeout= 300;
47
my $opt_shutdown_timeout= 120;
48
my $opt_max_retries= 3;
49
my $opt_kvm_logfile= '/dev/null';
50
my $opt_user= undef;
51
my $opt_extra_kvm= [];
52
my $opt_baseimage= undef;
53
my @user_cmd_opt;
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
54
my $opt_work_image= undef;
40.1.1 by knielsen at knielsen-hq
Add runvm --windows option to use correct shutdown cmd.
55
my $opt_win;
1 by knielsen at knielsen-hq
Import the runvm tool.
56
4.1.3 by knielsen at knielsen-hq
Disable ssh host key checks when ssh'ing into guest (as they are annoying and not useful).
57
# Disable host key checking for ssh.
58
# This is a bit convoluted due to OpenSSH's slight security-paranoia.
59
# Without this, we would get a login failure if using another VM image
60
# (with different host key) on the same port, which is annoying.
61
# An alternative would be to use CheckHostIP=no and HostKeyAlias=<img.qcow2>
62
# to get ssh to check a different key for each image. But that would still
63
# cause an error if re-generating an image (with new ssh host key), and it
64
# doesn't really give any additional security.
219 by Daniel Bartholomew
fix typo in ssh_exec command
65
my @ssh_cmd_prefix= ($ssh_exec, '-t', '-t',
4.1.3 by knielsen at knielsen-hq
Disable ssh host key checks when ssh'ing into guest (as they are annoying and not useful).
66
                     '-o', 'UserKnownHostsFile=/dev/null',
67
                     '-o', 'StrictHostKeyChecking=no',
68
                     '-o', 'LogLevel=ERROR');
69
1 by knielsen at knielsen-hq
Import the runvm tool.
70
my $image;
71
my $pidfile;
72
73
sub usage {
74
  print <<END;
75
Usage: $0 <options> image.qcow2 [command ...]
4.1.2 by knielsen at knielsen-hq
Add documentation of runvm and all options to `runvm --help`.
76
77
Boot the given KVM virtual machine image and wait for it to come up.
78
Run the list of commands one at a time, aborting on receiving an error.
79
When all commands are run (or one of them failed), shutdown the virtual
80
machine and exit.
81
82
Commands are by default run inside the virtual machine using ssh(1). By
83
prefixing a command with an equals sign '=', it will instead be run on the
84
host system (for example to copy files into or out of the virtual machine
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
85
using scp(1)). By prefixing with an exclamation sign '!' it will be run
86
even if a previous command fails (normal commands are not processed after
87
failure of a previous command). The '=' and '!' prefixes may be combined.
4.1.2 by knielsen at knielsen-hq
Add documentation of runvm and all options to `runvm --help`.
88
89
Some care is taken to ensure that the virtual machine is shutdown
90
gracefully and not left running even in case the controlling tty is
91
closed or the parent process killed. If a previous virtual machine is
92
already running on a conflicting port, an attempt is made to shut it
93
down first. For this purpose, a PID file is created in \$HOME/.runvm/
94
95
Available options:
96
97
  -p, --port=N        Forward this port on the host side to the ssh port (port
98
                      22) on the guest side. Must be different for each runvm
99
                      instance running in parallel to avoid conflicts. The
100
                      default is $opt_port.
101
                      To copy files in/out of the guest use a command prefixed
102
                      with '=' calling scp(1) with the -P option using the port
103
                      specified here, like this:
104
                          runvm img.qcow2 "=scp -P 2222 file.txt localhost:"
105
  -u, --user=USER     Name of the account to ssh into in the guest. Defaults to
106
                      the name of the user invoking runvm on the host.
107
  -m, --memory=N      Amount of memory (in megabytes) to allocate to the guest.
108
                      Defaults to $opt_memory.
109
  --smp=N             Number of CPU cores to allocate to the guest.
110
                      Defaults to $opt_smp.
111
  -c, --cpu=NAME      Type of CPU to emulate for KVM, see qemu(1) for details.
112
                      For example:
113
                          --cpu=qemu64      For 64-bit amd64 emulation
114
                          --cpu=qemu32      For 32-bit x86 emulation
115
                          --cpu=qemu32,-nx  32-bit and disable "no-execute"
116
                      The default is $opt_cpu
117
  --netdev=NAME       Network device to emulate. The 'virtio' device has good
118
                      performance but may not have driver support in all
119
                      operating systems, if so another can be specified.
120
                      The default is $opt_netdev.
121
  --kvm=OPT           Pass additional option OPT to kvm. Specify multiple times
122
                      to pass more than one option. For example
123
                          runvm --kvm=-cdrom --kvm=mycd.iso img.qcow2 ...
124
  --initial-sleep=SECS
125
                      Wait this many seconds before starting to poll the guest
126
                      ssh port for it to be up. Default $opt_initial_sleep.
127
  --startup-timeout=SECS
128
                      Wait at most this many seconds for the guest OS to respond
129
                      to ssh. If this time is exceeded assume it has failed to
130
                      boot correctly. Default $opt_startup_timeout.
131
  --shutdown-timeout=SECS
132
                      Wait at most this many seconds for the guest OS to
133
                      shutdown gracefully after sending a shutdown command. If
134
                      this time is exceeded, assume the guest has failed to
135
                      shutdown gracefully and kill it forcibly. Default $opt_shutdown_timeout.
136
  --kvm-retries=N     If the guest fails to come up, retry the boot this many
137
                      times before giving up. This helps if the virtual machine
138
                      sometimes crashes during boot. Default $opt_max_retries.
139
  -l, --logfile=FILE  File to redirect the output from kvm into. This includes
140
                      any (error) messages from kvm, and also includes anything
141
                      the guest writes to the kvm emulated serial port (it can
142
                      be useful to set the guest to send boot loader and kernel
143
                      messages to the serial console and log them with this
144
                      option). Default is to not log this output anywhere.
145
  -b, --base-image=IMG
146
                      Instead of booting an existing image, create a new
147
                      copy-on-write image based on IMG. This uses the -b option
148
                      of qemu-img(1). IMG is not modified in any way. This way,
149
                      the booted image can be discarded after use, so that each
150
                      use of IMG is using the same reference image with no risk
151
                      of "polution" between different invocations.
152
                      Note that this DELETES any existing image of the same
153
                      name as the one specified on the command line to boot! It
154
                      will be replaced with the image created as a copy of IMG,
155
                      with any modifications done during the runvm session.
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
156
  --work-image=<file> Use <file> for the new copy-on-write-image while running,
157
                      and afterwards move it back to the specified image.qcow2
158
                      location. Used with eg. /dev/shm/ to save I/O. Only
159
                      applicable when --base-image is used.
40.1.1 by knielsen at knielsen-hq
Add runvm --windows option to use correct shutdown cmd.
160
  --windows           The guest is Windows, not Linux.
1 by knielsen at knielsen-hq
Import the runvm tool.
161
END
162
  exit 1;
163
};
164
165
# Quote and escape meta-characters as necessary.
166
# Don't have to do this perfectly, as it's just for printing, but
167
# doing at least some effort is nice for copy-paste ability.
168
sub quote_for_print {
169
  my @print_args= @_;
170
  for (@print_args) {
171
    if (/[^-_\/\+=,.a-zA-Z0-9]/) {
172
      if (/[\']/) {
173
        s/\\/\\\\/g;
174
        s/\"/\\\"/g;
175
        s/\$/\\\$/g;
176
        s/\`/\\\`/g;
177
        $_= '"'. $_ .'"';
178
      } else {
179
        $_= "'". $_ . "'";
180
      }
181
    }
182
  }
183
  return @print_args;
184
}
185
186
sub exec_with_print {
187
  my @args= @_;
188
189
  print STDERR "+ ", join(" ", quote_for_print(@args)), "\n";
190
  exec {$args[0]} @args
191
      or die "exec() failed: $!\n";
192
}
193
194
sub system_with_print {
195
  my @args= @_;
196
197
  print STDERR "+ ", join(" ", quote_for_print(@args)), "\n";
198
  my $res= system {$args[0]} @args;
199
  return $res;
200
}
201
202
sub is_port_used {
203
  socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'))
204
      or die "socket() failed: $!\n";
205
  my $addr= sockaddr_in($opt_port, inet_aton('localhost'));
206
  my $res= connect(SOCK, $addr);
207
  close SOCK;
208
  return $res;
209
}
210
211
sub get_kvm_pid {
212
  open PIDFILE, '<', $pidfile
213
      or return undef;
214
  my $pid= <PIDFILE>;
215
  close PIDFILE;
216
  chomp($pid);
217
  if ($pid =~ /^[0-9]+$/) {
218
    return $pid;
219
  } else {
220
    return undef;
221
  }
222
}
223
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
224
# Copy back any working image to the permanently saved location.
225
# We do this here, so that we will not do it until kvm is shut down, and
226
# also minimise the risk that we leave the work image undeleted, eg. if
227
# the parent is killed.
228
sub copy_back_work_image {
229
  if (defined($opt_work_image) && defined($opt_baseimage)) {
230
    system('/bin/mv', $opt_work_image, $image);
231
  }
232
}
233
1 by knielsen at knielsen-hq
Import the runvm tool.
234
# Start the KVM process.
235
#
236
# We want to avoid leaving stray KVM processes running, even when other things
237
# go wrong (Crashed Buildbot, master-slave connection breaks, etc).
238
#
239
# Further, Even if we do manage to leave a stray KVM, we want the next
240
# invocation to be able to succeed by first shutting down the old one if at
241
# all possible.
242
#
243
sub start_kvm {
244
  my $kvm_pid= get_kvm_pid();
245
  # Don't attempt to use a stale pid file.
246
  if (defined ($kvm_pid) && !kill(0, $kvm_pid)) {
247
    # No process associated with pid file (or if there is we do not
248
    # have privileges to signal it).
249
    $kvm_pid= undef;
250
  }
251
252
  # If the port is unused, seems safer to leave any stray process
253
  # running (it shouldn't really bother us) rather than trying to kill
254
  # it in an unclean fashion.
255
  if (is_port_used()) {
256
    shutdown_kvm($kvm_pid);
257
  }
258
259
  if (is_port_used()) {
260
    die "Cannot start KVM. The port $opt_port is already in use, and we\n".
261
        "were not able to shutdown any existing KVM process properly to\n".
262
        "free up the port.\n";
263
  }
264
265
  # We fork() a management process in-between the main parent process and the
266
  # KVM process. This process will attempt to cleanly shutdown the KVM process
267
  # if the parent dies; this is better to preserve the integrity of the VM
268
  # disk image (no fsck etc. on next boot).
269
  #
270
  # The stdin of the management process is made a pipe so it can easily detect
271
  # parent exit by waiting for stdin to close.
272
  #
273
  # The stdin of KVM is redirected to /dev/null, and the output is
274
  # sent to log file.
275
  open KVM_LOG, '>', $opt_kvm_logfile
276
      or die "Failed to open '$opt_kvm_logfile' for writing: $!\n";
277
278
  # We want the kvm startup command both in the normal stdout log and
279
  # in the kernel log.
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
280
  my $img= (defined($opt_baseimage) && defined($opt_work_image) ?
281
            $opt_work_image : $image);
1 by knielsen at knielsen-hq
Import the runvm tool.
282
  my @kvm_cmdline=
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
283
      ($kvm_exec, '-m', $opt_memory, '-hda', $img,
208 by Daniel Bartholomew
Changed /bin/true to true to support systems where true is at /usr/bin/true
284
       '-boot', 'c', '-smp', $opt_smp, @cpu_fix,
285
       '-nographic', '-net', 'nic,model='. $opt_netdev,
133 by knielsen at knielsen-hq
Only listen on interface localhost for guest ssh incoming connections.
286
       '-net', "user,hostfwd=tcp:127.0.0.1:${opt_port}-:22",
1 by knielsen at knielsen-hq
Import the runvm tool.
287
       '-pidfile', $pidfile,
50 by knielsen at knielsen-hq
runvm: add --localhost kvm options for windows guests to get correct time.
288
       ($opt_win ? ('-localtime') : ()),
1 by knielsen at knielsen-hq
Import the runvm tool.
289
       @$opt_extra_kvm);
290
  print STDERR "+ ", join(" ", quote_for_print(@kvm_cmdline)), "\n";
291
292
  my $res= open(PIPE1, '|-');
293
  if (!defined($res)) {
294
    die "fork() or pipe() failed: $!\n";
295
  } elsif (!$res) {
296
    # Management process.
297
298
    # Make us the process group leader, so that when the parent
299
    # process group is signalled, we get time to do our own cleanup.
300
    setpgrp(0,0);
301
302
    # Close not used file descriptors.
303
    close PIPE1;
304
305
    # Set up a signal handler so that we can exit when the kvm child
306
    # process does.
307
    $SIG{'CHLD'}= sub {
308
      waitpid(-1, 0);
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
309
      my $status= $?;
310
      copy_back_work_image();
311
      exit($status);
1 by knielsen at knielsen-hq
Import the runvm tool.
312
    };
313
    $res= fork();
314
    if (!defined($res)) {
315
      die "fork() failed: $!\n";
316
    } elsif (!$res) {
317
      # KVM child process.
318
      # Kill stdin.
319
      open STDIN, '<', '/dev/null'
320
          or die "Failed to redirect stdin: $!\n";
321
      # Redirect STDOUT/STDERR to log file.
322
      open STDOUT, '>&KVM_LOG'
323
          or die "Failed to redirect stdout: $!\n";
324
      open STDERR, '>&STDOUT'
325
          or die "Failed to redirect stderr: $!\n";
326
      exec_with_print @kvm_cmdline;
327
      # Not reached.
328
      die "Unexpected failure to start kvm.";
329
    } else {
330
      # Management process after forking kvm child.
331
332
      close KVM_LOG;
333
334
      # We just wait for the STDIN pipe from parent to close, indicating that
335
      # the parent process has exited. Once this happens, we shutdown the KVM
336
      # child process and exit.
337
338
      scalar(<STDIN>);
339
      # Parent process exited.
340
      print STDERR "Parent process exited, shutting down KVM...\n";
341
      shutdown_kvm(get_kvm_pid());
342
      waitpid($res, 0);
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
343
      my $status= $?;
344
345
      copy_back_work_image();
346
      exit($status);
1 by knielsen at knielsen-hq
Import the runvm tool.
347
    }
348
  } else {
349
    # Parent process.
350
    close KVM_LOG;
351
  }
352
}
353
354
sub check_if_still_running {
355
  my ($kvm_pid)= @_;
356
  return 1 if is_port_used();
357
  return 1 if $kvm_pid && kill(0, $kvm_pid);
358
  return undef;
359
}
360
361
# Shutdown kvm. Try nicely first, to protect disk images, but kill
362
# hard if necessary.
363
sub shutdown_kvm {
364
  my ($kvm_pid)= @_;
365
366
  my $pid;
367
  my $timeout= undef;
368
  $SIG{ALRM}= sub {
369
    kill 9, $pid
370
        if defined($pid);
371
    $timeout= 1;
372
  };
373
  alarm($opt_shutdown_timeout);
374
375
  while (!$timeout) {
376
    $pid= fork();
377
    if (!defined($pid)) {
378
      die "Fatal error: Cannot fork(): $!\n";
379
    } elsif (!$pid) {
380
      # Child.
40.1.1 by knielsen at knielsen-hq
Add runvm --windows option to use correct shutdown cmd.
381
      if ($opt_win) {
382
        exec_with_print(@ssh_cmd_prefix, '-o', 'ConnectTimeout=4', '-p', $opt_port,
383
                        @user_cmd_opt, 'localhost',
384
                        'shutdown', '-s', '-f', '-t', '1');
848 by Daniel Bartholomew
Added test for FreeBSD VMs so that they are shutdown properly
385
      } elsif ($opt_baseimage =~ /freebsd/) {
386
        exec_with_print(@ssh_cmd_prefix, '-o', 'ConnectTimeout=4', '-p', $opt_port,
387
                        @user_cmd_opt, 'localhost',
388
                        'sudo', '/sbin/shutdown', '-p', 'now');
40.1.1 by knielsen at knielsen-hq
Add runvm --windows option to use correct shutdown cmd.
389
      } else {
390
        exec_with_print(@ssh_cmd_prefix, '-o', 'ConnectTimeout=4', '-p', $opt_port,
391
                        @user_cmd_opt, 'localhost',
392
                        'sudo', '/sbin/shutdown', '-h', 'now');
393
      }
1 by knielsen at knielsen-hq
Import the runvm tool.
394
    } else {
395
      # Parent.
396
      my $res= waitpid $pid, 0;
397
      $pid= undef;
398
      last unless $?;
399
      last if !check_if_still_running($kvm_pid);
400
      sleep 1;
401
    }
402
  }
403
404
  # See if it will come down by itself.
405
  my $still_running;
406
  for(;;) {
407
    $still_running= check_if_still_running($kvm_pid);
408
    last if $timeout || !$still_running;
409
    sleep 1;
410
  }
411
412
  alarm(0);
413
  $SIG{ALRM}= 'DEFAULT';
414
415
  return unless $still_running;
416
417
  # Ok, it refuses to die, kill it the hard way.
418
  print STDERR "Failed to gracefully shutdown KVM within ".
419
      "$opt_shutdown_timeout seconds\nTrying kill -9 ...\n";
420
  kill 9, $kvm_pid;
88 by knielsen at knielsen-hq
More robust force shutdown handling.
421
  for (1 .. 10) {
422
    sleep 1;
423
    last if !kill(0, $kvm_pid) && !is_port_used();
424
  }
1 by knielsen at knielsen-hq
Import the runvm tool.
425
  # If that didn't work, there is not much else we can try.
426
  print STDERR "Unable to kill kvm process (pid $kvm_pid).\n"
427
      if kill(0, $kvm_pid);
428
}
429
430
# Wait for kvm to come up, with timeout for giving up.
431
# Return 0 on success, -1 on timeout, 1 on kvm process gone.
432
sub wait_for_up {
433
  my ($kvm_pid)= @_;
434
435
  # Set an alarm() timeout so we don't hang forever waiting for a broken KVM
436
  # to come up.
437
  my $pid;
438
  my $timeout= undef;
439
  $SIG{ALRM}= sub {
440
    kill 9, $pid
441
        if defined($pid);
442
    $timeout= 1;
443
  };
444
  alarm($opt_startup_timeout);
445
446
  sleep ($opt_initial_sleep)
447
      if $opt_initial_sleep;
448
449
  my $ret= -1;
91 by knielsen at knielsen-hq
Runvm: more robust wait for VM startup.
450
  # Occasionally we see ssh connection succeeding, then immediately
451
  # after failing, then after a brief moment working again,
452
  # permanently. Handle this by checking a few times with short
453
  # interval that the connection is really working.
454
  my $success_attempts= 0;
1 by knielsen at knielsen-hq
Import the runvm tool.
455
  while (!$timeout) {
456
    $pid= fork();
457
    if (!defined($pid)) {
458
      die "Fatal error: Cannot fork(): $!\n";
459
    } elsif (!$pid) {
460
      # Child.
4.1.3 by knielsen at knielsen-hq
Disable ssh host key checks when ssh'ing into guest (as they are annoying and not useful).
461
      exec_with_print(@ssh_cmd_prefix, '-o', 'ConnectTimeout=4', '-p', $opt_port,
208 by Daniel Bartholomew
Changed /bin/true to true to support systems where true is at /usr/bin/true
462
           @user_cmd_opt, 'localhost', 'true');
1 by knielsen at knielsen-hq
Import the runvm tool.
463
    } else {
464
      # Parent.
465
      my $res= waitpid $pid, 0;
466
      $pid= undef;
467
      if ($? == 0) {
91 by knielsen at knielsen-hq
Runvm: more robust wait for VM startup.
468
        if (++$success_attempts >= 3) {
469
          # Ok, KVM is up now!
470
          $ret= 0;
471
          last;
472
        }
473
      } else {
474
        $success_attempts= 0;
1 by knielsen at knielsen-hq
Import the runvm tool.
475
      }
476
      $kvm_pid= get_kvm_pid()
477
          unless defined($kvm_pid);
478
      if (!kill(0, $kvm_pid)) {
479
        # The KVM process seems to have died!
480
        $ret= 1;
481
        last;
482
      }
91 by knielsen at knielsen-hq
Runvm: more robust wait for VM startup.
483
      # Wait a bit before retrying (select() is an easy way to get
484
      # portable sub-second sleep).
485
      select(undef, undef, undef, $success_attempts ? 0.33 : 2);
1 by knielsen at knielsen-hq
Import the runvm tool.
486
    }
487
  }
488
489
  alarm(0);
490
  $SIG{ALRM}= 'DEFAULT';
491
  return $ret;
492
}
493
494
my $result= GetOptions
495
    ( 'port|p=i' => \$opt_port,
496
      'user|u=s' => \$opt_user,
497
#      'background|b' => \$opt_background,
498
      'memory|m=i' => \$opt_memory,
499
      'smp=i' => \$opt_smp,
500
      'cpu|c=s' => \$opt_cpu,
501
      'netdev=s' => \$opt_netdev,
502
      'kvm=s' => $opt_extra_kvm,
503
#      'shutdown|s' => \$opt_shutdown,
504
      'initial-sleep=i' => \$opt_initial_sleep,
505
      'startup-timeout=i' => \$opt_startup_timeout,
506
      'shutdown-timeout=i' => \$opt_shutdown_timeout,
507
      'kvm-retries=i' => \$opt_max_retries,
508
      'logfile|l=s' => \$opt_kvm_logfile,
509
      'base-image|b=s' => \$opt_baseimage,
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
510
      'work-image=s' => \$opt_work_image,
40.1.1 by knielsen at knielsen-hq
Add runvm --windows option to use correct shutdown cmd.
511
      'windows' => \$opt_win,
1 by knielsen at knielsen-hq
Import the runvm tool.
512
    );
513
514
if (defined($opt_user)) {
515
    @user_cmd_opt= ('-l', $opt_user);
516
}
517
518
if (@ARGV < 1) {
519
    print STDERR "No KVM/Qemu image specified, aborting.\n";
520
    usage();
521
}
522
523
$image= shift @ARGV;
524
525
$pidfile= $ENV{HOME} . "/.runvm";
526
system 'mkdir', '-p', $pidfile
527
    and die "Failed to create pidfile directory '$pidfile': $!\n";
528
$pidfile.= "kvm_$opt_port.pid";
529
209 by Daniel Bartholomew
fix @cpu_fix to support Ubuntu 13.04 "raring" amd64 VMs
530
# Fix for Ubuntu 13.04 "raring" amd64 VMs
531
if ($opt_port == 2279) {
532
  @cpu_fix= ('-cpu', "$opt_cpu");
533
} else {
534
  @cpu_fix= ('-cpu', "$opt_cpu,-kvmclock");
535
}
1 by knielsen at knielsen-hq
Import the runvm tool.
536
537
my $retries= 0;
538
for (;;) {
539
  if (defined($opt_baseimage)) {
94 by knielsen at knielsen-hq
Implement --work-image option. This allows to run with the temporary VM image
540
    my $img= (defined($opt_work_image) ? $opt_work_image : $image);
331 by Daniel Bartholomew
change to ensure qemu-img creates images compatible with older kvm
541
    my $res= system_with_print($qimg_exe, 'create', '-o', 'compat=0.10', '-b', $opt_baseimage, '-f', 'qcow2', $img);
1 by knielsen at knielsen-hq
Import the runvm tool.
542
    if ($res) {
543
      print STDERR "Failed to clone base image, aborting\n";
544
      exit 1;
545
    }
546
  }
547
548
  start_kvm();
549
  my $err= wait_for_up();
550
  last unless $err;
551
552
  # Hm, we did not come up :-(. Retry until the limit.
553
  $retries++;
554
555
  print "KVM does not seem to come up properly, shutting down and ",
556
      ($retries < $opt_max_retries ? "retrying" : "aborting"), ".\n";
557
  shutdown_kvm(get_kvm_pid());
558
  exit 1 unless $retries < $opt_max_retries;
559
}
560
561
my $ret= 0;
562
for my $arg (@ARGV) {
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
563
  my $always_run= undef;
564
  my $local_cmd= undef;
565
  # Leading exclamation mark means run even if an earlier command failed.
566
  $always_run= 1
567
      if $arg =~ s/^(=?)\!\s*/$1/;
568
  # A leading equals sign '=' means it is a host command, else guest.
569
  $local_cmd= 1
570
      if $arg =~ s/^=\s*//;
571
  # If a command already failed, only run commands prefixed with `!'.
572
  next if $ret && !$always_run;
573
1 by knielsen at knielsen-hq
Import the runvm tool.
574
  my $res;
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
575
  if ($local_cmd) {
1 by knielsen at knielsen-hq
Import the runvm tool.
576
    print STDERR "= $arg\n";
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
577
    $res= system($arg);
1 by knielsen at knielsen-hq
Import the runvm tool.
578
  } else {
579
    print STDERR "+ $arg\n";
4.1.3 by knielsen at knielsen-hq
Disable ssh host key checks when ssh'ing into guest (as they are annoying and not useful).
580
    $res= system(@ssh_cmd_prefix, '-p', $opt_port, @user_cmd_opt, 'localhost', $arg);
1 by knielsen at knielsen-hq
Import the runvm tool.
581
  }
582
  if ($res < 0) {
583
    print STDERR "Could not spawn command: $!\n";
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
584
    $ret= 1 unless $ret;
1 by knielsen at knielsen-hq
Import the runvm tool.
585
  } elsif ($res > 0) {
586
    my $exit_val= $res >> 8;
587
    my $core= (($res >> 7) & 1) ? " (core dumped)" : "";
588
    my $sig= $res & 127;
589
    if ($core || $sig) {
590
      print STDERR "Terminated$core";
591
      print STDERR ": got signal $sig"
592
          if $sig;
593
      print STDERR "\n";
594
    } else {
595
      print STDERR "Command exit $exit_val\n";
596
    }
90 by knielsen at knielsen-hq
Add ! command prefix to force commands to run even if a previous command fails.
597
    $ret= $exit_val || 1 unless $ret;
1 by knielsen at knielsen-hq
Import the runvm tool.
598
  }
599
}
600
601
shutdown_kvm(get_kvm_pid());
602
603
exit $ret;