9ea6f70ccb57ee22b80c5e17141350321b5a0ff1
[pve-firewall.git] / src / PVE / API2 / Firewall / Aliases.pm
1 package PVE::API2::Firewall::AliasesBase;
2
3 use strict;
4 use warnings;
5 use PVE::Exception qw(raise raise_param_exc);
6 use PVE::JSONSchema qw(get_standard_option);
7
8 use PVE::Firewall;
9
10 use base qw(PVE::RESTHandler);
11
12 my $api_properties = {
13     cidr => {
14         description => "Network/IP specification in CIDR format.",
15         type => 'string', format => 'IPorCIDR',
16     },
17     name => get_standard_option('pve-fw-alias'),
18     rename => get_standard_option('pve-fw-alias', {
19         description => "Rename an existing alias.",
20         optional => 1,
21     }),
22     comment => {
23         type => 'string',
24         optional => 1,
25     },
26 };
27
28 sub lock_config {
29     my ($class, $param, $code) = @_;
30
31     die "implement this in subclass";
32 }
33
34 sub load_config {
35     my ($class, $param) = @_;
36
37     die "implement this in subclass";
38
39     #return ($fw_conf, $rules);
40 }
41
42 sub save_aliases {
43     my ($class, $param, $fw_conf, $aliases) = @_;
44
45     die "implement this in subclass";
46 }
47
48 sub rule_env {
49     my ($class, $param) = @_;
50
51     die "implement this in subclass";
52 }
53
54 my $additional_param_hash = {};
55
56 sub 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
70 my $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
80 sub 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",
90         permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
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                     },
106                     digest => get_standard_option('pve-config-digest', { optional => 0} ),
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
122 sub 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.",
136         permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
137         protected => 1,
138         parameters => {
139             additionalProperties => 0,
140             properties => $properties,
141         },
142         returns => { type => "null" },
143         code => sub {
144             my ($param) = @_;
145
146             my ($fw_conf, $aliases) = $class->load_config($param);
147
148             my $name = lc($param->{name});
149
150             raise_param_exc({ name => "alias '$param->{name}' already exists" })
151                 if defined($aliases->{$name});
152
153             my $data = { name => $param->{name}, cidr => $param->{cidr} };
154             $data->{comment} = $param->{comment} if $param->{comment};
155
156             $aliases->{$name} = $data;
157
158             $class->save_aliases($param, $fw_conf, $aliases);
159
160             return undef;
161         }});
162 }
163
164 sub register_read_alias {
165     my ($class) = @_;
166
167     my $properties = $class->additional_parameters();
168
169     $properties->{name} = $api_properties->{name};
170
171     $class->register_method({
172         name => 'read_alias',
173         path => '{name}',
174         method => 'GET',
175         description => "Read alias.",
176         permissions => PVE::Firewall::rules_audit_permissions($class->rule_env()),
177         parameters => {
178             additionalProperties => 0,
179             properties => $properties,
180         },
181         returns => { type => "object" },
182         code => sub {
183             my ($param) = @_;
184
185             my ($fw_conf, $aliases) = $class->load_config($param);
186
187             my $name = lc($param->{name});
188
189             raise_param_exc({ name => "no such alias" })
190                 if !defined($aliases->{$name});
191
192             return $aliases->{$name};
193         }});
194 }
195
196 sub register_update_alias {
197     my ($class) = @_;
198
199     my $properties = $class->additional_parameters();
200
201     $properties->{name} = $api_properties->{name};
202     $properties->{rename} = $api_properties->{rename};
203     $properties->{cidr} = $api_properties->{cidr};
204     $properties->{comment} = $api_properties->{comment};
205     $properties->{digest} = get_standard_option('pve-config-digest');
206
207     $class->register_method({
208         name => 'update_alias',
209         path => '{name}',
210         method => 'PUT',
211         description => "Update IP or Network alias.",
212         permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
213         protected => 1,
214         parameters => {
215             additionalProperties => 0,
216             properties => $properties,
217         },
218         returns => { type => "null" },
219         code => sub {
220             my ($param) = @_;
221
222             my ($fw_conf, $aliases) = $class->load_config($param);
223
224             my $list = &$aliases_to_list($aliases);
225
226             my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
227
228             PVE::Tools::assert_if_modified($digest, $param->{digest});
229
230             my $name = lc($param->{name});
231
232             raise_param_exc({ name => "no such alias" }) if !$aliases->{$name};
233
234             my $data = { name => $param->{name}, cidr => $param->{cidr} };
235             $data->{comment} = $param->{comment} if $param->{comment};
236
237             $aliases->{$name} = $data;
238
239             my $rename = $param->{rename};
240             $rename = lc($rename) if $rename;
241
242             if ($rename && ($name ne $rename)) {
243                 raise_param_exc({ name => "alias '$param->{rename}' already exists" })
244                     if defined($aliases->{$rename});
245                 $aliases->{$name}->{name} = $param->{rename};
246                 $aliases->{$rename} = $aliases->{$name};
247                 delete $aliases->{$name};
248             }
249
250             $class->save_aliases($param, $fw_conf, $aliases);
251
252             return undef;
253         }});
254 }
255
256 sub register_delete_alias {
257     my ($class) = @_;
258
259     my $properties = $class->additional_parameters();
260
261     $properties->{name} = $api_properties->{name};
262     $properties->{digest} = get_standard_option('pve-config-digest');
263
264     $class->register_method({
265         name => 'remove_alias',
266         path => '{name}',
267         method => 'DELETE',
268         description => "Remove IP or Network alias.",
269         permissions => PVE::Firewall::rules_modify_permissions($class->rule_env()),
270         protected => 1,
271         parameters => {
272             additionalProperties => 0,
273             properties => $properties,
274         },
275         returns => { type => "null" },
276         code => sub {
277             my ($param) = @_;
278
279             my ($fw_conf, $aliases) = $class->load_config($param);
280
281             my $list = &$aliases_to_list($aliases);
282             my (undef, $digest) = PVE::Firewall::copy_list_with_digest($list);
283             PVE::Tools::assert_if_modified($digest, $param->{digest});
284
285             my $name = lc($param->{name});
286             delete $aliases->{$name};
287
288             $class->save_aliases($param, $fw_conf, $aliases);
289
290             return undef;
291         }});
292 }
293
294 sub register_handlers {
295     my ($class) = @_;
296
297     $class->register_get_aliases();
298     $class->register_create_alias();
299     $class->register_read_alias();
300     $class->register_update_alias();
301     $class->register_delete_alias();
302 }
303
304 package PVE::API2::Firewall::ClusterAliases;
305
306 use strict;
307 use warnings;
308
309 use base qw(PVE::API2::Firewall::AliasesBase);
310
311 sub rule_env {
312     my ($class, $param) = @_;
313
314     return 'cluster';
315 }
316
317 sub lock_config {
318     my ($class, $param, $code) = @_;
319
320     PVE::Firewall::lock_clusterfw_conf(10, $code, $param);
321 }
322
323 sub load_config {
324     my ($class, $param) = @_;
325
326     my $fw_conf = PVE::Firewall::load_clusterfw_conf();
327     my $aliases = $fw_conf->{aliases};
328
329     return ($fw_conf, $aliases);
330 }
331
332 sub save_aliases {
333     my ($class, $param, $fw_conf, $aliases) = @_;
334
335     $fw_conf->{aliases} = $aliases;
336     PVE::Firewall::save_clusterfw_conf($fw_conf);
337 }
338
339 __PACKAGE__->register_handlers();
340
341 package PVE::API2::Firewall::VMAliases;
342
343 use strict;
344 use warnings;
345 use PVE::JSONSchema qw(get_standard_option);
346
347 use base qw(PVE::API2::Firewall::AliasesBase);
348
349 sub rule_env {
350     my ($class, $param) = @_;
351
352     return 'vm';
353 }
354
355 __PACKAGE__->additional_parameters({
356     node => get_standard_option('pve-node'),
357     vmid => get_standard_option('pve-vmid'),
358 });
359
360 sub lock_config {
361     my ($class, $param, $code) = @_;
362
363     PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param);
364 }
365
366 sub load_config {
367     my ($class, $param) = @_;
368
369     my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
370     my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'vm', $param->{vmid});
371     my $aliases = $fw_conf->{aliases};
372
373     return ($fw_conf, $aliases);
374 }
375
376 sub save_aliases {
377     my ($class, $param, $fw_conf, $aliases) = @_;
378
379     $fw_conf->{aliases} = $aliases;
380     PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
381 }
382
383 __PACKAGE__->register_handlers();
384
385 package PVE::API2::Firewall::CTAliases;
386
387 use strict;
388 use warnings;
389 use PVE::JSONSchema qw(get_standard_option);
390
391 use base qw(PVE::API2::Firewall::AliasesBase);
392
393 sub rule_env {
394     my ($class, $param) = @_;
395
396     return 'ct';
397 }
398
399 __PACKAGE__->additional_parameters({
400     node => get_standard_option('pve-node'),
401     vmid => get_standard_option('pve-vmid'),
402 });
403
404 sub lock_config {
405     my ($class, $param, $code) = @_;
406
407     PVE::Firewall::lock_vmfw_conf($param->{vmid}, 10, $code, $param);
408 }
409
410 sub load_config {
411     my ($class, $param) = @_;
412
413     my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
414     my $fw_conf = PVE::Firewall::load_vmfw_conf($cluster_conf, 'ct', $param->{vmid});
415     my $aliases = $fw_conf->{aliases};
416
417     return ($fw_conf, $aliases);
418 }
419
420 sub save_aliases {
421     my ($class, $param, $fw_conf, $aliases) = @_;
422
423     $fw_conf->{aliases} = $aliases;
424     PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
425 }
426
427 __PACKAGE__->register_handlers();
428
429 1;