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

Last change on this file since 2358 was 2320, checked in by nanardon, 4 years ago

Add LA_ACL_DEBUG env. var.

  • Property svn:keywords set to Id Rev
File size: 7.9 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.1.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} || $ENV{LA_USERNAME}) {
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
137    my $basename = $section || $self->default_base_name;
138
139    my $base = $self->_load_base($basename) or do {
140        la_log(LA_ERR, "%s didn't load", $basename);
141        return;
142    };
143
144    $base->load or do {
145        la_log(LA_ERR, "%s didn't load", $base->label);
146        return;
147    };
148    $base;
149}
150
151# do the bad work
152sub _load_base {
153    my ($self, $section) = @_;
154    my $type = $self->val($section, 'type') or return;
155    la_log(LA_DEBUG, "Trying to load base %s", $section);
156
157    my %params =
158        map { $_ => ($self->val($section, $_)) }
159        ($self->Parameters($section), $self->Parameters('_default_'));
160 
161    my %defattr =
162        map { $_ => ($self->val('_defattr_', $_)) }
163        $self->Parameters('_defattr_');
164
165    $params{monitored} = {};
166    foreach my $item ($self->val($section, 'monitored')) {
167        $params{monitored}{lc($item)} = 1;
168    }
169
170    my $base = LATMOS::Accounts::Bases->new(
171        $type,
172        {
173            params => \%params,
174            label => $section,
175            acls => $self->{_acls},
176            allowed_values => $self->{_allowed_values},
177            configdir => $self->_configdir,
178            la => $self,
179            defattr => { %defattr },
180        },
181    ) or do {
182        la_log(LA_WARN, "Cannot instanciate base $section ($type)");
183        return;
184    };
185}
186
187=head2 list_synchro
188
189List synchronisation setup in L<latmos-accounts.ini>
190
191=cut
192
193sub list_synchro {
194    my ($self) = @_;
195    grep { $_ } map { /^sync:(.*)$/; $1 } $self->Sections
196}
197
198=head2 default_synchro_name
199
200Return de default synchronisation name
201
202=cut
203
204sub default_synchro_name {
205    my ($self) = @_;
206    $self->val('_default_', 'sync');
207}
208
209=head2 default_synchro
210
211Return a reference to default synchronisation object
212
213=cut
214
215sub default_synchro {
216    my ($self, %options) = @_;
217    my $syncname = $self->default_synchro_name or do {
218        la_log(LA_ERR, 'Cannot find default synchro in config');
219        return;
220    };
221    $self->create_synchro($syncname, %options);
222}
223
224=head2 create_synchro($name, %options)
225
226Return a reference to synchronisation object for C<$name> synchronisation.
227
228=cut
229
230sub create_synchro {
231    my ($self, $name, %options) = @_;
232
233    # taking options from config
234    if ($name) {
235        foreach my $param ($self->Parameters("sync:$name")) {
236            if (!defined($options{$param})) {
237                my @args = $self->val("sync:$name", $param);
238                $options{$param} = ($args[1] || $param eq 'to')
239                    ? [ @args ]
240                    : $args[0];
241            }
242        }
243    }
244
245    my $labfrom = $options{from} ? $self->base($options{from}) : $self->base;
246
247    my @labto =
248        grep { $_ }
249        map { $self->base($_) }
250        @{ $options{to} || []}
251        or do {
252        la_log(LA_ERR, "No destination base load in this synchro");
253        return;
254    };
255
256    my $sync = LATMOS::Accounts::Synchro->new(
257        $labfrom, [ @labto ],
258        state_dir => ($self->val('_default_', 'state_dir') || undef),
259        %options,
260        name => $name,
261    );
262}
263
264sub _sync_from_name {
265    my ($self, $syncname) = @_;
266    return if (!$syncname);
267    $self->val("sync:$syncname", 'from', $self->default_base_name);
268}
269
270=head2 sync_access($name, %options)
271
272Return a L<LATMOS::Accounts::SynchAccess> object over C<$name> synchronisation.
273
274=cut
275
276sub sync_access {
277    my ($self, $name, %options) = @_;
278
279    my @obases;
280    if ($name) {
281        @obases =
282        (map { $self->base($_) } ($self->_sync_from_name($name), $self->val("sync:$name", 'to')));
283    } elsif(@{ $options{bases} || []}) {
284        @obases = map { $self->base($_) } @{ $options{bases} || []};
285    } elsif (my $sname = $self->default_synchro_name) {
286        @obases = (map { $self->base($_) }
287            ($self->_sync_from_name($sname), $self->val("sync:$sname", 'to'))
288        );
289    }
290
291    if (!@obases) {
292        la_log(LA_ERR, "Cannot load any bases for syncronised action");
293        return;
294    }
295
296    la_log(LA_DEBUG, "Load databases: %s", join(', ', map { $_->label } @obases));
297
298    LATMOS::Accounts::SynchAccess->new([ @obases ]);
299}
300
301=head2 call_batch_sync
302
303Send signal to L<la-sync-manager> daemon to synchronize bases.
304
305=cut
306
307sub call_batch_sync {
308    my ($self) = @_;
309    if (my $sd = $self->val('_default_', 'state_dir')) {
310        if (open(my $fh, '<', $sd . '/sync-manager.pid')) {
311            my $pid = <$fh> || '';
312            chomp($pid);
313            close($fh);
314            if ($pid && kill 1, $pid) {
315                return 1; # \o/ we succeed
316            } else {
317                la_log(LA_ERR, "Can send signal -1 to la-sync-manager (pid: %s, %s)",
318                    $pid || 'none', $!);
319                return;
320            }
321        } else {
322            la_log(LA_ERR, 'Cannot open la-sync-manager pid file');
323            return;
324        }
325    } else {
326        la_log(LA_WARN, "No statedir setup, cannot find la-sync-manager pid file");
327        return;
328    }
329}
330
3311;
332
333__END__
334
335=head1 AUTHOR
336
337Thauvin Olivier, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
338
339=head1 COPYRIGHT AND LICENSE
340
341Copyright (C) 2009, 2010, 2011, 2012 by Thauvin Olivier
342
343This library is free software; you can redistribute it and/or modify
344it under the same terms as Perl itself, either Perl version 5.10.0 or,
345at your option, any later version of Perl 5 you may have available.
346
347=cut
Note: See TracBrowser for help on using the repository browser.