]>
git.proxmox.com Git - pve-cluster.git/blob - data/PVE/DataCenterConfig.pm
1 package PVE
:: DataCenterConfig
;
6 use PVE
:: JSONSchema
qw(parse_property_string) ;
10 my $migration_format = {
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." ,
22 type
=> 'string' , format
=> 'CIDR' ,
23 format_description
=> 'CIDR' ,
24 description
=> "CIDR of the (sub) network that is used for migration."
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 " .
44 "stay as is, and thus get recovered after about 2 minutes. " .
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 " .
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." ,
50 default => 'conditional' ,
54 my $next_id_format = {
57 description
=> "Lower, inclusive boundary for free next-id API range." ,
59 max
=> 1000 * 1000 * 1000 - 1 ,
65 description
=> "Upper, exclusive boundary for free next-id API range." ,
67 max
=> 1000 * 1000 * 1000 ,
68 default => 1000 * 1000 , # lower than the maximum on purpose
76 description
=> "U2F AppId URL override. Defaults to the origin." ,
77 format_description
=> 'APPID' ,
82 description
=> "U2F Origin override. Mostly useful for single nodes with a single URL." ,
83 format_description
=> 'URL' ,
88 my $webauthn_format = {
92 'Relying party name. Any text identifier.'
93 . ' Changing this *may* break existing credentials.' ,
94 format_description
=> 'RELYING_PARTY' ,
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' ,
110 'Relying party ID. Must be the domain name without protocol, port or location.'
111 . ' Changing this *will* break existing credentials.' ,
112 format_description
=> 'DOMAINNAME' ,
115 'allow-subdomains' => {
117 description
=> 'Whether to allow the origin to be a subdomain, rather than the exact URL.' ,
123 PVE
:: JSONSchema
:: register_format
( 'mac-prefix' , \
& pve_verify_mac_prefix
);
124 sub pve_verify_mac_prefix
{
125 my ( $mac_prefix, $noerr ) = @_ ;
127 if ( $mac_prefix !~ m/^[a-f0-9][02468ace](?::[a-f0-9]{2}){0,2}:?$/i ) {
128 return undef if $noerr ;
129 die "value is not a valid unicast MAC address prefix \n " ;
134 my $COLOR_RE = '[0-9a-fA-F]{6}' ;
135 my $TAG_COLOR_OVERRIDE_RE = "(?:${PVE::JSONSchema::PVE_TAG_RE}:${COLOR_RE}(?:\:${COLOR_RE})?)" ;
137 my $tag_style_format = {
141 enum
=> [ 'full' , 'circle' , 'dense' , 'none' ],
143 description
=> "Tag shape for the web ui tree. 'full' draws the full tag. "
144 . "'circle' draws only a circle with the background color. "
145 . "'dense' only draws a small rectancle (useful when many tags are assigned to each guest)."
146 . "'none' disables showing the tags." ,
151 pattern
=> "${TAG_COLOR_OVERRIDE_RE}(?:\; $TAG_COLOR_OVERRIDE_RE )*" ,
152 typetext
=> '<tag>:<hex-color>[:<hex-color-for-text>][;<tag>=...]' ,
153 description
=> "Manual color mapping for tags (semicolon separated)." ,
157 my $user_tag_privs_format = {
161 enum
=> [ 'none' , 'list' , 'existing' , 'free' ],
163 description
=> "Controls tag usage for users without `Sys.Modify` on `/` by either "
164 . "allowing `none`, a `list`, already `existing` or anything (`free`)." ,
165 verbose_description
=> "Controls which tags can be set or deleted on resources a user "
166 . "controls (such as guests). Users with the `Sys.Modify` privilege on `/` are always "
168 . "'none' no tags are usable. "
169 . "'list' tasg from 'user-allow'list' are usable. "
170 . "'existing' like list, but already existing tags of resources are also usable."
171 . "'free' no tag restrictions."
173 'user-allow-list' => {
176 pattern
=> "${PVE::JSONSchema::PVE_TAG_RE}(?:\;${PVE::JSONSchema::PVE_TAG_RE})*" ,
177 typetext
=> "<tag>[;<tag>...]" ,
178 description
=> "List of tags users are allowed to set and delete (semicolon separated) "
179 . "for 'user-allow' values 'list' and 'existing'." ,
183 my $datacenter_schema = {
185 additionalProperties
=> 0 ,
190 description
=> "Default keybord layout for vnc server." ,
191 enum
=> PVE
:: Tools
:: kvmkeymaplist
(),
196 description
=> "Default GUI language." ,
224 description
=> "Specify external http proxy which is used for downloads (example: 'http://username:password\ @host :port/')" ,
225 pattern
=> "http://.*" ,
227 # FIXME: remove with 8.0 (add check to pve7to8!), merged into "migration" since 4.3
228 migration_unsecure
=> {
231 description
=> "Migration is secure using SSH tunnel by default. " .
232 "For secure private networks you can disable it to speed up " .
233 "migration. Deprecated, use the 'migration' property instead!" ,
238 format
=> $next_id_format,
239 description
=> "Control the range for the free VMID auto-selection pool." ,
243 type
=> 'string' , format
=> $migration_format,
244 description
=> "For cluster wide migration settings." ,
249 description
=> "Select the default Console viewer. You can either use the builtin java"
250 . " 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." ,
251 # FIXME: remove 'applet' with 8.0 (add pve7to8 check!)
252 enum
=> [ 'applet' , 'vv' , 'html5' , 'xtermjs' ],
257 format
=> 'email-opt' ,
258 description
=> "Specify email address to send notification from (default is root @\$hostname )" ,
264 description
=> "Defines how many workers (per node) are maximal started " .
265 " on actions like 'stopall VMs' or task from the ha-manager." ,
270 default => 'watchdog' ,
271 enum
=> [ 'watchdog' , 'hardware' , 'both' ],
272 description
=> "Set the fencing mode of the HA cluster. Hardware mode " .
273 "needs a valid configuration of fence devices in /etc/pve/ha/fence.cfg." .
274 " With both all two modes are used." .
275 " \n\n WARNING: 'hardware' and 'both' are EXPERIMENTAL & WIP" ,
279 type
=> 'string' , format
=> $ha_format,
280 description
=> "Cluster wide HA settings." ,
285 format
=> 'mac-prefix' ,
286 description
=> 'Prefix for autogenerated MAC addresses.' ,
288 bwlimit
=> PVE
:: JSONSchema
:: get_standard_option
( 'bwlimit' ),
292 format
=> $u2f_format,
293 description
=> 'u2f' ,
298 format
=> $webauthn_format,
299 description
=> 'webauthn configuration' ,
303 description
=> "Datacenter description. Shown in the web-interface datacenter notes panel."
304 . " This is saved as comment inside the configuration file." ,
305 maxLength
=> 64 * 1024 ,
311 description
=> "Tag style options." ,
312 format
=> $tag_style_format,
314 'user-tag-access' => {
317 description
=> "Privilege options for user-settable tags" ,
318 format
=> $user_tag_privs_format,
320 'registered-tags' => {
323 description
=> "A list of tags that require a `Sys.Modify` on '/' to set and delete. "
324 . "Tags set here that are also in 'user-tag-access' also require `Sys.Modify`." ,
325 pattern
=> "(?:${PVE::JSONSchema::PVE_TAG_RE};)*${PVE::JSONSchema::PVE_TAG_RE}" ,
326 typetext
=> "<tag>[;<tag>...]" ,
331 # make schema accessible from outside (for documentation)
332 sub get_datacenter_schema
{ return $datacenter_schema };
334 sub parse_datacenter_config
{
335 my ( $filename, $raw ) = @_ ;
337 $raw = '' if ! defined ( $raw );
339 # description may be comment or key-value pair (or both)
341 for my $line ( split ( /\n/ , $raw )) {
342 if ( $line =~ /^\#(.*)$/ ) {
343 $comment .= PVE
:: Tools
:: decode_text
( $1 ) . " \n " ;
347 # parse_config ignores lines with # => use $raw
348 my $res = PVE
:: JSONSchema
:: parse_config
( $datacenter_schema, $filename, $raw );
350 $res ->{ description
} = $comment ;
352 if ( my $migration = $res ->{ migration
}) {
353 $res ->{ migration
} = parse_property_string
( $migration_format, $migration );
356 if ( my $next_id = $res ->{ 'next-id' }) {
357 $res ->{ 'next-id' } = parse_property_string
( $next_id_format, $next_id );
360 if ( my $ha = $res ->{ ha
}) {
361 $res ->{ ha
} = parse_property_string
( $ha_format, $ha );
364 if ( my $u2f = $res ->{ u2f
}) {
365 $res ->{ u2f
} = parse_property_string
( $u2f_format, $u2f );
368 if ( my $webauthn = $res ->{ webauthn
}) {
369 $res ->{ webauthn
} = parse_property_string
( $webauthn_format, $webauthn );
372 if ( my $tag_style = $res ->{ 'tag-style' }) {
373 $res ->{ 'tag-style' } = parse_property_string
( $tag_style_format, $tag_style );
376 if ( my $user_tag_privs = $res ->{ 'user-tag-access' }) {
377 $res ->{ 'user-tag-access' } =
378 parse_property_string
( $user_tag_privs_format, $user_tag_privs );
380 if ( my $user_tags = $res ->{ 'user-tag-access' }->{ 'user-allow-list' }) {
381 $res ->{ 'user-tag-access' }->{ 'user-allow-list' } = [ split ( ';' , $user_tags )];
385 if ( my $admin_tags = $res ->{ 'registered-tags' }) {
386 $res ->{ 'registered-tags' } = [ split ( ';' , $admin_tags )];
389 # for backwards compatibility only, new migration property has precedence
390 if ( defined ( $res ->{ migration_unsecure
})) {
391 if ( defined ( $res ->{ migration
}->{ type
})) {
392 warn "deprecated setting 'migration_unsecure' and new 'migration: type' " .
393 "set at same time! Ignore 'migration_unsecure' \n " ;
395 $res ->{ migration
}->{ type
} = ( $res ->{ migration_unsecure
}) ?
'insecure' : 'secure' ;
399 # for backwards compatibility only, applet maps to html5
400 if ( defined ( $res ->{ console
}) && $res ->{ console
} eq 'applet' ) {
401 $res ->{ console
} = 'html5' ;
407 sub write_datacenter_config
{
408 my ( $filename, $cfg ) = @_ ;
410 # map deprecated setting to new one
411 if ( defined ( $cfg ->{ migration_unsecure
}) && ! defined ( $cfg ->{ migration
})) {
412 my $migration_unsecure = delete $cfg ->{ migration_unsecure
};
413 $cfg ->{ migration
}->{ type
} = ( $migration_unsecure ) ?
'insecure' : 'secure' ;
416 # map deprecated applet setting to html5
417 if ( defined ( $cfg ->{ console
}) && $cfg ->{ console
} eq 'applet' ) {
418 $cfg ->{ console
} = 'html5' ;
421 if ( ref ( my $migration = $cfg ->{ migration
})) {
422 $cfg ->{ migration
} = PVE
:: JSONSchema
:: print_property_string
( $migration, $migration_format );
425 if ( defined ( my $next_id = $cfg ->{ 'next-id' })) {
426 $next_id = parse_property_string
( $next_id_format, $next_id ) if ! ref ( $next_id );
428 my $lower = int ( $next_id ->{ lower
} // $next_id_format ->{ lower
}->{ default });
429 my $upper = int ( $next_id ->{ upper
} // $next_id_format ->{ upper
}->{ default });
431 die "lower ( $lower ) <= upper ( $upper ) boundary rule broken \n " if $lower > $upper ;
433 $cfg ->{ 'next-id' } = PVE
:: JSONSchema
:: print_property_string
( $next_id, $next_id_format );
436 if ( ref ( my $ha = $cfg ->{ ha
})) {
437 $cfg ->{ ha
} = PVE
:: JSONSchema
:: print_property_string
( $ha, $ha_format );
440 if ( ref ( my $u2f = $cfg ->{ u2f
})) {
441 $cfg ->{ u2f
} = PVE
:: JSONSchema
:: print_property_string
( $u2f, $u2f_format );
444 if ( ref ( my $webauthn = $cfg ->{ webauthn
})) {
445 $cfg ->{ webauthn
} = PVE
:: JSONSchema
:: print_property_string
( $webauthn, $webauthn_format );
448 if ( ref ( my $tag_style = $cfg ->{ 'tag-style' })) {
449 $cfg ->{ 'tag-style' } = PVE
:: JSONSchema
:: print_property_string
( $tag_style, $tag_style_format );
452 if ( ref ( my $user_tag_privs = $cfg ->{ 'user-tag-access' })) {
453 if ( my $user_tags = $user_tag_privs ->{ 'user-allow-list' }) {
454 $user_tag_privs ->{ 'user-allow-list' } = join ( ';' , sort $user_tags -> @* );
456 $cfg ->{ 'user-tag-access' } =
457 PVE
:: JSONSchema
:: print_property_string
( $user_tag_privs, $user_tag_privs_format );
460 if ( ref ( my $admin_tags = $cfg ->{ 'registered-tags' })) {
461 $cfg ->{ 'registered-tags' } = join ( ';' , sort $admin_tags -> @* );
465 # add description as comment to top of file
466 my $description = $cfg ->{ description
} || '' ;
467 foreach my $line ( split ( /\n/ , $description )) {
468 $comment .= '#' . PVE
:: Tools
:: encode_text
( $line ) . " \n " ;
470 delete $cfg ->{ description
}; # add only as comment, no additional key-value pair
471 my $dump = PVE
:: JSONSchema
:: dump_config
( $datacenter_schema, $filename, $cfg );
473 return $comment . " \n " . $dump ;
476 PVE
:: Cluster
:: cfs_register_file
(
478 \
& parse_datacenter_config
,
479 \
& write_datacenter_config
,