Rename gpfs-nas-kickstart.cfg since it no longer references GPFS
[autocluster.git] / vircmd
1 #!/bin/bash
2 #make running virsh commands on a cluster easier
3
4 ####################
5 # show program usage
6 usage ()
7 {
8     cat >&2 <<EOF
9 Usage: vircmd [OPTION] ... <COMMAND>
10   options:
11     -x                    enable script debugging 
12     -n                    don't include the TSM node (if any)
13     -w, --wait [timeout]  for start/shutdown wait for desired state change
14
15   commands:
16      start CLUSTERNAME
17            start cluster nodes
18
19      destroy CLUSTERNAME
20            power off cluster nodes (may cause data loss)
21
22      shutdown CLUSTERNAME
23            shutdown cluster nodes
24
25      undefine CLUSTERNAME
26            remove cluster
27
28   CLUSTERNAME can be a glob-style pattern that specifies cluster nodes
29 EOF
30     exit 1
31 }
32
33 ############################
34 # parse command line options
35 temp=$(getopt -n "$prog" -o "xnw::" -l help -l wait:: -- "$@")
36
37 [ $? != 0 ] && usage
38
39 eval set -- "$temp"
40
41 no_tsm=0
42 wait=false
43 timeout=""
44
45 while true ; do
46     case "$1" in
47         -x) set -x; shift ;;
48         -n) no_tsm=1; shift ;;
49         -w|--wait) wait=true ; timeout="$2" ; shift 2 ;;
50         --) shift ; break ;;
51         -h|--help|*) usage ;; # Shouldn't happen, so this is reasonable.
52     esac
53 done
54
55 if [ $# -lt 2 ]; then
56     echo "Usage: vircmd COMMAND CLUSTERNAME"
57     exit 1
58 fi
59
60 cmd="$1"
61 cluster="$2"
62 count=0
63
64 if $wait ; then
65     case "$cmd" in
66         start)     desired_state="running"  ;;
67         shutdown)  desired_state="shut off" ;;
68         *) echo "waiting not supported with \"$cmd\"" ; echo ; usage ;;
69     esac
70 fi
71
72 export VIRSH_DEFAULT_CONNECT_URI=qemu:///system
73
74 get_nodes ()
75 {
76     for i in $domains ; do
77         case "$i" in
78             ($1)
79             # If we're not skipping the TSM node or this isn't the TSM node...
80             if [ "$no_tsm" = 0 -o "${i/tsm/}" = "$i" ] ; then
81                 nodes="${nodes} ${i}"
82             fi
83         esac
84     done
85 }
86
87 domains=$(virsh list --all | awk '{print $2}' | tail -n +3)
88 nodes=""
89
90 # If the cluster name doesn't have a wildcard then we need to be inventive.
91 if [ "${cluster/[\[\]\?\*]/}" = "$cluster" ] ; then
92     get_nodes "${cluster}n[0-9]"
93     get_nodes "${cluster}n[0-9][0-9]"
94     get_nodes "${cluster}base[0-9]"
95     get_nodes "${cluster}base[0-9][0-9]"
96     get_nodes "${cluster}storage[0-9]"
97     get_nodes "${cluster}storage[0-9][0-9]"
98     get_nodes "${cluster}tsm"
99     get_nodes "${cluster}tsm[0-9]"
100     get_nodes "${cluster}tsm[0-9][0-9]"
101 else
102     get_nodes "$cluster"
103 fi
104
105 [ -n "$nodes" ] || {
106     echo "No nodes in cluster $2"
107     exit 1
108 }
109
110 rc=0
111
112 for i in $nodes ; do
113     # We want to retry the command when we see an internal error.
114     for x in $(seq 1 5) ; do
115         out=$(virsh $cmd "$i" 2>&1)
116         ret=$? # Hard to avoid this since we always want to echo $out :-(
117         echo "$out"
118         if [ $ret -ne 0 ] ; then
119             case "$out" in
120                 *internal\ error*)
121                     echo "Retrying \"virsh $cmd $i\" due to internal error"
122                     sleep 3
123                     continue
124             esac
125         fi
126         break
127     done
128     [ $ret  = 0 ] || rc=$ret
129 done
130
131 # Now comes the waiting... but we don't wait if there was an error.
132 if [ $rc -ne 0 ] || ! $wait ; then
133     exit $rc
134 fi
135
136 count=0
137 while : ; do
138     if [ -n "$timeout" ] && [ $count -ge "$timeout" ] ; then
139         echo "Timed out after ${timeout}s waiting for nodes to enter state \"${desired_state}\":"
140         echo
141         fmt='%-20s %s\n'
142         printf "$fmt" "Domain" "State"
143         printf "$fmt" "------" "-----"
144         for i in $nodes ; do
145             state=$(virsh dominfo "$i" | sed -nr -e 's@^State:[[:space:]]+@@p')
146             printf "$fmt" "$i" "$state"
147         done
148         exit 62  # ETIME
149     fi
150
151     pat="^State:[[:space:]]+${desired_state}\$"
152     all_good=true
153     for i in $nodes ; do
154         # Often "vircmd dominfo" returns 1 and prints rubbish like this:
155         #  error: operation failed: could not query memory balloon allocation
156         # so we take pains to avoid this cluttering the output...
157         if virsh_out=$(virsh dominfo "$i" 2>&1) ; then
158             if ! echo "$virsh_out" | grep -E -q "$pat" ; then
159                 all_good=false
160             fi
161         fi
162     done
163     $all_good && exit 0
164
165     sleep 1
166     count=$(($count + 1))
167 done
168
169 exit $rc