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