pve-common/src/PVE/Job/Registry.pm
Thomas Lamprecht ec9e46fae6 job registry: avoid injecting the section id unconditionally in configs
this can result in a broken config due to it getting written out on
write_config serialization, and if a plugin did not declare `id` as
an option it understood (none do currently), it would then fail the
next parse, far from ideal...

As the section ID is available already anyway we should probably just
drop this, but for now avoid rushed changes and just make it
conforming to section config semantics and check if the option is
actually understood by the respective section type we're working on.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2022-11-13 11:50:42 +01:00

114 lines
3.2 KiB
Perl

package PVE::Job::Registry;
use strict;
use warnings;
# The job (config) base class, normally you would use this in one of two variants:
#
# 1) base of directly in manager and handle everything there; great for stuff that isn't residing
# outside of the manager, so that there is no cyclic dependency (forbidden!) required
#
# 2) use two (or even more) classes, one in the library (e.g., guest-common, access-control, ...)
# basing off this module, providing the basic config implementation. Then one in pve-manager
# (where every dependency is available) basing off the intermediate config one, that then holds
# the implementation of the 'run` method and is used in the job manager
use base qw(PVE::SectionConfig);
my $defaultData = {
propertyList => {
type => { description => "Section type." },
# FIXME: remove below? this is the section ID, schema would only be checked if a plugin
# declares this as explicit option, which isn't really required as its available anyway..
id => {
description => "The ID of the job.",
type => 'string',
format => 'pve-configid',
maxLength => 64,
},
enabled => {
description => "Determines if the job is enabled.",
type => 'boolean',
default => 1,
optional => 1,
},
schedule => {
description => "Backup schedule. The format is a subset of `systemd` calendar events.",
type => 'string', format => 'pve-calendar-event',
maxLength => 128,
},
comment => {
optional => 1,
type => 'string',
description => "Description for the Job.",
maxLength => 512,
},
'repeat-missed' => {
optional => 1,
type => 'boolean',
description => "If true, the job will be run as soon as possible if it was missed".
" while the scheduler was not running.",
default => 0,
},
},
};
sub private {
return $defaultData;
}
sub parse_config {
my ($class, $filename, $raw, $allow_unknown) = @_;
my $cfg = $class->SUPER::parse_config($filename, $raw, $allow_unknown);
for my $id (keys %{$cfg->{ids}}) {
my $data = $cfg->{ids}->{$id};
my $type = $data->{type};
# FIXME: below id injection is gross, guard to avoid breaking plugins that don't declare id
# as option; *iff* we want this it should be handled by section config directly.
if ($defaultData->{options}->{$type} && exists $defaultData->{options}->{$type}->{id}) {
$data->{id} = $id;
}
$data->{enabled} //= 1;
$data->{comment} = PVE::Tools::decode_text($data->{comment}) if defined($data->{comment});
}
return $cfg;
}
# call the plugin specific decode/encode code
sub decode_value {
my ($class, $type, $key, $value) = @_;
my $plugin = __PACKAGE__->lookup($type);
return $plugin->decode_value($type, $key, $value);
}
sub encode_value {
my ($class, $type, $key, $value) = @_;
my $plugin = __PACKAGE__->lookup($type);
return $plugin->encode_value($type, $key, $value);
}
sub write_config {
my ($class, $filename, $cfg, $allow_unknown) = @_;
for my $job (values $cfg->{ids}->%*) {
$job->{comment} = PVE::Tools::encode_text($job->{comment}) if defined($job->{comment});
}
$class->SUPER::write_config($filename, $cfg, $allow_unknown);
}
sub run {
my ($class, $cfg) = @_;
die "not implemented"; # implement in subclass
}
1;