r2083 + setSwitchVLANs(): use oneLiner(), handle "C" messages
[racktables] / gateways / switchvlans / main
CommitLineData
533aefb8 1#!/bin/sh
47a3aa24
DO
2
3# This is a RackTables gateway for changing switch ports membership
4# across VLANs. It works accordingly to the gateway protocol described
5# in gateways.php and accepts the following commands on its stdin:
fc11a02c
DO
6#
7# * connect: connect to a switch, fetch all necessary data, store and
8# disconnect
9#
47a3aa24
DO
10# * listvlans: list all VLANs found on the switch, propably filtering
11# out those administratively prohibited. Only the VLANs from this
12# list will be allowed as new destination for 'set' command.
fc11a02c 13#
47a3aa24 14# * listports: list all ports on the switch and their current status.
fc11a02c
DO
15# Untagged (switchport mode access) ports will be shown with their
16# VLAN ID and tagged ports will be shown as 'trunk' regardless of
17# how many VLANs they are members of.
18#
19# * listmacs: output unsorted list of all dynamically learned MAC
20# addresses present on the switch
21#
47a3aa24 22
7865c525
DO
23endpoint=
24hw=
25sw=
26user=
35331abf 27handler=
7865c525 28CONNECTED=0
35331abf 29MYDIR=`dirname $0`
47a3aa24 30
7cc7b297
DO
31decode_error()
32{
33 case "$1" in
34 0)
35 echo -n 'success'
36 ;;
37 1)
38 echo -n 'internal error 1'
39 ;;
40 2)
41 echo -n 'internal error 2'
42 ;;
43 3)
44 echo -n 'password not found'
45 ;;
46 4)
47 echo -n 'invalid password'
48 ;;
49 5)
50 echo -n 'cannot create temporary files'
51 ;;
52 6)
53 echo -n 'invalid command'
54 ;;
55 7)
56 echo -n 'unknown host OS'
57 ;;
58 *)
59 echo -n 'unknown error'
60 ;;
61 esac
62}
63
35331abf 64# Not only connect, but gather all the data at once and remember the context.
533aefb8
DO
65do_connect()
66{
7865c525
DO
67 endpoint=`echo $args | cut -s -d' ' -f1`
68 hw=`echo $args | cut -s -d' ' -f2`
69 sw=`echo $args | cut -s -d' ' -f3`
70 user=`echo $args | cut -s -d' ' -f4`
35331abf 71 # sanity checks
533aefb8
DO
72 if [ -z "$endpoint" -o -z "$hw" -o -z "$sw" -o -z "$user" ]; then
73 echo 'ERR!too few arguments to connect'
74 return
75 fi
35331abf 76 case "$sw" in
987af914 77 Cisco+IOS+12.0|Cisco+IOS+12.1|Cisco+IOS+12.2)
35331abf
DO
78 handler=cisco
79 ;;
80 *)
81 echo "ERR!Don't know how to handle $sw on $endpoint"
82 return
83 ;;
84 esac
85
533aefb8
DO
86 # prepare temp files
87 PORTINFO=`mktemp /tmp/racktables.XXXX`
88 if ! [ -f "$PORTINFO" ]; then
89 echo 'ERR!could not create portinfo tmpfile'
90 return
91 fi
92 VLANINFO=`mktemp /tmp/racktables.XXXX`
93 if ! [ -f "$VLANINFO" ]; then
94 echo 'ERR!could not create vlaninfo tmpfile'
95 rm -f "$PORTINFO"
96 return
97 fi
fc11a02c
DO
98 MACINFO=`mktemp /tmp/racktables.XXXX`
99 if ! [ -f "$MACINFO" ]; then
100 echo 'ERR!could not create MACinfo tmpfile'
101 rm -f "$PORTINFO" "$VLANINFO"
102 return
103 fi
47a3aa24 104
533aefb8 105 # get the data
fc11a02c 106 "$MYDIR/$handler.connector" $endpoint $hw $sw fetch "$VLANINFO" "$PORTINFO" "$MACINFO"
35331abf
DO
107 ret=$?
108 if [ $ret = 0 ]; then
109 CONNECTED=1
110 echo "OK!connected to $endpoint";
111 else
7cc7b297
DO
112 echo -n "ERR!Cannot connect to $endpoint ("
113 decode_error $ret
114 echo ')'
35331abf 115 fi
533aefb8
DO
116}
117
118do_listfile()
119{
120 local F=$1
121 if ! [ -f "$F" ]; then
122 echo "ERR!Lost temp file '$F' on the way"
123 return
124 fi
125 echo -n 'OK!'
d28ea105 126 local semicolon=''
533aefb8
DO
127 # tr might do the work, but use our chance to perform filtering once more
128 cat "$F" | while read line; do
129 [ "$line" = "" ] && continue
d28ea105
DO
130 echo -n "$semicolon$line"
131 semicolon=';'
533aefb8
DO
132 done
133 echo
134}
135
136do_set()
137{
7865c525
DO
138 # sanity checks
139 local setline=$1
140 if [ -z "$setline" ]; then
141 echo 'ERR!missing set argument'
142 return
143 fi
7865c525
DO
144 local REQUESTS=`mktemp /tmp/racktables.XXXX`
145 local REPLIES=`mktemp /tmp/racktables.XXXX`
146 echo $1 | tr ';' '\n' | while read setexpr; do
147 portname=`echo $setexpr | cut -s -d'=' -f1`
148 newvlan=`echo $setexpr | cut -s -d'=' -f2`
0dc931a4 149 curvlan=`egrep "^$portname=" $PORTINFO | cut -s -d'=' -f2 | cut -d',' -f2`
7865c525 150 if [ -z "$curvlan" ]; then
f0ff4930 151 echo "C!167!$portname" >> "$REPLIES"
7865c525
DO
152 continue
153 fi
154 if [ "$curvlan" = "trunk" ]; then
f0ff4930 155 echo "C!168!$portname" >> "$REPLIES"
7865c525
DO
156 continue
157 fi
5b6704b5 158 [ "$curvlan" = "$newvlan" ] && continue
7865c525 159 echo "$portname $newvlan" >> "$REQUESTS"
7082c58d 160 cmembers=`grep -c ",$newvlan$" "$PORTINFO"`
38356044 161 if [ "$cmembers" = "0" -a $newvlan -lt 4096 ]; then
f0ff4930
DO
162 echo "C!203!$portname!$newvlan" >> "$REPLIES"
163 echo "C!204" >> "$REPLIES"
7082c58d 164 fi
7865c525 165 done
f0ff4930 166 nr=`egrep -c '^C!1.' "$REPLIES"`
7865c525 167 if [ "$nr" -ge 1 ]; then
f0ff4930 168 echo "C!205!$nr" >> "$REPLIES"
7865c525 169 fi
533aefb8 170
7865c525 171 nq=`egrep -c '^.' "$REQUESTS"`
5b6704b5 172 if [ "$nq" -ge 1 ]; then
7865c525 173 # Go!
fc11a02c 174 "$MYDIR/$handler.connector" $endpoint $hw $sw push "$REQUESTS" "$REPLIES" "$MACINFO"
7865c525
DO
175 local ret=$?
176
177 if [ $ret != 0 ]; then
f0ff4930 178 echo "C!169!$endpoint!$ret"
7865c525
DO
179 return
180 fi
f0ff4930 181 echo "C!63!$nq" >> "$REPLIES"
7865c525
DO
182 fi
183 echo -n 'OK!'
184 local SEMICOLON=
185 while read reply; do
186 echo -n $SEMICOLON$reply
187 SEMICOLON=';'
7c3cb03c 188 timestamp=`date '+%Y-%m-%d %H:%M:%S'`
0dc931a4 189 [ -w "$MYDIR/changes.log" ] && echo "$timestamp $user@$endpoint $reply" >> "$MYDIR/changes.log"
7865c525
DO
190 done < "$REPLIES"
191 echo
192 rm -f "$REQUESTS" "$REPLIES"
193}
533aefb8
DO
194
195# main loop
196while read cmd args; do
47a3aa24 197 case $cmd in
533aefb8
DO
198 connect)
199 if [ $CONNECTED = 1 ]; then
200 echo 'ERR!Already connected'
201 else
202 do_connect $args
203 fi
204 ;;
47a3aa24 205 listvlans)
533aefb8
DO
206 if [ $CONNECTED = 1 ]; then
207 do_listfile "$VLANINFO"
208 else
209 echo 'ERR!Not connected'
210 fi
47a3aa24
DO
211 ;;
212 listports)
533aefb8
DO
213 if [ $CONNECTED = 1 ]; then
214 do_listfile "$PORTINFO"
215 else
216 echo 'ERR!Not connected'
217 fi
47a3aa24 218 ;;
9e76e210
DO
219 listmacs)
220 if [ $CONNECTED = 1 ]; then
221 do_listfile "$MACINFO"
222 else
223 echo 'ERR!Not connected'
224 fi
225 ;;
47a3aa24 226 set)
533aefb8
DO
227 if [ $CONNECTED = 1 ]; then
228 do_set $args
229 else
230 echo 'ERR!Not connected'
231 fi
47a3aa24
DO
232 ;;
233 *)
343d4bec 234 echo "ERR!unknown command $cmd"
47a3aa24
DO
235 esac
236done
237
fc11a02c 238rm -f "$PORTINFO" "$VLANINFO" "$MACINFO"
47a3aa24 239exit 0