Also implement concurrenty change prevention for ipset API.
PVE::Tools::assert_if_modified($digest, $param->{digest});
PVE::Tools::assert_if_modified($digest, $param->{digest});
- foreach my $name (keys %{$cluster_conf->{groups}}) {
- raise_param_exc({ name => "Security group '$name' already exists" })
- if !$param->{rename} && $name eq $param->{name};
+ if (!$param->{rename}) {
+ foreach my $name (keys %{$cluster_conf->{groups}}) {
+ raise_param_exc({ name => "Security group '$name' already exists" })
+ if $name eq $param->{name};
+ }
}
if ($param->{rename}) {
}
if ($param->{rename}) {
properties => {
name => get_standard_option('pve-security-group-name'),
digest => get_standard_option('pve-config-digest'),
properties => {
name => get_standard_option('pve-security-group-name'),
digest => get_standard_option('pve-config-digest'),
},
returns => { type => 'null' },
code => sub {
},
returns => { type => 'null' },
code => sub {
nomatch => {
type => 'boolean',
optional => 1,
nomatch => {
type => 'boolean',
optional => 1,
+ },
+ digest => get_standard_option('pve-config-digest', { optional => 0} ),
},
},
links => [ { rel => 'child', href => "{cidr}" } ],
},
},
links => [ { rel => 'child', href => "{cidr}" } ],
my ($fw_conf, $ipset) = $class->load_config($param);
my ($fw_conf, $ipset) = $class->load_config($param);
+ my $digest = $fw_conf->{digest};
+
+ my $res = [];
+ foreach my $entry (@$ipset) {
+ my $data = {digest => $digest};
+ foreach my $k (qw(cidr comment nomatch)) {
+ $data->{$k} = $entry->{$k} if $entry->{$k};
+ }
+ push @$res, $data;
+ }
+
+ return $res;
$properties->{cidr} = $api_properties->{cidr};
$properties->{nomatch} = $api_properties->{nomatch};
$properties->{comment} = $api_properties->{comment};
$properties->{cidr} = $api_properties->{cidr};
$properties->{nomatch} = $api_properties->{nomatch};
$properties->{comment} = $api_properties->{comment};
$class->register_method({
name => 'create_ip',
path => '',
$class->register_method({
name => 'create_ip',
path => '',
my ($param) = @_;
my ($fw_conf, $ipset) = $class->load_config($param);
my ($param) = @_;
my ($fw_conf, $ipset) = $class->load_config($param);
+ my $digest = $fw_conf->{digest};
foreach my $entry (@$ipset) {
foreach my $entry (@$ipset) {
- return $entry if $entry->{cidr} eq $param->{cidr};
+ if ($entry->{cidr} eq $param->{cidr}) {
+ $entry->{digest} = $digest;
+ return $entry;
+ }
}
raise_param_exc({ cidr => "no such IP/Network" });
}
raise_param_exc({ cidr => "no such IP/Network" });
$properties->{cidr} = $api_properties->{cidr};
$properties->{nomatch} = $api_properties->{nomatch};
$properties->{comment} = $api_properties->{comment};
$properties->{cidr} = $api_properties->{cidr};
$properties->{nomatch} = $api_properties->{nomatch};
$properties->{comment} = $api_properties->{comment};
+ $properties->{digest} = get_standard_option('pve-config-digest');
+
$class->register_method({
name => 'update_ip',
path => '{cidr}',
$class->register_method({
name => 'update_ip',
path => '{cidr}',
my ($fw_conf, $ipset) = $class->load_config($param);
my ($fw_conf, $ipset) = $class->load_config($param);
+ PVE::Tools::assert_if_modified($fw_conf->{digest}, $param->{digest});
+
foreach my $entry (@$ipset) {
if($entry->{cidr} eq $param->{cidr}) {
$entry->{nomatch} = $param->{nomatch};
foreach my $entry (@$ipset) {
if($entry->{cidr} eq $param->{cidr}) {
$entry->{nomatch} = $param->{nomatch};
$properties->{name} = $api_properties->{name};
$properties->{cidr} = $api_properties->{cidr};
$properties->{name} = $api_properties->{name};
$properties->{cidr} = $api_properties->{cidr};
+ $properties->{digest} = get_standard_option('pve-config-digest');
+
$class->register_method({
name => 'remove_ip',
path => '{cidr}',
$class->register_method({
name => 'remove_ip',
path => '{cidr}',
my ($fw_conf, $ipset) = $class->load_config($param);
my ($fw_conf, $ipset) = $class->load_config($param);
+ PVE::Tools::assert_if_modified($fw_conf->{digest}, $param->{digest});
+
my $new = [];
foreach my $entry (@$ipset) {
my $new = [];
foreach my $entry (@$ipset) {
type => "object",
properties => {
name => get_standard_option('ipset-name'),
type => "object",
properties => {
name => get_standard_option('ipset-name'),
+ digest => get_standard_option('pve-config-digest', { optional => 0} ),
+ comment => {
+ type => 'string',
+ optional => 1,
+ }
},
},
links => [ { rel => 'child', href => "{name}" } ],
},
},
links => [ { rel => 'child', href => "{name}" } ],
my $fw_conf = $class->load_config();
my $fw_conf = $class->load_config();
+ my $digest = $fw_conf->{digest};
+
my $res = [];
foreach my $name (keys %{$fw_conf->{ipset}}) {
my $res = [];
foreach my $name (keys %{$fw_conf->{ipset}}) {
- push @$res, { name => $name, count => scalar(@{$fw_conf->{ipset}->{$name}}) };
+ my $data = {
+ name => $name,
+ digest => $digest,
+ count => scalar(@{$fw_conf->{ipset}->{$name}})
+ };
+ if (my $comment = $fw_conf->{ipset_comments}->{$name}) {
+ $data->{comment} = $comment;
+ }
+ push @$res, $data;
additionalProperties => 0,
properties => {
name => get_standard_option('ipset-name'),
additionalProperties => 0,
properties => {
name => get_standard_option('ipset-name'),
+ comment => {
+ type => 'string',
+ optional => 1,
+ },
rename => get_standard_option('ipset-name', {
rename => get_standard_option('ipset-name', {
- description => "Rename an existing IPSet.",
+ description => "Rename an existing IPSet. You can set 'rename' to the same value as 'name' to update the 'comment' of an existing IPSet.",
+ digest => get_standard_option('pve-config-digest'),
}
},
returns => { type => 'null' },
}
},
returns => { type => 'null' },
my $fw_conf = $class->load_config();
my $fw_conf = $class->load_config();
- foreach my $name (keys %{$fw_conf->{ipset}}) {
- raise_param_exc({ name => "IPSet '$name' already exists" })
- if $name eq $param->{name};
+ my $digest = $fw_conf->{digest};
+
+ PVE::Tools::assert_if_modified($digest, $param->{digest});
+
+ if (!$param->{rename}) {
+ foreach my $name (keys %{$fw_conf->{ipset}}) {
+ raise_param_exc({ name => "IPSet '$name' already exists" })
+ if $name eq $param->{name};
+ }
}
if ($param->{rename}) {
}
if ($param->{rename}) {
if !$fw_conf->{ipset}->{$param->{rename}};
my $data = delete $fw_conf->{ipset}->{$param->{rename}};
$fw_conf->{ipset}->{$param->{name}} = $data;
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 {
$fw_conf->{ipset}->{$param->{name}} = [];
} else {
$fw_conf->{ipset}->{$param->{name}} = [];
+ $fw_conf->{ipset_comments}->{$param->{name}} = $param->{comment} if defined($param->{comment});
}
$class->save_config($fw_conf);
}
$class->save_config($fw_conf);
additionalProperties => 0,
properties => {
name => get_standard_option('ipset-name'),
additionalProperties => 0,
properties => {
name => get_standard_option('ipset-name'),
+ digest => get_standard_option('pve-config-digest'),
+ },
},
returns => { type => 'null' },
code => sub {
},
returns => { type => 'null' },
code => sub {
my $fw_conf = $class->load_config();
my $fw_conf = $class->load_config();
+ PVE::Tools::assert_if_modified($fw_conf->{digest}, $param->{digest});
+
return undef if !$fw_conf->{ipset}->{$param->{name}};
die "IPSet '$param->{name}' is not empty\n"
return undef if !$fw_conf->{ipset}->{$param->{name}};
die "IPSet '$param->{name}' is not empty\n"
push @{$res->{$section}}, $rule;
}
push @{$res->{$section}}, $rule;
}
-$res->{digest} = $digest->b64digest;
+ $res->{digest} = $digest->b64digest;
options => {},
groups => {},
group_comments => {},
options => {},
groups => {},
group_comments => {},
+ ipset => {} ,
+ ipset_comments => {},
};
my $digest = Digest::SHA->new('sha1');
};
my $digest = Digest::SHA->new('sha1');
- if ($line =~ m/^\[ipset\s+(\S+)\]\s*$/i) {
+ if ($line =~ m/^\[ipset\s+(\S+)\]\s*(?:#\s*(.*?)\s*)?$/i) {
$section = 'ipset';
$group = lc($1);
$section = 'ipset';
$group = lc($1);
$res->{$section}->{$group} = [];
$res->{$section}->{$group} = [];
+ $res->{ipset_comments}->{$group} = $comment if $comment;
$raw .= &$format_options($options) if scalar(keys %$options);
foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) {
$raw .= &$format_options($options) if scalar(keys %$options);
foreach my $ipset (sort keys %{$cluster_conf->{ipset}}) {
- $raw .= "[IPSET $ipset]\n\n";
+ if (my $comment = $cluster_conf->{ipset_comments}->{$ipset}) {
+ $raw .= "[IPSET $ipset] # $comment\n\n";
+ } else {
+ $raw .= "[IPSET $ipset]\n\n";
+ }
my $options = $cluster_conf->{ipset}->{$ipset};
$raw .= &$format_ipset($options);
$raw .= "\n";
my $options = $cluster_conf->{ipset}->{$ipset};
$raw .= &$format_ipset($options);
$raw .= "\n";