]>
git.proxmox.com Git - pve-common.git/blob - data/PVE/SectionConfig.pm
1 package PVE
::SectionConfig
;
6 use PVE
::Exception
qw(raise_param_exc);
7 use PVE
::JSONSchema
qw(get_standard_option);
26 my $type = $class->type();
27 my $pdata = $class->private();
29 my $plugindata = $class->plugindata();
30 $pdata->{plugindata
}->{$type} = $plugindata;
31 $pdata->{plugins
}->{$type} = $class;
53 my $pdata = $class->private();
54 my $propertyList = $pdata->{propertyList
};
58 additionalProperties
=> 0,
59 properties
=> $propertyList,
66 my $pdata = $class->private();
67 my $propertyList = $pdata->{propertyList
};
68 my $plugins = $pdata->{plugins
};
72 foreach my $p (keys %$propertyList) {
74 if (!$propertyList->{$p}->{optional
}) {
75 $props->{$p} = $propertyList->{$p};
78 foreach my $t (keys %$plugins) {
79 my $opts = $pdata->{options
}->{$t};
80 next if !defined($opts->{$p});
81 if (!$opts->{$p}->{fixed
}) {
82 $props->{$p} = $propertyList->{$p};
87 $props->{digest
} = get_standard_option
('pve-config-digest');
90 type
=> 'string', format
=> 'pve-configid-list',
91 description
=> "A list of settings you want to delete.",
98 additionalProperties
=> 0,
106 my $pdata = $class->private();
108 foreach my $k (qw(options plugins plugindata propertyList)) {
109 $pdata->{$k} = {} if !$pdata->{$k};
112 my $plugins = $pdata->{plugins
};
113 my $propertyList = $pdata->{propertyList
};
115 foreach my $type (keys %$plugins) {
116 my $props = $plugins->{$type}->properties();
117 foreach my $p (keys %$props) {
118 die "duplicate property" if defined($propertyList->{$p});
119 my $res = $propertyList->{$p} = {};
120 my $data = $props->{$p};
121 for my $a (keys %$data) {
122 $res->{$a} = $data->{$a};
124 $res->{optional
} = 1;
128 foreach my $type (keys %$plugins) {
129 my $opts = $plugins->{$type}->options();
130 foreach my $p (keys %$opts) {
131 die "undefined property '$p'" if !$propertyList->{$p};
133 $pdata->{options
}->{$type} = $opts;
136 $propertyList->{type
}->{type
} = 'string';
137 $propertyList->{type
}->{enum
} = [keys %$plugins];
141 my ($class, $type) = @_;
143 my $pdata = $class->private();
144 my $plugin = $pdata->{plugins
}->{$type};
146 die "unknown section type '$type'\n" if !$plugin;
154 my $pdata = $class->private();
156 return [ keys %{$pdata->{plugins
}} ];
160 my ($class, $type, $key, $value) = @_;
166 my ($class, $type, $key, $value) = @_;
172 my ($class, $type, $key, $value, $storeid, $skipSchemaCheck) = @_;
174 my $pdata = $class->private();
176 return $value if $key eq 'type' && $type eq $value;
178 my $opts = $pdata->{options
}->{$type};
179 die "unknown section type '$type'\n" if !$opts;
181 die "unexpected property '$key'\n" if !defined($opts->{$key});
183 my $schema = $pdata->{propertyList
}->{$key};
184 die "unknown property type\n" if !$schema;
186 my $ct = $schema->{type
};
188 $value = 1 if $ct eq 'boolean' && !defined($value);
190 die "got undefined value\n" if !defined($value);
192 die "property contains a line feed\n" if $value =~ m/[\n\r]/;
194 if (!$skipSchemaCheck) {
196 PVE
::JSONSchema
::check_prop
($value, $schema, '', $errors);
197 if (scalar(keys %$errors)) {
198 die "$errors->{$key}\n" if $errors->{$key};
199 die "$errors->{_root}\n" if $errors->{_root
};
200 die "unknown error\n";
207 sub parse_section_header
{
208 my ($class, $line) = @_;
210 if ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
211 my ($type, $sectionId) = ($1, $2);
212 my $errmsg = undef; # set if you want to skip whole section
213 my $config = {}; # to return additional attributes
214 return ($type, $sectionId, $errmsg, $config);
219 sub format_section_header
{
220 my ($class, $type, $sectionId) = @_;
222 return "$type: $sectionId\n";
227 my ($class, $filename, $raw) = @_;
229 my $pdata = $class->private();
234 my $digest = Digest
::SHA
::sha1_hex
(defined($raw) ?
$raw : '');
240 while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
244 next if $line =~ m/^\#/;
245 next if $line =~ m/^\s*$/;
247 my $errprefix = "file $filename line $lineno";
249 my ($type, $sectionId, $errmsg, $config) = $class->parse_section_header($line);
258 warn "$errprefix (skip section '$sectionId'): $errmsg\n";
261 warn "$errprefix (skip section '$sectionId'): missing type - internal error\n";
263 if (!($plugin = $pdata->{plugins
}->{$type})) {
265 warn "$errprefix (skip section '$sectionId'): unsupported type '$type'\n";
269 while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
273 next if $line =~ m/^\#/;
274 last if $line =~ m/^\s*$/;
276 next if $ignore; # skip
278 $errprefix = "file $filename line $lineno";
280 if ($line =~ m/^\s+(\S+)(\s+(.*\S))?\s*$/) {
281 my ($k, $v) = ($1, $3);
284 die "duplicate attribute\n" if defined($config->{$k});
285 $config->{$k} = $plugin->check_value($type, $k, $v, $sectionId);
287 warn "$errprefix (section '$sectionId') - unable to parse value of '$k': $@" if $@;
290 warn "$errprefix (section '$sectionId') - ignore config line: $line\n";
294 if (!$ignore && $type && $plugin && $config) {
295 $config->{type
} = $type;
296 eval { $ids->{$sectionId} = $plugin->check_config($sectionId, $config, 1, 1); };
297 warn "$errprefix (skip section '$sectionId'): $@" if $@;
298 $order->{$sectionId} = $pri++;
302 warn "$errprefix - ignore config line: $line\n";
307 my $cfg = { ids
=> $ids, order
=> $order, digest
=> $digest};
313 my ($class, $sectionId, $config, $create, $skipSchemaCheck) = @_;
315 my $type = $class->type();
316 my $pdata = $class->private();
317 my $opts = $pdata->{options
}->{$type};
319 my $settings = { type
=> $type };
321 foreach my $k (keys %$config) {
322 my $value = $config->{$k};
324 die "can't change value of fixed parameter '$k'\n"
325 if !$create && $opts->{$k}->{fixed
};
327 if (defined($value)) {
328 my $tmp = $class->check_value($type, $k, $value, $sectionId, $skipSchemaCheck);
329 $settings->{$k} = $class->decode_value($type, $k, $tmp);
331 die "got undefined value for option '$k'\n";
336 # check if we have a value for all required options
337 foreach my $k (keys %$opts) {
338 next if $opts->{$k}->{optional
};
339 die "missing value for required option '$k'\n"
340 if !defined($config->{$k});
347 my $format_config_line = sub {
348 my ($schema, $key, $value) = @_;
350 my $ct = $schema->{type
};
352 if ($ct eq 'boolean') {
353 return $value ?
"\t$key\n" : '';
355 return "\t$key $value\n" if "$value" ne '';
360 my ($class, $filename, $cfg) = @_;
362 my $pdata = $class->private();
363 my $propertyList = $pdata->{propertyList
};
367 my $ids = $cfg->{ids
};
368 my $order = $cfg->{order
};
371 foreach my $sectionId (keys %$ids) {
372 my $pri = $order->{$sectionId};
373 $maxpri = $pri if $pri && $pri > $maxpri;
375 foreach my $sectionId (keys %$ids) {
376 if (!defined ($order->{$sectionId})) {
377 $order->{$sectionId} = ++$maxpri;
381 foreach my $sectionId (sort {$order->{$a} <=> $order->{$b}} keys %$ids) {
382 my $scfg = $ids->{$sectionId};
383 my $type = $scfg->{type
};
384 my $opts = $pdata->{options
}->{$type};
386 die "unknown section type '$type'\n" if !$opts;
388 my $data = $class->format_section_header($type, $sectionId);
389 if ($scfg->{comment
}) {
391 my $v = $class->encode_value($type, $k, $scfg->{$k});
392 $data .= &$format_config_line($propertyList->{$k}, $k, $v);
395 $data .= "\tdisable\n" if $scfg->{disable
};
397 my $done_hash = { comment
=> 1, disable
=> 1};
399 foreach my $k (keys %$opts) {
400 next if $opts->{$k}->{optional
};
401 $done_hash->{$k} = 1;
403 die "section '$sectionId' - missing value for required option '$k'\n"
405 $v = $class->encode_value($type, $k, $v);
406 $data .= &$format_config_line($propertyList->{$k}, $k, $v);
409 foreach my $k (keys %$opts) {
410 next if defined($done_hash->{$k});
412 next if !defined($v);
413 $v = $class->encode_value($type, $k, $v);
414 $data .= &$format_config_line($propertyList->{$k}, $k, $v);
423 sub assert_if_modified
{
424 my ($cfg, $digest) = @_;
426 PVE
::Tools
::assert_if_modified
($cfg->{digest
}, $digest);