]> git.proxmox.com Git - pve-cluster.git/blame - data/PVE/DataCenterConfig.pm
parse datacenter config: remove "\s*" from comment regex
[pve-cluster.git] / data / PVE / DataCenterConfig.pm
CommitLineData
ab966729
FG
1package PVE::DataCenterConfig;
2
3use strict;
4use warnings;
5
51866274 6use PVE::JSONSchema qw(parse_property_string);
ab966729
FG
7use PVE::Tools;
8use PVE::Cluster;
9
10my $migration_format = {
11 type => {
12 default_key => 1,
13 type => 'string',
14 enum => ['secure', 'insecure'],
15 description => "Migration traffic is encrypted using an SSH tunnel by " .
16 "default. On secure, completely private networks this can be " .
17 "disabled to increase performance.",
18 default => 'secure',
19 },
20 network => {
21 optional => 1,
22 type => 'string', format => 'CIDR',
23 format_description => 'CIDR',
24 description => "CIDR of the (sub) network that is used for migration."
25 },
26};
27
28my $ha_format = {
29 shutdown_policy => {
30 type => 'string',
28c22b8d
TL
31 enum => ['freeze', 'failover', 'conditional', 'migrate'],
32 description => "The policy for HA services on node shutdown. 'freeze' disables ".
33 "auto-recovery, 'failover' ensures recovery, 'conditional' recovers on ".
34 "poweroff and freezes on reboot. 'migrate' will migrate running services ".
35 "to other nodes, if possible. With 'freeze' or 'failover', HA Services will ".
36 "always get stopped first on shutdown.",
37 verbose_description => "Describes the policy for handling HA services on poweroff ".
38 "or reboot of a node. Freeze will always freeze services which are still located ".
39 "on the node on shutdown, those services won't be recovered by the HA manager. ".
40 "Failover will not mark the services as frozen and thus the services will get ".
41 "recovered to other nodes, if the shutdown node does not come up again quickly ".
42 "(< 1min). 'conditional' chooses automatically depending on the type of shutdown, ".
43 "i.e., on a reboot the service will be frozen but on a poweroff the service will ".
1818509b 44 "stay as is, and thus get recovered after about 2 minutes. ".
dc43b8a4
TL
45 "Migrate will try to move all running services to another node when a reboot or ".
46 "shutdown was triggered. The poweroff process will only continue once no running services ".
1818509b
TL
47 "are located on the node anymore. If the node comes up again, the service will ".
48 "be moved back to the previously powered-off node, at least if no other migration, ".
49 "reloaction or recovery took place.",
ab966729
FG
50 default => 'conditional',
51 }
52};
53
75e5d02e
TL
54my $next_id_format = {
55 lower => {
56 type => 'integer',
57 description => "Lower, inclusive boundary for free next-id API range.",
58 min => 100,
59 max => 1000 * 1000 * 1000 - 1,
60 default => 100,
61 optional => 1,
62 },
63 upper => {
64 type => 'integer',
65 description => "Upper, inclusive boundary for free next-id API range.",
66 min => 100,
67 max => 1000 * 1000 * 1000 - 1,
68 default => 1000 * 1000, # lower than the maximum on purpose
69 optional => 1,
70 },
71};
72
bcfa5ac1 73my $u2f_format = {
ab966729
FG
74 appid => {
75 type => 'string',
76 description => "U2F AppId URL override. Defaults to the origin.",
77 format_description => 'APPID',
78 optional => 1,
79 },
80 origin => {
81 type => 'string',
82 description => "U2F Origin override. Mostly useful for single nodes with a single URL.",
83 format_description => 'URL',
84 optional => 1,
85 },
86};
87
8545a705
WB
88my $webauthn_format = {
89 rp => {
90 type => 'string',
91 description =>
92 'Relying party name. Any text identifier.'
93 .' Changing this *may* break existing credentials.',
94 format_description => 'RELYING_PARTY',
95 optional => 1,
96 },
97 origin => {
98 type => 'string',
99 description =>
100 'Site origin. Must be a `https://` URL (or `http://localhost`).'
101 .' Should contain the address users type in their browsers to access'
102 .' the web interface.'
103 .' Changing this *may* break existing credentials.',
104 format_description => 'URL',
105 optional => 1,
106 },
107 id => {
108 type => 'string',
109 description =>
110 'Relying part ID. Must be the domain name without protocol, port or location.'
111 .' Changing this *will* break existing credentials.',
112 format_description => 'DOMAINNAME',
113 optional => 1,
114 },
115};
ab966729
FG
116
117PVE::JSONSchema::register_format('mac-prefix', \&pve_verify_mac_prefix);
118sub pve_verify_mac_prefix {
119 my ($mac_prefix, $noerr) = @_;
120
121 if ($mac_prefix !~ m/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i) {
122 return undef if $noerr;
123 die "value is not a valid unicast MAC address prefix\n";
124 }
125 return $mac_prefix;
126}
127
128my $datacenter_schema = {
129 type => "object",
130 additionalProperties => 0,
131 properties => {
132 keyboard => {
133 optional => 1,
134 type => 'string',
135 description => "Default keybord layout for vnc server.",
136 enum => PVE::Tools::kvmkeymaplist(),
137 },
138 language => {
139 optional => 1,
140 type => 'string',
141 description => "Default GUI language.",
142 enum => [
143 'ca',
144 'da',
145 'de',
146 'en',
147 'es',
148 'eu',
149 'fa',
150 'fr',
151 'he',
152 'it',
153 'ja',
154 'nb',
155 'nn',
156 'pl',
157 'pt_BR',
158 'ru',
159 'sl',
160 'sv',
161 'tr',
162 'zh_CN',
163 'zh_TW',
164 ],
165 },
166 http_proxy => {
167 optional => 1,
168 type => 'string',
169 description => "Specify external http proxy which is used for downloads (example: 'http://username:password\@host:port/')",
170 pattern => "http://.*",
171 },
0cc6e737 172 # FIXME: remove with 8.0 (add check to pve7to8!), merged into "migration" since 4.3
ab966729
FG
173 migration_unsecure => {
174 optional => 1,
175 type => 'boolean',
176 description => "Migration is secure using SSH tunnel by default. " .
177 "For secure private networks you can disable it to speed up " .
178 "migration. Deprecated, use the 'migration' property instead!",
179 },
75e5d02e
TL
180 'next-id' => {
181 optional => 1,
182 type => 'string',
183 format => $next_id_format,
184 description => "Control the range for the free VMID auto-selection pool.",
185 },
ab966729
FG
186 migration => {
187 optional => 1,
188 type => 'string', format => $migration_format,
189 description => "For cluster wide migration settings.",
190 },
191 console => {
192 optional => 1,
193 type => 'string',
0cc6e737
TL
194 description => "Select the default Console viewer. You can either use the builtin java"
195 ." applet (VNC; deprecated and maps to html5), an external virt-viewer comtatible application (SPICE), an HTML5 based vnc viewer (noVNC), or an HTML5 based console client (xtermjs). If the selected viewer is not available (e.g. SPICE not activated for the VM), the fallback is noVNC.",
196 # FIXME: remove 'applet' with 8.0 (add pve7to8 check!)
ab966729
FG
197 enum => ['applet', 'vv', 'html5', 'xtermjs'],
198 },
199 email_from => {
200 optional => 1,
201 type => 'string',
202 format => 'email-opt',
203 description => "Specify email address to send notification from (default is root@\$hostname)",
204 },
205 max_workers => {
206 optional => 1,
207 type => 'integer',
208 minimum => 1,
209 description => "Defines how many workers (per node) are maximal started ".
210 " on actions like 'stopall VMs' or task from the ha-manager.",
211 },
212 fencing => {
213 optional => 1,
214 type => 'string',
215 default => 'watchdog',
216 enum => [ 'watchdog', 'hardware', 'both' ],
217 description => "Set the fencing mode of the HA cluster. Hardware mode " .
218 "needs a valid configuration of fence devices in /etc/pve/ha/fence.cfg." .
219 " With both all two modes are used." .
220 "\n\nWARNING: 'hardware' and 'both' are EXPERIMENTAL & WIP",
221 },
222 ha => {
223 optional => 1,
224 type => 'string', format => $ha_format,
225 description => "Cluster wide HA settings.",
226 },
227 mac_prefix => {
228 optional => 1,
229 type => 'string',
230 format => 'mac-prefix',
231 description => 'Prefix for autogenerated MAC addresses.',
232 },
233 bwlimit => PVE::JSONSchema::get_standard_option('bwlimit'),
234 u2f => {
235 optional => 1,
236 type => 'string',
237 format => $u2f_format,
238 description => 'u2f',
239 },
8545a705
WB
240 webauthn => {
241 optional => 1,
242 type => 'string',
243 format => $webauthn_format,
244 description => 'webauthn configuration',
245 },
2ae1c0bb
DJ
246 description => {
247 type => 'string',
248 description => "Datacenter description. Shown in the web-interface datacenter notes panel."
249 ." This is saved as comment inside the configuration file.",
250 maxLength => 64 * 1024,
251 optional => 1,
252 },
ab966729
FG
253 },
254};
255
256# make schema accessible from outside (for documentation)
257sub get_datacenter_schema { return $datacenter_schema };
258
259sub parse_datacenter_config {
260 my ($filename, $raw) = @_;
261
b5e2b244
TL
262 $raw = '' if !defined($raw);
263
2ae1c0bb
DJ
264 # description may be comment or key-value pair (or both)
265 my $comment = '';
459f6084 266 for my $line (split(/\n/, $raw)) {
09b99550 267 if ($line =~ /^\#(.*)$/) {
2ae1c0bb
DJ
268 $comment .= PVE::Tools::decode_text($1) . "\n";
269 }
270 }
271
272 # parse_config ignores lines with # => use $raw
b5e2b244 273 my $res = PVE::JSONSchema::parse_config($datacenter_schema, $filename, $raw);
ab966729 274
2ae1c0bb
DJ
275 $res->{description} = $comment;
276
ab966729 277 if (my $migration = $res->{migration}) {
51866274 278 $res->{migration} = parse_property_string($migration_format, $migration);
ab966729
FG
279 }
280
75e5d02e
TL
281 if (my $next_id = $res->{'next-id'}) {
282 $res->{'next-id'} = parse_property_string($next_id_format, $next_id);
283 }
284
ab966729 285 if (my $ha = $res->{ha}) {
51866274 286 $res->{ha} = parse_property_string($ha_format, $ha);
ab966729
FG
287 }
288
bcfa5ac1 289 if (my $u2f = $res->{u2f}) {
51866274 290 $res->{u2f} = parse_property_string($u2f_format, $u2f);
bcfa5ac1
FG
291 }
292
8545a705 293 if (my $webauthn = $res->{webauthn}) {
51866274 294 $res->{webauthn} = parse_property_string($webauthn_format, $webauthn);
8545a705
WB
295 }
296
ab966729
FG
297 # for backwards compatibility only, new migration property has precedence
298 if (defined($res->{migration_unsecure})) {
299 if (defined($res->{migration}->{type})) {
300 warn "deprecated setting 'migration_unsecure' and new 'migration: type' " .
301 "set at same time! Ignore 'migration_unsecure'\n";
302 } else {
303 $res->{migration}->{type} = ($res->{migration_unsecure}) ? 'insecure' : 'secure';
304 }
305 }
306
307 # for backwards compatibility only, applet maps to html5
308 if (defined($res->{console}) && $res->{console} eq 'applet') {
309 $res->{console} = 'html5';
310 }
311
312 return $res;
313}
314
315sub write_datacenter_config {
316 my ($filename, $cfg) = @_;
317
318 # map deprecated setting to new one
319 if (defined($cfg->{migration_unsecure}) && !defined($cfg->{migration})) {
320 my $migration_unsecure = delete $cfg->{migration_unsecure};
321 $cfg->{migration}->{type} = ($migration_unsecure) ? 'insecure' : 'secure';
322 }
323
324 # map deprecated applet setting to html5
325 if (defined($cfg->{console}) && $cfg->{console} eq 'applet') {
326 $cfg->{console} = 'html5';
327 }
328
5b576e26 329 if (ref(my $migration = $cfg->{migration})) {
ab966729
FG
330 $cfg->{migration} = PVE::JSONSchema::print_property_string($migration, $migration_format);
331 }
332
75e5d02e
TL
333 if (defined(my $next_id = $cfg->{'next-id'})) {
334 $next_id = parse_property_string($next_id_format, $next_id) if !ref($next_id);
335
336 my $lower = int($next_id->{lower} // $next_id_format->{lower}->{default});
337 my $upper = int($next_id->{upper} // $next_id_format->{upper}->{default});
338
339 die "lower ($lower) <= upper ($upper) boundary rule broken" if $lower > $upper;
340
341 $cfg->{'next-id'} = PVE::JSONSchema::print_property_string($next_id, $next_id_format);
342 }
343
5b576e26 344 if (ref(my $ha = $cfg->{ha})) {
ab966729
FG
345 $cfg->{ha} = PVE::JSONSchema::print_property_string($ha, $ha_format);
346 }
347
5b576e26 348 if (ref(my $u2f = $cfg->{u2f})) {
bcfa5ac1
FG
349 $cfg->{u2f} = PVE::JSONSchema::print_property_string($u2f, $u2f_format);
350 }
351
5b576e26 352 if (ref(my $webauthn = $cfg->{webauthn})) {
8545a705
WB
353 $cfg->{webauthn} = PVE::JSONSchema::print_property_string($webauthn, $webauthn_format);
354 }
355
2ae1c0bb
DJ
356 my $comment = '';
357 # add description as comment to top of file
358 my $description = $cfg->{description} || '';
359 foreach my $line (split(/\n/, $description)) {
360 $comment .= '#' . PVE::Tools::encode_text($line) . "\n";
361 }
362 delete $cfg->{description}; # add only as comment, no additional key-value pair
363 my $dump = PVE::JSONSchema::dump_config($datacenter_schema, $filename, $cfg);
364
365 return $comment . "\n" . $dump;
ab966729
FG
366}
367
02ce710f
TL
368PVE::Cluster::cfs_register_file(
369 'datacenter.cfg',
370 \&parse_datacenter_config,
371 \&write_datacenter_config,
372);
ab966729
FG
373
3741;