devstack/lib/baremetal
Sean Dague 16dd8b3ed9 introduce if/then & for/do rules
we mostly have a consistent style on if/then & for/do in devstack,
except when we don't. This attempts to build a set of rules to
enforce this.

Because there are times when lines are legitimately long, and there
is a continuation, this starts off ignoring if and for loops with
continuations. But for short versions, we should enforce this.

Changes to make devstack pass are included. The fact that the
cleanup patch was so small is pretty solid reason that this is
actually the style we've all agreed to.

Part of a git stash from hong kong that I finally cleaned up.

Change-Id: I6376d7afd59cc5ebba9ed69e5ee784a3d5934a10
2014-02-05 07:52:54 +01:00

472 lines
16 KiB
Plaintext

## vim: tabstop=4 shiftwidth=4 softtabstop=4
## Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
## All Rights Reserved.
##
## Licensed under the Apache License, Version 2.0 (the "License"); you may
## not use this file except in compliance with the License. You may obtain
## a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
## License for the specific language governing permissions and limitations
## under the License.
# This file provides devstack with the environment and utilities to
# control nova-compute's baremetal driver.
# It sets reasonable defaults to run within a single host,
# using virtual machines in place of physical hardware.
# However, by changing just a few options, devstack+baremetal can in fact
# control physical hardware resources on the same network, if you know
# the MAC address(es) and IPMI credentials.
#
# At a minimum, to enable the baremetal driver, you must set these in localrc:
#
# VIRT_DRIVER=baremetal
# ENABLED_SERVICES="$ENABLED_SERVICES,baremetal"
#
#
# We utilize diskimage-builder to create a ramdisk, and then
# baremetal driver uses that to push a disk image onto the node(s).
#
# Below we define various defaults which control the behavior of the
# baremetal compute service, and inform it of the hardware it will control.
#
# Below that, various functions are defined, which are called by devstack
# in the following order:
#
# before nova-cpu starts:
#
# - prepare_baremetal_toolchain
# - configure_baremetal_nova_dirs
#
# after nova and glance have started:
#
# - build_and_upload_baremetal_deploy_k_and_r $token
# - create_baremetal_flavor $BM_DEPLOY_KERNEL_ID $BM_DEPLOY_RAMDISK_ID
# - upload_baremetal_image $url $token
# - add_baremetal_node <first_mac> <second_mac>
# Save trace setting
XTRACE=$(set +o | grep xtrace)
set +o xtrace
# Sub-driver settings
# -------------------
# sub-driver to use for kernel deployment
#
# - nova.virt.baremetal.pxe.PXE
# - nova.virt.baremetal.tilera.TILERA
BM_DRIVER=${BM_DRIVER:-nova.virt.baremetal.pxe.PXE}
# sub-driver to use for remote power management
#
# - nova.virt.baremetal.fake.FakePowerManager, for manual power control
# - nova.virt.baremetal.ipmi.IPMI, for remote IPMI
# - nova.virt.baremetal.tilera_pdu.Pdu, for TilePro hardware
BM_POWER_MANAGER=${BM_POWER_MANAGER:-nova.virt.baremetal.fake.FakePowerManager}
# These should be customized to your environment and hardware
# -----------------------------------------------------------
# whether to create a fake environment, eg. for devstack-gate
BM_USE_FAKE_ENV=`trueorfalse False $BM_USE_FAKE_ENV`
# Extra options to pass to bm_poseur
# change the bridge name or IP: --bridge br99 --bridge-ip 192.0.2.1
# change the virtualization type: --engine qemu
BM_POSEUR_EXTRA_OPTS=${BM_POSEUR_EXTRA_OPTS:-}
# To provide PXE, configure nova-network's dnsmasq rather than run the one
# dedicated to baremetal. When enable this, make sure these conditions are
# fulfilled:
#
# 1) nova-compute and nova-network runs on the same host
# 2) nova-network uses FlatDHCPManager
#
# NOTE: the other BM_DNSMASQ_* have no effect on the behavior if this option
# is enabled.
BM_DNSMASQ_FROM_NOVA_NETWORK=`trueorfalse False $BM_DNSMASQ_FROM_NOVA_NETWORK`
# BM_DNSMASQ_IFACE should match FLAT_NETWORK_BRIDGE
if [ "$BM_USE_FAKE_ENV" ]; then
BM_DNSMASQ_IFACE=${BM_DNSMASQ_IFACE:-br99}
BM_DNSMASQ_RANGE=${BM_DNSMASQ_RANGE:-192.0.2.32,192.0.2.48}
else
BM_DNSMASQ_IFACE=${BM_DNSMASQ_IFACE:-eth0}
# if testing on a physical network,
# BM_DNSMASQ_RANGE must be changed to suit your network
BM_DNSMASQ_RANGE=${BM_DNSMASQ_RANGE:-}
fi
# BM_DNSMASQ_DNS provide dns server to bootstrap clients
BM_DNSMASQ_DNS=${BM_DNSMASQ_DNS:-}
# BM_FIRST_MAC *must* be set to the MAC address of the node you will
# boot. This is passed to dnsmasq along with the kernel/ramdisk to
# deploy via PXE.
BM_FIRST_MAC=${BM_FIRST_MAC:-}
# BM_SECOND_MAC is only important if the host has >1 NIC.
BM_SECOND_MAC=${BM_SECOND_MAC:-}
# Hostname for the baremetal nova-compute node, if not run on this host
BM_HOSTNAME=${BM_HOSTNAME:-$(hostname -f)}
# BM_PM_* options are only necessary if BM_POWER_MANAGER=...IPMI
BM_PM_ADDR=${BM_PM_ADDR:-0.0.0.0}
BM_PM_USER=${BM_PM_USER:-user}
BM_PM_PASS=${BM_PM_PASS:-pass}
# BM_FLAVOR_* options are arbitrary and not necessarily related to
# physical hardware capacity. These can be changed if you are testing
# BaremetalHostManager with multiple nodes and different flavors.
BM_CPU_ARCH=${BM_CPU_ARCH:-x86_64}
BM_FLAVOR_CPU=${BM_FLAVOR_CPU:-1}
BM_FLAVOR_RAM=${BM_FLAVOR_RAM:-1024}
BM_FLAVOR_ROOT_DISK=${BM_FLAVOR_ROOT_DISK:-10}
BM_FLAVOR_EPHEMERAL_DISK=${BM_FLAVOR_EPHEMERAL_DISK:-0}
BM_FLAVOR_SWAP=${BM_FLAVOR_SWAP:-1}
BM_FLAVOR_NAME=${BM_FLAVOR_NAME:-bm.small}
BM_FLAVOR_ID=${BM_FLAVOR_ID:-11}
BM_FLAVOR_ARCH=${BM_FLAVOR_ARCH:-$BM_CPU_ARCH}
# Below this, we set some path and filenames.
# Defaults are probably sufficient.
BM_IMAGE_BUILD_DIR=${BM_IMAGE_BUILD_DIR:-$DEST/diskimage-builder}
BM_POSEUR_DIR=${BM_POSEUR_DIR:-$DEST/bm_poseur}
# Use DIB to create deploy ramdisk and kernel.
BM_BUILD_DEPLOY_RAMDISK=`trueorfalse True $BM_BUILD_DEPLOY_RAMDISK`
# If not use DIB, these files are used as deploy ramdisk/kernel.
# (The value must be a relative path from $TOP_DIR/files/)
BM_DEPLOY_RAMDISK=${BM_DEPLOY_RAMDISK:-}
BM_DEPLOY_KERNEL=${BM_DEPLOY_KERNEL:-}
# If you need to add any extra flavors to the deploy ramdisk image
# eg, specific network drivers, specify them here
BM_DEPLOY_FLAVOR=${BM_DEPLOY_FLAVOR:-}
# set URL and version for google shell-in-a-box
BM_SHELL_IN_A_BOX=${BM_SHELL_IN_A_BOX:-http://shellinabox.googlecode.com/files/shellinabox-2.14.tar.gz}
# Functions
# ---------
# Check if baremetal is properly enabled
# Returns false if VIRT_DRIVER is not baremetal, or if ENABLED_SERVICES
# does not contain "baremetal"
function is_baremetal() {
if [[ "$ENABLED_SERVICES" =~ 'baremetal' && "$VIRT_DRIVER" = 'baremetal' ]]; then
return 0
fi
return 1
}
# Install diskimage-builder and shell-in-a-box
# so that we can build the deployment kernel & ramdisk
function prepare_baremetal_toolchain() {
git_clone $BM_IMAGE_BUILD_REPO $BM_IMAGE_BUILD_DIR $BM_IMAGE_BUILD_BRANCH
git_clone $BM_POSEUR_REPO $BM_POSEUR_DIR $BM_POSEUR_BRANCH
local shellinabox_basename=$(basename $BM_SHELL_IN_A_BOX)
if [[ ! -e $DEST/$shellinabox_basename ]]; then
cd $DEST
wget $BM_SHELL_IN_A_BOX
fi
if [[ ! -d $DEST/${shellinabox_basename%%.tar.gz} ]]; then
cd $DEST
tar xzf $shellinabox_basename
fi
if [[ ! $(which shellinaboxd) ]]; then
cd $DEST/${shellinabox_basename%%.tar.gz}
./configure
make
sudo make install
fi
}
# set up virtualized environment for devstack-gate testing
function create_fake_baremetal_env() {
local bm_poseur="$BM_POSEUR_DIR/bm_poseur"
# TODO(deva): add support for >1 VM
sudo $bm_poseur $BM_POSEUR_EXTRA_OPTS create-bridge
sudo $bm_poseur $BM_POSEUR_EXTRA_OPTS create-vm
BM_FIRST_MAC=$(sudo $bm_poseur get-macs)
# NOTE: there is currently a limitation in baremetal driver
# that requires second MAC even if it is not used.
# Passing a fake value allows this to work.
# TODO(deva): remove this after driver issue is fixed.
BM_SECOND_MAC='12:34:56:78:90:12'
}
function cleanup_fake_baremetal_env() {
local bm_poseur="$BM_POSEUR_DIR/bm_poseur"
sudo $bm_poseur $BM_POSEUR_EXTRA_OPTS destroy-vm
sudo $bm_poseur $BM_POSEUR_EXTRA_OPTS destroy-bridge
}
# prepare various directories needed by baremetal hypervisor
function configure_baremetal_nova_dirs() {
# ensure /tftpboot is prepared
sudo mkdir -p /tftpboot
sudo mkdir -p /tftpboot/pxelinux.cfg
PXEBIN=/usr/share/syslinux/pxelinux.0
if [ ! -f $PXEBIN ]; then
PXEBIN=/usr/lib/syslinux/pxelinux.0
if [ ! -f $PXEBIN ]; then
die $LINENO "pxelinux.0 (from SYSLINUX) not found."
fi
fi
sudo cp $PXEBIN /tftpboot/
sudo chown -R $STACK_USER:$LIBVIRT_GROUP /tftpboot
# ensure $NOVA_STATE_PATH/baremetal is prepared
sudo mkdir -p $NOVA_STATE_PATH/baremetal
sudo mkdir -p $NOVA_STATE_PATH/baremetal/console
sudo mkdir -p $NOVA_STATE_PATH/baremetal/dnsmasq
sudo touch $NOVA_STATE_PATH/baremetal/dnsmasq/dnsmasq-dhcp.host
sudo chown -R $STACK_USER $NOVA_STATE_PATH/baremetal
# ensure dnsmasq is installed but not running
# because baremetal driver will reconfigure and restart this as needed
is_package_installed dnsmasq || install_package dnsmasq
stop_service dnsmasq
}
# build deploy kernel+ramdisk, then upload them to glance
# this function sets BM_DEPLOY_KERNEL_ID and BM_DEPLOY_RAMDISK_ID
function upload_baremetal_deploy() {
token=$1
if [ "$BM_BUILD_DEPLOY_RAMDISK" = "True" ]; then
BM_DEPLOY_KERNEL=bm-deploy.kernel
BM_DEPLOY_RAMDISK=bm-deploy.initramfs
if [ ! -e "$TOP_DIR/files/$BM_DEPLOY_KERNEL" -o ! -e "$TOP_DIR/files/$BM_DEPLOY_RAMDISK" ]; then
$BM_IMAGE_BUILD_DIR/bin/ramdisk-image-create $BM_DEPLOY_FLAVOR deploy \
-o $TOP_DIR/files/bm-deploy
fi
fi
# load them into glance
BM_DEPLOY_KERNEL_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name $BM_DEPLOY_KERNEL \
--is-public True --disk-format=aki \
< $TOP_DIR/files/$BM_DEPLOY_KERNEL | grep ' id ' | get_field 2)
BM_DEPLOY_RAMDISK_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name $BM_DEPLOY_RAMDISK \
--is-public True --disk-format=ari \
< $TOP_DIR/files/$BM_DEPLOY_RAMDISK | grep ' id ' | get_field 2)
}
# create a basic baremetal flavor, associated with deploy kernel & ramdisk
#
# Usage: create_baremetal_flavor <aki_uuid> <ari_uuid>
function create_baremetal_flavor() {
aki=$1
ari=$2
nova flavor-create $BM_FLAVOR_NAME $BM_FLAVOR_ID \
$BM_FLAVOR_RAM $BM_FLAVOR_ROOT_DISK $BM_FLAVOR_CPU
nova flavor-key $BM_FLAVOR_NAME set \
"cpu_arch"="$BM_FLAVOR_ARCH" \
"baremetal:deploy_kernel_id"="$aki" \
"baremetal:deploy_ramdisk_id"="$ari"
}
# Pull run-time kernel/ramdisk out of disk image and load into glance.
# Note that $file is currently expected to be in qcow2 format.
# Sets KERNEL_ID and RAMDISK_ID
#
# Usage: extract_and_upload_k_and_r_from_image $token $file
function extract_and_upload_k_and_r_from_image() {
token=$1
file=$2
image_name=$(basename "$file" ".qcow2")
# this call returns the file names as "$kernel,$ramdisk"
out=$($BM_IMAGE_BUILD_DIR/bin/disk-image-get-kernel \
-x -d $TOP_DIR/files -o bm-deploy -i $file)
if [ $? -ne 0 ]; then
die $LINENO "Failed to get kernel and ramdisk from $file"
fi
XTRACE=$(set +o | grep xtrace)
set +o xtrace
out=$(echo "$out" | tail -1)
$XTRACE
OUT_KERNEL=${out%%,*}
OUT_RAMDISK=${out##*,}
# load them into glance
KERNEL_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name $image_name-kernel \
--is-public True --disk-format=aki \
< $TOP_DIR/files/$OUT_KERNEL | grep ' id ' | get_field 2)
RAMDISK_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name $image_name-initrd \
--is-public True --disk-format=ari \
< $TOP_DIR/files/$OUT_RAMDISK | grep ' id ' | get_field 2)
}
# Re-implementation of devstack's "upload_image" function
#
# Takes the same parameters, but has some peculiarities which made it
# easier to create a separate method, rather than complicate the logic
# of the existing function.
function upload_baremetal_image() {
local image_url=$1
local token=$2
# Create a directory for the downloaded image tarballs.
mkdir -p $FILES/images
# Downloads the image (uec ami+aki style), then extracts it.
IMAGE_FNAME=`basename "$image_url"`
if [[ ! -f $FILES/$IMAGE_FNAME || \
"$(stat -c "%s" $FILES/$IMAGE_FNAME)" = "0" ]]; then
wget -c $image_url -O $FILES/$IMAGE_FNAME
if [[ $? -ne 0 ]]; then
echo "Not found: $image_url"
return
fi
fi
local KERNEL=""
local RAMDISK=""
local DISK_FORMAT=""
local CONTAINER_FORMAT=""
case "$IMAGE_FNAME" in
*.tar.gz|*.tgz)
# Extract ami and aki files
[ "${IMAGE_FNAME%.tar.gz}" != "$IMAGE_FNAME" ] &&
IMAGE_NAME="${IMAGE_FNAME%.tar.gz}" ||
IMAGE_NAME="${IMAGE_FNAME%.tgz}"
xdir="$FILES/images/$IMAGE_NAME"
rm -Rf "$xdir";
mkdir "$xdir"
tar -zxf $FILES/$IMAGE_FNAME -C "$xdir"
KERNEL=$(for f in "$xdir/"*-vmlinuz* "$xdir/"aki-*/image; do
[ -f "$f" ] && echo "$f" && break; done; true)
RAMDISK=$(for f in "$xdir/"*-initrd* "$xdir/"ari-*/image; do
[ -f "$f" ] && echo "$f" && break; done; true)
IMAGE=$(for f in "$xdir/"*.img "$xdir/"ami-*/image; do
[ -f "$f" ] && echo "$f" && break; done; true)
if [[ -z "$IMAGE_NAME" ]]; then
IMAGE_NAME=$(basename "$IMAGE" ".img")
fi
DISK_FORMAT=ami
CONTAINER_FORMAT=ami
;;
*.qcow2)
IMAGE="$FILES/${IMAGE_FNAME}"
IMAGE_NAME=$(basename "$IMAGE" ".qcow2")
DISK_FORMAT=qcow2
CONTAINER_FORMAT=bare
;;
*) echo "Do not know what to do with $IMAGE_FNAME"; false;;
esac
if [ "$CONTAINER_FORMAT" = "bare" ]; then
extract_and_upload_k_and_r_from_image $token $IMAGE
elif [ "$CONTAINER_FORMAT" = "ami" ]; then
KERNEL_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name "$IMAGE_NAME-kernel" --is-public True \
--container-format aki \
--disk-format aki < "$KERNEL" | grep ' id ' | get_field 2)
RAMDISK_ID=$(glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name "$IMAGE_NAME-ramdisk" --is-public True \
--container-format ari \
--disk-format ari < "$RAMDISK" | grep ' id ' | get_field 2)
else
# TODO(deva): add support for other image types
return
fi
glance \
--os-auth-token $token \
--os-image-url http://$GLANCE_HOSTPORT \
image-create \
--name "${IMAGE_NAME%.img}" --is-public True \
--container-format $CONTAINER_FORMAT \
--disk-format $DISK_FORMAT \
${KERNEL_ID:+--property kernel_id=$KERNEL_ID} \
${RAMDISK_ID:+--property ramdisk_id=$RAMDISK_ID} < "${IMAGE}"
# override DEFAULT_IMAGE_NAME so that tempest can find the image
# that we just uploaded in glance
DEFAULT_IMAGE_NAME="${IMAGE_NAME%.img}"
}
function clear_baremetal_of_all_nodes() {
list=$(nova baremetal-node-list | awk -F '| ' 'NR>3 {print $2}' )
for node in $list; do
nova baremetal-node-delete $node
done
}
# Inform nova-baremetal about nodes, MACs, etc.
# Defaults to using BM_FIRST_MAC and BM_SECOND_MAC if parameters not specified
#
# Usage: add_baremetal_node <first_mac> <second_mac>
function add_baremetal_node() {
mac_1=${1:-$BM_FIRST_MAC}
mac_2=${2:-$BM_SECOND_MAC}
id=$(nova baremetal-node-create \
--pm_address="$BM_PM_ADDR" \
--pm_user="$BM_PM_USER" \
--pm_password="$BM_PM_PASS" \
"$BM_HOSTNAME" \
"$BM_FLAVOR_CPU" \
"$BM_FLAVOR_RAM" \
"$BM_FLAVOR_ROOT_DISK" \
"$mac_1" \
| grep ' id ' | get_field 2 )
[ $? -eq 0 ] || [ "$id" ] || die $LINENO "Error adding baremetal node"
if [ -n "$mac_2" ]; then
id2=$(nova baremetal-interface-add "$id" "$mac_2" )
[ $? -eq 0 ] || [ "$id2" ] || die $LINENO "Error adding interface to barmetal node $id"
fi
}
# Restore xtrace
$XTRACE
# Tell emacs to use shell-script-mode
## Local variables:
## mode: shell-script
## End: