[pve-devel] [PATCH] Add CT suspend/resume to PVE API

Daniel Hunsaker danhunsaker at gmail.com
Mon Mar 3 22:16:55 CET 2014


As discussed in a previous thread, following is a patch to support container
suspend (via vzctl chkpnt) and resume (via vzctl restore).

- Added /nodes/{node}/openvz/{vmid}/status/suspend to API
- Added /nodes/{node}/openvz/{vmid}/status/resume to API
- Adapted vm_suspend/vm_resume from PVE/QemuServer.pm into PVE/OpenVZ.pm
  - Removed locking since vzctl already does this for us, and the locks
    conflict with each other (container already locked)
  - Changed monitor commands to run_command(vzctl) calls
  - Refuse to suspend if CT is offline
  - Refuse to resume if CT is online
  - vzctl does these checks as well, but it doesn't really hurt to have them

This was great, but there were artifacts in the web UI - specifically, the
task descriptions were unformatted.  So, I moved over to the web UI code...

- Added descriptions for vzsuspend and vzresume tasks in web UI

And while I was there anyway...

- Added suspend/resume options to CmdMenu for both OpenVZ and QEMU guests
  - Confirm suspend before proceeding
  - No confirm on resume, since it's a startup action
- Fixed OpenVZ CmdMenu shutdown and stop confirmation prompts to refer to CTs

I considered adding these options to the toolbar, but there are enough options
there already that it can get crowded quick in smaller browser windows (such
as the ones I tend to use, for screen real estate purposes), so I opted
against that.

Signed-off-by: Daniel Hunsaker <danhunsaker at gmail.com>
---
 PVE/API2/OpenVZ.pm            | 97 +++++++++++++++++++++++++++++++++++++++++++
 PVE/OpenVZ.pm                 | 26 +++++++++++-
 www/manager/Utils.js          |  2 +
 www/manager/openvz/CmdMenu.js | 25 ++++++++++-
 www/manager/qemu/CmdMenu.js   | 21 ++++++++++
 5 files changed, 168 insertions(+), 3 deletions(-)

diff --git a/PVE/API2/OpenVZ.pm b/PVE/API2/OpenVZ.pm
index d9993fd..31f1b73 100644
--- a/PVE/API2/OpenVZ.pm
+++ b/PVE/API2/OpenVZ.pm
@@ -1391,6 +1391,103 @@ __PACKAGE__->register_method({
 	}});
 
 __PACKAGE__->register_method({
+	name => 'vm_suspend',
+	path => '{vmid}/status/suspend',
+	method => 'POST',
+	protected => 1,
+	proxyto => 'node',
+	description => "Suspend the container.",
+	permissions => {
+		check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
+	},
+	parameters => {
+		additionalProperties => 0,
+		properties => {
+			node => get_standard_option('pve-node'),
+			vmid => get_standard_option('pve-vmid'),
+		},
+	},
+	returns => {
+		type => 'string',
+	},
+	code => sub {
+		my ($param) = @_;
+
+		my $rpcenv = PVE::RPCEnvironment::get();
+
+		my $authuser = $rpcenv->get_user();
+
+		my $node = extract_param($param, 'node');
+
+		my $vmid = extract_param($param, 'vmid');
+
+		die "CT $vmid not running\n" if !PVE::OpenVZ::check_running($vmid);
+
+		my $realcmd = sub {
+			my $upid = shift;
+
+			syslog('info', "suspend CT $vmid: $upid\n");
+
+			PVE::OpenVZ::vm_suspend($vmid);
+
+			return;
+		};
+
+		my $upid = $rpcenv->fork_worker('vzsuspend', $vmid, $authuser, $realcmd);
+
+		return $upid;
+	}});
+
+__PACKAGE__->register_method({
+	name => 'vm_resume',
+	path => '{vmid}/status/resume',
+	method => 'POST',
+	protected => 1,
+	proxyto => 'node',
+	description => "Resume the container.",
+	permissions => {
+		check => ['perm', '/vms/{vmid}', [ 'VM.PowerMgmt' ]],
+	},
+	parameters => {
+		additionalProperties => 0,
+		properties => {
+			node => get_standard_option('pve-node'),
+			vmid => get_standard_option('pve-vmid'),
+		},
+	},
+	returns => {
+		type => 'string',
+	},
+	code => sub {
+		my ($param) = @_;
+
+		my $rpcenv = PVE::RPCEnvironment::get();
+
+		my $authuser = $rpcenv->get_user();
+
+		my $node = extract_param($param, 'node');
+
+		my $vmid = extract_param($param, 'vmid');
+
+		die "CT $vmid already running\n" if PVE::OpenVZ::check_running($vmid);
+
+		my $realcmd = sub {
+			my $upid = shift;
+
+			syslog('info', "resume CT $vmid: $upid\n");
+
+			PVE::OpenVZ::vm_resume($vmid);
+
+			return;
+		};
+
+		my $upid = $rpcenv->fork_worker('vzresume', $vmid, $authuser, $realcmd);
+
+		return $upid;
+	}});
+
+
+__PACKAGE__->register_method({
 	name => 'migrate_vm', 
 	path => '{vmid}/migrate',
 	method => 'POST',
diff --git a/PVE/OpenVZ.pm b/PVE/OpenVZ.pm
index 2b92979..eee7ca3 100644
--- a/PVE/OpenVZ.pm
+++ b/PVE/OpenVZ.pm
@@ -6,7 +6,7 @@ use File::stat qw();
 use POSIX qw (LONG_MAX);
 use IO::Dir;
 use IO::File;
-use PVE::Tools qw(extract_param $IPV6RE $IPV4RE);
+use PVE::Tools qw(run_command extract_param $IPV6RE $IPV4RE);
 use PVE::ProcFSTools;
 use PVE::Cluster qw(cfs_register_file cfs_read_file);
 use PVE::SafeSyslog;
@@ -1205,6 +1205,30 @@ sub lock_container {
 	return $res;
 }
 
+sub vm_suspend {
+	my ($vmid) = @_;
+
+	my $cmd = ['vzctl', 'chkpnt', $vmid];
+
+	eval { run_command($cmd); };
+	if (my $err = $@) {
+		syslog("err", "CT $vmid suspend failed - $err");
+		die $err;
+	}
+}
+
+sub vm_resume {
+	my ($vmid) = @_;
+
+	my $cmd = ['vzctl', 'restore', $vmid];
+
+	eval { run_command($cmd); };
+	if (my $err = $@) {
+		syslog("err", "CT $vmid resume failed - $err");
+		die $err;
+	}
+}
+
 sub replacepw {
 	my ($file, $epw) = @_;
 
diff --git a/www/manager/Utils.js b/www/manager/Utils.js
index 88ba93d..2463fee 100644
--- a/www/manager/Utils.js
+++ b/www/manager/Utils.js
@@ -567,6 +567,8 @@ Ext.define('PVE.Utils', { statics: {
 	vzmount: ['CT', gettext('Mount') ],
 	vzumount: ['CT', gettext('Unmount') ],
 	vzshutdown: ['CT', gettext('Shutdown') ],
+	vzsuspend: [ 'CT', gettext('Suspend') ],
+	vzresume: [ 'CT', gettext('Resume') ],
 	hamigrate: [ 'HA', gettext('Migrate') ],
 	hastart: [ 'HA', gettext('Start') ],
 	hastop: [ 'HA', gettext('Stop') ],
diff --git a/www/manager/openvz/CmdMenu.js b/www/manager/openvz/CmdMenu.js
index 14774a4..d4c5f40 100644
--- a/www/manager/openvz/CmdMenu.js
+++ b/www/manager/openvz/CmdMenu.js
@@ -50,10 +50,31 @@ Ext.define('PVE.openvz.CmdMenu', {
 		}
 	    },
 	    {
+		text: gettext('Suspend'),
+		icon: '/pve2/images/forward.png',
+		handler: function() {
+		    var msg = Ext.String.format(gettext("Do you really want to suspend CT {0}?"), vmid);
+		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+			if (btn !== 'yes') {
+			    return;
+			}
+
+			vm_command('suspend');
+		    });
+		}
+	    },
+	    {
+		text: gettext('Resume'),
+		icon: '/pve2/images/forward.png',
+		handler: function() {
+			vm_command('resume');
+		}
+	    },
+	    {
 		text: gettext('Shutdown'),
 		icon: '/pve2/images/stop.png',
 		handler: function() {
-		    var msg = Ext.String.format(gettext("Do you really want to shutdown VM {0}?"), vmid);
+		    var msg = Ext.String.format(gettext("Do you really want to shutdown CT {0}?"), vmid);
 		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
 			if (btn !== 'yes') {
 			    return;
@@ -67,7 +88,7 @@ Ext.define('PVE.openvz.CmdMenu', {
 		text: gettext('Stop'),
 		icon: '/pve2/images/gtk-stop.png',
 		handler: function() {
-		    var msg = Ext.String.format(gettext("Do you really want to stop VM {0}?"), vmid);
+		    var msg = Ext.String.format(gettext("Do you really want to stop CT {0}?"), vmid);
 		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
 			if (btn !== 'yes') {
 			    return;
diff --git a/www/manager/qemu/CmdMenu.js b/www/manager/qemu/CmdMenu.js
index 30fd82c..8c46b86 100644
--- a/www/manager/qemu/CmdMenu.js
+++ b/www/manager/qemu/CmdMenu.js
@@ -50,6 +50,27 @@ Ext.define('PVE.qemu.CmdMenu', {
 		}
 	    },
 	    {
+		text: gettext('Suspend'),
+		icon: '/pve2/images/forward.png',
+		handler: function() {
+		    var msg = Ext.String.format(gettext("Do you really want to suspend VM {0}?"), vmid);
+		    Ext.Msg.confirm(gettext('Confirm'), msg, function(btn) {
+			if (btn !== 'yes') {
+			    return;
+			}
+
+			vm_command('suspend');
+		    });
+		}
+	    },
+	    {
+		text: gettext('Resume'),
+		icon: '/pve2/images/forward.png',
+		handler: function() {
+			vm_command('resume');
+		}
+	    },
+	    {
 		text: gettext('Shutdown'),
 		icon: '/pve2/images/stop.png',
 		handler: function() {
-- 
1.8.3.2




More information about the pve-devel mailing list