[pve-devel] [[PATCH pve-container] 2/4] Add move_volume.

Thomas Lamprecht t.lamprecht at proxmox.com
Wed Apr 20 10:57:41 CEST 2016



On 04/20/2016 08:06 AM, Wolfgang Link wrote:
> Now it is possible to move the volume to an other storage.
> This works only when the CT is off, to keep the volume consistent.
> ---
>  src/PVE/API2/LXC.pm | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/PVE/CLI/pct.pm  |   1 +
>  2 files changed, 117 insertions(+)
>
> diff --git a/src/PVE/API2/LXC.pm b/src/PVE/API2/LXC.pm
> index 537ab69..976e25d 100644
> --- a/src/PVE/API2/LXC.pm
> +++ b/src/PVE/API2/LXC.pm
> @@ -1368,4 +1368,120 @@ __PACKAGE__->register_method({
>  	return PVE::LXC::Config->lock_config($vmid, $code);;
>      }});
>  
> +__PACKAGE__->register_method({
> +    name => 'move_ct_volume',
> +    path => '{vmid}/move_volume',
> +    method => 'POST',
> +    protected => 1,
> +    proxyto => 'node',
> +    description => "Move a rootfs-/mp-volume to a different storage",
> +    permissions => {
> +	description => "You need 'VM.Config.Disk' permissions on /vms/{vmid}, " .
> +	    "and 'Datastore.AllocateSpace' permissions on the storage.",
> +	check =>
> +	[ 'and',
> +	  ['perm', '/vms/{vmid}', [ 'VM.Config.Disk' ]],
> +	  ['perm', '/storage/{storage}', [ 'Datastore.AllocateSpace' ]],
> +	],
> +    },
> +    parameters => {
> +	additionalProperties => 0,
> +	properties => {
> +	    node => get_standard_option('pve-node'),
> +	    vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
> +	    storage => get_standard_option('pve-storage-id', {
> +		description => "Target Storage.",
> +		default => 'local',
> +		completion => \&PVE::Storage::complete_storage_enabled,
> +	    }),
> +	    delete => {
> +		type => 'boolean',
> +		description => "Delete the original volume after successful copy. By default the original disk is kept as unused disk.",
> +		optional => 1,
> +		default => 0,
> +	    },
> +	    volume => {
> +		type => 'string',
> +		description => "Volume which will move.\n Format: [rootfs|mp<x>]",
> +
> +	    },
> +	    digest => {
> +		type => 'string',
> +		description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
> +		maxLength => 40,
> +		optional => 1,
> +	    }
> +	},
> +    },
> +    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');
> +
> +	my $storage = extract_param($param, 'storage');
> +
> +	my $volume = extract_param($param, 'volume');
> +
> +	my $delete = extract_param($param, 'delete');
> +
> +	my $digest = extract_param($param, 'digest');
> +
> +	my $code = sub {
> +
> +	    my $conf = PVE::LXC::Config->load_config($vmid);
> +	    PVE::LXC::Config->check_lock($conf);
> +
> +	    die "can't move volume: $volume if snapshot exists\n"
> +		if %{$conf->{snapshots}};
> +
> +	    PVE::Tools::assert_if_modified($digest, $conf->{digest});
> +
> +	    die "Move Volume can't be done online.\n" if PVE::LXC::check_running($vmid);
> +
> +	    PVE::Cluster::log_msg('info', $authuser, "move_volume CT:$vmid Volume:$volume to Storage:$storage");
> +	    my $realcmd = sub {
> +
> +		my $storage_cfg = PVE::Storage::config();
> +
> +		my $mp;
> +		if ($volume eq 'rootfs') {
> +		    $mp = PVE::LXC::Config->parse_ct_rootfs($conf->{$volume});
> +		} else {
> +		    $mp = PVE::LXC::Config->parse_ct_mountpoint($conf->{$volume});
> +		}
> +
> +		my $old_volid =  $mp->{volume};
> +
> +		eval {
> +		    $mp->{volume} = PVE::LXC::copy_volume($mp, $vmid, $vmid, $storage, $storage_cfg, $conf);
> +
> +		    $conf->{$volume} = PVE::LXC::Config->print_ct_mountpoint($mp, $volume eq 'rootfs');
> +		};
> +		if (my $err = $@) {
> +		    die $err;
> +		}
> +
> +		if ($delete) {
> +		    PVE::Storage::vdisk_free($storage_cfg, $old_volid);
> +		} else {
> +		    my $unused = PVE::LXC::Config->add_unused_volume($conf, $old_volid);
> +		    $conf->{$unused} = $old_volid;
> +		}
> +		PVE::LXC::Config->write_config($vmid, $conf);
> +	    };
> +
> +	    return $rpcenv->fork_worker('move_volume', $vmid, $authuser, $realcmd);
> +	};
> +
> +	return PVE::LXC::Config->lock_config($vmid, $code);
I would use LXC::Config->set_lock(vmid, lock name) at the beginning and
remove_lock at the end of the worker code and omit the lock_config part
completely.

Lock config is only here for making changes to the config, which have a
short duration, you're coping volumes here which are long running
operations, set_lock is better suited for that.
> +  }});
>  1;
> diff --git a/src/PVE/CLI/pct.pm b/src/PVE/CLI/pct.pm
> index 1c04329..c18770c 100755
> --- a/src/PVE/CLI/pct.pm
> +++ b/src/PVE/CLI/pct.pm
> @@ -560,6 +560,7 @@ our $cmddef = {
>      
>      clone => [ "PVE::API2::LXC", 'clone_vm', ['vmid', 'newid'], { node => $nodename }, $upid_exit ],
>      migrate => [ "PVE::API2::LXC", 'migrate_vm', ['vmid', 'target'], { node => $nodename }, $upid_exit],
> +    move_volume => [ "PVE::API2::LXC", 'move_ct_volume', ['vmid', 'storage', 'volume'], { node => $nodename }, $upid_exit ],
>      
>      console => [ __PACKAGE__, 'console', ['vmid']],
>      enter => [ __PACKAGE__, 'enter', ['vmid']],




More information about the pve-devel mailing list