]> git.proxmox.com Git - pve-cluster.git/blobdiff - data/PVE/DataCenterConfig.pm
datacenter config: add tag-style property
[pve-cluster.git] / data / PVE / DataCenterConfig.pm
index 2f2dedf368b529799ac971f55e5997f93c0647d6..532e5e509965c6b6880b60d1d04748530a0ad3bb 100644 (file)
@@ -3,7 +3,7 @@ package PVE::DataCenterConfig;
 use strict;
 use warnings;
 
-use PVE::JSONSchema;
+use PVE::JSONSchema qw(parse_property_string);
 use PVE::Tools;
 use PVE::Cluster;
 
@@ -41,11 +41,35 @@ my $ha_format = {
            "recovered to other nodes, if the shutdown node does not come up again quickly ".
            "(< 1min). 'conditional' chooses automatically depending on the type of shutdown, ".
            "i.e., on a reboot the service will be frozen but on a poweroff the service will ".
-           "stay as is, and thus get recovered after about 2 minutes.",
+           "stay as is, and thus get recovered after about 2 minutes. ".
+           "Migrate will try to move all running services to another node when a reboot or ".
+           "shutdown was triggered. The poweroff process will only continue once no running services ".
+           "are located on the node anymore. If the node comes up again, the service will ".
+           "be moved back to the previously powered-off node, at least if no other migration, ".
+           "reloaction or recovery took place.",
        default => 'conditional',
     }
 };
 
+my $next_id_format = {
+    lower => {
+       type => 'integer',
+       description => "Lower, inclusive boundary for free next-id API range.",
+       min => 100,
+       max => 1000 * 1000 * 1000 - 1,
+       default => 100,
+       optional => 1,
+    },
+    upper => {
+       type => 'integer',
+       description => "Upper, exclusive boundary for free next-id API range.",
+       min => 100,
+       max => 1000 * 1000 * 1000,
+       default => 1000 * 1000, # lower than the maximum on purpose
+       optional => 1,
+    },
+};
+
 my $u2f_format = {
     appid => {
        type => 'string',
@@ -61,6 +85,40 @@ my $u2f_format = {
     },
 };
 
+my $webauthn_format = {
+    rp => {
+       type => 'string',
+       description =>
+           'Relying party name. Any text identifier.'
+           .' Changing this *may* break existing credentials.',
+       format_description => 'RELYING_PARTY',
+       optional => 1,
+    },
+    origin => {
+       type => 'string',
+       description =>
+           'Site origin. Must be a `https://` URL (or `http://localhost`).'
+           .' Should contain the address users type in their browsers to access'
+           .' the web interface.'
+           .' Changing this *may* break existing credentials.',
+       format_description => 'URL',
+       optional => 1,
+    },
+    id => {
+       type => 'string',
+       description =>
+           '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);
 sub pve_verify_mac_prefix {
@@ -73,6 +131,29 @@ 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).",
+    },
+};
+
 my $datacenter_schema = {
     type => "object",
     additionalProperties => 0,
@@ -117,6 +198,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',
@@ -124,6 +206,12 @@ my $datacenter_schema = {
              "For secure private networks you can disable it to speed up " .
              "migration. Deprecated, use the 'migration' property instead!",
        },
+       'next-id' => {
+           optional => 1,
+           type => 'string',
+           format => $next_id_format,
+           description => "Control the range for the free VMID auto-selection pool.",
+       },
        migration => {
            optional => 1,
            type => 'string', format => $migration_format,
@@ -132,7 +220,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 => {
@@ -176,6 +266,25 @@ my $datacenter_schema = {
            format => $u2f_format,
            description => 'u2f',
        },
+       webauthn => {
+           optional => 1,
+           type => 'string',
+           format => $webauthn_format,
+           description => 'webauthn configuration',
+       },
+       description => {
+           type => 'string',
+           description => "Datacenter description. Shown in the web-interface datacenter notes panel."
+               ." This is saved as comment inside the configuration file.",
+           maxLength => 64 * 1024,
+           optional => 1,
+       },
+       'tag-style' => {
+           optional => 1,
+           type => 'string',
+           description => "Tag style options.",
+           format => $tag_style_format,
+       },
     },
 };
 
@@ -185,18 +294,43 @@ sub get_datacenter_schema { return $datacenter_schema };
 sub parse_datacenter_config {
     my ($filename, $raw) = @_;
 
-    my $res = PVE::JSONSchema::parse_config($datacenter_schema, $filename, $raw // '');
+    $raw = '' if !defined($raw);
+
+    # description may be comment or key-value pair (or both)
+    my $comment = '';
+    for my $line (split(/\n/, $raw)) {
+       if ($line =~ /^\#(.*)$/) {
+           $comment .= PVE::Tools::decode_text($1) . "\n";
+       }
+    }
+
+    # parse_config ignores lines with # => use $raw
+    my $res = PVE::JSONSchema::parse_config($datacenter_schema, $filename, $raw);
+
+    $res->{description} = $comment;
 
     if (my $migration = $res->{migration}) {
-       $res->{migration} = PVE::JSONSchema::parse_property_string($migration_format, $migration);
+       $res->{migration} = parse_property_string($migration_format, $migration);
+    }
+
+    if (my $next_id = $res->{'next-id'}) {
+       $res->{'next-id'} = parse_property_string($next_id_format, $next_id);
     }
 
     if (my $ha = $res->{ha}) {
-       $res->{ha} = PVE::JSONSchema::parse_property_string($ha_format, $ha);
+       $res->{ha} = parse_property_string($ha_format, $ha);
     }
 
     if (my $u2f = $res->{u2f}) {
-       $res->{u2f} = PVE::JSONSchema::parse_property_string($u2f_format, $u2f);
+       $res->{u2f} = parse_property_string($u2f_format, $u2f);
+    }
+
+    if (my $webauthn = $res->{webauthn}) {
+       $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);
     }
 
     # for backwards compatibility only, new migration property has precedence
@@ -231,26 +365,53 @@ sub write_datacenter_config {
        $cfg->{console} = 'html5';
     }
 
-    if (ref($cfg->{migration})) {
-       my $migration = $cfg->{migration};
+    if (ref(my $migration = $cfg->{migration})) {
        $cfg->{migration} = PVE::JSONSchema::print_property_string($migration, $migration_format);
     }
 
-    if (ref($cfg->{ha})) {
-       my $ha = $cfg->{ha};
+    if (defined(my $next_id = $cfg->{'next-id'})) {
+        $next_id = parse_property_string($next_id_format, $next_id) if !ref($next_id);
+
+       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\n" if $lower > $upper;
+
+       $cfg->{'next-id'} = PVE::JSONSchema::print_property_string($next_id, $next_id_format);
+    }
+
+    if (ref(my $ha = $cfg->{ha})) {
        $cfg->{ha} = PVE::JSONSchema::print_property_string($ha, $ha_format);
     }
 
-    if (ref($cfg->{u2f})) {
-       my $u2f = $cfg->{u2f};
+    if (ref(my $u2f = $cfg->{u2f})) {
        $cfg->{u2f} = PVE::JSONSchema::print_property_string($u2f, $u2f_format);
     }
 
-    return PVE::JSONSchema::dump_config($datacenter_schema, $filename, $cfg);
+    if (ref(my $webauthn = $cfg->{webauthn})) {
+       $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);
+    }
+
+    my $comment = '';
+    # add description as comment to top of file
+    my $description = $cfg->{description} || '';
+    foreach my $line (split(/\n/, $description)) {
+       $comment .= '#' .  PVE::Tools::encode_text($line) . "\n";
+    }
+    delete $cfg->{description}; # add only as comment, no additional key-value pair
+    my $dump = PVE::JSONSchema::dump_config($datacenter_schema, $filename, $cfg);
+
+    return $comment . "\n" . $dump;
 }
 
-PVE::Cluster::cfs_register_file('datacenter.cfg',
-                 \&parse_datacenter_config,
-                 \&write_datacenter_config);
+PVE::Cluster::cfs_register_file(
+    'datacenter.cfg',
+    \&parse_datacenter_config,
+    \&write_datacenter_config,
+);
 
 1;