/ext/QVD-HKD/lib/QVD/HKD/VMHandler/LXC/Killer.pm

https://github.com/BillTheBest/theqvd · Perl · 131 lines · 110 code · 20 blank · 1 comment · 7 complexity · 58aaa9fb462ab3c460a3b181b5fa5213 MD5 · raw file

  1. package QVD::HKD::VMHanler::LXC::Killer;
  2. BEGIN { *debug = \$QVD::HKD::VMHandler::debug }
  3. our $debug;
  4. use strict;
  5. use warnings;
  6. use 5.010;
  7. use Linux::Proc::Mountinfo;
  8. use QVD::Log;
  9. use parent qw(QVD::HKD::VMHandler);
  10. use QVD::StateMachine::Declarative
  11. 'new' => { transitions => { _on_cmd_start => 'stopping_lxc' } },
  12. 'stopping_lxc' => { enter => '_stop_lxc',
  13. transitions => { _on_stop_lxc_done => 'killing_lxc_processes' } },
  14. 'killing_lxc_processes' => { enter => '_kill_lxc_processes',
  15. transitions => { _on_kill_lxc_processes_done => 'destroying_lxc' } },
  16. 'destroying_lxc' => { enter => '_destroy_lxc',
  17. transitions => { _on_destroy_lxc_done => 'umounting_filesystems' } },
  18. 'umounting_filesystems' => { enter => '_umount_filesystems',
  19. transitions => { _on_umount_filesystems_done => 'stopped' } },
  20. 'stopped' => { enter => '_on_stopped' };
  21. sub new {
  22. my ($class, %opts) = @_;
  23. my $lxc_name = delete $opts{lxc_name};
  24. my $rootfs = delete $opts{os_rootfs};
  25. my $self = $class->SUPER::new(%opts);
  26. $self->{lxc_name} = $lxc_name;
  27. $selt->{os_rootfs} = $rootfs;
  28. $self;
  29. }
  30. sub _stop_lxc {
  31. my $self = shift;
  32. $debug and $self->_debug("stopping container $self->{lxc_name}");
  33. DEBUG "Stopping container '$self->{lxc_name}'";
  34. system $self->_cfg('command.lxc-stop'), -n => $self->{lxc_name};
  35. $debug and $self->_debug("waiting for $self->{lxc_name} to reach state STOPPED");
  36. DEBUG "Waiting for container '$self->{lxc_name}' to reach state STOPPED";
  37. $self->_run_cmd([$self->_cfg('command.lxc-wait'), -n => $self->{lxc_name}, 'STOPPED'],
  38. timeout => $self->_cfg('internal.hkd.vmhandler.timeout.on_state.stopping'),
  39. ignore_errors => 1);
  40. }
  41. sub _kill_lxc_processes {
  42. my $self = shift;
  43. my $cgroup = $self->_cfg('path.cgroup');
  44. my $fn = "$cgroup/$self->{lxc_name}/cgroup.procs";
  45. open my $fh, '<', $fn or do {
  46. $debug and $self->_debug("unable to open $fn: $!");
  47. WARN "Unable to open '$fn': $!";
  48. return $self->_on_kill_lxc_processes_done;
  49. };
  50. if (my @pids = <$fh>) {
  51. if ($self->{killing_count}++ > $self->_cfg('internal.hkd.lxc.killer.retries')) {
  52. $debug and $self->_debug("too many retries, no more killing, peace!");
  53. WARN "Too many retries when killing cointainer processes: @pids";
  54. return $self->_on_kill_lxc_processes_error;
  55. }
  56. chomp @pids;
  57. $debug and $self->_debug("killing zombie processes and then trying again, pids: @pids");
  58. DEBUG "Killing zombie processes: PIDs @pids";
  59. kill KILL => @pids;
  60. $self->_call_after(2 => '_kill_lxc_processes');
  61. }
  62. else {
  63. $debug and $self->_debug("no PIDs found in $fn");
  64. INFO "No PIDs found in '$fn'";
  65. $self->_on_kill_lxc_processes_done;
  66. }
  67. }
  68. sub _destroy_lxc {
  69. my $self = shift;
  70. my $lxc_name = $self->{lxc_name} = "qvd-$self->{vm_id}";
  71. $self->_run_cmd([$self->_cfg('command.lxc-destroy'), -n => $lxc_name],
  72. timeout => $self->_cfg('internal.hkd.lxc.killer.destroy_lxc.timeout'),
  73. ignore_errors => 1);
  74. }
  75. sub _umount_filesystems {
  76. my $self = shift;
  77. my $rootfs = $self->{os_rootfs};
  78. unless (defined $rootfs) {
  79. # FIXME
  80. $debug and $self->_debug("FIXME: rootfs path has not been calculated yet");
  81. return $self->_on_umount_filesystems_done;
  82. }
  83. my $mi = Linux::Proc::Mountinfo->read;
  84. $self->{umounted} = {};
  85. if (my $at = $mi->at($rootfs)) {
  86. my @mnts = map $_->mount_point, @{$at->flatten};
  87. my @remaining = grep !$self->{umounted}, @mnts;
  88. if (@remaining) {
  89. my $next = $remaining[-1];
  90. $self->{umounted}{$next} = 1;
  91. return $self->_umount_filesystem($next);
  92. }
  93. else {
  94. $debug and $self->_debug("Some filesystems could not be umounted: @mnts");
  95. WARN "Some filesystems could not be umounted: @mnts";
  96. }
  97. }
  98. else {
  99. $debug and $self->_debug("No filesystem mounted at $rootfs found");
  100. INFO "Found no filesystem mounted at '$rootfs'";
  101. }
  102. $self->_on_umount_filesystems_done
  103. }
  104. sub _umount_filesystem {
  105. my ($self, $mnt) = @_;
  106. $self->_run_cmd([$self->_cfg('command.umount'), $mnt],
  107. timeout => $self->_cfg('internal.hkd.lxc.killer.umount.timeout'),
  108. ignore_errors => 1,
  109. on_done => '_umount_filesystems');
  110. }
  111. 1;