]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/API2/Qemu.pm
fix #2580: api/delete: drop VM from HA resources if purge is set
[qemu-server.git] / PVE / API2 / Qemu.pm
index 6ddedd2b1d16f438d3e2aa1ff4b95ef35e4ca28f..d8d3f3e6b312b6fa7e4e6a357c167736c9473147 100644 (file)
@@ -20,6 +20,7 @@ use PVE::ReplicationConfig;
 use PVE::GuestHelpers;
 use PVE::QemuConfig;
 use PVE::QemuServer;
+use PVE::QemuServer::Drive;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuMigrate;
 use PVE::RPCEnvironment;
@@ -400,6 +401,26 @@ __PACKAGE__->register_method({
        return $res;
     }});
 
+my $parse_restore_archive = sub {
+    my ($storecfg, $archive) = @_;
+
+    my ($archive_storeid, $archive_volname) = PVE::Storage::parse_volume_id($archive);
+
+    if (defined($archive_storeid)) {
+       my $scfg =  PVE::Storage::storage_config($storecfg, $archive_storeid);
+       if ($scfg->{type} eq 'pbs') {
+           return {
+               type => 'pbs',
+               volid => $archive,
+           };
+       }
+    }
+    my $path = PVE::Storage::abs_filesystem_path($storecfg, $archive);
+    return {
+       type => 'file',
+       path => $path,
+    };
+};
 
 
 __PACKAGE__->register_method({
@@ -422,7 +443,7 @@ __PACKAGE__->register_method({
                node => get_standard_option('pve-node'),
                vmid => get_standard_option('pve-vmid', { completion => \&PVE::Cluster::complete_next_vmid }),
                archive => {
-                   description => "The backup file.",
+                   description => "The backup archive. Either the file system path to a .tar or .vma file (use '-' to pipe data from stdin) or a proxmox storage backup volume identifier.",
                    type => 'string',
                    optional => 1,
                    maxLength => 255,
@@ -540,9 +561,11 @@ __PACKAGE__->register_method({
            if ($archive eq '-') {
                die "pipe requires cli environment\n"
                    if $rpcenv->{type} ne 'cli';
+               $archive = { type => 'pipe' };
            } else {
                PVE::Storage::check_volume_access($rpcenv, $authuser, $storecfg, $vmid, $archive);
-               $archive = PVE::Storage::abs_filesystem_path($storecfg, $archive);
+
+               $archive = $parse_restore_archive->($storecfg, $archive);
            }
        }
 
@@ -559,12 +582,19 @@ __PACKAGE__->register_method({
            die "$emsg vm is running\n" if PVE::QemuServer::check_running($vmid);
 
            my $realcmd = sub {
-               PVE::QemuServer::restore_archive($archive, $vmid, $authuser, {
+               my $restore_options = {
                    storage => $storage,
                    pool => $pool,
                    unique => $unique,
                    bwlimit => $bwlimit,
-               });
+               };
+               if ($archive->{type} eq 'file' || $archive->{type} eq 'pipe') {
+                   PVE::QemuServer::restore_file_archive($archive->{path} // '-', $vmid, $authuser, $restore_options);
+               } elsif ($archive->{type} eq 'pbs') {
+                   PVE::QemuServer::restore_proxmox_backup_archive($archive->{volid}, $vmid, $authuser, $restore_options);
+               } else {
+                   die "unknown backup archive type\n";
+               }
                my $restored_conf = PVE::QemuConfig->load_config($vmid);
                # Convert restored VM to template if backup was VM template
                if (PVE::QemuConfig->is_template($restored_conf)) {
@@ -601,7 +631,7 @@ __PACKAGE__->register_method({
                    $vollist = &$create_disks($rpcenv, $authuser, $conf, $arch, $storecfg, $vmid, $pool, $param, $storage);
 
                    if (!$conf->{bootdisk}) {
-                       my $firstdisk = PVE::QemuServer::resolve_first_disk($conf);
+                       my $firstdisk = PVE::QemuServer::Drive::resolve_first_disk($conf);
                        $conf->{bootdisk} = $firstdisk if $firstdisk;
                    }
 
@@ -823,7 +853,8 @@ __PACKAGE__->register_method({
     path => '{vmid}/config',
     method => 'GET',
     proxyto => 'node',
-    description => "Get current virtual machine configuration. This does not include pending configuration changes (see 'pending' API).",
+    description => "Get the virtual machine configuration with pending configuration " .
+       "changes applied. Set the 'current' parameter to get the current configuration instead.",
     permissions => {
        check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
     },
@@ -849,7 +880,7 @@ __PACKAGE__->register_method({
        },
     },
     returns => {
-       description => "The current VM configuration.",
+       description => "The VM configuration.",
        type => "object",
        properties => PVE::QemuServer::json_config_properties({
            digest => {
@@ -881,7 +912,7 @@ __PACKAGE__->register_method({
     path => '{vmid}/pending',
     method => 'GET',
     proxyto => 'node',
-    description => "Get virtual machine configuration, including pending changes.",
+    description => "Get the virtual machine configuration with both current and pending values.",
     permissions => {
        check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
     },
@@ -1440,10 +1471,12 @@ __PACKAGE__->register_method({
        my $conf = PVE::QemuConfig->load_config($vmid);
        my $storecfg = PVE::Storage::config();
        PVE::QemuConfig->check_protection($conf, "can't remove VM $vmid");
-       die "unable to remove VM $vmid - used in HA resources\n"
-           if PVE::HA::Config::vm_is_ha_managed($vmid);
+
+       my $ha_managed = PVE::HA::Config::service_is_configured("vm:$vmid");
 
        if (!$param->{purge}) {
+           die "unable to remove VM $vmid - used in HA resources and purge parameter not set.\n"
+               if $ha_managed;
            # don't allow destroy if with replication jobs but no purge param
            my $repl_conf = PVE::ReplicationConfig->new();
            $repl_conf->check_for_existing_jobs($vmid);
@@ -1466,8 +1499,14 @@ __PACKAGE__->register_method({
                PVE::AccessControl::remove_vm_access($vmid);
                PVE::Firewall::remove_vmfw_conf($vmid);
                if ($param->{purge}) {
+                   print "purging VM $vmid from related configurations..\n";
                    PVE::ReplicationConfig::remove_vmid_jobs($vmid);
                    PVE::VZDump::Plugin::remove_vmid_from_backup_jobs($vmid);
+
+                   if ($ha_managed) {
+                       PVE::HA::Config::delete_service_from_config("vm:$vmid");
+                       print "NOTE: removed VM $vmid from HA resource configuration.\n";
+                   }
                }
 
                # only now remove the zombie config, else we can have reuse race
@@ -1994,6 +2033,7 @@ __PACKAGE__->register_method({
                description => "Wait maximal timeout seconds.",
                type => 'integer',
                minimum => 0,
+               default => 'max(30, vm memory in GiB)',
                optional => 1,
            },
        },
@@ -2748,12 +2788,12 @@ __PACKAGE__->register_method({
 
         my $localnode = PVE::INotify::nodename();
 
-        if ($target && ($target eq $localnode || $target eq 'localhost')) {
+       if ($target && ($target eq $localnode || $target eq 'localhost')) {
            undef $target;
-       } else {
-           PVE::Cluster::check_node_exists($target);
        }
 
+       PVE::Cluster::check_node_exists($target) if $target;
+
        my $storecfg = PVE::Storage::config();
 
        if ($storage) {
@@ -2990,7 +3030,7 @@ __PACKAGE__->register_method({
            disk => {
                type => 'string',
                description => "The disk you want to move.",
-               enum => [ PVE::QemuServer::valid_drive_names() ],
+               enum => [PVE::QemuServer::Drive::valid_drive_names()],
            },
             storage => get_standard_option('pve-storage-id', {
                description => "Target storage.",
@@ -3067,7 +3107,7 @@ __PACKAGE__->register_method({
                 (!$format || !$oldfmt || $oldfmt eq $format);
 
            # this only checks snapshots because $disk is passed!
-           my $snapshotted = PVE::QemuServer::is_volume_in_use($storecfg, $conf, $disk, $old_volid);
+           my $snapshotted = PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $disk, $old_volid);
            die "you can't move a disk with snapshots and delete the source\n"
                if $snapshotted && $param->{delete};
 
@@ -3488,7 +3528,7 @@ __PACKAGE__->register_method({
            disk => {
                type => 'string',
                description => "The disk you want to resize.",
-               enum => [PVE::QemuServer::valid_drive_names()],
+               enum => [PVE::QemuServer::Drive::valid_drive_names()],
            },
            size => {
                type => 'string',
@@ -3584,7 +3624,8 @@ __PACKAGE__->register_method({
 
            PVE::QemuServer::qemu_block_resize($vmid, "drive-$disk", $storecfg, $volid, $newsize);
 
-           $drive->{size} = $newsize;
+           my $effective_size = eval { PVE::Storage::volume_size_info($storecfg, $volid, 3); };
+           $drive->{size} = $effective_size // $newsize;
            $conf->{$disk} = PVE::QemuServer::print_drive($drive);
 
            PVE::QemuConfig->write_config($vmid, $conf);
@@ -3840,7 +3881,7 @@ __PACKAGE__->register_method({
     proxyto => 'node',
     description => "Get snapshot configuration",
     permissions => {
-       check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback' ], any => 1],
+       check => ['perm', '/vms/{vmid}', [ 'VM.Snapshot', 'VM.Snapshot.Rollback', 'VM.Audit' ], any => 1],
     },
     parameters => {
        additionalProperties => 0,
@@ -3987,7 +4028,7 @@ __PACKAGE__->register_method({
                optional => 1,
                type => 'string',
                description => "If you want to convert only 1 disk to base image.",
-               enum => [PVE::QemuServer::valid_drive_names()],
+               enum => [PVE::QemuServer::Drive::valid_drive_names()],
            },
 
        },