]>
git.proxmox.com Git - pve-cluster.git/blob - data/PVE/DataCenterConfig.pm
1 package PVE
:: DataCenterConfig
;
6 use PVE
:: JSONSchema
qw(parse_property_string) ;
13 enum
=> [ 'basic' , 'static' ],
16 description
=> "Use this resource scheduler mode for HA." ,
17 verbose_description
=> "Configures how the HA manager should select nodes to start or " .
18 "recover services. With 'basic', only the number of services is used, with 'static', " .
19 "static CPU and memory configuration of services is considered." ,
23 my $migration_format = {
27 enum
=> [ 'secure' , 'insecure' ],
28 description
=> "Migration traffic is encrypted using an SSH tunnel by " .
29 "default. On secure, completely private networks this can be " .
30 "disabled to increase performance." ,
35 type
=> 'string' , format
=> 'CIDR' ,
36 format_description
=> 'CIDR' ,
37 description
=> "CIDR of the (sub) network that is used for migration."
41 my $notification_format = {
42 'package-updates' => {
44 enum
=> [ 'auto' , 'always' , 'never' ],
45 description
=> "Control when the daily update job should send out notification mails." ,
46 verbose_description
=> "Control how often the daily update job should send out notification mails: \n "
47 . "* 'auto' daily for systems with a valid subscription, as those are assumed to be "
48 . " production-ready and thus should know about pending updates. \n "
49 . "* 'always' every update, if there are new pending updates. \n "
50 . "* 'never' never send a notification for new pending updates. \n " ,
58 enum
=> [ 'freeze' , 'failover' , 'conditional' , 'migrate' ],
59 description
=> "The policy for HA services on node shutdown. 'freeze' disables " .
60 "auto-recovery, 'failover' ensures recovery, 'conditional' recovers on " .
61 "poweroff and freezes on reboot. 'migrate' will migrate running services " .
62 "to other nodes, if possible. With 'freeze' or 'failover', HA Services will " .
63 "always get stopped first on shutdown." ,
64 verbose_description
=> "Describes the policy for handling HA services on poweroff " .
65 "or reboot of a node. Freeze will always freeze services which are still located " .
66 "on the node on shutdown, those services won't be recovered by the HA manager. " .
67 "Failover will not mark the services as frozen and thus the services will get " .
68 "recovered to other nodes, if the shutdown node does not come up again quickly " .
69 "(< 1min). 'conditional' chooses automatically depending on the type of shutdown, " .
70 "i.e., on a reboot the service will be frozen but on a poweroff the service will " .
71 "stay as is, and thus get recovered after about 2 minutes. " .
72 "Migrate will try to move all running services to another node when a reboot or " .
73 "shutdown was triggered. The poweroff process will only continue once no running services " .
74 "are located on the node anymore. If the node comes up again, the service will " .
75 "be moved back to the previously powered-off node, at least if no other migration, " .
76 "reloaction or recovery took place." ,
77 default => 'conditional' ,
81 my $next_id_format = {
84 description
=> "Lower, inclusive boundary for free next-id API range." ,
86 max
=> 1000 * 1000 * 1000 - 1 ,
92 description
=> "Upper, exclusive boundary for free next-id API range." ,
94 max
=> 1000 * 1000 * 1000 ,
95 default => 1000 * 1000 , # lower than the maximum on purpose
103 description
=> "U2F AppId URL override. Defaults to the origin." ,
104 format_description
=> 'APPID' ,
109 description
=> "U2F Origin override. Mostly useful for single nodes with a single URL." ,
110 format_description
=> 'URL' ,
115 my $webauthn_format = {
119 'Relying party name. Any text identifier.'
120 . ' Changing this *may* break existing credentials.' ,
121 format_description
=> 'RELYING_PARTY' ,
127 'Site origin. Must be a `https://` URL (or `http://localhost`).'
128 . ' Should contain the address users type in their browsers to access'
129 . ' the web interface.'
130 . ' Changing this *may* break existing credentials.' ,
131 format_description
=> 'URL' ,
137 'Relying party ID. Must be the domain name without protocol, port or location.'
138 . ' Changing this *will* break existing credentials.' ,
139 format_description
=> 'DOMAINNAME' ,
142 'allow-subdomains' => {
144 description
=> 'Whether to allow the origin to be a subdomain, rather than the exact URL.' ,
150 PVE
:: JSONSchema
:: register_format
( 'mac-prefix' , \
& pve_verify_mac_prefix
);
151 sub pve_verify_mac_prefix
{
152 my ( $mac_prefix, $noerr ) = @_ ;
154 if ( $mac_prefix !~ m/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i ) {
155 return undef if $noerr ;
156 die "value is not a valid unicast MAC address prefix \n " ;
161 my $COLOR_RE = '[0-9a-fA-F]{6}' ;
162 my $TAG_COLOR_OVERRIDE_RE = "(?:${PVE::JSONSchema::PVE_TAG_RE}:${COLOR_RE}(?:\:${COLOR_RE})?)" ;
164 my $tag_style_format = {
168 enum
=> [ 'full' , 'circle' , 'dense' , 'none' ],
170 description
=> "Tag shape for the web ui tree. 'full' draws the full tag. "
171 . "'circle' draws only a circle with the background color. "
172 . "'dense' only draws a small rectancle (useful when many tags are assigned to each guest)."
173 . "'none' disables showing the tags." ,
178 pattern
=> "${TAG_COLOR_OVERRIDE_RE}(?:\; $TAG_COLOR_OVERRIDE_RE )*" ,
179 typetext
=> '<tag>:<hex-color>[:<hex-color-for-text>][;<tag>=...]' ,
180 description
=> "Manual color mapping for tags (semicolon separated)." ,
185 enum
=> [ 'config' , 'alphabetical' ],
186 default => 'alphabetical' ,
187 description
=> 'Controls the sorting of the tags in the web-interface and the API update.' ,
189 'case-sensitive' => {
191 description
=> 'Controls if filtering for unique tags on update should check case-sensitive.' ,
197 my $user_tag_privs_format = {
201 enum
=> [ 'none' , 'list' , 'existing' , 'free' ],
203 description
=> "Controls tag usage for users without `Sys.Modify` on `/` by either "
204 . "allowing `none`, a `list`, already `existing` or anything (`free`)." ,
205 verbose_description
=> "Controls which tags can be set or deleted on resources a user "
206 . "controls (such as guests). Users with the `Sys.Modify` privilege on `/` are always "
208 . "* 'none' no tags are usable. "
209 . "* 'list' tags from 'user-allow-list' are usable. "
210 . "* 'existing' like list, but already existing tags of resources are also usable."
211 . "* 'free' no tag restrictions." ,
213 'user-allow-list' => {
216 pattern
=> "${PVE::JSONSchema::PVE_TAG_RE}(?:\;${PVE::JSONSchema::PVE_TAG_RE})*" ,
217 typetext
=> "<tag>[;<tag>...]" ,
218 description
=> "List of tags users are allowed to set and delete (semicolon separated) "
219 . "for 'user-allow' values 'list' and 'existing'." ,
223 my $datacenter_schema = {
225 additionalProperties
=> 0 ,
229 type
=> 'string' , format
=> $crs_format,
230 description
=> "Cluster resource scheduling settings." ,
235 description
=> "Default keybord layout for vnc server." ,
236 enum
=> PVE
:: Tools
:: kvmkeymaplist
(),
241 description
=> "Default GUI language." ,
269 description
=> "Specify external http proxy which is used for downloads (example: 'http://username:password\ @host :port/')" ,
270 pattern
=> "http://.*" ,
272 # FIXME: remove with 8.0 (add check to pve7to8!), merged into "migration" since 4.3
273 migration_unsecure
=> {
276 description
=> "Migration is secure using SSH tunnel by default. " .
277 "For secure private networks you can disable it to speed up " .
278 "migration. Deprecated, use the 'migration' property instead!" ,
283 format
=> $next_id_format,
284 description
=> "Control the range for the free VMID auto-selection pool." ,
288 type
=> 'string' , format
=> $migration_format,
289 description
=> "For cluster wide migration settings." ,
294 description
=> "Select the default Console viewer. You can either use the builtin java"
295 . " 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." ,
296 # FIXME: remove 'applet' with 8.0 (add pve7to8 check!)
297 enum
=> [ 'applet' , 'vv' , 'html5' , 'xtermjs' ],
302 format
=> 'email-opt' ,
303 description
=> "Specify email address to send notification from (default is root @\$hostname )" ,
309 description
=> "Defines how many workers (per node) are maximal started " .
310 " on actions like 'stopall VMs' or task from the ha-manager." ,
315 default => 'watchdog' ,
316 enum
=> [ 'watchdog' , 'hardware' , 'both' ],
317 description
=> "Set the fencing mode of the HA cluster. Hardware mode " .
318 "needs a valid configuration of fence devices in /etc/pve/ha/fence.cfg." .
319 " With both all two modes are used." .
320 " \n\n WARNING: 'hardware' and 'both' are EXPERIMENTAL & WIP" ,
324 type
=> 'string' , format
=> $ha_format,
325 description
=> "Cluster wide HA settings." ,
330 format
=> 'mac-prefix' ,
331 description
=> 'Prefix for autogenerated MAC addresses.' ,
335 type
=> 'string' , format
=> $notification_format,
336 description
=> "Cluster-wide notification settings." ,
338 bwlimit
=> PVE
:: JSONSchema
:: get_standard_option
( 'bwlimit' ),
342 format
=> $u2f_format,
343 description
=> 'u2f' ,
348 format
=> $webauthn_format,
349 description
=> 'webauthn configuration' ,
353 description
=> "Datacenter description. Shown in the web-interface datacenter notes panel."
354 . " This is saved as comment inside the configuration file." ,
355 maxLength
=> 64 * 1024 ,
361 description
=> "Tag style options." ,
362 format
=> $tag_style_format,
364 'user-tag-access' => {
367 description
=> "Privilege options for user-settable tags" ,
368 format
=> $user_tag_privs_format,
370 'registered-tags' => {
373 description
=> "A list of tags that require a `Sys.Modify` on '/' to set and delete. "
374 . "Tags set here that are also in 'user-tag-access' also require `Sys.Modify`." ,
375 pattern
=> "(?:${PVE::JSONSchema::PVE_TAG_RE};)*${PVE::JSONSchema::PVE_TAG_RE}" ,
376 typetext
=> "<tag>[;<tag>...]" ,
381 # make schema accessible from outside (for documentation)
382 sub get_datacenter_schema
{ return $datacenter_schema };
384 sub parse_datacenter_config
{
385 my ( $filename, $raw ) = @_ ;
387 $raw = '' if ! defined ( $raw );
389 # description may be comment or key-value pair (or both)
391 for my $line ( split ( /\n/ , $raw )) {
392 if ( $line =~ /^\#(.*)$/ ) {
393 $comment .= PVE
:: Tools
:: decode_text
( $1 ) . " \n " ;
397 # parse_config ignores lines with # => use $raw
398 my $res = PVE
:: JSONSchema
:: parse_config
( $datacenter_schema, $filename, $raw );
400 $res ->{ description
} = $comment ;
402 if ( my $crs = $res ->{ crs
}) {
403 $res ->{ crs
} = parse_property_string
( $crs_format, $crs );
406 if ( my $migration = $res ->{ migration
}) {
407 $res ->{ migration
} = parse_property_string
( $migration_format, $migration );
410 if ( my $next_id = $res ->{ 'next-id' }) {
411 $res ->{ 'next-id' } = parse_property_string
( $next_id_format, $next_id );
414 if ( my $ha = $res ->{ ha
}) {
415 $res ->{ ha
} = parse_property_string
( $ha_format, $ha );
417 if ( my $notify = $res ->{ notify
}) {
418 $res ->{ notify
} = parse_property_string
( $notification_format, $notify );
421 if ( my $u2f = $res ->{ u2f
}) {
422 $res ->{ u2f
} = parse_property_string
( $u2f_format, $u2f );
425 if ( my $webauthn = $res ->{ webauthn
}) {
426 $res ->{ webauthn
} = parse_property_string
( $webauthn_format, $webauthn );
429 if ( my $tag_style = $res ->{ 'tag-style' }) {
430 $res ->{ 'tag-style' } = parse_property_string
( $tag_style_format, $tag_style );
433 if ( my $user_tag_privs = $res ->{ 'user-tag-access' }) {
434 $res ->{ 'user-tag-access' } =
435 parse_property_string
( $user_tag_privs_format, $user_tag_privs );
437 if ( my $user_tags = $res ->{ 'user-tag-access' }->{ 'user-allow-list' }) {
438 $res ->{ 'user-tag-access' }->{ 'user-allow-list' } = [ split ( ';' , $user_tags )];
442 if ( my $admin_tags = $res ->{ 'registered-tags' }) {
443 $res ->{ 'registered-tags' } = [ split ( ';' , $admin_tags )];
446 # for backwards compatibility only, new migration property has precedence
447 if ( defined ( $res ->{ migration_unsecure
})) {
448 if ( defined ( $res ->{ migration
}->{ type
})) {
449 warn "deprecated setting 'migration_unsecure' and new 'migration: type' " .
450 "set at same time! Ignore 'migration_unsecure' \n " ;
452 $res ->{ migration
}->{ type
} = ( $res ->{ migration_unsecure
}) ?
'insecure' : 'secure' ;
456 # for backwards compatibility only, applet maps to html5
457 if ( defined ( $res ->{ console
}) && $res ->{ console
} eq 'applet' ) {
458 $res ->{ console
} = 'html5' ;
464 sub write_datacenter_config
{
465 my ( $filename, $cfg ) = @_ ;
467 # map deprecated setting to new one
468 if ( defined ( $cfg ->{ migration_unsecure
}) && ! defined ( $cfg ->{ migration
})) {
469 my $migration_unsecure = delete $cfg ->{ migration_unsecure
};
470 $cfg ->{ migration
}->{ type
} = ( $migration_unsecure ) ?
'insecure' : 'secure' ;
473 # map deprecated applet setting to html5
474 if ( defined ( $cfg ->{ console
}) && $cfg ->{ console
} eq 'applet' ) {
475 $cfg ->{ console
} = 'html5' ;
478 if ( ref ( my $crs = $cfg ->{ crs
})) {
479 $cfg ->{ crs
} = PVE
:: JSONSchema
:: print_property_string
( $crs, $crs_format );
482 if ( ref ( my $migration = $cfg ->{ migration
})) {
483 $cfg ->{ migration
} = PVE
:: JSONSchema
:: print_property_string
( $migration, $migration_format );
486 if ( defined ( my $next_id = $cfg ->{ 'next-id' })) {
487 $next_id = parse_property_string
( $next_id_format, $next_id ) if ! ref ( $next_id );
489 my $lower = int ( $next_id ->{ lower
} // $next_id_format ->{ lower
}->{ default });
490 my $upper = int ( $next_id ->{ upper
} // $next_id_format ->{ upper
}->{ default });
492 die "lower ( $lower ) <= upper ( $upper ) boundary rule broken \n " if $lower > $upper ;
494 $cfg ->{ 'next-id' } = PVE
:: JSONSchema
:: print_property_string
( $next_id, $next_id_format );
497 if ( ref ( my $ha = $cfg ->{ ha
})) {
498 $cfg ->{ ha
} = PVE
:: JSONSchema
:: print_property_string
( $ha, $ha_format );
500 if ( ref ( my $notify = $cfg ->{ notify
})) {
501 $cfg ->{ notify
} = PVE
:: JSONSchema
:: print_property_string
( $notify, $notification_format );
504 if ( ref ( my $u2f = $cfg ->{ u2f
})) {
505 $cfg ->{ u2f
} = PVE
:: JSONSchema
:: print_property_string
( $u2f, $u2f_format );
508 if ( ref ( my $webauthn = $cfg ->{ webauthn
})) {
509 $cfg ->{ webauthn
} = PVE
:: JSONSchema
:: print_property_string
( $webauthn, $webauthn_format );
512 if ( ref ( my $tag_style = $cfg ->{ 'tag-style' })) {
513 $cfg ->{ 'tag-style' } = PVE
:: JSONSchema
:: print_property_string
( $tag_style, $tag_style_format );
516 if ( ref ( my $user_tag_privs = $cfg ->{ 'user-tag-access' })) {
517 if ( my $user_tags = $user_tag_privs ->{ 'user-allow-list' }) {
518 $user_tag_privs ->{ 'user-allow-list' } = join ( ';' , sort $user_tags -> @* );
520 $cfg ->{ 'user-tag-access' } =
521 PVE
:: JSONSchema
:: print_property_string
( $user_tag_privs, $user_tag_privs_format );
524 if ( ref ( my $admin_tags = $cfg ->{ 'registered-tags' })) {
525 $cfg ->{ 'registered-tags' } = join ( ';' , sort $admin_tags -> @* );
529 # add description as comment to top of file
530 my $description = $cfg ->{ description
} || '' ;
531 foreach my $line ( split ( /\n/ , $description )) {
532 $comment .= '#' . PVE
:: Tools
:: encode_text
( $line ) . " \n " ;
534 delete $cfg ->{ description
}; # add only as comment, no additional key-value pair
535 my $dump = PVE
:: JSONSchema
:: dump_config
( $datacenter_schema, $filename, $cfg );
537 return $comment . " \n " . $dump ;
540 PVE
:: Cluster
:: cfs_register_file
(
542 \
& parse_datacenter_config
,
543 \
& write_datacenter_config
,