implement abstract tags (#577)
[racktables] / gateways / switchvlans / cisco.connector
1 #!/bin/sh
2
3 # This file is a part of RackTables, a datacenter and server room management
4 # framework. See accompanying file "COPYING" for the full copyright and
5 # licensing information.
6
7 [ $# = 7 ] || exit 1
8
9 ENDPOINT=$1
10 HW=$2
11 SW=$3
12 COMMAND=$4
13 FILE1=$5
14 FILE2=$6
15 FILE3=$7
16 MYDIR=`dirname $0`
17 ostype=`uname -s`
18 case "$ostype" in
19 Linux)
20 SEDFLAG='-r'
21 ;;
22 FreeBSD)
23 SEDFLAG='-E'
24 ;;
25 *)
26 exit 7
27 esac
28
29
30 prepare_connect_commands()
31 {
32 [ $# = 1 ] || exit 2
33 local skip=yes cval found=no
34 while read line; do
35 if [ "$skip" = "yes" -a "$line" = "# S-T-A-R-T" ]; then
36 skip=no
37 continue
38 fi
39 if [ "$skip" = "no" -a "$line" = "# S-T-O-P" ]; then
40 skip=yes
41 continue
42 fi
43 [ "$skip" = "yes" ] && continue
44 # Allow comments.
45 [ -z "${line###*}" ] && continue
46
47 # First endpoint string/regexp match is sufficient for us.
48 cval=`echo $line | cut -s -d' ' -f1`
49 if [ -z "${1##$cval}" ]; then
50 found=yes
51 # Don't be too smart at the moment, just be able to handle
52 # the known-good case ;-)
53
54 username=`echo $line | cut -s -d' ' -f5`
55 [ "$username" != "-" ] && echo $username > $CMDS1
56 # access password
57 echo $line | cut -s -d' ' -f6 >> $CMDS1
58 enable_password=`echo $line | cut -s -d' ' -f7`
59 [ "$enable_password" != "-" ] && {
60 echo en >> $CMDS1
61 echo $enable_password >> $CMDS1
62 }
63 # same for ports
64 cat "$CMDS1" > "$CMDS2"
65 # ...and MAC addresses
66 cat "$CMDS1" > "$CMDS3"
67 break
68 fi
69 done < "$MYDIR/cisco.secrets.php"
70 [ "$found" = "yes" ] && return
71 echo "E!connector could not find credentials for $1" >> "$FILE2"
72 exit 3
73 }
74
75 prepare_fetch_commands()
76 {
77 printf 'term len 0\nshow vlan brief\nquit\n' >> $CMDS1
78 printf 'term len 0\nshow int status\nquit\n' >> $CMDS2
79 printf 'term len 0\nshow mac-address-table\nquit\n' >> $CMDS3
80 }
81
82 prepare_push_commands()
83 {
84 printf 'term len 0\nconf t\n' >> $CMDS1
85 while read portname vlanid; do
86 if [ -z "$portname" -o -z "$vlanid" ]; then
87 echo "E!could not parse input in connector" >> "$FILE2"
88 continue
89 fi
90 if [ "$vlanid" = "trunk" ]; then
91 echo "E!trunking is not allowed" >> "$FILE2"
92 continue
93 fi
94 printf "int $portname\n" >> $CMDS1
95 if [ $vlanid -lt 4096 ]; then
96 printf "no description\n" >> $CMDS1
97 else
98 printf "descr VLAN$vlanid\n" >> $CMDS1
99 fi
100 "$MYDIR/vlandecoder" $vlanid >> $CMDS1
101 printf "exit\n" >> $CMDS1
102 echo "I!Port $portname@$ENDPOINT has been assigned to VLAN $vlanid" >> "$FILE2"
103 done < "$FILE1"
104 printf "end\nwri\nquit\n" >> $CMDS1
105 }
106
107 do_fetch()
108 {
109 local tmp_ifname tmp_ifdescr tmp_status tmp_vlanid
110 nc $ENDPOINT 23 < $CMDS1 > "$OUT1"
111 if fgrep -q '% Bad passwords' "$OUT1"; then
112 echo "E!password mismatch while trying to connect to $ENDPOINT" >> "$FILE2"
113 exit 4
114 fi
115 nc $ENDPOINT 23 < $CMDS2 > "$OUT2a"
116 nc $ENDPOINT 23 < $CMDS3 > "$OUT3"
117 cat "$OUT1" | fgrep ' active ' | sed $SEDFLAG 's/^([[:digit:]]+)[[:space:]]+(.+)[[:space:]]+active (.*)/\1=\2/;s/[[:space:]]+$//' > $FILE1
118 # Add trunk data, if appropriate.
119 [ -s "$MYDIR/vlantable" ] && cat "$MYDIR/vlantable" >> $FILE1
120
121 # First extract structured info about VLAN membership, then map
122 # special descriptions into VLAN IDs.
123 cat "$OUT2a" | egrep '^(Et|Fa|Gi|Te)' | sed $SEDFLAG 's/[~%]/__RTTMP_percent_sign__/g;s/^([A-Za-z/0-9]+) +(.*) +(connected|notconnect|disabled|err-disabled|monitoring|suspended) +/\1~\2%\3%/;s/%(trunk|routed|([0-9]+)) .*$/%\1/;s/%(monitoring|suspended)%/%connected%/;s/%(err-disabled)%/%disabled%/;s/ +%/%/;s/~/%/' > $OUT2b
124 while read line; do
125 tmp_ifname=`echo $line | cut -d% -f1`
126 tmp_ifdescr=`echo $line | cut -d% -f2`
127 tmp_status=`echo $line | cut -d% -f3`
128 tmp_vlanid=`echo $line | cut -d% -f4`
129 # If the port has a description pretending to be a martian VLAN, map it onto the VLAN ID.
130 if [ -n "$tmp_ifdescr" -a -z "${tmp_ifdescr##VLAN*}" ]; then
131 tmp_vlanid=${tmp_ifdescr##VLAN}
132 fi
133 echo "$tmp_ifname=$tmp_status,$tmp_vlanid" >> $FILE2
134 done < $OUT2b
135 # FIXME
136 # Here we need to distinguish between different platforms and IOS version,
137 # cause they produce output in different formats.
138 if [ "$SW" = "Cisco+IOS+12.0" ]; then
139 cat "$OUT3" | LC_ALL=C tr -d '\r' | fgrep Dynamic | sed $SEDFLAG 's/ +Dynamic +([0-9]+) +(.+)/=\1@\2/;s/FastEthernet/Fa/;s/GigabitEthernet/Gi/' > "$FILE3"
140 elif [ "$SW" = "Cisco+IOS+12.2" -o "$SW" = "Cisco+IOS+12.1" ]; then
141 case "$HW" in
142 Cisco+Catalyst+35*|Cisco+Catalyst+37*|Cisco+Catalyst+29*)
143 cat "$OUT3" | LC_ALL=C tr -d '\r' | egrep 'STATIC|DYNAMIC' | \
144 sed $SEDFLAG 's/ +([0-9]+|All) +(.+) (DYNAMIC|STATIC) +(.+)/\2=\1@\4/;s/FastEthernet/Fa/;s/GigabitEthernet/Gi/' > "$FILE3"
145 ;;
146 Cisco+Catalyst+49*)
147 cat "$OUT3" | LC_ALL=C tr -d '\r' | fgrep dynamic | \
148 sed $SEDFLAG 's/ +([0-9]+) +([0-9a-f\.]+) dynamic ip +([a-zA-Z/0-9]+) */\2=\1@\3/;s/FastEthernet/Fa/;s/GigabitEthernet/Gi/;s/TenGi/Te/' > "$FILE3"
149 ;;
150 esac
151 fi
152 }
153
154 do_push()
155 {
156 nc $ENDPOINT 23 < $CMDS1 >/dev/null
157 }
158
159 remove_tempfiles()
160 {
161 [ -f "$CMDS1" ] && rm -f "$CMDS1"
162 [ -f "$CMDS2" ] && rm -f "$CMDS2"
163 [ -f "$CMDS3" ] && rm -f "$CMDS3"
164 [ -f "$OUT1" ] && rm -f "$OUT1"
165 [ -f "$OUT2a" ] && rm -f "$OUT2a"
166 [ -f "$OUT2b" ] && rm -f "$OUT2b"
167 [ -f "$OUT3" ] && rm -f "$OUT3"
168 }
169
170 create_tempfiles()
171 {
172 # This one is for VLAN list.
173 CMDS1=`mktemp /tmp/cisco.connector.XXXXXX`
174 # And this one holds ports list...
175 CMDS2=`mktemp /tmp/cisco.connector.XXXXXX`
176 # ...and one more for MAC address table
177 CMDS3=`mktemp /tmp/cisco.connector.XXXXXX`
178 # The following are buffers to hold the whole switch output
179 # before filtering.
180 OUT1=`mktemp /tmp/cisco.connector.XXXXXX`
181 OUT2a=`mktemp /tmp/cisco.connector.XXXXXX`
182 OUT2b=`mktemp /tmp/cisco.connector.XXXXXX`
183 OUT3=`mktemp /tmp/cisco.connector.XXXXXX`
184 [ -f "$CMDS1" -a -f "$CMDS2" -a -f "$CMDS3" -a -f "$OUT1" -a -f "$OUT2a" -a -f "$OUT2b" -a -f "$OUT3" ] && return
185 echo "E!connector cannot create tempfiles" >> "$FILE2"
186 remove_tempfiles
187 exit 5
188 }
189
190 case $COMMAND in
191 fetch)
192 create_tempfiles
193 prepare_connect_commands $ENDPOINT
194 prepare_fetch_commands
195 do_fetch
196 remove_tempfiles
197 ;;
198 push)
199 create_tempfiles
200 prepare_connect_commands $ENDPOINT
201 prepare_push_commands
202 do_push
203 remove_tempfiles
204 ;;
205 *)
206 echo "E!unknown command for connector" >> "$FILE2"
207 exit 6
208 ;;
209 esac
210
211 exit 0