node_name_format_* functions should produce the node name
[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}[a-z]*[0-9]"
93 else
94     get_nodes "$cluster"
95 fi
96
97 [ -n "$nodes" ] || {
98     echo "No nodes in cluster $2"
99     exit 1
100 }
101
102 rc=0
103
104 for i in $nodes ; do
105     # We want to retry the command when we see an internal error.
106     for x in $(seq 1 5) ; do
107         out=$(virsh $cmd "$i" 2>&1)
108         ret=$? # Hard to avoid this since we always want to echo $out :-(
109         echo "$out"
110         if [ $ret -ne 0 ] ; then
111             case "$out" in
112                 *internal\ error*)
113                     echo "Retrying \"virsh $cmd $i\" due to internal error"
114                     sleep 3
115                     continue
116             esac
117         fi
118         break
119     done
120     [ $ret  = 0 ] || rc=$ret
121 done
122
123 # Now comes the waiting... but we don't wait if there was an error.
124 if [ $rc -ne 0 ] || ! $wait ; then
125     exit $rc
126 fi
127
128 count=0
129 while : ; do
130     if [ -n "$timeout" ] && [ $count -ge "$timeout" ] ; then
131         echo "Timed out after ${timeout}s waiting for nodes to enter state \"${desired_state}\":"
132         echo
133         fmt='%-20s %s\n'
134         printf "$fmt" "Domain" "State"
135         printf "$fmt" "------" "-----"
136         for i in $nodes ; do
137             state=$(virsh dominfo "$i" | sed -nr -e 's@^State:[[:space:]]+@@p')
138             printf "$fmt" "$i" "$state"
139         done
140         exit 62  # ETIME
141     fi
142
143     pat="^State:[[:space:]]+${desired_state}\$"
144     all_good=true
145     for i in $nodes ; do
146         # Often "vircmd dominfo" returns 1 and prints rubbish like this:
147         #  error: operation failed: could not query memory balloon allocation
148         # so we take pains to avoid this cluttering the output...
149         if virsh_out=$(virsh dominfo "$i" 2>&1) ; then
150             if ! echo "$virsh_out" | grep -E -q "$pat" ; then
151                 all_good=false
152             fi
153         fi
154     done
155     $all_good && exit 0
156
157     sleep 1
158     count=$(($count + 1))
159 done
160
161 exit $rc