forked from stb-tester/stb-tester
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstbt-power
executable file
·145 lines (128 loc) · 4.77 KB
/
stbt-power
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
#!/bin/bash
#/ usage: stbt power [--help] [--power-outlet <uri>] on|off|status
#/
#/ Send commands to network-controllable power switch.
#/
#/ Options:
#/ -h, --help Print this help message and exit.
#/ --power-outlet <uri>
#/ Address of the power device and the outlet on the device.
#/ The format of <uri> is: (ipp|pdu):<hostname>:<outlet>
#/ ipp|pdu Model of the controllable power supply:
#/ * ipp: IP Power 9258
#/ * pdu: PDUeX KWX
#/ <hostname> The device's network address.
#/ <outlet> Address of the individual power outlet on
#/ the device. Allowed values depend on the
#/ specific device model. Optional for the
#/ "status" command.
#/ Taken from stbt.conf's "global.power_outlet" if not
#/ specified on the command line.
usage() { grep '^#/' "$0" | cut -c4-; } # Print the above usage message.
die() { echo "stbt power: error: $*" >&2; exit 1; }
main() {
while [ $# -gt 0 ]; do
case "$1" in
-h|--help) usage; exit 0;;
--power-outlet) uri="$2"; shift;;
--power-outlet=*) uri="${1#--power-outlet=}";;
*) break;;
esac
shift
done
command="$1"
[[ "$command" =~ ^(on|off|status)$ ]] || die "invalid command '$command'"
[[ -z "$uri" ]] && {
uri=$("$(dirname "$0")"/stbt-config "global.power_outlet" 2>/dev/null) ||
die "no power-outlet specified on command line or in config file"
}
model=$(uri model "$uri") || die "invalid power-outlet uri '$uri'"
hostname=$(uri hostname "$uri") || die "invalid power-outlet uri '$uri'"
outlet=$(uri outlet "$uri") || die "invalid power-outlet uri '$uri'"
[[ -z "$outlet" && $command != status ]] &&
die "missing outlet from uri '$uri'"
$model $command $hostname "$outlet"
}
uri() {
local regex='^(?<model>pdu|ipp):(?<hostname>[^: ]+)(:(?<outlet>[^: ]+))?$'
echo "$2" | perl -ne \
"if (/$regex/) { print $+{$1} ? $+{$1} : ''; }
else { exit 1; }"
}
ipp() {
local command=$1 hostname=$2 outlet="$3" output
output=$(
curl --silent --fail http://admin:12345678@$hostname/Set.cmd?CMD=$(
ipp_command $command "$outlet")
) || die "failed to connect to '$hostname'"
echo "$output" | grep -q BADPARAM &&
die "invalid outlet '$outlet' (hint: use the 'status' command)"
# Prettify the output from the device
echo "$output" |
sed 's|</*html>||g' |
tr "," "\n" |
sed -e 's|=1| = ON|g' -e 's|=0| = OFF|g' |
ipp_filteroutlet "$outlet" |
head -4 # IP Power device prints 8 outlet names, but only has 4.
}
ipp_command() {
local command=$1 outlet="$2"
case "$1" in
on) echo "SetPower+$outlet=1";;
off) echo "SetPower+$outlet=0";;
status) echo "GetPower";;
esac
}
ipp_filteroutlet() {
local outlet="$1"
if [ -z "$outlet" ]; then
cat
else
grep "$outlet" ||
die "invalid outlet '$outlet' (hint: use the 'status' command)"
fi
}
pdu() {
local command=$1 hostname=$2 outlet="$3" pdu_error command_ids data _
pdu_error="Failed to execute command '$command' on PDU '$hostname' "
pdu_error+="outlet '${outlet:-all}'"
if [[ $command == status ]]; then
if [[ -n $outlet ]]; then
pdu_status $hostname "$outlet" || die "$pdu_error"
else
{ pdu_status $hostname '1-A[0-9]+' || die "$pdu_error"; } | \
awk '{ printf("1-A%d: %s\n", NR, $0) }' # Add outlet addresses
fi
else
declare -A command_ids=([on]=1 [off]=2)
# 2 attempts to minimise failure rate
for _ in 1 2; do
data="selOutlet=%3F$(pdu_outlet_no "$outlet")&"
data+="ctrl_all=${command_ids[$command]}"
_curl -d "$data" \
http://admin:admin@$hostname/Forms/index_3 >/dev/null
# The above HTTP POST always succeeds, but doesn't always switch
# the power outlet. Check by querying the new outlet status,
# allowing up to 8 seconds for it to take effect.
for _ in {1..8}; do
sleep 1
pdu_status $hostname "$outlet" | grep -iq "$command" && return
done
done
die "$pdu_error"
fi
}
pdu_status() {
local hostname=$1 outlet="$2"
_curl http://admin:admin@$hostname | awk "/$outlet/,/<\/ul>/" | \
grep -Eo 'ON|OFF'
}
pdu_outlet_no() {
echo $1 | sed 's/^1-A//'
}
_curl() {
# 2 attempts to minimise failure rate
curl --anyauth --fail --silent "$@" ||
curl --anyauth --fail --show-error --silent "$@"
}
main "$@"