mirror of
git://git.proxmox.com/git/pve-storage.git
synced 2024-12-22 13:34:16 +03:00
add disk rename feature
Functionality has been added for the following storage types: * directory ones, based on the default implementation: * directory * NFS * CIFS * gluster * ZFS * (thin) LVM * Ceph A new feature `rename` has been introduced to mark which storage plugin supports the feature. Version API and AGE have been bumped. Signed-off-by: Aaron Lauterer <a.lauterer@proxmox.com> the intention of this feature is to support the following use-cases: - reassign a volume from one owning guest to another (which usually entails a rename, since the owning vmid is encoded in the volume name) - rename a volume (e.g., to use a more meaningful name instead of the auto-assigned ...-disk-123) only the former is implemented at the caller side in qemu-server/pve-container for now, but since the lower-level feature is basically the same for both, we can take advantage of the storage plugin API bump now to get the building block for this future feature in place already. adapt ApiChangelog change to fix conflicts and added more detail above Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
93fbc01963
commit
95dfa44ca1
@ -8,6 +8,11 @@ Future changes should be documented in here.
|
||||
|
||||
## Version 10:
|
||||
|
||||
* a new `rename_volume` method has been added
|
||||
|
||||
Storage plugins with rename support need to enable
|
||||
the `rename` feature flag; e.g. in the `volume_has_feature` method.
|
||||
|
||||
* Replace `volume_snapshot_list` with `volume_snapshot_info`:
|
||||
|
||||
`volume_snapshot_list` was used exclusively by replication and currently, replication is only
|
||||
|
@ -349,6 +349,7 @@ sub volume_snapshot_needs_fsfreeze {
|
||||
# snapshot - taking a snapshot is possible
|
||||
# sparseinit - volume is sparsely initialized
|
||||
# template - conversion to base image is possible
|
||||
# rename - renaming volumes is possible
|
||||
# $snap - check if the feature is supported for a given snapshot
|
||||
# $running - if the guest owning the volume is running
|
||||
# $opts - hash with further options:
|
||||
@ -1860,6 +1861,26 @@ sub complete_volume {
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub rename_volume {
|
||||
my ($cfg, $source_volid, $target_vmid, $target_volname) = @_;
|
||||
|
||||
die "no source volid provided\n" if !$source_volid;
|
||||
die "no target VMID or target volname provided\n" if !$target_vmid && !$target_volname;
|
||||
|
||||
my ($storeid, $source_volname) = parse_volume_id($source_volid);
|
||||
|
||||
activate_storage($cfg, $storeid);
|
||||
|
||||
my $scfg = storage_config($cfg, $storeid);
|
||||
my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
|
||||
|
||||
$target_vmid = ($plugin->parse_volname($source_volname))[3] if !$target_vmid;
|
||||
|
||||
return $plugin->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
|
||||
return $plugin->rename_volume($scfg, $storeid, $source_volname, $target_vmid, $target_volname);
|
||||
});
|
||||
}
|
||||
|
||||
# Various io-heavy operations require io/bandwidth limits which can be
|
||||
# configured on multiple levels: The global defaults in datacenter.cfg, and
|
||||
# per-storage overrides. When we want to do a restore from storage A to storage
|
||||
|
@ -339,6 +339,15 @@ sub lvcreate {
|
||||
run_command($cmd, errmsg => "lvcreate '$vg/$name' error");
|
||||
}
|
||||
|
||||
sub lvrename {
|
||||
my ($vg, $oldname, $newname) = @_;
|
||||
|
||||
run_command(
|
||||
['/sbin/lvrename', $vg, $oldname, $newname],
|
||||
errmsg => "lvrename '${vg}/${oldname}' to '${newname}' error",
|
||||
);
|
||||
}
|
||||
|
||||
sub alloc_image {
|
||||
my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
|
||||
|
||||
@ -584,6 +593,7 @@ sub volume_has_feature {
|
||||
|
||||
my $features = {
|
||||
copy => { base => 1, current => 1},
|
||||
rename => {current => 1},
|
||||
};
|
||||
|
||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
|
||||
@ -692,4 +702,28 @@ sub volume_import_write {
|
||||
input => '<&'.fileno($input_fh));
|
||||
}
|
||||
|
||||
sub rename_volume {
|
||||
my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
|
||||
|
||||
my (
|
||||
undef,
|
||||
$source_image,
|
||||
$source_vmid,
|
||||
$base_name,
|
||||
$base_vmid,
|
||||
undef,
|
||||
$format
|
||||
) = $class->parse_volname($source_volname);
|
||||
$target_volname = $class->find_free_diskname($storeid, $scfg, $target_vmid, $format)
|
||||
if !$target_volname;
|
||||
|
||||
my $vg = $scfg->{vgname};
|
||||
my $lvs = lvm_list_volumes($vg);
|
||||
die "target volume '${target_volname}' already exists\n"
|
||||
if ($lvs->{$vg}->{$target_volname});
|
||||
|
||||
lvrename($vg, $source_volname, $target_volname);
|
||||
return "${storeid}:${target_volname}";
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -355,6 +355,7 @@ sub volume_has_feature {
|
||||
template => { current => 1},
|
||||
copy => { base => 1, current => 1, snap => 1},
|
||||
sparseinit => { base => 1, current => 1},
|
||||
rename => {current => 1},
|
||||
};
|
||||
|
||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
|
||||
|
@ -1049,6 +1049,7 @@ sub volume_has_feature {
|
||||
snap => {qcow2 => 1} },
|
||||
sparseinit => { base => {qcow2 => 1, raw => 1, vmdk => 1},
|
||||
current => {qcow2 => 1, raw => 1, vmdk => 1} },
|
||||
rename => { current => {qcow2 => 1, raw => 1, vmdk => 1} },
|
||||
};
|
||||
|
||||
# clone_image creates a qcow2 volume
|
||||
@ -1056,6 +1057,8 @@ sub volume_has_feature {
|
||||
defined($opts->{valid_target_formats}) &&
|
||||
!(grep { $_ eq 'qcow2' } @{$opts->{valid_target_formats}});
|
||||
|
||||
return 0 if $feature eq 'rename' && $class->can('api') && $class->api() < 10;
|
||||
|
||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
|
||||
$class->parse_volname($volname);
|
||||
|
||||
@ -1578,4 +1581,39 @@ sub volume_import_formats {
|
||||
return ();
|
||||
}
|
||||
|
||||
sub rename_volume {
|
||||
my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
|
||||
die "not implemented in storage plugin '$class'\n" if $class->can('api') && $class->api() < 10;
|
||||
die "no path found\n" if !$scfg->{path};
|
||||
|
||||
my (
|
||||
undef,
|
||||
$source_image,
|
||||
$source_vmid,
|
||||
$base_name,
|
||||
$base_vmid,
|
||||
undef,
|
||||
$format
|
||||
) = $class->parse_volname($source_volname);
|
||||
|
||||
$target_volname = $class->find_free_diskname($storeid, $scfg, $target_vmid, $format, 1)
|
||||
if !$target_volname;
|
||||
|
||||
my $basedir = $class->get_subdir($scfg, 'images');
|
||||
|
||||
mkpath "${basedir}/${target_vmid}";
|
||||
|
||||
my $old_path = "${basedir}/${source_vmid}/${source_image}";
|
||||
my $new_path = "${basedir}/${target_vmid}/${target_volname}";
|
||||
|
||||
die "target volume '${target_volname}' already exists\n" if -e $new_path;
|
||||
|
||||
my $base = $base_name ? "${base_vmid}/${base_name}/" : '';
|
||||
|
||||
rename($old_path, $new_path) ||
|
||||
die "rename '$old_path' to '$new_path' failed - $!\n";
|
||||
|
||||
return "${storeid}:${base}${target_vmid}/${target_volname}";
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -742,6 +742,7 @@ sub volume_has_feature {
|
||||
template => { current => 1},
|
||||
copy => { base => 1, current => 1, snap => 1},
|
||||
sparseinit => { base => 1, current => 1},
|
||||
rename => {current => 1},
|
||||
};
|
||||
|
||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) = $class->parse_volname($volname);
|
||||
@ -757,4 +758,37 @@ sub volume_has_feature {
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub rename_volume {
|
||||
my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
|
||||
|
||||
my (
|
||||
undef,
|
||||
$source_image,
|
||||
$source_vmid,
|
||||
$base_name,
|
||||
$base_vmid,
|
||||
undef,
|
||||
$format
|
||||
) = $class->parse_volname($source_volname);
|
||||
$target_volname = $class->find_free_diskname($storeid, $scfg, $target_vmid, $format)
|
||||
if !$target_volname;
|
||||
|
||||
eval {
|
||||
my $cmd = $rbd_cmd->($scfg, $storeid, 'info', $target_volname);
|
||||
run_rbd_command($cmd, errmsg => "exist check", quiet => 1);
|
||||
};
|
||||
die "target volume '${target_volname}' already exists\n" if !$@;
|
||||
|
||||
my $cmd = $rbd_cmd->($scfg, $storeid, 'rename', $source_image, $target_volname);
|
||||
|
||||
run_rbd_command(
|
||||
$cmd,
|
||||
errmsg => "could not rename image '${source_image}' to '${target_volname}'",
|
||||
);
|
||||
|
||||
$base_name = $base_name ? "${base_name}/" : '';
|
||||
|
||||
return "${storeid}:${base_name}${target_volname}";
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -696,6 +696,7 @@ sub volume_has_feature {
|
||||
copy => { base => 1, current => 1},
|
||||
sparseinit => { base => 1, current => 1},
|
||||
replicate => { base => 1, current => 1},
|
||||
rename => {current => 1},
|
||||
};
|
||||
|
||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
|
||||
@ -798,4 +799,34 @@ sub volume_import_formats {
|
||||
return $class->volume_export_formats($scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots);
|
||||
}
|
||||
|
||||
sub rename_volume {
|
||||
my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
|
||||
|
||||
my (
|
||||
undef,
|
||||
$source_image,
|
||||
$source_vmid,
|
||||
$base_name,
|
||||
$base_vmid,
|
||||
undef,
|
||||
$format
|
||||
) = $class->parse_volname($source_volname);
|
||||
$target_volname = $class->find_free_diskname($storeid, $scfg, $target_vmid, $format)
|
||||
if !$target_volname;
|
||||
|
||||
my $pool = $scfg->{pool};
|
||||
my $source_zfspath = "${pool}/${source_image}";
|
||||
my $target_zfspath = "${pool}/${target_volname}";
|
||||
|
||||
my $exists = 0 == run_command(['zfs', 'get', '-H', 'name', $target_zfspath],
|
||||
noerr => 1, quiet => 1);
|
||||
die "target volume '${target_volname}' already exists\n" if $exists;
|
||||
|
||||
$class->zfs_request($scfg, 5, 'rename', ${source_zfspath}, ${target_zfspath});
|
||||
|
||||
$base_name = $base_name ? "${base_name}/" : '';
|
||||
|
||||
return "${storeid}:${base_name}${target_volname}";
|
||||
}
|
||||
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user