3 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
6 # lc_common - This file contains common variables and functions to be used by
7 # Lustre cluster config scripts.
9 ################################################################################
11 #****************************** Common Variables ******************************#
12 export PATH=$PATH:/sbin:/usr/sbin
15 export REMOTE=${REMOTE:-"ssh -x -q"}
16 #export REMOTE=${REMOTE:-"pdsh -S -R ssh -w"}
19 export MKFS=${MKFS:-"mkfs.lustre"}
20 export TUNEFS=${TUNEFS:-"tunefs.lustre"}
21 export LCTL=${LCTL:-"lctl"}
23 # Software RAID command
24 export MDADM=${MDADM:-"mdadm"}
26 # Some scripts to be called
27 export MODULE_CONFIG=${MODULE_CONFIG:-"lc_modprobe"}
28 export VERIFY_CLUSTER_NET=${VERIFY_CLUSTER_NET:-"lc_net"}
29 export GEN_HB_CONFIG=${GEN_HB_CONFIG:-"lc_hb"}
30 export GEN_CLUMGR_CONFIG=${GEN_CLUMGR_CONFIG:-"lc_cluman"}
31 export SCRIPT_VERIFY_SRVIP=${SCRIPT_VERIFY_SRVIP:-"lc_servip"}
32 export SCRIPT_GEN_MONCF=${SCRIPT_GEN_MONCF:-"lc_mon"}
33 export SCRIPT_CONFIG_MD=${SCRIPT_CONFIG_MD:-"lc_md"}
34 export SCRIPT_CONFIG_LVM=${SCRIPT_CONFIG_LVM:-"lc_lvm"}
36 # Variables of HA software
37 HBVER_HBV1="hbv1" # Heartbeat version 1
38 HBVER_HBV2="hbv2" # Heartbeat version 2
39 HATYPE_CLUMGR="cluman" # Cluster Manager
41 # Configuration directories and files
42 HA_DIR=${HA_DIR:-"/etc/ha.d"} # Heartbeat configuration directory
43 MON_DIR=${MON_DIR:-"/etc/mon"} # mon configuration directory
44 CIB_DIR=${CIB_DIR:-"/var/lib/heartbeat/crm"} # cib.xml directory
46 HA_CF=${HA_DIR}/ha.cf # ha.cf file
47 HA_RES=${HA_DIR}/haresources # haresources file
48 HA_CIB=${CIB_DIR}/cib.xml
50 CLUMAN_DIR="/etc" # CluManager configuration directory
51 CLUMAN_CONFIG=${CLUMAN_DIR}/cluster.xml
53 CLUMAN_TOOLS_PATH=${CLUMAN_TOOLS_PATH:-"/usr/sbin"} # CluManager tools
54 CONFIG_CMD=${CONFIG_CMD:-"${CLUMAN_TOOLS_PATH}/redhat-config-cluster-cmd"}
56 HB_TMP_DIR="/tmp/heartbeat" # Temporary directory
57 CLUMGR_TMP_DIR="/tmp/clumanager"
58 TMP_DIRS="${HB_TMP_DIR} ${CLUMGR_TMP_DIR}"
60 FS_TYPE=${FS_TYPE:-"lustre"} # Lustre filesystem type
61 FILE_SUFFIX=${FILE_SUFFIX:-".lustre"} # Suffix of the generated config files
63 # Marker of the MD device line
64 export MD_MARKER=${MD_MARKER:-"MD"}
66 # Marker of the LVM device line
67 export PV_MARKER=${PV_MARKER:-"PV"}
68 export VG_MARKER=${VG_MARKER:-"VG"}
69 export LV_MARKER=${LV_MARKER:-"LV"}
71 declare -a CONFIG_ITEM # Items in each line of the CSV file
72 declare -a NODE_NAME # Hostnames of nodes have been configured
74 declare -a MGS_NODENAME # Node names of the MGS servers
75 declare -a MGS_IDX # Indexes of MGSs in the global arrays
76 declare -i MGS_NUM # Number of MGS servers in the cluster
79 # All of the Lustre target items in the CSV file
80 declare -a HOST_NAME MODULE_OPTS DEVICE_NAME MOUNT_POINT DEVICE_TYPE FS_NAME
81 declare -a MGS_NIDS INDEX FORMAT_OPTIONS MKFS_OPTIONS MOUNT_OPTIONS FAILOVERS
83 # Heartbeat software requires that node names in the configuration directive
84 # must (normally) match the "uname -n" of that machine. Since the value of the
85 # "failover nids" field in the CSV file is the NID(s) of failover partner node,
86 # we have to figure out the corresponding hostname of that node.
87 declare -a FAILOVERS_NAMES
89 export VERIFY_CONNECT=true # Verify network connectivity by default
90 export USE_ALLNODES=false # Not operating on all the nodes by default
91 export SPECIFIED_NODELIST="" # Specified list of nodes to be operated on
92 export EXCLUDED_NODELIST="" # Specified list of nodes to be excluded
93 export NODES_TO_USE="" # Defacto list of nodes to be operated on
94 export NODELIST_OPT=""
95 export VERBOSE_OUTPUT=false
99 #****************************** Common Functions ******************************#
101 # verbose_output string
102 # Output verbose information $string
104 if ${VERBOSE_OUTPUT}; then
105 echo "`basename $0`: $*"
110 # error_output string
111 # Output error string to stderr, prefixing with ERROR
112 # for easy error parsing from the rest of the output.
114 echo >&2 "$(basename $0): ERROR: $*"
118 # error_exit rc string
119 # Output error to stderr via error_output and exit with rc.
128 # Check whether the reomte command is pdsh
130 if [ "${REMOTE}" = "${REMOTE#*pdsh}" ]; then
137 # check_file csv_file
138 # Check the file $csv_file
141 if [ $# -eq 0 ]; then
142 error_output "check_file(): Missing CSV file!"
147 if [ ! -s ${CSV_FILE} ]; then
148 error_output "check_file(): ${CSV_FILE}"\
149 "does not exist or is empty!"
157 # Parse a line in the CSV file
160 if [ $# -eq 0 ]; then
161 error_output "parse_line(): Missing argument!"
165 declare -i i=0 # Index of the CONFIG_ITEM array
168 declare -i s_quote_flag=0 # Flag of the single quote character
169 declare -i d_quote_flag=0 # Flag of the double quotes character
170 local TMP_LETTER LINE
174 # Initialize the CONFIG_ITEM array
177 # Get the length of the line
181 while [ ${idx} -lt ${length} ]; do
182 # Get a letter from the line
183 TMP_LETTER=${LINE:${idx}:1}
185 case "${TMP_LETTER}" in
187 if [ ${s_quote_flag} -eq 1 -o ${d_quote_flag} -eq 1 ]
189 CONFIG_ITEM[i]=${CONFIG_ITEM[i]}${TMP_LETTER}
197 if [ ${s_quote_flag} -eq 0 ]; then
204 if [ ${d_quote_flag} -eq 0 ]; then
217 CONFIG_ITEM[i]=${CONFIG_ITEM[i]}${TMP_LETTER}
221 # Extract the real value of each field
222 # Remove surrounded double-quotes, etc.
223 for ((idx = 0; idx <= $i; idx++)); do
224 # Strip the leading and trailing space-characters
225 CONFIG_ITEM[idx]=`expr "${CONFIG_ITEM[idx]}" : '[[:space:]]*\(.*\)[[:space:]]*$'`
227 [ -z "${CONFIG_ITEM[idx]}" ] && continue
229 # Remove the surrounded double-quotes
230 while [ -z "`echo "${CONFIG_ITEM[idx]}"|sed -e 's/^".*"$//'`" ]; do
231 CONFIG_ITEM[idx]=`echo "${CONFIG_ITEM[idx]}" | sed -e 's/^"//' -e 's/"$//'`
234 CONFIG_ITEM[idx]=`echo "${CONFIG_ITEM[idx]}" | sed -e 's/""/"/g'`
241 # If $name is a symbolic link, then display it's value
245 if [ -h "$NAME" ]; then
252 # configured_host host_name
254 # Check whether the devices in $host_name has been configured or not
259 for ((i = 0; i < ${#NODE_NAME[@]}; i++)); do
260 [ "${host_name}" = "${NODE_NAME[i]}" ] && return 0
266 # remote_error fn_name host_addr ret_str
267 # Verify the return result from remote command
269 local fn_name host_addr ret_str
277 if [ "${ret_str}" != "${ret_str#*connect:*}" ]; then
278 error_output "${fn_name}(): ${ret_str}"
282 if [ -z "${ret_str}" ]; then
283 error_output "${fn_name}():" \
284 "No results from remote!" \
285 "Check network connectivity between the local host and ${host_addr}!"
293 # Convert $nid to hostname of the lustre cluster node
297 local addr nettype ip_addr
301 [ "${nid}" != "${nid#*@*}" ] && nettype=${nid#*@} || nettype=tcp
302 if [ -z "${addr}" ]; then
303 echo "`basename $0`: nid2hostname() error: Invalid nid - \"${nid}\"!"
308 lo*) host_name=`hostname`;;
310 # FIXME: Parse the /etc/elanhosts configuration file to
311 # convert ElanID to hostname
314 # FIXME: Convert portal ID to hostname
318 # Is it IP address or hostname?
319 if [ -n "`echo ${ip_addr} | sed -e 's/\([0-9]\{1,3\}\.\)\{3,3\}[0-9]\{1,3\}//'`" ]
326 # Execute remote command to get the host name
327 ret_str=$(${REMOTE} ${ip_addr} "hostname" 2>&1 </dev/null)
328 if [ ${PIPESTATUS[0]} -ne 0 -a -n "${ret_str}" ]; then
329 echo "`basename $0`: nid2hostname() error:" \
330 "remote command to ${ip_addr} error: ${ret_str}"
333 remote_error "nid2hostname" ${ip_addr} "${ret_str}" && return 1
336 host_name=`echo ${ret_str} | awk '{print $2}'`
338 host_name=`echo ${ret_str} | awk '{print $1}'`
348 # Get the hostname of the lustre cluster node which has the nids - $nids
355 for nid in ${nids//,/ }; do
356 [ "${nid}" != "${nid#*@*}" ] && nettype=${nid#*@} || nettype=tcp
359 lo* | elan* | ptl*) ;;
361 host_name=$(nid2hostname ${nid})
362 if [ ${PIPESTATUS[0]} -ne 0 ]; then
370 if [ -z "${host_name}" ]; then
371 echo "`basename $0`: nids2hostname() error:" \
372 "Can not get the hostname from nids - \"${nids}\"!"
380 # ip2hostname_single_node nids
381 # Convert IP addresses in $nids into hostnames
382 # NID in $nids are delimited by commas, ie all the $nids belong to one node
383 ip2hostname_single_node() {
389 for nid in ${orig_nids//,/ }; do
390 [ "${nid}" != "${nid#*@*}" ] && nettype=${nid#*@} || nettype=tcp
393 lo* | elan* | ptl*) ;;
395 host_name=$(nid2hostname ${nid})
396 if [ ${PIPESTATUS[0]} -ne 0 ]; then
401 nid=${host_name}@${nettype}
405 [ -z "${nids}" ] && nids=${nid} || nids=${nids},${nid}
412 # ip2hostname_multi_node nids
413 # Convert IP addresses in $nids into hostnames
414 # NIDs belong to multiple nodes are delimited by colons in $nids
415 ip2hostname_multi_node() {
420 for nid in ${orig_nids//:/ }; do
421 nid=$(ip2hostname_single_node ${nid})
422 if [ ${PIPESTATUS[0]} -ne 0 ]; then
427 [ -z "${nids}" ] && nids=${nid} || nids=${nids}:${nid}
434 # comma_list space-delimited-list
435 # Convert a space-delimited list to a sorted list of unique values
436 # separated by commas.
438 # the sed converts spaces to commas, but leaves the last space
439 # alone, so the line doesn't end with a comma.
440 echo "$*" | tr -s " " "\n" | sort -b -u | tr "\n" " " | sed 's/ \([^$]\)/,\1/g'
443 # host_in_hostlist hostname hostlist
444 # Given a hostname, and a list of hostnames, return true if the hostname
445 # appears in the list of hostnames, or false otherwise.
450 [ -z "$HOST" -o -z "$HOSTLIST" ] && false && return
452 # Hostnames in the list are separated by commas.
453 [[ ,$HOSTLIST, == *,$HOST,* ]] && true && return
458 # exclude_items_from_list list_of_items list_of_items_to_exclude
459 # Given a list of items, and a second list of items to exclude from
460 # the first list, return the contents of the first list minus the contents
462 exclude_items_from_list() {
467 # Handle an empty inlist by throwing back an empty string.
468 if [ -z "$INLIST" ]; then
473 # Handle an empty excludelist by throwing back the inlist unmodified.
474 if [ -z "$EXCLUDELIST" ]; then
479 for ITEM in ${INLIST//,/ }; do
480 if ! host_in_hostlist $ITEM $EXCLUDELIST; then
481 OUTLIST="$OUTLIST,$ITEM"
485 # strip leading comma
489 # get_csv_nodelist csv_file
490 # Get the comma-separated list of all the nodes from the CSV file
496 ! check_file ${csv_file} 2>&1 && return 1
498 all_nodelist=$(egrep -v "([[:space:]]|^)#" ${csv_file} | cut -d, -f 1)
499 all_nodelist=$(comma_list ${all_nodelist})
506 # Get the comma-separated list of nodes to be operated on
507 # Note: CSV_FILE, USE_ALLNODES, SPECIFIED_NODELIST and EXCLUDED_NODELIST
508 # are global variables
512 # Get the list of all the nodes in the CSV file
513 ALL_NODELIST=$(get_csv_nodelist ${CSV_FILE})
514 [ ${PIPESTATUS[0]} -ne 0 ] && echo "${ALL_NODELIST}" && return 1
516 if [ -z "${ALL_NODELIST}" ]; then
517 echo "`basename $0`: get_nodelist() error:"\
518 "There are no hosts in the ${CSV_FILE} file!"
522 if ${USE_ALLNODES}; then
523 echo ${ALL_NODELIST} && return 0
526 if [ -n "${SPECIFIED_NODELIST}" ]; then
527 echo $(exclude_items_from_list ${SPECIFIED_NODELIST} ${EXCLUDED_NODELIST})
531 if [ -n "${EXCLUDED_NODELIST}" ]; then
532 echo $(exclude_items_from_list ${ALL_NODELIST} ${EXCLUDED_NODELIST})
536 # No hosts to be operated on
541 # check_nodelist nodelist
542 # Given a list of nodes to be operated on, check whether the nodelist is
543 # empty or not and output prompt message.
545 local nodes_to_use=$1
547 if [ -z "${nodes_to_use}" ]; then
548 error_output "There are no nodes to be operated on."\
549 "Check the node selection options (-a, -w or -x)."
553 verbose_output "Operating on the following nodes: ${nodes_to_use}"
559 # nid_in_nidlist nid nidlist
560 # Given a nid, and a list of nids in one node (delimited by comma ','),
561 # return true if the nid appears in the list of nids, or false otherwise.
567 [ -z "${nid}" -o -z "${nidlist}" ] && false && return
569 if [[ "${nid}" != *@* || "${nid#*@}" == tcp* ]]; then
570 # network type is tcp
571 for my_nid in ${nidlist//,/ }; do
572 [ "${nid%@*}" = "${my_nid%@*}" ] && true && return
575 # network type is not tcp
576 [[ ,${nidlist}, == *,${nid},* ]] && true && return
582 # get_mgs_nids mgs_hostname mgs_nids
583 # Get the corresponding NID(s) of the MGS node ${mgs_hostname} from the
584 # "mgs nids" field of one lustre target in the CSV file
587 local all_mgs_nids="$2"
591 # Check whether the hostname of the mgs node is in
592 # the mgs nids string
593 for mgs_nids in ${all_mgs_nids//:/ }; do
594 if nid_in_nidlist ${mgs_node} ${mgs_nids}; then
600 # Let's use lctl to get the real nids from the mgs node
601 ret_str=$($REMOTE $mgs_node "PATH=\$PATH:/sbin:/usr/sbin
602 $LCTL list_nids" 2>&1 </dev/null)
603 if [ ${PIPESTATUS[0]} -ne 0 -a -n "${ret_str}" ]; then
604 echo "$(basename $0): get_mgs_nids() error:" \
605 "remote command to ${mgs_node} error: ${ret_str}"
608 remote_error "get_mgs_nids" ${mgs_node} "${ret_str}" && return 1
610 local real_mgs_nids=${ret_str//${mgs_node}:/}
611 for real_mgs_nid in ${real_mgs_nids}; do
612 for mgs_nids in ${all_mgs_nids//:/ }; do
613 if nid_in_nidlist ${real_mgs_nid} ${mgs_nids}; then
620 echo "$(basename $0): get_mgs_nids() error:" \
621 "Can not figure out which nids corresponding to the MGS"\
622 "node ${mgs_node} from \"${all_mgs_nids}\"!"
627 # Check the items required for OSTs, MDTs and MGS
629 # When formatting an OST, the following items: hostname,
630 # device name, device type and mgs nids, cannot have null value.
632 # When formatting an MDT or MGS, the following items: hostname,
633 # device name and device type, cannot have null value.
634 check_lustre_item() {
636 if [ $# -eq 0 ]; then
637 error_output "check_lustre_item(): Missing argument"\
638 "for function check_lustre_item()!"
644 # Check hostname, device name and device type
645 if [ -z "${HOST_NAME[i]}" ] || \
646 [ -z "${DEVICE_NAME[i]}" ] || [ -z "${DEVICE_TYPE[i]}" ]; then
647 error_output "check_lustre_item(): Some required"\
648 "item has null value! Check hostname,"\
649 "device name and device type!"
654 if [ "${DEVICE_TYPE[i]}" = "ost" ]&&[ -z "${MGS_NIDS[i]}" ]; then
655 error_output "check_lustre_item(): OST's mgs nids"\
656 "item has null value!"
661 if [ -z "${MOUNT_POINT[i]}" ]; then
662 error_output "check_lustre_item(): mount"\
663 "point item of target ${DEVICE_NAME[i]} has null value!"
670 # Get the number of MGS nodes in the cluster
673 MGS_NUM=${#MGS_NODENAME[@]}
674 [ -z "${MGS_NODENAME[0]}" ] && let "INIT_IDX += 1" \
675 && let "MGS_NUM += 1"
678 # is_mgs_node hostname
679 # Verify whether @hostname is a MGS node
685 for ((i = ${INIT_IDX}; i < ${MGS_NUM}; i++)); do
686 [ "${MGS_NODENAME[i]}" = "${host_name}" ] && return 0
692 # Check whether the MGS nodes are in the same failover group
700 for ((i = ${INIT_IDX}; i < ${MGS_NUM}; i++)); do
701 mgs_node=${MGS_NODENAME[i]}
702 for ((j = ${INIT_IDX}; j < ${MGS_NUM}; j++)); do
703 [ "${MGS_NODENAME[j]}" = "${mgs_node}" ] && continue 1
706 if [ "${FAILOVERS_NAMES[idx]#*$mgs_node*}" = "${FAILOVERS_NAMES[idx]}" ]
708 error_output "check_mgs_group():"\
709 "MGS node ${mgs_node} is not in the ${HOST_NAME[idx]}"\
719 # Get and check MGS servers.
720 # There should be no more than one MGS specified in the entire CSV file.
724 declare -i exp_idx # Index of explicit MGS servers
725 declare -i imp_idx # Index of implicit MGS servers
726 local is_exp_mgs is_imp_mgs
729 # Initialize the MGS_NODENAME and MGS_IDX arrays
735 for ((i = 0; i < ${#HOST_NAME[@]}; i++)); do
739 # Check whether this node is an explicit MGS node
741 if [ "${DEVICE_TYPE[i]#*mgs*}" != "${DEVICE_TYPE[i]}" ]; then
742 verbose_output "Explicit MGS target" \
743 "${DEVICE_NAME[i]} in host ${HOST_NAME[i]}."
747 if [ "${DEVICE_TYPE[i]}" = "mdt" -a -z "${MGS_NIDS[i]}" ]; then
748 verbose_output "Implicit MGS target" \
749 "${DEVICE_NAME[i]} in host ${HOST_NAME[i]}."
753 # Get and check MGS servers
754 if ${is_exp_mgs} || ${is_imp_mgs}; then
755 # Check whether more than one MGS target in one MGS node
756 if is_mgs_node ${HOST_NAME[i]}; then
757 error_output "check_mgs():"\
758 "More than one MGS target in the same node -"\
759 "\"${HOST_NAME[i]}\"!"
763 # Get and check primary MGS server and backup MGS server
764 if [ "${FORMAT_OPTIONS[i]}" = "${FORMAT_OPTIONS[i]#*noformat*}" ]
767 if [ -z "${MGS_NODENAME[0]}" ]; then
768 if [ "${is_exp_mgs}" = "true" -a ${imp_idx} -gt 1 ] \
769 || [ "${is_imp_mgs}" = "true" -a ${exp_idx} -gt 1 ]; then
770 error_output "check_mgs():"\
771 "There exist both explicit and implicit MGS"\
772 "targets in the CSV file!"
775 MGS_NODENAME[0]=${HOST_NAME[i]}
778 mgs_node=${MGS_NODENAME[0]}
779 if [ "${FAILOVERS_NAMES[i]#*$mgs_node*}" = "${FAILOVERS_NAMES[i]}" ]
781 error_output "check_mgs():"\
782 "More than one primary MGS nodes in the CSV" \
783 "file - ${MGS_NODENAME[0]} and ${HOST_NAME[i]}!"
785 error_output "check_mgs():"\
786 "MGS nodes ${MGS_NODENAME[0]} and ${HOST_NAME[i]}"\
787 "are failover pair, one of them should use"\
788 "\"--noformat\" in the format options item!"
792 else # Backup MGS server
793 if [ "${is_exp_mgs}" = "true" -a ${imp_idx} -gt 1 ] \
794 || [ "${is_imp_mgs}" = "true" -a ${exp_idx} -gt 1 ]; then
795 error_output "check_mgs():"\
796 "There exist both explicit and implicit MGS"\
797 "targets in the CSV file!"
801 if ${is_exp_mgs}; then # Explicit MGS
802 MGS_NODENAME[exp_idx]=${HOST_NAME[i]}
804 exp_idx=$(( exp_idx + 1 ))
806 MGS_NODENAME[imp_idx]=${HOST_NAME[i]}
808 imp_idx=$(( imp_idx + 1 ))
811 fi #End of "if ${is_exp_mgs} || ${is_imp_mgs}"
814 # Check whether the MGS nodes are in the same failover group
815 if ! check_mgs_group; then
822 # Execute remote command to add module options to
823 # the module configuration file
824 add_module_options() {
828 if [ -z "$hostname" ]; then
829 error_output "add_module_options(): Missing hostname!"
833 [ -z "${MODULE_OPTS[i]}" ] && return 0
835 # Execute remote command to add module options to
836 # the module configuration file
837 verbose_output "Adding module options to $hostname"
838 $REMOTE $hostname "PATH=\$PATH:/sbin:/usr/sbin
839 echo \"${MODULE_OPTS[i]}\" | $MODULE_CONFIG"
840 local RC=${PIPESTATUS[0]}
841 if [ $RC -ne 0 ]; then
842 error_output "add_module_options():"\
843 "Failed to add module options to $hostname!"
850 # check_lnet_connect hostname_index mgs_hostname
851 # Check whether the target node can contact the MGS node @mgs_hostname
852 # If @mgs_hostname is null, then it means the primary MGS node
853 check_lnet_connect() {
863 # Execute remote command to check that
864 # this node can contact the MGS node
865 verbose_output "Checking lnet connectivity between" \
866 "${HOST_NAME[i]} and the MGS node ${mgs_node}"
867 mgs_prim_nids=`echo ${MGS_NIDS[i]} | awk -F: '{print $1}'`
869 if [ -z "${mgs_node}" -o $MGS_NUM -eq 1 ]; then
870 nids_str=${mgs_prim_nids} # nids of primary MGS node
871 if [ -z "${nids_str}" ]; then
872 error_output "check_lnet_connect():"\
873 "Check the mgs nids item of host ${HOST_NAME[i]}!"\
874 "Missing nids of the primary MGS node!"
878 # Get the corresponding NID(s) of the MGS node ${mgs_node}
879 # from the "mgs nids" field
880 nids_str=$(get_mgs_nids ${mgs_node} ${MGS_NIDS[i]})
881 if [ ${PIPESTATUS[0]} -ne 0 ]; then
882 error_output "${nids_str}"
888 for mgs_nid in ${nids_str//,/ }
890 for try in $(seq 0 5); do
891 $REMOTE ${HOST_NAME[i]} "PATH=\$PATH:/sbin:/usr/sbin
892 $LCTL ping $mgs_nid 5 1>/dev/null"
893 if [ ${PIPESTATUS[0]} -eq 0 ]; then
894 # This node can contact the MGS node
895 verbose_output "${HOST_NAME[i]} can contact the MGS" \
896 "node $mgs_node by using nid \"$mgs_nid\"!"
903 if ! ${ping_mgs}; then
904 error_output "check_lnet_connect():" \
905 "${HOST_NAME[i]} cannot contact the MGS node ${mgs_node}"\
906 "with nids - \"${nids_str}\"! Check ${LCTL} command!"
913 # Start lnet network in the cluster node and check that
914 # this node can contact the MGS node
916 if ! $VERIFY_CONNECT; then
921 if [ $# -eq 0 ]; then
922 error_output "check_lnet(): Missing argument!"
930 # Execute remote command to start lnet network
931 verbose_output "Starting lnet network on ${HOST_NAME[i]}"
932 ret_str=$($REMOTE ${HOST_NAME[i]} "PATH=\$PATH:/sbin:/usr/sbin
933 modprobe lnet && $LCTL network up" 2>&1)
934 if [ ${PIPESTATUS[0]} -ne 0 ]; then
935 error_output "check_lnet(): start lnet network on" \
936 "${HOST_NAME[i]} error: $ret_str"
940 if is_mgs_node ${HOST_NAME[i]}; then
944 # Execute remote command to check that
945 # this node can contact the MGS node
946 for ((j = 0; j < ${MGS_NUM}; j++)); do
947 if ! check_lnet_connect $i ${MGS_NODENAME[j]}; then
955 # Start lnet network in the MGS node
960 if [ -z "${MGS_NODENAME[0]}" -a -z "${MGS_NODENAME[1]}" ]; then
961 if ${USE_ALLNODES}; then
962 verbose_output "There is no MGS target in the ${CSV_FILE} file."
964 verbose_output "There is no MGS target in the node list \"${NODES_TO_USE}\"."
969 for ((i = ${INIT_IDX}; i < ${MGS_NUM}; i++)); do
970 # Execute remote command to add lnet options lines to
971 # the MGS node's modprobe.conf/modules.conf
973 add_module_options $idx ${MGS_NODENAME[i]} || return ${PIPESTATUS[0]}
975 # Start lnet network in the MGS node
976 check_lnet $idx || return ${PIPESTATUS[0]}
982 # Get all the Lustre target items in the CSV file and do some checks.
985 if [ $# -eq 0 ]; then
986 error_output "get_lustre_items(): Missing argument"\
987 "for function get_lustre_items()!"
995 declare -i line_num=0
999 while read -u 9 -r LINE; do
1000 line_num=${line_num}+1
1001 # verbose_output "Parsing line ${line_num}: $LINE"
1003 # Get rid of the empty line
1004 [ -z "`echo ${LINE} | awk '/[[:alnum:]]/ {print $0}'`" ] && continue
1006 # Get rid of the comment line
1007 [ -z "`echo \"${LINE}\" | egrep -v \"([[:space:]]|^)#\"`" ] && continue
1009 # Skip the Linux MD/LVM line
1010 marker=$(echo ${LINE} | cut -d, -f 2)
1011 if [ "${marker}" = "${MD_MARKER}" -o "${marker}" = "${PV_MARKER}" ] \
1012 || [ "${marker}" = "${VG_MARKER}" -o "${marker}" = "${LV_MARKER}" ]; then
1016 # Skip the host which is not specified in the host list
1017 if ! ${USE_ALLNODES}; then
1018 hostname=$(echo ${LINE} | cut -d, -f 1)
1019 ! host_in_hostlist ${hostname} ${NODES_TO_USE} && continue
1022 # Parse the config line into CONFIG_ITEM
1023 if ! parse_line "$LINE"; then
1024 error_output "parse_line(): Occurred"\
1025 "on line ${line_num} in ${CSV_FILE}: $LINE"
1029 HOST_NAME[idx]=${CONFIG_ITEM[0]}
1030 MODULE_OPTS[idx]=${CONFIG_ITEM[1]}
1031 DEVICE_NAME[idx]=${CONFIG_ITEM[2]}
1032 MOUNT_POINT[idx]=${CONFIG_ITEM[3]}
1033 DEVICE_TYPE[idx]=${CONFIG_ITEM[4]}
1034 FS_NAME[idx]=${CONFIG_ITEM[5]}
1035 MGS_NIDS[idx]=${CONFIG_ITEM[6]}
1036 INDEX[idx]=${CONFIG_ITEM[7]}
1037 FORMAT_OPTIONS[idx]=${CONFIG_ITEM[8]}
1038 MKFS_OPTIONS[idx]=${CONFIG_ITEM[9]}
1039 MOUNT_OPTIONS[idx]=${CONFIG_ITEM[10]}
1040 FAILOVERS[idx]=${CONFIG_ITEM[11]}
1042 MODULE_OPTS[idx]=`echo "${MODULE_OPTS[idx]}" | sed 's/"/\\\"/g'`
1044 # Convert IP addresses in NIDs to hostnames
1045 FAILOVERS_NAMES[idx]=$(ip2hostname_multi_node ${FAILOVERS[idx]})
1046 if [ ${PIPESTATUS[0]} -ne 0 ]; then
1047 error_output "${FAILOVERS_NAMES[idx]}"
1051 # Check some required items for formatting target
1052 if ! check_lustre_item $idx; then
1053 error_output "check_lustre_item():"\
1054 "Occurred on line ${line_num} in ${CSV_FILE}."