powermon.in 4.06 KB
Newer Older
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
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#

#
# Testbed Power controller monitor
#
# powermon [-TPC] [type...]
#
# -T monitor temperature
# -P monitor power consumed
# -C monitor current used
#
# "type" is the types of power controllers to monitor.
#
# The default is to monitor TPC on all controllers in the DB that
# support a status call.
#

#
# Configure variables
#
my $TB         = "@prefix@";
my $TBOPS      = "@TBOPSEMAIL@";
my $ELABINELAB = @ELABINELAB@;

use lib "@prefix@/lib";
use libdb;
use power_rpc27;
use power_sgmote;
use power_mail;
use power_whol;
use snmpit_apc;
use libtestbed;
use strict;
use English;
use Getopt::Std;
use POSIX qw(strftime);

sub usage() {
    print << "END";
Usage: $0 [-TPC] [ <type> ... ]
 -T turn on temperature (in degrees F) monitoring
 -P turn on power (watts) consumption monitoring
 -C turn on current (amps) used monitoring

 -A turn on all monitoring
 -N turn off all monitoring

 <type> is the types of power controllers to monitor.
 The default is to monitor temps on all controllers that support status.
END
}

my $optlist = "ANTPC";
my $dotemps = 1;
my $dopower = 0;
my $docurrent = 0;

#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
my %options = ();
if (! getopts($optlist, \%options)) {
    usage();
}
if (defined($options{"A"})) {
    $dotemps = $dopower = $docurrent = 1;
}
if (defined($options{"N"})) {
    $dotemps = $dopower = $docurrent = 0;
}
if (defined($options{"T"})) {
    $dotemps = 1;
}
if (defined($options{"P"})) {
    $dopower = 1;
}
if (defined($options{"C"})) {
    $docurrent = 1;
}
die("Only admins are allowed to query status\n")
    if ($UID != 0 && !TBAdmin($UID));
exit(dostatus(@ARGV));

sub byname() {
    my ($as, $an, $bs, $bn);

    if ($a =~ /(.*[^\d])(\d+)$/) {
	$as = $1; $an = $2;
    } else {
	$as = $a;
    }
    if ($b =~ /(.*[^\d])(\d+)$/) {
	$bs = $1; $bn = $2;
    } else {
	$bs = $b;
    }
    $as cmp $bs || $an <=> $bn;
}

#
# Query the given controllers for their status
#
sub dostatus(@) {
    my @wanted = @_;
    my %ctrls = ();
    my $errors = 0;

    if ($ELABINELAB) {
	warn "Cannot get status from inner elab\n";
	return 1;
    }

    my $doall = (@wanted == 0);

    #
    # Fetch all possible power controllers
    #
    my $result = DBQueryFatal("select n.node_id,t.type ". 
			      "from nodes as n " .
			      "left join node_types as t on n.type=t.type " .
			      "where n.role='powerctrl'");
    while (my ($ctrl, $type) = $result->fetchrow()) {
	$ctrls{$ctrl} = $type;
    }

    @wanted = sort byname keys(%ctrls)
	if ($doall);

    #
    # Loop through desired controllers getting status
137
138
    # We do this in a child process so we can time it out if
    # one of the controllers is not responding.
139
    #
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    my $syspid = fork();
    if ($syspid) {
	#
	# Allow 5 seconds per controller
	#
	local $SIG{ALRM} = sub { kill("TERM", $syspid); };
	my $to = 5 * scalar(@wanted);
	alarm $to;
	waitpid($syspid, 0);
	alarm 0;
	if ($?) {
	    logit("*** Status fetch failed after $to seconds with exit val $?");
	}
	return $?;
    }

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
    for my $ctrl (@wanted) {
	my %status;

	if (!defined($ctrls{$ctrl})) {
	    warn "No such power controller '$ctrl', ignored\n";
	    $errors++;
	    next;
	}
	if ($ctrls{$ctrl} =~ /^RPC/) {
	    if (rpc27status($ctrl,\%status)) {
		warn "Could not get status for $ctrl.\n";
		$errors++;
		next;
	    }
	    my $msg = "$ctrl: ";
	    $msg .= $status{current} . "A, "
		if ($docurrent && $status{current});
	    $msg .= $status{power} . "W, "
		if ($dopower && $status{power});
	    if ($dotemps &&
		defined($status{tempF}) || defined($status{tempC})) {
		my $temp = $status{tempF};
		if (!defined($temp)) {
		    $temp = $status{tempC} * 9 / 5 + 32;
		}
		$msg .= ${temp} . "F";
	    }
	    logit($msg);
	} elsif (!$doall) {
	    warn "Cannot get status for $ctrl (type " .
		$ctrls{$ctrl} . ") yet\n";
	    $errors++;
	}
    }
190
    exit($errors);
191
192
193
194
195
196
197
}

sub logit($) {
    my ($msg) = @_;

    print strftime("%b %e %H:%M:%S", localtime)." powermon[$$]: $msg\n";
}