File Coverage

blib/lib/Ingres/Utility/IIMonitor.pm
Criterion Covered Total %
statement 12 157 7.6
branch 0 68 0.0
condition 0 21 0.0
subroutine 4 11 36.3
pod 6 6 100.0
total 22 263 8.3


line stmt bran cond sub pod time code
1             package Ingres::Utility::IIMonitor;
2              
3 1     1   22577 use warnings;
  1         2  
  1         29  
4 1     1   5 use strict;
  1         1  
  1         28  
5 1     1   5 use Carp;
  1         5  
  1         80  
6 1     1   798 use Expect::Simple;
  1         55919  
  1         2158  
7              
8             =head1 NAME
9              
10             Ingres::Utility::IIMonitor - API to C Ingres RDBMS utility
11              
12             =head1 VERSION
13              
14             Version 0.13
15              
16             =cut
17              
18             our $VERSION = '0.13';
19              
20             =head1 SYNOPSIS
21              
22             use Ingres::Utility::IIMonitor;
23            
24             # create a connection to an IIDBMS server
25             # (server id can be obtained through Ingres::Utility::IINamu)
26             $foo = Ingres::Utility::IIMonitor->new($serverid);
27            
28             # showServer() - shows server status
29             #
30             # is the server listening to new connections? (OPEN/CLOSED)
31             $status =$foo->showServer('LISTEN');
32             #
33             # is the server being shut down?
34             $status =$foo->showServer('SHUTDOWN');
35            
36             # setServer() - sets server status
37             #
38             # stop listening to new connections
39             $status =$foo->setServer('CLOSED');
40             #
41             # start shutting down (wait for connections to close)
42             $status =$foo->setServer('SHUT');
43            
44             # stop() - stops IIDBMS server (transactions rolled back)
45             #
46             $ret = $foo->stop();
47            
48             # showSessions($target,$mode) - prepares to get sessions info
49             print $foo->showSessions('SYSTEM','FORMATTED');
50            
51             # getSession() - get sessions call-after-call from previous showSessions()
52             while (%session = $foo->getSession()) {
53             print "Session ". $session{'SESSION_ID'} . ":\n"
54             foreach $label, $value (%session) {
55             print "\t$label:\t$value\n" if ($label ne 'SESSION_ID');
56             }
57             }
58            
59            
60             =head1 DESCRIPTION
61              
62             This module provides an API to the iimonitor utility for
63             Ingres RDBMS, which provides local control of IIDBMS servers
64             and sessions (system and user conections).
65              
66              
67             =head1 METHODS
68              
69             =over
70              
71             =item C
72              
73             Constructor, connects to an IIDBMS server through iimonitor utility.
74              
75             Takes the server id as argument to identify which server
76             to control.
77              
78             $iimonitor = Ingres::Utility::IIMonitor->new(12345);
79            
80             The server id can be obtained through L module.
81              
82             =cut
83              
84             sub new($) {
85 0     0 1   my $class = shift;
86 0           my $this = {};
87 0   0       $class = ref($class) || $class;
88 0           bless $this, $class;
89 0           my $serverId = shift;
90 0 0         if (! $serverId) {
91 0           croak "parameter missing: serverId";
92             }
93 0 0         if (! defined($ENV{'II_SYSTEM'})) {
94 0           croak "Ingres environment variable II_SYSTEM not set";
95             }
96 0           my $iimonitor_file = $ENV{'II_SYSTEM'} . '/ingres/bin/iimonitor';
97            
98 0 0         if (! -x $iimonitor_file) {
99 0           croak "Ingres utility cannot be executed: $iimonitor_file";
100             }
101 0           $this->{cmd} = $iimonitor_file;
102 0 0         $this->{xpct} = new Expect::Simple {
103             Cmd => "$iimonitor_file $serverId",
104             Prompt => [ -re => 'IIMONITOR>\s+' ],
105             DisconnectCmd => 'QUIT',
106             Verbose => 0,
107             Debug => 0,
108             Timeout => 10
109             } or croak "Module Expect::Simple cannot be instanciated";
110 0           $this->{serverId} = $serverId;
111 0           return $this;
112             }
113              
114              
115             =item C
116              
117             Returns the server status.
118              
119             Takes the server status to query:
120              
121             LISTEN = server listening to new connections
122            
123             SHUTDOWN = server waiting for connections to close to end process.
124              
125             Returns 'OPEN', 'CLOSED' or 'PENDING' (for shutdown).
126              
127             =cut
128              
129             sub showServer($) {
130 0     0 1   my $this = shift;
131 0 0         my $serverStatus = uc (@_ ? shift : '');
132 0 0         if ($serverStatus) {
133 0 0         if ($serverStatus ne 'LISTEN') {
134 0 0         if ($serverStatus ne 'SHUTDOWN') {
135 0           carp "invalid status: ($serverStatus)";
136 0           return ();
137             }
138             }
139             }
140             #print $this . ": cmd = $cmd";
141 0           my $obj = $this->{xpct};
142 0           $obj->send( 'SHOW SERVER ' . $serverStatus );
143 0           my $before = $obj->before;
144 0           while ($before =~ /\ \ /) {
145 0           $before =~ s/\ \ /\ /g;
146             }
147 0           my @antes = split /\r\n/,$before;
148 0           return join($/,@antes);
149             }
150              
151              
152             =item C
153              
154             Changes the server status to the state indicated by the argument:
155              
156             SHUT = server will shutdown after all connections are closed
157              
158             CLOSED = stops listening to new connections
159              
160             OPEN = reestablishes listening to new connections
161              
162             =cut
163              
164             sub setServer($) {
165 0     0 1   my $this = shift;
166 0           my $serverStatus = uc (shift);
167 0 0         if (! $serverStatus) {
168 0           carp 'no status given';
169             }
170 0 0         if ($serverStatus ne 'SHUT') {
171 0 0         if ($serverStatus ne 'CLOSED') {
172 0 0         if ($serverStatus ne 'OPEN') {
173 0           carp "invalid status: ($serverStatus)";
174 0           return;
175             }
176             }
177             }
178 0           my $obj = $this->{xpct};
179 0           $obj->send( 'SET SERVER ' . $serverStatus );
180 0           my $before = $obj->before;
181 0           while ($before =~ /\ \ /) {
182 0           $before =~ s/\ \ /\ /g;
183             }
184 0           my @antes = split /\r\n/,$before;
185 0           return $before;
186            
187             }
188              
189              
190             =item C
191              
192             Stops server immediatly, rolling back transactions and closing all connections.
193              
194             =cut
195              
196             sub stopServer() {
197 0     0 1   my $this = shift;
198 0           my $obj = $this->{xpct};
199 0           $obj->send( 'STOP');
200 0           my $before = $obj->before;
201 0           while ($before =~ /\ \ /) {
202 0           $before =~ s/\ \ /\ /g;
203             }
204 0           my @antes = split /\r\n/,$before;
205 0           return;
206            
207             }
208              
209             # Transform into all uppercase and translate spaces into underscores
210             sub _prepareName($) {
211 0     0     my $this = shift;
212 0           my $name = shift;
213 0           $name = uc $name;
214 0           $name =~ tr/\ /\_/;
215 0           return $name;
216             }
217              
218              
219             =item C
220              
221             Prepares to show info on sessions on IIDBMS server, for being fetched later by getNextSession().
222              
223             Returns the output from iimonitor.
224              
225             Takes the following parameters:
226             [], []
227            
228             TARGET = Which session type: USER (default), SYSTEM or ALL
229             MODE = Which server info: FORMATTED, STATS. Default is a short format.
230              
231             =cut
232              
233             sub showSessions(;$$) {
234 0     0 1   my $this = shift;
235 0           my $target;
236             my $mode;
237 0 0         $target = uc (@_ ? shift : 'USER');
238 0 0 0       if ($target eq 'FORMATTED' or
239             $target eq 'STATS') {
240 0 0         if (@_) {
241 0           carp "invalid paramter after $target: (" . join(' ',@_) . ")";
242 0           return '';
243             }
244 0           $mode = $target;
245 0           $target = 'USER';
246             }
247             else {
248 0 0 0       if ($target ne 'USER' and
      0        
      0        
249             $target ne 'SYSTEM' and
250             $target ne 'ALL' and
251             $target ne '') {
252 0           carp "invalid target: ($target)";
253 0           return '';
254             }
255 0 0         $mode =uc (@_ ? shift : '');
256 0 0 0       if ($mode ne 'FORMATTED' and
      0        
257             $mode ne 'STATS' and
258             $mode ne '') {
259 0           carp "invalid mode: ($mode)";
260 0           return '';
261             }
262             }
263 0           my $obj = $this->{xpct};
264 0           $obj->send("SHOW $target SESSIONS $mode");
265 0           my $before = $obj->before;
266             # while ($before =~ /\ \ /) {
267             # $before =~ s/\ \ /\ /g;
268             # }
269 0           $this->{sessWho} = $target;
270 0           $this->{sessMode} = $mode;
271 0           my @tmp = split (/\r\n/,$before);
272 0           $this->{sessOutArray} = \@tmp;
273 0           $this->{sessBuff} = ();
274 0           $this->{sessPtr} = 0;
275 0           return $before;
276             }
277              
278              
279             =item C
280              
281             Returns sequentially (call-after-call) each session reported by showSessions() as a hash of
282             as many elements as returned by each session target and mode, where the key is the name
283             showed on labels of iimonitor's output, all uppercase and spaces translated into underscores (_).
284              
285             Unlabeled info gets its key from the previously labeled field appended by '_#', where
286             index is the sequential order (starting by 0) on which the info appeared.
287              
288             This way, all info is in pairs of (LABEL,VALUE), whithout parenthesis or trailing spaces.
289              
290             UFO - Unidentified Format Output - will be translated into words forming pairs of labels and values,
291             PLEASE REPORT THIS, because this is not expected to happen. Meanwhile see what you can do with
292             these pairs, and will probably need extra parsing. If you report this, there's hope they will be
293             properly handled on the next version.
294              
295              
296             =cut
297              
298             sub getSession() {
299 0     0 1   my $this = shift;
300 0           my @foo;
301 0           my %sess = ();
302 0           my $name;
303             my $value;
304 0           my $i;
305 0           my $j;
306 0 0         if ($this->{sessPtr} >= scalar @{$this->{sessOutArray}}) {
  0            
307 0           $this->{sessPtr} = 0;
308 0           return %sess;
309             }
310             FOR_gNS:
311 0           for ($i = $this->{sessPtr}; ($i < scalar @{$this->{sessOutArray}}); $i++) {
  0            
312 0           $_ = $this->{sessOutArray}[$i];
313 0 0         if (/^session\s/i) {
    0          
    0          
    0          
    0          
    0          
314 0 0         if ($this->{sessMode} eq 'STATS') {
315 0 0         if (@foo = (/^(session)\s([0-9A-Fa-f]+)\s+\((.*)\)(\s*)(.*)/i)) {
316 0 0         if (scalar keys %sess > 0) {
317 0           last FOR_gNS;
318             }
319 0           $sess{'SESSION_ID'} = $2;
320 0           $sess{'SESSION_USER'} = $3;
321 0 0         if (defined $5) {
322 0           my @stats = split /\s+/,$5;
323 0           for ($j = 0; ($j < (scalar @stats)); $j += 2) {
324 0           $name = $stats[$j];
325 0           $name = $this->_prepareName($name);
326 0           $value = '';
327 0 0         if (defined $stats[$j+1]) {
328 0           $value = $stats[$j+1];
329             }
330 0           $sess{$name} = $value;
331             }
332             }
333             }
334             }
335             else {
336 0 0         if (@foo = (/^(session)\s([0-9A-Fa-f]+)\s+\((.*)\)\s+(cs_state)\:\s(.*)\s\((.*)\)\s(cs_mask)\:\s(.*)/i)) {
337 0 0         if (scalar keys %sess > 0) {
338 0           last FOR_gNS;
339             }
340 0           $sess{'SESSION_ID'} = $2;
341 0           $sess{'SESSION_USER'} = $3;
342 0           $sess{'CS_STATE'} = $5;
343 0           $sess{'CS_STATE_#0'} = $6;
344 0           $sess{'CS_MASK'} = $8;
345             }
346             }
347             }
348             elsif (@foo = (/^\s+(user)\:\s(.*)\((.*)\s+.*\)/i)) {
349 0           $sess{'USER'} = $2;
350 0           $sess{'USER_#0'} = $3;
351             }
352             elsif (@foo = (/^\s+(db\sname)\:\s(.*)\((owned\sby)\:\s(.*)\s+\)/i)) {
353 0           $sess{'DB_NAME'} = $2;
354 0           $sess{'OWNED_BY'} = $4;
355             }
356             elsif (@foo = (/^\s+(application\scode)\:\s(.*)\s(current\sfacility)\:\s(.*)\s+\((.*)\)/i)) {
357 0           $sess{'APPLICATION_CODE'} = $2;
358 0           $sess{'CURRENT_FACILITY'} = $4;
359 0           $sess{'CURRENT_FACILITY_#0'} = $5;
360             }
361             elsif (@foo = (/^\s+(.*)\:\s+(.*:.*)/)) {
362 0           $name = $this->_prepareName($1);
363 0           $sess{$name} = $2;
364             }
365             elsif (@foo = (/^\s+(.*)\:\s*(.*)/)) {
366 0           $name = $this->_prepareName($1);
367 0           $sess{$name} = $2;
368             }
369             else { # UFO - Unidentifyed Format Output
370 0           @foo = split ' ';
371 0           for ($j = 0; ($j < scalar @foo) ; $j += 2) {
372 0 0         if (defined $foo[$j]) {
373 0           $name = $this->_prepareName($foo[$j]);
374 0           $value = '';
375 0 0         if (defined $foo[$j+1]) {
376 0           $value = $foo[$j+1];
377 0           while (substr($value,length($value)-1) eq ' ') {
378 0           chop $value;
379             }
380             }
381 0           $sess{$name} = $value;
382             }
383             }
384             }
385             }
386 0           $this->{sessPtr} = $i;
387 0           return %sess;
388             }
389              
390             =back
391              
392             =head1 DIAGNOSTICS
393              
394             =over
395              
396             =item C<< parameter missing: serverId >>
397              
398             Call to method new() is missing the serverId argument to indicate the IIDBMS
399             to connect to.
400              
401             =item C<< Ingres environment variable II_SYSTEM not set >>
402              
403             Ingres environment variables should be set in the user session running
404             this module.
405             II_SYSTEM provides the root install dir (the one before 'ingres' dir).
406             LD_LIBRARY_PATH too. See Ingres RDBMS docs.
407              
408             =item C<< Ingres utility cannot be executed: _COMMAND_FULL_PATH_ >>
409              
410             The IIMONITOR command could not be found or does not permits execution for
411             the current user.
412              
413             =item C<< parameter missing: serverStatus >>
414              
415             Call to method setServer() is missing the serverStatus argument.
416              
417             =item C<< invalid status: (_SERVER_STATUS_PARAM_) >>
418              
419             The showServer() or setServer() methods received an invalid argument.
420              
421             =item C<< invalid target: (_TARGET_) >>
422              
423             The showServer() takes the first argument only as USER/SYSTEM/ALL.
424              
425             =item C<< invalid mode: (_MODE_) >>
426              
427             The showServer() takes the second or only one argument only as FORMATTED/STATS.
428              
429             =item C<< invalid paramter after _TARGET_: (_PARAMETER_) >>
430              
431             If showServer() takes the first as FORMATTED/STATS then no other parameter is
432             accepted.
433              
434             =back
435              
436              
437             =head1 CONFIGURATION AND ENVIRONMENT
438            
439             Requires Ingres environment variables, such as II_SYSTEM and LD_LIBRARY_PATH.
440              
441             See Ingres RDBMS documentation.
442              
443              
444             =head1 DEPENDENCIES
445              
446             L
447              
448              
449             =head1 INCOMPATIBILITIES
450              
451             None reported.
452              
453              
454             =head1 BUGS AND LIMITATIONS
455              
456             No bugs have been reported.
457              
458             Please report any bugs or feature requests to C,
459             or through the web interface at L.
460              
461              
462             =head1 SUPPORT
463              
464             You can find documentation for this module with the perldoc command.
465              
466             perldoc Ingres::Utility::IIMonitor
467              
468             You can also look for information at:
469              
470             =over 4
471              
472             =item * AnnoCPAN: Annotated CPAN documentation
473              
474             L
475              
476             =item * CPAN Ratings
477              
478             L
479              
480             =item * RT: CPAN's request tracker
481              
482             L
483              
484             =item * Search CPAN
485              
486             L
487              
488             =back
489              
490              
491             =head1 ACKNOWLEDGEMENTS
492              
493             Thanks to Computer Associates (CA) for licensing Ingres as
494             open source, and let us hope for Ingres Corp to keep it that way.
495              
496             =head1 AUTHOR
497              
498             Joner Cyrre Worm C<< >>
499              
500              
501             =head1 LICENSE AND COPYRIGHT
502              
503             Copyright (c) 2006, Joner Cyrre Worm C<< >>. All rights reserved.
504              
505              
506             Ingres is a registered brand of Ingres Corporation.
507              
508             This module is free software; you can redistribute it and/or
509             modify it under the same terms as Perl itself. See L.
510              
511              
512             =head1 DISCLAIMER OF WARRANTY
513              
514             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
515             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
516             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
517             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
518             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
519             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
520             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
521             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
522             NECESSARY SERVICING, REPAIR, OR CORRECTION.
523              
524             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
525             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
526             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
527             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
528             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
529             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
530             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
531             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
532             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
533             SUCH DAMAGES.
534              
535             =cut
536              
537             1; # End of Ingres::Utility::IIMonitor
538             __END__