[pve-devel] [PATCH firewall 3/7] api: lock configs
Fabian Grünbichler
f.gruenbichler at proxmox.com
Wed Apr 29 10:52:52 CEST 2020
wherever we have a r-m-w cycle.
Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
Notes:
best viewed with -w
src/PVE/API2/Firewall/Aliases.pm | 80 +++++++++-------
src/PVE/API2/Firewall/Cluster.pm | 36 ++++----
src/PVE/API2/Firewall/Groups.pm | 52 ++++++-----
src/PVE/API2/Firewall/Host.pm | 42 +++++----
src/PVE/API2/Firewall/IPSet.pm | 152 ++++++++++++++++++-------------
src/PVE/API2/Firewall/Rules.pm | 94 +++++++++++--------
src/PVE/API2/Firewall/VM.pm | 43 ++++-----
7 files changed, 280 insertions(+), 219 deletions(-)
diff --git a/src/PVE/API2/Firewall/Aliases.pm b/src/PVE/API2/Firewall/Aliases.pm
index 9ea6f70..33ac669 100644
--- a/src/PVE/API2/Firewall/Aliases.pm
+++ b/src/PVE/API2/Firewall/Aliases.pm
@@ -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;
}});
diff --git a/src/PVE/API2/Firewall/Cluster.pm b/src/PVE/API2/Firewall/Cluster.pm
index 0bf8285..c9c3e67 100644
--- a/src/PVE/API2/Firewall/Cluster.pm
+++ b/src/PVE/API2/Firewall/Cluster.pm
@@ -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
diff --git a/src/PVE/API2/Firewall/Groups.pm b/src/PVE/API2/Firewall/Groups.pm
index ec0d016..558ba8e 100644
--- a/src/PVE/API2/Firewall/Groups.pm
+++ b/src/PVE/API2/Firewall/Groups.pm
@@ -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;
}});
diff --git a/src/PVE/API2/Firewall/Host.pm b/src/PVE/API2/Firewall/Host.pm
index 2303494..b66ca55 100644
--- a/src/PVE/API2/Firewall/Host.pm
+++ b/src/PVE/API2/Firewall/Host.pm
@@ -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;
}});
diff --git a/src/PVE/API2/Firewall/IPSet.pm b/src/PVE/API2/Firewall/IPSet.pm
index 72e7524..913dd86 100644
--- a/src/PVE/API2/Firewall/IPSet.pm
+++ b/src/PVE/API2/Firewall/IPSet.pm
@@ -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;
}});
diff --git a/src/PVE/API2/Firewall/Rules.pm b/src/PVE/API2/Firewall/Rules.pm
index 1fde596..1e76e99 100644
--- a/src/PVE/API2/Firewall/Rules.pm
+++ b/src/PVE/API2/Firewall/Rules.pm
@@ -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;
}});
diff --git a/src/PVE/API2/Firewall/VM.pm b/src/PVE/API2/Firewall/VM.pm
index 5b9b6dd..48b8c5f 100644
--- a/src/PVE/API2/Firewall/VM.pm
+++ b/src/PVE/API2/Firewall/VM.pm
@@ -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;
}});
--
2.20.1
More information about the pve-devel
mailing list