Whamcloud - gitweb
LU-1866 osd: ancillary work for initial OI scrub
[fs/lustre-release.git] / lustre / scripts / lustre_config.in
1 #!/bin/bash
2
3 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
4
5 #
6 # lustre_config - format and set up multiple lustre servers from a csv file
7 #
8 # This script is used to parse each line of a spreadsheet (csv file) and 
9 # execute remote commands to format (mkfs.lustre) every Lustre target 
10 # that will be part of the Lustre cluster.
11
12 # In addition, it can also verify the network connectivity and hostnames in 
13 # the cluster, configure Linux MD/LVM devices and produce High-Availability
14 # software configurations for Heartbeat or CluManager.
15 #
16 ################################################################################
17
18 # Usage
19 usage() {
20     cat <<EOF
21
22 Usage: $(basename $0) [options] <-a|-w|-x> <csv file>
23
24     This script is used to format and set up multiple lustre servers from a
25     csv file.
26
27     Options:
28     -h          help and examples
29     -a          select all the nodes from the csv file to operate on
30     -w hostname,hostname,...
31                 select the specified list of nodes (separated by commas) to
32                 operate on rather than all the nodes in the csv file
33     -x hostname,hostname,...
34                 exclude the specified list of nodes (separated by commas)
35     -t HAtype   produce High-Availability software configurations
36                 The argument following -t is used to indicate the High-
37                 Availability software type. The HA software types which 
38                 are currently supported are: hbv1 (Heartbeat version 1)
39                 and hbv2 (Heartbeat version 2).
40     -n          no net - don't verify network connectivity and hostnames
41                 in the cluster
42     -d          configure Linux MD/LVM devices before formatting the
43                 Lustre targets
44     -f          force-format the Lustre targets using --reformat option
45     -m          no fstab change - don't modify /etc/fstab to add the new
46                 Lustre targets
47                 If using this option, then the value of "mount options"
48                 item in the csv file will be passed to mkfs.lustre, else
49                 the value will be added into the /etc/fstab.
50     -u          upgrade Lustre targets from 1.4 to 1.6
51     -v          verbose mode
52     csv file    a spreadsheet that contains configuration parameters
53                 (separated by commas) for each target in a Lustre cluster
54
55 EOF
56 }
57
58 # Samples 
59 sample() {
60     cat <<EOF
61
62 This script is used to parse each line of a spreadsheet (csv file) and 
63 execute remote commands to format (mkfs.lustre) every Lustre target 
64 that will be part of the Lustre cluster.
65
66 It can also optionally: 
67  * upgrade Lustre targets from 1.4 to 1.6
68  * verify the network connectivity and hostnames in the cluster
69  * configure Linux MD/LVM devices
70  * modify /etc/modprobe.conf to add Lustre networking info
71  * add the Lustre server info to /etc/fstab
72  * produce configurations for Heartbeat or CluManager.
73
74 There are 5 kinds of line formats in the csv file. They represent the following 
75 targets:
76 1) Linux MD device
77 The format is:
78 hostname,MD,md name,operation mode,options,raid level,component devices
79
80 hostname            hostname of the node in the cluster
81 MD                  marker of MD device line
82 md name             MD device name, e.g. /dev/md0
83 operation mode      create or remove, default is create
84 options             a "catchall" for other mdadm options, e.g. "-c 128"
85 raid level          raid level: 0,1,4,5,6,10,linear and multipath
86 component devices   block devices to be combined into the MD device
87                     Multiple devices are separated by space or by using
88                     shell expansions, e.g. "/dev/sd{a,b,c}"
89
90 2) Linux LVM PV (Physical Volume)
91 The format is:
92 hostname,PV,pv names,operation mode,options
93
94 hostname            hostname of the node in the cluster
95 PV                  marker of PV line
96 pv names            devices or loopback files to be initialized for later
97                     use by LVM or to be wiped the label, e.g. /dev/sda
98                     Multiple devices or files are separated by space or by
99                     using shell expansions, e.g. "/dev/sd{a,b,c}"
100 operation mode      create or remove, default is create
101 options             a "catchall" for other pvcreate/pvremove options
102                     e.g. "-vv"
103
104 3) Linux LVM VG (Volume Group)
105 The format is:
106 hostname,VG,vg name,operation mode,options,pv paths
107
108 hostname            hostname of the node in the cluster
109 VG                  marker of VG line
110 vg name             name of the volume group, e.g. ost_vg
111 operation mode      create or remove, default is create
112 options             a "catchall" for other vgcreate/vgremove options
113                     e.g. "-s 32M"
114 pv paths            physical volumes to construct this VG, required by
115                     create mode
116                     Multiple PVs are separated by space or by using
117                     shell expansions, e.g. "/dev/sd[k-m]1"
118
119 4) Linux LVM LV (Logical Volume)
120 The format is:
121 hostname,LV,lv name,operation mode,options,lv size,vg name
122
123 hostname            hostname of the node in the cluster
124 LV                  marker of LV line
125 lv name             name of the logical volume to be created (optional)
126                     or path of the logical volume to be removed (required
127                     by remove mode)
128 operation mode      create or remove, default is create
129 options             a "catchall" for other lvcreate/lvremove options
130                     e.g. "-i 2 -I 128"
131 lv size             size [kKmMgGtT] to be allocated for the new LV
132                     Default unit is megabytes.
133 vg name             name of the VG in which the new LV will be created
134
135 5) Lustre target
136 The format is:
137 hostname,module_opts,device name,mount point,device type,fsname,mgs nids,index,
138 format options,mkfs options,mount options,failover nids
139
140 hostname            hostname of the node in the cluster, must match "uname -n"
141 module_opts         Lustre networking module options
142 device name         Lustre target (block device or loopback file)
143 mount point         Lustre target mount point
144 device type         Lustre target type (mgs, mdt, ost, mgs|mdt, mdt|mgs)
145 fsname              Lustre filesystem name, should be limited to 8 characters 
146                     Default is "lustre".
147 mgs nids            NID(s) of remote mgs node, required for mdt and ost targets
148                     If this item is not given for an mdt, it is assumed that
149                     the mdt will also be an mgs, according to mkfs.lustre.
150 index               Lustre target index
151 format options      a "catchall" contains options to be passed to mkfs.lustre
152                     "--device-size", "--param", etc. all goes into this item.
153 mkfs options        format options to be wrapped with --mkfsoptions="" and
154                     passed to mkfs.lustre
155 mount options       If this script is invoked with "-m" option, then the value of
156                     this item will be wrapped with --mountfsoptions="" and passed
157                     to mkfs.lustre, else the value will be added into /etc/fstab.
158 failover nids       NID(s) of failover partner node
159
160 All the NIDs in one node are delimited by commas (','). When multiple nodes are
161 specified, they are delimited by a colon (':').
162
163 Items left blank will be set to defaults.
164
165 Example 1 - Simple, with combo MGS/MDT:
166 -------------------------------------------------------------------------------
167 # combo mdt/mgs
168 lustre-mgs,options lnet networks=tcp,/tmp/mgs,/mnt/mgs,mgs|mdt,,,,--device-size=10240
169
170 # ost0
171 lustre-ost,options lnet networks=tcp,/tmp/ost0,/mnt/ost0,ost,,lustre-mgs@tcp0,,--device-size=10240
172
173 # ost1
174 lustre-ost,options lnet networks=tcp,/tmp/ost1,/mnt/ost1,ost,,lustre-mgs@tcp0,,--device-size=10240
175 -------------------------------------------------------------------------------
176
177 Example 2 - Separate MGS/MDT, two networks interfaces:
178 -------------------------------------------------------------------------------
179 # mgs
180 lustre-mgs1,options lnet 'networks="tcp,elan"',/dev/sda,/mnt/mgs,mgs,,,,--quiet --param="sys.timeout=50",,"defaults,noauto","lustre-mgs2,2@elan"
181
182 # mdt
183 lustre-mdt1,options lnet 'networks="tcp,elan"',/dev/sdb,/mnt/mdt,mdt,lustre2,"lustre-mgs1,1@elan:lustre-mgs2,2@elan",,--quiet --param="lov.stripesize=4194304",-J size=16,"defaults,noauto",lustre-mdt2
184
185 # ost
186 lustre-ost1,options lnet 'networks="tcp,elan"',/dev/sdc,/mnt/ost,ost,lustre2,"lustre-mgs1,1@elan:lustre-mgs2,2@elan",,--quiet,-I 512,"defaults,noauto",lustre-ost2
187 -------------------------------------------------------------------------------
188
189 Example 3 - with combo MGS/MDT failover pair and OST failover pair:
190 -------------------------------------------------------------------------------
191 # combo mgs/mdt
192 lustre-mgs1,options lnet networks=tcp,/tmp/mgs,/mnt/mgs,mgs|mdt,,,,--quiet --device-size=10240,,,lustre-mgs2@tcp0
193
194 # combo mgs/mdt backup (--noformat)
195 lustre-mgs2,options lnet networks=tcp,/tmp/mgs,/mnt/mgs,mgs|mdt,,,,--quiet --device-size=10240 --noformat,,,lustre-mgs1@tcp0
196
197 # ost
198 lustre-ost1,options lnet networks=tcp,/tmp/ost1,/mnt/ost1,ost,,"lustre-mgs1@tcp0:lustre-mgs2@tcp0",,--quiet --device-size=10240,,,lustre-ost2@tcp0
199
200 # ost backup (--noformat) (note different device name)
201 lustre-ost2,options lnet networks=tcp,/tmp/ost2,/mnt/ost2,ost,,"lustre-mgs1@tcp0:lustre-mgs2@tcp0",,--quiet --device-size=10240 --noformat,,,lustre-ost1@tcp0
202 -------------------------------------------------------------------------------
203
204 Example 4 - Configure Linux MD/LVM devices before formatting Lustre targets:
205 -------------------------------------------------------------------------------
206 # MD device on mgsnode
207 mgsnode,MD,/dev/md0,,-q,1,/dev/sda1 /dev/sdb1
208
209 # MD/LVM devices on ostnode
210 ostnode,MD,/dev/md0,,-q -c 128,5,"/dev/sd{a,b,c}"
211 ostnode,MD,/dev/md1,,-q -c 128,5,"/dev/sd{d,e,f}"
212 ostnode,PV,/dev/md0 /dev/md1
213 ostnode,VG,ost_vg,,-s 32M,/dev/md0 /dev/md1
214 ostnode,LV,ost0,,-i 2 -I 128,300G,ost_vg
215 ostnode,LV,ost1,,-i 2 -I 128,300G,ost_vg
216
217 # combo mgs/mdt
218 mgsnode,options lnet networks=tcp,/dev/md0,/mnt/mgs,mgs|mdt,,,,--quiet
219
220 # ost0
221 ostnode,options lnet networks=tcp,/dev/ost_vg/ost0,/mnt/ost0,ost,,mgsnode,,--quiet
222
223 # ost1
224 ostnode,options lnet networks=tcp,/dev/ost_vg/ost1,/mnt/ost1,ost,,mgsnode,,--quiet
225 -------------------------------------------------------------------------------
226
227 EOF
228     exit 0
229 }
230
231 # Get the library of functions
232 . @scriptlibdir@/lc_common
233
234 #***************************** Global variables *****************************#
235 declare -a NODE_NAMES               # node names in the failover group
236 declare -a TARGET_OPTS              # target services in one failover group
237
238 CONFIG_MD_LVM=false
239 MODIFY_FSTAB=true
240 UPGRADE_TARGET=false
241 # Get and check the positional parameters
242 while getopts "aw:x:t:ndfmuhv" OPTION; do
243     case $OPTION in
244     a)
245         [ -z "${SPECIFIED_NODELIST}" ] && [ -z "${EXCLUDED_NODELIST}" ] \
246         && USE_ALLNODES=true
247         NODELIST_OPT="${NODELIST_OPT} -a"
248         ;;
249     w)
250         USE_ALLNODES=false
251         SPECIFIED_NODELIST=$OPTARG
252         NODELIST_OPT="${NODELIST_OPT} -w ${SPECIFIED_NODELIST}"
253         ;;
254     x)
255         USE_ALLNODES=false
256         EXCLUDED_NODELIST=$OPTARG
257         NODELIST_OPT="${NODELIST_OPT} -x ${EXCLUDED_NODELIST}"
258         ;;
259     t)
260         HATYPE_OPT=$OPTARG
261         if [ "${HATYPE_OPT}" != "${HBVER_HBV1}" ] \
262         && [ "${HATYPE_OPT}" != "${HBVER_HBV2}" ] \
263         && [ "${HATYPE_OPT}" != "${HATYPE_CLUMGR}" ]; then
264             error_output "Invalid HA software type" \
265                       "- ${HATYPE_OPT}!"
266             usage 1>&2
267             exit 1
268         fi
269         ;;
270     n)
271         VERIFY_CONNECT=false
272         ;;
273     d)
274         CONFIG_MD_LVM=true
275         ;;
276     f)
277         REFORMAT_OPTION=$"--reformat "
278         ;;
279     m)
280         MODIFY_FSTAB=false
281         ;;
282     u)
283         UPGRADE_TARGET=true 
284         ;;
285     h)
286         usage
287         sample
288         ;;
289     v)
290         VERBOSE_OPT=$" -v"
291         VERBOSE_OUTPUT=true
292         ;;
293     ?)
294         usage 1>&2
295         exit 1
296         ;;
297     esac
298 done
299
300 # Toss out the parameters we've already processed
301 shift  `expr $OPTIND - 1`
302
303 # Here we expect the csv file
304 if [ $# -eq 0 ]; then
305     error_output "Missing csv file!"
306     usage 1>&2
307     exit 1
308 fi
309
310 CSV_FILE=$1
311
312 # Construct the command line of mkfs.lustre
313 construct_mkfs_cmdline() {
314     # Check argument
315     if [ $# -eq 0 ]; then
316         error_output "construct_mkfs_cmdline():"\
317                   "Missing argument for function construct_mkfs_cmdline()!"
318         return 1
319     fi
320
321     declare -i i=$1
322     local mgsnids mgsnids_str
323     local failnids failnids_str
324
325     if $UPGRADE_TARGET; then
326         MKFS_CMD="$TUNEFS --writeconf"
327     else
328         MKFS_CMD="$MKFS $REFORMAT_OPTION"
329     fi
330
331     case "${DEVICE_TYPE[i]}" in
332     "ost")
333         MKFS_CMD="$MKFS_CMD --ost"
334         ;;
335     "mdt")
336         MKFS_CMD="$MKFS_CMD --mdt"
337         ;;
338     "mgs")
339         MKFS_CMD="$MKFS_CMD --mgs"
340         ;;
341     "mdt|mgs" | "mgs|mdt")
342         MKFS_CMD="$MKFS_CMD --mgs --mdt"
343         ;;
344     *)
345         error_output "construct_mkfs_cmdline():"\
346                   "Invalid device type - \"${DEVICE_TYPE[i]}\"!"
347         return 1
348         ;;
349     esac
350
351     if [ -n "${FS_NAME[i]}" ]; then
352         MKFS_CMD="$MKFS_CMD --fsname=${FS_NAME[i]}"
353     fi
354
355     if [ -n "${MGS_NIDS[i]}" ]; then
356         mgsnids_str=${MGS_NIDS[i]}
357         for mgsnids in ${mgsnids_str//:/ }; do
358             MKFS_CMD="$MKFS_CMD --mgsnode=$mgsnids"
359         done
360     fi
361
362     if [ -n "${INDEX[i]}" ]; then
363         MKFS_CMD="$MKFS_CMD --index=${INDEX[i]}"
364     fi
365
366     if [ -n "${FORMAT_OPTIONS[i]}" ]; then
367         MKFS_CMD="$MKFS_CMD ${FORMAT_OPTIONS[i]}"
368     fi
369
370     if ! $UPGRADE_TARGET && [ -n "${MKFS_OPTIONS[i]}" ]; then
371         MKFS_CMD="$MKFS_CMD --mkfsoptions=\"${MKFS_OPTIONS[i]}\""
372     fi
373
374     if [ -n "${MOUNT_OPTIONS[i]}" ] && ! $MODIFY_FSTAB; then
375         MKFS_CMD="$MKFS_CMD --mountfsoptions=\"${MOUNT_OPTIONS[i]}\""
376     fi
377
378     if [ -n "${FAILOVERS[i]}" ]; then
379         failnids_str=${FAILOVERS[i]}
380         for failnids in ${failnids_str//:/ }; do
381             MKFS_CMD="$MKFS_CMD --failnode=$failnids"
382         done
383     fi
384
385     MKFS_CMD="$MKFS_CMD ${DEVICE_NAME[i]}"
386     return 0
387
388
389 # Get all the node names in this failover group
390 get_nodenames() {
391     # Check argument
392     if [ $# -eq 0 ]; then
393         error_output "get_nodenames(): Missing"\
394                   "argument for function get_nodenames()!"
395         return 1
396     fi
397
398     declare -i i=$1
399     declare -i idx
400     local nids
401
402     # Initialize the NODE_NAMES array
403     unset NODE_NAMES
404
405     NODE_NAMES[0]=${HOST_NAME[i]}
406
407     idx=1
408     for nids in ${FAILOVERS_NAMES[i]//:/ }
409     do
410         NODE_NAMES[idx]=$(nids2hostname ${nids})
411         if [ ${PIPESTATUS[0]} -ne 0 ]; then
412             error_output "${NODE_NAMES[idx]}"
413             return 1
414         fi
415     
416         idx=$idx+1
417     done
418
419     return 0
420 }
421
422 # Verify whether the format line has HA items
423 is_ha_line() {
424     declare -i i=$1
425
426     [ -n "${FAILOVERS[i]}" ] && return 0
427
428     return 1
429 }
430
431 # Produce HA software's configuration files
432 gen_ha_config() {
433     declare -i i=$1
434     declare -i idx
435     local  cmd_line
436
437     # Prepare parameters
438     # Hostnames option
439     HOSTNAME_OPT=${HOST_NAME[i]}
440
441     if ! get_nodenames $i; then
442         error_output "gen_ha_config(): Can not get the"\
443         "failover nodenames from failover nids - \"${FAILOVERS[i]}\" in"\
444         "the \"${HOST_NAME[i]}\" failover group!"
445         return 1
446     fi
447
448     for ((idx = 1; idx < ${#NODE_NAMES[@]}; idx++)); do
449         HOSTNAME_OPT=${HOSTNAME_OPT}$":"${NODE_NAMES[idx]}
450     done
451
452     # Target devices option
453     DEVICE_OPT=" -d "${TARGET_OPTS[0]}
454     for ((idx = 1; idx < ${#TARGET_OPTS[@]}; idx++)); do
455         DEVICE_OPT=${DEVICE_OPT}" -d "${TARGET_OPTS[idx]}
456     done
457
458     # Construct the generation script command line
459     case "${HATYPE_OPT}" in
460     "${HBVER_HBV1}"|"${HBVER_HBV2}")    # Heartbeat 
461         cmd_line=${GEN_HB_CONFIG}$" -r ${HATYPE_OPT} -n ${HOSTNAME_OPT}"
462         cmd_line=${cmd_line}${DEVICE_OPT}${VERBOSE_OPT}
463         ;;
464     "${HATYPE_CLUMGR}")                 # CluManager
465         cmd_line=${GEN_CLUMGR_CONFIG}$" -n ${HOSTNAME_OPT}"
466         cmd_line=${cmd_line}${DEVICE_OPT}${VERBOSE_OPT}
467         ;;
468     esac
469     
470     # Execute script to generate HA software's configuration files
471     verbose_output "Generating HA software's configurations in"\
472                "${HOST_NAME[i]} failover group..."
473     verbose_output "${cmd_line}"
474     eval $(echo "${cmd_line}")
475     if [ ${PIPESTATUS[0]} -ne 0 ]; then
476         return 1
477     fi
478     verbose_output "Generate HA software's configurations in"\
479                "${HOST_NAME[i]} failover group OK"
480     
481     return 0
482 }
483
484 # Configure HA software
485 config_ha() {
486     if $UPGRADE_TARGET || [ -z "${HATYPE_OPT}" ]; then
487         return 0
488     fi
489
490     declare -i i j k
491     declare -i prim_idx         # Index for PRIM_HOSTNAMES array
492     declare -i target_idx       # Index for TARGET_OPTS and HOST_INDEX arrays
493
494     declare -a PRIM_HOSTNAMES   # Primary hostnames in all the failover
495                                 # groups in the lustre cluster
496     declare -a HOST_INDEX       # Indices for the same node in all the 
497                                 # format lines in the csv file
498     local prim_host
499
500     # Initialize the PRIM_HOSTNAMES array
501     prim_idx=0
502     unset PRIM_HOSTNAMES
503
504     # Get failover groups and generate HA configuration files
505     for ((i = 0; i < ${#HOST_NAME[@]}; i++)); do
506         prim_host=${HOST_NAME[i]}
507
508         for ((j = 0; j < ${#PRIM_HOSTNAMES[@]}; j++)); do
509             [ "${prim_host}" = "${PRIM_HOSTNAMES[j]}" ] && continue 2
510         done
511
512         target_idx=0
513         unset HOST_INDEX
514         unset TARGET_OPTS
515         for ((k = 0; k < ${#HOST_NAME[@]}; k++)); do
516             if [ "${prim_host}" = "${HOST_NAME[k]}" ] && is_ha_line "${k}"
517             then
518                 HOST_INDEX[target_idx]=$k
519                 TARGET_OPTS[target_idx]=${DEVICE_NAME[k]}:${MOUNT_POINT[k]}
520                 target_idx=$(( target_idx + 1 ))
521             fi
522         done
523
524         if [ ${#TARGET_OPTS[@]} -ne 0 ]; then
525             PRIM_HOSTNAMES[prim_idx]=${prim_host}
526             prim_idx=$(( prim_idx + 1 ))
527
528             if ! gen_ha_config ${HOST_INDEX[0]}; then
529                 return 1
530             fi
531         fi
532     done
533
534     if [ ${#PRIM_HOSTNAMES[@]} -eq 0 ]; then
535         verbose_output "There are no \"failover nids\" items in the"\
536         "csv file. No HA configuration files are generated!"
537     fi
538
539     rm -rf ${TMP_DIRS}
540     return 0
541 }
542
543 # Execute remote command to add lnet options lines to remote nodes'
544 # modprobe.conf/modules.conf and format(mkfs.lustre) Lustre targets
545 mass_config() {
546     local COMMAND
547     declare -a REMOTE_PID 
548     declare -a REMOTE_CMD 
549     declare -i pid_num=0
550     declare -i i=0
551     local checked_hosts=""
552
553     if [ ${#HOST_NAME[@]} -eq 0 ]; then
554         verbose_output "There are no Lustre targets specified."
555         return 0
556     fi
557
558     if ! $UPGRADE_TARGET; then
559         # Start lnet network in the MGS node
560         start_mgs_lnet || return 1    
561     fi
562
563     for ((i = 0; i < ${#HOST_NAME[@]}; i++)); do
564         # Construct the command line of mkfs.lustre
565         if ! construct_mkfs_cmdline $i; then
566             return 1    
567         fi
568
569         # create the mount point on the node
570         COMMAND="mkdir -p ${MOUNT_POINT[i]}"
571         verbose_output "Creating the mount point ${MOUNT_POINT[i]} on" \
572                        "${HOST_NAME[i]}"
573         ${REMOTE} ${HOST_NAME[i]} "${COMMAND}" >&2 
574         if [ ${PIPESTATUS[0]} -ne 0 ]; then
575             error_output "mass_config():"\
576                  "Failed to execute remote command to"\
577                  "create the mountpoint on ${HOST_NAME[i]}!"
578             return 1
579         fi
580
581         if ! $UPGRADE_TARGET && ! is_mgs_node ${HOST_NAME[i]} && \
582         ! host_in_hostlist ${HOST_NAME[i]} $checked_hosts; then
583             # Execute remote command to add lnet options lines to 
584             # modprobe.conf/modules.conf
585             add_module_options $i ${HOST_NAME[i]} || return ${PIPESTATUS[0]}
586
587             # Check lnet networks
588             check_lnet $i || return ${PIPESTATUS[0]}
589
590             checked_hosts="$checked_hosts,${HOST_NAME[i]}"
591         fi
592
593         # Execute remote command to format or upgrade Lustre target
594         local OP
595         $UPGRADE_TARGET && OP="Upgrading" || OP="Formatting"
596         verbose_output "$OP Lustre target ${DEVICE_NAME[i]} on ${HOST_NAME[i]}..."
597
598         COMMAND="export PATH=\$PATH:/sbin:/usr/sbin; $MKFS_CMD"
599         REMOTE_CMD[$pid_num]="$REMOTE ${HOST_NAME[i]} \"$COMMAND\""
600         verbose_output "$OP command line is: ${REMOTE_CMD[$pid_num]}"
601
602         $REMOTE ${HOST_NAME[i]} "$COMMAND" &
603         REMOTE_PID[$pid_num]=$!
604         let pid_num=$pid_num+1
605         sleep 1
606     done
607
608     # Wait for the exit status of the background remote command
609     verbose_output "Waiting for the return of the remote command..."
610     fail_exit_status=false
611     for ((pid_num = 0; pid_num < ${#REMOTE_PID[@]}; pid_num++)); do
612         wait ${REMOTE_PID[${pid_num}]}
613         if [ ${PIPESTATUS[0]} -ne 0 ]; then
614             error_output "mass_config(): Failed"\
615             "to execute \"${REMOTE_CMD[${pid_num}]}\"!"
616             fail_exit_status=true
617         fi
618     done
619
620     if ${fail_exit_status}; then
621         return 1
622     fi    
623
624     verbose_output "Success on all Lustre targets!"
625     return 0
626 }
627
628 # get_mntopts hostname device_name failovers
629 # Construct the mount options of Lustre target @device_name in host @hostname
630 get_mntopts() {
631     local host_name=$1
632     local device_name=$2
633     local failovers=$3
634     local mnt_opts=
635     local ret_str
636
637     [ -n "${failovers}" ] && mnt_opts=defaults,noauto || mnt_opts=defaults
638
639     # Execute remote command to check whether the device
640     # is a block device or not
641     ret_str=$(${REMOTE} ${host_name} \
642             "[ -b ${device_name} ] && echo block || echo loop" 2>&1)
643     if [ ${PIPESTATUS[0]} -ne 0 -a -n "${ret_str}" ]; then
644         echo "`basename $0`: get_mntopts() error:" \
645         "remote command to ${host_name} error: ${ret_str}"
646         return 1
647     fi
648
649     if [ -z "${ret_str}" ]; then
650         echo "`basename $0`: get_mntopts() error: remote error:" \
651         "No results from remote!" \
652         "Check network connectivity between the local host and ${host_name}!"
653         return 1
654     fi
655
656     [ "${ret_str}" != "${ret_str#*loop}" ] && mnt_opts=${mnt_opts},loop
657
658     echo ${mnt_opts}
659     return 0
660 }
661
662 # Execute remote command to modify /etc/fstab to add the new Lustre targets
663 modify_fstab() {
664     declare -i i
665     local mntent mntopts device_name
666     local COMMAND
667
668     if ! ${MODIFY_FSTAB}; then
669         return 0    
670     fi
671
672     for ((i = 0; i < ${#HOST_NAME[@]}; i++)); do
673         verbose_output "Modify /etc/fstab of host ${HOST_NAME[i]}"\
674                    "to add Lustre target ${DEVICE_NAME[i]}"
675         mntent=${DEVICE_NAME[i]}"\t\t"${MOUNT_POINT[i]}"\t\t"${FS_TYPE}
676
677         # Get mount options
678         if [ -n "${MOUNT_OPTIONS[i]}" ]; then
679             # The mount options already specified in the csv file.
680             mntopts="${MOUNT_OPTIONS[i]}"
681         else
682             mntopts=$(get_mntopts ${HOST_NAME[i]} ${DEVICE_NAME[i]}\
683                     ${FAILOVERS[i]})
684             if [ ${PIPESTATUS[0]} -ne 0 ]; then
685                 error_output "${mntopts}"
686                 return 1
687             fi
688         fi
689
690         mntent=${mntent}"\t"${mntopts}"\t"0" "0
691         verbose_output "`echo -e ${mntent}`"
692
693         # Execute remote command to modify /etc/fstab
694         device_name=${DEVICE_NAME[i]//\//\\/}
695         COMMAND=". @scriptlibdir@/lc_common; \
696                 sed -i \"/^${device_name}\t/d\" \$(fcanon /etc/fstab); \
697                 echo -e \"${mntent}\" >> \$(fcanon /etc/fstab)"
698         ${REMOTE} ${HOST_NAME[i]} "${COMMAND}" >&2
699         if [ ${PIPESTATUS[0]} -ne 0 ]; then
700             error_output "modify_fstab():"\
701             "Failed to modify /etc/fstab of host ${HOST_NAME[i]}"\
702             "to add Lustre target ${DEVICE_NAME[i]}!"
703             return 1
704         fi
705     done
706
707     return 0
708 }
709
710 #********************************* Main Flow **********************************#
711
712 # Check the csv file
713 check_file $CSV_FILE || exit ${PIPESTATUS[0]}
714
715 # Get the list of nodes to be operated on
716 NODES_TO_USE=$(get_nodelist) || error_exit ${PIPESTATUS[0]} "$NODES_TO_USE"
717
718 # Check the node list
719 check_nodelist $NODES_TO_USE || exit ${PIPESTATUS[0]}
720
721 if ${VERIFY_CONNECT}; then
722 # Check the network connectivity and hostnames
723     echo "`basename $0`: Checking the cluster network connectivity"\
724          "and hostnames..."
725     if ! ${VERIFY_CLUSTER_NET} ${NODELIST_OPT} ${VERBOSE_OPT} ${CSV_FILE}; then
726         exit 1
727     fi
728     echo "`basename $0`: Check the cluster network connectivity"\
729          "and hostnames OK!"
730     echo
731 fi
732
733 if $CONFIG_MD_LVM && ! $UPGRADE_TARGET; then
734 # Configure Linux MD/LVM devices
735     echo "`basename $0`: Configuring Linux MD/LVM devices..."
736     if ! ${SCRIPT_CONFIG_MD} ${NODELIST_OPT} ${VERBOSE_OPT} ${CSV_FILE}; then
737         exit 1
738     fi
739
740     if ! ${SCRIPT_CONFIG_LVM} ${NODELIST_OPT} ${VERBOSE_OPT} ${CSV_FILE}; then
741         exit 1
742     fi
743     echo "`basename $0`: Configure Linux MD/LVM devices OK!"
744     echo
745 fi
746
747 # Configure the Lustre cluster
748 echo "`basename $0`: ******** Lustre cluster configuration BEGIN ********"
749
750 get_lustre_items $CSV_FILE || exit ${PIPESTATUS[0]}
751
752 check_mgs || exit ${PIPESTATUS[0]}
753
754 # Format or upgrade Lustre server targets
755 mass_config || exit ${PIPESTATUS[0]}
756
757 # Modify /etc/fstab to add the new Lustre server targets
758 modify_fstab || exit ${PIPESTATUS[0]}
759
760 # Produce HA software's configuration files
761 if ! config_ha; then
762     rm -rf ${TMP_DIRS}
763     exit 1
764 fi
765
766 echo "`basename $0`: ******** Lustre cluster configuration END **********"
767
768 exit 0