Merge branch 'stable-2.7' into stable-2.8
[ganeti-local] / tools / vcluster-setup.in
1 #!/bin/bash
2 #
3
4 # Copyright (C) 2012 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21 set -e -u -o pipefail
22 shopt -s extglob
23
24 readonly self=$(readlink -f $0)
25 readonly ensure_dirs=@PKGLIBDIR@/ensure-dirs
26 readonly action_shortcuts=( start stop restart status watcher )
27 readonly default_nodecount=5
28 readonly default_instcount=10
29 readonly default_netprefix=192.0.2
30 readonly default_netdev=eth0
31 readonly default_initscript=@SYSCONFDIR@/init.d/ganeti
32 readonly cluster_name=cluster
33 readonly etc_hosts_filename=/etc/hosts
34
35 # IP address space:
36 # Cluster: .1
37 # Nodes: .10-.99
38 # Instances: .100-.254
39 readonly first_node_ipaddr_octet=10
40 readonly first_inst_ipaddr_octet=100
41
42 readonly max_node_count=$((first_inst_ipaddr_octet - first_node_ipaddr_octet))
43 readonly max_instance_count=$((255 - first_inst_ipaddr_octet))
44
45 usage() {
46   echo "Usage: $0 [-E] [-N] [-c <number>] [-i <number>] [-p <prefix>]"\
47        '[-n <netdev>] [-I <path>] <directory>'
48   echo
49   echo 'Options:'
50   echo "  -c  Number of virtual nodes (defaults to $default_nodecount)"
51   echo "  -i  Number of instances (defaults to $default_instcount)"
52   echo "  -p  IPv4 network prefix (defaults to $default_netprefix)"
53   echo '  -n  Network device for virtual IP addresses (defaults to'\
54        "$default_netdev)"
55   echo "  -I  Path to init script (defaults to $default_initscript)"
56   echo "  -E  Do not modify $etc_hosts_filename"
57   echo '  -N  Do not configure networking'
58 }
59
60 # Variables for options
61 nodecount=$default_nodecount
62 instcount=$default_instcount
63 netprefix=$default_netprefix
64 netdev=$default_netdev
65 initscript=$default_initscript
66 etchosts=1
67 networking=1
68
69 # Parse options
70 while getopts :hENc:p:n:i:I: opt; do
71   case "$opt" in
72     h)
73       usage
74       exit 0
75     ;;
76     c)
77       nodecount="$OPTARG"
78       if [[ "$nodecount" != +([0-9]) ]]; then
79         echo "Invalid node count number: $nodecount" >&2
80         exit 1
81       elif (( nodecount > max_node_count )); then
82         echo "Node count must be $max_node_count or lower" >&2
83         exit 1
84       fi
85     ;;
86     i)
87       instcount="$OPTARG"
88       if [[ "$instcount" != +([0-9]) ]]; then
89         echo "Invalid instance count number: $instcount" >&2
90         exit 1
91       elif (( instcount > max_instance_count )); then
92         echo "Instance count must be $max_instance_count or lower" >&2
93         exit 1
94       fi
95     ;;
96     p)
97       netprefix="$OPTARG"
98       if [[ "$netprefix" != +([0-9]).+([0-9]).+([0-9]) ]]; then
99         echo "Invalid network prefix: $netprefix" >&2
100         exit 1
101       fi
102     ;;
103     n)
104       netdev="$OPTARG"
105       if ! ip link show $netdev >/dev/null; then
106         echo "Invalid network device: $netdev" >&2
107         exit 1
108       fi
109     ;;
110     I)
111       initscript="$OPTARG"
112       if [[ ! -x $initscript ]]; then
113         echo "Init script '$initscript' is not executable" >&2
114         exit 1
115       fi
116       ;;
117     E)
118       etchosts=
119       ;;
120     N)
121       networking=
122       ;;
123     \?)
124       echo "Invalid option: -$OPTARG" >&2
125       usage >&2
126       exit 1
127       ;;
128     :)
129       echo "Option -$OPTARG requires an argument" >&2
130       usage >&2
131       exit 1
132       ;;
133   esac
134 done
135
136 shift $((OPTIND - 1))
137
138 if [[ "$#" != 1 ]]; then
139   usage
140   exit 1
141 fi
142
143 readonly rootdir=$1; shift
144
145 if [[ ! -d "$rootdir" ]]; then
146   echo "Directory '$rootdir' does not exist!" >&2
147   exit 1
148 fi
149
150 if (( $nodecount < 1 )); then
151   echo "Must create at least one node, currently requested $nodecount" >&2
152   exit 1
153 fi
154
155 node_hostname() {
156   local -r number="$1"
157
158   echo "node$((number + 1))"
159 }
160
161 instance_hostname() {
162   local -r number="$1"
163
164   echo "instance$((number + 1))"
165 }
166
167 node_ipaddr() {
168   local -r number="$1"
169
170   echo "$netprefix.$((first_node_ipaddr_octet + number))"
171 }
172
173 instance_ipaddr() {
174   local -r number="$1"
175
176   echo "$netprefix.$((first_inst_ipaddr_octet + number))"
177 }
178
179 setup_node() {
180   local -r number="$1"
181   local -r nodedir=$rootdir/$(node_hostname $number)
182
183   echo "Setting up node '$(node_hostname $number)' ..." >&2
184
185   if [[ ! -d $nodedir ]]; then
186     mkdir $nodedir
187   fi
188
189   mkdir -p \
190     $nodedir@SYSCONFDIR@/{default,ganeti} \
191     $nodedir@LOCALSTATEDIR@/lock\
192     $nodedir@LOCALSTATEDIR@/{lib,log,run}/ganeti
193
194   GANETI_HOSTNAME=$(node_hostname $number) \
195   GANETI_ROOTDIR=$nodedir \
196   $ensure_dirs
197
198   local -r daemon_args="-b $(node_ipaddr $number)"
199
200   cat > $nodedir/etc/default/ganeti <<EOF
201 # Default settings for virtual node $i
202 NODED_ARGS='--no-mlock $daemon_args'
203 MASTERD_ARGS=''
204 RAPI_ARGS='$daemon_args'
205 CONFD_ARGS='$daemon_args'
206
207 export GANETI_ROOTDIR='$nodedir'
208 export GANETI_HOSTNAME='$(node_hostname $number)'
209 EOF
210
211   cat > $nodedir/cmd <<EOF
212 #!/bin/bash
213
214 export GANETI_ROOTDIR='$nodedir'
215 export GANETI_HOSTNAME='$(node_hostname $number)'
216
217 bash -c "\$*"
218 EOF
219   chmod +x $nodedir/cmd
220 }
221
222 setup_all_nodes() {
223   for ((i=0; i < nodecount; ++i)); do
224     setup_node $i
225   done
226 }
227
228 setup_etc_hosts() {
229   echo "Configuring $etc_hosts_filename ..." >&2
230   (
231     set -e -u
232     local -r tmpfile=$(mktemp $etc_hosts_filename.vcluster.XXXXX)
233     trap "rm -f $tmpfile" EXIT
234     {
235       egrep -v "^$netprefix.[[:digit:]]+[[:space:]]" $etc_hosts_filename
236       echo "$netprefix.1 $cluster_name"
237       for ((i=0; i < nodecount; ++i)); do
238         echo "$(node_ipaddr $i) $(node_hostname $i)"
239       done
240       for ((i=0; i < instcount; ++i)); do
241         echo "$(instance_ipaddr $i) $(instance_hostname $i)"
242       done
243     } > $tmpfile && \
244     chmod 0644 $tmpfile && \
245     mv $tmpfile $etc_hosts_filename && \
246     trap - EXIT
247   )
248 }
249
250 setup_network_interfaces() {
251   echo 'Configuring network ...' >&2
252   for ((i=0; i < nodecount; ++i)); do
253     local ipaddr="$(node_ipaddr $i)/32"
254     ip addr del "$ipaddr" dev "$netdev" || :
255     ip addr add "$ipaddr" dev "$netdev"
256   done
257 }
258
259 setup_scripts() {
260   echo 'Configuring helper scripts ...' >&2
261   for action in "${action_shortcuts[@]}"; do
262     {
263       echo '#!/bin/bash'
264       for ((i=0; i < nodecount; ++i)); do
265         local name=$(node_hostname $i)
266         if [[ $action = watcher ]]; then
267           echo "echo 'Running watcher for virtual node \"$name\" ..."
268           echo "$name/cmd ganeti-watcher \"\$@\""
269         else
270           echo "echo 'Action \"$action\" for virtual node \"$name\" ...'"
271           echo "$name/cmd $initscript $action \"\$@\""
272         fi
273       done
274     } > $rootdir/$action-all
275     chmod +x $rootdir/$action-all
276   done
277 }
278
279 show_info() {
280   cat <<EOF
281 Virtual cluster setup is complete.
282
283 Root directory: $rootdir
284 Cluster name: $cluster_name
285 EOF
286
287   echo 'Nodes:' $(for ((i=0; i < nodecount; ++i)); do node_hostname $i; done)
288
289   cat <<EOF
290
291 Initialize cluster:
292   cd $rootdir && node1/cmd gnt-cluster init --no-etc-hosts \\
293     --no-ssh-init --no-lvm-storage --no-drbd-storage $cluster_name
294
295 Change cluster settings:
296   cd $rootdir && node1/cmd gnt-cluster modify \\
297     --enabled-hypervisors=fake --specs-nic-count=min=0 \\
298     --specs-disk-size=min=0 --specs-disk-count=min=0
299
300 Add node:
301   cd $rootdir && node1/cmd gnt-node add --no-ssh-key-check node2
302 EOF
303 }
304
305 setup_all_nodes
306 if [[ -n "$etchosts" ]]; then
307   setup_etc_hosts
308 fi
309 if [[ -n "$networking" ]]; then
310   setup_network_interfaces
311 fi
312 setup_scripts
313 show_info
314
315 exit 0
316
317 # vim: set sw=2 sts=2 et :