blob: 6f9afc678a8157acd0753ef9d02ba50927257373 [file] [log] [blame]
Anthony Youngb62b4ca2011-10-26 22:29:08 -07001#!/bin/bash
2#
3# Copyright (c) 2011 Citrix Systems, Inc.
4# Copyright 2011 OpenStack LLC.
5# Copyright (C) 2011 Nicira, Inc
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20
21set -eux
22
23. /etc/xensource-inventory
24
25NAME="XenServer OpenStack VPX"
26DATA_VDI_SIZE="500MiB"
27BRIDGE_M=
28BRIDGE_P=
29KERNEL_PARAMS=
30VPX_FILE=os-vpx.xva
31AS_TEMPLATE=
32FROM_TEMPLATE=
33RAM=
34WAIT_FOR_NETWORK=
35BALLOONING=
36
37usage()
38{
39cat << EOF
40
41 Usage: $0 [-f FILE_PATH] [-d DISK_SIZE] [-v BRIDGE_NAME] [-m BRIDGE_NAME] [-p BRIDGE_NAME]
42 [-k PARAMS] [-r RAM] [-i|-c] [-w] [-b]
43
44 Installs XenServer OpenStack VPX.
45
46 OPTIONS:
47
48 -h Shows this message.
49 -i Install OpenStack VPX as template.
50 -c Clone from existing template.
51 -w Wait for the network settings to show up before exiting.
52 -b Enable memory ballooning. When set min_RAM=RAM/2 max_RAM=RAM.
53 -f path Specifies the path to the XVA.
54 Default to ./os-vpx.xva.
55 -d disk-size Specifies the size in MiB for the data disk.
56 Defaults to 500 MiB.
57 -m bridge Specifies the bridge for the isolated management network.
58 Defaults to xenbr0.
59 -v bridge Specifies the bridge for the vm network
60 -p bridge Specifies the bridge for the externally facing network.
61 -k params Specifies kernel parameters.
62 -r MiB Specifies RAM used by the VPX, in MiB.
63 By default it will take the value from the XVA.
64
65 EXAMPLES:
66
67 Create a VPX that connects to the isolated management network using the
68 default bridge with a data disk of 1GiB:
69 install-os-vpx.sh -f /root/os-vpx-devel.xva -d 1024
70
71 Create a VPX that connects to the isolated management network using xenbr1
72 as bridge:
73 install-os-vpx.sh -m xenbr1
74
75 Create a VPX that connects to both the management and public networks
76 using xenbr1 and xapi4 as bridges:
77 install-os-vpx.sh -m xenbr1 -p xapi4
78
79 Create a VPX that connects to both the management and public networks
80 using the default for management traffic:
81 install-os-vpx.sh -m xapi4
82
83 Create a VPX that automatically becomes the master:
84 install-os-vpx.sh -k geppetto_master=true
85
86EOF
87}
88
89get_params()
90{
91 while getopts "hicwbf:d:v:m:p:k:r:" OPTION;
92 do
93 case $OPTION in
94 h) usage
95 exit 1
96 ;;
97 i)
98 AS_TEMPLATE=1
99 ;;
100 c)
101 FROM_TEMPLATE=1
102 ;;
103 w)
104 WAIT_FOR_NETWORK=1
105 ;;
106 b)
107 BALLOONING=1
108 ;;
109 f)
110 VPX_FILE=$OPTARG
111 ;;
112 d)
113 DATA_VDI_SIZE="${OPTARG}MiB"
114 ;;
115 m)
116 BRIDGE_M=$OPTARG
117 ;;
118 p)
119 BRIDGE_P=$OPTARG
120 ;;
121 k)
122 KERNEL_PARAMS=$OPTARG
123 ;;
124 r)
125 RAM=$OPTARG
126 ;;
127 v)
128 BRIDGE_V=$OPTARG
129 ;;
130 ?)
131 usage
132 exit
133 ;;
134 esac
135 done
136 if [[ -z $BRIDGE_M ]]
137 then
138 BRIDGE_M=xenbr0
139 fi
140}
141
142
143xe_min()
144{
145 local cmd="$1"
146 shift
147 xe "$cmd" --minimal "$@"
148}
149
150
151get_dest_sr()
152{
153 IFS=,
154 sr_uuids=$(xe sr-list --minimal other-config:i18n-key=local-storage)
155 dest_sr=""
156 for sr_uuid in $sr_uuids
157 do
158 pbd=$(xe pbd-list --minimal sr-uuid=$sr_uuid host-uuid=$INSTALLATION_UUID)
159 if [ "$pbd" ]
160 then
161 echo "$sr_uuid"
162 unset IFS
163 return
164 fi
165 done
166 unset IFS
167
168 dest_sr=$(xe_min sr-list uuid=$(xe_min pool-list params=default-SR))
169 if [ "$dest_sr" = "" ]
170 then
171 echo "No local storage and no default storage; cannot import VPX." >&2
172 exit 1
173 else
174 echo "$dest_sr"
175 fi
176}
177
178
179find_network()
180{
181 result=$(xe_min network-list bridge="$1")
182 if [ "$result" = "" ]
183 then
184 result=$(xe_min network-list name-label="$1")
185 fi
186 echo "$result"
187}
188
189
190find_template()
191{
192 xe_min template-list other-config:os-vpx=true
193}
194
195
196renumber_system_disk()
197{
198 local v="$1"
199 local vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk userdevice=xvda \
200 params=vdi-uuid)
201 if [ "$vdi_uuid" ]
202 then
203 local vbd_uuid=$(xe_min vbd-list vm-uuid="$v" vdi-uuid="$vdi_uuid")
204 xe vbd-destroy uuid="$vbd_uuid"
205 local new_vbd_uuid=$(xe vbd-create vm-uuid="$v" vdi-uuid="$vdi_uuid" \
206 device=0 bootable=true type=Disk)
207 xe vbd-param-set other-config:owner uuid="$new_vbd_uuid"
208 fi
209}
210
211
212create_vif()
213{
214 xe vif-create vm-uuid="$1" network-uuid="$2" device="$3"
215}
216
217create_gi_vif()
218{
219 local v="$1"
220 # Note that we've made the outbound device eth1, so that it comes up after
221 # the guest installer VIF, which means that the outbound one wins in terms
222 # of gateway.
223 local gi_network_uuid=$(xe_min network-list \
224 other-config:is_guest_installer_network=true)
225 create_vif "$v" "$gi_network_uuid" "0" >/dev/null
226}
227
228create_vm_vif()
229{
230 local v="$1"
231 echo "Installing management interface on $BRIDGE_V."
232 local out_network_uuid=$(find_network "$BRIDGE_V")
233 create_vif "$v" "$out_network_uuid" "1" >/dev/null
234}
235
236create_management_vif()
237{
238 local v="$1"
239 echo "Installing management interface on $BRIDGE_M."
240 local out_network_uuid=$(find_network "$BRIDGE_M")
241 create_vif "$v" "$out_network_uuid" "2" >/dev/null
242}
243
244
245# This installs the interface for public traffic, only if a bridge is specified
246# The interface is not configured at this stage, but it will be, once the admin
247# tasks are complete for the services of this VPX
248create_public_vif()
249{
250 local v="$1"
251 if [[ -z $BRIDGE_P ]]
252 then
253 echo "Skipping installation of interface for public traffic."
254 else
255 echo "Installing public interface on $BRIDGE_P."
256 pub_network_uuid=$(find_network "$BRIDGE_P")
257 create_vif "$v" "$pub_network_uuid" "3" >/dev/null
258 fi
259}
260
261
262label_system_disk()
263{
264 local v="$1"
265 local vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk userdevice=0 \
266 params=vdi-uuid)
267 xe vdi-param-set \
268 name-label="$NAME system disk" \
269 other-config:os-vpx=true \
270 uuid=$vdi_uuid
271}
272
273
274create_data_disk()
275{
276 local v="$1"
277
278 local sys_vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk params=vdi-uuid)
279 local data_vdi_uuid=$(xe_min vdi-list other-config:os-vpx-data=true)
280
281 if echo "$data_vdi_uuid" | grep -q ,
282 then
283 echo "Multiple data disks found -- assuming that you want a new one."
284 data_vdi_uuid=""
285 else
286 data_in_use=$(xe_min vbd-list vdi-uuid="$data_vdi_uuid")
287 if [ "$data_in_use" != "" ]
288 then
289 echo "Data disk already in use -- will create another one."
290 data_vdi_uuid=""
291 fi
292 fi
293
294 if [ "$data_vdi_uuid" = "" ]
295 then
296 echo -n "Creating new data disk ($DATA_VDI_SIZE)... "
297 sr_uuid=$(xe_min vdi-list params=sr-uuid uuid="$sys_vdi_uuid")
298 data_vdi_uuid=$(xe vdi-create name-label="$NAME data disk" \
299 sr-uuid="$sr_uuid" \
300 type=user \
301 virtual-size="$DATA_VDI_SIZE")
302 xe vdi-param-set \
303 other-config:os-vpx-data=true \
304 uuid="$data_vdi_uuid"
305 dom0_uuid=$(xe_min vm-list is-control-domain=true)
306 vbd_uuid=$(xe vbd-create device=autodetect type=Disk \
307 vdi-uuid="$data_vdi_uuid" vm-uuid="$dom0_uuid")
308 xe vbd-plug uuid=$vbd_uuid
309 dev=$(xe_min vbd-list params=device uuid=$vbd_uuid)
310 mke2fs -q -j -m0 /dev/$dev
311 e2label /dev/$dev vpxstate
312 xe vbd-unplug uuid=$vbd_uuid
313 xe vbd-destroy uuid=$vbd_uuid
314 else
315 echo -n "Attaching old data disk... "
316 fi
317 vbd_uuid=$(xe vbd-create device=2 type=Disk \
318 vdi-uuid="$data_vdi_uuid" vm-uuid="$v")
319 xe vbd-param-set other-config:os-vpx-data=true uuid=$vbd_uuid
320 echo "done."
321}
322
323
324set_kernel_params()
325{
326 local v="$1"
327 local args=$KERNEL_PARAMS
328 local cmdline=$(cat /proc/cmdline)
329 for word in $cmdline
330 do
331 if echo "$word" | grep -q "geppetto"
332 then
333 args="$word $args"
334 fi
335 done
336 if [ "$args" != "" ]
337 then
338 echo "Passing Geppetto args to VPX: $args."
339 xe vm-param-set PV-args="$args" uuid="$v"
340 fi
341}
342
343
344set_memory()
345{
346 local v="$1"
347 if [ "$RAM" != "" ]
348 then
349 echo "Setting RAM to $RAM MiB."
350 [ "$BALLOONING" == 1 ] && RAM_MIN=$(($RAM / 2)) || RAM_MIN=$RAM
351 xe vm-memory-limits-set static-min=16MiB static-max=${RAM}MiB \
352 dynamic-min=${RAM_MIN}MiB dynamic-max=${RAM}MiB \
353 uuid="$v"
354 fi
355}
356
357
358# Make the VM auto-start on server boot.
359set_auto_start()
360{
361 local v="$1"
362 xe vm-param-set uuid="$v" other-config:auto_poweron=true
363}
364
365
366set_all()
367{
368 local v="$1"
369 set_kernel_params "$v"
370 set_memory "$v"
371 set_auto_start "$v"
372 label_system_disk "$v"
373 create_gi_vif "$v"
374 create_vm_vif "$v"
375 create_management_vif "$v"
376 create_public_vif "$v"
377}
378
379
380log_vifs()
381{
382 local v="$1"
383
384 (IFS=,
385 for vif in $(xe_min vif-list vm-uuid="$v")
386 do
387 dev=$(xe_min vif-list uuid="$vif" params=device)
388 mac=$(xe_min vif-list uuid="$vif" params=MAC | sed -e 's/:/-/g')
389 echo "eth$dev has MAC $mac."
390 done
391 unset IFS) | sort
392}
393
394
395destroy_vifs()
396{
397 local v="$1"
398 IFS=,
399 for vif in $(xe_min vif-list vm-uuid="$v")
400 do
401 xe vif-destroy uuid="$vif"
402 done
403 unset IFS
404}
405
406
407get_params "$@"
408
409thisdir=$(dirname "$0")
410
411if [ "$FROM_TEMPLATE" ]
412then
413 template_uuid=$(find_template)
414 name=$(xe_min template-list params=name-label uuid="$template_uuid")
415 echo -n "Cloning $name... "
416 vm_uuid=$(xe vm-clone vm="$template_uuid" new-name-label="$name")
417 xe vm-param-set is-a-template=false uuid="$vm_uuid"
418 echo $vm_uuid.
419
420 destroy_vifs "$vm_uuid"
421 set_all "$vm_uuid"
422else
423 if [ ! -f "$VPX_FILE" ]
424 then
425 # Search $thisdir/$VPX_FILE too. In particular, this is used when
426 # installing the VPX from the supp-pack, because we want to be able to
427 # invoke this script from the RPM and the firstboot script.
428 if [ -f "$thisdir/$VPX_FILE" ]
429 then
430 VPX_FILE="$thisdir/$VPX_FILE"
431 else
432 echo "$VPX_FILE does not exist." >&2
433 exit 1
434 fi
435 fi
436
437 echo "Found OS-VPX File: $VPX_FILE. "
438
439 dest_sr=$(get_dest_sr)
440
441 echo -n "Installing $NAME... "
442 vm_uuid=$(xe vm-import filename=$VPX_FILE sr-uuid="$dest_sr")
443 echo $vm_uuid.
444
445 renumber_system_disk "$vm_uuid"
446
447 nl=$(xe_min vm-list params=name-label uuid=$vm_uuid)
448 xe vm-param-set \
449 "name-label=${nl/ import/}" \
450 other-config:os-vpx=true \
451 uuid=$vm_uuid
452
453 set_all "$vm_uuid"
454 create_data_disk "$vm_uuid"
455
456 if [ "$AS_TEMPLATE" ]
457 then
458 xe vm-param-set uuid="$vm_uuid" is-a-template=true \
459 other-config:instant=true
460 echo -n "Installing VPX from template... "
461 vm_uuid=$(xe vm-clone vm="$vm_uuid" new-name-label="${nl/ import/}")
462 xe vm-param-set is-a-template=false uuid="$vm_uuid"
463 echo "$vm_uuid."
464 fi
465fi
466
467
468log_vifs "$vm_uuid"
469
470echo -n "Starting VM... "
471xe vm-start uuid=$vm_uuid
472echo "done."
473
474
475show_ip()
476{
477 ip_addr=$(echo "$1" | sed -n "s,^.*"$2"/ip: \([^;]*\).*$,\1,p")
478 echo -n "IP address for $3: "
479 if [ "$ip_addr" = "" ]
480 then
481 echo "did not appear."
482 else
483 echo "$ip_addr."
484 fi
485}
486
487
488if [ "$WAIT_FOR_NETWORK" ]
489then
490 echo "Waiting for network configuration... "
491 i=0
492 while [ $i -lt 600 ]
493 do
494 ip=$(xe_min vm-list params=networks uuid=$vm_uuid)
495 if [ "$ip" != "<not in database>" ]
496 then
497 show_ip "$ip" "1" "$BRIDGE_M"
498 if [[ $BRIDGE_P ]]
499 then
500 show_ip "$ip" "2" "$BRIDGE_P"
501 fi
502 echo "Installation complete."
503 exit 0
504 fi
505 sleep 10
506 let i=i+1
507 done
508fi