summaryrefslogtreecommitdiff
path: root/src/pmdas/samba/pmdasamba.pl
blob: f10d7e1af27c5c7433491a2484f8d8c6fe5235ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#
# Copyright (c) 2012-2013 Red Hat.
# Copyright (c) 2009 Aconex.  All Rights Reserved.
#
# 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.
#

use strict;
use warnings;
use PCP::PMDA;

use vars qw( $pmda %metrics );

#
# This is the main workhorse routine, both value extraction and
# namespace population is under-pinned by this.  The approach we
# use here is to extract profile output, construct a hash (keyed
# by metric ID), containing name and value pairs (array refs).
#
sub samba_fetch
{
    my $item = 0;
    my $cluster = 0;
    my $prefix = '';
    my $generated_cluster = 20; # start well above hard-coded ones

    # work around smbstatus / libpopt adverse reaction to these variables 
    delete $ENV{'POSIXLY_CORRECT'};
    delete $ENV{'POSIX_ME_HARDER'};

    my $smbstats = "smbstatus --profile";
    open(STATS, "$smbstats |") ||
	$pmda->err("pmdasamba failed to open $smbstats pipe: $!");

    while (<STATS>) {
	if (m/^\*\*\*\*\s+(\w+[^*]*)\**$/) {
	    my $heading = $1;
	    $heading =~ s/ +$//g;
	    $item = 0;
	    if ($heading eq 'System Calls') {
		$cluster = 1; $prefix = 'syscalls';
	    } elsif ($heading eq 'Stat Cache') {
		$cluster = 2; $prefix = 'statcache';
	    } elsif ($heading eq 'Write Cache') {
		$cluster = 3; $prefix = 'writecache';
	    } elsif ($heading eq 'SMB Calls') {
		$cluster = 4; $prefix = 'smb';
	    } elsif ($heading eq 'Pathworks Calls') {
		$cluster = 5; $prefix = 'pathworks';
	    } elsif ($heading eq 'Trans2 Calls') {
		$cluster = 6; $prefix = 'trans2';
	    } elsif ($heading eq 'NT Transact Calls') {
		$cluster = 7; $prefix = 'NTtransact';
	    } elsif ($heading eq 'ACL Calls') {
		$cluster = 8; $prefix = 'acl';
	    } elsif ($heading eq 'NMBD Calls') {
		$cluster = 9; $prefix = 'nmb';
	    } else {
                # samba 4.1 renames several clusters of statistics.
                # Let's generate cluster names instead of hard-coding them.
                $cluster = $generated_cluster++;
                $prefix = $heading;
                $prefix =~ s/ /_/g;
                $prefix =~ tr/A-Z/a-z/;
	    }
	    # $pmda->log("metric cluster: $cluster = $prefix");
	}
	# we've found a real name/value pair, work out PMID and hash it
	elsif (m/^([\[\]\w]+):\s+(\d+)$/) {
	    my @metric = ( $1, $2 );
	    my $pmid;

            $metric[0] =~ tr/\[\]/_/d;

	    if ($cluster == 0) {
		$metric[0] = "samba.$metric[0]";
	    } else {
	        $metric[0] = "samba.$prefix.$metric[0]";
	    }
	    $pmid = pmda_pmid($cluster,$item++);
	    $metrics{$pmid} = \@metric;
	    # $pmda->log("metric: $metric[0], ID = $pmid, value = $metric[1]");
	}
        else {
	    $pmda->log("pmdasamba failed to parse line $_");
        }
    }
    close STATS;
}

sub samba_fetch_callback
{
    my ($cluster, $item, $inst) = @_;
    my $pmid = pmda_pmid($cluster, $item);
    my $value;

#    $pmda->log("samba_fetch_callback $metric_name $cluster:$item ($inst)\n");

    if ($inst != PM_IN_NULL)	{ return (PM_ERR_INST, 0); }

    # hash lookup based on PMID, value is $metrics{$pmid}[1]
    $value = $metrics{$pmid};
    if (!defined($value))	{ return (PM_ERR_APPVERSION, 0); }
    return ($value->[1], 1);
}

$pmda = PCP::PMDA->new('samba', 76);

samba_fetch();	# extract names and values into %metrics, keyed on PMIDs

# hash iterate, keys are PMIDs, names and values are in @metrics{$pmid}.
foreach my $pmid (sort(keys %metrics)) {
    my $name = $metrics{$pmid}[0];
    if ($name eq 'samba.writecache.num_write_caches' ||
	$name eq 'samba.writecache.allocated_caches') {
	$pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
			pmda_units(0,0,1,0,0,PM_COUNT_ONE), $name, '', '');
    } elsif ($name =~ /_time$/) {
	$pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
			pmda_units(0,1,0,0,PM_TIME_USEC,0), $name, '', '');
    } else {
	$pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER,
			pmda_units(0,0,1,0,0,PM_COUNT_ONE), $name, '', '');
    }
    # $pmda->log("pmdasamba added metric $name\n");
}
# close STATS;

$pmda->set_fetch(\&samba_fetch);
$pmda->set_fetch_callback(\&samba_fetch_callback);
# NB: needs to run as root, as smb usually does
$pmda->run;

=pod

=head1 NAME

pmdasamba - Samba performance metrics domain agent (PMDA)

=head1 DESCRIPTION

B<pmdasamba> is a Performance Metrics Domain Agent (PMDA) which exports
metric values from Samba, a Windows SMB/CIFS server for UNIX.

In order for values to be made available by this PMDA, Samba must have
been built with profiling support (WITH_PROFILE in "smbd -b" output).
This PMDA dynamically enumerates much of its metric hierarchy, based on
the contents of "smbstatus --profile".

When the agent is installed (see below), the Install script will attempt
to enable Samba statistics gathering, using "smbcontrol --profile".

=head1 INSTALLATION

If you want access to the names and values for the samba performance
metrics, do the following as root:

	# cd $PCP_PMDAS_DIR/samba
	# ./Install

If you want to undo the installation, do the following as root:

	# cd $PCP_PMDAS_DIR/samba
	# ./Remove

B<pmdasamba> is launched by pmcd(1) and should never be executed
directly.  The Install and Remove scripts notify pmcd(1) when
the agent is installed or removed.

=head1 FILES

=over

=item $PCP_PMDAS_DIR/samba/Install

installation script for the B<pmdasamba> agent

=item $PCP_PMDAS_DIR/samba/Remove

undo installation script for the B<pmdasamba> agent

=item $PCP_LOG_DIR/pmcd/samba.log

default log file for error messages from B<pmdasamba>

=back

=head1 SEE ALSO

pmcd(1), smbd(1) and samba(7).