]> git.proxmox.com Git - pve-firewall.git/blame - src/PVE/API2/Firewall/Rules.pm
improve error handling
[pve-firewall.git] / src / PVE / API2 / Firewall / Rules.pm
CommitLineData
86791289
DM
1package PVE::API2::Firewall::RulesBase;
2
3use strict;
4use warnings;
5use PVE::JSONSchema qw(get_standard_option);
0d22acb3 6use PVE::Exception qw(raise raise_param_exc);
86791289
DM
7
8use PVE::Firewall;
9
10use base qw(PVE::RESTHandler);
11
12my $api_properties = {
86791289
DM
13 pos => {
14 description => "Rule position.",
15 type => 'integer',
16 minimum => 0,
17 },
18};
19
20sub load_config {
21 my ($class, $param) = @_;
22
23 die "implement this in subclass";
24
25 #return ($fw_conf, $rules);
26}
27
28sub save_rules {
29 my ($class, $param, $fw_conf, $rules) = @_;
30
31 die "implement this in subclass";
32}
33
63c91681 34my $additional_param_hash = {};
86791289 35
7ca36671
DM
36sub allow_groups {
37 return 1;
38}
39
63c91681 40sub additional_parameters {
86791289
DM
41 my ($class, $new_value) = @_;
42
63c91681
DM
43 if (defined($new_value)) {
44 $additional_param_hash->{$class} = $new_value;
45 }
86791289 46
63c91681
DM
47 # return a copy
48 my $copy = {};
49 my $org = $additional_param_hash->{$class} || {};
50 foreach my $p (keys %$org) { $copy->{$p} = $org->{$p}; }
51 return $copy;
86791289
DM
52}
53
54sub register_get_rules {
55 my ($class) = @_;
56
63c91681 57 my $properties = $class->additional_parameters();
86791289
DM
58
59 $class->register_method({
60 name => 'get_rules',
61 path => '',
62 method => 'GET',
63 description => "List rules.",
64 parameters => {
65 additionalProperties => 0,
66 properties => $properties,
67 },
68 returns => {
69 type => 'array',
70 items => {
71 type => "object",
72 properties => {
73 pos => {
74 type => 'integer',
75 }
76 },
77 },
78 links => [ { rel => 'child', href => "{pos}" } ],
79 },
80 code => sub {
81 my ($param) = @_;
82
83 my ($fw_conf, $rules) = $class->load_config($param);
84
5d38d64f 85 my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules);
86791289
DM
86
87 my $ind = 0;
5d38d64f
DM
88 foreach my $rule (@$list) {
89 $rule->{pos} = $ind++;
86791289
DM
90 }
91
5d38d64f 92 return $list;
86791289
DM
93 }});
94}
95
96sub register_get_rule {
97 my ($class) = @_;
98
63c91681 99 my $properties = $class->additional_parameters();
86791289
DM
100
101 $properties->{pos} = $api_properties->{pos};
102
86791289
DM
103 $class->register_method({
104 name => 'get_rule',
105 path => '{pos}',
106 method => 'GET',
107 description => "Get single rule data.",
108 parameters => {
109 additionalProperties => 0,
110 properties => $properties,
111 },
112 returns => {
113 type => "object",
114 properties => {
115 pos => {
116 type => 'integer',
117 }
118 },
119 },
120 code => sub {
121 my ($param) = @_;
122
123 my ($fw_conf, $rules) = $class->load_config($param);
124
5d38d64f 125 my ($list, $digest) = PVE::Firewall::copy_list_with_digest($rules);
86791289 126
5d38d64f 127 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$list);
86791289 128
5d38d64f
DM
129 my $rule = $list->[$param->{pos}];
130 $rule->{pos} = $param->{pos};
131
132 return $rule;
86791289
DM
133 }});
134}
135
136sub register_create_rule {
137 my ($class) = @_;
138
63c91681 139 my $properties = $class->additional_parameters();
86791289
DM
140
141 my $create_rule_properties = PVE::Firewall::add_rule_properties($properties);
3655b01f
DM
142 $create_rule_properties->{action}->{optional} = 0;
143 $create_rule_properties->{type}->{optional} = 0;
144
86791289
DM
145 $class->register_method({
146 name => 'create_rule',
147 path => '',
148 method => 'POST',
149 description => "Create new rule.",
150 protected => 1,
151 parameters => {
152 additionalProperties => 0,
153 properties => $create_rule_properties,
154 },
155 returns => { type => "null" },
156 code => sub {
157 my ($param) = @_;
158
159 my ($fw_conf, $rules) = $class->load_config($param);
160
3655b01f 161 my $rule = {};
86791289
DM
162
163 PVE::Firewall::copy_rule_data($rule, $param);
7ca36671 164 PVE::Firewall::verify_rule($rule, $class->allow_groups());
86791289 165
3655b01f
DM
166 $rule->{enable} = 0 if !defined($param->{enable});
167
86791289
DM
168 unshift @$rules, $rule;
169
170 $class->save_rules($param, $fw_conf, $rules);
171
172 return undef;
173 }});
174}
175
176sub register_update_rule {
177 my ($class) = @_;
178
63c91681 179 my $properties = $class->additional_parameters();
86791289
DM
180
181 $properties->{pos} = $api_properties->{pos};
182
86791289
DM
183 $properties->{moveto} = {
184 description => "Move rule to new position <moveto>. Other arguments are ignored.",
185 type => 'integer',
186 minimum => 0,
187 optional => 1,
188 };
189
5b7974df
DM
190 $properties->{delete} = {
191 type => 'string', format => 'pve-configid-list',
192 description => "A list of settings you want to delete.",
193 optional => 1,
194 };
195
86791289
DM
196 my $update_rule_properties = PVE::Firewall::add_rule_properties($properties);
197
198 $class->register_method({
199 name => 'update_rule',
200 path => '{pos}',
201 method => 'PUT',
202 description => "Modify rule data.",
203 protected => 1,
204 parameters => {
205 additionalProperties => 0,
206 properties => $update_rule_properties,
207 },
208 returns => { type => "null" },
209 code => sub {
210 my ($param) = @_;
211
212 my ($fw_conf, $rules) = $class->load_config($param);
213
5d38d64f
DM
214 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
215 PVE::Tools::assert_if_modified($digest, $param->{digest});
ddf1e07d 216
86791289
DM
217 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
218
219 my $rule = $rules->[$param->{pos}];
220
221 my $moveto = $param->{moveto};
222 if (defined($moveto) && $moveto != $param->{pos}) {
223 my $newrules = [];
224 for (my $i = 0; $i < scalar(@$rules); $i++) {
225 next if $i == $param->{pos};
226 if ($i == $moveto) {
227 push @$newrules, $rule;
228 }
229 push @$newrules, $rules->[$i];
230 }
231 push @$newrules, $rule if $moveto >= scalar(@$rules);
232 $rules = $newrules;
233 } else {
234 PVE::Firewall::copy_rule_data($rule, $param);
5b7974df
DM
235
236 PVE::Firewall::delete_rule_properties($rule, $param->{'delete'}) if $param->{'delete'};
7ca36671
DM
237
238 PVE::Firewall::verify_rule($rule, $class->allow_groups());
86791289
DM
239 }
240
241 $class->save_rules($param, $fw_conf, $rules);
242
243 return undef;
244 }});
245}
246
247sub register_delete_rule {
248 my ($class) = @_;
249
63c91681 250 my $properties = $class->additional_parameters();
86791289
DM
251
252 $properties->{pos} = $api_properties->{pos};
ddf1e07d
DM
253
254 $properties->{digest} = get_standard_option('pve-config-digest');
86791289 255
86791289
DM
256 $class->register_method({
257 name => 'delete_rule',
258 path => '{pos}',
259 method => 'DELETE',
260 description => "Delete rule.",
261 protected => 1,
262 parameters => {
263 additionalProperties => 0,
264 properties => $properties,
265 },
266 returns => { type => "null" },
267 code => sub {
268 my ($param) = @_;
269
270 my ($fw_conf, $rules) = $class->load_config($param);
271
5d38d64f
DM
272 my (undef, $digest) = PVE::Firewall::copy_list_with_digest($rules);
273 PVE::Tools::assert_if_modified($digest, $param->{digest});
86791289
DM
274
275 die "no rule at position $param->{pos}\n" if $param->{pos} >= scalar(@$rules);
276
277 splice(@$rules, $param->{pos}, 1);
278
279 $class->save_rules($param, $fw_conf, $rules);
280
281 return undef;
282 }});
283}
284
285sub register_handlers {
286 my ($class) = @_;
287
288 $class->register_get_rules();
289 $class->register_get_rule();
290 $class->register_create_rule();
291 $class->register_update_rule();
292 $class->register_delete_rule();
293}
294
295package PVE::API2::Firewall::GroupRules;
296
297use strict;
298use warnings;
387d0ffc 299use PVE::JSONSchema qw(get_standard_option);
86791289
DM
300
301use base qw(PVE::API2::Firewall::RulesBase);
302
387d0ffc 303__PACKAGE__->additional_parameters({ group => get_standard_option('pve-security-group-name') });
86791289 304
7ca36671
DM
305sub allow_groups {
306 return 0;
307}
308
86791289
DM
309sub load_config {
310 my ($class, $param) = @_;
311
312 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
313 my $rules = $fw_conf->{groups}->{$param->{group}};
314 die "no such security group '$param->{group}'\n" if !defined($rules);
315
316 return ($fw_conf, $rules);
317}
318
319sub save_rules {
320 my ($class, $param, $fw_conf, $rules) = @_;
321
322 $fw_conf->{groups}->{$param->{group}} = $rules;
323 PVE::Firewall::save_clusterfw_conf($fw_conf);
324}
325
63c91681 326__PACKAGE__->register_handlers();
86791289
DM
327
328package PVE::API2::Firewall::ClusterRules;
329
330use strict;
331use warnings;
332
333use base qw(PVE::API2::Firewall::RulesBase);
334
335sub load_config {
336 my ($class, $param) = @_;
337
338 my $fw_conf = PVE::Firewall::load_clusterfw_conf();
339 my $rules = $fw_conf->{rules};
340
341 return ($fw_conf, $rules);
342}
343
344sub save_rules {
345 my ($class, $param, $fw_conf, $rules) = @_;
346
347 $fw_conf->{rules} = $rules;
348 PVE::Firewall::save_clusterfw_conf($fw_conf);
349}
350
63c91681
DM
351__PACKAGE__->register_handlers();
352
353package PVE::API2::Firewall::HostRules;
354
355use strict;
356use warnings;
357use PVE::JSONSchema qw(get_standard_option);
358
359use base qw(PVE::API2::Firewall::RulesBase);
360
361__PACKAGE__->additional_parameters({ node => get_standard_option('pve-node')});
362
363sub load_config {
364 my ($class, $param) = @_;
365
366 my $fw_conf = PVE::Firewall::load_hostfw_conf();
367 my $rules = $fw_conf->{rules};
368
369 return ($fw_conf, $rules);
370}
371
372sub save_rules {
373 my ($class, $param, $fw_conf, $rules) = @_;
374
375 $fw_conf->{rules} = $rules;
376 PVE::Firewall::save_hostfw_conf($fw_conf);
377}
378
379__PACKAGE__->register_handlers();
86791289 380
464f933e
DM
381package PVE::API2::Firewall::VMRules;
382
383use strict;
384use warnings;
385use PVE::JSONSchema qw(get_standard_option);
386
387use base qw(PVE::API2::Firewall::RulesBase);
388
389__PACKAGE__->additional_parameters({
390 node => get_standard_option('pve-node'),
391 vmid => get_standard_option('pve-vmid'),
392});
393
394sub load_config {
395 my ($class, $param) = @_;
396
397 my $fw_conf = PVE::Firewall::load_vmfw_conf($param->{vmid});
398 my $rules = $fw_conf->{rules};
399
400 return ($fw_conf, $rules);
401}
402
403sub save_rules {
404 my ($class, $param, $fw_conf, $rules) = @_;
405
406 $fw_conf->{rules} = $rules;
407 PVE::Firewall::save_vmfw_conf($param->{vmid}, $fw_conf);
408}
409
410__PACKAGE__->register_handlers();
411
86791289 4121;