<div dir="ltr">Rebased on latest public master.</div><div class="gmail_extra"><br clear="all"><div>- Daniel Hunsaker<br>Owner / Developer<br>Lei's Genesis Experiment: Code For The Future!</div>
<br><br><div class="gmail_quote">On Mon, Mar 3, 2014 at 2:16 PM, Daniel Hunsaker <span dir="ltr"><<a href="mailto:danhunsaker@gmail.com" target="_blank">danhunsaker@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

As discussed in a previous thread, following is a patch to support container<br>
suspend (via vzctl chkpnt) and resume (via vzctl restore).<br>
<br>
- Added /nodes/{node}/openvz/{vmid}/status/suspend to API<br>
- Added /nodes/{node}/openvz/{vmid}/status/resume to API<br>
- Adapted vm_suspend/vm_resume from PVE/QemuServer.pm into PVE/OpenVZ.pm<br>
  - Removed locking since vzctl already does this for us, and the locks<br>
    conflict with each other (container already locked)<br>
  - Changed monitor commands to run_command(vzctl) calls<br>
  - Refuse to suspend if CT is offline<br>
  - Refuse to resume if CT is online<br>
  - vzctl does these checks as well, but it doesn't really hurt to have them<br>
<br>
This was great, but there were artifacts in the web UI - specifically, the<br>
task descriptions were unformatted.  So, I moved over to the web UI code...<br>
<br>
- Added descriptions for vzsuspend and vzresume tasks in web UI<br>
<br>
And while I was there anyway...<br>
<br>
- Added suspend/resume options to CmdMenu for both OpenVZ and QEMU guests<br>
  - Confirm suspend before proceeding<br>
  - No confirm on resume, since it's a startup action<br>
- Fixed OpenVZ CmdMenu shutdown and stop confirmation prompts to refer to CTs<br>
<br>
I considered adding these options to the toolbar, but there are enough options<br>
there already that it can get crowded quick in smaller browser windows (such<br>
as the ones I tend to use, for screen real estate purposes), so I opted<br>
against that.<br>
<br>
Signed-off-by: Daniel Hunsaker <<a href="mailto:danhunsaker@gmail.com">danhunsaker@gmail.com</a>><br>
---<br>
 PVE/API2/OpenVZ.pm            | 97 +++++++++++++++++++++++++++++++++++++++++++<br>
 PVE/OpenVZ.pm                 | 26 +++++++++++-<br>
 www/manager/Utils.js          |  2 +<br>
 www/manager/openvz/CmdMenu.js | 25 ++++++++++-<br>
 www/manager/qemu/CmdMenu.js   | 21 ++++++++++<br>
 5 files changed, 168 insertions(+), 3 deletions(-)<br>
<br>
diff --git a/PVE/API2/OpenVZ.pm b/PVE/API2/OpenVZ.pm<br>
index d9993fd..31f1b73 100644<br>
--- a/PVE/API2/OpenVZ.pm<br>
+++ b/PVE/API2/OpenVZ.pm<br>
@@ -1391,6 +1391,103 @@ __PACKAGE__->register_method({<br>
        }});<br>
<br>
 __PACKAGE__->register_method({<br>
+       name => 'vm_suspend',<br>
+       path => '{vmid}/status/suspend',<br>
+       method => 'POST',<br>
+       protected => 1,<br>
+       proxyto => 'node',<br>
+       description => "Suspend the container.",<br>
+       permissions => {<br>
+               check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],<br>
+       },<br>
+       parameters => {<br>
+               additionalProperties => 0,<br>
+               properties => {<br>
+                       node => get_standard_option('pve-node'),<br>
+                       vmid => get_standard_option('pve-vmid'),<br>
+               },<br>
+       },<br>
+       returns => {<br>
+               type => 'string',<br>
+       },<br>
+       code => sub {<br>
+               my ($param) = @_;<br>
+<br>
+               my $rpcenv = PVE::RPCEnvironment::get();<br>
+<br>
+               my $authuser = $rpcenv->get_user();<br>
+<br>
+               my $node = extract_param($param, 'node');<br>
+<br>
+               my $vmid = extract_param($param, 'vmid');<br>
+<br>
+               die "CT $vmid not running\n" if !PVE::OpenVZ::check_running($vmid);<br>
+<br>
+               my $realcmd = sub {<br>
+                       my $upid = shift;<br>
+<br>
+                       syslog('info', "suspend CT $vmid: $upid\n");<br>
+<br>
+                       PVE::OpenVZ::vm_suspend($vmid);<br>
+<br>
+                       return;<br>
+               };<br>
+<br>
+               my $upid = $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd);<br>
+<br>
+               return $upid;<br>
+       }});<br>
+<br>
+__PACKAGE__->register_method({<br>
+       name => 'vm_resume',<br>
+       path => '{vmid}/status/resume',<br>
+       method => 'POST',<br>
+       protected => 1,<br>
+       proxyto => 'node',<br>
+       description => "Resume the container.",<br>
+       permissions => {<br>
+               check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],<br>
+       },<br>
+       parameters => {<br>
+               additionalProperties => 0,<br>
+               properties => {<br>
+                       node => get_standard_option('pve-node'),<br>
+                       vmid => get_standard_option('pve-vmid'),<br>
+               },<br>
+       },<br>
+       returns => {<br>
+               type => 'string',<br>
+       },<br>
+       code => sub {<br>
+               my ($param) = @_;<br>
+<br>
+               my $rpcenv = PVE::RPCEnvironment::get();<br>
+<br>
+               my $authuser = $rpcenv->get_user();<br>
+<br>
+               my $node = extract_param($param, 'node');<br>
+<br>
+               my $vmid = extract_param($param, 'vmid');<br>
+<br>
+               die "CT $vmid already running\n" if PVE::OpenVZ::check_running($vmid);<br>
+<br>
+               my $realcmd = sub {<br>
+                       my $upid = shift;<br>
+<br>
+                       syslog('info', "resume CT $vmid: $upid\n");<br>
+<br>
+                       PVE::OpenVZ::vm_resume($vmid);<br>
+<br>
+                       return;<br>
+               };<br>
+<br>
+               my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd);<br>
+<br>
+               return $upid;<br>
+       }});<br>
+<br>
+<br>
+__PACKAGE__->register_method({<br>
        name => 'migrate_vm',<br>
        path => '{vmid}/migrate',<br>
        method => 'POST',<br>
diff --git a/PVE/OpenVZ.pm b/PVE/OpenVZ.pm<br>
index 2b92979..eee7ca3 100644<br>
--- a/PVE/OpenVZ.pm<br>
+++ b/PVE/OpenVZ.pm<br>
@@ -6,7 +6,7 @@ use File::stat qw();<br>
 use POSIX qw (LONG_MAX);<br>
 use IO::Dir;<br>
 use IO::File;<br>
-use PVE::Tools qw(extract_param $IPV6RE $IPV4RE);<br>
+use PVE::Tools qw(run_command extract_param $IPV6RE $IPV4RE);<br>
 use PVE::ProcFSTools;<br>
 use PVE::Cluster qw(cfs_register_file cfs_read_file);<br>
 use PVE::SafeSyslog;<br>
@@ -1205,6 +1205,30 @@ sub lock_container {<br>
        return $res;<br>
 }<br>
<br>
+sub vm_suspend {<br>
+       my ($vmid) = @_;<br>
+<br>
+       my $cmd = ['vzctl', 'chkpnt', $vmid];<br>
+<br>
+       eval { run_command($cmd); };<br>
+       if (my $err = $@) {<br>
+               syslog("err", "CT $vmid suspend failed - $err");<br>
+               die $err;<br>
+       }<br>
+}<br>
+<br>
+sub vm_resume {<br>
+       my ($vmid) = @_;<br>
+<br>
+       my $cmd = ['vzctl', 'restore', $vmid];<br>
+<br>
+       eval { run_command($cmd); };<br>
+       if (my $err = $@) {<br>
+               syslog("err", "CT $vmid resume failed - $err");<br>
+               die $err;<br>
+       }<br>
+}<br>
+<br>
 sub replacepw {<br>
        my ($file, $epw) = @_;<br>
<br>
diff --git a/www/manager/Utils.js b/www/manager/Utils.js<br>
index 88ba93d..2463fee 100644<br>
--- a/www/manager/Utils.js<br>
+++ b/www/manager/Utils.js<br>
@@ -567,6 +567,8 @@ Ext.define('PVE.Utils', { statics: {<br>
        vzmount: ['CT', gettext('Mount') ],<br>
        vzumount: ['CT', gettext('Unmount') ],<br>
        vzshutdown: ['CT', gettext('Shutdown') ],<br>
+       vzsuspend: [ 'CT', gettext('Suspend') ],<br>
+       vzresume: [ 'CT', gettext('Resume') ],<br>
        hamigrate: [ 'HA', gettext('Migrate') ],<br>
        hastart: [ 'HA', gettext('Start') ],<br>
        hastop: [ 'HA', gettext('Stop') ],<br>
diff --git a/www/manager/openvz/CmdMenu.js b/www/manager/openvz/CmdMenu.js<br>
index 14774a4..d4c5f40 100644<br>
--- a/www/manager/openvz/CmdMenu.js<br>
+++ b/www/manager/openvz/CmdMenu.js<br>
@@ -50,10 +50,31 @@ Ext.define('PVE.openvz.CmdMenu', {<br>
                }<br>
            },<br>
            {<br>
+               text: gettext('Suspend'),<br>
+               icon: '/pve2/images/forward.png',<br>
+               handler: function() {<br>
+                   var msg = Ext.String.format(gettext("Do you really want to suspend CT {0}?"), vmid);<br>
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {<br>
+                       if (btn !== 'yes') {<br>
+                           return;<br>
+                       }<br>
+<br>
+                       vm_command('suspend');<br>
+                   });<br>
+               }<br>
+           },<br>
+           {<br>
+               text: gettext('Resume'),<br>
+               icon: '/pve2/images/forward.png',<br>
+               handler: function() {<br>
+                       vm_command('resume');<br>
+               }<br>
+           },<br>
+           {<br>
                text: gettext('Shutdown'),<br>
                icon: '/pve2/images/stop.png',<br>
                handler: function() {<br>
-                   var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), vmid);<br>
+                   var msg = Ext.String.format(gettext("Do you really want to shutdown CT {0}?"), vmid);<br>
                    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {<br>
                        if (btn !== 'yes') {<br>
                            return;<br>
@@ -67,7 +88,7 @@ Ext.define('PVE.openvz.CmdMenu', {<br>
                text: gettext('Stop'),<br>
                icon: '/pve2/images/gtk-stop.png',<br>
                handler: function() {<br>
-                   var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), vmid);<br>
+                   var msg = Ext.String.format(gettext("Do you really want to stop CT {0}?"), vmid);<br>
                    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {<br>
                        if (btn !== 'yes') {<br>
                            return;<br>
diff --git a/www/manager/qemu/CmdMenu.js b/www/manager/qemu/CmdMenu.js<br>
index 30fd82c..8c46b86 100644<br>
--- a/www/manager/qemu/CmdMenu.js<br>
+++ b/www/manager/qemu/CmdMenu.js<br>
@@ -50,6 +50,27 @@ Ext.define('PVE.qemu.CmdMenu', {<br>
                }<br>
            },<br>
            {<br>
+               text: gettext('Suspend'),<br>
+               icon: '/pve2/images/forward.png',<br>
+               handler: function() {<br>
+                   var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), vmid);<br>
+                   Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {<br>
+                       if (btn !== 'yes') {<br>
+                           return;<br>
+                       }<br>
+<br>
+                       vm_command('suspend');<br>
+                   });<br>
+               }<br>
+           },<br>
+           {<br>
+               text: gettext('Resume'),<br>
+               icon: '/pve2/images/forward.png',<br>
+               handler: function() {<br>
+                       vm_command('resume');<br>
+               }<br>
+           },<br>
+           {<br>
                text: gettext('Shutdown'),<br>
                icon: '/pve2/images/stop.png',<br>
                handler: function() {<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.2<br>
<br>
</font></span></blockquote></div><br></div>