]> git.proxmox.com Git - pve-firewall.git/commitdiff
api: lock configs
authorFabian Grünbichler <f.gruenbichler@proxmox.com>
Wed, 29 Apr 2020 08:52:52 +0000 (10:52 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Sat, 2 May 2020 17:05:49 +0000 (19:05 +0200)
wherever we have a r-m-w cycle.

Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
src/PVE/API2/Firewall/Aliases.pm
src/PVE/API2/Firewall/Cluster.pm
src/PVE/API2/Firewall/Groups.pm
src/PVE/API2/Firewall/Host.pm
src/PVE/API2/Firewall/IPSet.pm
src/PVE/API2/Firewall/Rules.pm
src/PVE/API2/Firewall/VM.pm

index 9ea6f70ccb57ee22b80c5e17141350321b5a0ff1..33ac669d6381f76c6f5c8ce46156925bb22ca1d7 100644 (file)
@@ -143,19 +143,23 @@ sub register_create_alias {
        code => sub {
            my ($param) = @_;
 
-           my ($fw_conf, $aliases) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my $name = lc($param->{name});
+               my ($fw_conf, $aliases) = $class->load_config($param);
 
-           raise_param_exc({ name => "alias '$param->{name}' already exists" })
-               if defined($aliases->{$name});
+               my $name = lc($param->{name});
 
-           my $data = { name => $param->{name}, cidr => $param->{cidr} };
-           $data->{comment} = $param->{comment} if $param->{comment};
+               raise_param_exc({ name => "alias '$param->{name}' already exists" })
+                   if defined($aliases->{$name});
 
-           $aliases->{$name} = $data;
+               my $data = { name => $param->{name}, cidr => $param->{cidr} };
+               $data->{comment} = $param->{comment} if $param->{comment};
 
-           $class->save_aliases($param, $fw_conf, $aliases);
+               $aliases->{$name} = $data;
+
+               $class->save_aliases($param, $fw_conf, $aliases);
+           });
 
            return undef;
        }});
@@ -219,35 +223,39 @@ sub register_update_alias {
        code => sub {
            my ($param) = @_;
 
-           my ($fw_conf, $aliases) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my $list = &$aliases_to_list($aliases);
+               my ($fw_conf, $aliases) = $class->load_config($param);
 
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
+               my $list = &$aliases_to_list($aliases);
 
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
 
-           my $name = lc($param->{name});
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           raise_param_exc({ name => "no such alias" }) if !$aliases->{$name};
+               my $name = lc($param->{name});
 
-           my $data = { name => $param->{name}, cidr => $param->{cidr} };
-           $data->{comment} = $param->{comment} if $param->{comment};
+               raise_param_exc({ name => "no such alias" }) if !$aliases->{$name};
 
-           $aliases->{$name} = $data;
+               my $data = { name => $param->{name}, cidr => $param->{cidr} };
+               $data->{comment} = $param->{comment} if $param->{comment};
 
-           my $rename = $param->{rename};
-           $rename = lc($rename) if $rename;
+               $aliases->{$name} = $data;
 
-           if ($rename && ($name ne $rename)) {
-               raise_param_exc({ name => "alias '$param->{rename}' already exists" })
-                   if defined($aliases->{$rename});
-               $aliases->{$name}->{name} = $param->{rename};
-               $aliases->{$rename} = $aliases->{$name};
-               delete $aliases->{$name};
-           }
+               my $rename = $param->{rename};
+               $rename = lc($rename) if $rename;
 
-           $class->save_aliases($param, $fw_conf, $aliases);
+               if ($rename && ($name ne $rename)) {
+                   raise_param_exc({ name => "alias '$param->{rename}' already exists" })
+                       if defined($aliases->{$rename});
+                   $aliases->{$name}->{name} = $param->{rename};
+                   $aliases->{$rename} = $aliases->{$name};
+                   delete $aliases->{$name};
+               }
+
+               $class->save_aliases($param, $fw_conf, $aliases);
+           });
 
            return undef;
        }});
@@ -276,16 +284,20 @@ sub register_delete_alias {
        code => sub {
            my ($param) = @_;
 
-           my ($fw_conf, $aliases) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my $list = &$aliases_to_list($aliases);
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my ($fw_conf, $aliases) = $class->load_config($param);
 
-           my $name = lc($param->{name});
-           delete $aliases->{$name};
+               my $list = &$aliases_to_list($aliases);
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
+
+               my $name = lc($param->{name});
+               delete $aliases->{$name};
 
-           $class->save_aliases($param, $fw_conf, $aliases);
+               $class->save_aliases($param, $fw_conf, $aliases);
+           });
 
            return undef;
        }});
index 0bf8285f6db86b423dac612dacde921ccade8caa..c9c3e67a16c5212b1a4984c2081e4adf7fc07198 100644 (file)
@@ -132,29 +132,31 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
+       PVE::Firewall::lock_clusterfw_conf(10, sub {
+           my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
 
-       my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
-       PVE::Tools::assert_if_modified($digest, $param->{digest});
+           my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
+           PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-       if ($param->{delete}) {
-           foreach my $opt (PVE::Tools::split_list($param->{delete})) {
-               raise_param_exc({ delete => "no such option '$opt'" })
-                   if !$option_properties->{$opt};
-               delete $cluster_conf->{options}->{$opt};
+           if ($param->{delete}) {
+               foreach my $opt (PVE::Tools::split_list($param->{delete})) {
+                   raise_param_exc({ delete => "no such option '$opt'" })
+                       if !$option_properties->{$opt};
+                   delete $cluster_conf->{options}->{$opt};
+               }
            }
-       }
 
-       if (defined($param->{enable}) && ($param->{enable} > 1)) {
-           $param->{enable} = time();
-       }
+           if (defined($param->{enable}) && ($param->{enable} > 1)) {
+               $param->{enable} = time();
+           }
 
-       foreach my $k (keys %$option_properties) {
-           next if !defined($param->{$k});
-           $cluster_conf->{options}->{$k} = $param->{$k};
-       }
+           foreach my $k (keys %$option_properties) {
+               next if !defined($param->{$k});
+               $cluster_conf->{options}->{$k} = $param->{$k};
+           }
 
-       PVE::Firewall::save_clusterfw_conf($cluster_conf);
+           PVE::Firewall::save_clusterfw_conf($cluster_conf);
+       });
 
        # instant firewall update when using double (anti-lockout) API call
        # -> not waiting for a firewall update at the first (timestamp enable) set
index ec0d01694fca2943260d9320fc469730bb6fed65..558ba8ee893c5fd29e8595bea5a857478616a02e 100644 (file)
@@ -91,37 +91,39 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
+       PVE::Firewall::lock_clusterfw_conf(10, sub {
+           my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
 
-       if ($param->{rename}) {
-           my (undef, $digest) = &$get_security_group_list($cluster_conf);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+           if ($param->{rename}) {
+               my (undef, $digest) = &$get_security_group_list($cluster_conf);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           raise_param_exc({ group => "Security group '$param->{rename}' does not exist" })
-               if !$cluster_conf->{groups}->{$param->{rename}};
+               raise_param_exc({ group => "Security group '$param->{rename}' does not exist" })
+                   if !$cluster_conf->{groups}->{$param->{rename}};
 
-           # prevent overwriting an existing group
-           raise_param_exc({ group => "Security group '$param->{group}' does already exist" })
-               if $cluster_conf->{groups}->{$param->{group}} &&
-               $param->{group} ne $param->{rename};
+               # prevent overwriting an existing group
+               raise_param_exc({ group => "Security group '$param->{group}' does already exist" })
+                   if $cluster_conf->{groups}->{$param->{group}} &&
+                   $param->{group} ne $param->{rename};
 
-           my $data = delete $cluster_conf->{groups}->{$param->{rename}};
-           $cluster_conf->{groups}->{$param->{group}} = $data;
-           if (my $comment = delete $cluster_conf->{group_comments}->{$param->{rename}}) {
-               $cluster_conf->{group_comments}->{$param->{group}} = $comment;
-           }
-           $cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
-       } else {
-           foreach my $name (keys %{$cluster_conf->{groups}}) {
-               raise_param_exc({ group => "Security group '$name' already exists" })
-                   if $name eq $param->{group};
-           }
+               my $data = delete $cluster_conf->{groups}->{$param->{rename}};
+               $cluster_conf->{groups}->{$param->{group}} = $data;
+               if (my $comment = delete $cluster_conf->{group_comments}->{$param->{rename}}) {
+                   $cluster_conf->{group_comments}->{$param->{group}} = $comment;
+               }
+               $cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
+           } else {
+               foreach my $name (keys %{$cluster_conf->{groups}}) {
+                   raise_param_exc({ group => "Security group '$name' already exists" })
+                       if $name eq $param->{group};
+               }
 
-           $cluster_conf->{groups}->{$param->{group}} = [];
-           $cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
-       }
+               $cluster_conf->{groups}->{$param->{group}} = [];
+               $cluster_conf->{group_comments}->{$param->{group}} = $param->{comment} if defined($param->{comment});
+           }
 
-       PVE::Firewall::save_clusterfw_conf($cluster_conf);
+           PVE::Firewall::save_clusterfw_conf($cluster_conf);
+       });
 
        return undef;
     }});
index 23034944ee336a3730075241d263480472ad62f2..b66ca55e553e981af0161802a578ed6c6434a116 100644 (file)
@@ -118,30 +118,32 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
-       my $hostfw_conf = PVE::Firewall::load_hostfw_conf($cluster_conf);
-
-       my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($hostfw_conf->{options});
-       PVE::Tools::assert_if_modified($digest, $param->{digest});
-
-       if ($param->{delete}) {
-           foreach my $opt (PVE::Tools::split_list($param->{delete})) {
-               raise_param_exc({ delete => "no such option '$opt'" })
-                   if !$option_properties->{$opt};
-               delete $hostfw_conf->{options}->{$opt};
+       PVE::Firewall::lock_hostfw_conf(10, sub {
+           my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
+           my $hostfw_conf = PVE::Firewall::load_hostfw_conf($cluster_conf);
+
+           my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($hostfw_conf->{options});
+           PVE::Tools::assert_if_modified($digest, $param->{digest});
+
+           if ($param->{delete}) {
+               foreach my $opt (PVE::Tools::split_list($param->{delete})) {
+                   raise_param_exc({ delete => "no such option '$opt'" })
+                       if !$option_properties->{$opt};
+                   delete $hostfw_conf->{options}->{$opt};
+               }
            }
-       }
 
-       if (defined($param->{enable})) {
-           $param->{enable} = $param->{enable} ? 1 : 0;
-       }
+           if (defined($param->{enable})) {
+               $param->{enable} = $param->{enable} ? 1 : 0;
+           }
 
-       foreach my $k (keys %$option_properties) {
-           next if !defined($param->{$k});
-           $hostfw_conf->{options}->{$k} = $param->{$k};
-       }
+           foreach my $k (keys %$option_properties) {
+               next if !defined($param->{$k});
+               $hostfw_conf->{options}->{$k} = $param->{$k};
+           }
 
-       PVE::Firewall::save_hostfw_conf($hostfw_conf);
+           PVE::Firewall::save_hostfw_conf($hostfw_conf);
+       });
 
        return undef;
     }});
index 72e7524b603ebb9a4b2ff6cef01ff78080b65722..913dd86b4c58f83cfd711c0dbba32e7b2037fb4f 100644 (file)
@@ -148,12 +148,17 @@ sub register_delete_ipset {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
+
+               my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
 
-           die "IPSet '$param->{name}' is not empty\n"
-               if scalar(@$ipset);
+               die "IPSet '$param->{name}' is not empty\n"
+                   if scalar(@$ipset);
 
-           $class->save_ipset($param, $fw_conf, undef);
+               $class->save_ipset($param, $fw_conf, undef);
+
+           });
 
            return undef;
        }});
@@ -184,30 +189,35 @@ sub register_create_ip {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my $cidr = $param->{cidr};
+               my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
 
-           foreach my $entry (@$ipset) {
-               raise_param_exc({ cidr => "address '$cidr' already exists" })
-                   if $entry->{cidr} eq $cidr;
-           }
+               my $cidr = $param->{cidr};
+
+               foreach my $entry (@$ipset) {
+                   raise_param_exc({ cidr => "address '$cidr' already exists" })
+                       if $entry->{cidr} eq $cidr;
+               }
+
+               raise_param_exc({ cidr => "a zero prefix is not allowed in ipset entries" })
+                   if $cidr =~ m!/0+$!;
 
-           raise_param_exc({ cidr => "a zero prefix is not allowed in ipset entries" })
-               if $cidr =~ m!/0+$!;
+               # make sure alias exists (if $cidr is an alias)
+               PVE::Firewall::resolve_alias($cluster_conf, $fw_conf, $cidr)
+                   if $cidr =~ m/^${PVE::Firewall::ip_alias_pattern}$/;
 
-           # make sure alias exists (if $cidr is an alias)
-           PVE::Firewall::resolve_alias($cluster_conf, $fw_conf, $cidr)
-               if $cidr =~ m/^${PVE::Firewall::ip_alias_pattern}$/;
+               my $data = { cidr => $cidr };
 
-           my $data = { cidr => $cidr };
+               $data->{nomatch} = 1 if $param->{nomatch};
+               $data->{comment} = $param->{comment} if $param->{comment};
 
-           $data->{nomatch} = 1 if $param->{nomatch};
-           $data->{comment} = $param->{comment} if $param->{comment};
+               unshift @$ipset, $data;
 
-           unshift @$ipset, $data;
+               $class->save_ipset($param, $fw_conf, $ipset);
 
-           $class->save_ipset($param, $fw_conf, $ipset);
+           });
 
            return undef;
        }});
@@ -276,19 +286,27 @@ sub register_update_ip {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
+           my $found = $class->lock_config($param, sub {
+               my ($param) = @_;
+
+               my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
 
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           foreach my $entry (@$ipset) {
-               if($entry->{cidr} eq $param->{cidr}) {
-                   $entry->{nomatch} = $param->{nomatch};
-                   $entry->{comment} = $param->{comment};
-                   $class->save_ipset($param, $fw_conf, $ipset);
-                   return;
+               foreach my $entry (@$ipset) {
+                   if($entry->{cidr} eq $param->{cidr}) {
+                       $entry->{nomatch} = $param->{nomatch};
+                       $entry->{comment} = $param->{comment};
+                       $class->save_ipset($param, $fw_conf, $ipset);
+                       return 1;
+                   }
                }
-           }
+
+               return 0;
+           });
+
+           return if $found;
 
            raise_param_exc({ cidr => "no such IP/Network" });
        }});
@@ -318,18 +336,22 @@ sub register_delete_ip {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my ($cluster_conf, $fw_conf, $ipset) = $class->load_config($param);
 
-           my $new = [];
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($ipset);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           foreach my $entry (@$ipset) {
-               push @$new, $entry if $entry->{cidr} ne $param->{cidr};
-           }
+               my $new = [];
 
-           $class->save_ipset($param, $fw_conf, $new);
+               foreach my $entry (@$ipset) {
+                   push @$new, $entry if $entry->{cidr} ne $param->{cidr};
+               }
+
+               $class->save_ipset($param, $fw_conf, $new);
+           });
 
            return undef;
        }});
@@ -611,37 +633,41 @@ sub register_create {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           if ($param->{rename}) {
-               my (undef, $digest) = &$get_ipset_list($fw_conf);
-               PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my ($cluster_conf, $fw_conf) = $class->load_config($param);
 
-               raise_param_exc({ name => "IPSet '$param->{rename}' does not exist" })
-                   if !$fw_conf->{ipset}->{$param->{rename}};
+               if ($param->{rename}) {
+                   my (undef, $digest) = &$get_ipset_list($fw_conf);
+                   PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-               # prevent overwriting existing ipset
-               raise_param_exc({ name => "IPSet '$param->{name}' does already exist"})
-                   if $fw_conf->{ipset}->{$param->{name}} &&
-                   $param->{name} ne $param->{rename};
+                   raise_param_exc({ name => "IPSet '$param->{rename}' does not exist" })
+                       if !$fw_conf->{ipset}->{$param->{rename}};
 
-               my $data = delete $fw_conf->{ipset}->{$param->{rename}};
-               $fw_conf->{ipset}->{$param->{name}} = $data;
-               if (my $comment = delete $fw_conf->{ipset_comments}->{$param->{rename}}) {
-                   $fw_conf->{ipset_comments}->{$param->{name}} = $comment;
-               }
-               $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
-           } else {
-               foreach my $name (keys %{$fw_conf->{ipset}}) {
-                   raise_param_exc({ name => "IPSet '$name' already exists" })
-                       if $name eq $param->{name};
-               }
+                   # prevent overwriting existing ipset
+                   raise_param_exc({ name => "IPSet '$param->{name}' does already exist"})
+                       if $fw_conf->{ipset}->{$param->{name}} &&
+                       $param->{name} ne $param->{rename};
 
-               $fw_conf->{ipset}->{$param->{name}} = [];
-               $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
-           }
+                   my $data = delete $fw_conf->{ipset}->{$param->{rename}};
+                   $fw_conf->{ipset}->{$param->{name}} = $data;
+                   if (my $comment = delete $fw_conf->{ipset_comments}->{$param->{rename}}) {
+                       $fw_conf->{ipset_comments}->{$param->{name}} = $comment;
+                   }
+                   $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
+               } else {
+                   foreach my $name (keys %{$fw_conf->{ipset}}) {
+                       raise_param_exc({ name => "IPSet '$name' already exists" })
+                           if $name eq $param->{name};
+                   }
+
+                   $fw_conf->{ipset}->{$param->{name}} = [];
+                   $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
+               }
 
-           $class->save_config($param, $fw_conf);
+               $class->save_config($param, $fw_conf);
+           });
 
            return undef;
        }});
index 1fde59659711a8738636d82384d379827c4d90da..1e76e99ae879a32be3f9d07655d538cc7471ac63 100644 (file)
@@ -225,18 +225,22 @@ sub register_create_rule {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
+
+               my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
 
-           my $rule = {};
+               my $rule = {};
 
-           PVE::Firewall::copy_rule_data($rule, $param);
-           PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
+               PVE::Firewall::copy_rule_data($rule, $param);
+               PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
 
-           $rule->{enable} = 0 if !defined($param->{enable});
+               $rule->{enable} = 0 if !defined($param->{enable});
 
-           unshift @$rules, $rule;
+               unshift @$rules, $rule;
 
-           $class->save_rules($param, $fw_conf, $rules);
+               $class->save_rules($param, $fw_conf, $rules);
+           });
 
            return undef;
        }});
@@ -282,36 +286,40 @@ sub register_update_rule {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
+
+               my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
 
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
+               die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
 
-           my $rule = $rules->[$param->{pos}];
+               my $rule = $rules->[$param->{pos}];
 
-           my $moveto = $param->{moveto};
-           if (defined($moveto) && $moveto != $param->{pos}) {
-               my $newrules = [];
-               for (my $i = 0; $i < scalar(@$rules); $i++) {
-                   next if $i == $param->{pos};
-                   if ($i == $moveto) {
-                       push @$newrules, $rule;
+               my $moveto = $param->{moveto};
+               if (defined($moveto) && $moveto != $param->{pos}) {
+                   my $newrules = [];
+                   for (my $i = 0; $i < scalar(@$rules); $i++) {
+                       next if $i == $param->{pos};
+                       if ($i == $moveto) {
+                           push @$newrules, $rule;
+                       }
+                       push @$newrules, $rules->[$i];
                    }
-                   push @$newrules, $rules->[$i];
-               }
-               push @$newrules, $rule if $moveto >= scalar(@$rules);
-               $rules = $newrules;
-           } else {
-               PVE::Firewall::copy_rule_data($rule, $param);
+                   push @$newrules, $rule if $moveto >= scalar(@$rules);
+                   $rules = $newrules;
+               } else {
+                   PVE::Firewall::copy_rule_data($rule, $param);
 
-               PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
+                   PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
 
-               PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
-           }
+                   PVE::Firewall::verify_rule($rule, $cluster_conf, $fw_conf, $class->rule_env());
+               }
 
-           $class->save_rules($param, $fw_conf, $rules);
+               $class->save_rules($param, $fw_conf, $rules);
+           });
 
            return undef;
        }});
@@ -344,16 +352,20 @@ sub register_delete_rule {
        code => sub {
            my ($param) = @_;
 
-           my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
+           $class->lock_config($param, sub {
+               my ($param) = @_;
 
-           my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
+               my ($cluster_conf, $fw_conf, $rules) = $class->load_config($param);
 
-           die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
+               my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
 
-           splice(@$rules, $param->{pos}, 1);
+               die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
 
-           $class->save_rules($param, $fw_conf, $rules);
+               splice(@$rules, $param->{pos}, 1);
+
+               $class->save_rules($param, $fw_conf, $rules);
+           });
 
            return undef;
        }});
@@ -433,12 +445,16 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param);
+       __PACKAGE__->lock_config($param, sub {
+           my ($param) = @_;
+
+           my (undef, $cluster_conf, $rules) = __PACKAGE__->load_config($param);
 
-       die "Security group '$param->{group}' is not empty\n"
-           if scalar(@$rules);
+           die "Security group '$param->{group}' is not empty\n"
+               if scalar(@$rules);
 
-       __PACKAGE__->save_rules($param, $cluster_conf, undef);
+           __PACKAGE__->save_rules($param, $cluster_conf, undef);
+       });
 
        return undef;
     }});
index 5b9b6dd7a6c670b80fd343b7022b076d9105b63d..48b8c5fe2a974a02a0bb37d54fd4317b3d9f8cf6 100644 (file)
@@ -121,31 +121,32 @@ sub register_handlers {
        code => sub {
            my ($param) = @_;
 
-
-           my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
-           my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
-
-           my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options});
-           PVE::Tools::assert_if_modified($digest, $param->{digest});
-
-           if ($param->{delete}) {
-               foreach my $opt (PVE::Tools::split_list($param->{delete})) {
-                   raise_param_exc({ delete => "no such option '$opt'" })
-                       if !$option_properties->{$opt};
-                   delete $vmfw_conf->{options}->{$opt};
+           PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, sub {
+               my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
+               my $vmfw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, $rule_env, $param->{vmid});
+
+               my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($vmfw_conf->{options});
+               PVE::Tools::assert_if_modified($digest, $param->{digest});
+
+               if ($param->{delete}) {
+                   foreach my $opt (PVE::Tools::split_list($param->{delete})) {
+                       raise_param_exc({ delete => "no such option '$opt'" })
+                           if !$option_properties->{$opt};
+                       delete $vmfw_conf->{options}->{$opt};
+                   }
                }
-           }
 
-           if (defined($param->{enable})) {
-               $param->{enable} = $param->{enable} ? 1 : 0;
-           }
+               if (defined($param->{enable})) {
+                   $param->{enable} = $param->{enable} ? 1 : 0;
+               }
 
-           foreach my $k (keys %$option_properties) {
-               next if !defined($param->{$k});
-               $vmfw_conf->{options}->{$k} = $param->{$k};
-           }
+               foreach my $k (keys %$option_properties) {
+                   next if !defined($param->{$k});
+                   $vmfw_conf->{options}->{$k} = $param->{$k};
+               }
 
-           PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf);
+               PVE::Firewall::save_vmfw_conf($param->{vmid}, $vmfw_conf);
+           });
 
            return undef;
        }});