]> git.proxmox.com Git - pve-guest-common.git/blobdiff - PVE/AbstractConfig.pm
get_backup_volumes: clarifcation and indentation improvements to comment
[pve-guest-common.git] / PVE / AbstractConfig.pm
index 698db58959645f51b36f07b38809acd437c01201..ee004868936651aed02964106b48eaca4b49db76 100644 (file)
@@ -8,6 +8,7 @@ use PVE::INotify;
 use PVE::Cluster;
 use PVE::Storage;
 
+use PVE::GuestHelpers qw(typesafe_ne);
 use PVE::ReplicationConfig;
 use PVE::Replication;
 
@@ -105,57 +106,114 @@ sub print_pending_delete {
 sub add_to_pending_delete {
     my ($class, $conf, $key, $force) = @_;
 
-    delete $conf->{pending}->{$key};
-    my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete});
-    $pending_delete_hash->{$key}->{force} = $force;
-    $conf->{pending}->{delete} = $class->print_pending_delete($pending_delete_hash);
+    $conf->{pending} //= {};
+    my $pending = $conf->{pending};
+    my $pending_delete_hash = $class->parse_pending_delete($pending->{delete});
+
+    $pending_delete_hash->{$key} = { force => $force };
+
+    $pending->{delete} = $class->print_pending_delete($pending_delete_hash);
+
+    return $conf;
 }
 
 sub remove_from_pending_delete {
     my ($class, $conf, $key) = @_;
 
-    my $pending_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete});
+    my $pending = $conf->{pending};
+    my $pending_delete_hash = $class->parse_pending_delete($pending->{delete});
+
+    return $conf if ! exists $pending_delete_hash->{$key};
+
     delete $pending_delete_hash->{$key};
 
     if (%$pending_delete_hash) {
-       $conf->{pending}->{delete} = $class->print_pending_delete($pending_delete_hash);
+       $pending->{delete} = $class->print_pending_delete($pending_delete_hash);
     } else {
-       delete $conf->{pending}->{delete};
+       delete $pending->{delete};
     }
+
+    return $conf;
 }
 
 sub cleanup_pending {
     my ($class, $conf) = @_;
 
+    my $pending = $conf->{pending};
     # remove pending changes when nothing changed
     my $changes;
     foreach my $opt (keys %{$conf->{pending}}) {
        next if $opt eq 'delete'; # just to be sure
-       if (defined($conf->{$opt}) && ($conf->{pending}->{$opt} eq  $conf->{$opt})) {
+       if (defined($conf->{$opt}) && ($pending->{$opt} eq $conf->{$opt})) {
            $changes = 1;
-           delete $conf->{pending}->{$opt};
+           delete $pending->{$opt};
        }
     }
 
-    my $current_delete_hash = $class->parse_pending_delete($conf->{pending}->{delete});
+    my $current_delete_hash = $class->parse_pending_delete($pending->{delete});
     my $pending_delete_hash = {};
-    while (my ($opt, $force) = each %$current_delete_hash) {
+    for my $opt (keys %$current_delete_hash) {
        if (defined($conf->{$opt})) {
-           $pending_delete_hash->{$opt} = $force;
+           $pending_delete_hash->{$opt} = $current_delete_hash->{$opt};
        } else {
            $changes = 1;
        }
     }
 
     if (%$pending_delete_hash) {
-       $conf->{pending}->{delete} = $class->print_pending_delete($pending_delete_hash);
+       $pending->{delete} = $class->print_pending_delete($pending_delete_hash);
     } else {
-       delete $conf->{pending}->{delete};
+       delete $pending->{delete};
     }
 
     return $changes;
 }
 
+sub get_partial_fast_plug_option {
+    my ($class) = @_;
+
+    die "abstract method - implement me ";
+}
+
+sub partial_fast_plug {
+    my ($class, $conf, $opt) = @_;
+
+    my $partial_fast_plug_option = $class->get_partial_fast_plug_option();
+    return 0 if !$partial_fast_plug_option->{$opt};
+
+    my $format = $partial_fast_plug_option->{$opt}->{fmt};
+    my $fast_pluggable = $partial_fast_plug_option->{$opt}->{properties};
+
+    my $configured = {};
+    if (exists($conf->{$opt})) {
+       $configured = PVE::JSONSchema::parse_property_string($format, $conf->{$opt});
+    }
+    my $pending = PVE::JSONSchema::parse_property_string($format, $conf->{pending}->{$opt});
+
+    my $changes = 0;
+
+    # merge configured and pending opts to iterate
+    my @all_keys = keys %{{ %$pending, %$configured }};
+
+    foreach my $subopt (@all_keys) {
+       my $type = $format->{$subopt}->{type};
+       if (typesafe_ne($configured->{$subopt}, $pending->{$subopt}, $type)) {
+           if ($fast_pluggable->{$subopt}) {
+               $configured->{$subopt} = $pending->{$subopt};
+               $changes = 1
+           }
+       }
+    }
+
+    # if there're no keys in $configured (after merge) there shouldn't be anything to change
+    if (keys %$configured) {
+       $conf->{$opt} = PVE::JSONSchema::print_property_string($configured, $format);
+    }
+
+    return $changes;
+}
+
+
 sub load_snapshot_config {
     my ($class, $vmid, $snapname) = @_;
 
@@ -197,7 +255,7 @@ sub load_current_config {
 
 
 # Lock config file using flock, run $code with @param, unlock config file.
-# $timeout is the maximum time to aquire the flock
+# $timeout is the maximum time to acquire the flock
 sub lock_config_full {
     my ($class, $vmid, $timeout, $code, @param) = @_;
 
@@ -211,19 +269,19 @@ sub lock_config_full {
 }
 
 sub create_and_lock_config {
-    my ($class, $vmid, $allow_existing) = @_;
+    my ($class, $vmid, $allow_existing, $lock) = @_;
 
     $class->lock_config_full($vmid, 5, sub {
        PVE::Cluster::check_vmid_unused($vmid, $allow_existing);
 
        my $conf = eval { $class->load_config($vmid) } || {};
        $class->check_lock($conf);
-       $conf->{lock} = 'create';
+       $conf->{lock} = $lock // 'create';
        $class->write_config($vmid, $conf);
     });
 }
 
-# destroys configuration, only applyable for configs owned by the callers node.
+# destroys configuration, only applicable for configs owned by the callers node.
 # dies if removal fails, e.g., when inquorate.
 sub destroy_config {
     my ($class, $vmid) = @_;
@@ -233,7 +291,7 @@ sub destroy_config {
 }
 
 # Lock config file using flock, run $code with @param, unlock config file.
-# $timeout is the maximum time to aquire the flock
+# $timeout is the maximum time to acquire the flock
 # $shared eq 1 creates a non-exclusive ("read") flock
 sub lock_config_mode {
     my ($class, $vmid, $timeout, $shared, $code, @param) = @_;
@@ -338,7 +396,7 @@ sub is_template {
     return 1 if defined $conf->{template} && $conf->{template} == 1;
 }
 
-# Checks whether $feature is availabe for the referenced volumes in $conf.
+# Checks whether $feature is available for the referenced volumes in $conf.
 # Note: depending on the parameters, some volumes may be skipped!
 sub has_feature {
     my ($class, $feature, $conf, $storecfg, $snapname, $running, $backup_only) = @_;
@@ -354,6 +412,22 @@ sub get_replicatable_volumes {
     die "implement me - abstract method\n";
 }
 
+# Returns all the guests volumes which would be included in a vzdump job
+# Return Format (array-ref with hash-refs as elements):
+# [
+#   {
+#     key,        key in the config, e.g. mp0, scsi0,...
+#     included,   boolean
+#     reason,     string
+#     data        volume object as returned from foreach_drive/foreach_mountpoint
+#   },
+# ]
+sub get_backup_volumes {
+    my ($class, $conf) = @_;
+
+    die "implement me - abstract method\n";
+}
+
 # Internal snapshots
 
 # NOTE: Snapshot create/delete involves several non-atomic