]> git.proxmox.com Git - pve-cluster.git/blobdiff - data/PVE/DataCenterConfig.pm
dc config: mark HA CRS scheduler sub-property optional
[pve-cluster.git] / data / PVE / DataCenterConfig.pm
index 0a2fa2cd71144aa7f0477637d12b904198372cc0..c50a0cdb87576c852f3050664e831f7bcfa98b39 100644 (file)
@@ -7,6 +7,19 @@ use PVE::JSONSchema qw(parse_property_string);
 use PVE::Tools;
 use PVE::Cluster;
 
+my $crs_format = {
+    ha => {
+       type => 'string',
+       enum => ['basic', 'static'],
+       optional => 1,
+       default => 'basic',
+       description => "Use this resource scheduler mode for HA.",
+       verbose_description => "Configures how the HA manager should select nodes to start or ".
+           "recover services. With 'basic', only the number of services is used, with 'static', ".
+           "static CPU and memory configuration of services is considered.",
+    },
+};
+
 my $migration_format = {
     type => {
        default_key => 1,
@@ -25,6 +38,20 @@ my $migration_format = {
     },
 };
 
+my $notification_format = {
+    'package-updates' => {
+       type => 'string',
+       enum => ['auto', 'always', 'never'],
+       description => "Control when the daily update job should send out notification mails.",
+       verbose_description => "Control how often the daily update job should send out notification mails:\n"
+           ."* 'auto' daily for systems with a valid subscription, as those are assumed to be "
+           ." production-ready and thus should know about pending updates.\n"
+           ."* 'always' every update, if there are new pending updates.\n"
+           ."* 'never' never send a notification for new pending updates.\n",
+       default => 'auto',
+    },
+};
+
 my $ha_format = {
     shutdown_policy => {
        type => 'string',
@@ -62,9 +89,9 @@ my $next_id_format = {
     },
     upper => {
        type => 'integer',
-       description => "Upper, inclusive boundary for free next-id API range.",
+       description => "Upper, exclusive boundary for free next-id API range.",
        min => 100,
-       max => 1000 * 1000 * 1000 - 1,
+       max => 1000 * 1000 * 1000,
        default => 1000 * 1000, # lower than the maximum on purpose
        optional => 1,
     },
@@ -107,11 +134,17 @@ my $webauthn_format = {
     id => {
        type => 'string',
        description =>
-           'Relying part ID. Must be the domain name without protocol, port or location.'
+           'Relying party ID. Must be the domain name without protocol, port or location.'
            .' Changing this *will* break existing credentials.',
        format_description => 'DOMAINNAME',
        optional => 1,
     },
+    'allow-subdomains' => {
+       type => 'boolean',
+       description => 'Whether to allow the origin to be a subdomain, rather than the exact URL.',
+       optional => 1,
+       default => 1,
+    },
 };
 
 PVE::JSONSchema::register_format('mac-prefix', \&pve_verify_mac_prefix);
@@ -125,10 +158,77 @@ sub pve_verify_mac_prefix {
     return $mac_prefix;
 }
 
+my $COLOR_RE = '[0-9a-fA-F]{6}';
+my $TAG_COLOR_OVERRIDE_RE = "(?:${PVE::JSONSchema::PVE_TAG_RE}:${COLOR_RE}(?:\:${COLOR_RE})?)";
+
+my $tag_style_format = {
+    'shape' => {
+       optional => 1,
+       type => 'string',
+       enum => ['full', 'circle', 'dense', 'none'],
+       default => 'circle',
+       description => "Tag shape for the web ui tree. 'full' draws the full tag. "
+           ."'circle' draws only a circle with the background color. "
+           ."'dense' only draws a small rectancle (useful when many tags are assigned to each guest)."
+           ."'none' disables showing the tags.",
+    },
+    'color-map' => {
+       optional => 1,
+       type => 'string',
+       pattern => "${TAG_COLOR_OVERRIDE_RE}(?:\;$TAG_COLOR_OVERRIDE_RE)*",
+       typetext => '<tag>:<hex-color>[:<hex-color-for-text>][;<tag>=...]',
+       description => "Manual color mapping for tags (semicolon separated).",
+    },
+    ordering => {
+       optional => 1,
+       type => 'string',
+       enum => ['config', 'alphabetical'],
+       default => 'alphabetical',
+       description => 'Controls the sorting of the tags in the web-interface and the API update.',
+    },
+    'case-sensitive' => {
+       type => 'boolean',
+       description => 'Controls if filtering for unique tags on update should check case-sensitive.',
+       optional => 1,
+       default => 0,
+    },
+};
+
+my $user_tag_privs_format = {
+    'user-allow' => {
+       optional => 1,
+       type => 'string',
+       enum => ['none', 'list', 'existing', 'free'],
+       default => 'free',
+       description => "Controls tag usage for users without `Sys.Modify` on `/` by either "
+           ."allowing `none`, a `list`, already `existing` or anything (`free`).",
+       verbose_description => "Controls which tags can be set or deleted on resources a user "
+           ."controls (such as guests). Users with the `Sys.Modify` privilege on `/` are always "
+           ." unrestricted. "
+           ."* 'none' no tags are usable. "
+           ."* 'list' tags from 'user-allow-list' are usable. "
+           ."* 'existing' like list, but already existing tags of resources are also usable."
+           ."* 'free' no tag restrictions.",
+    },
+    'user-allow-list' => {
+       optional => 1,
+       type => 'string',
+       pattern => "${PVE::JSONSchema::PVE_TAG_RE}(?:\;${PVE::JSONSchema::PVE_TAG_RE})*",
+       typetext => "<tag>[;<tag>...]",
+       description => "List of tags users are allowed to set and delete (semicolon separated) "
+           ."for 'user-allow' values 'list' and 'existing'.",
+    },
+};
+
 my $datacenter_schema = {
     type => "object",
     additionalProperties => 0,
     properties => {
+       crs => {
+           optional => 1,
+           type => 'string', format => $crs_format,
+           description => "Cluster resource scheduling settings.",
+       },
        keyboard => {
            optional => 1,
            type => 'string',
@@ -169,6 +269,7 @@ my $datacenter_schema = {
            description => "Specify external http proxy which is used for downloads (example: 'http://username:password\@host:port/')",
            pattern => "http://.*",
        },
+       # FIXME: remove with 8.0 (add check to pve7to8!), merged into "migration" since 4.3
        migration_unsecure => {
            optional => 1,
            type => 'boolean',
@@ -190,7 +291,9 @@ my $datacenter_schema = {
        console => {
            optional => 1,
            type => 'string',
-           description => "Select the default Console viewer. You can either use the builtin java 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.",
+           description => "Select the default Console viewer. You can either use the builtin java"
+               ." 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.",
+           # FIXME: remove 'applet' with 8.0 (add pve7to8 check!)
            enum => ['applet', 'vv', 'html5', 'xtermjs'],
        },
        email_from => {
@@ -227,6 +330,11 @@ my $datacenter_schema = {
            format => 'mac-prefix',
            description => 'Prefix for autogenerated MAC addresses.',
        },
+       notify => {
+           optional => 1,
+           type => 'string', format => $notification_format,
+           description => "Cluster-wide notification settings.",
+       },
        bwlimit => PVE::JSONSchema::get_standard_option('bwlimit'),
        u2f => {
            optional => 1,
@@ -247,6 +355,26 @@ my $datacenter_schema = {
            maxLength => 64 * 1024,
            optional => 1,
        },
+       'tag-style' => {
+           optional => 1,
+           type => 'string',
+           description => "Tag style options.",
+           format => $tag_style_format,
+       },
+       'user-tag-access' => {
+           optional => 1,
+           type => 'string',
+           description => "Privilege options for user-settable tags",
+           format => $user_tag_privs_format,
+       },
+       'registered-tags' => {
+           optional => 1,
+           type => 'string',
+           description => "A list of tags that require a `Sys.Modify` on '/' to set and delete. "
+               ."Tags set here that are also in 'user-tag-access' also require `Sys.Modify`.",
+           pattern => "(?:${PVE::JSONSchema::PVE_TAG_RE};)*${PVE::JSONSchema::PVE_TAG_RE}",
+           typetext => "<tag>[;<tag>...]",
+       },
     },
 };
 
@@ -261,7 +389,7 @@ sub parse_datacenter_config {
     # description may be comment or key-value pair (or both)
     my $comment = '';
     for my $line (split(/\n/, $raw)) {
-       if ($line =~ /^\#(.*)\s*$/) {
+       if ($line =~ /^\#(.*)$/) {
            $comment .= PVE::Tools::decode_text($1) . "\n";
        }
     }
@@ -271,6 +399,10 @@ sub parse_datacenter_config {
 
     $res->{description} = $comment;
 
+    if (my $crs = $res->{crs}) {
+       $res->{crs} = parse_property_string($crs_format, $crs);
+    }
+
     if (my $migration = $res->{migration}) {
        $res->{migration} = parse_property_string($migration_format, $migration);
     }
@@ -282,6 +414,9 @@ sub parse_datacenter_config {
     if (my $ha = $res->{ha}) {
        $res->{ha} = parse_property_string($ha_format, $ha);
     }
+    if (my $notify = $res->{notify}) {
+       $res->{notify} = parse_property_string($notification_format, $notify);
+    }
 
     if (my $u2f = $res->{u2f}) {
        $res->{u2f} = parse_property_string($u2f_format, $u2f);
@@ -291,6 +426,23 @@ sub parse_datacenter_config {
        $res->{webauthn} = parse_property_string($webauthn_format, $webauthn);
     }
 
+    if (my $tag_style = $res->{'tag-style'}) {
+       $res->{'tag-style'} = parse_property_string($tag_style_format, $tag_style);
+    }
+
+    if (my $user_tag_privs = $res->{'user-tag-access'}) {
+       $res->{'user-tag-access'} =
+           parse_property_string($user_tag_privs_format, $user_tag_privs);
+
+       if (my $user_tags = $res->{'user-tag-access'}->{'user-allow-list'}) {
+           $res->{'user-tag-access'}->{'user-allow-list'} = [split(';', $user_tags)];
+       }
+    }
+
+    if (my $admin_tags = $res->{'registered-tags'}) {
+       $res->{'registered-tags'} = [split(';', $admin_tags)];
+    }
+
     # for backwards compatibility only, new migration property has precedence
     if (defined($res->{migration_unsecure})) {
        if (defined($res->{migration}->{type})) {
@@ -323,6 +475,10 @@ sub write_datacenter_config {
        $cfg->{console} = 'html5';
     }
 
+    if (ref(my $crs = $cfg->{crs})) {
+       $cfg->{crs} = PVE::JSONSchema::print_property_string($crs, $crs_format);
+    }
+
     if (ref(my $migration = $cfg->{migration})) {
        $cfg->{migration} = PVE::JSONSchema::print_property_string($migration, $migration_format);
     }
@@ -333,7 +489,7 @@ sub write_datacenter_config {
        my $lower = int($next_id->{lower} // $next_id_format->{lower}->{default});
        my $upper = int($next_id->{upper} // $next_id_format->{upper}->{default});
 
-       die "lower ($lower) <= upper ($upper) boundary rule broken" if $lower > $upper;
+       die "lower ($lower) <= upper ($upper) boundary rule broken\n" if $lower > $upper;
 
        $cfg->{'next-id'} = PVE::JSONSchema::print_property_string($next_id, $next_id_format);
     }
@@ -341,6 +497,9 @@ sub write_datacenter_config {
     if (ref(my $ha = $cfg->{ha})) {
        $cfg->{ha} = PVE::JSONSchema::print_property_string($ha, $ha_format);
     }
+    if (ref(my $notify = $cfg->{notify})) {
+       $cfg->{notify} = PVE::JSONSchema::print_property_string($notify, $notification_format);
+    }
 
     if (ref(my $u2f = $cfg->{u2f})) {
        $cfg->{u2f} = PVE::JSONSchema::print_property_string($u2f, $u2f_format);
@@ -350,6 +509,22 @@ sub write_datacenter_config {
        $cfg->{webauthn} = PVE::JSONSchema::print_property_string($webauthn, $webauthn_format);
     }
 
+    if (ref(my $tag_style = $cfg->{'tag-style'})) {
+       $cfg->{'tag-style'} = PVE::JSONSchema::print_property_string($tag_style, $tag_style_format);
+    }
+
+    if (ref(my $user_tag_privs = $cfg->{'user-tag-access'})) {
+       if (my $user_tags = $user_tag_privs->{'user-allow-list'}) {
+           $user_tag_privs->{'user-allow-list'} = join(';', sort $user_tags->@*);
+       }
+       $cfg->{'user-tag-access'} =
+           PVE::JSONSchema::print_property_string($user_tag_privs, $user_tag_privs_format);
+    }
+
+    if (ref(my $admin_tags = $cfg->{'registered-tags'})) {
+       $cfg->{'registered-tags'} = join(';', sort $admin_tags->@*);
+    }
+
     my $comment = '';
     # add description as comment to top of file
     my $description = $cfg->{description} || '';