]> git.proxmox.com Git - pve-firewall.git/blame - src/PVE/API2/Firewall/Aliases.pm
fix #5335: stable sorting in cluster.fw
[pve-firewall.git] / src / PVE / API2 / Firewall / Aliases.pm
CommitLineData
81d574a7
DM
1package PVE::API2::Firewall::AliasesBase;
2
3use strict;
4use warnings;
5use PVE::Exception qw(raise raise_param_exc);
6use PVE::JSONSchema qw(get_standard_option);
7
8use PVE::Firewall;
9
10use base qw(PVE::RESTHandler);
11
75a12a9d 12my $api_properties = {
81d574a7
DM
13 cidr => {
14 description => "Network/IP specification in CIDR format.",
ae029a88 15 type => 'string', format => 'IPorCIDR',
81d574a7
DM
16 },
17 name => get_standard_option('pve-fw-alias'),
cdc39d63
DM
18 rename => get_standard_option('pve-fw-alias', {
19 description => "Rename an existing alias.",
20 optional => 1,
21 }),
81d574a7
DM
22 comment => {
23 type => 'string',
24 optional => 1,
cdc39d63 25 },
81d574a7
DM
26};
27
05496017
FG
28sub lock_config {
29 my ($class, $param, $code) = @_;
30
31 die "implement this in subclass";
32}
33
81d574a7
DM
34sub load_config {
35 my ($class, $param) = @_;
36
37 die "implement this in subclass";
38
39 #return ($fw_conf, $rules);
40}
41
42sub save_aliases {
43 my ($class, $param, $fw_conf, $aliases) = @_;
44
45 die "implement this in subclass";
46}
47
5679b3a8
DM
48sub rule_env {
49 my ($class, $param) = @_;
75a12a9d 50
5679b3a8
DM
51 die "implement this in subclass";
52}
53
81d574a7
DM
54my $additional_param_hash = {};
55
56sub additional_parameters {
57 my ($class, $new_value) = @_;
58
59 if (defined($new_value)) {
60 $additional_param_hash->{$class} = $new_value;
61 }
62
63 # return a copy
64 my $copy = {};
65 my $org = $additional_param_hash->{$class} || {};
66 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
67 return $copy;
68}
69
70my $aliases_to_list = sub {
71 my ($aliases) = @_;
72
73 my $list = [];
74 foreach my $k (sort keys %$aliases) {
75 push @$list, $aliases->{$k};
76 }
77 return $list;
78};
79
80sub register_get_aliases {
81 my ($class) = @_;
82
83 my $properties = $class->additional_parameters();
84
85 $class->register_method({
86 name => 'get_aliases',
87 path => '',
88 method => 'GET',
89 description => "List aliases",
5679b3a8 90 permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
81d574a7
DM
91 parameters => {
92 additionalProperties => 0,
93 properties => $properties,
94 },
95 returns => {
96 type => 'array',
97 items => {
98 type => "object",
99 properties => {
100 name => { type => 'string' },
101 cidr => { type => 'string' },
102 comment => {
103 type => 'string',
104 optional => 1,
105 },
75a12a9d 106 digest => get_standard_option('pve-config-digest', { optional => 0} ),
81d574a7
DM
107 },
108 },
109 links => [ { rel => 'child', href => "{name}" } ],
110 },
111 code => sub {
112 my ($param) = @_;
113
114 my ($fw_conf, $aliases) = $class->load_config($param);
115
116 my $list = &$aliases_to_list($aliases);
117
118 return PVE::Firewall::copy_list_with_digest($list);
119 }});
120}
121
122sub register_create_alias {
123 my ($class) = @_;
124
125 my $properties = $class->additional_parameters();
126
127 $properties->{name} = $api_properties->{name};
128 $properties->{cidr} = $api_properties->{cidr};
129 $properties->{comment} = $api_properties->{comment};
130
131 $class->register_method({
132 name => 'create_alias',
133 path => '',
134 method => 'POST',
135 description => "Create IP or Network Alias.",
5679b3a8 136 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
81d574a7
DM
137 protected => 1,
138 parameters => {
139 additionalProperties => 0,
140 properties => $properties,
141 },
142 returns => { type => "null" },
143 code => sub {
144 my ($param) = @_;
145
a38849e6
FG
146 $class->lock_config($param, sub {
147 my ($param) = @_;
81d574a7 148
a38849e6 149 my ($fw_conf, $aliases) = $class->load_config($param);
75a12a9d 150
a38849e6 151 my $name = lc($param->{name});
75a12a9d 152
a38849e6
FG
153 raise_param_exc({ name => "alias '$param->{name}' already exists" })
154 if defined($aliases->{$name});
81d574a7 155
a38849e6
FG
156 my $data = { name => $param->{name}, cidr => $param->{cidr} };
157 $data->{comment} = $param->{comment} if $param->{comment};
81d574a7 158
a38849e6
FG
159 $aliases->{$name} = $data;
160
161 $class->save_aliases($param, $fw_conf, $aliases);
162 });
81d574a7
DM
163
164 return undef;
165 }});
166}
167
168sub register_read_alias {
169 my ($class) = @_;
170
171 my $properties = $class->additional_parameters();
172
173 $properties->{name} = $api_properties->{name};
75a12a9d 174
81d574a7
DM
175 $class->register_method({
176 name => 'read_alias',
177 path => '{name}',
178 method => 'GET',
179 description => "Read alias.",
5679b3a8 180 permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
81d574a7
DM
181 parameters => {
182 additionalProperties => 0,
183 properties => $properties,
184 },
185 returns => { type => "object" },
186 code => sub {
187 my ($param) = @_;
188
189 my ($fw_conf, $aliases) = $class->load_config($param);
190
191 my $name = lc($param->{name});
192
193 raise_param_exc({ name => "no such alias" })
194 if !defined($aliases->{$name});
195
196 return $aliases->{$name};
197 }});
198}
199
200sub register_update_alias {
201 my ($class) = @_;
202
203 my $properties = $class->additional_parameters();
204
205 $properties->{name} = $api_properties->{name};
cdc39d63 206 $properties->{rename} = $api_properties->{rename};
81d574a7
DM
207 $properties->{cidr} = $api_properties->{cidr};
208 $properties->{comment} = $api_properties->{comment};
209 $properties->{digest} = get_standard_option('pve-config-digest');
210
211 $class->register_method({
212 name => 'update_alias',
213 path => '{name}',
214 method => 'PUT',
215 description => "Update IP or Network alias.",
5679b3a8 216 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
81d574a7
DM
217 protected => 1,
218 parameters => {
219 additionalProperties => 0,
220 properties => $properties,
221 },
222 returns => { type => "null" },
223 code => sub {
224 my ($param) = @_;
225
a38849e6
FG
226 $class->lock_config($param, sub {
227 my ($param) = @_;
81d574a7 228
a38849e6 229 my ($fw_conf, $aliases) = $class->load_config($param);
81d574a7 230
a38849e6 231 my $list = &$aliases_to_list($aliases);
81d574a7 232
a38849e6 233 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
81d574a7 234
a38849e6 235 PVE::Tools::assert_if_modified($digest, $param->{digest});
81d574a7 236
a38849e6 237 my $name = lc($param->{name});
81d574a7 238
a38849e6 239 raise_param_exc({ name => "no such alias" }) if !$aliases->{$name};
81d574a7 240
a38849e6
FG
241 my $data = { name => $param->{name}, cidr => $param->{cidr} };
242 $data->{comment} = $param->{comment} if $param->{comment};
81d574a7 243
a38849e6 244 $aliases->{$name} = $data;
cdc39d63 245
a38849e6
FG
246 my $rename = $param->{rename};
247 $rename = lc($rename) if $rename;
cdc39d63 248
a38849e6
FG
249 if ($rename && ($name ne $rename)) {
250 raise_param_exc({ name => "alias '$param->{rename}' already exists" })
251 if defined($aliases->{$rename});
252 $aliases->{$name}->{name} = $param->{rename};
253 $aliases->{$rename} = $aliases->{$name};
254 delete $aliases->{$name};
255 }
256
257 $class->save_aliases($param, $fw_conf, $aliases);
258 });
cdc39d63
DM
259
260 return undef;
81d574a7
DM
261 }});
262}
263
264sub register_delete_alias {
265 my ($class) = @_;
266
267 my $properties = $class->additional_parameters();
268
269 $properties->{name} = $api_properties->{name};
81d574a7
DM
270 $properties->{digest} = get_standard_option('pve-config-digest');
271
272 $class->register_method({
273 name => 'remove_alias',
274 path => '{name}',
275 method => 'DELETE',
276 description => "Remove IP or Network alias.",
5679b3a8 277 permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
81d574a7
DM
278 protected => 1,
279 parameters => {
280 additionalProperties => 0,
281 properties => $properties,
282 },
283 returns => { type => "null" },
284 code => sub {
285 my ($param) = @_;
286
a38849e6
FG
287 $class->lock_config($param, sub {
288 my ($param) = @_;
81d574a7 289
a38849e6 290 my ($fw_conf, $aliases) = $class->load_config($param);
81d574a7 291
a38849e6
FG
292 my $list = &$aliases_to_list($aliases);
293 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
294 PVE::Tools::assert_if_modified($digest, $param->{digest});
295
296 my $name = lc($param->{name});
297 delete $aliases->{$name};
81d574a7 298
a38849e6
FG
299 $class->save_aliases($param, $fw_conf, $aliases);
300 });
75a12a9d 301
81d574a7
DM
302 return undef;
303 }});
304}
305
306sub register_handlers {
307 my ($class) = @_;
308
309 $class->register_get_aliases();
310 $class->register_create_alias();
311 $class->register_read_alias();
312 $class->register_update_alias();
313 $class->register_delete_alias();
314}
315
316package PVE::API2::Firewall::ClusterAliases;
317
318use strict;
319use warnings;
320
321use base qw(PVE::API2::Firewall::AliasesBase);
322
5679b3a8
DM
323sub rule_env {
324 my ($class, $param) = @_;
75a12a9d 325
5679b3a8
DM
326 return 'cluster';
327}
328
05496017
FG
329sub lock_config {
330 my ($class, $param, $code) = @_;
331
332 PVE::Firewall::lock_clusterfw_conf(10, $code, $param);
333}
334
81d574a7
DM
335sub load_config {
336 my ($class, $param) = @_;
337
338 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
339 my $aliases = $fw_conf->{aliases};
340
341 return ($fw_conf, $aliases);
342}
343
344sub save_aliases {
345 my ($class, $param, $fw_conf, $aliases) = @_;
346
347 $fw_conf->{aliases} = $aliases;
348 PVE::Firewall::save_clusterfw_conf($fw_conf);
349}
350
351__PACKAGE__->register_handlers();
352
e76a9f53
DM
353package PVE::API2::Firewall::VMAliases;
354
355use strict;
356use warnings;
357use PVE::JSONSchema qw(get_standard_option);
358
359use base qw(PVE::API2::Firewall::AliasesBase);
360
5679b3a8
DM
361sub rule_env {
362 my ($class, $param) = @_;
75a12a9d 363
5679b3a8
DM
364 return 'vm';
365}
366
75a12a9d 367__PACKAGE__->additional_parameters({
e76a9f53 368 node => get_standard_option('pve-node'),
75a12a9d 369 vmid => get_standard_option('pve-vmid'),
e76a9f53
DM
370});
371
05496017
FG
372sub lock_config {
373 my ($class, $param, $code) = @_;
374
375 PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param);
376}
377
e76a9f53
DM
378sub load_config {
379 my ($class, $param) = @_;
380
42ec8178
DM
381 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
382 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
b6b8e6ad
DM
383 my $aliases = $fw_conf->{aliases};
384
385 return ($fw_conf, $aliases);
386}
387
388sub save_aliases {
389 my ($class, $param, $fw_conf, $aliases) = @_;
390
391 $fw_conf->{aliases} = $aliases;
392 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
393}
394
395__PACKAGE__->register_handlers();
396
397package PVE::API2::Firewall::CTAliases;
398
399use strict;
400use warnings;
401use PVE::JSONSchema qw(get_standard_option);
402
403use base qw(PVE::API2::Firewall::AliasesBase);
404
5679b3a8
DM
405sub rule_env {
406 my ($class, $param) = @_;
75a12a9d 407
5679b3a8
DM
408 return 'ct';
409}
410
75a12a9d 411__PACKAGE__->additional_parameters({
b6b8e6ad 412 node => get_standard_option('pve-node'),
75a12a9d 413 vmid => get_standard_option('pve-vmid'),
b6b8e6ad
DM
414});
415
05496017
FG
416sub lock_config {
417 my ($class, $param, $code) = @_;
418
419 PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param);
420}
421
b6b8e6ad
DM
422sub load_config {
423 my ($class, $param) = @_;
424
42ec8178
DM
425 my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
426 my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
e76a9f53
DM
427 my $aliases = $fw_conf->{aliases};
428
429 return ($fw_conf, $aliases);
430}
431
432sub save_aliases {
433 my ($class, $param, $fw_conf, $aliases) = @_;
434
435 $fw_conf->{aliases} = $aliases;
436 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
437}
438
439__PACKAGE__->register_handlers();
440
81d574a7 4411;