# -*-perl-*- # Cricket: a configuration, polling and data display wrapper for RRD files # # Copyright (C) 1998 Jeff R. Allen and WebTV Networks, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # A fetch routine for retrieving data from Windows Management # Instrumentation Counters, the Microsoft implementation of the Web-Based # Enterprise Management (WBEM) standard. This implementation feeds WQL # (similar to SQL) queries to the WMI COM Interface. use Common::Log; use Win32::OLE; use Win32::OLE::Enum; # V.* reg exp should match verion 1.1 (Win2K) or 1.2 (WinXP) use Win32::OLE::Const 'Microsoft WMI Scripting V.* Library'; $main::gDSFetch{'wbem'} = \&wbemFetch; sub wbemFetch { # This procedure is passed a REFERENCE to an array of wbem datasources. # Each line consists of "index:host:namespace:table:field:predicate" # Predicate is optional. # VERY IMPORTANT: The index MUST be returned with the corresponding value, # otherwise it'll get put back into the wrong spot in the RRD. my($dsList, $name, $target) = @_; my (@results, @lines, $line, @nextline); my ($locator, $service, $objectSet, $object) = (undef, undef, undef, undef); my $query = undef; my ($index, $host, $namespace, $table, $field, $predicate); my (@fieldList, @indexList); my $isConnected = 0; # sort lines by host, namespace, and table # (default they are sorted by index) @lines = sort { substr ($a, index($a, ':')) cmp substr ($b, index($b, ':')); } (@{$dsList}); # connect or load the WMI locator $locator = Win32::OLE->GetActiveObject("WbemScripting.SWbemLocator"); $locator = Win32::OLE->new("WbemScripting.SWbemLocator") unless defined $locator; Error("failed to load WMI locator") unless defined $locator; $locator -> {Security_} -> {ImpersonationLevel} = wbemImpersonationLevelImpersonate; $line = shift @lines; CONNECTLOOP: while (defined($line)) { ($index, $host, $namespace, $table, $field, $predicate) = split(/:/,$line,6); # obtain the WMI service interface for the namespace/host undef $service; $service = $locator -> ConnectServer($host,$namespace); if (defined $service) { $isConnected = 1; } else { Warn("ConnectServer to $host $namespace failed:"); Warn(Win32::OLE->LastError()); $isConnected = 0; } TABLELOOP: while (1) { @fieldList = (); @indexList = (); FIELDLOOP: while (1) { push @fieldList, "$field"; push @indexList, $index; # group together queries to the same table with the same predicate $line = shift @lines; @nextline = split(/:/,$line,6) if (defined($line)); if (!defined($line) || $table ne $nextline[3] || ($predicate ? $predicate : "") ne ($nextline[5] ? $nextline[5] : "") || $host ne $nextline[1] || $namespace ne $nextline[2]) { last FIELDLOOP; } ($index, $field) = ($nextline[0], $nextline[4]); } # construct and run the query $query = "SELECT " . join(',',@fieldList) . " FROM $table"; $query .= " WHERE $predicate" if ($predicate); undef $objectSet; $objectSet = $service -> ExecQuery($query, "WQL", wbemFlagReturnWhenComplete) if ($isConnected); if (!($isConnected) || !$objectSet) { Warn("Query {$query} against $host $namespace failed:"); Warn(Win32::OLE->LastError()) if $isConnected; Warn("no connection") unless $isConnected; push @results, map { $_ . ':U' } @indexList; } else { $object = undef; my @temp = in $objectSet; # query should always be singleton select $object = shift @temp; if ($object) { for (my $i = 1; $i <= scalar(@fieldList); $i++) { my $data = $object -> {$fieldList[$i-1]}; push @results, "$indexList[$i - 1]:$data" } } else { Warn("No result from $query: " . Win32::OLE->LastError()); push @results, map { $_ . ':U' } @indexList; } } # @nextline is already set # check if a new connection is required # use an order designed to take advantage of shortcut evaluation if (!defined($line) || $host ne $nextline[1] || $namespace ne $nextline[2]) { last TABLELOOP; } # continue with the next table/predicate ($index, $host, $namespace, $table, $field, $predicate) = @nextline; } } # not certain is this required undef $object; undef $objectSet; undef $service; undef $locator; return @results; } 1; # Local Variables: # mode: perl # indent-tabs-mode: nil # tab-width: 4 # perl-indent-level: 4 # End: