X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FQemuServer%2FImportDisk.pm;h=51ad52eab43ebad24a104de116dc5eea88587c7a;hb=HEAD;hp=e8e83b3448d606a8c65c640dbe76771e6f21fcb6;hpb=0f0aa6b71ec00ea93447772fff9876e21c11e099;p=qemu-server.git diff --git a/PVE/QemuServer/ImportDisk.pm b/PVE/QemuServer/ImportDisk.pm index e8e83b34..132932ae 100755 --- a/PVE/QemuServer/ImportDisk.pm +++ b/PVE/QemuServer/ImportDisk.pm @@ -9,14 +9,15 @@ use PVE::Tools qw(run_command extract_param); # imports an external disk image to an existing VM # and creates by default a drive entry unused[n] pointing to the created volume -# $optional->{drive_name} may be used to specify ide0, scsi1, etc ... -# $optional->{format} may be used to specify qcow2, raw, etc ... +# $params->{drive_name} may be used to specify ide0, scsi1, etc ... +# $params->{format} may be used to specify qcow2, raw, etc ... +# $params->{skiplock} may be used to skip checking for a lock in the VM config +# $params->{'skip-config-update'} may be used to import the disk without updating the VM config sub do_import { - my ($src_path, $vmid, $storage_id, $optional) = @_; + my ($src_path, $vmid, $storage_id, $params) = @_; - my $drive_name = extract_param($optional, 'drive_name'); - my $format = extract_param($optional, 'format'); - my $debug = extract_param($optional, 'debug'); + my $drive_name = extract_param($params, 'drive_name'); + my $format = extract_param($params, 'format'); if ($drive_name && !(PVE::QemuServer::is_valid_drivename($drive_name))) { die "invalid drive name: $drive_name\n"; } @@ -26,78 +27,63 @@ sub do_import { # get target format, target image's path, and whether it's possible to sparseinit my $storecfg = PVE::Storage::config(); - my $dst_format = PVE::QemuServer::resolve_dst_disk_format($storecfg, - $storage_id, undef, $format); - warn "format : $dst_format\n" if $debug; - - my $dst_volid = PVE::Storage::vdisk_alloc($storecfg, $storage_id, $vmid, - $dst_format, undef, $src_size / 1024); - my $dst_path = PVE::Storage::path($storecfg, $dst_volid); - - warn "args: $src_path, $vmid, $storage_id, $optional\n", - "\$dst_volid: $dst_volid\n", if $debug; - - # qemu-img convert does the hard job - # we don't attempt to guess filetypes ourselves - my $convert_command = ['qemu-img', 'convert', $src_path, '-p', '-n', '-O', $dst_format]; - if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst_volid)) { - push @$convert_command, "zeroinit:$dst_path"; - } else { - push @$convert_command, $dst_path; - } + my $dst_format = PVE::QemuServer::resolve_dst_disk_format($storecfg, $storage_id, undef, $format); + warn "format '$format' is not supported by the target storage - using '$dst_format' instead\n" + if $format && $format ne $dst_format; + + my $dst_volid = PVE::Storage::vdisk_alloc($storecfg, $storage_id, $vmid, $dst_format, undef, $src_size / 1024); + + my $zeroinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $dst_volid); my $create_drive = sub { my $vm_conf = PVE::QemuConfig->load_config($vmid); - PVE::QemuConfig->check_lock($vm_conf); + if (!$params->{skiplock}) { + PVE::QemuConfig->check_lock($vm_conf); + } if ($drive_name) { - # should never happen as setting $drive_name is not exposed to public interface - die "cowardly refusing to overwrite existing entry: $drive_name" if $vm_conf->{$drive_name}; - - my $modified = {}; # record what $option we modify - $modified->{$drive_name} = 1; - $vm_conf->{pending}->{$drive_name} = $dst_volid; - PVE::QemuConfig->write_config($vmid, $vm_conf); - - my $running = PVE::QemuServer::check_running($vmid); - if ($running) { - my $errors = {}; - PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, $storecfg, $modified, $errors); - if (scalar(keys %$errors)) { - foreach my $k (keys %$errors) { - warn "$k: $errors->{$k}\n" if $debug; - warn "hotplugging imported disk failed\n"; - } - } - } else { - PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, $storecfg); - } + # should never happen as setting $drive_name is not exposed to public interface + die "cowardly refusing to overwrite existing entry: $drive_name\n" if $vm_conf->{$drive_name}; + + my $modified = {}; # record what $option we modify + $modified->{$drive_name} = 1; + $vm_conf->{pending}->{$drive_name} = $dst_volid; + PVE::QemuConfig->write_config($vmid, $vm_conf); + my $running = PVE::QemuServer::check_running($vmid); + if ($running) { + my $errors = {}; + PVE::QemuServer::vmconfig_hotplug_pending($vmid, $vm_conf, $storecfg, $modified, $errors); + warn "hotplugging imported disk '$_' failed: $errors->{$_}\n" for keys %$errors; + } else { + PVE::QemuServer::vmconfig_apply_pending($vmid, $vm_conf, $storecfg); + } } else { - PVE::QemuConfig->add_unused_volume($vm_conf, $dst_volid); + $drive_name = PVE::QemuConfig->add_unused_volume($vm_conf, $dst_volid); PVE::QemuConfig->write_config($vmid, $vm_conf); } - }; eval { # trap interrupts so we have a chance to clean up - local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub { - die "interrupted by signal\n"; - }; + local $SIG{INT} = + local $SIG{TERM} = + local $SIG{QUIT} = + local $SIG{HUP} = + local $SIG{PIPE} = sub { die "interrupted by signal $!\n"; }; + PVE::Storage::activate_volumes($storecfg, [$dst_volid]); - run_command($convert_command); + PVE::QemuServer::qemu_img_convert($src_path, $dst_volid, $src_size, undef, $zeroinit); PVE::Storage::deactivate_volumes($storecfg, [$dst_volid]); - PVE::QemuConfig->lock_config($vmid, $create_drive); + PVE::QemuConfig->lock_config($vmid, $create_drive) if !$params->{'skip-config-update'}; }; - - my $err = $@; - if ($err) { - eval { # do not die before we returned $err - PVE::Storage::vdisk_free($storecfg, $dst_volid); - }; + if (my $err = $@) { + eval { PVE::Storage::vdisk_free($storecfg, $dst_volid) }; + warn "cleanup of $dst_volid failed: $@\n" if $@; die $err; } + + return ($drive_name, $dst_volid); } 1;