DevStack: Configure nodes/environment to boot in UEFI mode

This patch is adding support for DevStack to configure nodes and
environment (Ubuntu and Fedora) to deploy nodes in UEFI mode.

A new configuration called IRONIC_BOOT_MODE was added to DevStack and
supports two values: "bios" and "uefi". Defaults to "bios".

Partial-Bug: #1625616
Change-Id: I4e9247c6a91c707db08247a8ac04b1f146cd3714
This commit is contained in:
Lucas Alvares Gomes 2016-09-22 10:21:24 -03:00
parent 18a1f97d24
commit 07686f475d
3 changed files with 149 additions and 19 deletions

View File

@ -35,3 +35,4 @@ xinetd
squashfs-tools
libvirt-dev
socat
ipxe-qemu

View File

@ -17,3 +17,5 @@ xinetd
squashfs-tools
libvirt-devel
socat
edk2-ovmf
ipxe-roms-qemu

View File

@ -399,10 +399,66 @@ IRONIC_PXE_BOOT_IMAGE=${IRONIC_PXE_BOOT_IMAGE:-$(get_pxe_boot_file)}
IRONIC_AUTOMATED_CLEAN_ENABLED=$(trueorfalse True IRONIC_AUTOMATED_CLEAN_ENABLED)
# Whether configure the nodes to boot in Legacy BIOS or UEFI mode. Accepted
# values are: "bios" or "uefi", defaults to "bios".
#
# WARNING: UEFI is EXPERIMENTAL. The CirrOS images uploaded by DevStack by
# default WILL NOT WORK with UEFI. You will need to download the UEFI capable
# images manually from [0] and upload it to Glance before deploying.
IRONIC_BOOT_MODE=${IRONIC_BOOT_MODE:-bios}
IRONIC_UEFI_FILES_DIR=${IRONIC_UEFI_FILES_DIR:-/var/lib/libvirt/images}
UEFI_LOADER_PATH=$IRONIC_UEFI_FILES_DIR/OVMF_CODE.fd
UEFI_NVRAM_PATH=$IRONIC_UEFI_FILES_DIR/OVMF_VARS.fd
# Sanity checks
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
if [[ "$IRONIC_IPXE_ENABLED" == "False" ]]; then
die $LINENO "Boot mode UEFI is only supported when used with iPXE for now."
fi
if ! is_fedora && ! is_ubuntu; then
die $LINENO "Boot mode UEFI only works in Ubuntu or Fedora for now."
fi
fi
# Functions
# ---------
# UEFI related functions
function get_uefi_ipxe_boot_file {
if is_ubuntu; then
echo /usr/lib/ipxe/ipxe.efi
elif is_fedora; then
echo /usr/share/ipxe/ipxe-x86_64.efi
fi
}
function get_uefi_loader {
if is_ubuntu; then
echo /usr/share/OVMF/OVMF_CODE.fd
elif is_fedora; then
echo /usr/share/edk2/ovmf/OVMF_CODE.fd
fi
}
function get_uefi_nvram {
if is_ubuntu; then
echo /usr/share/OVMF/OVMF_VARS.fd
elif is_fedora; then
echo /usr/share/edk2/ovmf/OVMF_VARS.fd
fi
}
# Misc
function restart_libvirt {
local libvirt_service_name="libvirtd"
if is_ubuntu && [ ! -f /etc/init.d/libvirtd ]; then
libvirt_service_name="libvirt-bin"
fi
restart_service $libvirt_service_name
}
# Test if any Ironic services are enabled
# is_ironic_enabled
function is_ironic_enabled {
@ -459,9 +515,12 @@ function is_deploy_iso_required {
return 1
}
# TODO(lucasagomes): This logic was moved from DevStack and need some
# refactor
IRONIC_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-x86_64-uec}
IRONIC_DEFAULT_IMAGE_NAME=cirros-${CIRROS_VERSION}-x86_64-uec
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
IRONIC_DEFAULT_IMAGE_NAME=cirros-d160722-x86_64-uec
fi
IRONIC_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-$IRONIC_DEFAULT_IMAGE_NAME}
if [[ "$IMAGE_URLS" != *"$IRONIC_IMAGE_NAME"* ]]; then
@ -469,8 +528,13 @@ if [[ "$IMAGE_URLS" != *"$IRONIC_IMAGE_NAME"* ]]; then
IMAGE_URLS+=","
fi
IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz"
IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-disk.img"
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
IMAGE_URLS+="http://download.cirros-cloud.net/daily/20160722/cirros-d160722-x86_64-uec.tar.gz"
IMAGE_URLS+=",http://download.cirros-cloud.net/daily/20160722/cirros-d160722-x86_64-disk.img"
else
IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz"
IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-disk.img"
fi
fi
if [[ "$IRONIC_TEMPEST_WHOLE_DISK_IMAGE" == "True" ]]; then
@ -579,6 +643,35 @@ function install_ironic {
install_apache_wsgi
fi
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
# Append the nvram configuration to libvirt if it's not present already
if ! sudo grep -q "^nvram" /etc/libvirt/qemu.conf; then
echo "nvram=[\"$UEFI_LOADER_PATH:$UEFI_NVRAM_PATH\"]" | sudo tee -a /etc/libvirt/qemu.conf
fi
# Replace the default virtio PXE ROM in QEMU with an EFI capable
# one. The EFI ROM should work on with both boot modes, Legacy
# BIOS and UEFI.
if is_ubuntu; then
# FIXME(lucasagomes): Enable the multiverse repository by
# default in the image running the gate tests. Also move the
# installation of the ovmf package to files/debs/ironic
sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu $(lsb_release -sc) multiverse"
sudo apt-get update
install_package ovmf
sudo rm /usr/share/qemu/pxe-virtio.rom
sudo ln -s /usr/lib/ipxe/qemu/efi-virtio.rom /usr/share/qemu/pxe-virtio.rom
elif is_fedora; then
sudo rm /usr/share/qemu/pxe-virtio.rom
sudo ln -s /usr/share/ipxe.efi/1af41000.rom /usr/share/qemu/pxe-virtio.rom
fi
# Restart libvirt to the changes to take effect
restart_libvirt
fi
if is_deployed_by_ipmitool && [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
setup_virtualbmc
fi
@ -659,6 +752,25 @@ function configure_ironic_dirs {
cp $IRONIC_PXE_BOOT_IMAGE $IRONIC_TFTPBOOT_DIR
setup_syslinux_modules
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
local uefi_ipxe_boot_file
local uefi_loader
local uefi_nvram
uefi_ipxe_boot_file=$(get_uefi_ipxe_boot_file)
if [ ! -f $uefi_ipxe_boot_file ]; then
die $LINENO "iPXE UEFI boot file $uefi_pxe_bootfile_name not found."
fi
cp $uefi_ipxe_boot_file $IRONIC_TFTPBOOT_DIR
# Copy the OVMF images to libvirt's path
uefi_loader=$(get_uefi_loader)
uefi_nvram=$(get_uefi_nvram)
sudo cp $uefi_loader $UEFI_LOADER_PATH
sudo cp $uefi_nvram $UEFI_NVRAM_PATH
fi
# Create the logs directory when saving the deploy logs to the filesystem
if [ "$IRONIC_DEPLOY_LOGS_STORAGE_BACKEND" = "local"] && [ "$IRONIC_DEPLOY_LOGS_COLLECT" != "never" ]; then
sudo install -d -o $STACK_USER $IRONIC_DEPLOY_LOGS_LOCAL_PATH
@ -905,9 +1017,12 @@ function configure_ironic_conductor {
if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then
local pxebin
pxebin=`basename $IRONIC_PXE_BOOT_IMAGE`
uefipxebin=`basename $(get_uefi_ipxe_boot_file)`
iniset $IRONIC_CONF_FILE pxe ipxe_enabled True
iniset $IRONIC_CONF_FILE pxe pxe_config_template '\$pybasedir/drivers/modules/ipxe_config.template'
iniset $IRONIC_CONF_FILE pxe pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
iniset $IRONIC_CONF_FILE pxe pxe_bootfile_name $pxebin
iniset $IRONIC_CONF_FILE pxe uefi_pxe_config_template '$pybasedir/drivers/modules/ipxe_config.template'
iniset $IRONIC_CONF_FILE pxe uefi_pxe_bootfile_name $uefipxebin
iniset $IRONIC_CONF_FILE deploy http_root $IRONIC_HTTP_DIR
iniset $IRONIC_CONF_FILE deploy http_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT"
if [[ "$IRONIC_IPXE_USE_SWIFT" == "True" ]]; then
@ -1100,8 +1215,6 @@ function create_ovs_taps {
}
function setup_qemu_log_hook {
local libvirt_service_name
# Make sure the libvirt hooks directory exist
sudo mkdir -p $IRONIC_LIBVIRT_HOOKS_PATH
@ -1112,13 +1225,7 @@ function setup_qemu_log_hook {
s|%LOG_DIR%|$IRONIC_VM_LOG_DIR|g;
" -i $IRONIC_LIBVIRT_HOOKS_PATH/qemu
# Restart the libvirt daemon
libvirt_service_name="libvirt-bin"
if is_fedora; then
libvirt_service_name="libvirtd"
fi
restart_service $libvirt_service_name
restart_libvirt
}
function create_bridge_and_vms {
@ -1143,6 +1250,10 @@ function create_bridge_and_vms {
fi
vm_opts+=" -E $IRONIC_VM_ENGINE"
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
vm_opts+=" -L $UEFI_LOADER_PATH -N $UEFI_NVRAM_PATH"
fi
for vm_name in $(_ironic_bm_vm_names); do
sudo -E su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/create-node.sh -n $vm_name \
-c $IRONIC_VM_SPECS_CPU -m $IRONIC_VM_SPECS_RAM -d $IRONIC_VM_SPECS_DISK \
@ -1252,7 +1363,13 @@ function enroll_nodes {
local total_nodes=0
local total_cpus=0
while read hardware_info; do
local node_capabilities=""
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
node_capabilities+=" -p capabilities=boot_mode:uefi"
fi
if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
local mac_address
mac_address=$(echo $hardware_info | awk '{print $1}')
@ -1330,10 +1447,15 @@ function enroll_nodes {
if [[ "$dynamic_allocation" == "True" ]]; then
node_options+=" -i dynamic_allocation=$dynamic_allocation"
fi
node_options+=" -p capabilities="
node_options+="server_hardware_type_uri:$server_hardware_type_uri,"
node_options+="enclosure_group_uri:$enclosure_group_uri,"
node_options+="server_profile_template_uri:$server_profile_template_uri"
if [[ "$node_capabilities" ]]; then
node_capabilities+=","
else
node_capabilities+=" -p capabilities="
fi
node_capabilities+="server_hardware_type_uri:$server_hardware_type_uri,"
node_capabilities+="enclosure_group_uri:$enclosure_group_uri,"
node_capabilities+="server_profile_template_uri:$server_profile_template_uri"
elif is_deployed_by_ilo; then
node_options+=" -i ilo_address=$bmc_address -i ilo_password=$bmc_passwd\
-i ilo_username=$bmc_username"
@ -1362,6 +1484,7 @@ function enroll_nodes {
-p memory_mb=$ironic_node_ram\
-p local_gb=$ironic_node_disk\
-p cpu_arch=$ironic_node_arch \
$node_capabilities \
$node_options \
| grep " uuid " | get_field 2)
@ -1398,6 +1521,10 @@ function enroll_nodes {
openstack flavor create --ephemeral $ironic_ephemeral_disk --ram $ironic_node_ram --disk $adjusted_disk --vcpus $ironic_node_cpu baremetal
openstack flavor set baremetal --property "cpu_arch"="$ironic_node_arch"
if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then
openstack flavor set baremetal --property "capabilities:boot_mode"="uefi"
fi
# NOTE(dtantsur): sometimes nova compute fails to start with ironic due
# to keystone restarting and not being able to authenticate us.
# Restart it just to be sure (and avoid gate problems like bug 1537076)