vcluster-setup: Add more parameters to "gnt-cluster init"
[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 )
27 readonly default_nodecount=5
28 readonly default_instcount=10
29 readonly default_netprefix=192.0.2
30 readonly default_netdev=eth0
31 readonly cluster_name=cluster
32
33 # IP address space:
34 # Cluster: .1
35 # Nodes: .10-.99
36 # Instances: .100-.254
37 readonly first_node_ipaddr_octet=10
38 readonly first_inst_ipaddr_octet=100
39
40 readonly max_node_count=$((first_inst_ipaddr_octet - first_node_ipaddr_octet))
41 readonly max_instance_count=$((255 - first_inst_ipaddr_octet))
42
43 usage() {
44   echo "Usage: $0 [-E] [-N] [-c <number>] [-i <number>] [-p <prefix>]"\
45        '[-n <netdev>] <directory>'
46   echo
47   echo 'Options:'
48   echo "  -c  Number of virtual nodes (defaults to $default_nodecount)"
49   echo "  -i  Number of instances (defaults to $default_instcount)"
50   echo "  -p  IPv4 network prefix (defaults to $default_netprefix)"
51   echo '  -n  Network device for virtual IP addresses (defaults to'\
52        "$default_netdev)"
53   echo '  -E  Do not modify /etc/hosts'
54   echo '  -N  Do not configure networking'
55 }
56
57 # Variables for options
58 nodecount=$default_nodecount
59 instcount=$default_instcount
60 netprefix=$default_netprefix
61 netdev=$default_netdev
62 etchosts=1
63 networking=1
64
65 # Parse options
66 while getopts :hENc:p:n:i: opt; do
67   case "$opt" in
68     h)
69       usage
70       exit 0
71     ;;
72     c)
73       nodecount="$OPTARG"
74       if [[ "$nodecount" != +([0-9]) ]]; then
75         echo "Invalid node count number: $nodecount" >&2
76         exit 1
77       elif (( nodecount > max_node_count )); then
78         echo "Node count must be $max_node_count or lower" >&2
79         exit 1
80       fi
81     ;;
82     i)
83       instcount="$OPTARG"
84       if [[ "$instcount" != +([0-9]) ]]; then
85         echo "Invalid instance count number: $instcount" >&2
86         exit 1
87       elif (( instcount > max_instance_count )); then
88         echo "Instance count must be $max_instance_count or lower" >&2
89         exit 1
90       fi
91     ;;
92     p)
93       netprefix="$OPTARG"
94       if [[ "$netprefix" != +([0-9]).+([0-9]).+([0-9]) ]]; then
95         echo "Invalid network prefix: $netprefix" >&2
96         exit 1
97       fi
98     ;;
99     n)
100       netdev="$OPTARG"
101       if ! ip link show $netdev >/dev/null; then
102         echo "Invalid network device: $netdev" >&2
103         exit 1
104       fi
105     ;;
106     E)
107       etchosts=
108       ;;
109     N)
110       networking=
111       ;;
112     \?)
113       echo "Invalid option: -$OPTARG" >&2
114       usage >&2
115       exit 1
116       ;;
117     :)
118       echo "Option -$OPTARG requires an argument" >&2
119       usage >&2
120       exit 1
121       ;;
122   esac
123 done
124
125 shift $((OPTIND - 1))
126
127 if [[ "$#" != 1 ]]; then
128   usage
129   exit 1
130 fi
131
132 readonly rootdir=$1; shift
133
134 if [[ ! -d "$rootdir" ]]; then
135   echo "Directory '$rootdir' does not exist!" >&2
136   exit 1
137 fi
138
139 if (( $nodecount < 1 )); then
140   echo "Must create at least one node, currently requested $nodecount" >&2
141   exit 1
142 fi
143
144 node_hostname() {
145   local -r number="$1"
146
147   echo "node$((number + 1))"
148 }
149
150 instance_hostname() {
151   local -r number="$1"
152
153   echo "instance$((number + 1))"
154 }
155
156 node_ipaddr() {
157   local -r number="$1"
158
159   echo "$netprefix.$((first_node_ipaddr_octet + number))"
160 }
161
162 instance_ipaddr() {
163   local -r number="$1"
164
165   echo "$netprefix.$((first_inst_ipaddr_octet + number))"
166 }
167
168 setup_node() {
169   local -r number="$1"
170   local -r nodedir=$rootdir/$(node_hostname $number)
171
172   echo "Setting up node '$(node_hostname $number)' ..." >&2
173
174   if [[ ! -d $nodedir ]]; then
175     mkdir $nodedir
176   fi
177
178   mkdir -p \
179     $nodedir@SYSCONFDIR@/default \
180     $nodedir@LOCALSTATEDIR@/lock\
181     $nodedir@LOCALSTATEDIR@/{lib,log,run}/ganeti
182
183   GANETI_HOSTNAME=$(node_hostname $number) \
184   GANETI_ROOTDIR=$nodedir \
185   $ensure_dirs
186
187   local -r daemon_args="-b $(node_ipaddr $number)"
188
189   cat > $nodedir/etc/default/ganeti <<EOF
190 # Default settings for virtual node $i
191 NODED_ARGS='--no-mlock $daemon_args'
192 MASTERD_ARGS=''
193 RAPI_ARGS='$daemon_args'
194 CONFD_ARGS='$daemon_args'
195
196 export GANETI_ROOTDIR='$nodedir'
197 export GANETI_HOSTNAME='$(node_hostname $number)'
198 EOF
199
200   cat > $nodedir/cmd <<EOF
201 #!/bin/bash
202
203 export GANETI_ROOTDIR='$nodedir'
204 export GANETI_HOSTNAME='$(node_hostname $number)'
205
206 bash -c "\$*"
207 EOF
208   chmod +x $nodedir/cmd
209 }
210
211 setup_all_nodes() {
212   for ((i=0; i < nodecount; ++i)); do
213     setup_node $i
214   done
215 }
216
217 setup_etc_hosts() {
218   echo 'Configuring /etc/hosts ...' >&2
219   (
220     set -e -u
221     local -r tmpfile=$(mktemp /etc/hosts.vcluster.XXXXX)
222     trap "rm -f $tmpfile" EXIT
223     {
224       egrep -v "^$netprefix.[[:digit:]]+[[:space:]]" /etc/hosts
225       echo "$netprefix.1 $cluster_name"
226       for ((i=0; i < nodecount; ++i)); do
227         echo "$(node_ipaddr $i) $(node_hostname $i)"
228       done
229       for ((i=0; i < instcount; ++i)); do
230         echo "$(instance_ipaddr $i) $(instance_hostname $i)"
231       done
232     } > $tmpfile && \
233     chmod 0644 $tmpfile && \
234     mv $tmpfile /etc/hosts && \
235     trap - EXIT
236   )
237 }
238
239 setup_network_interfaces() {
240   echo 'Configuring network ...' >&2
241   for ((i=0; i < nodecount; ++i)); do
242     local ipaddr="$(node_ipaddr $i)/32"
243     ip addr del "$ipaddr" dev "$netdev" || :
244     ip addr add "$ipaddr" dev "$netdev"
245   done
246 }
247
248 setup_scripts() {
249   echo 'Configuring helper scripts ...' >&2
250   for action in "${action_shortcuts[@]}"; do
251     {
252       echo '#!/bin/bash'
253       for ((i=0; i < nodecount; ++i)); do
254         local name=$(node_hostname $i)
255         echo "echo 'Action \"$action\" for virtual node \"$name\" ...'"
256         echo "$name/cmd /etc/init.d/ganeti $action"
257       done
258     } > $rootdir/$action-all
259     chmod +x $rootdir/$action-all
260   done
261 }
262
263 show_info() {
264   cat <<EOF
265 Virtual cluster setup is complete.
266
267 Root directory: $rootdir
268 Cluster name: $cluster_name
269 EOF
270
271   echo 'Nodes:' $(for ((i=0; i < nodecount; ++i)); do node_hostname $i; done)
272
273   cat <<EOF
274
275 Initialize cluster:
276   cd $rootdir && node1/cmd gnt-cluster init --no-etc-hosts \\
277     --no-ssh-init --no-lvm-storage --no-drbd-storage $cluster_name
278
279 Change cluster settings:
280   cd $rootdir && node1/cmd gnt-cluster modify \\
281     --enabled-hypervisors=fake --specs-nic-count=min=0 \\
282     --specs-disk-size=min=0 --specs-disk-count=min=0
283
284 Add node:
285   cd $rootdir && node1/cmd gnt-node add --no-ssh-key-check node2
286 EOF
287 }
288
289 setup_all_nodes
290 if [[ -n "$etchosts" ]]; then
291   setup_etc_hosts
292 fi
293 if [[ -n "$networking" ]]; then
294   setup_network_interfaces
295 fi
296 setup_scripts
297 show_info
298
299 exit 0
300
301 # vim: set sw=2 sts=2 et :