vcluster-setup.in 6.63 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!/bin/bash
#

# Copyright (C) 2012 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

set -e -u -o pipefail
shopt -s extglob

readonly self=$(readlink -f $0)
readonly ensure_dirs=@PKGLIBDIR@/ensure-dirs
readonly action_shortcuts=( start stop restart status )
readonly default_nodecount=5
readonly default_instcount=10
readonly default_netprefix=192.0.2
readonly default_netdev=eth0
readonly cluster_name=cluster

# IP address space:
# Cluster: .1
# Nodes: .10-.99
# Instances: .100-.254
readonly first_node_ipaddr_octet=10
readonly first_inst_ipaddr_octet=100

readonly max_node_count=$((first_inst_ipaddr_octet - first_node_ipaddr_octet))
readonly max_instance_count=$((255 - first_inst_ipaddr_octet))

usage() {
  echo "Usage: $0 [-c <number>] [-i <number>] [-p <prefix>] [-n <netdev>]"\
       '<directory>'
  echo
  echo 'Options:'
  echo "  -c  Number of virtual nodes (defaults to $default_nodecount)"
  echo "  -i  Number of instances (defaults to $default_instcount)"
  echo "  -p  IPv4 network prefix (defaults to $default_netprefix)"
  echo '  -n  Network device for virtual IP addresses (defaults to'\
       "$default_netdev)"
}

# Variables for options
nodecount=$default_nodecount
instcount=$default_instcount
netprefix=$default_netprefix
netdev=$default_netdev

# Parse options
while getopts :hc:p:n:i: opt; do
  case "$opt" in
    h)
      usage
      exit 0
    ;;
    c)
      nodecount="$OPTARG"
      if [[ "$nodecount" != +([0-9]) ]]; then
        echo "Invalid node count number: $nodecount" >&2
        exit 1
      elif (( nodecount > max_node_count )); then
        echo "Node count must be $max_node_count or lower" >&2
        exit 1
      fi
    ;;
    i)
      instcount="$OPTARG"
      if [[ "$instcount" != +([0-9]) ]]; then
        echo "Invalid instance count number: $instcount" >&2
        exit 1
      elif (( instcount > max_instance_count )); then
        echo "Instance count must be $max_instance_count or lower" >&2
        exit 1
      fi
    ;;
    p)
      netprefix="$OPTARG"
      if [[ "$netprefix" != +([0-9]).+([0-9]).+([0-9]) ]]; then
        echo "Invalid network prefix: $netprefix" >&2
        exit 1
      fi
    ;;
    n)
      netdev="$OPTARG"
      if ! ip link show $netdev >/dev/null; then
        echo "Invalid network device: $netdev" >&2
        exit 1
      fi
    ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      usage >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument" >&2
      usage >&2
      exit 1
      ;;
  esac
done

shift $((OPTIND - 1))

if [[ "$#" != 1 ]]; then
  usage
  exit 1
fi

readonly rootdir=$1; shift

if [[ ! -d "$rootdir" ]]; then
  echo "Directory '$rootdir' does not exist!" >&2
  exit 1
fi

if (( $nodecount < 1 )); then
  echo "Must create at least one node, currently requested $nodecount" >&2
  exit 1
fi

node_hostname() {
  local -r number="$1"

  echo "node$((number + 1))"
}

instance_hostname() {
  local -r number="$1"

  echo "instance$((number + 1))"
}

node_ipaddr() {
  local -r number="$1"

  echo "$netprefix.$((first_node_ipaddr_octet + number))"
}

instance_ipaddr() {
  local -r number="$1"

  echo "$netprefix.$((first_inst_ipaddr_octet + number))"
}

setup_node() {
  local -r number="$1"
  local -r nodedir=$rootdir/$(node_hostname $number)

  echo "Setting up node '$(node_hostname $number)' ..." >&2

  if [[ ! -d $nodedir ]]; then
    mkdir $nodedir
  fi

  mkdir -p \
    $nodedir/etc/default \
    $nodedir/var/lock\
    $nodedir/var/{lib,log,run}/ganeti

  GANETI_HOSTNAME=$(node_hostname $number) \
  GANETI_ROOTDIR=$nodedir \
  $ensure_dirs

  local -r daemon_args="-b $(node_ipaddr $number)"

  cat > $nodedir/etc/default/ganeti <<EOF
# Default settings for virtual node $i
NODED_ARGS='--no-mlock $daemon_args'
MASTERD_ARGS=''
RAPI_ARGS='$daemon_args'
CONFD_ARGS='$daemon_args'

export GANETI_ROOTDIR='$nodedir'
export GANETI_HOSTNAME='$(node_hostname $number)'
EOF

  cat > $nodedir/cmd <<EOF
#!/bin/bash

export GANETI_ROOTDIR='$nodedir'
export GANETI_HOSTNAME='$(node_hostname $number)'

bash -c "\$*"
EOF
  chmod +x $nodedir/cmd
}

setup_all_nodes() {
  for ((i=0; i < nodecount; ++i)); do
    setup_node $i
  done
}

setup_etc_hosts() {
  echo 'Configuring /etc/hosts ...' >&2
  (
    set -e -u
    local -r tmpfile=$(mktemp /etc/hosts.vcluster.XXXXX)
    trap "rm -f $tmpfile" EXIT
    {
      egrep -v "^$netprefix.[[:digit:]]+[[:space:]]" /etc/hosts
      echo "$netprefix.1 $cluster_name"
      for ((i=0; i < nodecount; ++i)); do
        echo "$(node_ipaddr $i) $(node_hostname $i)"
      done
      for ((i=0; i < instcount; ++i)); do
        echo "$(instance_ipaddr $i) $(instance_hostname $i)"
      done
    } > $tmpfile && \
    chmod 0644 $tmpfile && \
    mv $tmpfile /etc/hosts && \
    trap - EXIT
  )
}

setup_network_interfaces() {
  echo 'Configuring network ...' >&2
  for ((i=0; i < nodecount; ++i)); do
    local ipaddr="$(node_ipaddr $i)/32"
    ip addr del "$ipaddr" dev "$netdev" || :
    ip addr add "$ipaddr" dev "$netdev"
  done
}

setup_scripts() {
  echo 'Configuring helper scripts ...' >&2
  for action in "${action_shortcuts[@]}"; do
    {
      echo '#!/bin/bash'
      for ((i=0; i < nodecount; ++i)); do
        local name=$(node_hostname $i)
        echo "echo 'Action \"$action\" for virtual node \"$name\" ...'"
        echo "$name/cmd /etc/init.d/ganeti $action"
      done
    } > $rootdir/$action-all
    chmod +x $rootdir/$action-all
  done
}

show_info() {
  cat <<EOF
Virtual cluster setup is complete.

Root directory: $rootdir
Cluster name: $cluster_name
EOF

  echo 'Nodes:' $(for ((i=0; i < nodecount; ++i)); do node_hostname $i; done)

  cat <<EOF

Initialize cluster:
  cd $rootdir && node1/cmd gnt-cluster init --no-etc-hosts $cluster_name

Change cluster settings:
  cd $rootdir && node1/cmd gnt-cluster modify \\
    --enabled-hypervisors=fake \\
    --specs-disk-size=min=0 --specs-disk-count=min=0

Add node:
  cd $rootdir && node1/cmd gnt-node add --no-ssh-key-check node2
EOF
}

setup_all_nodes
setup_etc_hosts
setup_network_interfaces
setup_scripts
show_info

exit 0

# vim: set sw=2 sts=2 et :