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

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