Whamcloud - gitweb
d618c699a3a52c2c96775dc3d0b37f3ab54bf941
[fs/lustre-release.git] / lustre / scripts / lc_net.in
1 #!/bin/bash
2 #
3 # lc_net - script for Lustre cluster network verification
4 #
5 ###############################################################################
6
7 # Usage
8 usage() {
9         cat >&2 <<EOF
10
11 Usage:  `basename $0` [options] <csv file>
12
13         Options:
14         -a              select all the nodes from the csv file to operate on
15         -w hostname,hostname,...
16                         select the specified list of nodes (separated by commas)
17         -x hostname,hostname,...
18                         exclude the specified list of nodes (separated by commas)
19         -v              verbose mode
20         csv file        a spreadsheet that contains configuration parameters 
21                         (separated by commas) for each target in a Lustre cl-
22                         uster, the first field of each line is the host name 
23                         of the cluster node
24
25 EOF
26         exit 1
27 }
28
29 # Get the library of functions
30 . @scriptlibdir@/lc_common
31
32 VERBOSE_OUTPUT=false
33 # Get and check the positional parameters
34 while getopts "aw:x:v" OPTION; do
35         case $OPTION in
36         a)
37                 [ -z "${SPECIFIED_NODELIST}" ] && [ -z "${EXCLUDED_NODELIST}" ]\
38                 && USE_ALLNODES=true
39                 ;;
40         w)
41                 USE_ALLNODES=false
42                 SPECIFIED_NODELIST=$OPTARG
43                 ;;
44         x)
45                 USE_ALLNODES=false
46                 EXCLUDED_NODELIST=$OPTARG
47                 ;;
48         v) 
49                 VERBOSE_OUTPUT=true
50                 ;;
51         ?) 
52                 usage 
53         esac
54 done
55
56 # Toss out the parameters we've already processed
57 shift  `expr $OPTIND - 1`
58
59 # Here we expect the csv file
60 if [ $# -eq 0 ]; then
61         echo >&2 $"`basename $0`: Missing csv file!"
62         usage
63 fi
64
65 # Global variables
66 CSV_FILE=$1
67 declare -a HOST_NAMES
68 declare -a HOST_IPADDRS
69
70 # Get the hosts to be operated on
71 get_hostnames() {
72         local NODES_TO_USE
73
74         # Initialize the HOST_NAMES array
75         unset HOST_NAMES
76
77         # Get the list of nodes to be operated on
78         NODES_TO_USE=$(get_nodelist)
79         [ ${PIPESTATUS[0]} -ne 0 ] && echo >&2 "${NODES_TO_USE}" && return 1
80
81         # Check the node list
82         if [ -z "${NODES_TO_USE}" ]; then
83                 echo "`basename $0`: There are no hosts to be operated on."\
84                 "Check the node selection options (-a, -w or -x)."
85                 return 1
86         fi
87
88         # Load the hostnames in the nodelist into the array
89         HOST_NAMES=( $(echo ${NODES_TO_USE//,/ }) )
90
91         return 0
92 }
93
94 # ping_host host_name
95 # Check whether host $host_name is reachable. 
96 # If it is, then return the IP address of this host.
97 ping_host() {
98         local host_name=$1
99         local ip_addr=
100         local ret_str
101
102         if [ -z "${host_name}" ]; then
103                 echo "`basename $0`: ping_host() error: Missing hostname!"
104                 return 1
105         fi
106
107         # Run ping command
108         ret_str=$(ping -c1 ${host_name} 2>&1)
109         if [ ${PIPESTATUS[0]} -ne 0 ]; then
110                 if [ -n "${ret_str}" ]; then
111                         echo "`basename $0`: ping_host() error: ${ret_str}!"
112                 else
113                         echo "`basename $0`: ping_host() error:"\
114                         "Host ${host_name} does not respond to ping!"
115                 fi
116                 return 1
117         fi
118
119         # Get the IP address
120         ip_addr=`echo "${ret_str}" | head -1 | awk '{print $3}' | \
121                 sed -e 's/^(//' -e 's/)$//'`
122
123         echo "${ip_addr}"
124         return 0
125 }
126
127 # local_check index
128 # Check the network connectivity between local host and ${HOST_NAMES[index]}.
129 local_check() {
130         declare -i i=$1
131
132         # Check whether ${HOST_NAMES[i]} is reachable
133         # and get the IP address of this host from ping
134         HOST_IPADDRS[i]=$(ping_host ${HOST_NAMES[i]})
135         if [ ${PIPESTATUS[0]} -ne 0 ]; then
136                 echo >&2 "${HOST_IPADDRS[i]}"
137                 return 1
138         fi
139
140         return 0
141 }
142
143 # remote_check index
144 # Check whether ${HOST_NAMES[index]} can resolve its own name and whether
145 # this host agrees with the local host about what its name is resolved to.
146 remote_check() {
147         declare -i i=$1
148         local cmd ret_str
149         local ip_addr=          # the IP address got from remote ping
150
151         # Execute remote command to check whether ${HOST_NAMES[i]}
152         # can resolve its own name
153         cmd="ping -c1 ${HOST_NAMES[i]} 2>&1"
154         ret_str=$(${REMOTE} ${HOST_NAMES[i]} "${cmd}" 2>&1)
155         if [ ${PIPESTATUS[0]} -ne 0 -a -n "${ret_str}" ]; then
156                 echo >&2 "`basename $0`: remote_check() error:"\
157                 "remote to ${HOST_NAMES[i]} error: ${ret_str}!"
158                 return 1
159         fi
160
161         if [ -z "${ret_str}" ]; then
162                 echo >&2 "`basename $0`: remote_check() error:"\
163                 "No results from ${HOST_NAMES[i]}! Check the network"\
164                 "connectivity between local host and ${HOST_NAMES[i]}!"
165                 return 1
166         fi
167
168         # Get the IP address of ${HOST_NAMES[i]} from its own ping
169         if is_pdsh; then
170                 ip_addr=`echo "${ret_str}" | head -1 | awk '{print $4}'`
171         else
172                 ip_addr=`echo "${ret_str}" | head -1 | awk '{print $3}'`
173         fi
174         ip_addr=`echo "${ip_addr}" | sed -e 's/^(//' -e 's/)$//'`
175
176         # Compare IP addresses
177         # Check whether ${HOST_NAMES[i]} agrees with the local host
178         # about what its name is resolved to.
179         if [ "${ip_addr}" != "${HOST_IPADDRS[i]}" ]; then
180                 echo >&2 "`basename $0`: remote_check() error:"\
181                 "Local host resolves ${HOST_NAMES[i]} to IP address"\
182                 "\"${HOST_IPADDRS[i]}\", while its own resolution is"\
183                 "\"${ip_addr}\". They are not the same!"
184                 return 1
185         fi
186         
187         return 0
188 }
189
190 # network_verify
191 # Verify name resolution and network connectivity of the Lustre cluster
192 network_verify() {
193         declare -i i
194
195         # Initialize the HOST_IPADDRS array
196         unset HOST_IPADDRS
197
198         # Get all the host names to be operated on 
199         ! get_hostnames && return 1
200
201         # Check the network connectivity between local host 
202         # and other cluster nodes
203         for ((i = 0; i < ${#HOST_NAMES[@]}; i++)); do
204                 [ "${HOST_NAMES[i]}" = "`hostname`" ] && continue
205
206                 verbose_output "Verifying network connectivity between"\
207                                "\"`hostname`\" and \"${HOST_NAMES[i]}\"..."
208                 ! local_check $i && return 1
209                 ! remote_check $i && return 1
210                 verbose_output "OK"
211         done
212
213         return 0
214 }
215
216 # Main flow
217 if ! check_file ${CSV_FILE}; then
218         exit 1  
219 fi
220
221 # Cluster network verification
222 if ! network_verify; then
223         exit 1  
224 fi
225
226 exit 0