source: ocsinventory-agent/trunk/fuentes/lib/Ocsinventory/Agent.pm @ 468

Last change on this file since 468 was 468, checked in by mabarracus, 4 years ago

Copyt trusty code

File size: 14.6 KB
Line 
1#!/usr/bin/perl
2
3package Ocsinventory::Agent;
4
5use strict;
6use warnings;
7
8# THIS IS AN UGLY WORKAROUND FOR
9# http://rt.cpan.org/Ticket/Display.html?id=38067
10use XML::Simple;
11
12eval {XMLout("<a>b</a>");};
13if ($@){
14    no strict 'refs';
15    ${*{"XML::SAX::"}{HASH}{'parsers'}} = sub {
16        return [ {
17            'Features' => {
18                'http://xml.org/sax/features/namespaces' => '1'
19            },
20            'Name' => 'XML::SAX::PurePerl'
21        }
22        ]
23    };
24}
25# END OF THE UGLY FIX!
26
27require Exporter;
28
29use Ocsinventory::Logger;
30use Ocsinventory::Agent::XML::Inventory;
31use Ocsinventory::Agent::XML::Prolog;
32
33use Ocsinventory::Agent::Network;
34use Ocsinventory::Agent::Backend;
35use Ocsinventory::Agent::AccountConfig;
36use Ocsinventory::Agent::AccountInfo;
37use Ocsinventory::Agent::Config;
38
39use Ocsinventory::Agent::Hooks;
40#use Ocsinventory::Agent::Pid;
41use Ocsinventory::Agent::Common;
42
43sub run {
44
45        # Load setting from the config file
46    my $config = new Ocsinventory::Agent::Config;
47
48
49        #$params->{$_} = $config->{$_} foreach (keys %$config);
50
51    $ENV{LC_ALL} = 'C'; # Turn off localised output for commands
52    $ENV{LANG} = 'C'; # Turn off localised output for commands
53
54
55        #####################################
56        ################ MAIN ###############
57        #####################################
58
59
60        ############################
61        #### CLI parameters ########
62        ############################
63        $config->loadUserParams();
64
65        # I close STDERR to avoid error message during the module execution
66        # at the begining I was doing shell redirection:
67        #  my @ret = `cmd 2> /dev/null`;
68        # but this syntax is not supported on (at least) FreeBSD and Solaris
69        # c.f: http://www.perlmonks.org/?node_id=571072
70        #my $tmp;
71        #open ($tmp, ">&STDERR");
72        #$params->{"savedstderr"} = $tmp;
73        #if($params->{debug}) {
74        #  $params->{verbose} = 1;
75        #} else {
76        #  close(STDERR);
77        #}
78
79    if ($config->{config}{logfile}) {
80        $config->{config}{logger} = 'File';
81    }
82
83    my $logger = new Ocsinventory::Logger ({
84            config => $config->{config}
85    });
86
87    my $common = new Ocsinventory::Agent::Common({
88            logger => $logger,
89            config => $config->{config},
90    }); 
91
92        # $< == $REAL_USER_ID
93    if ( $< ne '0' ) {
94        $logger->info("You should run this program as super-user.");
95    }
96
97    if (not $config->{config}{scanhomedirs}) {
98        $logger->debug("--scan-homedirs missing. Don't scan user directories");
99    }
100
101    if ($config->{config}{nosoft}) {
102        $logger->info("the parameter --nosoft is deprecated and may be removed in a future release, please use --nosoftware instead.");
103        $config->{config}{nosoftware} = 1
104    }
105
106   # desactivate local mode even if it is set in config file or command line
107   if (defined($config->{config}{nolocal})) {
108       undef $config->{config}{'local'};
109   }
110
111
112        # TODO put that in Ocsinventory::Agent::Config
113    if (!$config->{config}{'stdout'} && !$config->{config}{'local'} && $config->{config}{server} !~ /^http(|s):\/\//) {
114        $logger->debug("the --server passed doesn't have a protocol, assume http as default");
115        $config->{config}{server} = "http://".$config->{config}{server}.'/ocsinventory';
116    }
117
118
119######################## Objects initilisation ###############################################################
120
121# The agent can contact different servers. Each server accountconfig is
122# stored in a specific file:
123    if (!recMkdir ($config->{config}{basevardir})) {
124
125        if (! -d $ENV{HOME}."/.ocsinventory/var") {
126            $logger->info("Failed to create ".$config->{config}{basevardir}." directory: $!. ".
127                "I'm going to use the home directory instead (~/.ocsinventory/var).");
128        }
129
130        $config->{config}{basevardir} = $ENV{HOME}."/.ocsinventory/var";
131        if (!recMkdir ($config->{config}{basevardir})) {
132            $logger->error("Failed to create ".$config->{config}{basedir}." directory: $!".
133                "The HOSTID will not be written on the harddrive. You may have duplicated ".
134                "entry of this computer in your OCS database");
135        }
136        $logger->debug("var files are stored in ".$config->{config}{basevardir});
137    }
138
139    if (defined($config->{config}{server}) && $config->{config}{server}) {
140        my $dir = $config->{config}{server};
141        $dir =~ s/\//_/g;
142        $config->{config}{vardir} = $config->{config}{basevardir}."/".$dir;
143        if (defined ($config->{config}{local}) && $config->{config}{local}) {
144            $logger->debug ("--server ignored since you also use --local");
145            $config->{config}{server} = undef;
146        }
147    } elsif (defined($config->{config}{local}) && $config->{config}{local}) {
148        $config->{config}{vardir} = $config->{config}{basevardir}."/__LOCAL__";
149    }
150
151    if (!recMkdir ($config->{config}{vardir})) {
152        $logger->error("Failed to create ".$config->{config}{vardir}." directory: $!");
153    }
154
155    if (-d $config->{config}{vardir}) {
156        $config->{config}{accountconfig} = $config->{config}{vardir}."/ocsinv.conf";
157        $config->{config}{accountinfofile} = $config->{config}{vardir}."/ocsinv.adm";
158        $config->{config}{last_statefile} = $config->{config}{vardir}."/last_state";
159        $config->{config}{next_timefile} = $config->{config}{vardir}."/next_timefile";
160    }
161
162################################################################################################################
163
164
165##########################  load CFG files ######################################################################
166
167    my $accountconfig = new Ocsinventory::Agent::AccountConfig({
168            logger => $logger,
169            config => $config->{config},
170        });
171
172    my $srv = $accountconfig->get('OCSFSERVER');
173    $config->{config}{server} = $srv if $srv;
174    $config->{config}{deviceid}   = $accountconfig->get('DEVICEID');
175
176        # Should I create a new deviceID?
177    chomp(my $hostname = `uname -n| cut -d . -f 1`);
178    if ((!$config->{config}{deviceid}) || $config->{config}{deviceid} !~ /\Q$hostname\E-(?:\d{4})(?:-\d{2}){5}/) {
179        my ($YEAR, $MONTH , $DAY, $HOUR, $MIN, $SEC) = (localtime(time))[5,4,3,2,1,0];
180
181        $config->{config}{old_deviceid} = $config->{config}{deviceid};
182        $config->{config}{deviceid} =sprintf "%s-%02d-%02d-%02d-%02d-%02d-%02d",
183        $hostname, ($YEAR+1900), ($MONTH+1), $DAY, $HOUR, $MIN, $SEC;
184        $accountconfig->set('DEVICEID',$config->{config}{deviceid});
185    }
186
187    my $accountinfo = new Ocsinventory::Agent::AccountInfo({
188            logger => $logger,
189            # TODOparams => $params,
190            config => $config->{config},
191            common => $common,
192        });
193
194        # --lazy
195    if ($config->{config}{lazy}) {
196        my $nexttime = (stat($config->{config}{next_timefile}))[9];
197
198        if ($nexttime && $nexttime > time) {
199            $logger->info("[Lazy] Must wait until ".localtime($nexttime)." exiting...");
200            exit 0;
201        }
202    }
203
204    if ($config->{config}{daemon}) {
205
206        $logger->debug("Time to call Proc::Daemon");
207        eval { require Proc::Daemon; };
208        if ($@) {
209            print "Can't load Proc::Daemon. Is the module installed?";
210            exit 1;
211        }
212        Proc::Daemon::Init();
213        $logger->debug("Daemon started");
214        if (isAgentAlreadyRunning({
215                    logger => $logger,
216                })) {
217            $logger->debug("An agent is already runnnig, exiting...");
218            exit 1;
219        }
220
221    }
222   
223    $logger->debug("OCS Agent initialised");
224
225################# Now we can create a context hash #########################################################
226
227    my $context = {
228      installpath => $config->{config}->{vardir},
229      servername => $config->{config}->{server},
230      authuser => $config->{config}->{user},
231      authpwd => $config->{config}->{password},
232      authrealm => $config->{config}->{realm},
233      deviceid => $config->{config}->{deviceid},
234      version => $config->{VERSION},
235      config => $config->{config},
236      accountconfig => $accountconfig,
237      accountinfo => $accountinfo,
238      logger => $logger,
239      common => $common,
240      #OCS_AGENT_CMDL => "TOTO", # TODO cmd line parameter changed with the unified agent
241    };
242
243################################# HERE WE GO !!! ###################################################
244    while (1) {
245
246        my $exitcode = 0;
247        my $wait;
248        if ($config->{config}{daemon} || $config->{config}{wait}) {
249            my $serverdelay;
250            if(($config->{config}{wait} eq 'server') || ($config->{config}{wait}!~/^\d+$/)){
251                $serverdelay = $accountconfig->get('PROLOG_FREQ')*3600;
252            }
253            else{
254                $serverdelay = $config->{config}{wait};
255            }
256            $wait = int rand($serverdelay?$serverdelay:$config->{config}{delaytime});
257            $logger->info("Going to sleep for $wait second(s)");
258            sleep ($wait);
259
260        }
261
262
263        # Create an hook object to use handlers of modules.
264        my $hooks = new Ocsinventory::Agent::Hooks($context);
265
266
267        #Using start_handler hook       
268        $hooks->run({name => 'start_handler'});
269               
270
271
272        #################### Local Mode #######################
273        if ($config->{config}{stdout} || $config->{config}{local}) {
274
275            # TODO, avoid to create Backend at two different places
276            my $backend = new Ocsinventory::Agent::Backend ({
277                    context => $context,
278            });
279
280
281            my $inventory = new Ocsinventory::Agent::XML::Inventory ({
282                    # TODO, check if the accoun{info,config} are needed in localmode
283                    backend => $backend,
284                    context => $context,
285            });
286
287            #Launching inventory
288            $inventory->initialise();
289
290            #Using inventory_writer hook
291            $hooks->run({name => 'inventory_handler'}, $inventory);
292
293            if ($config->{config}{stdout}) {
294                $inventory->printXML();
295            } elsif ($config->{config}{local}) {
296                $inventory->writeXML();
297            }
298        } 
299        else { 
300
301            ############ I've to contact the server ########################"
302            my $network = new Ocsinventory::Agent::Network ({
303                    accountconfig => $accountconfig,
304                    accountinfo => $accountinfo,
305                    logger => $logger,
306                    config => $config->{config},
307                    common => $common,
308            });
309
310            #Adding the network object in $context
311            $context->{network}= $network;
312
313            my $sendInventory = 1;
314            my $httpresp;
315            my $prologresp;
316
317            if (!$config->{config}{force}) {
318                my $prolog = new Ocsinventory::Agent::XML::Prolog({
319                       context => $context,
320                });
321
322                #Using prolog_writer hook
323                $hooks->run({name => 'prolog_writer'}, $prolog);
324
325                #Formatting the XML
326                my $prologXML = $prolog->getContent(); 
327
328                $httpresp = $network->sendXML({message => $prologXML});
329                $prologresp = $network->getXMLResp($httpresp,'Prolog');
330
331                if ($prologresp) {
332                  #Using prolog_reader hook
333                  $hooks->run({name => 'prolog_reader'}, $prologresp->getRawXML());
334
335                  if (!$prologresp->isInventoryAsked()) {
336                    $sendInventory = 0;
337                  }
338
339                } else { # Failed to reach the server
340                    if ($config->{config}{lazy}) {
341                        # To avoid flooding a heavy loaded server
342                        my $previousPrologFreq;
343                        if( ! ($previousPrologFreq = $accountconfig->get('PROLOG_FREQ') ) ){
344                             $previousPrologFreq = $config->{config}{delaytime};
345                             $logger->info("No previous PROLOG_FREQ found - using fallback delay(".$config->{config}{delaytime}." seconds)");
346                         }
347                         else{
348                             $logger->info("Previous PROLOG_FREQ found ($previousPrologFreq)");
349                             $previousPrologFreq = $previousPrologFreq*3600;
350                         }
351                         my $time = time + $previousPrologFreq;
352                         utime $time,$time,$config->{config}{next_timefile};
353                     }
354                     exit 1 unless $config->{config}{daemon};
355                     $sendInventory = 0;
356                }
357             }
358
359             if (!$sendInventory) {
360                 $logger->info("Don't send the inventory");
361
362             } else { # Send the inventory!
363
364                 my $backend = new Ocsinventory::Agent::Backend ({
365                        prologresp => $prologresp,
366                        context => $context,
367                 });
368
369                 my $inventory = new Ocsinventory::Agent::XML::Inventory ({
370                        # TODO, check if the accoun{info,config} are needed in localmode
371                        backend => $backend,
372                        context => $context,
373                 });
374
375                 #Launching inventory
376                 $inventory->initialise();
377
378                 #Using inventory_writer hook
379                 $hooks->run({name => 'inventory_handler'}, $inventory);
380
381                 #Formatting the XML
382                 my $inventoryXML = $inventory->getContent(); 
383
384                 #Sending Inventory
385                 $httpresp = $network->sendXML({message => $inventoryXML}); 
386                 if (my $invresp = $network->getXMLResp($httpresp,'Inventory')) {
387                     $inventory->saveLastState();
388                 } else {
389                     exit (1) unless $config->{config}{daemon};
390                 }
391            }
392
393        }
394
395        #Using end_handler_hook
396        $hooks->run({name => 'end_handler'});
397
398        exit (0) unless $config->{config}{daemon};
399
400    }
401
402
403##########################################
404############Functions#####################
405##########################################
406
407
408    sub recMkdir {
409        my $dir = shift;
410
411        my @t = split /\//, $dir;
412        shift @t;
413        return unless @t;
414
415        my $t;
416        foreach (@t) {
417            $t .= '/'.$_;
418            if ((!-d $t) && (!mkdir $t)) {
419                return;
420            }
421        }
422        1;
423    }
424
425    sub isAgentAlreadyRunning {
426        my $params = shift;
427        my $logger = $params->{logger};
428        # TODO add a workaround if Proc::PID::File is not installed
429        eval { require Proc::PID::File; };
430        if(!$@) {
431            $logger->debug('Proc::PID::File available, checking for pid file');
432            if (Proc::PID::File->running()) {
433                $logger->debug('parent process already exists');
434                return 1;
435            }
436        }
437
438        return 0;
439    }
440
441}
442
4431;
444
Note: See TracBrowser for help on using the repository browser.