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

Last change on this file since 2578 was 2578, checked in by latmossys, 9 months ago
  • Next SVN version
  • Property svn:keywords set to Id Rev
File size: 8.7 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.8.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    $self->{_loguser} = $options{loguser};
77    bless($self, $class);
78
79    unless ($options{noacl}) {
80        if (-f (my $aclf = join('/', $self->_configdir, 'la-acls.ini'))) {
81            $self->{_acls} = LATMOS::Accounts::Acls->new($aclf) or do {
82                la_log(LA_ERR, 'Cannot load ACL file %s', $aclf);
83                return;
84            };
85        }
86    }
87
88    if (-f (my $allowf = join('/', $self->_configdir, 'la-allowed-values.ini'))) {
89        $self->{_allowed_values} = Config::IniFiles->new(
90            -file => $allowf,
91        ) or do {
92            la_log(LA_ERR, 'Cannot load ALLOWED VALUES %s', $allowf);
93            return;
94        };
95    }
96
97    $self
98}
99
100=head2 state_dir
101
102Return state_dir for this instance
103
104=cut
105
106sub state_dir {
107    my ( $self ) = @_;
108
109    return $self->val( '_default_', 'state_dir', '/var/lib/latmos-accounts' );
110}
111
112=head2 list_bases
113
114Return the base list found in config file
115
116=cut
117
118sub list_bases {
119    my ($self) = @_;
120    grep {
121        !m/^_.*_$/ &&
122        !m/^sync:/
123    } $self->Sections
124}
125
126=head2 default_base_name
127
128Return the default base name according config file
129
130=cut
131
132sub default_base_name {
133    my ($self) = @_;
134    $self->val('_default_', 'base', ($self->list_bases)[0]);
135}
136
137=head2 base($basename)
138
139Return a L<LATMOS::Accounts::Base> object over base named $basename
140defined in the config file.
141
142The base is loaded by this function.
143
144=cut
145
146sub base {
147    my ($self, $section) = @_;
148    # this method perform a cache
149
150    my $basename = $section || $self->default_base_name;
151
152    my $base = $self->_load_base($basename) or do {
153        la_log(LA_ERR, "%s didn't load", $basename);
154        return;
155    };
156
157    $base->load or do {
158        la_log(LA_ERR, "%s didn't load", $base->label);
159        return;
160    };
161    $base;
162}
163
164=head2 LogUser
165
166Return the username to use when no user is connected
167
168=cut
169
170sub LogUser {
171    my ( $self, $Login ) = @_;
172
173    my $name = $self->{_loguser} || '@Console';
174
175    if ($Login) {
176        $self->{_loguser} = $Login;
177    }
178
179    return $name;
180}
181
182# do the bad work
183sub _load_base {
184    my ($self, $section) = @_;
185    my $type = $self->val($section, 'type') or return;
186    la_log(LA_DEBUG, "Trying to load base %s", $section);
187
188    my %params = ();
189
190    foreach ( $self->Parameters($section), $self->Parameters('_default_') ) {
191        my @vals = $self->val($section, $_);
192        $params{ $_ } = scalar(@vals) > 1 ? \@vals : $vals[0];
193    }
194 
195    my %defattr = ();
196
197    foreach ( $self->Parameters('_defattr_') ) {
198        my ($val) = $self->val( '_defattr_', $_ );
199        $defattr{ $_ } = $val;
200    }
201
202    if (my $ini = $self->{_allowed_values}) {
203        foreach my $attr ( $ini->Sections ) {
204            if ( my @defaults = $ini->val( $attr, 'default' ) ) {
205                $defattr{ $attr } = @defaults > 1 ? @defaults : $defaults[0];
206            }
207        }
208    }
209
210    $params{monitored} = {};
211    foreach my $item ($self->val($section, 'monitored')) {
212        $params{monitored}{lc($item)} = 1;
213    }
214
215    my $base = LATMOS::Accounts::Bases->new(
216        $type,
217        {
218            params => \%params,
219            label => $section,
220            acls => $self->{_acls},
221            allowed_values => $self->{_allowed_values},
222            configdir => $self->_configdir,
223            la => $self,
224            defattr => { %defattr },
225        },
226    ) or do {
227        la_log(LA_WARN, "Cannot instanciate base $section ($type)");
228        return;
229    };
230}
231
232=head2 list_synchro
233
234List synchronisation setup in L<latmos-accounts.ini>
235
236=cut
237
238sub list_synchro {
239    my ($self) = @_;
240    grep { $_ } map { /^sync:(.*)$/; $1 } $self->Sections
241}
242
243=head2 default_synchro_name
244
245Return de default synchronisation name
246
247=cut
248
249sub default_synchro_name {
250    my ($self) = @_;
251    $self->val('_default_', 'sync');
252}
253
254=head2 default_synchro
255
256Return a reference to default synchronisation object
257
258=cut
259
260sub default_synchro {
261    my ($self, %options) = @_;
262    my $syncname = $self->default_synchro_name or do {
263        la_log(LA_ERR, 'Cannot find default synchro in config');
264        return;
265    };
266    $self->create_synchro($syncname, %options);
267}
268
269=head2 create_synchro($name, %options)
270
271Return a reference to synchronisation object for C<$name> synchronisation.
272
273=cut
274
275sub create_synchro {
276    my ($self, $name, %options) = @_;
277
278    # taking options from config
279    if ($name) {
280        foreach my $param ($self->Parameters("sync:$name")) {
281            if (!defined($options{$param})) {
282                my @args = $self->val("sync:$name", $param);
283                $options{$param} = ($args[1] || $param eq 'to')
284                    ? [ @args ]
285                    : $args[0];
286            }
287        }
288    }
289
290    my $labfrom = $options{from} ? $self->base($options{from}) : $self->base;
291
292    my @labto =
293        grep { $_ }
294        map { $self->base($_) }
295        @{ $options{to} || []}
296        or do {
297        la_log(LA_ERR, "No destination base load in this synchro");
298        return;
299    };
300
301    my $sync = LATMOS::Accounts::Synchro->new(
302        $labfrom, [ @labto ],
303        state_dir => $self->state_dir,
304        %options,
305        name => $name,
306    );
307}
308
309sub _sync_from_name {
310    my ($self, $syncname) = @_;
311    return if (!$syncname);
312    $self->val("sync:$syncname", 'from', $self->default_base_name);
313}
314
315=head2 sync_access($name, %options)
316
317Return a L<LATMOS::Accounts::SynchAccess> object over C<$name> synchronisation.
318
319=cut
320
321sub sync_access {
322    my ($self, $name, %options) = @_;
323
324    my @obases;
325    if ($name) {
326        @obases =
327        (map { $self->base($_) } ($self->_sync_from_name($name), $self->val("sync:$name", 'to')));
328    } elsif(@{ $options{bases} || []}) {
329        @obases = map { $self->base($_) } @{ $options{bases} || []};
330    } elsif (my $sname = $self->default_synchro_name) {
331        @obases = (map { $self->base($_) }
332            ($self->_sync_from_name($sname), $self->val("sync:$sname", 'to'))
333        );
334    }
335
336    if (!@obases) {
337        la_log(LA_ERR, "Cannot load any bases for syncronised action");
338        return;
339    }
340
341    la_log(LA_DEBUG, "Load databases: %s", join(', ', map { $_->label } @obases));
342
343    LATMOS::Accounts::SynchAccess->new([ @obases ]);
344}
345
346=head2 call_batch_sync
347
348Send signal to L<la-sync-manager> daemon to synchronize bases.
349
350=cut
351
352sub call_batch_sync {
353    my ($self) = @_;
354    if (my $sd = $self->state_dir) {
355        if (open(my $fh, '<', $sd . '/sync-manager.pid')) {
356            my $pid = <$fh> || '';
357            chomp($pid);
358            close($fh);
359            if ($pid && kill 1, $pid) {
360                return 1; # \o/ we succeed
361            } else {
362                la_log(LA_ERR, "Can send signal -1 to la-sync-manager (pid: %s, %s)",
363                    $pid || 'none', $!);
364                return;
365            }
366        } else {
367            la_log(LA_ERR, 'Cannot open la-sync-manager pid file');
368            return;
369        }
370    } else {
371        la_log(LA_WARN, "No statedir setup, cannot find la-sync-manager pid file");
372        return;
373    }
374}
375
3761;
377
378__END__
379
380=head1 AUTHOR
381
382Thauvin Olivier, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
383
384=head1 COPYRIGHT AND LICENSE
385
386Copyright (C) 2009, 2010, 2011, 2012 by Thauvin Olivier
387
388This library is free software; you can redistribute it and/or modify
389it under the same terms as Perl itself, either Perl version 5.10.0 or,
390at your option, any later version of Perl 5 you may have available.
391
392=cut
Note: See TracBrowser for help on using the repository browser.