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

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

Copyt trusty code

File size: 7.7 KB
Line 
1package Ocsinventory::Agent::XML::Inventory;
2# TODO: resort the functions
3use strict;
4use warnings;
5
6=head1 NAME
7
8Ocsinventory::Agent::XML::Inventory - the XML abstraction layer
9
10=head1 DESCRIPTION
11
12OCS Inventory uses XML for the data transmition. The module is the
13abstraction layer. It's mostly used in the backend module where it
14called $inventory in general.
15
16=cut
17
18use XML::Simple;
19use Digest::MD5 qw(md5_base64);
20use Config;
21
22use Ocsinventory::Agent::Backend;
23
24=over 4
25
26=item new()
27
28The usual constructor.
29
30=cut
31sub new {
32  my (undef, $params) = @_;
33
34  my $self = {};
35  $self->{accountinfo} = $params->{context}->{accountinfo};
36  $self->{accountconfig} = $params->{context}->{accountconfig};
37  $self->{backend} = $params->{backend};
38  $self->{common} = $params->{context}->{common};
39
40  my $logger = $self->{logger} = $params->{context}->{logger};
41  $self->{config} = $params->{context}->{config};
42
43  if (!($self->{config}{deviceid})) {
44    $logger->fault ('deviceid unititalised!');
45  }
46
47  $self->{xmlroot}{QUERY} = ['INVENTORY'];
48  $self->{xmlroot}{DEVICEID} = [$self->{config}->{deviceid}];
49
50  #$self->{xmlroot}{CONTENT}{HARDWARE} = {
51    # TODO move that in a backend module
52   # ARCHNAME => [$Config{archname}]
53  #};
54
55  # Is the XML centent initialised?
56  $self->{isInitialised} = undef;
57
58  bless $self;
59}
60
61=item initialise()
62
63Runs the backend modules to initilise the data.
64
65=cut
66sub initialise {
67  my ($self) = @_;
68
69  return if $self->{isInitialised};
70
71  $self->{backend}->feedInventory ({inventory => $self});
72  $self->{isInitialised} = 1;
73
74}
75
76
77=item getContent()
78
79Return the inventory as a XML string.
80
81=cut
82sub getContent {
83  my ($self, $args) = @_;
84
85  my $logger = $self->{logger};
86  my $common = $self->{common};
87
88  if ($self->{isInitialised}) {
89    $self->processChecksum();
90
91    #  checks for MAC, NAME and SSN presence
92    my $macaddr = $self->{xmlroot}->{CONTENT}->{NETWORKS}->[0]->{MACADDR}->[0];
93    my $ssn = $self->{xmlroot}->{CONTENT}->{BIOS}->{SSN}->[0];
94    my $name = $self->{xmlroot}->{CONTENT}->{HARDWARE}->{NAME}->[0];
95
96    my $missing;
97
98    $missing .= "MAC-address " unless $macaddr;
99    $missing .= "SSN " unless $ssn;
100    $missing .= "HOSTNAME " unless $name;
101
102    if ($missing) {
103      $logger->debug('Missing value(s): '.$missing.'. I will send this inventory to the server BUT important value(s) to identify the computer are missing');
104    }
105
106    $self->{accountinfo}->setAccountInfo($self);
107
108    my $content = XMLout( $self->{xmlroot}, RootName => 'REQUEST', XMLDecl => '<?xml version="1.0" encoding="UTF-8"?>', SuppressEmpty => undef );
109
110    #Cleaning XML to delete unprintable characters
111    my $clean_content=$common->cleanXml($content);
112
113    #Cleaning xmltags content after adding it o inventory
114    $common->flushXMLTags();
115
116    return $clean_content;
117  }
118}
119
120=item printXML()
121
122Only for debugging purpose. Print the inventory on STDOUT.
123
124=cut
125sub printXML {
126  my ($self, $args) = @_;
127
128  if ($self->{isInitialised}) {
129    print $self->getContent();
130  }
131}
132
133=item writeXML()
134
135Save the generated inventory as an XML file. The 'local' key of the config
136is used to know where the file as to be saved.
137
138=cut
139sub writeXML {
140  my ($self, $args) = @_;
141
142  my $logger = $self->{logger};
143
144  if ($self->{config}{local} =~ /^$/) {
145    $logger->fault ('local path unititalised!');
146  }
147
148  if ($self->{isInitialised}) {
149
150    my $localfile = $self->{config}{local}."/".$self->{config}{deviceid}.'.ocs';
151    $localfile =~ s!(//){1,}!/!;
152
153    # Convert perl data structure into xml strings
154
155    if (open OUT, ">$localfile") {
156      print OUT $self->getContent();
157      close OUT or warn;
158      $logger->info("Inventory saved in $localfile");
159    } else {
160      warn "Can't open `$localfile': $!"
161    }
162  }
163}
164
165=item processChecksum()
166
167Compute the <CHECKSUM/> field. This information is used by the server to
168know which parts of the XML have changed since the last inventory.
169
170The is done thank to the last_file file. It has MD5 prints of the previous
171inventory.
172
173=cut
174sub processChecksum {
175  my $self = shift;
176  my $logger = $self->{logger};
177  my $common = $self->{common};
178
179#To apply to $checksum with an OR
180  my %mask = (
181    'HARDWARE'      => 1,
182    'BIOS'          => 2,
183    'MEMORIES'      => 4,
184    'SLOTS'         => 8,
185    'REGISTRY'      => 16,
186    'CONTROLLERS'   => 32,
187    'MONITORS'      => 64,
188    'PORTS'         => 128,
189    'STORAGES'      => 256,
190    'DRIVES'        => 512,
191    'INPUT'         => 1024,
192    'MODEMS'        => 2048,
193    'NETWORKS'      => 4096,
194    'PRINTERS'      => 8192,
195    'SOUNDS'        => 16384,
196    'VIDEOS'        => 32768,
197    'SOFTWARES'     => 65536,
198    'VIRTUALMACHINES' => 131072,
199  );
200  # TODO CPUS is not in the list
201
202  if (!$self->{config}->{vardir}) {
203    $logger->fault ("vardir uninitialised!");
204  }
205
206  my $checksum = 0;
207
208  if (!$self->{config}{local} && $self->{config}->{last_statefile}) {
209    if (-f $self->{config}->{last_statefile}) {
210      # TODO: avoid a violant death in case of problem with XML
211      $self->{last_state_content} = XML::Simple::XMLin(
212
213        $self->{config}->{last_statefile},
214        SuppressEmpty => undef,
215        ForceArray => 1
216
217      );
218    } else {
219      $logger->debug ('last_state file: `'.
220        $self->{config}->{last_statefile}.
221        "' doesn't exist (yet).");
222    }
223  }
224
225  foreach my $section (keys %mask) {
226    #If the checksum has changed...
227    my $hash = md5_base64(XML::Simple::XMLout($self->{xmlroot}{'CONTENT'}{$section}));
228    if (!$self->{last_state_content}->{$section}[0] || $self->{last_state_content}->{$section}[0] ne $hash ) {
229      $logger->debug ("Section $section has changed since last inventory");
230      #We make OR on $checksum with the mask of the current section
231      $checksum |= $mask{$section};
232      # Finally I store the new value.
233      $self->{last_state_content}->{$section}[0] = $hash;
234    }
235  }
236
237  $common->setHardware({CHECKSUM => $checksum});
238}
239
240=item saveLastState()
241
242At the end of the process IF the inventory was saved
243correctly, the last_state is saved.
244
245=cut
246sub saveLastState {
247  my ($self, $args) = @_;
248
249  my $logger = $self->{logger};
250
251  if (!defined($self->{last_state_content})) {
252          $self->processChecksum();
253  }
254
255  if (!defined ($self->{config}->{last_statefile})) {
256    $logger->debug ("Can't save the last_state file. File path is not initialised.");
257    return;
258  }
259
260  if (open LAST_STATE, ">".$self->{config}->{last_statefile}) {
261    print LAST_STATE my $string = XML::Simple::XMLout( $self->{last_state_content}, RootName => 'LAST_STATE' );;
262    close LAST_STATE or warn;
263  } else {
264    $logger->debug ("Cannot save the checksum values in ".$self->{config}->{last_statefile}.":$!");
265  }
266}
267
268=item addSection()
269
270A generic way to save a section in the inventory. Please avoid this
271solution.
272
273=cut
274sub addSection {
275  my ($self, $args) = @_;
276  my $logger = $self->{logger};
277  my $multi = $args->{multi};
278  my $tagname = $args->{tagname};
279
280  for( keys %{$self->{xmlroot}{CONTENT}} ){
281    if( $tagname eq $_ ){
282      $logger->debug("Tag name `$tagname` already exists - Don't add it");
283      return 0;
284    }
285  }
286
287  if($multi){
288    $self->{xmlroot}{CONTENT}{$tagname} = [];
289  }
290  else{
291    $self->{xmlroot}{CONTENT}{$tagname} = {};
292  }
293  return 1;
294}
295
296=item feedSection()
297
298Add information in inventory.
299
300=back
301=cut
302# Q: is that really useful()? Can't we merge with addSection()?
303sub feedSection{
304  my ($self, $args) = @_;
305  my $tagname = $args->{tagname};
306  my $values = $args->{data};
307  my $logger = $self->{logger};
308
309  my $found=0;
310  for( keys %{$self->{xmlroot}{CONTENT}} ){
311    $found = 1 if $tagname eq $_;
312  }
313
314  if(!$found){
315    $logger->debug("Tag name `$tagname` doesn't exist - Cannot feed it");
316    return 0;
317  }
318
319  if( $self->{xmlroot}{CONTENT}{$tagname} =~ /ARRAY/ ){
320    push @{$self->{xmlroot}{CONTENT}{$tagname}}, $args->{data};
321  }
322  else{
323    $self->{xmlroot}{CONTENT}{$tagname} = $values;
324  }
325
326  return 1;
327}
328
3291;
Note: See TracBrowser for help on using the repository browser.