1#!/bin/sh
2
3#
4# Analyze equipment configuration files and chain different phases
5# to build the network graph.
6#
7# Syntax:
8#	$0 [-v] [-1] [-t] [eq ... eq]
9#
10# History :
11#   2004/06/08 : pda/jean   : design
12#   2004/09/29 : pda/jean   : remove generated files before new generation
13#   2006/06/01 : pda/jean   : test snmp community
14#   2006/06/19 : pda/boggia : send sensors
15#   2007/07/17 : pda        : rancid does not detect cisco access point model
16#   2008/10/01 : pda        : add -1 mode ("at least once")
17#   2008/11/12 : pda/jean   : add special equipment _vlan
18#   2010/11/17 : pda        : adapt list-vlans
19#   2010/11/17 : pda/jean   : stop sending sensors
20#   2010/11/23 : pda        : remove status file
21#   2010/12/18 : pda        : rework installation
22#   2012/01/18 : pda        : rancidconfdir + ranciddb -> ranciddir
23#
24
25TMP=/tmp/topo.$$
26TMPERR=/tmp/topoerr.$$
27
28eval `%CONFPROG% \
29		ranciddir \
30		eqvirtdir \
31		eqgendir \
32		filterdir \
33		topograph \
34		topobindir \
35		checkrouterif \
36		ssidsensors \
37		topocpgraph \
38		`
39vlanfile=$eqgendir/_vlan.eq
40
41VERBOSE=0
42
43##############################################################################
44# Utility functions
45##############################################################################
46
47verbose ()
48{
49    if [ $VERBOSE != 0 ]
50    then echo "$*" >&2
51    fi
52}
53
54usage ()
55{
56    echo "usage: anaconf [-v][-1][-t] [eq ...eq]" >&2
57    exit 1
58}
59
60##############################################################################
61# Phases to build the graph
62##############################################################################
63
64#
65# Get equipment list in the rancid configuration file, and extract
66# equipment model from the equipment configuration file.
67#
68
69list_rancid ()
70{
71    verbose "calling 'list-rancid'"
72    $topobindir/list-rancid $ranciddir/router.db $ranciddir/configs > $TMP
73    return $?
74}
75
76#
77# Clean-up the generation directory. This handles the case where
78# old equipments have been removed from rancid.
79#
80
81cleanup_eqgen ()
82{
83    if [ $# = 0 ]
84    then rm -f $eqgendir/*
85    fi
86    return 0
87}
88
89#
90# Get vlans list.
91#
92
93list_vlans ()
94{
95    verbose "calling 'list-vlans'"
96    $topobindir/list-vlans > $vlanfile
97    return $?
98}
99
100#
101# Extract informations from equipment configuration files
102#
103
104analyze_conf ()
105{
106    if [ $# = 0 ]
107    then
108	analyze_eq < $TMP
109    else
110	for eq
111	do
112	    if [ "$eq" = "_vlan" ]
113	    then :
114	    elif [ -f "$eqvirtdir/$eq.eq" ]
115	    then :
116	    elif grep "^$eq " $TMP | analyze_eq
117	    then :
118	    else echo "$eq not found in list-rancid result" >&2
119	    fi
120	done
121    fi
122    return 0
123}
124
125#
126# Filter to rewrite equipement configuration file.
127# Original configuration is simply "piped" to a program
128#
129
130filter ()
131{
132  eqtype=$1
133  infile=$2
134
135  # The filter program is called only if it exists in "filterdir" directory ;
136  # "filterdir" is a variable defined in the configuration file
137
138  if [ -n "$filterdir" -a -f "$filterdir/$eqtype" ] ; then
139
140    # The name of the program called is be the same as the equipment type
141    # Example: /usr/lib/netmagis/filters/cisco
142
143    $filterdir/$eqtype < $infile
144  else
145    cat $infile
146  fi
147}
148
149analyze_eq ()
150{
151    r=1				# 1 if no equipment found
152    while read name type model
153    do
154	# remove domain name
155	n=`echo $name | sed 's/\..*//'`
156
157	verbose "analyze $name"
158	# for an unknown reason, rancid does not detect model for
159	# some Cisco access points (not for all)
160	if [ x"$model" = x ]
161	then model="UNKNOWN"
162	fi
163	eqconf="/tmp/$name.$$"
164	filter $type $ranciddir/configs/$name > $eqconf
165	$topobindir/analyze $topobindir $type "$model" $eqconf $n \
166	    > $eqgendir/$n.eq
167	rm $eqconf
168	r=0			# at least one equipment found
169    done
170    return $r
171}
172
173#
174# Equipments not managed by rancid, just copy files (virtual files)
175#
176
177copy_eqvirt ()
178{
179    for nameeq in `ls $eqvirtdir | grep '\.eq$'`
180    do
181	cp $eqvirtdir/$nameeq $eqgendir/$nameeq
182    done
183    return 0
184}
185
186#
187# Local policy to get sensors for each ssid
188#
189
190ssidsensors ()
191{
192    if [ "$ssidsensors" = yes ]
193    then $topobindir/ssidsensors
194    else cat
195    fi
196}
197
198#
199# Graph generation
200#
201
202build_graph ()
203{
204    verbose "graph generation"
205    cat $eqgendir/* \
206	| ssidsensors \
207	| $topobindir/buildgraph > $topograph.tmp \
208	    && mv $topograph.tmp $topograph
209    return $?
210}
211
212#
213# Check that SNMP community is specified on all equipments
214#
215
216check_snmp ()
217{
218    verbose "SNMP community check"
219    r=0
220    WITHOUTSNMP=`$topobindir/dumpgraph < $topograph \
221	| sed -n '/^eq .* snmp -$/s/eq \([^ ]*\) .*/\1/p'`
222    if [ "$WITHOUTSNMP" != "" ]
223    then
224	(
225	    echo "Warning : equipements without any SNMP community string"
226	    echo "$WITHOUTSNMP" | sed 's/^/	/'
227	) >&2
228	r=1
229    fi
230    return $r
231}
232
233#
234# Check that router interfaces are declared in the DNS
235# (not activated here)
236#
237
238check_dns ()
239{
240    verbose "checking DNS declaration of router interfaces"
241    if [ "checkrouterif" = "yes" ]
242    then
243	$topobindir/getnetif < $topograph | $topobindir/checkdns
244    fi
245    return 0
246}
247
248#
249# Copy graph to another host if configured
250#
251
252copy_graph ()
253{
254    if [ -n "$topocpgraph" -a -n "$topograph" ]
255    then
256    	userhost=`echo "$topocpgraph" | cut -f1 -d:`
257    	destfile=`echo "$topocpgraph" | cut -f2 -d:`
258    	scp -q $topograph $userhost:$destfile.new && \
259	    ssh -q $userhost \
260	    	"mv $destfile $destfile.old;mv $destfile.new $destfile"
261    fi
262    return 0
263}
264
265##############################################################################
266# Phase chaining
267##############################################################################
268
269chain ()
270{
271    list_rancid		\
272	&& cleanup_eqgen $*	\
273	&& list_vlans		\
274	&& analyze_conf $*	\
275	&& copy_eqvirt		\
276	&& build_graph		\
277	&& copy_graph		\
278	&& check_snmp		\
279	&& check_dns
280    return $?
281}
282
283execute ()
284{
285    if [ "$ONCE" = true -o "$TESTONLY" = true ]
286    then
287	chain $*
288	error=$?
289    else
290	rm -f $TMPERR
291	chain $* 2> $TMPERR
292
293	#
294	# Distinguish true errors (return code != 0) from inconsistencies
295	# detected by various tools (buildgraph for example): the last
296	# do not prevent graph building.
297	#
298
299	error=$?
300	if [ $error != 0 ]
301	then
302	    if [ -s $TMPERR ]
303	    then NEWERR="`cat $TMPERR`"
304	    else NEWERR="Unknown error (no error message)"
305	    fi
306	else
307	    if [ -s $TMPERR ]
308	    then NEWERR="`cat $TMPERR`"
309	    fi
310	fi
311
312	#
313	# Display warning or error messages
314	#
315
316	if [ ! -z "$NEWERR" ]
317	then echo "$NEWERR"
318	fi
319    fi
320
321    return $error
322}
323
324##############################################################################
325# Main program
326##############################################################################
327
328#
329# Syntax checking
330#
331
332args=`getopt v1 $*`
333
334if [ $? != 0 ]
335then usage
336fi
337
338set -- $args
339
340TESTONLY=false
341for i in $*
342do
343    case "$i" in
344	-v)	VERBOSE=1
345		shift
346		;;
347	-1)	ONCE=true
348		shift
349		;;
350	--)	shift
351		break
352		;;
353    esac
354done
355
356if [ $? != 0 ]
357then usage
358fi
359
360#
361# Go!
362#
363
364execute $*
365error=$?
366
367#
368# Exit clean-up
369#
370
371rm -f $TMP $TMPERR
372exit $error
373