]> git.proxmox.com Git - pmg-api.git/blob - src/PMG/API2/Config.pm
Add API2 module for PBS configuration
[pmg-api.git] / src / PMG / API2 / Config.pm
1 package PMG::API2::Config;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6
7 use PVE::SafeSyslog;
8 use PVE::Tools qw(extract_param);
9 use HTTP::Status qw(:constants);
10 use Storable qw(dclone);
11 use PVE::JSONSchema qw(get_standard_option);
12 use PVE::RESTHandler;
13 use Time::HiRes qw();
14
15 use PMG::Config;
16 use PMG::API2::RuleDB;
17 use PMG::API2::LDAP;
18 use PMG::API2::Domains;
19 use PMG::API2::Transport;
20 use PMG::API2::Cluster;
21 use PMG::API2::MyNetworks;
22 use PMG::API2::SMTPWhitelist;
23 use PMG::API2::MimeTypes;
24 use PMG::API2::Fetchmail;
25 use PMG::API2::DestinationTLSPolicy;
26 use PMG::API2::DKIMSign;
27 use PMG::API2::SACustom;
28 use PMG::API2::PBS::Remote;
29
30 use base qw(PVE::RESTHandler);
31
32 my $section_type_enum = PMG::Config::Base->lookup_types();
33
34 __PACKAGE__->register_method ({
35 subclass => "PMG::API2::RuleDB",
36 path => 'ruledb',
37 });
38
39 __PACKAGE__->register_method ({
40 subclass => "PMG::API2::SMTPWhitelist",
41 path => 'whitelist',
42 });
43
44 __PACKAGE__->register_method ({
45 subclass => "PMG::API2::LDAP",
46 path => 'ldap',
47 });
48
49 __PACKAGE__->register_method ({
50 subclass => "PMG::API2::Domains",
51 path => 'domains',
52 });
53
54 __PACKAGE__->register_method ({
55 subclass => "PMG::API2::Fetchmail",
56 path => 'fetchmail',
57 });
58
59 __PACKAGE__->register_method ({
60 subclass => "PMG::API2::Transport",
61 path => 'transport',
62 });
63
64 __PACKAGE__->register_method ({
65 subclass => "PMG::API2::MyNetworks",
66 # set fragment delimiter (no subdirs) - we need that, because CIDRs
67 # contain a slash '/'
68 fragmentDelimiter => '',
69 path => 'mynetworks',
70 });
71
72 __PACKAGE__->register_method ({
73 subclass => "PMG::API2::Cluster",
74 path => 'cluster',
75 });
76
77 __PACKAGE__->register_method ({
78 subclass => "PMG::API2::MimeTypes",
79 path => 'mimetypes',
80 });
81
82 __PACKAGE__->register_method ({
83 subclass => "PMG::API2::DestinationTLSPolicy",
84 path => 'tlspolicy',
85 });
86
87 __PACKAGE__->register_method({
88 subclass => "PMG::API2::DKIMSign",
89 path => 'dkim',
90 });
91
92 __PACKAGE__->register_method({
93 subclass => "PMG::API2::SACustom",
94 path => 'customscores',
95 });
96
97 __PACKAGE__->register_method ({
98 subclass => "PMG::API2::PBS::Remote",
99 path => 'pbs',
100 });
101
102 __PACKAGE__->register_method ({
103 name => 'index',
104 path => '',
105 method => 'GET',
106 description => "Directory index.",
107 parameters => {
108 additionalProperties => 0,
109 properties => {},
110 },
111 returns => {
112 type => 'array',
113 items => {
114 type => "object",
115 properties => { section => { type => 'string'} },
116 },
117 links => [ { rel => 'child', href => "{section}" } ],
118 },
119 code => sub {
120 my ($param) = @_;
121
122 my $res = [];
123 foreach my $section (@$section_type_enum) {
124 push @$res, { section => $section };
125 }
126
127 push @$res, { section => 'ldap' };
128 push @$res, { section => 'mynetworks' };
129 push @$res, { section => 'mimetypes' };
130 push @$res, { section => 'users' };
131 push @$res, { section => 'domains' };
132 push @$res, { section => 'fetchmail' };
133 push @$res, { section => 'cluster' };
134 push @$res, { section => 'ruledb' };
135 push @$res, { section => 'transport' };
136 push @$res, { section => 'whitelist' };
137 push @$res, { section => 'regextest' };
138 push @$res, { section => 'tlspolicy' };
139 push @$res, { section => 'dkim' };
140 push @$res, { section => 'pbs' };
141
142 return $res;
143 }});
144
145 my $api_read_config_section = sub {
146 my ($section) = @_;
147
148 my $cfg = PMG::Config->new();
149
150 my $data = dclone($cfg->{ids}->{$section} // {});
151 $data->{digest} = $cfg->{digest};
152 delete $data->{type};
153
154 return $data;
155 };
156
157 my $api_update_config_section = sub {
158 my ($section, $param) = @_;
159
160 my $code = sub {
161 my $cfg = PMG::Config->new();
162 my $ids = $cfg->{ids};
163
164 my $digest = extract_param($param, 'digest');
165 PVE::SectionConfig::assert_if_modified($cfg, $digest);
166
167 my $delete_str = extract_param($param, 'delete');
168 die "no options specified\n"
169 if !$delete_str && !scalar(keys %$param);
170
171 foreach my $opt (PVE::Tools::split_list($delete_str)) {
172 delete $ids->{$section}->{$opt};
173 }
174
175 my $plugin = PMG::Config::Base->lookup($section);
176 my $config = $plugin->check_config($section, $param, 0, 1);
177
178 foreach my $p (keys %$config) {
179 $ids->{$section}->{$p} = $config->{$p};
180 }
181
182 $cfg->write();
183
184 $cfg->rewrite_config(undef, 1);
185 };
186
187 PMG::Config::lock_config($code, "update config section '$section' failed");
188 };
189
190 foreach my $section (@$section_type_enum) {
191
192 my $plugin = PMG::Config::Base->lookup($section);
193
194 __PACKAGE__->register_method ({
195 name => "read_${section}_section",
196 path => $section,
197 method => 'GET',
198 proxyto => 'master',
199 permissions => { check => [ 'admin', 'audit' ] },
200 description => "Read $section configuration properties.",
201 parameters => {
202 additionalProperties => 0,
203 properties => {},
204 },
205 returns => { type => 'object' },
206 code => sub {
207 my ($param) = @_;
208
209 return $api_read_config_section->($section);
210 }});
211
212 __PACKAGE__->register_method ({
213 name => "update_${section}_section",
214 path => $section,
215 method => 'PUT',
216 proxyto => 'master',
217 protected => 1,
218 permissions => { check => [ 'admin' ] },
219 description => "Update $section configuration properties.",
220 parameters => $plugin->updateSchema(1),
221 returns => { type => 'null' },
222 code => sub {
223 my ($param) = @_;
224
225 $api_update_config_section->($section, $param);
226
227 return undef;
228 }});
229 }
230
231 __PACKAGE__->register_method({
232 name => 'regextest',
233 path => 'regextest',
234 method => 'POST',
235 protected => 0,
236 permissions => { check => [ 'admin', 'qmanager', 'audit' ] },
237 description => "Test Regex ignoring case",
238 parameters => {
239 additionalProperties => 0,
240 properties => {
241 regex => {
242 type => 'string',
243 description => 'The Regex to test',
244 maxLength => 1024,
245 },
246 text => {
247 type => 'string',
248 description => 'The String to test',
249 maxLength => 1024,
250 }
251 },
252 },
253 returns => {
254 type => 'number',
255 },
256 code => sub {
257 my ($param) = @_;
258
259 my $text = $param->{text};
260 my $regex = $param->{regex};
261
262 my $regex_check = sub {
263 my $start_time = [Time::HiRes::gettimeofday];
264 my $match = 0;
265 if ($text =~ /$regex/i) {
266 $match = 1;
267 }
268 my $elapsed = Time::HiRes::tv_interval($start_time) * 1000;
269 die "The Regular Expression '$regex' did not match the text '$text' (elapsed time: $elapsed ms)\n"
270 if !$match;
271 return $elapsed;
272 };
273
274 my $elapsed = PVE::Tools::run_fork_with_timeout(2, $regex_check);
275 if ($elapsed eq '') {
276 die "The Regular Expression timed out\n";
277 }
278
279 return $elapsed;
280 }});
281
282 1;