<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>