#!/bin/bash # vim: set et ts=4 sw=4 ft=sh : # DRBDMANAGE_DBUS_AUTH_FILE=/etc/dbus-1/system.d/org.drbd.drbdmanaged-stack.conf DRBDBASEURL=http://openstack-ci-pkgs.linbit.com/packages/005/trusty function pre_install_drbd_devstack { # Install OS packages, if necessary if [[ ! -d "${FILES:?FILES not set yet}" ]]; then mkdir "${FILES}" fi packages=( drbd-utils_8.9.6+linbit-1_amd64.deb drbd8-utils_8.9.6+linbit-1_amd64.deb drbd-dkms_9.0.1+linbit-1_all.deb python-drbdmanage_0.93-3_all.deb ) # get packages for p in "${packages[@]}"; do if [[ ! -f "${FILES}/${p}" ]]; then # If there are newer packages, change the download number here. wget "$DRBDBASEURL/$p" -O "${FILES}/${p}" fi done # install packages sudo apt-get update sudo apt-get install --yes debhelper python-dbus dbus \ lvm2 thin-provisioning-tools for i in "${packages[@]}"; do if [[ -f "${FILES}/${i}" ]]; then echo "installing ${i}" sudo dpkg --force-confnew --install "${FILES}/${i}" || true fi done # now go fetch :) echo echo "installing deps" sudo apt-get install --fix-broken --yes return 0 } function install_drbd_devstack { # Install the service. # Write DRBDmanage configuration; # use the single-thinpool driver for these tests. sudo sed -i "s/^drbdctrl-vg\s*=.*/drbdctrl-vg = ${DRBD_DRBDCTRL_VG}/g" \ /etc/drbdmanaged.cfg echo " [LOCAL] storage-plugin = drbdmanage.storage.lvm_thinlv.LvmThinLv force=1 [Plugin:ThinLV] volume-group = $DRBD_DATA_VG pool-name = drbdthinpool " | sudo tee /etc/drbdmanaged.cfg # allow the stack user access to drbdmanage sudo tee "$DRBDMANAGE_DBUS_AUTH_FILE" > /dev/null << "EOF" EOF # done. } function _find_lo_for_dev { sudo losetup -a | grep "$1" } function _drbd_make_vg { local vg_name="${1:?No VG name given}" local vg_size="$2" local vg_lo_dev="$3" local vg_dev="/dev/${vg_lo_dev}" # If the VG exists, there's nothing left to do. if sudo vgdisplay | grep -q "${vg_name}" ; then return fi # if the file exists, don't destroy it... if [[ ! -f "${FILES}/${vg_name}" ]]; then sudo truncate -s "${vg_size}" "${FILES}/${vg_name}" fi # if the loop device is present, don't recreate it... if [[ ! -e "${vg_dev}" ]]; then local vg_lo_minor="$(echo "${vg_lo_dev}" | sed 's/loop//g')" sudo mknod -m 660 "${vg_dev}" b 7 "${vg_lo_minor}" fi # if the file is already assigned a loop device, don't reassign if ! _find_lo_for_dev "${vg_lo_dev}" | grep -q "${vg_name}" ; then sudo losetup "${vg_dev}" "${FILES}/${vg_name}" fi local lvm_cfg="devices { global_filter=[ 'a|${vg_lo_dev}|' ] }" # # if the lvm.conf already accepts the loop device, don't insert it again # if ! sudo grep -q "${vg_lo_dev}" /etc/lvm/lvm.conf ; then # sudo sed -i.drbdctrl-bak "s/global_filter = \[ /global_filter = \[ \"a|${vg_lo_dev}|\", /g" /etc/lvm/lvm.conf # fi # if theres already a pv signature, don't try to recreate if ! sudo pvdisplay | grep -q "${vg_lo_dev}" ; then sudo pvscan --config "${lvm_cfg}" if sudo pvdisplay | grep -q "${vg_lo_dev}" ; then sudo pvcreate --config "${lvm_cfg}" "${vg_dev}" fi fi # if theres already a vg, don't try to recreate if ! sudo vgdisplay | grep -q "${vg_name}" ; then sudo vgscan if ! sudo vgdisplay | grep -q "${vg_name}" ; then sudo vgcreate --config "${lvm_cfg}" "${vg_name}" "${vg_dev}" fi fi } function _modify_udev_file { local file="$1" local search="$2" local sed_cmd="$3" local path="/lib/udev/rules.d/${file}" if [[ -f "$path" ]] && ! grep "${search}" "$path"; then sudo sed -i "${sed_cmd}" "$path" fi } function _this_is_the_initial_node { [[ -z "$SERVICE_HOST" || "$SERVICE_HOST" == "127.0.0.1" || "$SERVICE_HOST" == "$HOST_IP" ]] } function configure_drbd_devstack { # Configure the service. # This gets called before starting the c-vol service; the next callback, # init_drbd_devstack, is too late for that, so we need to make DRBDmanage # operational here. local be_name="${1:-drbdmanage}" # Initialize and start the service. # need to setup loopback device(s) for DRBD _drbd_make_vg "${DRBD_DRBDCTRL_VG:?DRBD_DRBDCTRL_VG is not set}" \ "${DRBD_DRBDCTRL_VG_SZ}" "${DRBD_DRBDCTRL_LODEV}" # Do the same thing for the DATA volume group _drbd_make_vg "${DRBD_DATA_VG:?DRBD_DATA_VG is not set}" \ "${DRBD_DATA_VG_SZ}" "${DRBD_DATA_LODEV}" local vg_size=$(LC_ALL=C sudo vgdisplay --columns --units M \ --noheadings -o vg_free --nosuffix "${DRBD_DATA_VG}") # No quotes, so that the whitespace around the number gets eaten by the shell local thinpool_size=$( echo $vg_size \* 30 / 32 - 64 | bc ) if ! sudo lvdisplay "${DRBD_DATA_VG}/drbdthinpool" ; then sudo /sbin/lvcreate -L "${thinpool_size}"M -T "${DRBD_DATA_VG}/drbdthinpool" fi # Deactivate udev calling blkid etc. on the DRBD backend devices - that is # neither needed nor wanted, because blkid having the device open can race # with DRBD attaching. # This will result in a message like # kernel: [...] drbd CV_...: drbdX: open("/dev/...") failed with -16 # which means EBUSY _modify_udev_file 60-persistent-storage-dm.rules \ 'ENV{DM_NAME}=="'"${DRBD_DATA_VG}"'-CV_' \ 's:DM_SUSPENDED.*=="1",.*GOTO="\(.*\)":&\nENV{DM_NAME}=="'"${DRBD_DATA_VG}"'-CV_*", GOTO="\1"\n:' _modify_udev_file 80-btrfs-lvm.rules \ 'ENV{DM_NAME}=="'"${DRBD_DATA_VG}"'-CV_' \ 's:SUBSYSTEM.="block",.*GOTO="\(.*\)":&\nENV{DM_NAME}=="'"${DRBD_DATA_VG}"'-CV_*", GOTO="\1"\n:' # The same can happen to the DRBDmanage control volume, too, of course! _modify_udev_file 60-persistent-storage-dm.rules \ 'ENV{DM_NAME}=="'"${DRBD_DRBDCTRL_VG}"'-.drbdctrl' \ 's:DM_SUSPENDED.*=="1",.*GOTO="\(.*\)":&\nENV{DM_NAME}=="'"${DRBD_DRBDCTRL_VG}"'-.drbdctrl", GOTO="\1"\n:' _modify_udev_file 80-btrfs-lvm.rules \ 'ENV{DM_NAME}=="'"${DRBD_DRBDCTRL_VG}"'-.drbdctrl' \ 's:SUBSYSTEM.="block",.*GOTO="\(.*\)":&\nENV{DM_NAME}=="'"${DRBD_DRBDCTRL_VG}"'-.drbdctrl", GOTO="\1"\n:' # drbdmanage modii: --no-control-volume --no-storage --no-autojoin no_stor="${CINDER_DRBD_NO_STORAGE:+--no-storage}" # initialize drbdmanage if _this_is_the_initial_node ; then # No quotes, so that it can expand to an empty string (and get ignored), too. sudo drbdmanage init --quiet $no_stor else # Do we want $HOST_IP, or a possibly different one that should be reachable by the SERVICE_HOST? # Is the $SERVICE_HOST always a drbdmanage node, or should we go to $CINDER_SERVICE_HOST? # for now some debug output set | grep SERVICE_HOST local my_address="$HOST_IP" if [[ -z "$my_address" ]] ; then # Fallback, in case that script gets called standalone. my_address="$(ip -oneline route get "$SERVICE_HOST" | \ grep "$SERVICE_HOST" | awk '/src (.*)/ { print $5 }')" fi echo "I am from $my_address" # ;) no_cv="${CINDER_DRBD_NO_CV:+--no-control-volume}" ssh -oBatchMode=yes -oStrictHostKeyChecking=no stack@"$SERVICE_HOST" \ sudo drbdmanage new-node --no-autojoin "$no_cv" "$no_stor" \ --quiet "$HOSTNAME" "$my_address" ssh -oBatchMode=yes -oStrictHostKeyChecking=no stack@"$SERVICE_HOST" \ sudo drbdmanage howto-join "$HOSTNAME" --quiet | sudo bash fi sudo drbdmanage shutdown --quiet sudo drbdmanage debug 'set loglevel=debug' sudo drbdmanage nodes if [[ -n "$CINDER_CONF" && -f "$CINDER_CONF" ]] ; then iniset $CINDER_CONF "$be_name" volume_backend_name "$be_name" local driver=DrbdManageIscsiDriver if [[ -n "$CINDER_DRBD_USE_DRBD_PROTOCOL" ]] ; then driver=DrbdManageDrbdDriver fi iniset $CINDER_CONF "$be_name" volume_driver \ cinder.volume.drivers.drbdmanagedrv.$driver fi } function init_drbd_devstack { true } function shutdown_drbd_devstack { # Shut the service down. # drbdadm down all # drbdmanage shutdown --quiet echo "shutdown drbd devstack" } function cleanup_drbd_devstack { # Cleanup the service. # something like # drbdmanage list-resource --short | xargs -l drbdmanage remove-resource # ??? # drbdmanage resources -m | sed 's/,.*//g' | xargs -l drbdmanage remove-resource --quiet echo "cleanup drbd devstack" } #debug main #source $(dirname '$0')/../settings #pre_install_drbd_devstack #install_drbd_devstack #configure_drbd_devstack #init_drbd_devstack # Tell emacs to use shell-script-mode ## Local variables: ## mode: shell-script ## End: