Browse code

Integration testing preparation for Ironic

Add ability to create/register qemu vms for Ironic testing purposes

Implements bp:deprecate-baremetal-driver

Change-Id: If452438fcc0ff562531b33a36cd189b235654b48

Alexander Gordeev authored on 2014/01/31 23:02:07
Showing 15 changed files
... ...
@@ -24,10 +24,17 @@ if is_service_enabled ir-api ir-cond; then
24 24
         # Start the ironic API and ironic taskmgr components
25 25
         echo_summary "Starting Ironic"
26 26
         start_ironic
27
+
28
+        if [[ "$IRONIC_BAREMETAL_BASIC_OPS" = "True" ]]; then
29
+            prepare_baremetal_basic_ops
30
+        fi
27 31
     fi
28 32
 
29 33
     if [[ "$1" == "unstack" ]]; then
30 34
         stop_ironic
35
+        if [[ "$IRONIC_BAREMETAL_BASIC_OPS" = "True" ]]; then
36
+            cleanup_baremetal_basic_ops
37
+        fi
31 38
     fi
32 39
 
33 40
     if [[ "$1" == "clean" ]]; then
34 41
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+libguestfs0
1
+libvirt-bin
2
+openssh-client
3
+openvswitch-switch
4
+openvswitch-datapath-dkms
5
+python-libguestfs
6
+python-libvirt
7
+syslinux
8
+tftpd-hpa
9
+xinetd
0 10
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+libguestfs
1
+libvirt
2
+libvirt-python
3
+openssh-clients
4
+openvswitch
5
+python-libguestfs
6
+syslinux
7
+tftp-server
8
+xinetd
... ...
@@ -140,7 +140,10 @@ BM_DEPLOY_KERNEL=${BM_DEPLOY_KERNEL:-}
140 140
 
141 141
 # If you need to add any extra flavors to the deploy ramdisk image
142 142
 # eg, specific network drivers, specify them here
143
-BM_DEPLOY_FLAVOR=${BM_DEPLOY_FLAVOR:-}
143
+#
144
+# NOTE(deva): this will be moved to lib/ironic in a future patch
145
+#             for now, set the default to a suitable value for Ironic's needs
146
+BM_DEPLOY_FLAVOR=${BM_DEPLOY_FLAVOR:--a amd64 ubuntu deploy-ironic}
144 147
 
145 148
 # set URL and version for google shell-in-a-box
146 149
 BM_SHELL_IN_A_BOX=${BM_SHELL_IN_A_BOX:-http://shellinabox.googlecode.com/files/shellinabox-2.14.tar.gz}
... ...
@@ -220,7 +223,7 @@ function upload_baremetal_deploy {
220 220
         BM_DEPLOY_KERNEL=bm-deploy.kernel
221 221
         BM_DEPLOY_RAMDISK=bm-deploy.initramfs
222 222
         if [ ! -e "$TOP_DIR/files/$BM_DEPLOY_KERNEL" -o ! -e "$TOP_DIR/files/$BM_DEPLOY_RAMDISK" ]; then
223
-            $BM_IMAGE_BUILD_DIR/bin/ramdisk-image-create $BM_DEPLOY_FLAVOR deploy \
223
+            $BM_IMAGE_BUILD_DIR/bin/ramdisk-image-create $BM_DEPLOY_FLAVOR \
224 224
                 -o $TOP_DIR/files/bm-deploy
225 225
         fi
226 226
     fi
... ...
@@ -18,16 +18,19 @@
18 18
 # - stop_ironic
19 19
 # - cleanup_ironic
20 20
 
21
-# Save trace setting
21
+# Save trace and pipefail settings
22 22
 XTRACE=$(set +o | grep xtrace)
23
+PIPEFAIL=$(set +o | grep pipefail)
23 24
 set +o xtrace
24
-
25
+set +o pipefail
25 26
 
26 27
 # Defaults
27 28
 # --------
28 29
 
29 30
 # Set up default directories
30 31
 IRONIC_DIR=$DEST/ironic
32
+IRONIC_DATA_DIR=$DATA_DIR/ironic
33
+IRONIC_STATE_PATH=/var/lib/ironic
31 34
 IRONICCLIENT_DIR=$DEST/python-ironicclient
32 35
 IRONIC_AUTH_CACHE_DIR=${IRONIC_AUTH_CACHE_DIR:-/var/cache/ironic}
33 36
 IRONIC_CONF_DIR=${IRONIC_CONF_DIR:-/etc/ironic}
... ...
@@ -35,6 +38,28 @@ IRONIC_CONF_FILE=$IRONIC_CONF_DIR/ironic.conf
35 35
 IRONIC_ROOTWRAP_CONF=$IRONIC_CONF_DIR/rootwrap.conf
36 36
 IRONIC_POLICY_JSON=$IRONIC_CONF_DIR/policy.json
37 37
 
38
+# Set up defaults for functional / integration testing
39
+IRONIC_SCRIPTS_DIR=${IRONIC_SCRIPTS_DIR:-$TOP_DIR/tools/ironic/scripts}
40
+IRONIC_TEMPLATES_DIR=${IRONIC_TEMPLATES_DIR:-$TOP_DIR/tools/ironic/templates}
41
+IRONIC_BAREMETAL_BASIC_OPS=$(trueorfalse False $IRONIC_BAREMETAL_BASIC_OPS)
42
+IRONIC_SSH_USERNAME=${IRONIC_SSH_USERNAME:-`whoami`}
43
+IRONIC_SSH_KEY_DIR=${IRONIC_SSH_KEY_DIR:-$IRONIC_DATA_DIR/ssh_keys}
44
+IRONIC_SSH_KEY_FILENAME=${IRONIC_SSH_KEY_FILENAME:-ironic_key}
45
+IRONIC_KEY_FILE=$IRONIC_SSH_KEY_DIR/$IRONIC_SSH_KEY_FILENAME
46
+IRONIC_SSH_VIRT_TYPE=${IRONIC_SSH_VIRT_TYPE:-virsh}
47
+IRONIC_TFTPBOOT_DIR=${IRONIC_TFTPBOOT_DIR:-$IRONIC_DATA_DIR/tftpboot}
48
+IRONIC_VM_SSH_PORT=${IRONIC_VM_SSH_PORT:-2222}
49
+IRONIC_VM_SSH_ADDRESS=${IRONIC_VM_SSH_ADDRESS:-$HOST_IP}
50
+IRONIC_VM_COUNT=${IRONIC_VM_COUNT:-1}
51
+IRONIC_VM_SPECS_CPU=${IRONIC_VM_SPECS_CPU:-1}
52
+IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-256}
53
+IRONIC_VM_SPECS_DISK=${IRONIC_VM_SPECS_DISK:-10}
54
+IRONIC_VM_EMULATOR=${IRONIC_VM_EMULATOR:-/usr/bin/qemu-system-x86_64}
55
+IRONIC_VM_NETWORK_BRIDGE=${IRONIC_VM_NETWORK_BRIDGE:-brbm}
56
+IRONIC_VM_NETWORK_RANGE=${IRONIC_VM_NETWORK_RANGE:-192.0.2.0/24}
57
+IRONIC_VM_MACS_CSV_FILE=${IRONIC_VM_MACS_CSV_FILE:-$IRONIC_DATA_DIR/ironic_macs.csv}
58
+IRONIC_AUTHORIZED_KEYS_FILE=${IRONIC_AUTHORIZED_KEYS_FILE:-$HOME/.ssh/authorized_keys}
59
+
38 60
 # Support entry points installation of console scripts
39 61
 IRONIC_BIN_DIR=$(get_python_exec_prefix)
40 62
 
... ...
@@ -86,8 +111,8 @@ function configure_ironic {
86 86
     iniset $IRONIC_CONF_FILE DEFAULT debug True
87 87
     inicomment $IRONIC_CONF_FILE DEFAULT log_file
88 88
     iniset $IRONIC_CONF_FILE DEFAULT sql_connection `database_connection_url ironic`
89
+    iniset $IRONIC_CONF_FILE DEFAULT state_path $IRONIC_STATE_PATH
89 90
     iniset $IRONIC_CONF_FILE DEFAULT use_syslog $SYSLOG
90
-
91 91
     # Configure Ironic conductor, if it was enabled.
92 92
     if is_service_enabled ir-cond; then
93 93
         configure_ironic_conductor
... ...
@@ -97,6 +122,10 @@ function configure_ironic {
97 97
     if is_service_enabled ir-api; then
98 98
         configure_ironic_api
99 99
     fi
100
+
101
+    if [[ "$IRONIC_BAREMETAL_BASIC_OPS" == "True" ]]; then
102
+        configure_ironic_auxiliary
103
+    fi
100 104
 }
101 105
 
102 106
 # configure_ironic_api() - Is used by configure_ironic(). Performs
... ...
@@ -125,6 +154,10 @@ function configure_ironic_conductor {
125 125
     cp -r $IRONIC_DIR/etc/ironic/rootwrap.d $IRONIC_CONF_DIR
126 126
 
127 127
     iniset $IRONIC_CONF_FILE DEFAULT rootwrap_config $IRONIC_ROOTWRAP_CONF
128
+    iniset $IRONIC_CONF_FILE conductor api_url http://$SERVICE_HOST:6385
129
+    iniset $IRONIC_CONF_FILE pxe tftp_server $SERVICE_HOST
130
+    iniset $IRONIC_CONF_FILE pxe tftp_root $IRONIC_TFTPBOOT_DIR
131
+    iniset $IRONIC_CONF_FILE pxe tftp_master_path $IRONIC_TFTPBOOT_DIR/master_images
128 132
 }
129 133
 
130 134
 # create_ironic_cache_dir() - Part of the init_ironic() process
... ...
@@ -225,9 +258,233 @@ function stop_ironic {
225 225
     screen -S $SCREEN_NAME -p ir-cond -X kill
226 226
 }
227 227
 
228
+function is_ironic {
229
+    if ( is_service_enabled ir-cond && is_service_enabled ir-api ); then
230
+        return 0
231
+    fi
232
+    return 1
233
+}
234
+
235
+function configure_ironic_dirs {
236
+    sudo mkdir -p $IRONIC_DATA_DIR
237
+    sudo mkdir -p $IRONIC_STATE_PATH
238
+    sudo mkdir -p $IRONIC_TFTPBOOT_DIR
239
+    sudo chown -R $STACK_USER $IRONIC_DATA_DIR $IRONIC_STATE_PATH
240
+    sudo chown -R $STACK_USER:$LIBVIRT_GROUP $IRONIC_TFTPBOOT_DIR
241
+    if is_ubuntu; then
242
+        PXEBIN=/usr/lib/syslinux/pxelinux.0
243
+    elif is_fedora; then
244
+        PXEBIN=/usr/share/syslinux/pxelinux.0
245
+    fi
246
+    if [ ! -f $PXEBIN ]; then
247
+        die $LINENO "pxelinux.0 (from SYSLINUX) not found."
248
+    fi
249
+
250
+    cp $PXEBIN $IRONIC_TFTPBOOT_DIR
251
+    mkdir -p $IRONIC_TFTPBOOT_DIR/pxelinux.cfg
252
+}
253
+
254
+function ironic_ensure_libvirt_group {
255
+    groups $STACK_USER | grep -q $LIBVIRT_GROUP || adduser $STACK_USER $LIBVIRT_GROUP
256
+}
257
+
258
+function create_bridge_and_vms {
259
+    ironic_ensure_libvirt_group
260
+
261
+    # Call libvirt setup scripts in a new shell to ensure any new group membership
262
+    sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/setup-network"
263
+
264
+    sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/create-nodes \
265
+        $IRONIC_VM_SPECS_CPU $IRONIC_VM_SPECS_RAM $IRONIC_VM_SPECS_DISK \
266
+        amd64 $IRONIC_VM_COUNT $IRONIC_VM_NETWORK_BRIDGE $IRONIC_VM_EMULATOR" >> $IRONIC_VM_MACS_CSV_FILE
267
+
268
+}
269
+
270
+function enroll_vms {
271
+
272
+    CHASSIS_ID=$(ironic chassis-create -d "ironic test chassis" | grep " uuid " | get_field 2)
273
+    IRONIC_NET_ID=$(neutron net-list | grep private | get_field 1)
274
+    local idx=0
275
+
276
+    # work around; need to know what netns neutron uses for private network
277
+    neutron port-create private
278
+
279
+    while read MAC; do
280
+
281
+        NODE_ID=$(ironic node-create --chassis_uuid $CHASSIS_ID --driver pxe_ssh \
282
+            -i ssh_virt_type=$IRONIC_SSH_VIRT_TYPE \
283
+            -i ssh_address=$IRONIC_VM_SSH_ADDRESS \
284
+            -i ssh_port=$IRONIC_VM_SSH_PORT \
285
+            -i ssh_username=$IRONIC_SSH_USERNAME \
286
+            -i ssh_key_filename=$IRONIC_SSH_KEY_DIR/$IRONIC_SSH_KEY_FILENAME \
287
+            -p cpus=$IRONIC_VM_SPECS_CPU \
288
+            -p memory_mb=$IRONIC_VM_SPECS_RAM \
289
+            -p local_gb=$IRONIC_VM_SPECS_DISK \
290
+            -p cpu_arch=x86_64 \
291
+            | grep " uuid " | get_field 2)
292
+
293
+        ironic port-create --address $MAC --node_uuid $NODE_ID
294
+
295
+        idx=$((idx+1))
296
+
297
+    done < $IRONIC_VM_MACS_CSV_FILE
298
+
299
+    # create the nova flavor
300
+    nova flavor-create baremetal auto $IRONIC_VM_SPECS_RAM $IRONIC_VM_SPECS_DISK $IRONIC_VM_SPECS_CPU
301
+    nova flavor-key baremetal set "cpu_arch"="x86_64" "baremetal:deploy_kernel_id"="$BM_DEPLOY_KERNEL_ID" "baremetal:deploy_ramdisk_id"="$BM_DEPLOY_RAMDISK_ID"
302
+
303
+    # intentional sleep to make sure the tag has been set to port
304
+    sleep 10
305
+    TAPDEV=$(sudo ip netns exec qdhcp-${IRONIC_NET_ID} ip link list | grep tap | cut -d':' -f2 | cut -b2-)
306
+    TAG_ID=$(sudo ovs-vsctl show |grep ${TAPDEV} -A1 -m1 | grep tag | cut -d':' -f2 | cut -b2-)
307
+
308
+    # make sure veth pair is not existing, otherwise delete its links
309
+    sudo ip link show ovs-tap1 && sudo ip link delete ovs-tap1
310
+    sudo ip link show brbm-tap1 && sudo ip link delete brbm-tap1
311
+    # create veth pair for future interconnection between br-int and brbm
312
+    sudo ip link add brbm-tap1 type veth peer name ovs-tap1
313
+    sudo ip link set dev brbm-tap1 up
314
+    sudo ip link set dev ovs-tap1 up
315
+
316
+    sudo ovs-vsctl -- --if-exists del-port ovs-tap1 -- add-port br-int ovs-tap1 tag=$TAG_ID
317
+    sudo ovs-vsctl -- --if-exists del-port brbm-tap1 -- add-port $IRONIC_VM_NETWORK_BRIDGE brbm-tap1
318
+}
319
+
320
+function configure_tftpd {
321
+    # enable tftp natting for allowing connections to SERVICE_HOST's tftp server
322
+    sudo modprobe nf_conntrack_tftp
323
+    sudo modprobe nf_nat_tftp
324
+
325
+    if is_ubuntu; then
326
+        PXEBIN=/usr/lib/syslinux/pxelinux.0
327
+    elif is_fedora; then
328
+        PXEBIN=/usr/share/syslinux/pxelinux.0
329
+    fi
330
+    if [ ! -f $PXEBIN ]; then
331
+        die $LINENO "pxelinux.0 (from SYSLINUX) not found."
332
+    fi
333
+
334
+    # stop tftpd and setup serving via xinetd
335
+    stop_service tftpd-hpa || true
336
+    [ -f /etc/init/tftpd-hpa.conf ] && echo "manual" | sudo tee /etc/init/tftpd-hpa.override
337
+    sudo cp $IRONIC_TEMPLATES_DIR/tftpd-xinetd.template /etc/xinetd.d/tftp
338
+    sudo sed -e "s|%TFTPBOOT_DIR%|$IRONIC_TFTPBOOT_DIR|g" -i /etc/xinetd.d/tftp
339
+
340
+    # setup tftp file mapping to satisfy requests at the root (booting) and
341
+    # /tftpboot/ sub-dir (as per deploy-ironic elements)
342
+    echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file
343
+    echo "r ^(/tftpboot/) $IRONIC_TFTPBOOT_DIR/\2" >>$IRONIC_TFTPBOOT_DIR/map-file
344
+
345
+    chmod -R 0755 $IRONIC_TFTPBOOT_DIR
346
+    restart_service xinetd
347
+}
348
+
349
+function configure_ironic_ssh_keypair {
350
+    # Generating ssh key pair for stack user
351
+    if [[ ! -d $IRONIC_SSH_KEY_DIR ]]; then
352
+        mkdir -p $IRONIC_SSH_KEY_DIR
353
+    fi
354
+    if [[ ! -d $HOME/.ssh ]]; then
355
+        mkdir -p $HOME/.ssh
356
+        chmod 700 $HOME/.ssh
357
+    fi
358
+    echo -e 'n\n' | ssh-keygen -q -t rsa -P '' -f $IRONIC_KEY_FILE
359
+    cat $IRONIC_KEY_FILE.pub | tee -a $IRONIC_AUTHORIZED_KEYS_FILE
360
+}
361
+
362
+function ironic_ssh_check {
363
+    local KEY_FILE=$1
364
+    local FLOATING_IP=$2
365
+    local PORT=$3
366
+    local DEFAULT_INSTANCE_USER=$4
367
+    local ACTIVE_TIMEOUT=$5
368
+    if ! timeout $ACTIVE_TIMEOUT sh -c "while ! ssh -p $PORT -o StrictHostKeyChecking=no -i $KEY_FILE ${DEFAULT_INSTANCE_USER}@$FLOATING_IP echo success; do sleep 1; done"; then
369
+        die $LINENO "server didn't become ssh-able!"
370
+    fi
371
+}
372
+
373
+function configure_ironic_sshd {
374
+    # Ensure sshd server accepts connections from localhost only
375
+
376
+    SSH_CONFIG=/etc/ssh/sshd_config
377
+    HOST_PORT=$IRONIC_VM_SSH_ADDRESS:$IRONIC_VM_SSH_PORT
378
+    if ! sudo grep ListenAddress $SSH_CONFIG | grep $HOST_PORT; then
379
+        echo "ListenAddress $HOST_PORT" | sudo tee -a $SSH_CONFIG
380
+    fi
381
+
382
+    SSH_SERVICE_NAME=sshd
383
+    if is_ubuntu; then
384
+        SSH_SERVICE_NAME=ssh
385
+    fi
386
+
387
+    restart_service $SSH_SERVICE_NAME
388
+    # to ensure ssh service is up and running
389
+    sleep 3
390
+    ironic_ssh_check $IRONIC_SSH_KEY_DIR/$IRONIC_SSH_KEY_FILENAME $IRONIC_VM_SSH_ADDRESS $IRONIC_VM_SSH_PORT $IRONIC_SSH_USERNAME 10
391
+
392
+}
393
+
394
+function configure_ironic_auxiliary {
395
+    configure_ironic_dirs
396
+    configure_ironic_ssh_keypair
397
+    configure_ironic_sshd
398
+}
399
+
400
+function prepare_baremetal_basic_ops {
401
+
402
+    # install diskimage-builder
403
+    git_clone $BM_IMAGE_BUILD_REPO $BM_IMAGE_BUILD_DIR $BM_IMAGE_BUILD_BRANCH
404
+
405
+    # make sure all needed service were enabled
406
+    for srv in nova glance key neutron; do
407
+        if ! is_service_enabled "$srv"; then
408
+            die $LINENO "$srv should be enabled for ironic tests"
409
+        fi
410
+    done
411
+
412
+    SCREEN_NAME=${SCREEN_NAME:-stack}
413
+    SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
414
+
415
+    # stop all nova services
416
+    stop_nova || true
417
+
418
+    # remove any nova services failure status
419
+    find $SERVICE_DIR/$SCREEN_NAME -name 'n-*.failure' -exec rm -f '{}' \;
420
+
421
+    # start them again
422
+    start_nova_api
423
+    start_nova
424
+
425
+    TOKEN=$(keystone token-get | grep ' id ' | get_field 2)
426
+    die_if_not_set $LINENO TOKEN "Keystone fail to get token"
427
+
428
+    echo_summary "Creating and uploading baremetal images for ironic"
429
+
430
+    # build and upload separate deploy kernel & ramdisk
431
+    upload_baremetal_deploy $TOKEN
432
+
433
+    create_bridge_and_vms
434
+    enroll_vms
435
+    configure_tftpd
436
+}
437
+
438
+function cleanup_baremetal_basic_ops {
439
+    rm -f $IRONIC_VM_MACS_CSV_FILE
440
+    if [ -f $IRONIC_KEY_FILE ]; then
441
+        KEY=`cat $IRONIC_KEY_FILE.pub`
442
+        # remove public key from authorized_keys
443
+        grep -v "$KEY" $IRONIC_AUTHORIZED_KEYS_FILE > temp && mv temp $IRONIC_AUTHORIZED_KEYS_FILE
444
+        chmod 0600 $IRONIC_AUTHORIZED_KEYS_FILE
445
+    fi
446
+    sudo rm -rf $IRONIC_DATA_DIR $IRONIC_STATE_PATH
447
+    sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/cleanup-nodes $IRONIC_VM_COUNT $IRONIC_VM_NETWORK_BRIDGE"
448
+    sudo rm -rf /etc/xinetd.d/tftp /etc/init/tftpd-hpa.override
449
+    restart_service xinetd
450
+}
228 451
 
229
-# Restore xtrace
452
+# Restore xtrace + pipefail
230 453
 $XTRACE
454
+$PIPEFAIL
231 455
 
232 456
 # Tell emacs to use shell-script-mode
233 457
 ## Local variables:
234 458
new file mode 100644
... ...
@@ -0,0 +1,75 @@
0
+# lib/nova_plugins/hypervisor-ironic
1
+# Configure the ironic hypervisor
2
+
3
+# Enable with:
4
+# VIRT_DRIVER=ironic
5
+
6
+# Dependencies:
7
+# ``functions`` file
8
+# ``nova`` configuration
9
+
10
+# install_nova_hypervisor - install any external requirements
11
+# configure_nova_hypervisor - make configuration changes, including those to other services
12
+# start_nova_hypervisor - start any external services
13
+# stop_nova_hypervisor - stop any external services
14
+# cleanup_nova_hypervisor - remove transient data and cache
15
+
16
+# Save trace setting
17
+MY_XTRACE=$(set +o | grep xtrace)
18
+set +o xtrace
19
+
20
+
21
+# Defaults
22
+# --------
23
+
24
+# Entry Points
25
+# ------------
26
+
27
+# clean_nova_hypervisor - Clean up an installation
28
+function cleanup_nova_hypervisor {
29
+    # This function intentionally left blank
30
+    :
31
+}
32
+
33
+# configure_nova_hypervisor - Set config files, create data dirs, etc
34
+function configure_nova_hypervisor {
35
+    iniset $NOVA_CONF ironic sql_connection `database_connection_url nova_bm`
36
+    LIBVIRT_FIREWALL_DRIVER=${LIBVIRT_FIREWALL_DRIVER:-"nova.virt.firewall.NoopFirewallDriver"}
37
+    iniset $NOVA_CONF DEFAULT compute_driver ironic.nova.virt.ironic.IronicDriver
38
+    iniset $NOVA_CONF DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER
39
+    iniset $NOVA_CONF DEFAULT scheduler_host_manager ironic.nova.scheduler.ironic_host_manager.IronicHostManager
40
+    iniset $NOVA_CONF DEFAULT ram_allocation_ratio 1.0
41
+    iniset $NOVA_CONF DEFAULT reserved_host_memory_mb 0
42
+    # ironic section
43
+    iniset $NOVA_CONF ironic admin_username admin
44
+    iniset $NOVA_CONF ironic admin_password $ADMIN_PASSWORD
45
+    iniset $NOVA_CONF ironic admin_url $KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0
46
+    iniset $NOVA_CONF ironic admin_tenant_name demo
47
+    iniset $NOVA_CONF ironic api_endpoint http://$SERVICE_HOST:6358/v1
48
+}
49
+
50
+# install_nova_hypervisor() - Install external components
51
+function install_nova_hypervisor {
52
+    # This function intentionally left blank
53
+    :
54
+}
55
+
56
+# start_nova_hypervisor - Start any required external services
57
+function start_nova_hypervisor {
58
+    # This function intentionally left blank
59
+    :
60
+}
61
+
62
+# stop_nova_hypervisor - Stop any external services
63
+function stop_nova_hypervisor {
64
+    # This function intentionally left blank
65
+    :
66
+}
67
+
68
+
69
+# Restore xtrace
70
+$MY_XTRACE
71
+
72
+# Local variables:
73
+# mode: shell-script
74
+# End:
... ...
@@ -267,7 +267,7 @@ DEFAULT_VIRT_DRIVER=libvirt
267 267
 is_package_installed xenserver-core && DEFAULT_VIRT_DRIVER=xenserver
268 268
 VIRT_DRIVER=${VIRT_DRIVER:-$DEFAULT_VIRT_DRIVER}
269 269
 case "$VIRT_DRIVER" in
270
-    libvirt)
270
+    ironic|libvirt)
271 271
         LIBVIRT_TYPE=${LIBVIRT_TYPE:-kvm}
272 272
         if [[ "$os_VENDOR" =~ (Debian) ]]; then
273 273
             LIBVIRT_GROUP=libvirt
... ...
@@ -55,7 +55,13 @@ export_proxy_variables
55 55
 # ================
56 56
 
57 57
 # Install package requirements
58
-install_package $(get_packages general $ENABLED_SERVICES)
58
+PACKAGES=$(get_packages general $ENABLED_SERVICES)
59
+if is_ubuntu && echo $PACKAGES | grep -q dkms ; then
60
+    # ensure headers for the running kernel are installed for any DKMS builds
61
+    PACKAGES="$PACKAGES linux-headers-$(uname -r)"
62
+fi
63
+
64
+install_package $PACKAGES
59 65
 
60 66
 if [[ -n "$SYSLOG" && "$SYSLOG" != "False" ]]; then
61 67
     if is_ubuntu || is_fedora; then
62 68
new file mode 100755
... ...
@@ -0,0 +1,25 @@
0
+#!/usr/bin/env bash
1
+
2
+# **cleanup-nodes**
3
+
4
+# Cleans up baremetal poseur nodes and volumes created during ironic setup
5
+# Assumes calling user has proper libvirt group membership and access.
6
+
7
+set -exu
8
+
9
+LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"}
10
+
11
+VM_COUNT=$1
12
+NETWORK_BRIDGE=$2
13
+
14
+for (( idx=0; idx<$VM_COUNT; idx++ )); do
15
+    NAME="baremetal${NETWORK_BRIDGE}_${idx}"
16
+    VOL_NAME="baremetal${NETWORK_BRIDGE}-${idx}.qcow2"
17
+    virsh list | grep -q $NAME && virsh destroy $NAME
18
+    virsh list --inactive | grep -q $NAME && virsh undefine $NAME
19
+
20
+    if virsh pool-list | grep -q $LIBVIRT_STORAGE_POOL ; then
21
+      virsh vol-list $LIBVIRT_STORAGE_POOL | grep -q $VOL_NAME &&
22
+          virsh vol-delete $VOL_NAME --pool $LIBVIRT_STORAGE_POOL
23
+    fi
24
+done
0 25
new file mode 100755
... ...
@@ -0,0 +1,78 @@
0
+#!/usr/bin/env python
1
+
2
+import argparse
3
+import os.path
4
+
5
+import libvirt
6
+
7
+templatedir = os.path.join(os.path.dirname(os.path.dirname(__file__)),
8
+                           'templates')
9
+
10
+
11
+def main():
12
+    parser = argparse.ArgumentParser(
13
+        description="Configure a kvm virtual machine for the seed image.")
14
+    parser.add_argument('--name', default='seed',
15
+                        help='the name to give the machine in libvirt.')
16
+    parser.add_argument('--image',
17
+                        help='Use a custom image file (must be qcow2).')
18
+    parser.add_argument('--engine', default='qemu',
19
+                        help='The virtualization engine to use')
20
+    parser.add_argument('--arch', default='i686',
21
+                        help='The architecture to use')
22
+    parser.add_argument('--memory', default='2097152',
23
+                        help="Maximum memory for the VM in KB.")
24
+    parser.add_argument('--cpus', default='1',
25
+                        help="CPU count for the VM.")
26
+    parser.add_argument('--bootdev', default='hd',
27
+                        help="What boot device to use (hd/network).")
28
+    parser.add_argument('--network', default="brbm",
29
+                        help='The libvirt network name to use')
30
+    parser.add_argument('--libvirt-nic-driver', default='e1000',
31
+                        help='The libvirt network driver to use')
32
+    parser.add_argument('--emulator', default=None,
33
+                        help='Path to emulator bin for vm template')
34
+    args = parser.parse_args()
35
+    with file(templatedir + '/vm.xml', 'rb') as f:
36
+        source_template = f.read()
37
+    params = {
38
+        'name': args.name,
39
+        'imagefile': args.image,
40
+        'engine': args.engine,
41
+        'arch': args.arch,
42
+        'memory': args.memory,
43
+        'cpus': args.cpus,
44
+        'bootdev': args.bootdev,
45
+        'network': args.network,
46
+        'emulator': args.emulator,
47
+    }
48
+
49
+    if args.emulator:
50
+        params['emulator'] = args.emulator
51
+    else:
52
+        if os.path.exists("/usr/bin/kvm"):  # Debian
53
+            params['emulator'] = "/usr/bin/kvm"
54
+        elif os.path.exists("/usr/bin/qemu-kvm"):  # Redhat
55
+            params['emulator'] = "/usr/bin/qemu-kvm"
56
+
57
+    nicparams = {
58
+        'nicdriver': args.libvirt_nic_driver,
59
+        'network': args.network,
60
+    }
61
+
62
+    params['bm_network'] = """
63
+<!-- neutron friendly 'bare metal' network -->
64
+<interface type='network'>
65
+  <source network='%(network)s'/>
66
+  <virtualport type='openvswitch'/>
67
+  <model type='%(nicdriver)s'/>
68
+  <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
69
+</interface>""" % nicparams
70
+
71
+    libvirt_template = source_template % params
72
+    conn = libvirt.open("qemu:///system")
73
+    a = conn.defineXML(libvirt_template)
74
+    print ("Created machine %s with UUID %s" % (args.name, a.UUIDString()))
75
+
76
+if __name__ == '__main__':
77
+    main()
0 78
new file mode 100755
... ...
@@ -0,0 +1,68 @@
0
+#!/usr/bin/env bash
1
+
2
+# **create-nodes**
3
+
4
+# Creates baremetal poseur nodes for ironic testing purposes
5
+
6
+set -exu
7
+
8
+# Keep track of the devstack directory
9
+TOP_DIR=$(cd $(dirname "$0")/.. && pwd)
10
+
11
+CPU=$1
12
+MEM=$(( 1024 * $2 ))
13
+# extra G to allow fuzz for partition table : flavor size and registered size
14
+# need to be different to actual size.
15
+DISK=$(( $3 + 1))
16
+
17
+case $4 in
18
+    i386) ARCH='i686' ;;
19
+    amd64) ARCH='x86_64' ;;
20
+    *) echo "Unsupported arch $4!" ; exit 1 ;;
21
+esac
22
+
23
+TOTAL=$(($5 - 1))
24
+BRIDGE=$6
25
+EMULATOR=$7
26
+
27
+LIBVIRT_NIC_DRIVER=${LIBVIRT_NIC_DRIVER:-"e1000"}
28
+LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"}
29
+
30
+if ! virsh pool-list --all | grep -q $LIBVIRT_STORAGE_POOL; then
31
+    virsh pool-define-as --name $LIBVIRT_STORAGE_POOL dir --target /var/lib/libvirt/images >&2
32
+    virsh pool-autostart $LIBVIRT_STORAGE_POOL >&2
33
+    virsh pool-start $LIBVIRT_STORAGE_POOL >&2
34
+fi
35
+
36
+pool_state=$(virsh pool-info $LIBVIRT_STORAGE_POOL | grep State | awk '{ print $2 }')
37
+if [ "$pool_state" != "running" ] ; then
38
+  [ ! -d /var/lib/libvirt/images ] && sudo mkdir /var/lib/libvirt/images
39
+  virsh pool-start $LIBVIRT_STORAGE_POOL >&2
40
+fi
41
+
42
+PREALLOC=
43
+if [ -f /etc/debian_version ]; then
44
+    PREALLOC="--prealloc-metadata"
45
+fi
46
+
47
+DOMS=""
48
+for idx in $(seq 0 $TOTAL) ; do
49
+    NAME="baremetal${BRIDGE}_${idx}"
50
+    DOMS="$DOMS $NAME"
51
+    VOL_NAME="baremetal${BRIDGE}-${idx}.qcow2"
52
+    (virsh list --all | grep -q $NAME) && continue
53
+
54
+    virsh vol-list --pool $LIBVIRT_STORAGE_POOL | grep -q $VOL_NAME &&
55
+        virsh vol-delete $VOL_NAME --pool $LIBVIRT_STORAGE_POOL >&2
56
+    virsh vol-create-as $LIBVIRT_STORAGE_POOL ${VOL_NAME} ${DISK}G --format qcow2 $PREALLOC >&2
57
+    volume_path=$(virsh vol-path --pool $LIBVIRT_STORAGE_POOL $VOL_NAME)
58
+    # Pre-touch the VM to set +C, as it can only be set on empty files.
59
+    sudo touch "$volume_path"
60
+    sudo chattr +C "$volume_path" || true
61
+    $TOP_DIR/scripts/configure-vm --bootdev network --name $NAME --image "$volume_path" --arch $ARCH --cpus $CPU --memory $MEM --libvirt-nic-driver $LIBVIRT_NIC_DRIVER --emulator $EMULATOR --network $BRIDGE >&2
62
+done
63
+
64
+for dom in $DOMS ; do
65
+    # echo mac
66
+    virsh dumpxml $dom | grep "mac address" | head -1 | cut -d\' -f2
67
+done
0 68
new file mode 100755
... ...
@@ -0,0 +1,24 @@
0
+#!/usr/bin/env bash
1
+
2
+# **setup-network**
3
+
4
+# Setups openvswitch libvirt network suitable for
5
+# running baremetal poseur nodes for ironic testing purposes
6
+
7
+set -exu
8
+
9
+# Keep track of the devstack directory
10
+TOP_DIR=$(cd $(dirname "$0")/.. && pwd)
11
+BRIDGE_SUFFIX=${1:-''}
12
+BRIDGE_NAME=brbm$BRIDGE_SUFFIX
13
+
14
+# Only add bridge if missing
15
+(sudo ovs-vsctl list-br | grep ${BRIDGE_NAME}$) || sudo ovs-vsctl add-br ${BRIDGE_NAME}
16
+
17
+# remove bridge before replacing it.
18
+(virsh net-list | grep "${BRIDGE_NAME} ") && virsh net-destroy ${BRIDGE_NAME}
19
+(virsh net-list --inactive  | grep "${BRIDGE_NAME} ") && virsh net-undefine ${BRIDGE_NAME}
20
+
21
+virsh net-define <(sed s/brbm/$BRIDGE_NAME/ $TOP_DIR/templates/brbm.xml)
22
+virsh net-autostart ${BRIDGE_NAME}
23
+virsh net-start ${BRIDGE_NAME}
0 24
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+<network>
1
+  <name>brbm</name>
2
+  <forward mode='bridge'/>
3
+  <bridge name='brbm'/>
4
+  <virtualport type='openvswitch'/>
5
+</network>
0 6
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+service tftp
1
+{
2
+  protocol        = udp
3
+  port            = 69
4
+  socket_type     = dgram
5
+  wait            = yes
6
+  user            = root
7
+  server          = /usr/sbin/in.tftpd
8
+  server_args     = -v -v -v -v -v --map-file %TFTPBOOT_DIR%/map-file %TFTPBOOT_DIR%
9
+  disable         = no
10
+}
0 11
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+<domain type='%(engine)s'>
1
+  <name>%(name)s</name>
2
+  <memory unit='KiB'>%(memory)s</memory>
3
+  <vcpu>%(cpus)s</vcpu>
4
+  <os>
5
+    <type arch='%(arch)s' machine='pc-1.0'>hvm</type>
6
+    <boot dev='%(bootdev)s'/>
7
+    <bootmenu enable='no'/>
8
+  </os>
9
+  <features>
10
+    <acpi/>
11
+    <apic/>
12
+    <pae/>
13
+  </features>
14
+  <clock offset='utc'/>
15
+  <on_poweroff>destroy</on_poweroff>
16
+  <on_reboot>restart</on_reboot>
17
+  <on_crash>restart</on_crash>
18
+  <devices>
19
+    <emulator>%(emulator)s</emulator>
20
+    <disk type='file' device='disk'>
21
+      <driver name='qemu' type='qcow2' cache='writeback'/>
22
+      <source file='%(imagefile)s'/>
23
+      <target dev='vda' bus='virtio'/>
24
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
25
+    </disk>
26
+    <controller type='ide' index='0'>
27
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
28
+    </controller>
29
+    %(network)s
30
+    %(bm_network)s
31
+    <input type='mouse' bus='ps2'/>
32
+    <graphics type='vnc' port='-1' autoport='yes'/>
33
+    <video>
34
+      <model type='cirrus' vram='9216' heads='1'/>
35
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
36
+    </video>
37
+    <memballoon model='virtio'>
38
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
39
+    </memballoon>
40
+  </devices>
41
+</domain>
42
+