bump version to 4.1-3
[pve-firewall.git] / src / PVE / API2 / Firewall / Cluster.pm
1 package PVE::API2::Firewall::Cluster;
2
3 use strict;
4 use warnings;
5 use PVE::Exception qw(raise raise_param_exc raise_perm_exc);
6 use PVE::JSONSchema qw(get_standard_option);
7
8 use PVE::Firewall;
9 use PVE::API2::Firewall::Aliases;
10 use PVE::API2::Firewall::Rules;
11 use PVE::API2::Firewall::Groups;
12 use PVE::API2::Firewall::IPSet;
13
14 #fixme: locking?
15
16
17 use base qw(PVE::RESTHandler);
18
19 __PACKAGE__->register_method ({
20     subclass => "PVE::API2::Firewall::Groups",
21     path => 'groups',
22 });
23
24 __PACKAGE__->register_method ({
25     subclass => "PVE::API2::Firewall::ClusterRules",
26     path => 'rules',
27 });
28
29 __PACKAGE__->register_method ({
30     subclass => "PVE::API2::Firewall::ClusterIPSetList",
31     path => 'ipset',
32 });
33
34 __PACKAGE__->register_method ({
35     subclass => "PVE::API2::Firewall::ClusterAliases",
36     path => 'aliases',
37 });
38
39
40 __PACKAGE__->register_method({
41     name => 'index',
42     path => '',
43     method => 'GET',
44     permissions => { user => 'all' },
45     description => "Directory index.",
46     parameters => {
47         additionalProperties => 0,
48     },
49     returns => {
50         type => 'array',
51         items => {
52             type => "object",
53             properties => {},
54         },
55         links => [ { rel => 'child', href => "{name}" } ],
56     },
57     code => sub {
58         my ($param) = @_;
59
60         my $result = [
61             { name => 'aliases' },
62             { name => 'rules' },
63             { name => 'options' },
64             { name => 'groups' },
65             { name => 'ipset' },
66             { name => 'macros' },
67             { name => 'refs' },
68             ];
69
70         return $result;
71     }});
72
73 my $option_properties = $PVE::Firewall::cluster_option_properties;
74
75 my $add_option_properties = sub {
76     my ($properties) = @_;
77
78     foreach my $k (keys %$option_properties) {
79         $properties->{$k} = $option_properties->{$k};
80     }
81
82     return $properties;
83 };
84
85
86 __PACKAGE__->register_method({
87     name => 'get_options',
88     path => 'options',
89     method => 'GET',
90     description => "Get Firewall options.",
91     permissions => {
92         check => ['perm', '/', [ 'Sys.Audit' ]],
93     },
94     parameters => {
95         additionalProperties => 0,
96     },
97     returns => {
98         type => "object",
99         #additionalProperties => 1,
100         properties => $option_properties,
101     },
102     code => sub {
103         my ($param) = @_;
104
105         my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
106
107         return PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
108     }});
109
110
111 __PACKAGE__->register_method({
112     name => 'set_options',
113     path => 'options',
114     method => 'PUT',
115     description => "Set Firewall options.",
116     protected => 1,
117     permissions => {
118         check => ['perm', '/', [ 'Sys.Modify' ]],
119     },
120     parameters => {
121         additionalProperties => 0,
122         properties => &$add_option_properties({
123             delete => {
124                 type => 'string', format => 'pve-configid-list',
125                 description => "A list of settings you want to delete.",
126                 optional => 1,
127             },
128             digest => get_standard_option('pve-config-digest'),
129         }),
130     },
131     returns => { type => "null" },
132     code => sub {
133         my ($param) = @_;
134
135         PVE::Firewall::lock_clusterfw_conf(10, sub {
136             my $cluster_conf = PVE::Firewall::load_clusterfw_conf();
137
138             my (undef, $digest) = PVE::Firewall::copy_opject_with_digest($cluster_conf->{options});
139             PVE::Tools::assert_if_modified($digest, $param->{digest});
140
141             if ($param->{delete}) {
142                 foreach my $opt (PVE::Tools::split_list($param->{delete})) {
143                     raise_param_exc({ delete => "no such option '$opt'" })
144                         if !$option_properties->{$opt};
145                     delete $cluster_conf->{options}->{$opt};
146                 }
147             }
148
149             if (defined($param->{enable}) && ($param->{enable} > 1)) {
150                 $param->{enable} = time();
151             }
152
153             foreach my $k (keys %$option_properties) {
154                 next if !defined($param->{$k});
155                 $cluster_conf->{options}->{$k} = $param->{$k};
156             }
157
158             PVE::Firewall::save_clusterfw_conf($cluster_conf);
159         });
160
161         # instant firewall update when using double (anti-lockout) API call
162         # -> not waiting for a firewall update at the first (timestamp enable) set
163         if (defined($param->{enable}) && ($param->{enable} > 1)) {
164             PVE::Firewall::update();
165         }
166
167         return undef;
168     }});
169
170 __PACKAGE__->register_method({
171     name => 'get_macros',
172     path => 'macros',
173     method => 'GET',
174     description => "List available macros",
175     permissions => { user => 'all' },
176     parameters => {
177         additionalProperties => 0,
178     },
179     returns => {
180         type => 'array',
181         items => {
182             type => "object",
183             properties => {
184                 macro => {
185                     description => "Macro name.",
186                     type => 'string',
187                 },
188                 descr => {
189                     description => "More verbose description (if available).",
190                     type => 'string',
191                 }
192             },
193         },
194     },
195     code => sub {
196         my ($param) = @_;
197
198         my $res = [];
199
200         my ($macros, $descr) = PVE::Firewall::get_macros();
201
202         foreach my $macro (keys %$macros) {
203             push @$res, { macro => $macro, descr => $descr->{$macro} || $macro };
204         }
205
206         return $res;
207     }});
208
209 __PACKAGE__->register_method({
210     name => 'refs',
211     path => 'refs',
212     method => 'GET',
213     description => "Lists possible IPSet/Alias reference which are allowed in source/dest properties.",
214     permissions => {
215         check => ['perm', '/', [ 'Sys.Audit' ]],
216     },
217     parameters => {
218         additionalProperties => 0,
219         properties => {
220             type => {
221                 description => "Only list references of specified type.",
222                 type => 'string',
223                 enum => ['alias', 'ipset'],
224                 optional => 1,
225             },
226         },
227     },
228     returns => {
229         type => 'array',
230         items => {
231             type => "object",
232             properties => {
233                 type => {
234                     type => 'string',
235                     enum => ['alias', 'ipset'],
236                 },
237                 name => {
238                     type => 'string',
239                 },
240                 ref => {
241                     type => 'string',
242                 },
243                 comment => {
244                     type => 'string',
245                     optional => 1,
246                 },
247             },
248         },
249     },
250     code => sub {
251         my ($param) = @_;
252
253         my $conf = PVE::Firewall::load_clusterfw_conf();
254
255         my $res = [];
256
257         if (!$param->{type} || $param->{type} eq 'ipset') {
258             foreach my $name (keys %{$conf->{ipset}}) {
259                 my $data = {
260                     type => 'ipset',
261                     name => $name,
262                     ref => "+$name",
263                 };
264                 if (my $comment = $conf->{ipset_comments}->{$name}) {
265                     $data->{comment} = $comment;
266                 }
267                 push @$res, $data;
268             }
269         }
270
271         if (!$param->{type} || $param->{type} eq 'alias') {
272             foreach my $name (keys %{$conf->{aliases}}) {
273                 my $e = $conf->{aliases}->{$name};
274                 my $data = {
275                     type => 'alias',
276                     name => $name,
277                     ref => $name,
278                 };
279                 $data->{comment} = $e->{comment} if $e->{comment};
280                 push @$res, $data;
281             }
282         }
283
284         return $res;
285     }});
286
287 1;