Skip to content

Instantly share code, notes, and snippets.

@ThinGuy
Created January 16, 2019 18:07
Show Gist options
  • Save ThinGuy/b4e1922d8939653d72eaa1f30712a73b to your computer and use it in GitHub Desktop.
Save ThinGuy/b4e1922d8939653d72eaa1f30712a73b to your computer and use it in GitHub Desktop.
Microcloud with virtip
gen-sa-ip() {
gen-sa-ip_usage() { printf "\nFunction: ${FUNCNAME%_*}\n\nPurpose: Generates a random IP address using the self-assigned range (169.254.0.0-169.254.255.255)\n\n\tUsage: ${FUNCNAME%_*}\n\n" 1>&2;return; }
[[ $1 = '-h' || $1 = '--help' ]] && { ${FUNCNAME}_usage; return; }
printf '169.254.%01d.%01d\n' $((RANDOM%256)) $((RANDOM%256))
}
export -f gen-sa-ip
wrap() {
local DESC="${FUNCNAME}: Like fold, but with indents\n"
[[ $1 = '--desc' ]] && { printf "${DESC}";return; }
wrap_usage() {
printf "${DESC}\n"
printf "\e[2GUsage: ${FUNCNAME%%_*} [-i #] [-w #]\n"
printf "\e[4G -i, --indent NUM\e[20GNumber of spaces to indent (default 0)\n"
printf "\e[4G -w, --wrap NUM\e[20GColumn number to wrap text at (default 80)\n"
printf "\n\e[2GEx:\n"
printf "\e[4G <STDOUT>|${FUNCNAME%%_*} -i 5 -w 75 \n"
}
local INDENT=0
local WRAP=80
ARGS=`getopt -o w:i:h -l wrap:,indent:,help -n ${FUNCNAME} -- "$@"`
eval set -- "$ARGS"
while true ; do
case "$1" in
-i|--indent) local INDENT=${2};shift 2;;
-w|--wrap) local WRAP=${2};shift 2;;
-h|--help) ${FUNCNAME}_usage;return 2;;
--) shift;break;;
esac
done
fold -sw $((${WRAP}-${INDENT}))|sed 's/^./'$(printf "\e[${INDENT}G")'&/g'
}
export -f wrap
ul-msg() {
[[ $1 = '--desc' ]] && { printf "\e[2G${FUNCNAME}: Underlines the provided string with line style, indent, and bold options.\n";return; };
local INDENT= BOLD=
local STYLE=s
local UL=$(printf '\u2501')
ARGS=$(getopt -o dbi: --long double,bold,indent: -- "$@")
eval set -- "$ARGS"
while true; do
case "$1" in
-i | --indent) local INDENT='\e['${2}'G';shift 2;;
-b | --bold) local BOLD='\e[1m';shift 1;;
-d | --double) local STYLE=d;shift 1;;
--) shift;break;;
esac
done
[[ ${STYLE} = d ]] && local UL=$(printf '\u2550') || local UL=$(printf '\u2501')
printf "\n${BOLD}${INDENT}${@}";
local StrLen=$(($(echo ${@}|sed -E -e 's,\x1B\[[0-9;]*[a-zA-Z],,g;s/^[ \t]*|[ \t]*$//g'|wc -c)-2));
[[ ${@} =~ .*\\n$ || ${@} =~ .*\\n.$ ]] || echo;
printf "${BOLD}${INDENT}"
eval printf "%.3s" ${UL}{0..7};printf "\e[0m\n\n"
}
export -f ul-msg
spin-trap() { trap 'tput sgr0;tput cnorm; tput rmcup;eval kill -9 \$spid &>/dev/null;trap - INT TERM EXIT; return 0' INT TERM EXIT; }
export -f spin-trap
spin-trap-clear() { trap - INT TERM EXIT;tput sgr0;tput cnorm;kill -9 \$spid &>/dev/null;return; }
export -f spin-trap-clear
microcloud-tag-cleanup() {
local DESC="${FUNCNAME}: Removes tags that start with a given value from machines that not deployed, also deletes tag if not associated with any machines\n"
microcloud-tag-cleanup_usage() {
printf "\e[2G${DESC}\n"|wrap -i$((2+${#FUNCNAME[1]}))
printf "\e[2GUsage: ${#FUNCNAME[1]} -p <name> [-i <name> ]\n"
printf "\e[5G-p, --prefix\e[20GPerform cleanup on tags that start with provided prefix\n"
printf "\e[5G-i, --ignore\e[20GIgnore tags that start with the the provided prefix\n"
printf "\e[5G-h, --help\e[20GThis message\n"
printf "\n\e[2GEx:\n"
printf "\e[7G${#FUNCNAME[1]} -p east-edge -i east-edge-prod\n"
printf "\e[7GWill perform cleanup on all tags starting with east-edge, except for those that start with east-edge-prod\n"|wrap -i$((7+${#FUNCNAME[1]}))
printf "\n\n"
}
unset PTAG ITAG
ARGS=$(getopt -o p:i:h --long prefix:,ignore:,help,desc -- "$@")
eval set -- "$ARGS"
while true; do
case "$1" in
-p | --prefix) local PTAG=${2};shift 2;;
-i | --ignore) local ITAG=${2};shift 2;;
--desc) printf "\n\e[2G${DESC}\n";return 0;;
-h|--help) ${FUNCNAME}_usage;return 2;;
--) shift;break;;
esac
done
[[ -n $PTAG ]] || { printf "\e[2GNo tag prefix provided\n\n";${FUNCNAME}_usage;return 2; }
[[ -n $PTAG ]] && { printf "\e[6G - Cleaning up tags starting with: ${PTAG}\n"; }
[[ -n $ITAG ]] && { printf "\e[6G - Ignoring tags starting with: ${PTAG}\n"; }
maas 2>/dev/null ${MAAS_PROFILE} machines read|jq 2>/dev/null -r '.[]|"\(.tag_names|to_entries[]|select(.value|startswith("'${PTAG}'")).value) \(select(.status==4).system_id)"'|xargs -n2 -P1 bash -c 'maas 2>/dev/null ${MAAS_PROFILE} tag update-nodes $0 remove=$1|wrap -i 5 -w 80'
if [[ -n $ITAG ]];then
(maas 2>/dev/null ${MAAS_PROFILE} tags read |jq 2>/dev/null -r '.[]|select(.name|startswith("'${PTAG}'"))|select(.name|startswith("'${ITAG}'")|not).name')|(xargs -n1 -P0 bash -c '[[ -n $0 ]] && printf "$0 $(maas 2>/dev/null ${MAAS_PROFILE} tag nodes $0|jq '"'"'length==0'"'"')\n"|sed /false/d'|[[ -n $1 && -n $2 ]] && xargs -n2 -P1 bash -c 'printf -- "\e[3G - Deleting tag $0 (no machines assigned)\n";maas 2>/dev/null ${MAAS_PROFILE} tag delete $0|wrap -i 5 -w 80' )
else
(maas 2>/dev/null ${MAAS_PROFILE} tags read |jq 2>/dev/null -r '.[]|select(.name|startswith("'${PTAG}'")).name')|(xargs -n1 -P0 bash -c '[[ -n $0 ]] && printf "$0 $(maas 2>/dev/null ${MAAS_PROFILE} tag nodes $0|jq '"'"'length==0'"'"')\n"|sed /false/d'|[[ -n $1 && -n $2 ]] && xargs -n2 -P1 bash -c 'printf -- "\e[3G - Deleting tag $0 (no machines assigned)\n";maas 2>/dev/null ${MAAS_PROFILE} tag delete $|wrap -i 5 -w 80' )
fi
}
export -f microcloud-tag-cleanup
wait-pods-ready() {
local DESC="${FUNCNAME}: Waits in back until Pod hosts are deployed then performs final configuration \n"
wait-pods-ready_usage() {
printf "\e[2G${DESC}\n"|wrap -i $((2+${#FUNCNAME[1]}))
printf "\e[2GUsage: ${FUNCNAME[1]} -c <cpu overcommit> -m <memory overcommit> hostname:system_id pair (multiple pairs allowed)\n"
printf "\e[5G-c|--cpu-ocr\e[20GConfigure pods with given cpu overcommit ratio (Min:1.0 Max:10)\n\e[20Recommed Value: <= 10\n\n"
printf "\e[5G-m|--mem-ocr\e[20GConfigure pods with given memory overcommit ratio (Min:1.0 Max:10)\n\e[20Recommed Value: <= 1.5\n\n"
printf "\e[5G-t|--tag\e[20GMachines with this tag will be processes\n\e[20Recommed Value: <= 1.5\n\n"
printf "\e[5G-h, --help\e[20GThis message\n"
printf "\n\e[2GEx:\n"
printf "\e[7G${FUNCNAME} -c 10 -i 1.25 -t microcloud-kvm-xzypdq\n"|wrap -i$((7+${#FUNCNAME[1]}))
printf "\e[7GWill wait until all the machines associated with the give tag are in deployed state\n"
printf "\e[7Gthen will configure the cpu and memory overcommit.\n\m"
printf "\e[7GUsing the example values, 56 core/512 GiB RAM will have virtual 560 Cores and allow memory ballooning up to 640 GiB\n"|wrap -i$((7+${#FUNCNAME[1]}))
printf "\n\n"
}
ARGS=$(getopt -o c:m:t:hd --long tag:,cpu-ocr:,mem-ocr:,help,desc -- "$@")
eval set -- "$ARGS"
while true; do
case "$1" in
-c|-cpu-ocr) local CPU_OCR=${2};shift 2;;
-m|--mem-ocr) local MEM_OCR=${2};shift 2;;
-t|--tag) local TAG=${2};shift 2;;
--) shift;break;;
esac
done
#Remaining args are processed as hostname/system_id value pair. They should be presented in format of "hostname:system_id"
local -a TAGGED_MACHINES=($(maas admin tag nodes ${TAG}|jq -r '.[]|"\(.hostname):\(.system_id)"'))
[[ -z ${CPU_OCR} ]] && local CPU_OCR=1
[[ -z ${MEM_OCR} ]] && local MEM_OCR=1
# Check for integer and use bc to check ge/le of integers due to possible decimal points
[[ ${CPU_OCR} =~ ^[0-9]+[\.][0-9]+$|^[0-9]+ ]] || { printf "Expected a postive integer for CPU overcommit. Setting to 10\n";local CPU_OC=10; }
[[ ${MEM_OCR} =~ ^[0-9]+[\.][0-9]+$|^[0-9]+ ]] || { printf "Expected a positive integer for Memory overcommit. Setting to a safe 1.5\n";local MEM_OCR=1.5; }
[[ $(bc -l <<< "${CPU_OCR} <= 10") -eq 1 ]] || { printf "Maximum CPU overcommit is 10\n. Setting safe value of 4\n";local CPU_OC=4; }
[[ $(bc -l <<< "${MEM_OCR} <= 10") -eq 1 ]] || { printf "Maximum Memory overcommit is 10\n. Setting safe value of 1.25\n";local MEM_OCR=1.25; }
[[ $(bc -l <<< "${CPU_OCR} >= 1") -eq 1 ]] || { printf "Minimum CPU overcommit is 1 (no-overcommit). Setting to 1.\n";local CPU_OC=1; }
[[ $(bc -l <<< "${MEM_OCR} >= 1") -eq 1 ]] || { printf "Minimum Memory overcommit is 1 (no-overcommit). Setting to 1.\n";local MEM_OCR=1; }
local -a INSTALLED_MACHINES=($(sudo -u postgres psql -F":" --no-align -P pager=off -t maasdb -c "SELECT hostname,system_id from maasserver_node WHERE system_id SIMILAR TO '%($(printf '%s\n' ${TAGGED_MACHINES[@]##*:}|paste -sd\|))%' and status = 6 ORDER BY hostname"))
MSG="Waiting for ${#TAGGED_MACHINES[@]} machines ($(printf "%s\n" ${TAGGED_MACHINES[@]%%:*}|sort -uV|paste -sd,)) to finish deploying"
while [[ -n $(maas admin tag nodes ${TAG}|jq -r '.[].status_name'|grep -v Deployed) ]];do
MSG="Waiting for ${#TAGGED_MACHINES[@]} machines ($(maas admin tag nodes ${TAG}|jq -r '.[].hostname'|paste -sd,)) to finish deploying"
printf "${MSG}"
for i in {1..3..1};do
printf '\e[1m%0.1s\e[0m' .${i}
sleep .5
done
printf "\r${MSG}\e[K\r"
sleep 1
done
printf "\nInstallation Complete!Setting CPU and Memory over commit ratios on ($(printf "%s\n" ${TAGGED_MACHINES[@]%%:*}|sort -uV|paste -sd,))\n\n";sleep 1
spin-trap
query-pods() {
tput civis
declare -ag POD_ELEMENT_L1=('Pod Name' 'Pod ID' 'Hostname' 'System ID' 'Cores' 'CPU RO' 'CPU (GHz)' ' Mem (GiB)' 'Memory RO' 'Storage (GB)' 'Storage ID' 'Tags' 'Power Addr')
declare -ag POD_ELEMENT_L2=("$(printf '\u200A')" "$(printf '\u200A')" ' ' "$(printf '\u200A')" ' p/v' "$(printf '\u200A')" "$(printf '\u200A')" ' p/v' "$(printf '\u200A')" "$(printf '\u200A')" "$(printf '\u200A')" "$(printf '\u200A')" "$(printf '\u200A')")
export PI=$(printf "%s\n" "${POD_ELEMENT_L1[@]}"|paste -sd'|';printf "%s\n" "${POD_ELEMENT_L2[@]}"|paste -sd'|'; sudo -u postgres psql -F"|" --no-align -P pager=off -t maasdb -c "SELECT
bmc.name,bmc.id,hostname,system_id,concat_ws('/',bmc.cores,(bmc.cores*bmc.cpu_over_commit_ratio)),bmc.cpu_over_commit_ratio,bmc.cpu_speed::TEXT,concat_ws('/',round(bmc.memory/2^10),round((bmc.memory/2^10)*bmc.memory_over_commit_ratio)),bmc.cpu_over_commit_ratio,round(bmc.local_storage/2^30),
bmc.default_storage_pool_id,bmc.tags,bmc.power_parameters
FROM maasserver_bmc bmc LEFT JOIN maasserver_node node ON bmc.name = node.hostname WHERE cores > 0 and node.system_id SIMILAR TO '%($(printf '%s\n' ${INSTALLED_MACHINES[@]##*:}|paste -sd"|"))%' ORDER BY node.hostname"|sed -Er 's/."power_pass": .* |"power_address":/ /g;s/[",:]|\{ |.}$| //g;s/ |\| /|/g')
declare -ag PL=($(echo "${PI}"|awk -F"|" '{ for (i=1; i<=NF; i++) { max[i] = length($i) > max[i] ? length($i) : max[i] ;ncols = i > ncols ? i : ncols }} END { for (col=1; col <= ncols; col++) {printf "%d\n", max[col]}}'))
echo "$PI"|sed '3i'$(for l in ${PL[@]};do eval printf '%0.3s' "${LS}{0..${l}}";echo;done|paste -sd'|')''|column -nexts'|'|sed '1,3s/^.*$/'$(printf "\e[1;38;2;255;255;255m&\e[0m")'/;2s/^.*$/'$(printf "\e[38;2;175;175;175m&\e[0m")'/'
}
local -a POD_IDS=($(printf '%s\n' ${INSTALLED_MACHINES[@]##*:}|xargs -n1 -P1 bash -c 'maas ${MAAS_PROFILE} pods read|jq -r '"'"'.[]|select(.host.system_id=="'"'"'$0'"'"'").id'"'"''))
SET_OC=$(printf "%s\n" ${POD_IDS[@]}|xargs -n1 -P1 bash -c 'maas ${MAAS_PROFILE} pod update $0 memory_over_commit_ratio='${MEM_OCR}' cpu_over_commit_ratio='${CPU_OCR}'') &
export spid=$!
while kill -0 $spid 2>/dev/null;do
printf '\e[s'
query-pods
printf '\e[u'
sleep .25
done
wait $spid
spin-trap-clear
}
export -f wait-pods-ready
create-lxd-microcloud() {
local DESC="${FUNCNAME}: Deploy a LXD Cluster via MAAS command line"
#ENV Setttings
local CI_TZ='America/Los_Angeles'
local CI_LC='en_US.UTF-8'
#Package Settings
local CI_PKG_UPG=true
local CI_PKG_UPD=true
# Test for Ubuntu Country Mirror based on Locale
local CI_TC=${CI_LC:3:2}
if [[ -n ${CI_TC} && $(curl -slSL -w %{http_code} -o /dev/null ${CI_TC,,}.archive.ubuntu.com) -eq 200 ]];then
local CI_CC=${CI_TC}
local CI_APT_MIRROR=${CI_CC,,}.archive.ubuntu.com
else
local CI_APT_MIRROR=archive.ubuntu.com
fi
#Generic KeepAliveD Settings for a Cluster VIP using Keepalived
local VIP_VRRP_CIDR=
local VIP_VRRP_PASS="$(cat /dev/urandom|tr -dc 'a-z0-9'|fold -w6|head -n1)"
local VIP_VRRP_INSTANCE="MICROCLOUD-VIP"
local VIP_VRRP_ENABLE=false
#Defaults if not chosen
local ENABLE_GPU=false
local BASE_TAG="microcloud-lxd"
local STORAGE_POOL_DEVICE=
local STORAGE_POOL_TYPE=file
#Enforce 3 node min
local ENFORE_HA=true
local -a CI_PKG_LIST=(
bridge-utils
build-essential
jq
prips
squashfuse
unzip
zfsutils-linux
keepalived
)
create-lxd-microcloud_usage() {
printf "\n\e[2G${DESC}\n\n"
printf "\e[2G\e[1mUsage\e[0m: ${FUNCNAME%%_*} [-n <count>] [-t <tag>] [-d <distro>] ( -g gpu-passthrough support ) (-p storage-pool block device)\n\n"
printf "\e[4G -n, --count\e[20GNumber of nodes\n"
printf "\e[4G -t, --tag \e[20GExisting tag to use when selecting nodes\n"
printf "\e[4G -d, --distro\e[20GName of Ubuntu Distro (Default: bionic)\n"
printf "\e[4G -p, --pool-device\e[20GBlock device to use for Storage Pool (Optional: default uses file method)\n"
printf "\e[4G -g, --gpu\e[20GEnable GPU passthrough support\n"
printf "\e[4G -H, --ha\e[20GEnsure n+2 servers are available (default: True)\n"
printf "\e[4G -N, --no-ha\e[20GAllow less than n+2 servers in a cloud (default: False)\n"
printf "\e[4G -T, --cloud-name\e[20Name of cloud for tagging purposes (default: ${BASE_TAG}-xxxxxx)\n"
printf "\e[4G -c, --comment\e[20Comment to apply to tags related to the microcloud\n"
printf "\e[4G -v, --vrrp\e[20Enable a VIP managed by KeepAliveD (default: false)\n"
printf "\e[4G -V, --VIP\e[20IP Address to use for the VIP\n"
printf "\e[4G -i, --instance\e[20KeepAliveD instance name for VRRP_VIP service (default: MICROCLOUD_VIP)\n"
printf "\e[4G -P, --vrrp-password\e[20Password used by KeepAliveD to track state (default: Random 6 digit alpha numeric\n"
printf "\e[4G -h, --help\e[20GThis message\n"
printf "\n\n"
}
ARGS=$(getopt -o n:c:t:d:p:C:T:P:v:o:gdhHNV -l count:,tag:,distro:,pool-device:,comment:,cloud-name:.vip:,vrrp-password:,gpu,help,desc,enable-vrrp,ha,no-ha -n ${FUNCNAME} -- "$@")
eval set -- "$ARGS"
while true ; do
case "$1" in
-n|-c|--count) local COUNT=${2};shift 2;;
-t|--tag) local TAG=${2};local TAG=${TAG,,};shift 2;;
-d|--distro) local DISTRO=${2};local DISTRO=${DISTRO,,};shift 2;;
-p|--pool-device) local STORAGE_POOL_DEVICE=${2};local STORAGE_POOL_DEVICE=${STORAGE_POOL_DEVICE,,};local STORAGE_POOL_TYPE=device;shift 2;;
-g|--gpu) local ENABLE_GPU=true;shift 1;;
-H|--ha) local ENFORCE_HA=true;shift 1;;
-N|--no-ha) local ENFORCE_HA=false;shift 1;;
-C|--comment) local CLOUD_COMMENT=${2};shift 2;;
-T|--cloud-name) local CLOUD_NAME=${2};shift 2;;
-V|--enable-vrrp) local VIP_VRRP_ENABLE=true;shift 1;;
-v|--vip) local VIP_VRRP_CIDR=${2};shift 2;;
-i|--vrrp-instance) local VIP_VRRP_INSTANCE=${2};shift 2;;
-P|--vrrp-password) local VIP_VRRP_PASS=${2};shift 2;;
--desc) printf "\n\e[2G${DESC}\n";return 2;;
-h|--help) ${FUNCNAME}_usage;return 2;;
--) shift;break;;
esac
done
command -v maas &>/dev/null || { printf "\n\n\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0m\e[38;2;0;255;0m maas-cli \e[0m\e[1m2.5+\e[0m is required for this demo.\n\e[9GPlease install and configure version 2.5 or later\n\n";return 1; }
[[ $(dpkg-query -s maas|grep -oP '(?<=Version: )[^?]{3}'|sed 's/\.//') -lt 25 ]] && { printf "\n\n\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mMAAS \e[38;2;0;255;0m2.5\e[0m\e[1m+\e[0m is required for this demo.\n\e[9GYou are running version \e[38;2;255;255;0m$(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m\n\n";return 1; }
command -v jq &>/dev/null || { printf "Installing pre-req utils...";sudo apt install jq -yqq|tee 1>/dev/null /tmp/${FUNCNAME}.log; }
local OK='\u00A0\e[38;2;0;255;0m\u2713\e[0m\u00A0\n'
local FAILED='\u00A0\e[38;2;255;0;0m\u2718\e[0m\u00A0\n'
local ERR_MSG='\e[0m\e[1;38;2;255;255;255m\e[1;48;2;255;0;0m***\ufeffERROR\ufeff***\e[0m'
local WRN_MSG='\e[0m\e[1;38;2;255;255;255m\e[1;48;2;255;255;0m***\ufeffERROR\ufeff***\e[0m'
[[ -z ${MAAS_PROFILE} ]] && { read -srp "$(printf "Please enter your MAAS profile name: ")" MAAS_PROFILE_INPUT;local MAAS_PROFILE=$MAAS_PROFILE_INPUT; }
printf -- "\n\e[1mMicro-cloud Demo - LXD\e[0m\n\n"
printf -- "\e[3G- Provisioning by \e[1mMAAS $(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m${OK}\n"
printf -- "\e[6G- Powered by \e[1m$(lsb_release -ds)\e[0m${OK}\n"
printf -- "\e[3G- Featuring \e[1mLXD $(snap info lxd|awk '/- </{print $2}') with clustering\e[0m${OK}\n"
[[ ${ENABLE_GPU} = true ]] && printf -- "\e[3G- \e[1m GPGPU\e[0m Passthrough enabled\e[0m${OK}\n"
#Validation and error handling
local -a VALID_TAGS=($(maas ${MAAS_PROFILE} tags read|jq -r '.[].name'))
local -a VALID_DISTROS=($(maas ${MAAS_PROFILE} boot-resources read|jq -r '.[]|"\(select((.name|startswith("grub")|not) and (.name|startswith("ubuntu")) and (.name|startswith("pxe")|not)).name|sub("ubuntu/"; ""))"'|sort -uV))
if [[ ${VIP_VRRP_ENABLE} = true ]];then
printf -- "\e[3GSimple Virtual IP Address Failover enabled\n"
[[ -n ${VIP_VRRP_CIDR} ]] && { printf -- "\e[5G- Virtual IP: ${VIP_VRRP_CIDR}\n"; } || { local VIP_VRRP_CIDR_=$(gen-sa-ip);printf -- "\e[5G- VIP_VRRP_CIDR: ${VIP_VRRP_CIDR} (auto-generated)\n"; }
[[ -n ${VIP_VRRP_INSTANCE} ]] && { printf -- "\e[5G- VRRP Instance Name: ${VIP_VRRP_INSTANCE}}\n"; } || { local VIP_VRRP_INSTANCE="VIP-$(cat /dev/urandom|tr -dc 'A-Z0-9'|fold -w6|head -n1)";printf -- "\e[5G- VRRP INSTANCE: ${VIP_VRRP_INSTANCE} (auto-generated)\n"; }
[[ -n ${VIP_VRRP_PASS} ]] && { printf -- "\e[5G- VRRP Passwd: ${VIP_VRRP_PASS}\n"; } || { local VIP_VRRP_PASS="$(cat /dev/urandom|tr -dc 'a-z0-9'|fold -w6|head -n1)";printf -- "\e[5G- VRRP Passwd: ${VIP_VRRP_PASS} (auto-generated)\n"; }
fi
# If not a physical disk, set storage pool to use a file
[[ ${STORAGE_POOL_TYPE} = device ]] && { printf "\e[3G- Storage Pool will use block device ${STORAGE_POOL_DEVICE} \n\n"; local STORAGE_POOL_TYPE=device; } || { local STORAGE_POOL_TYPE=file;local STORAGE_POOL_DEVICE="/var/snap/lxd/common/lxd/disks/local.img";printf "\e[3G- Storage Pool on Cluster Hosts will be file-based \n\n"; }
[[ ${COUNT} =~ ^[0-9]+$ ]] || { local COUNT=3;printf "\e[3G- Setting Node count to ${COUNT}\n\n"; }
[[ ${COUNT} =~ ^[0-9]+$ && ${COUNT} -lt 3 ]] && { local COUNT=3;printf "\e[3G- Minimum LXD Cluster node count is ${COUNT}. Setting Node count to ${COUNT}.\n\n"; }
[[ -z ${TAG} ]] && { printf "\e[2GERROR: No tag name given ${TAG}\n\n\e[2GValid tags are:\n";printf "\e[4G- %s\n" ${VALID_TAGS[@]};return 1; }
[[ -n ${TAG} && -n $(grep -P '(^|\s)\K'${TAG}'(?=\s|$)' <<< ${VALID_TAGS[@]}) ]] || { printf "\e[2GERROR: No tags exist named ${TAG}\n\n\e[2GValid tags are:\n";printf "\e[4G- %s\n" ${VALID_TAGS[@]};return 1; }
[[ -n ${TAG} ]] && { printf "\e[3G- Using tag \"${TAG}\" as primary machine constraint\n\n"; }
[[ -n ${DISTRO} ]] || { local DISTRO="bionic"; }
[[ -n ${DISTRO} && -n $(grep -P '(^|\s)\K'${DISTRO}'(?=\s|$)' <<< ${VALID_DISTROS[@]}) ]] || { printf "\e[2GERROR: invalid distro: ${DISTRO}\n\n\e[2GValid distros for LXD Clusters are:\n";printf "\e[4G- %s\n" ${VALID_DISTROS[@]};return 1; }
[[ -n ${DISTRO} ]] && { printf "\e[3G- Setting distro to ${DISTRO}\n\n"; }
printf "\n\e[3G- Gathering values from to use for setting up the lxd-cluster. Please wait..."
#Get values we'll be replacing in lxd-cluster script template
local MAAS_LIST=$(maas list|awk '/'${MAAS_PROFILE}'/')
local MAAS_API=$(echo ${MAAS_LIST}|awk '{print $3}')
local MAAS_IP=$(echo ${MAAS_LIST}|awk -F'(//|:)' '{print $3}')
local MAAS_URL=$(echo ${MAAS_LIST}|awk '{gsub(/\/api.*/,"");print $2}')
local MAAS_SUBNET=$(maas ${MAAS_PROFILE} subnets read|jq -r '.[]|select(.vlan.fabric_id==0).cidr')
local MAAS_DOMAIN=$(maas ${MAAS_PROFILE} domains read|jq -r '.[]|select((.authoritative==true) and .id==0).name')
IFS=$'\n' && declare -ag MAAS_SSH_HOST_KEYS=($(maas ${MAAS_PROFILE} sshkeys read|jq -r '.[]|"\(.key)"'))
if [[ -n ${MAAS_API} && -n ${MAAS_URL} && -n ${MAAS_SUBNET} && -n ${MAAS_IP} && -n ${MAAS_DOMAIN} ]];then
printf "${OK}"
else
printf "${FAILED}\e[2GThere was an issue gathering lxd-cluster values from maas. Make you are running this while logged into the maas-cli. Quitting\n\n"
echo
for v in API URL SUBNET IP DOMAIN;do eval echo MAAS_$v=\$MAAS_$v;done
echo
return 1
fi
[[ ${COUNT} -eq 1 ]] && W= || W=s
if [[ ${STORAGE_POOL_TYPE} = device ]];then
printf "\n\e[3G- Finding ${COUNT} machine${W} :\n\e[5G- Marked as \"Ready\"\n\e[5G- Tagged with \"${TAG}\"\n"
local READY_TAGGED_MACHINES=($(maas ${MAAS_PROFILE} machines read|jq -r '.[]|select(.physicalblockdevice_set[].name|contains("'${STORAGE_POOL_DEVICE##*/}'"))|select((.tag_names[]|contains("'"${TAG}"'")) and .status == 4)|"\(.hostname):\(.system_id)"'|head -n${COUNT}|sort -V))
[[ ${#READY_TAGGED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not find enough machines to create a LXD Cluster.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#READY_TAGGED_MACHINES[@]}\n\n";return 1; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#READY_TAGGED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machines with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#READY_TAGGED_MACHINES[@]}
else
printf "\n\e[3G- Finding ${COUNT} machine${W} :\n\e[5G- Marked as \"Ready\"\e[5G- Tagged with \"${TAG}\"\n\e[5G- Has physical disk named ${STORAGE_POOL_DEVICE}\n"
local -a READY_TAGGED_MACHINES=($(maas ${MAAS_PROFILE} machines read|jq -r '.[]|select((.tag_names[]|contains("'"${TAG}"'")) and .status == 4)|"\(.hostname):\(.system_id)"'|head -n${COUNT}|sort -V))
[[ ${#READY_TAGGED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not find enough machines to create a LXD Cluster.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#READY_TAGGED_MACHINES[@]}\n\n";return 1; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#READY_TAGGED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#READY_TAGGED_MACHINES[@]}
fi
printf "\n\e[3G- Allocating the following Host${W} to the LXD Pods:\n"
printf -- "\e[6G - %s\n" ${READY_TAGGED_MACHINES[@]}|sed 's/:/ \(/g;s/.$/&\)/g';echo
local -a ALLOCATED_MACHINES=($(printf "%s\n" ${READY_TAGGED_MACHINES[@]##*:}|xargs -I{} -n1 -P0 maas ${MAAS_PROFILE} machines allocate system_id={}|jq -r '"\(.hostname):\(.system_id)"'|sort -uV))
[[ ${#ALLOCATED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not allocate enough machines to create a LXD Cluster.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#ALLOCATED_MACHINES[@]}\n\n";return 1; }
[[ ${#ALLOCATED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#ALLOCATED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only allocate ${#ALLOCATED_MACHINES[@]} machine${W}. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#ALLOCATED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only allocate ${#ALLOCATED_MACHINES[@]} machines. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#ALLOCATED_MACHINES[@]}
# The first element in the array will be the Cluster Primary
#
local CLOUD_PRIMARY=${ALLOCATED_MACHINES[0]%%:*}
printf "\e[3G- First cluster member will be ${CLOUD_PRIMARY}\n\n"
# Preconfigure the system keys in /etc/ssh so we can setup the cluster without any prompts or exchanging ssh keys
local -a KEY_TYPES=(rsa dsa ecdsa)
printf "\e[3G- Creating pre-generated ssh private keys \($(printf '%s\n' ${KEY_TYPES[@]}|paste -sd',') \) for the cluster\n"
xargs -n1 -P0 bash -c 'ssh-keygen &>/dev/null -t $0 -f /tmp/lxd_cluster_ssh_host_$0_key -P ""' <<< ${KEY_TYPES[@]}
local SSH_HOST_KEYS="$(printf "\nssh_keys:\n";xargs -n1 -P1 bash -c 'printf " $0_private: |\n$(cat /tmp/lxd_cluster_ssh_host_$0_key|sed '"'"'s/^.*$/ &/g'"'"')\n\n $0_public: $(cat /tmp/lxd_cluster_ssh_host_$0_key.pub)\n\n"' <<< ${KEY_TYPES[@]})"
#Remove preseeded ssh keys from local machine
printf "\e[5G- Deleting local copies of pregenerated keys \n\n"
rm -rf /tmp/lxd_cluster_ssh_host* /tmp/lxd_cluster_user_ssh*
# Get SSH Public keys from local accounts and maas. Remove duplicates
printf "\e[3G- Looking for public keys to add to LXD profiles on Cluster\n"
local SSH_PUB_KEYS=$((if [[ -n $(find 2>/dev/null ~/.ssh -iname "*.pub") ]];then
echo ssh_authorized_keys:
find 2>/dev/null ~/.ssh -iname "*.pub"|xargs -n1 -P1 bash -c 'printf -- '"'"' - %s\n'"'"' "$(cat $0)"'
fi
if [[ -n $(command -v maas 2>/dev/null) ]];then
if [[ $(maas 2>/dev/null ${MAAS_PROFILE} sshkeys read|jq 2>/dev/null length) -ge 1 ]];then
echo "ssh_authorized_keys:"
maas 2>/dev/null ${MAAS_PROFILE} sshkeys read|jq 2>/dev/null -r '.[]|"\(.key)"'| \
while IFS= read -r line;do
sed 's/^/ - /g'
done
fi
fi
)|awk '!seen[$0]++')
echo
# Create correct the stanza for disk or file based storage pool
[[ ${STORAGE_POOL_TYPE} = device ]] && local STORAGE_POOL_CONF=$(cat <<EOF
storage_pools:
- config:
source: ${STORAGE_POOL_DEVICE}
description: LXD Storage Pool on ${STORAGE_POOL_DEVICE,,}
name: local
driver: zfs
- config:
size: 100GB
source: /var/snap/lxd/common/lxd/disks/local.img
zfs.pool_name: default
description: File Based LXD Storage Pool
name: default
driver: zfs
EOF
)
[[ ${STORAGE_POOL_TYPE} != device ]] && local STORAGE_POOL_CONF=$(cat <<EOF
storage_pools:
- config:
size: 100GB
source: /var/snap/lxd/common/lxd/disks/local.img
zfs.pool_name: local
description: File Based LXD Storage Pool
name: local
driver: zfs
EOF
)
#Indent yaml for use in LXD preeseed yaml
local LXD_SSH_PUB_KEYS=$(echo;echo "${SSH_PUB_KEYS}"|sed 's/^/ /g')
# Create a string of the Cluster hosts that we can for SSH config files (thus the added asterisk)
# (easier to remove the asterisk in a variable than to add it, so it's added to main variable)
local CLUSTER_HOST_LIST=$(printf "%s*\n" ${ALLOCATED_MACHINES[@]%%:*}|paste -sd" "|sort -uV)
# Create Package List for Cluster hosts
local CI_PACKAGES=$([[ ${#CI_PKG_LIST[@]} -ge 1 ]] && printf "packages: [$(printf '%s\n' ${CI_PKG_LIST[@]}|paste -sd',')]\n")
# xpath auto tags for varius different nVidia GPGPUs
if [[ ${ENABLE_GPU} = true ]];then
printf "\e[3G- Configuring xpath auto-tags for GPGPU Detection at the hardware level in MAAS...\n\n"
NVDA_3D_CONTROLLER_TAG_DEF='//node[@id="display"]/description = "3D controller" and //node[@id="display"]/vendor = "NVDA Corporation" and //node[@id="display"]/product = "NVIDIA Corporation"'
NVDA_3D_CONTROLLER_TAG_COMMENT='xpath auto-tag to prevent nvidia general-purpose GPUs that have been claimed by nouveau or nvidiafb module'
declare -ag NVDA_GPGPU_TESLA_PRODUCTS=(P4 P40 P100 V100 T4)
NVDA_GPGPU_TESLA_PROD_DEF="$(for p in ${NVDA_GPGPU_TESLA_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_TESLA_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Tesla") and '"${NVDA_GPGPU_TESLA_PROD_DEF}"''
NVDA_GPGPU_TESLA_TAG_COMMENT="xpath auto-tag for nVidia Tesla-based general-purpose GPUs"
declare -ag NVDA_GPGPU_QUADRO_PRODUCTS=(K M P2000 P4000 P5000 P6000)
NVDA_GPGPU_QUADRO_PROD_DEF="$(for p in ${NVDA_GPGPU_QUADRO_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_QUADRO_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Quadro") and '"${NVDA_GPGPU_QUADRO_PROD_DEF}"''
NVDA_GPGPU_QUADRO_TAG_COMMENT="xpath auto-tag for nVidia Quadro-based general-purpose GPUs"
declare -ag NVDA_GPGPU_ALL_PRODUCTS=($(printf "%s\n" ${NVDA_GPGPU_TESLA_PRODUCTS[@]} ${NVDA_GPGPU_QUADRO_PRODUCTS[@]}|paste -sd" "))
NVDA_GPGPU_ALL_PROD_DEF="$(for p in ${NVDA_GPGPU_TESLA_PRODUCTS[@]} ${NVDA_GPGPU_QUADRO_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_ALL_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Quadro") or contains(//node[@id="display"]/product,"Tesla") and '"${NVDA_GPGPU_ALL_PROD_DEF}"''
NVDA_GPGPU_ALL_TAG_COMMENT="xpath auto-tag for nVidia Quadro and Tesla-based general-purpose GPUs"
NVDA_GPGPU_ALL_KERNEL_OPTS='nomodeset modprobe.blacklist=nouveau modprobe.blacklist=nvidiafb intel_iommu=on iommu=pt rd.driver.pre=vfio-pci video=efifb:off vfio_iommu_type1.allow_unsafe_interrupts=1'
declare -ag GPGPU_ARR=(NVDA_3D_CONTROLLER NVDA_GPGPU_TESLA NVDA_GPGPU_QUADRO NVDA_GPGPU_ALL)
MAAS_TAGS=$(maas ${MAAS_PROFILE} tags read)
for G in ${GPGPU_ARR[@]};do
if [[ -n $(jq -r '.[]|select(.name=="'${G,,}'").name' <<< ${MAAS_TAGS}) ]];then
printf "\e[5G - Updating xpath auto tag for ${G} products...\n"
maas ${MAAS_PROFILE} tag update ${G,,} name=${G,,} definition=$(eval echo \$${G}_TAG_DEF) comment=$(eval echo \$${G}_TAG_COMMENT)|wrap -i8 -w80
[[ ${G} = NVDA_GPGPU_ALL || ${G} = NVDA_3D_CONTROLLER ]] && maas ${MAAS_PROFILE} tag update ${G,,} name=${G,,} kernel_opts="${NVDA_GPGPU_ALL_KERNEL_OPTS}"|wrap -i8 -w80
printf '\n\n'
else
printf "\e[5G - Creating xpath auto tag for ${G} products...\n\n"
maas ${MAAS_PROFILE} tags create name=${G,,} definition=$(eval echo \$${G}_TAG_DEF) comment=$(eval echo \$${G}_TAG_COMMENT)|wrap -i8 -w80
[[ ${G} = NVDA_GPGPU_ALL || ${G} = NVDA_3D_CONTROLLER ]] && maas ${MAAS_PROFILE} tag update ${G,,} name=${G,,} kernel_opts="${NVDA_GPGPU_ALL_KERNEL_OPTS}"|wrap -i8 -w80
printf '\n\n'
fi
done
fi
#Make LXD Image Script to preseed LXD Clusters image store
printf "\e[3G- Writing LXD Image Copy Script to Cloud-Init file...\n\n"
local LXD_IMAGE_SCRIPT=$(
cat <<EOF|base64 -w0
#!/bin/bash
printf "\e[1mLXD Image Copy Tool\e[0m\n"
#Add ubuntu minimal remotes if they are not defined
printf "\e[2GChecking if ubuntu-minimal repos have been added...\n"
[[ -n \$(/snap/bin/lxc 2>/dev/null remote list|awk '/ubuntu.com\/minimal\/daily/{print $2}') ]] || { printf "\e[2G - Adding ubuntu-minimal-daily repo\n";/snap/bin/lxc remote add ubuntu-min-daily https://cloud-images.ubuntu.com/minimal/daily --protocol simplestreams --public; }
[[ -n \$(/snap/bin/lxc 2>/dev/null remote list|awk '/ubuntu.com\/minimal\/releases/{print $2}') ]] || { printf "\e[2G - Adding ubuntu-minimal-releases repo\n";/snap/bin/lxc remote add ubuntu-min-releases https://cloud-images.ubuntu.com/minimal/releases --protocol simplestreams --public; }
printf "\e[2GCreating array of simplestreams-based remotes\n"
declare -ag REPOS=(\$(/snap/bin/lxc remote list --format=json|jq -r 'to_entries[]|select((.key|startswith("fcb")|not) and .value.Protocol=="simplestreams").key'))
printf "\e[2GCreating array of unique LXD images from ${#REPOS[@]} repos...\n"
declare -ag IMAGES=(\$(xargs -n1 -P0 bash -c '/snap/bin/lxc image list \${0}: a=amd64 --format=json|jq -r '"'"'.[]|select(.aliases!=null)|"'"'"'\$0'"'"':\(.fingerprint|sub("\\\\s.*"; ""))|'"'"'\$0-'"'"'\(.properties.os|ascii_downcase)-\(.properties.release|ascii_downcase)"'"'"'' <<< \${REPOS[@]}|\
sed \
-e 's/ubuntu\(-min-daily\)-ubuntu-\(.*\)/\2\1/' \
-e 's/ubuntu\(-min\)-ubuntu-\(.*\)/\2\1/' \
-e 's/ubuntu\(-daily\)-ubuntu-\(.*\)/\2\1/' \
-e '/images-ubuntu-.*[a-z]$/d' \
-e 's/ubuntu-ubuntu-/ubuntu-r-/g' \
-e 's/ubuntu\(-r\)-\(.*\)/\2\1/' \
-e 's/-daily$/-d/g' \
-e 's/images-//g' \
-e 's/-current//g' \
-e 's/min$/&-r/g'))
printf "\e[2G - Discovered \${#IMAGES[@]} unique LXD OS images\n\n\e[4G - Note:\n\e[6G - aliases that end with \"-r\" are \"release\" builds (aka GA)\n\e[6G - aliases that end with \"-d\" are \"daily\" builds\n\e[2GCommencing downloads...\n\n"
for ((i=0; i<\${#IMAGES[@]}; i++));do printf '%s %s\n' \${IMAGES[i]%%|*} \${IMAGES[i]##*|};done|xargs -n2 -P0 bash -c '/snap/bin/lxc image copy \$0 --alias \$1 --public --auto-update local:'
EOF
)
[[ ${VIP_VRRP_ENABLE} = true ]] && printf "\e[3G- Writing KeepAliveD configuration Script to Cloud-Init file...\n\n"
[[ ${VIP_VRRP_ENABLE} = true ]] && local VIP_VRRP_SCRIPT=$(
cat <<EOS|base64 -w0
#!/bin/bash
#root check
if [[ \$EUID -ne 0 ]]; then
printf '\n\e[1;33mThis script requires admin privileges.\e[0m\e[1;37m Please run via sudo.\e[0m\n\n'
exit 1
fi
if [[ \$(hostname 2>/dev/null -s) = ${CLOUD_PRIMARY} ]];then
cat <<EOM|/etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@\$(hostname -d)
}
notification_email_from \$(hostname -f)
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_instance ${VIP_VRRP_INSTANCE} {
state MASTER
# Specify the network interface to which the virtual address is assigned
interface \$(ip route get ${MAAS_IP}|grep -oP '(?<=dev )[^ ]+')
# The virtual router ID must be unique to each VRRP instance that you define
virtual_router_id 41
# Set the value of priority higher on the master server than on a backup server
priority 200
advert_int 1
authentication {
auth_type PASS
auth_pass ${VIP_VRRP_PASS}
}
virtual_ipaddress {
$VIP_VRRP_CIDR
}
}
EOM
else
cat <<EOB|/etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@\$(hostname -d)
}
notification_email_from \$(hostname -f)
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_instance ${VIP_VRRP_INSTANCE} {
state BACKUP
# Specify the network interface to which the virtual address is assigned
\$(ip route get ${MAAS_IP}|grep -oP '"'"'(?<=dev )[^ ]+'"'"')
virtual_router_id 41
# Set the value of priority lower on the backup server than on the master server
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass ${VIP_VRRP_PASS}
}
virtual_ipaddress {
${VIP_VRRP_CIDR}
}
}
EOB
fi
EOS
)
#Make LXD Cluster Script and convert to base64 to include in cloud-init user-data
printf "\e[3G- Writing LXD Cluster Script to Cloud-Init file...\n\n"
local LXD_CLUSTER_SCRIPT=$(
cat <<EOF|base64 -w0
#!/bin/bash
if [[ \$(hostname 2>/dev/null -s) = ${CLOUD_PRIMARY} ]];then
cat <<EOT|sudo lxd init --preseed
config:
core.https_address: \$(dig +short @${MAAS_IP} \$(hostname -f)):8443
core.trust_password: ubuntu
maas.api.key: ${MAAS_API}
maas.api.url: ${MAAS_URL}
networks:
- config:
ipv4.address: auto
ipv4.nat: 'true'
ipv6.address: auto
ipv6.nat: 'true'
name: lxdbr0
type: bridge
${STORAGE_POOL_CONF}
profiles:
- name: default
description: 'Default LXD Profile'
config:
user.user-data: |
#cloud-config
${LXD_SSH_PUB_KEYS}
devices:
eth0:
name: eth0
nictype: bridged
parent: lxdbr0
type: nic
root:
path: /
pool: local
type: disk
- name: privileged
description: 'Privileged LXD Profile'
config:
linux.kernel_modules: ip_tables,ip6_tables,netlink_diag,nf_nat,overlay
migration.incremental.memory: 'true'
raw.lxc: |-
lxc.cgroup.devices.allow = c 10:237 rwm
lxc.apparmor.profile = unconfined
lxc.cgroup.devices.allow = b 7:* rwm
security.nesting: 'true'
security.privileged: 'true'
user.user-data: |
#cloud-config
${LXD_SSH_PUB_KEYS}
devices:
eth0:
name: eth0
nictype: bridged
parent: lxdbr0
type: nic
root:
path: /
pool: local
type: disk
kvm:
path: /dev/kvm
type: unix-char
mem:
path: /dev/mem
type: unix-char
loop-control:
path: /dev/loop-control
type: unix-char
loop0:
path: /dev/loop0
type: unix-block
loop1:
path: /dev/loop1
type: unix-block
loop2:
path: /dev/loop2
type: unix-block
loop3:
path: /dev/loop3
type: unix-block
loop4:
path: /dev/loop4
type: unix-block
loop5:
path: /dev/loop5
type: unix-block
loop6:
path: /dev/loop6
type: unix-block
loop7:
path: /dev/loop7
type: unix-block
- name: maas
description: 'MAAS LXD Profile'
config:
user.user-data: |
#cloud-config
${LXD_SSH_PUB_KEYS}
devices:
eth0:
maas.subnet.ipv4: ${MAAS_SUBNET}
name: eth0
nictype: bridged
parent: br0
type: nic
root:
path: /
pool: local
type: disk
- name: maas-privileged
description: 'MAAS Privileged LXD Profile'
config:
linux.kernel_modules: ip_tables,ip6_tables,netlink_diag,nf_nat,overlay
migration.incremental.memory: 'true'
raw.lxc: |-
lxc.cgroup.devices.allow = c 10:237 rwm
lxc.apparmor.profile = unconfined
lxc.cgroup.devices.allow = b 7:* rwm
security.nesting: 'true'
security.privileged: 'true'
user.user-data: |
#cloud-config
${LXD_SSH_PUB_KEYS}
devices:
eth0:
maas.subnet.ipv4: ${MAAS_SUBNET}
name: eth0
nictype: bridged
parent: br0
type: nic
root:
path: /
pool: local
type: disk
kvm:
path: /dev/kvm
type: unix-char
mem:
path: /dev/mem
type: unix-char
loop-control:
path: /dev/loop-control
type: unix-char
loop0:
path: /dev/loop0
type: unix-block
loop1:
path: /dev/loop1
type: unix-block
loop2:
path: /dev/loop2
type: unix-block
loop3:
path: /dev/loop3
type: unix-block
loop4:
path: /dev/loop4
type: unix-block
loop5:
path: /dev/loop5
type: unix-block
loop6:
path: /dev/loop6
type: unix-block
loop7:
path: /dev/loop7
type: unix-block
cluster:
server_name: \$(hostname 2>/dev/null -s)
enabled: true
member_config: []
cluster_address: ''
cluster_certificate: ''
server_address: ''
cluster_password: ''
EOT
elif [[ \$(hostname 2>/dev/null -s) != ${CLOUD_PRIMARY} ]];then
while [[ \$(sudo ssh 2>/dev/null -i /etc/ssh/ssh_host_rsa_key -tt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@${CLOUD_PRIMARY} 'test -f /var/snap/lxd/common/lxd/server.crt';echo $?) -ne 0 ]];do sleep 5;done
cat <<EOT|sudo lxd init --preseed
config: {}
networks: []
storage_pools: []
profiles: []
cluster:
server_name: \$(hostname -s)
enabled: true
member_config:
- entity: storage-pool
name: local
key: source
value: ${STORAGE_POOL_DEVICE}
description: ''
- entity: storage-pool
name: local
key: volatile.initial_source
value: ${STORAGE_POOL_DEVICE}
description: ''
- entity: storage-pool
name: local
key: zfs.pool_name
value: local
description: ''
cluster_address: ${CLOUD_PRIMARY}.${MAAS_DOMAIN}:8443
cluster_certificate: |
\$(sudo ssh 2>/dev/null -i /etc/ssh/ssh_host_rsa_key -tt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@${CLOUD_PRIMARY} 'sed -e ":a;N;$!ba;s/\n/\n\n/g" /var/snap/lxd/common/lxd/server.crt'|sed 's/^.*$/ &/g')
server_address: \$(dig +short @${MAAS_IP} \$(hostname -f)):8443
cluster_password: ubuntu
EOT
fi
EOF
)
#Remove old tags on redeployment
printf "\n\e[2GCleaning up tags on machines which are no longer deployed...\n"
microcloud-tag-cleanup -p ${BASE_TAG} -i ${MICROCLOUD_TAG}
local MICROCLOUD_TAG="${BASE_TAG}-$(cat /dev/urandom|tr -dc 'a-z0-9'|fold -w6|head -n1)"
printf "\n\e[3G- Creating tag \"${MICROCLOUD_TAG}\" for this microcloud...\n"
maas ${MAAS_PROFILE} tags create name=${MICROCLOUD_TAG} comment="${CLOUD_COMMENT};$(echo -n ${MICROCLOUD_TAG^^}|sed 's/-/_/g')_HOSTS=(`printf '%s\n' ${ALLOCATED_MACHINES[@]##*:}|paste -sd" "` ); $(echo -n ${MICROCLOUD_TAG^^}|sed 's/-/_/g')_BUILD_DATE=$(date --iso-8601=seconds)" &>/dev/null
printf "\e[5G- Tagging ${#ALLOCATED_MACHINES[@]} machine${W} with \"${MICROCLOUD_TAG}\"...\n"
ADD=$(printf "add=%s\n" ${ALLOCATED_MACHINES[@]##*:}|paste -sd' ')
local ADDED=$(eval "maas ${MAAS_PROFILE} tag update-nodes ${MICROCLOUD_TAG} "$ADD""|jq -r .added)
[[ ${ADDED} -eq ${#ALLOCATED_MACHINES[@]} ]] && { printf "\e[8G- Successfully tagged ${ADDED}/${#ALLOCATED_MACHINES[@]} machines with the \"${MICROCLOUD_TAG}\" tag ${OK} "; } || { printf "\e[8G- Could only tag ${ADDED}/${#ALLOCATED_MACHINES[@]} machines with ${MICROCLOUD_TAG} ${FAILED} \n"; }
echo
printf "\n\e[3G- Deploying the following hosts to ${MICROCLOUD_TAG}:\n"
printf -- "\e[5G - %s\n" ${ALLOCATED_MACHINES[@]}|sed 's/:/ \(/g;s/.$/&\)/g';echo
local -a SYSID_ARR=($(printf "%s\n" ${ALLOCATED_MACHINES[@]##*:}))
local -a DEPLOYED_MACHINES=($(printf "%s\n" ${SYSID_ARR[@]}|xargs -I{} -n1 -P1 maas ${MAAS_PROFILE} machine deploy {} distro_series=${DISTRO} user_data="$(echo;cat <<EOF|tee /tmp/${FUNCNAME}.cloud-init.yaml|base64 -w0
#cloud-config-2
bootcmd:
- (ip route get ${MAAS_IP}|grep -oP '(?<=dev )[^ ]+')|xargs -n1 ip route add default dev
final_message: LXD-Cluster Install complete on \$(hostname -f)
timezone: ${CI_TZ}
locale: ${CI_LC}
apt:
proxy: http://${MAAS_IP}:8000/
primary:
- arches: [amd64]
uri: http://${CI_APT_MIRROR}/ubuntu
security:
- arches: [amd64]
uri: http://security.ubuntu.com/ubuntu
package_update: ${CI_PKG_UPD}
package_upgrade: ${CI_PKG_UPG}
${CI_PACKAGES}
write_files:
- encoding: b64
content: ${LXD_CLUSTER_SCRIPT}
path: /usr/local/bin/lxd-cluster.sh
permissions: '755'
owner: root:root
- encoding: b64
content: ${LXD_IMAGE_SCRIPT}
path: /usr/local/bin/lxc-image-copy.sh
permissions: '755'
owner: root:root
- encoding: b64
content: ${VIP_VRRP_SCRIPT}
path: /usr/local/bin/configure-vrrp.sh
permissions: '755'
owner: root:root
${SSH_HOST_KEYS}
${SSH_PUB_KEYS}
runcmd:
- set -x
- for i in \$(seq \$(find /dev -iname 'loop[0-9]*'|wc -l) 1 256);do mknod -m0660 /dev/loop\${i} b 7 \${i} && chown root.disk /dev/loop\${i};done
- if [ \$(lsb_release -sr|sed 's/\.//g') -le 1804 ];then apt purge lxd lxd-client -y;fi
- if [ \$(lsb_release -sr|sed 's/\.//g') -ge 1810 ];then snap remove lxd;fi
- apt autoremove -y
- snap install lxd --candidate
- adduser \$(id -un 1000) lxd
- if [ ! \$(id -un 1000) = ubuntu -a -n \$(id 2>/dev/null -u ubuntu) ];then adduser ubuntu lxd;fi
- if [ ! -f \$(awk -F":" '/'\$(id -un 0)'/{print \$6}' /etc/passwd)/.ssh/id_rsa ];then printf "y\n"|ssh-keygen -f ~/.ssh/id_rsa -P "";fi
- if [ ! -f \$(awk -F":" '/'\$(id -un 1000)'/{print \$6}' /etc/passwd)/.ssh/id_rsa ];then su - \$(id -un 1000) -c 'printf "y\n"|ssh-keygen -f ~/.ssh/id_rsa -P ""' ;fi
- if [ ! \$(id -un 1000) = ubuntu -a -n \$(id 2>/dev/null -u ubuntu) ];then if [ ! -f \$(awk -F":" '/ubuntu/{print \$6}' /etc/passwd)/.ssh/id_rsa ];then su - ubuntu -c 'printf "y\n"|ssh-keygen -f ~/.ssh/id_rsa -P ""' ;fi;fi
- cp /etc/ssh/ssh_host_rsa_key* \$(awk -F\":\" '/'\$(id -un 1000)'/{print \$6}'/etc/passwd)/.ssh/
- chown -R \$(id -un 1000):\$(id -un 1000) \$(awk -F\":\" '/'\$(id -un 1000)'/{print \$6}'/etc/passwd)/.ssh/
- cat /etc/ssh/ssh_host_rsa_key.pub|tee 1>/dev/null -a \$(awk -F":" '/'\$(id -un 0)'/{print \$6}' /etc/passwd)/.ssh/authorized_keys \$(awk -F":" '/'\$(id -un 1000)'/{print \$6}' /etc/passwd)/.ssh/authorized_keys
- printf -- '\nHost ${CLUSTER_HOST_LIST}\n\tAddressFamily inet\n\tCheckHostIP no\n\tForwardX11Trusted yes\n\tForwardX11 yes\n\tIdentityFile /etc/ssh/ssh_host_rsa_key\n LogLevel FATAL\n SendEnv LANG LC_*\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n User ubuntu\n\tXAuthLocation /usr/bin/xauth\n'|tee -a 1>/dev/null /etc/ssh/ssh_config
- printf -- '%s\n' ${CLUSTER_HOST_LIST//\*/}|xargs -I{} -n1 -P0 ssh-keyscan 2>/dev/null -H {}|su - \$(id -un 1000) -c 'tee -a ~/.ssh/known_hosts'
- printf -- '%s\n' ${CLUSTER_HOST_LIST//\*/}|xargs -I{} -n1 -P0 ssh-keyscan 2>/dev/null -H {}|tee -a \$(awk -F\":\" '/'\$(id -un 0)'/{print \$6}' /etc/passwd)/.ssh/known_hosts
- if [ -f /usr/local/bin/lxd-cluster.sh ];then /usr/local/bin/lxd-cluster.sh;fi
- if [ \$(hostname -s) = ${CLOUD_PRIMARY} -a -f /usr/local/bin/lxc-image-copy.sh ];then /usr/local/bin/lxc-image-copy.sh;fi
- snap install conjure-up --classic
- lxc 2>/dev/null profile device set maas eth0 parent \$(ip route get ${MAAS_IP}|/bin/grep -oP '(?<=dev )[^ ]+')
- lxc 2>/dev/null profile device set maas-privileged eth0 parent \$(ip route get ${MAAS_IP}|/bin/grep -oP '(?<=dev )[^ ]+')
- export ENABLE_GPU_SUPPORT=${ENABLE_GPU}
- if [ \${ENABLE_GPU_SUPPORT} = true ];then echo Detecting GPGPU devices...;fi
- if [ \${ENABLE_GPU_SUPPORT} = true ];then export GPU_CMD='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"';fi
- if [ \${ENABLE_GPU_SUPPORT} = true ];then export GPU_CONF_FILE='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{printf "export NVDA_GPU_%02d_ID=%s\nexport NVDA_GPU_%02d_BUS=%s\n",NR,substr(\$(NF-2),2,9),NR,\$1}'"'"'|tee -a /etc/gpgpu-pci-ids.conf';fi
- if [ \${ENABLE_GPU_SUPPORT} = true ];then export GPU_PCI_LIST='lspci -nn|awk -vIGNORECASE=1 '"'"'BEGIN {printf "%s","options vfio-pci ids="} /\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"|tee /etc/modprobe.d/vfio.conf';fi
- if [ \${ENABLE_GPU_SUPPORT} = true ];then if [ -n \$(eval \$GPU_CMD) ];then echo ' GPGPUs Detected!';printf '%s\n' vfio vfio_pci > /etc/modules-load.d/vfio.conf;eval \$GPU_CONF_FILE;eval \$GPU_PCI_LIST;fi;fi
- export VIP_VRRP_ENABLE=${VIP_VRRP_ENABLE}
- if [ \${VIP_VRRP_ENABLE} = true ];then echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf;fi
- if [ \${VIP_VRRP_ENABLE} = true ];then sysctl -p;fi
- if [ \${VIP_VRRP_ENABLE} = true ];then install -D -m 644 /dev/null '/etc/systemd/system/keepalived.service';fi
- |-
if [ \${VIP_VRRP_ENABLE} = true ];then
cat > '/etc/systemd/system/keepalived.service' << 'EOF'
[Unit]
Description=LVS and VRRP High Availability monitor
After=network.target
ConditionFileNotEmpty=/etc/keepalived/keepalived.conf
[Service]
Type=simple
EnvironmentFile=-/etc/default/keepalived
ExecStart=/usr/sbin/keepalived --dont-fork
ExecReload=/bin/kill -s HUP \$MAINPID
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
fi
- if [ \${VIP_VRRP_ENABLE} = true ];then /bin/systemctl enable '/etc/systemd/system/keepalived.service';fi
- if [ \${VIP_VRRP_ENABLE} = true ];then /bin/systemctl start '/etc/systemd/system/keepalived.service';fi
- touch /var/tmp/install-complete
EOF
)"|jq 2>/dev/null -r '"\(.hostname):\(.system_id)"'))
printf "\n\e[2GA copy of the cloud-init used for this deployment can be found at\n\e[2G/tmp/${FUNCNAME}.cloud-init.yaml\n\n"
}
export -f create-lxd-microcloud
create-kvm-microcloud() {
local DESC="${FUNCNAME}: Deploy a KVM Pods with Cloud-Init customizations via MAAS command line"
# Env Setttings
local CI_TZ='America/Los_Angeles'
local CI_LC='en_US.UTF-8'
#Package/Mirror Settings
local CI_PKG_UPG=true
local CI_PKG_UPD=true
# Test for Ubuntu Country Mirror based on Locale
local CI_TC=${CI_LC:3:2}
if [[ -n ${CI_TC} && $(curl -slSL -w %{http_code} -o /dev/null ${CI_TC,,}.archive.ubuntu.com) -eq 200 ]];then
local CI_CC=${CI_TC}
local CI_APT_MIRROR=${CI_CC,,}.archive.ubuntu.com
else
local CI_APT_MIRROR=archive.ubuntu.com
fi
#Generic KeepAliveD Settings for a Cluster VIP using Keepalived
#ENV Setttings
local CI_TZ='America/Los_Angeles'
local CI_LC='en_US.UTF-8'
#Package Settings
local CI_PKG_UPG=true
local CI_PKG_UPD=true
# Test for Ubuntu Country Mirror based on Locale
local CI_TC=${CI_LC:3:2}
if [[ -n ${CI_TC} && $(curl -slSL -w %{http_code} -o /dev/null ${CI_TC,,}.archive.ubuntu.com) -eq 200 ]];then
local CI_CC=${CI_TC}
local CI_APT_MIRROR=${CI_CC,,}.archive.ubuntu.com
else
local CI_APT_MIRROR=archive.ubuntu.com
fi
#Generic KeepAliveD Settings for a Cluster VIP using Keepalived
local VIP_VRRP_CIDR=
local VIP_VRRP_ENABLE=false
#Defaults if not chosen
local ENABLE_GPU=false
local BASE_TAG="microcloud-kvm"
local STORAGE_POOL_DEVICE=
local STORAGE_POOL_TYPE=file
local ENFORE_HA=true
local -a CI_PKG_LIST=(
bridge-utils
build-essential
jq
prips
squashfuse
unzip
zfsutils-linux
keepalived
)
local -a CI_PKG_LIST_BIONIC=(
apt-utils
build-essential
debconf-utils
jq
libvirt-bin
libvirt-daemon-driver-storage*
libvirt-daemon-system
ovmf
qemu-kvm
squashfuse
virtinst
virt-manager
virt-viewer
zfsutils
keepalived
)
local -a CI_PKG_LIST_COSMIC=(
apt-utils
build-essential
debconf-utils
jq
qemu-kvm
libvirt-daemon*
ovmf
squashfuse
virtinst
virt-manager
zfsutils-linux
keepalived
)
create-kvm-microcloud_usage() {
printf "\n\e[2G${DESC}\n\n"
printf "\e[2G\e[1mUsage\e[0m: ${FUNCNAME%%_*} [-c <count>] [-t <tag>] [-d <distro>] ( -g gpu-passthrough support ) (-p storage-pool block device)\n\n"
printf "\e[4G -n, --count\e[20GNumber of nodes (Min: 3) \n"
printf "\e[4G -t, --tag \e[20GExisting tag to use when selecting nodes\n"
printf "\e[4G -d, --distro\e[20GName of Ubuntu Distro (Default: bionic)\n"
printf "\e[4G -p, --pool-device\e[20GBlock device to use for KVM Storage Pool (Default: File-based Pool)\n"
printf "\e[4G -g, --gpu\e[20GEnable GPU passthrough support\n"
printf "\e[4G -H, --ha\e[20GEnsure n+2 servers are available (default: True)\n"
printf "\e[4G -N, --no-ha\e[20GAllow less than n+2 servers in a cloud (default: False)\n"
printf "\e[4G -T, --cloud-name\e[20GUse a custom tag to indentify this microcloud\n"
printf "\e[4G -c, --comment\e[20GComment to apply to tags related to the microcloud\n"
printf "\e[4G -v, --vrrp\e[20GEnable simple Virtual IP address failover using Keepalived (default: false)\n"
printf "\e[4G -V, --VIP\e[20GIP Address to use for the VIP\n"
printf "\e[4G -i, --instance\e[20GKeepAliveD instance name for VRRP_VIP service (default: MICROCLOUD_VIP)\n"
printf "\e[4G -P, --vrrp-password\e[20GPassword used by KeepAliveD to track state (default: Random 6 digit alpha numeric\n"
printf "\e[4G --cpu-ocr\e[20G CPU overcommit ratio for KVM 1.0 >= <= 10.0 (default: 1 recommended: 10\n"
printf "\e[4G --mem-ocr\e[20G memory overcommit ratio for KVM 1.0 >= <= 10.0 (default: 1 recommended: < 1.5\n"
printf "\e[4G -h, --help\e[20GThis message\n"
printf "\n\n"
}
ARGS=$(getopt -o n:c:t:d:p:C:T:P:v:o:gdhHNV -l count:,tag:,distro:,pool-device:,comment:,cloud-name:.vip:,vrrp-password:,cpu-ocr:,mem-ocr:,gpu,help,desc,enable-vrrp,ha,no-ha -n ${FUNCNAME} -- "$@")
eval set -- "$ARGS"
while true ; do
case "$1" in
-n|-c|--count) local COUNT=${2};shift 2;;
-t|--tag) local TAG=${2};local TAG=${TAG,,};shift 2;;
-d|--distro) local DISTRO=${2};local DISTRO=${DISTRO,,};shift 2;;
-p|--pool-device) local STORAGE_POOL_DEVICE=${2};local STORAGE_POOL_DEVICE=${STORAGE_POOL_DEVICE,,};local STORAGE_POOL_TYPE=device;shift 2;;
-g|--gpu) local ENABLE_GPU=true;shift 1;;
-H|--ha) local ENFORCE_HA=true;shift 1;;
-N|--no-ha) local ENFORCE_HA=false;shift 1;;
-C|--comment) local CLOUD_COMMENT="${2}";shift 2;;
-T|--cloud-name) local CLOUD_NAME="${2,,}";shift 2;;
-V|--enable-vrrp) local VIP_VRRP_ENABLE=true;shift 1;;
-v|--vip) local VIP_VRRP_CIDR=${2};shift 2;;
-i|--vrrp-instance) local VIP_VRRP_INSTANCE=${2};shift 2;;
-P|--vrrp-password) local VIP_VRRP_PASS=${2};shift 2;;
--cpu-ocr) local CPU_OCR=${2};shift 2;;
--mem-ocr) local MEM_OCR=${2};shift 2;;
--desc) printf "\n\e[2G${DESC}\n";return 0;;
-h|--help) ${FUNCNAME}_usage;return 2;;
--) shift;break;;
esac
done
command -v maas &>/dev/null || { printf "\n\n\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0m\e[38;2;0;255;0m maas-cli \e[0m\e[1m2.5+\e[0m is required for this demo.\n\e[9GPlease install and configure version 2.5 or later\n\n";return 1; }
[[ $(dpkg-query -s maas|grep -oP '(?<=Version: )[^?]{3}'|sed 's/\.//') -lt 25 ]] && { printf "\n\n\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mMAAS \e[38;2;0;255;0m2.5\e[0m\e[1m+\e[0m is required for this demo.\n\e[9GYou are running version \e[38;2;255;255;0m$(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m\n\n";return 1; }
command -v jq &>/dev/null || sudo apt install jq -y
local OK='\u00A0\e[38;2;0;255;0m\u2713\e[0m\u00A0\n'
local FAILED='\u00A0\e[38;2;255;0;0m\u2718\u00A0\n'
printf -- "\n\e[1mMicro-cloud Demo - KVM\e[0m\n\n"
printf -- "\e[3G- Provisioning by \e[1mMAAS $(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m${OK}\n"
printf -- "\e[6G- Powered by \e[1m$(lsb_release -ds)\e[0m${OK}\n"
printf -- "\e[3G- Featuring \e[1mKVM Pods \e[0m${OK}\n"
printf '\n\n'
[[ -z ${MAAS_PROFILE} ]] && { read -srp "$(printf "\e[2GPlease enter your MAAS profile name: ")" MAAS_PROFILE_INPUT;local MAAS_PROFILE=$MAAS_PROFILE_INPUT; }
local MAAS_IP=$(maas list|awk -F"//|:" '/^'${MAAS_PROFILE}'/{print $3}')
#Validation and error handling
local -a VALID_TAGS=($(maas ${MAAS_PROFILE} tags read|jq -r '.[].name'))
local -a VALID_DISTROS=($(maas ${MAAS_PROFILE} boot-resources read|jq -r '.[]|"\(select((.name|startswith("grub")|not) and (.name|startswith("ubuntu")) and (.name|startswith("pxe")|not)).name|sub("ubuntu/"; ""))"'|sort -uV))
printf -- "\e[1m\e[2GProcessing selections\e[0m:\n\n"
[[ ${ENABLE_GPU} = true ]] && printf -- "\e[3G- GPGPU Passthrough enabled\n"
if [[ ${VIP_VRRP_ENABLE} = true ]];then
printf -- "\e[3GSimple Virtual IP Address Failover enabled\n"
[[ -n ${VIP_VRRP_CIDR} ]] && { printf -- "\e[5G- Virtual IP: ${VIP_VRRP_CIDR}\n"; } || { local VIP_VRRP_CIDR_=$(gen-sa-ip);printf -- "\e[5G- VIP_VRRP_CIDR: ${VIP_VRRP_CIDR} (auto-generated)\n"; }
[[ -n ${VIP_VRRP_INSTANCE} ]] && { printf -- "\e[5G- VRRP Instance Name: ${VIP_VRRP_INSTANCE}}\n"; } || { local VIP_VRRP_INSTANCE="VIP-$(cat /dev/urandom|tr -dc 'A-Z0-9'|fold -w6|head -n1)";printf -- "\e[5G- VRRP INSTANCE: ${VIP_VRRP_INSTANCE} (auto-generated)\n"; }
[[ -n ${VIP_VRRP_PASS} ]] && { printf -- "\e[5G- VRRP Passwd: ${VIP_VRRP_PASS}\n"; } || { local VIP_VRRP_PASS="$(cat /dev/urandom|tr -dc 'a-z0-9'|fold -w6|head -n1)";printf -- "\e[5G- VRRP Passwd: ${VIP_VRRP_PASS} (auto-generated)\n"; }
fi
[[ ${ENFORCE_HA} = true ]] && { printf "\e[3G- Enforcing n+2 Rule\n"; }
[[ ${ENFORCE_HA} = true && $COUNT -lt 3 ]] && { local COUNT=3;printf "\e[3G- Setting node count to 3\n"; }
# If not a physical disk, set storage pool to use a file
[[ ${STORAGE_POOL_TYPE} = device ]] && { printf "\e[3G- Storage Pool will use block device ${STORAGE_POOL_DEVICE} \n"; local STORAGE_POOL_TYPE=device; } || { local STORAGE_POOL_TYPE=file;local STORAGE_POOL_DEVICE="/var/lib/libvirt/maas-images/";printf "\e[3G- Storage Pool will be file-based \n"; }
[[ -z ${COUNT} ]] && { [[ ${ENFORCE_HA} = true ]] && { local COUNT=3;printf "\e[3G- Setting Node count to ${COUNT}\n"; } || { local COUNT=1;printf "\e[3G- Setting Node count to ${COUNT}\n"; }; }
[[ ${COUNT} =~ ^[0-9]+$ && ${COUNT} -lt 3 && ${ENFORCE_HA} = true ]] && { local COUNT=3;printf "\e[3G- Minimum Node count for HA is ${COUNT}. Setting Node count to ${COUNT}.\n\n"; }
[[ -z ${TAG} ]] && { printf "\e[2GERROR: No tag name given ${TAG}\n\n\e[2GValid tags are:\n";printf "\e[4G- %s\n" ${VALID_TAGS[@]};return 1; }
[[ -n ${TAG} && -n $(grep -P '(^|\s)\K'${TAG}'(?=\s|$)' <<< ${VALID_TAGS[@]}) ]] || { printf "\e[2GERROR: No tags exist named ${TAG}\n\n\e[2GValid tags are:\n";printf "\e[4G- %s\n" ${VALID_TAGS[@]};return 1; }
[[ -n ${DISTRO} ]] && { printf "\e[3G- Setting distro to ${DISTRO}\n"; } || { local DISTRO="bionic";printf "\e[3G- Setting distro to ${DISTRO}\n"; }
[[ -n ${DISTRO} && -n $(grep -P '(^|\s)\K'${DISTRO}'(?=\s|$)' <<< ${VALID_DISTROS[@]}) ]] || { printf "\e[2GERROR: Invalid Distro: ${DISTRO}\n\n\e[2GValid distros for KVM Pods are:\n";printf "\e[4G- %s\n" ${VALID_DISTROS[@]};return 1; }
[[ ${COUNT} -eq 1 ]] && W= || W=s
if [[ ${STORAGE_POOL_TYPE} = device ]];then
printf "\n\e[3G- Finding ${COUNT} machine${W} :\n\e[5G- Marked as \"Ready\"\n\e[5G- Tagged with \"${TAG}\"\n"
local READY_TAGGED_MACHINES=($(maas ${MAAS_PROFILE} machines read|jq -r '.[]|select(.physicalblockdevice_set[].name|contains("'${STORAGE_POOL_DEVICE##*/}'"))|select((.tag_names[]|contains("'"${TAG}"'")) and .status == 4)|"\(.hostname):\(.system_id)"'|head -n${COUNT}|sort -V))
[[ ${#READY_TAGGED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not find enough machines to create a KVM Cluster.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#READY_TAGGED_MACHINES[@]}\n\n";return 1; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#READY_TAGGED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machines with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#READY_TAGGED_MACHINES[@]}
else
printf "\n\e[3G- Finding ${COUNT} machine${W} :\n\e[5G- Marked as \"Ready\"\e[5G- Tagged with \"${TAG}\"\n\e[5G- Has physical disk named ${STORAGE_POOL_DEVICE}\n"
local -a READY_TAGGED_MACHINES=($(maas ${MAAS_PROFILE} machines read|jq -r '.[]|select((.tag_names[]|contains("'"${TAG}"'")) and .status == 4)|"\(.hostname):\(.system_id)"'|head -n${COUNT}|sort -V))
[[ ${#READY_TAGGED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not find enough machines to create a KVM Cluster.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#READY_TAGGED_MACHINES[@]}\n\n";return 1; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#READY_TAGGED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#READY_TAGGED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only find ${#READY_TAGGED_MACHINES[@]} machine${W} with the ${TAG} tag. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#READY_TAGGED_MACHINES[@]}
fi
printf "\n\e[2GAllocating the following Host${W} to the KVM Pods:\n"
printf -- "\e[2G - %s\n" ${READY_TAGGED_MACHINES[@]}|sed 's/:/ \(/g;s/.$/&\)/g';echo
local -a ALLOCATED_MACHINES=($(printf "%s\n" ${READY_TAGGED_MACHINES[@]##*:}|xargs -I{} -n1 -P0 maas ${MAAS_PROFILE} machines allocate system_id={}|jq -r '"\(.hostname):\(.system_id)"'|sort -uV))
[[ ${#ALLOCATED_MACHINES[@]} -lt 3 && ${ENFORCE_HA} = true ]] && { printf "\e[2G\e[2G\e[38;2;255;255;0mSorry! \e[0mCould not allocate enough machines to create a KVM Pods.\n\n\e[9GMachines Required: 3\n\e[9GMachines Found:\e[4C\e[38;2;255;0;0m${#ALLOCATED_MACHINES[@]}\n\n";return 1; }
[[ ${#ALLOCATED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = true && ${#ALLOCATED_MACHINES[@]} -ge 3 ]] && { read -erp "$(printf "\n\e[2G - Could only allocate ${#ALLOCATED_MACHINES[@]} machine${W}. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
[[ ${#ALLOCATED_MACHINES[@]} -lt ${COUNT} && ${ENFORCE_HA} = false ]] && { read -erp "$(printf "\n\e[2G - Could only allocate ${#ALLOCATED_MACHINES[@]} machines. Continue? [y/n] : ")" CONT; [[ ${CONT,,} =~ y ]] && echo || return 0; }
local COUNT=${#ALLOCATED_MACHINES[@]}
# Get SSH Public keys from local accounts and maas. Remove duplicates
local SSH_PUB_KEYS=$((if [[ -n $(find 2>/dev/null ~/.ssh -iname "*.pub") ]];then
echo ssh_authorized_keys:
find 2>/dev/null ~/.ssh -iname "*.pub"|xargs -n1 -P1 bash -c 'printf -- '"'"' - %s\n'"'"' "$(cat $0)"'
fi
if [[ -n $(command -v maas 2>/dev/null) ]];then
if [[ $(maas 2>/dev/null ${MAAS_PROFILE} sshkeys read|jq 2>/dev/null length) -ge 1 ]];then
echo "ssh_authorized_keys:"
maas 2>/dev/null ${MAAS_PROFILE} sshkeys read|jq 2>/dev/null -r '.[]|"\(.key)"'| \
while IFS= read -r line;do
sed 's/^/ - /g'
done
fi
fi
)|awk '!seen[$0]++')
# Create a string of the Cluster hosts that we can for SSH config files (thus the added asterisk)
# (easier to remove the asterisk in a variable than to add it, so it's added to main variable)
local CLUSTER_HOST_LIST=$(printf "%s*\n" ${ALLOCATED_MACHINES[@]%%:*}|paste -sd" "|sort -uV)
# Create Package List for Cluster hosts
[[ ${DISTRO,,} = xenial || ${DISTRO,,} = bionic ]] && local CI_PACKAGES=$([[ ${#CI_PKG_LIST_BIONIC[@]} -ge 1 ]] && printf "packages: [$(printf '%s\n' ${CI_PKG_LIST_BIONIC[@]}|paste -sd',')]\n")
[[ ${DISTRO,,} = cosmic || ${DISTRO,,} = disco ]] && local CI_PACKAGES=$([[ ${#CI_PKG_LIST_COSMIC[@]} -ge 1 ]] && printf "packages: [$(printf '%s\n' ${CI_PKG_LIST_COSMIC[@]}|paste -sd',')]\n")
# xpath auto tags for varius different nVidia GPGPUs
if [[ ${ENABLE_GPU} = true ]];then
printf "\e[2GConfiguring xpath auto-tags for GPGPU Detection at the hardware level in MAAS...\n\n"
NVDA_3D_CONTROLLER_TAG_DEF='//node[@id="display"]/description = "3D controller" and //node[@id="display"]/vendor = "NVDA Corporation" and //node[@id="display"]/product = "NVIDIA Corporation"'
NVDA_3D_CONTROLLER_TAG_COMMENT='xpath auto-tag for nvidia general-purpose GPUs that have been claimed by noveau or nvidiafb module'
declare -ag NVDA_GPGPU_TESLA_PRODUCTS=(P4 P40 P100 V100 T4)
NVDA_GPGPU_TESLA_PROD_DEF="$(for p in ${NVDA_GPGPU_TESLA_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_TESLA_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Tesla") and '"${NVDA_GPGPU_TESLA_PROD_DEF}"''
NVDA_GPGPU_TESLA_TAG_COMMENT="xpath auto-tag for nVidia Tesla-based general-purpose GPUs"
declare -ag NVDA_GPGPU_QUADRO_PRODUCTS=(K M P2000 P4000 P5000 P6000)
NVDA_GPGPU_QUADRO_PROD_DEF="$(for p in ${NVDA_GPGPU_QUADRO_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_QUADRO_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Quadro") and '"${NVDA_GPGPU_QUADRO_PROD_DEF}"''
NVDA_GPGPU_QUADRO_TAG_COMMENT="xpath auto-tag for nVidia Quadro-based general-purpose GPUs"
declare -ag NVDA_GPGPU_ALL_PRODUCTS=($(printf "%s\n" ${NVDA_GPGPU_TESLA_PRODUCTS[@]} ${NVDA_GPGPU_QUADRO_PRODUCTS[@]}|paste -sd" "))
NVDA_GPGPU_ALL_PROD_DEF="$(for p in ${NVDA_GPGPU_TESLA_PRODUCTS[@]} ${NVDA_GPGPU_QUADRO_PRODUCTS[@]};do printf '%s\n' '//node[@id="display"]/product[starts-with(.,"'${p}'")] or '; done|sed '$ s/ or//g')"
NVDA_GPGPU_ALL_TAG_DEF='contains(//node[@id="display"]/vendor,"nVidia") and contains(//node[@id="display"]/product,"Quadro") or contains(//node[@id="display"]/product,"Tesla") and '"${NVDA_GPGPU_ALL_PROD_DEF}"''
NVDA_GPGPU_ALL_TAG_COMMENT="xpath auto-tag for nVidia Quadro and Tesla-based general-purpose GPUs"
NVDA_GPGPU_ALL_KERNEL_OPTS="nomodeset modprobe.blacklist=nouveau modprobe.blacklist=nvidiafb intel_iommu=on iommu=pt rd.driver.pre=vfio-pci video=efifb:off vfio_iommu_type1.allow_unsafe_interrupts=1"
declare -ag GPGPU_ARR=(NVDA_3D_CONTROLLER NVDA_GPGPU_TESLA NVDA_GPGPU_QUADRO NVDA_GPGPU_ALL)
MAAS_TAGS=$(maas ${MAAS_PROFILE} tags read)
for G in ${GPGPU_ARR[@]};do
if [[ -n $(jq -r '.[]|select(.name=="'${G,,}'").name' <<< ${MAAS_TAGS}) ]];then
printf "\e[2G - Updating xpath auto tag for ${G} products...\n"
maas ${MAAS_PROFILE} tag update ${G,,} name="${G,,}" definition="$(eval echo \$${G}_TAG_DEF)" comment="$(eval echo \$${G}_TAG_COMMENT)"
[[ ${G} = NVDA_GPGPU_ALL || ${G} = NVDA_3D_CONTROLLER ]] && maas ${MAAS_PROFILE} tag update ${G,,} name="${G,,}" kernel_opts="${NVDA_GPGPU_ALL_KERNEL_OPTS}"
printf '\n\n'
else
printf "\e[2G - Creating xpath auto tag for ${G} products...\n\n"
maas ${MAAS_PROFILE} tags create name="${G,,}" definition="$(eval echo \$${G}_TAG_DEF)" comment="$(eval echo \$${G}_TAG_COMMENT)"
[[ ${G} = NVDA_GPGPU_ALL || ${G} = NVDA_3D_CONTROLLER ]] && maas ${MAAS_PROFILE} tag update ${G,,} name="${G,,}" kernel_opts="${NVDA_GPGPU_ALL_KERNEL_OPTS}"
printf '\n\n'
fi
done
fi
[[ ${VIP_VRRP_ENABLE} = true ]] && printf "\e[3G- Writing KeepAliveD configuration Script to Cloud-Init file...\n\n"
[[ ${VIP_VRRP_ENABLE} = true ]] && local VIP_VRRP_SCRIPT=$(cat <<EOS|base64 -w0
#!/bin/bash
#root check
if [[ $EUID -ne 0 ]]; then
printf '\n\e[1;33mThis script requires admin privileges.\e[0m\e[1;37m Please run via sudo.\e[0m\n\n'
exit 1
fi
if [[ \$(hostname 2>/dev/null -s) = ${CLOUD_PRIMARY} ]];then
cat <<EOM|/etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@\$(hostname -d)
}
notification_email_from \$(hostname -f)
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_instance ${VIP_VRRP_INSTANCE} {
state MASTER
# Specify the network interface to which the virtual address is assigned
interface \$(ip route get ${MAAS_IP}|grep -oP '(?<=dev )[^ ]+')
# The virtual router ID must be unique to each VRRP instance that you define
virtual_router_id 81
# Set the value of priority higher on the master server than on a backup server
priority 200
advert_int 1
authentication {
auth_type PASS
auth_pass ${VIP_VRRP_PASS}
}
virtual_ipaddress {
$VIP_VRRP_CIDR
}
}
EOM
else
cat <<EOB|/etc/keepalived/keepalived.conf
global_defs {
notification_email {
root@\$(hostname -d)
}
notification_email_from \$(hostname -f)
smtp_server localhost
smtp_connect_timeout 30
}
vrrp_instance ${VIP_VRRP_INSTANCE} {
state BACKUP
# Specify the network interface to which the virtual address is assigned
\$(ip route get ${MAAS_IP}|grep -oP '"'"'(?<=dev )[^ ]+'"'"')
virtual_router_id 81
# Set the value of priority lower on the backup server than on the master server
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass ${VIP_VRRP_PASS}
}
virtual_ipaddress {
${VIP_VRRP_CIDR}
}
}
EOB
fi
EOS
)
local MICROCLOUD_TAG="${BASE_TAG}-$(cat /dev/urandom|tr -dc 'a-z0-9'|fold -w6|head -n1)"
printf "\n\e[2GCreating tag \"${MICROCLOUD_TAG}\" for this microcloud...\n"
#Remove old tags on redeployment
printf "\n\e[2GCleaning up tags on machines that no longer deployed...\n"
microcloud-tag-cleanup -p ${BASE_TAG} -i ${MICROCLOUD_TAG}
maas ${MAAS_PROFILE} tags create name=${MICROCLOUD_TAG} comment="$(echo -n ${MICROCLOUD_TAG^^}|sed 's/-/_/g')_HOSTS=(`printf '%s\n' ${ALLOCATED_MACHINES[@]##*:}|paste -sd" "` ); $(echo -n ${MICROCLOUD_TAG^^}|sed 's/-/_/g')_BUILD_DATE=$(date --iso-8601=seconds)" &>/dev/null
printf "\e[2G- Tagging ${#ALLOCATED_MACHINES[@]} machines with \"${MICROCLOUD_TAG}\"...\n"
ADD=$(printf "add=%s\n" ${ALLOCATED_MACHINES[@]##*:}|paste -sd' ')
local ADDED=$(eval "maas ${MAAS_PROFILE} tag update-nodes ${MICROCLOUD_TAG} "$ADD""|jq -r .added)
[[ ${ADDED} -eq ${#ALLOCATED_MACHINES[@]} ]] && { printf "\e[4G - Successfully tagged ${ADDED}/${#ALLOCATED_MACHINES[@]} machines with the \"${MICROCLOUD_TAG}\" tag ${OK} "; } || { printf "\e[2G - Could only tag ${ADDED}/${#ALLOCATED_MACHINES[@]} machines with ${MICROCLOUD_TAG} ${FAILED} \n"; }
echo
printf "\n\e[2GDeploying the following host${W} to ${MICROCLOUD_TAG}:\n\n"
printf -- "\e[2G - %s\n" ${ALLOCATED_MACHINES[@]}|sed 's/:/ \(/g;s/.$/&\)/g';echo
local -a SYSID_ARR=($(printf "%s\n" ${ALLOCATED_MACHINES[@]##*:}))
local -a DEPLOYED_MACHINES=($(printf "%s\n" ${SYSID_ARR[@]}|xargs -I{} -n1 -P1 maas ${MAAS_PROFILE} machine deploy {} install_kvm=true distro_series=${DISTRO} user_data="$(echo;cat <<EOF|tee /tmp/${FUNCNAME}.cloud-init.yaml|base64 -w0
#cloud-config-2
bootcmd:
- (ip route get ${MAAS_IP}|grep -oP '(?<=dev )[^ ]+')|xargs -n1 ip route add default dev
final_message: KVM Pod Deployment Complete on \$(hostname -f)
timezone: ${CI_TZ}
locale: ${CI_LC}
apt:
proxy: http://${MAAS_IP}:8000/
primary:
- arches: [amd64]
uri: http://${CI_APT_MIRROR}/ubuntu
security:
- arches: [amd64]
uri: http://security.ubuntu.com/ubuntu
write_files:
- encoding: b64
content: ${VIP_VRRP_SCRIPT}
path: /usr/local/bin/configure-vrrp.sh
permissions: '755'
owner: root:root
package_update: ${CI_PKG_UPD}
package_upgrade: ${CI_PKG_UPG}
${CI_PACKAGES}
${SSH_PUB_KEYS}
runcmd:
- set -x
- /usr/sbin/usermod --append --groups libvirt,libvirt-qemu virsh
- systemctl restart sshd
- /bin/sleep 10
- for i in \$(seq \$(find /dev -iname 'loop[0-9]*'|wc -l) 1 256);do mknod -m0660 /dev/loop\${i} b 7 \${i} && chown root.disk /dev/loop\${i};done
- export ENABLE_GPU_SUPPORT=${ENABLE_GPU}
- if [[ \${ENABLE_GPU_SUPPORT} = true ]];then export GPU_CMD='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"';fi
- if [[ \${ENABLE_GPU_SUPPORT} = true ]];then export GPU_CONF_FILE='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{printf "export NVDA_GPU_%02d_ID=%s\nexport NVDA_GPU_%02d_BUS=%s\n",NR,substr(\$(NF-2),2,9),NR,\$1}'"'"'|tee -a /etc/gpgpu-pci-ids.conf';fi
- if [[ \${ENABLE_GPU_SUPPORT} = true ]];then export GPU_PCI_LIST='lspci -nn|awk -vIGNORECASE=1 '"'"'BEGIN {printf "%s","options vfio-pci ids="} /\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"|tee /etc/modprobe.d/vfio.conf';fi
- if [ -n \$(eval \$GPU_CMD) ];then echo GPGPUs Detected;printf '%s\n' vfio vfio_pci > /etc/modules-load.d/vfio.conf;eval \$GPU_CONF_FILE;eval \$GPU_PCI_LIST;fi
- systemctl restart libvirtd
- export STORAGE_POOL_TYPE=${STORAGE_POOL_TYPE}
- if [ \${STORAGE_POOL_TYPE} = device ];then zpool create local ${STORAGE_POOL_DEVICE};fi
- if [ \${STORAGE_POOL_TYPE} = device ];then zfs create local/maas-zfs;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then zfs set dedup=on local;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then zfs set compression=on local;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then virsh pool-define-as --name maas-images-zfs --type zfs --source-name local --source-dev=${STORAGE_POOL_DEVICE};fi
- if [ \${STORAGE_POOL_TYPE} = device ];then virsh pool-start maas-images-zfs;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then virsh pool-autostart maas-images-zfs;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then mkdir -p /var/lib/libvirt/extra-images && virsh pool-define-as extra-images-dir dir - - - - '/var/lib/libvirt/extra-images';fi
- if [ \${STORAGE_POOL_TYPE} = device ];then virsh pool-start extra-images-dir;fi
- if [ \${STORAGE_POOL_TYPE} = device ];then virsh pool-autostart extra-images-dir;fi
- export VIP_VRRP_ENABLE=${VIP_VRRP_ENABLE}
- if [ \${VIP_VRRP_ENABLE} = true ];then echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf;fi
- if [ \${VIP_VRRP_ENABLE} = true ];then sysctl -p;fi
- if [ \${VIP_VRRP_ENABLE} = true ];then install -D -m 644 /dev/null '/etc/systemd/system/keepalived.service';fi
- |-
if [ \${VIP_VRRP_ENABLE} = true ];then
cat > '/etc/systemd/system/keepalived.service' << 'EOF'
[Unit]
Description=LVS and VRRP High Availability monitor
After=network.target
ConditionFileNotEmpty=/etc/keepalived/keepalived.conf
[Service]
Type=simple
EnvironmentFile=-/etc/default/keepalived
ExecStart=/usr/sbin/keepalived --dont-fork
ExecReload=/bin/kill -s HUP \$MAINPID
KillMode=process
[Install]
WantedBy=multi-user.target
EOF
fi
- if [ \${VIP_VRRP_ENABLE} = true ];then /bin/systemctl enable '/etc/systemd/system/keepalived.service';fi
- touch /var/tmp/install-complete
EOF
)" |jq 2>/dev/null -r '"\(.hostname):\(.system_id)"'))
printf "\n\e[4G - A copy of the cloud-init used for this deployment can be found at\n\e[2G/tmp/${FUNCNAME}.cloud-init.yaml\n\n"
wait-pods-ready -c ${CPU_OCR} -m ${MEM_OCR} -t ${MICROCLOUD_TAG}
}
export -f create-kvm-microcloud
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment