source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts.pm @ 2256

Last change on this file since 2256 was 2243, checked in by nanardon, 5 years ago

Improve schema upgrade procedure

  • Property svn:keywords set to Id Rev
File size: 7.6 KB
Line 
1package LATMOS::Accounts;
2
3use 5.010000;
4use strict;
5use warnings;
6use base qw(Config::IniFiles);
7use LATMOS::Accounts::Bases;
8use LATMOS::Accounts::Synchro;
9use LATMOS::Accounts::SynchAccess;
10use LATMOS::Accounts::Log;
11use LATMOS::Accounts::Acls;
12use LATMOS::Accounts::I18N;
13
14our $VERSION = '6.0.0';
15
16binmode(STDOUT, ":utf8");
17binmode(STDERR, ":utf8");
18
19=head1 NAME
20
21LATMOS::Accounts - Core module for LATMOS account management tools
22
23=head1 DESCRITPTION
24
25=cut
26
27# Return the configuration directory according settings:
28#
29sub _configdir {
30   my ($self) = @_;
31   $ENV{LA_CONFIG} ||
32   ($self || {})->{_configdir} ||
33   '/etc/latmos-accounts'
34}
35
36=head1 FUNCTION
37
38=head2 new($configdir, %options)
39
40Instanciate a new LATMOS::Accounts object.
41
42C<$configdir> if defined is the directory containing files to use,
43default to F</etc/latmos-accounts/>.
44
45C<%options> can contains:
46
47=over 4
48
49=item noacl
50
51If true, acls configuration are not load and code act like everything is
52allowed.
53
54This flag is usefull for administrative tools, for which no acl must apply.
55
56=back
57
58=cut
59
60sub new {
61    my ($class, $config, %options) = @_;
62
63    $config ||= _configdir();
64
65    my $configfile = join('/', $config, 'latmos-accounts.ini');
66
67    my $self = Config::IniFiles->new(
68        -file => $configfile,
69        '-default' => '_default_',
70    ) or do {
71        la_log(LA_ERR, 'Can\'t open main config file %s', $configfile);
72        return;
73    };
74
75    $self->{_configdir} = $config;
76    bless($self, $class);
77
78    unless ($options{noacl}) {
79        if (-f (my $aclf = join('/', $self->_configdir, 'la-acls.ini'))) {
80            $self->{_acls} = LATMOS::Accounts::Acls->new($aclf) or do {
81                la_log(LA_ERR, 'Cannot load ACL file %s', $aclf);
82                return;
83            };
84        }
85    }
86
87    if (-f (my $allowf = join('/', $self->_configdir, 'la-allowed-values.ini'))) {
88        $self->{_allowed_values} = Config::IniFiles->new(
89            -file => $allowf,
90        ) or do {
91            la_log(LA_ERR, 'Cannot load ALLOWED VALUES %s', $allowf);
92            return;
93        };
94    }
95
96    $self
97}
98
99=head2 list_bases
100
101Return the base list found in config file
102
103=cut
104
105sub list_bases {
106    my ($self) = @_;
107    grep {
108        !m/^_.*_$/ &&
109        !m/^sync:/
110    } $self->Sections
111}
112
113=head2 default_base_name
114
115Return the default base name according config file
116
117=cut
118
119sub default_base_name {
120    my ($self) = @_;
121    $self->val('_default_', 'base', ($self->list_bases)[0]);
122}
123
124=head2 base($basename)
125
126Return a L<LATMOS::Accounts::Base> object over base named $basename
127defined in the config file.
128
129The base is loaded by this function.
130
131=cut
132
133sub base {
134    my ($self, $section) = @_;
135    # this method perform a cache
136    my $base = $self->_load_base($section || $self->default_base_name);
137
138    $base->load or do {
139        la_log(LA_ERR, "%s didn't load", $base->label);
140        return;
141    };
142    $base;
143}
144
145# do the bad work
146sub _load_base {
147    my ($self, $section) = @_;
148    my $type = $self->val($section, 'type') or return;
149    la_log(LA_DEBUG, "Trying to load base %s", $section);
150
151    my %params =
152        map { $_ => ($self->val($section, $_)) }
153        ($self->Parameters($section), $self->Parameters('_default_'));
154 
155    my %defattr =
156        map { $_ => ($self->val('_defattr_', $_)) }
157        $self->Parameters('_defattr_');
158
159    my $base = LATMOS::Accounts::Bases->new(
160        $type,
161        {
162            params => \%params,
163            label => $section,
164            acls => $self->{_acls},
165            allowed_values => $self->{_allowed_values},
166            configdir => $self->_configdir,
167            la => $self,
168            defattr => { %defattr },
169        },
170    ) or do {
171        la_log(LA_WARN, "Cannot instanciate base $section ($type)");
172        return;
173    };
174}
175
176=head2 list_synchro
177
178List synchronisation setup in L<latmos-accounts.ini>
179
180=cut
181
182sub list_synchro {
183    my ($self) = @_;
184    grep { $_ } map { /^sync:(.*)$/; $1 } $self->Sections
185}
186
187=head2 default_synchro_name
188
189Return de default synchronisation name
190
191=cut
192
193sub default_synchro_name {
194    my ($self) = @_;
195    $self->val('_default_', 'sync');
196}
197
198=head2 default_synchro
199
200Return a reference to default synchronisation object
201
202=cut
203
204sub default_synchro {
205    my ($self, %options) = @_;
206    my $syncname = $self->default_synchro_name or do {
207        la_log(LA_ERR, 'Cannot find default synchro in config');
208        return;
209    };
210    $self->create_synchro($syncname, %options);
211}
212
213=head2 create_synchro($name, %options)
214
215Return a reference to synchronisation object for C<$name> synchronisation.
216
217=cut
218
219sub create_synchro {
220    my ($self, $name, %options) = @_;
221
222    # taking options from config
223    if ($name) {
224        foreach my $param ($self->Parameters("sync:$name")) {
225            if (!defined($options{$param})) {
226                my @args = $self->val("sync:$name", $param);
227                $options{$param} = ($args[1] || $param eq 'to')
228                    ? [ @args ]
229                    : $args[0];
230            }
231        }
232    }
233
234    my $labfrom = $options{from} ? $self->base($options{from}) : $self->base;
235
236    my @labto =
237        grep { $_ }
238        map { $self->base($_) }
239        @{ $options{to} || []}
240        or do {
241        la_log(LA_ERR, "No destination base load in this synchro");
242        return;
243    };
244
245    my $sync = LATMOS::Accounts::Synchro->new(
246        $labfrom, [ @labto ],
247        state_dir => ($self->val('_default_', 'state_dir') || undef),
248        %options,
249        name => $name,
250    );
251}
252
253sub _sync_from_name {
254    my ($self, $syncname) = @_;
255    return if (!$syncname);
256    $self->val("sync:$syncname", 'from', $self->default_base_name);
257}
258
259=head2 sync_access($name, %options)
260
261Return a L<LATMOS::Accounts::SynchAccess> object over C<$name> synchronisation.
262
263=cut
264
265sub sync_access {
266    my ($self, $name, %options) = @_;
267
268    my @obases;
269    if ($name) {
270        @obases =
271        (map { $self->base($_) } ($self->_sync_from_name($name), $self->val("sync:$name", 'to')));
272    } elsif(@{ $options{bases} || []}) {
273        @obases = map { $self->base($_) } @{ $options{bases} || []};
274    } elsif (my $sname = $self->default_synchro_name) {
275        @obases = (map { $self->base($_) }
276            ($self->_sync_from_name($sname), $self->val("sync:$sname", 'to'))
277        );
278    }
279
280    if (!@obases) {
281        la_log(LA_ERR, "Cannot load any bases for syncronised action");
282        return;
283    }
284
285    la_log(LA_DEBUG, "Load databases: %s", join(', ', map { $_->label } @obases));
286
287    LATMOS::Accounts::SynchAccess->new([ @obases ]);
288}
289
290=head2 call_batch_sync
291
292Send signal to L<la-sync-manager> daemon to synchronize bases.
293
294=cut
295
296sub call_batch_sync {
297    my ($self) = @_;
298    if (my $sd = $self->val('_default_', 'state_dir')) {
299        if (open(my $fh, '<', $sd . '/sync-manager.pid')) {
300            my $pid = <$fh> || '';
301            chomp($pid);
302            close($fh);
303            if ($pid && kill 1, $pid) {
304                return 1; # \o/ we succeed
305            } else {
306                la_log(LA_ERR, "Can send signal -1 to la-sync-manager (pid: %s, %s)",
307                    $pid || 'none', $!);
308                return;
309            }
310        } else {
311            la_log(LA_ERR, 'Cannot open la-sync-manager pid file');
312            return;
313        }
314    } else {
315        la_log(LA_WARN, "No statedir setup, cannot find la-sync-manager pid file");
316        return;
317    }
318}
319
3201;
321
322__END__
323
324=head1 AUTHOR
325
326Thauvin Olivier, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
327
328=head1 COPYRIGHT AND LICENSE
329
330Copyright (C) 2009, 2010, 2011, 2012 by Thauvin Olivier
331
332This library is free software; you can redistribute it and/or modify
333it under the same terms as Perl itself, either Perl version 5.10.0 or,
334at your option, any later version of Perl 5 you may have available.
335
336=cut
Note: See TracBrowser for help on using the repository browser.