Last active
February 4, 2019 05:00
-
-
Save ThinGuy/4531a39413a128689c1b116863ddc4cb to your computer and use it in GitHub Desktop.
Microcloud demo using MAAS 2.5, KVM Pods and LXD Clustering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
microcloud-tag-cleanup() { | |
local OTAG=$1 | |
local NTAG=$2 | |
# remove ready machines from a given tag ${OTAG} | |
# delete given tags ${OTAG} that do not contain machines | |
# Exclude a given tag ${NTAG} from deletion | |
[[ -z $OTAG || $OTAG =~ [-]+h ]] && { printf "${FUNCNAME}: <tag_name> [ exclude_name ]\n";return 1; } | |
local MAAS_INFO=$(maas 2>/dev/null ${MAAS_PROFILE} machines read) | |
jq 2>/dev/null -r '.[]|"\(.tag_names|to_entries[]|select(.value|startswith("'${OTAG}'")).value) \(select(.status==4).system_id)"' <<< ${MAAS_INFO}|xargs -n2 -P0 bash -c 'maas 2>/dev/null ${MAAS_PROFILE} tag update-nodes $0 remove=$1' | |
if [[ -n $NTAG ]];then | |
maas 2>/dev/null ${MAAS_PROFILE} tags read |jq 2>/dev/null -r '.[]|select(.name|startswith("'${OTAG}'"))|select(.name|startswith("'${NTAG}'")|not).name'|xargs -n1 -P0 bash -c 'printf "$0 $(maas 2>/dev/null ${MAAS_PROFILE} tag nodes $0|jq length==0)\n"'|awk '/true/{print $1}'|xargs -n1 -P0 maas 2>/dev/null ${MAAS_PROFILE} tag delete | |
else | |
maas 2>/dev/null ${MAAS_PROFILE} tags read |jq 2>/dev/null -r '.[]|select(.name|startswith("'${OTAG}'")).name'|xargs -n1 -P0 bash -c 'printf "$0 $(maas 2>/dev/null ${MAAS_PROFILE} tag nodes $0|jq length==0)\n"'|awk '/true/{print $1}'|xargs -n1 -P0 maas 2>/dev/null ${MAAS_PROFILE} tag delete | |
fi | |
} &> /dev/null | |
export -f microcloud-tag-cleanup | |
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" | |
} | |
maas-microcloud-lxd() { | |
local DESC="${FUNCNAME}: Deploy a LXD Cluster via MAAS command line" | |
local CI_TZ='America/Los_Angeles' | |
local CI_LC='en_US.UTF-8' | |
# 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 | |
local CI_PKG_UPG=true | |
local CI_PKG_UPD=true | |
local ENABLE_GPU=false | |
local BASE_TAG="microcloud-lxd" | |
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 | |
) | |
maas-microcloud-lxd_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 -c, --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[20GPhysical disk 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 -h, --help\e[20GThis message\n" | |
printf "\n\n" | |
} | |
ARGS=$(getopt -o n:c:t:d:p:gdhHN -l count:,tag:,distro:,pool-device:,gpu,help,desc,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;; | |
--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 - LXD\e[0m\n\n" | |
printf -- " - Powered by \e[1m$(lsb_release -ds)\e[0m${OK}\n" | |
printf -- " - Provisioning by \e[1mMAAS $(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m${OK}\n" | |
printf -- " - Featuring \e[1mLXD $(snap info lxd|awk '/- </{print $2}') with clustering\e[0m${OK}\n" | |
[[ ${ENABLE_GPU} = true ]] && printf -- " -\e[1m GPGPU\e[0m Passthrough enabled\e[0m${OK}\n" | |
[[ -z ${MAAS_PROFILE} ]] && { read -srp "$(printf "Please enter your MAAS profile name: ")" MAAS_PROFILE_INPUT;local MAAS_PROFILE=$MAAS_PROFILE_INPUT; } | |
#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 not a physical disk, set storage pool to use a file | |
[[ ${STORAGE_POOL_TYPE} = device ]] && { printf "\e[3G- Storage Pool on Cluster Hosts will be using 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[2GAllocating the following Host${W} to the LXD 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 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 LXD_PRIMARY=${ALLOCATED_MACHINES[0]%%:*} | |
# 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) | |
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 | |
rm -rf /tmp/lxd_cluster_ssh_host* /tmp/lxd_cluster_user_ssh* | |
# 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 correct the stanza for disk or file based storage pool | |
[[ ${STORAGE_POOL_DEVICE} =~ dev || ${STORAGE_POOL_DEVICE} =~ sd ]] && local LXD_STORAGE_POOL=$(cat <<EOF | |
storage_pools: | |
- config: | |
source: ${STORAGE_POOL_DEVICE} | |
description: 'Default LXD Storage Pool' | |
name: local | |
driver: zfs | |
EOF | |
) | |
[[ ! ${STORAGE_POOL_DEVICE} =~ dev && ! ${STORAGE_POOL_DEVICE} =~ sd ]] && local LXD_STORAGE_POOL=$(cat <<EOF | |
storage_pools: | |
- config: | |
size: 100GB | |
source: /var/snap/lxd/common/lxd/disks/local.img | |
zfs.pool_name: local | |
description: "" | |
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[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 | |
if [[ ${ENABLE_GPU} = true ]];then | |
printf "\e[2G - Adding GPGPU Detection at the OS level using cloud-init...\n" | |
local CI_GPU_COMMANDS=" - echo Adding GPGPU Support | |
- if [ -n \$(lspci -nn|awk -vIGNORECASE=1 -F'[ \\\\]\\\\[]' '/\\[03/&&/nvidia/{print \$(NF-3)}') ];then lspci -nn|awk -vIGNORECASE=1 -F'[ \\\\]\\\\[]' '/\\[03/&&/nvidia/{printf \"export NVDA_GPU_%02d_ID=%s\nexport NVDA_GPU_%02d_BUS=%s\n\",NR,\$(NF-3),NR,\$1}'|tee -a /etc/gpgpu-pci-ids.conf;fi | |
- if [ -n \$(lspci -nn|awk -vIGNORECASE=1 -F'[ \\\\]\\\\[]' '/\\[03/&&/nvidia/{print \$(NF-3)}') ];then lspci -nn|awk -vIGNORECASE=1 -F'[ \\\\]\\\\[]' 'BEGIN {printf \"%s\",\"options vfio-pci ids=\"} /\\[03/&&/nvidia/{printf \"%s,\",\$(NF-3)} END {print \"\\n\"}'|sed 's/,$//'|tee /etc/modprobe.d/vfio.conf;fi | |
- if [ -n \$(lspci -nn|awk -vIGNORECASE=1 -F'[ \\\\]\\\\[]' '/\\[03/&&/nvidia/{print \$(NF-3)}') ];then printf 'vfio\nvfio_pci\n' > /etc/modules-load.d/vfio.conf;fi | |
" | |
fi | |
#Make LXD Image Script to preseed LXD Clusters image store | |
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 | |
) | |
#Make LXD Cluster Script and convert to base64 to include in cloud-init user-data | |
local LXD_CLUSTER_SCRIPT=$(cat <<EOF|base64 -w0 | |
#!/bin/bash | |
if [[ \$(hostname 2>/dev/null -s) = ${LXD_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: none | |
ipv6.nat: 'false' | |
name: lxdbr0 | |
type: bridge | |
${LXD_STORAGE_POOL} | |
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) != ${LXD_PRIMARY} ]];then | |
while [[ \$(sudo ssh 2>/dev/null -i /etc/ssh/ssh_host_rsa_key -tt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ubuntu@${LXD_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: ${LXD_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@${LXD_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 | |
) | |
local CI_USER_DATA=$(cat <<EOF|tee /tmp/${FUNCNAME}.cloud-init.yaml|base64 -w0 | |
#cloud-config | |
bootcmd: | |
- ip route add default via ${MAAS_IP} | |
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 | |
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) = ${LXD_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 GPU_CMD='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"' | |
- 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' | |
- 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' | |
- 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 | |
- touch /var/tmp/install-complete | |
${SSH_HOST_KEYS} | |
${SSH_PUB_KEYS} | |
EOF | |
) | |
#Remove old tags on redeployment | |
printf "\n\e[2GCleaning up any existing microcloud tags that these machines may have belonged to...\n" | |
printf '%s\n' ${ALLOCATED_MACHINES[@]##*:}|xargs -n1 -P0 bash -c 'maas 2>/dev/null ${MAAS_PROFILE} machine read $0|jq 2>/dev/null -r '"'"'.tag_names[]|select(startswith("'${BASE_TAG}'"))'"'"''|xargs -n1 -P0 maas 2>/dev/null ${MAAS_PROFILE} tag delete &>/dev/null | |
local MICROCLOUD_TAG="${BASE_TAG}-$(grep -m1 -oaE '[a-z0-9]{6}' /dev/random|head -n1)" | |
printf "\n\e[2GCreating tag \"${MICROCLOUD_TAG}\" for this microcloud...\n" | |
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 hosts to ${MICROCLOUD_TAG} :\n\n" | |
printf -- "\e[2G - %s\n" ${ALLOCATED_MACHINES[@]}|sed 's/:/ \(/g;s/.$/&\)/g';echo | |
local -a DEPLOYED_MACHINES=($(printf "%s\n" ${ALLOCATED_MACHINES[@]##*:}|xargs -I{} -n1 -P1 maas ${MAAS_PROFILE} machine deploy {} distro_series=${DISTRO} user_data=${CI_USER_DATA}|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" | |
microcloud-tag-cleanup ${BASE_TAG} ${MICROCLOUD_TAG} | |
} | |
export -f maas-microcloud-lxd | |
maas-microcloud-kvm() { | |
local DESC="${FUNCNAME}: Deploy a KVM Pods with Cloud-Init customizations via MAAS command line" | |
local CI_TZ='America/Los_Angeles' | |
local CI_LC='en_US.UTF-8' | |
# 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 | |
local CI_PKG_UPG=true | |
local CI_PKG_UPD=true | |
local BASE_TAG="microcloud-kvm" | |
local ENABLE_GPU=false | |
local STORAGE_POOL_DEVICE= | |
local STORAGE_POOL_TYPE=file | |
local ENFORCE_HA=true | |
local -a CI_PKG_LIST=( | |
apt-utils | |
build-essential | |
debconf-utils | |
jq | |
libvirt-daemon-driver-storage-zfs | |
libvirt-daemon-system | |
ovmf | |
squashfuse | |
virtinst | |
virt-manager | |
zfsutils | |
) | |
maas-microcloud-kvm_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 -c, --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[20GPhysical disk 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 -h, --help\e[20GThis message\n" | |
printf "\n\n" | |
} | |
ARGS=$(getopt -o n:c:t:d:p:gdhHN -l count:,tag:,distro:,pool-device:,gpu,help,desc,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;; | |
--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- Powered by \e[1m$(lsb_release -ds)\e[0m${OK}\n" | |
printf -- "\e[3G- Provisioning by \e[1mMAAS $(dpkg-query -s maas|grep -oP '(?<=Version: )[^~]+')\e[0m${OK}\n" | |
printf -- "\e[3G- Featuring \e[1mKVM Pods \e[0m${OK}\n" | |
[[ ${ENABLE_GPU} = true ]] && printf -- " -\e[1m GPGPU\e[0m Passthrough enabled\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)) | |
[[ ${ENFORCE_HA} = true ]] && { local COUNT=3;printf "\e[3G- Enforcing n+2 Node count\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/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 | |
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[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 | |
local CI_USER_DATA=$(cat <<EOF|tee /tmp/${FUNCNAME}.cloud-init.yaml|base64 -w0 | |
#cloud-config-2 | |
bootcmd: | |
- ip route add default via 172.27.21.254 | |
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 | |
package_update: ${CI_PKG_UPD} | |
package_upgrade: ${CI_PKG_UPG} | |
${CI_PACKAGES} | |
${SSH_PUB_KEYS} | |
runcmd: | |
- set -x | |
- mkdir -p /home/virsh/bin | |
- ln -s /usr/bin/virsh /home/virsh/bin/virsh | |
- sh -c echo 'PATH=/home/virsh/bin' >> /home/virsh/.bashrc | |
- sh -c printf "Match user virsh\\n X11Forwarding no\\n AllowTcpForwarding no\\n PermitTTY no\\n ForceCommand nc -q 0 -U /var/run/libvirt/libvirt-sock\\n" >> /etc/ssh/sshd_config | |
- /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 GPU_CMD='lspci -nn|awk -vIGNORECASE=1 '"'"'/\[03.*intel/{ORS=",";print substr(\$(NF-2),2,9)}'"'"'|sed "s/,$/\\n/"' | |
- 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' | |
- 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' | |
- 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 | |
- zpool create local /dev/sdb | |
- zfs create local/maas | |
- zfs set dedup=on local | |
- zfs set compression=on local | |
- |- | |
virsh pool-define /dev/stdin <<EOF | |
<pool type="zfs"> | |
<name>maas-zfs</name> | |
<source> | |
<name>local</name> | |
<device path="/dev/sdb"/> | |
</source> | |
</pool> | |
EOF | |
- virsh pool-start maas-zfs | |
- virsh pool-autostart maas-zfs | |
- touch /var/tmp/install-complete | |
EOF | |
) | |
#Remove old tags on redeployment | |
printf "\n\e[2GCleaning up any existing microcloud tags previously assigned host${W}...\n" | |
printf '%s\n' ${ALLOCATED_MACHINES[@]##*:}|xargs -n1 -P0 bash -c 'maas 2>/dev/null ${MAAS_PROFILE} machine read $0|jq 2>/dev/null -r '"'"'.tag_names[]|select(startswith("'${BASE_TAG}'"))'"'"''|xargs -n1 -P0 maas 2>/dev/null ${MAAS_PROFILE} tag delete &>/dev/null | |
local MICROCLOUD_TAG="${BASE_TAG}-$(grep -m1 -oaE '[a-z0-9]{6}' /dev/random|head -n1)" | |
printf "\n\e[2GCreating tag \"${MICROCLOUD_TAG}\" for this microcloud...\n" | |
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 DEPLOYED_MACHINES=($(printf "%s\n" ${ALLOCATED_MACHINES[@]##*:}|xargs -I{} -n1 -P1 maas ${MAAS_PROFILE} machine deploy {} install_kvm=true distro_series=${DISTRO} user_data=${CI_USER_DATA}|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" | |
microcloud-tag-cleanup ${BASE_TAG} ${MICROCLOUD_TAG} | |
} | |
export -f maas-microcloud-lxd | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment