+++ /dev/null
-API2_SOURCES= \
- RealmSync.pm \
-
-.PHONY: install
-install:
- for i in ${API2_SOURCES}; do install -D -m 0644 $$i ${DESTDIR}${PERLDIR}/PVE/API2/AccessControl/$$i; done
+++ /dev/null
-package PVE::API2::AccessControl::RealmSync;
-
-use strict;
-use warnings;
-
-
-use PVE::Cluster qw(cfs_lock_file cfs_read_file cfs_write_file);
-use PVE::Exception qw(raise_param_exc);
-use PVE::JSONSchema qw(get_standard_option);
-use PVE::Job::Registry ();
-use PVE::SectionConfig ();
-use PVE::Tools qw(extract_param);
-
-use PVE::Jobs::RealmSync ();
-
-use base qw(PVE::RESTHandler);
-
-my $get_cluster_last_run = sub {
- my ($jobid) = @_;
-
- my $state = eval { PVE::Jobs::RealmSync::get_state($jobid) };
- die "error on getting state for '$jobid': $@\n" if $@;
-
- if (my $upid = $state->{upid}) {
- if (my $decoded = PVE::Tools::upid_decode($upid)) {
- return $decoded->{starttime};
- }
- } else {
- return $state->{time};
- }
-
- return undef;
-};
-
-__PACKAGE__->register_method ({
- name => 'syncjob_index',
- path => '',
- method => 'GET',
- description => "List configured realm-sync-jobs.",
- permissions => {
- check => ['perm', '/', ['Sys.Audit']],
- },
- parameters => {
- additionalProperties => 0,
- properties => {},
- },
- returns => {
- type => 'array',
- items => {
- type => "object",
- properties => {
- id => {
- description => "The ID of the entry.",
- type => 'string'
- },
- enabled => {
- description => "If the job is enabled or not.",
- type => 'boolean',
- },
- comment => {
- description => "A comment for the job.",
- type => 'string',
- optional => 1,
- },
- schedule => {
- description => "The configured sync schedule.",
- type => 'string',
- },
- realm => get_standard_option('realm'),
- scope => get_standard_option('sync-scope'),
- 'remove-vanished' => get_standard_option('sync-remove-vanished'),
- 'last-run' => {
- description => "Last execution time of the job in seconds since the beginning of the UNIX epoch",
- type => 'integer',
- optional => 1,
- },
- 'next-run' => {
- description => "Next planned execution time of the job in seconds since the beginning of the UNIX epoch.",
- type => 'integer',
- optional => 1,
- },
- },
- },
- links => [ { rel => 'child', href => "{id}" } ],
- },
- code => sub {
- my ($param) = @_;
-
- my $rpcenv = PVE::RPCEnvironment::get();
- my $user = $rpcenv->get_user();
-
- my $jobs_data = cfs_read_file('jobs.cfg');
- my $order = $jobs_data->{order};
- my $jobs = $jobs_data->{ids};
-
- my $res = [];
- for my $jobid (sort { $order->{$a} <=> $order->{$b} } keys %$jobs) {
- my $job = $jobs->{$jobid};
- next if $job->{type} ne 'realm-sync';
-
- $job->{id} = $jobid;
- if (my $schedule = $job->{schedule}) {
- $job->{'last-run'} = eval { $get_cluster_last_run->($jobid) };
- my $last_run = $job->{'last-run'} // time(); # current time as fallback
-
- my $calendar_event = Proxmox::RS::CalendarEvent->new($schedule);
- my $next_run = $calendar_event->compute_next_event($last_run);
- $job->{'next-run'} = $next_run if defined($next_run);
- }
-
- push @$res, $job;
- }
-
- return $res;
- }});
-
-__PACKAGE__->register_method({
- name => 'read_job',
- path => '{id}',
- method => 'GET',
- description => "Read realm-sync job definition.",
- permissions => {
- check => ['perm', '/', ['Sys.Audit']],
- },
- parameters => {
- additionalProperties => 0,
- properties => {
- id => {
- type => 'string',
- format => 'pve-configid',
- },
- },
- },
- returns => {
- type => 'object',
- },
- code => sub {
- my ($param) = @_;
-
- my $jobs = cfs_read_file('jobs.cfg');
- my $id = $param->{id};
- my $job = $jobs->{ids}->{$id};
- return $job if $job && $job->{type} eq 'realm-sync';
-
- raise_param_exc({ id => "No such job '$id'" });
-
- }});
-
-__PACKAGE__->register_method({
- name => 'create_job',
- path => '{id}',
- method => 'POST',
- protected => 1,
- description => "Create new realm-sync job.",
- permissions => {
- description => "'Realm.AllocateUser' on '/access/realm/<realm>' and "
- ."'User.Modify' permissions to '/access/groups/'.",
- check => [ 'and',
- ['perm', '/access/realm/{realm}', ['Realm.AllocateUser']],
- ['perm', '/access/groups', ['User.Modify']],
- ],
- },
- parameters => PVE::Jobs::RealmSync->createSchema(),
- returns => { type => 'null' },
- code => sub {
- my ($param) = @_;
-
- my $id = extract_param($param, 'id');
-
- cfs_lock_file('jobs.cfg', undef, sub {
- my $data = cfs_read_file('jobs.cfg');
-
- die "Job '$id' already exists\n"
- if $data->{ids}->{$id};
-
- my $plugin = PVE::Job::Registry->lookup('realm-sync');
- my $opts = $plugin->check_config($id, $param, 1, 1);
-
- my $realm = $opts->{realm};
- my $cfg = cfs_read_file('domains.cfg');
-
- raise_param_exc({ realm => "No such realm '$realm'" })
- if !defined($cfg->{ids}->{$realm});
-
- my $realm_type = $cfg->{ids}->{$realm}->{type};
- raise_param_exc({ realm => "Only LDAP/AD realms can be synced." })
- if $realm_type ne 'ldap' && $realm_type ne 'ad';
-
- $data->{ids}->{$id} = $opts;
-
- cfs_write_file('jobs.cfg', $data);
- });
- die "$@" if ($@);
-
- return undef;
- }});
-
-__PACKAGE__->register_method({
- name => 'update_job',
- path => '{id}',
- method => 'PUT',
- protected => 1,
- description => "Update realm-sync job definition.",
- permissions => {
- description => "'Realm.AllocateUser' on '/access/realm/<realm>' and 'User.Modify'"
- ." permissions to '/access/groups/'.",
- check => [ 'and',
- ['perm', '/access/realm/{realm}', ['Realm.AllocateUser']],
- ['perm', '/access/groups', ['User.Modify']],
- ],
- },
- parameters => PVE::Jobs::RealmSync->updateSchema(),
- returns => { type => 'null' },
- code => sub {
- my ($param) = @_;
-
- my $id = extract_param($param, 'id');
- my $delete = extract_param($param, 'delete');
- $delete = [PVE::Tools::split_list($delete)] if $delete;
-
- die "no job options specified\n" if !scalar(keys %$param);
-
- cfs_lock_file('jobs.cfg', undef, sub {
- my $jobs = cfs_read_file('jobs.cfg');
-
- my $plugin = PVE::Job::Registry->lookup('realm-sync');
- my $opts = $plugin->check_config($id, $param, 0, 1);
-
- my $job = $jobs->{ids}->{$id};
- die "no such realm-sync job\n" if !$job || $job->{type} ne 'realm-sync';
-
- my $options = $plugin->options();
- PVE::SectionConfig::delete_from_config($job, $options, $opts, $delete);
-
- $job->{$_} = $param->{$_} for keys $param->%*;
-
- cfs_write_file('jobs.cfg', $jobs);
-
- return;
- });
- die "$@" if ($@);
- }});
-
-
-__PACKAGE__->register_method({
- name => 'delete_job',
- path => '{id}',
- method => 'DELETE',
- description => "Delete realm-sync job definition.",
- permissions => {
- check => ['perm', '/', ['Sys.Modify']],
- },
- protected => 1,
- parameters => {
- additionalProperties => 0,
- properties => {
- id => {
- type => 'string',
- format => 'pve-configid',
- },
- },
- },
- returns => { type => 'null' },
- code => sub {
- my ($param) = @_;
-
- my $id = $param->{id};
-
- cfs_lock_file('jobs.cfg', undef, sub {
- my $jobs = cfs_read_file('jobs.cfg');
-
- if (!defined($jobs->{ids}->{$id}) || $jobs->{ids}->{$id}->{type} ne 'realm-sync') {
- raise_param_exc({ id => "No such job '$id'" });
- }
- delete $jobs->{ids}->{$id};
-
- cfs_write_file('jobs.cfg', $jobs);
- PVE::Jobs::RealmSync::save_state($id, undef);
- });
- die "$@" if $@;
-
- return undef;
- }});
-
-1;
--- /dev/null
+SOURCES = \
+ RealmSync.pm \
+
+.PHONY: install
+install:
+ for i in $(SOURCES); do install -D -m 0644 $$i $(DESTDIR)$(PERLDIR)/PVE/API2/Jobs/$$i; done
--- /dev/null
+package PVE::API2::Jobs::RealmSync;
+
+use strict;
+use warnings;
+
+use PVE::Cluster qw(cfs_lock_file cfs_read_file cfs_write_file);
+use PVE::Exception qw(raise_param_exc);
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Job::Registry ();
+use PVE::SectionConfig ();
+use PVE::Tools qw(extract_param);
+
+use PVE::Jobs::RealmSync ();
+
+use base qw(PVE::RESTHandler);
+
+my $get_cluster_last_run = sub {
+ my ($jobid) = @_;
+
+ my $state = eval { PVE::Jobs::RealmSync::get_state($jobid) };
+ die "error on getting state for '$jobid': $@\n" if $@;
+
+ if (my $upid = $state->{upid}) {
+ if (my $decoded = PVE::Tools::upid_decode($upid)) {
+ return $decoded->{starttime};
+ }
+ } else {
+ return $state->{time};
+ }
+
+ return undef;
+};
+
+__PACKAGE__->register_method ({
+ name => 'syncjob_index',
+ path => '',
+ method => 'GET',
+ description => "List configured realm-sync-jobs.",
+ permissions => {
+ check => ['perm', '/', ['Sys.Audit']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {},
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => {
+ id => {
+ description => "The ID of the entry.",
+ type => 'string'
+ },
+ enabled => {
+ description => "If the job is enabled or not.",
+ type => 'boolean',
+ },
+ comment => {
+ description => "A comment for the job.",
+ type => 'string',
+ optional => 1,
+ },
+ schedule => {
+ description => "The configured sync schedule.",
+ type => 'string',
+ },
+ realm => get_standard_option('realm'),
+ scope => get_standard_option('sync-scope'),
+ 'remove-vanished' => get_standard_option('sync-remove-vanished'),
+ 'last-run' => {
+ description => "Last execution time of the job in seconds since the beginning of the UNIX epoch",
+ type => 'integer',
+ optional => 1,
+ },
+ 'next-run' => {
+ description => "Next planned execution time of the job in seconds since the beginning of the UNIX epoch.",
+ type => 'integer',
+ optional => 1,
+ },
+ },
+ },
+ links => [ { rel => 'child', href => "{id}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $user = $rpcenv->get_user();
+
+ my $jobs_data = cfs_read_file('jobs.cfg');
+ my $order = $jobs_data->{order};
+ my $jobs = $jobs_data->{ids};
+
+ my $res = [];
+ for my $jobid (sort { $order->{$a} <=> $order->{$b} } keys %$jobs) {
+ my $job = $jobs->{$jobid};
+ next if $job->{type} ne 'realm-sync';
+
+ $job->{id} = $jobid;
+ if (my $schedule = $job->{schedule}) {
+ $job->{'last-run'} = eval { $get_cluster_last_run->($jobid) };
+ my $last_run = $job->{'last-run'} // time(); # current time as fallback
+
+ my $calendar_event = Proxmox::RS::CalendarEvent->new($schedule);
+ my $next_run = $calendar_event->compute_next_event($last_run);
+ $job->{'next-run'} = $next_run if defined($next_run);
+ }
+
+ push @$res, $job;
+ }
+
+ return $res;
+ }});
+
+__PACKAGE__->register_method({
+ name => 'read_job',
+ path => '{id}',
+ method => 'GET',
+ description => "Read realm-sync job definition.",
+ permissions => {
+ check => ['perm', '/', ['Sys.Audit']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ id => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ },
+ },
+ returns => {
+ type => 'object',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $jobs = cfs_read_file('jobs.cfg');
+ my $id = $param->{id};
+ my $job = $jobs->{ids}->{$id};
+ return $job if $job && $job->{type} eq 'realm-sync';
+
+ raise_param_exc({ id => "No such job '$id'" });
+
+ }});
+
+__PACKAGE__->register_method({
+ name => 'create_job',
+ path => '{id}',
+ method => 'POST',
+ protected => 1,
+ description => "Create new realm-sync job.",
+ permissions => {
+ description => "'Realm.AllocateUser' on '/access/realm/<realm>' and "
+ ."'User.Modify' permissions to '/access/groups/'.",
+ check => [ 'and',
+ ['perm', '/access/realm/{realm}', ['Realm.AllocateUser']],
+ ['perm', '/access/groups', ['User.Modify']],
+ ],
+ },
+ parameters => PVE::Jobs::RealmSync->createSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'id');
+
+ cfs_lock_file('jobs.cfg', undef, sub {
+ my $data = cfs_read_file('jobs.cfg');
+
+ die "Job '$id' already exists\n"
+ if $data->{ids}->{$id};
+
+ my $plugin = PVE::Job::Registry->lookup('realm-sync');
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ my $realm = $opts->{realm};
+ my $cfg = cfs_read_file('domains.cfg');
+
+ raise_param_exc({ realm => "No such realm '$realm'" })
+ if !defined($cfg->{ids}->{$realm});
+
+ my $realm_type = $cfg->{ids}->{$realm}->{type};
+ raise_param_exc({ realm => "Only LDAP/AD realms can be synced." })
+ if $realm_type ne 'ldap' && $realm_type ne 'ad';
+
+ $data->{ids}->{$id} = $opts;
+
+ cfs_write_file('jobs.cfg', $data);
+ });
+ die "$@" if ($@);
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method({
+ name => 'update_job',
+ path => '{id}',
+ method => 'PUT',
+ protected => 1,
+ description => "Update realm-sync job definition.",
+ permissions => {
+ description => "'Realm.AllocateUser' on '/access/realm/<realm>' and 'User.Modify'"
+ ." permissions to '/access/groups/'.",
+ check => [ 'and',
+ ['perm', '/access/realm/{realm}', ['Realm.AllocateUser']],
+ ['perm', '/access/groups', ['User.Modify']],
+ ],
+ },
+ parameters => PVE::Jobs::RealmSync->updateSchema(),
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'id');
+ my $delete = extract_param($param, 'delete');
+ $delete = [PVE::Tools::split_list($delete)] if $delete;
+
+ die "no job options specified\n" if !scalar(keys %$param);
+
+ cfs_lock_file('jobs.cfg', undef, sub {
+ my $jobs = cfs_read_file('jobs.cfg');
+
+ my $plugin = PVE::Job::Registry->lookup('realm-sync');
+ my $opts = $plugin->check_config($id, $param, 0, 1);
+
+ my $job = $jobs->{ids}->{$id};
+ die "no such realm-sync job\n" if !$job || $job->{type} ne 'realm-sync';
+
+ my $options = $plugin->options();
+ PVE::SectionConfig::delete_from_config($job, $options, $opts, $delete);
+
+ $job->{$_} = $param->{$_} for keys $param->%*;
+
+ cfs_write_file('jobs.cfg', $jobs);
+
+ return;
+ });
+ die "$@" if ($@);
+ }});
+
+
+__PACKAGE__->register_method({
+ name => 'delete_job',
+ path => '{id}',
+ method => 'DELETE',
+ description => "Delete realm-sync job definition.",
+ permissions => {
+ check => ['perm', '/', ['Sys.Modify']],
+ },
+ protected => 1,
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ id => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ },
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = $param->{id};
+
+ cfs_lock_file('jobs.cfg', undef, sub {
+ my $jobs = cfs_read_file('jobs.cfg');
+
+ if (!defined($jobs->{ids}->{$id}) || $jobs->{ids}->{$id}->{type} ne 'realm-sync') {
+ raise_param_exc({ id => "No such job '$id'" });
+ }
+ delete $jobs->{ids}->{$id};
+
+ cfs_write_file('jobs.cfg', $jobs);
+ PVE::Jobs::RealmSync::save_state($id, undef);
+ });
+ die "$@" if $@;
+
+ return undef;
+ }});
+
+1;
TFA.pm \
OpenId.pm
-SUBDIRS=AccessControl
+SUBDIRS = Jobs
.PHONY: install
install: