use base 'Exporter';
our @EXPORT_OK = qw(
+register_standard_option
get_standard_option
parse_property_string
-register_standard_option
+print_property_string
);
our $CONFIGID_RE = qr/[a-z][a-z0-9_-]+/i;
type => 'string', format => 'pve-storage-id',
});
+register_standard_option('pve-bridge-id', {
+ description => "Bridge to attach guest network devices to.",
+ type => 'string', format => 'pve-bridge-id',
+ format_description => 'bridge',
+});
+
register_standard_option('pve-config-digest', {
description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
type => 'string',
return parse_id($storeid, 'storage', $noerr);
}
+PVE::JSONSchema::register_format('pve-bridge-id', \&parse_bridge_id);
+sub parse_bridge_id {
+ my ($id, $noerr) = @_;
+
+ if ($id !~ m/^[-_.\w\d]+$/) {
+ return undef if $noerr;
+ die "invalid bridge ID '$id'\n";
+ }
+ return $id;
+}
+
PVE::JSONSchema::register_format('acme-plugin-id', \&parse_acme_plugin_id);
sub parse_acme_plugin_id {
my ($pluginid, $noerr) = @_;
return $node;
}
+# maps source to target ID using an ID map
+sub map_id {
+ my ($map, $source) = @_;
+
+ return $source if !defined($map);
+
+ return $map->{entries}->{$source}
+ if $map->{entries} && defined($map->{entries}->{$source});
+
+ return $map->{default} if $map->{default};
+
+ # identity (fallback)
+ return $source;
+}
+
sub parse_idmap {
my ($idmap, $idformat) = @_;
return $input;
};
+PVE::JSONSchema::register_standard_option('pve-targetstorage', {
+ description => "Mapping from source to target storages. Providing only a single storage ID maps all source storages to that storage. Providing the special value '1' will map each source storage to itself.",
+ type => 'string',
+ format => 'storage-pair-list',
+ optional => 1,
+});
+
# note: this only checks a single list entry
-# when using a storagepair-list map, you need to pass the full parameter to
+# when using a storage-pair-list map, you need to pass the full parameter to
# parse_idmap
-register_format('storagepair', \&verify_storagepair);
+register_format('storage-pair', \&verify_storagepair);
sub verify_storagepair {
my ($storagepair, $noerr) = @_;
return $verify_idpair->($storagepair, $noerr, 'pve-storage-id');
}
+# note: this only checks a single list entry
+# when using a bridge-pair-list map, you need to pass the full parameter to
+# parse_idmap
+register_format('bridge-pair', \&verify_bridgepair);
+sub verify_bridgepair {
+ my ($bridgepair, $noerr) = @_;
+ return $verify_idpair->($bridgepair, $noerr, 'pve-bridge-id');
+}
+
register_format('mac-addr', \&pve_verify_mac_addr);
sub pve_verify_mac_addr {
my ($mac_addr, $noerr) = @_;
format => $bwlimit_format,
});
+my $remote_format = {
+ host => {
+ type => 'string',
+ format_description => 'Remote Proxmox hostname or IP',
+ },
+ port => {
+ type => 'integer',
+ optional => 1,
+ },
+ apitoken => {
+ type => 'string',
+ format_description => 'A full Proxmox API token including the secret value.',
+ },
+ fingerprint => get_standard_option(
+ 'fingerprint-sha256',
+ {
+ optional => 1,
+ format_description => 'Remote host\'s certificate fingerprint, if not trusted by system store.',
+ }
+ ),
+};
+register_format('proxmox-remote', $remote_format);
+register_standard_option('proxmox-remote', {
+ description => "Specification of a remote endpoint.",
+ type => 'string', format => 'proxmox-remote',
+});
+
+our $PVE_TAG_RE = qr/[a-z0-9_][a-z0-9_\-\+\.]*/i;
+
# used for pve-tag-list in e.g., guest configs
register_format('pve-tag', \&pve_verify_tag);
sub pve_verify_tag {
my ($value, $noerr) = @_;
- return $value if $value =~ m/^[a-z0-9_][a-z0-9_\-\+\.]*$/i;
+ return $value if $value =~ m/^${PVE_TAG_RE}$/i;
return undef if $noerr;
die "unable to decode TFA secret\n";
}
+
+PVE::JSONSchema::register_format('pve-task-status-type', \&verify_task_status_type);
+sub verify_task_status_type {
+ my ($value, $noerr) = @_;
+
+ return $value if $value =~ m/^(ok|error|warning|unknown)$/i;
+
+ return undef if $noerr;
+
+ die "invalid status '$value'\n";
+}
+
sub check_format {
my ($format, $value, $path) = @_;
}
# A way to parse configuration data by giving a json schema
-sub parse_config {
- my ($schema, $filename, $raw) = @_;
+sub parse_config : prototype($$$;$) {
+ my ($schema, $filename, $raw, $comment_key) = @_;
# do fast check (avoid validate_schema($schema))
die "got strange schema" if !$schema->{type} ||
my $cfg = {};
+ my $comment_data;
+ my $handle_comment = sub { $_[0] =~ /^#/ };
+ if (defined($comment_key)) {
+ $comment_data = '';
+ my $comment_re = qr/^\Q$comment_key\E:\s*(.*\S)\s*$/;
+ $handle_comment = sub {
+ if ($_[0] =~ /^\#(.*)\s*$/ || $_[0] =~ $comment_re) {
+ $comment_data .= PVE::Tools::decode_text($1) . "\n";
+ return 1;
+ }
+ return undef;
+ };
+ }
+
while ($raw =~ /^\s*(.+?)\s*$/gm) {
my $line = $1;
- next if $line =~ /^#/;
+ next if $handle_comment->($line);
if ($line =~ m/^(\S+?):\s*(.*)$/) {
my $key = $1;
}
}
+ if (defined($comment_data)) {
+ $cfg->{$comment_key} = $comment_data;
+ }
+
my $errors = {};
check_prop($cfg, $schema, '', $errors);