#!/bin/bash set -aeou pipefail SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" function printHelp(){ cat << EOF Usage ${0##*/} [options..] -h,-?, --help Show help and exit -s, --salt run a masterless salt-call -y, --yes answer 'yes' on all questions -t, --tools Install/update tools (kubectl, helm, etc) -r, --rancher Install rancher server VM --rmt-sync Sync database with SUSE Customer Center --rmt-enable-products Enable all preconfigured repositories --rmt-mirror Mirror repositories EOF } function asktobreak(){ if [[ "$ANSWER_YES" == true ]];then printf "\n" return 1 fi printf "Do you want to run this step (y/n)" while read -r -n 1 -s answer; do if [[ $answer == [YyNn] ]];then [[ $answer == [Yy] ]] && return_value=1 [[ $answer == [Nn] ]] && return_value=0 printf "\n" break; fi done return $return_value } function new_log(){ # script output printf "\n**** [%s] ***\n" "$*" } function log(){ printf "%s\n" "$*" } function parse_yaml() { # ripped from https://gist.github.com/pkuczynski/8665367#gistcomment-2174214 local yaml_file=$1 local prefix=$2 local s local w local fs s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs="$(echo @|tr @ '\034')" ( sed -ne 's/--//g; s/\"/\\\"/g; s/\#.*//g; s/\s*$//g;' \ -e "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ -e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" | awk -F"$fs" '{ indent = length($1)/2; if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";} vname[indent] = $2; for (i in vname) {if (i > indent) {delete vname[i]}} if (length($3) > 0) { vn=""; for (i=0; i /dev/null 2>&1 RESULT=$? if [[ $RESULT != 0 ]];then printf "$1 is not installed, do your want to install it [y/N]?" read -r -n 1 -s answer; printf "\n" if [[ $answer == [yY] ]];then sudo zypper --non-interactive install "$1" fi fi set -e } function do_salt_call(){ local salt="sudo salt-call --local --file-root $SCRIPTDIR/salt/states --pillar-root $SCRIPTDIR/salt/pillars --module-dirs=$SCRIPTDIR/salt/modules" new_log "Running salt high state" if asktobreak;then return fi $salt state.apply pillar="{username: $USER}" } function rmt_sync(){ new_log "Sync RMT Database with SUSE Customer Center" if asktobreak; then return fi sudo rmt-cli sync } function rmt_enable_products(){ new_log "Enable the following products in RMT?" eval $(parse_yaml $SCRIPTDIR/salt/pillars/rmt.sls "SALT_") if [[ -f salt/pillars/local.sls ]];then eval $(parse_yaml $SCRIPTDIR/salt/pillars/local.sls "SALT_") fi for name in "${SALT_rmt_products__name[@]}"; do echo " * $name" done if asktobreak; then return fi sudo rmt-cli products enable "${SALT_rmt_products__id[*]}" } function rmt_mirror(){ new_log "Mirror all repositories" if asktobreak; then return fi sudo rmt-cli mirror all } function install_tools(){ new_log "Install client tools" echo "- kubectl" echo "- helm" echo "- stern" echo "- virtctl" if asktobreak; then return fi set +e echo "---- kubectl ----" cd $HOME/bin if [[ -f kubectl ]]; then KUBECTL_CURRENT=$(./kubectl version --client 2> /dev/null| sed -n 's/.* GitVersion:"\(v[0-9]*\.[0-9]*\.[0-9]*\)".*/\1/p') else KUBECTL_CURRENT="N/A" fi KUBECTL_STABLE="$(curl -L -s https://dl.k8s.io/release/stable.txt)" echo "Installed version: $KUBECTL_CURRENT" echo "Latest stable version: $KUBECTL_STABLE" if [[ "$KUBECTL_CURRENT" != "$KUBECTL_STABLE" ]]; then echo "updating to $KUBECTL_STABLE" curl -LO https://dl.k8s.io/release/$KUBECTL_STABLE/bin/linux/amd64/kubectl chmod +x kubectl fi echo "" echo "---- helm ----" if [[ -f helm ]]; then HELM_CURRENT=$(./helm version | sed -n 's/.*Version:"\(v[0-9]*\.[0-9]*\.[0-9]*\)".*/\1/p') else HELM_CURRENT="N/A" fi HELM_STABLE="$(curl -Ls https://github.com/helm/helm/releases | egrep 'href="/helm/helm/releases/tag/v[0-9]+.[0-9]+.[0-9]+\"' | head -n 1 | sed -n 's/.*tag\/\(v.*\)" data.*/\1/p')" echo "Installed version: $HELM_CURRENT" echo "Latest stable version: $HELM_STABLE" if [[ "$HELM_CURRENT" != "$HELM_STABLE" ]]; then echo "updating to $HELM_STABLE" curl -LO https://get.helm.sh/helm-$HELM_STABLE-linux-amd64.tar.gz tar xvzf helm-$HELM_STABLE-linux-amd64.tar.gz --strip-components=1 linux-amd64/helm rm helm-$HELM_STABLE-linux-amd64.tar.gz fi echo "" echo "---- stern ----" if [[ -f stern ]]; then STERN_CURRENT="v$(./stern -v | head -n1 | cut -d " " -f2)" else STERN_CURRENT="N/A" fi STERN_STABLE="$(curl -Ls https://github.com/stern/stern/releases | egrep 'href="/stern/stern/releases/tag/v[0-9]+.[0-9]+.[0-9]+*\"' | head -n 1 | sed -n 's/.*tag\/\(v.*\)" data.*/\1/p')" echo "Installed version: $STERN_CURRENT" echo "Latest stable version: $STERN_STABLE" if [[ "$STERN_CURRENT" != "$STERN_STABLE" ]]; then echo "updating to $STERN_STABLE" curl -LO https://github.com/stern/stern/releases/download/$STERN_STABLE/stern_${STERN_STABLE:1}_linux_amd64.tar.gz tar xvzf stern_${STERN_STABLE:1}_linux_amd64.tar.gz --strip-components=1 stern_${STERN_STABLE:1}_linux_amd64/stern rm stern_${STERN_STABLE:1}_linux_amd64.tar.gz fi echo "" echo "---- virtctl ----" if [[ -f stern ]]; then VIRTCTL_CURRENT="$(./virtctl version --client 2> /dev/null| sed -n 's/.*GitVersion:"\(v[0-9]*\.[0-9]*\.[0-9]*\)".*/\1/p')" else VIRTCTL_CURRENT="N/A" fi VIRTCTL_STABLE="$(curl -Ls https://github.com/kubevirt/kubevirt/releases | egrep 'href="/kubevirt/kubevirt/releases/tag/v[0-9]+.[0-9]+.[0-9]+*\"' | head -n 1 | sed -n 's/.*tag\/\(v.*\)" data.*/\1/p')" echo "Installed version: $VIRTCTL_CURRENT" echo "Latest stable version: $VIRTCTL_STABLE" if [[ "$VIRTCTL_CURRENT" != "$VIRTCTL_STABLE" ]]; then echo "updating to $VIRTCTL_STABLE" curl -Lo virtctl https://github.com/kubevirt/kubevirt/releases/download/$VIRTCTL_STABLE/virtctl-$VIRTCTL_STABLE-linux-amd64 chmod +x ./virtctl fi echo "" set -e } function install_rancher_vm(){ new_log "Install rancher vm" if asktobreak; then return fi systemctl is-active libvirtd --quiet || ( echo "libvirtd is not running...."; return 1) if sudo virsh list --all | grep -q "rancher";then echo "rancher VM already installed..." return 0 fi eval $(parse_yaml $SCRIPTDIR/salt/pillars/network.sls "SALT_") eval $(parse_yaml $SCRIPTDIR/salt/pillars/rancher.sls "SALT_") eval $(parse_yaml $SCRIPTDIR/salt/pillars/ssh.sls "SALT_") eval $(parse_yaml $SCRIPTDIR/salt/pillars/local.sls "SALT_") # Download openSUSE MicroOS image if sudo test ! -f /var/lib/libvirt/images/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2;then echo "Downloading MicroOS" curl -Lo /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2 http://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2 curl -Lo /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256 http://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256 cd /tmp/ echo "checking sha256sum" if ! echo "$(cat /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2.sha256 | cut -f 1 -d " ") openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2" | sudo sha256sum --check --status;then echo "sha256sum doesn't match on openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2" exit 1 fi echo "Moving image file to /var/lib/libvirt/images" sudo mv /tmp/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2 /var/lib/libvirt/images/ fi # Create the Butane config file if [[ -f $HOME/rancherVM.yaml ]]; then echo "rancher butane file already exists" else SSH_PUB_KEYS="" for i in "${SALT_ssh_user_pub_keys[@]}"; do if [[ "$i" != "[]" ]];then SSH_PUB_KEYS="$SSH_PUB_KEYS - $i\n" fi done cat << EOF >> $HOME/rancherVM.yaml variant: fcos version: 1.0.0 passwd: users: - name: root ssh_authorized_keys: $(echo -e "$SSH_PUB_KEYS") password_hash: "$(echo ${SALT_rancher_bootstrapPassword} | mkpasswd --method=SHA-512 --stdin)" storage: files: - path: /etc/sysconfig/network/ifcfg-eth0 mode: 0600 overwrite: true contents: inline: | BOOTPROTO='static' STARTMODE='auto' BROADCAST='' ETHTOOL_OPTIONS='' IPADDR='${SALT_network_ip%.*}.${SALT_network_hosts_rancher}/24' MTU='' NAME='' NETWORK='' REMOTE_IPADDR='' ZONE=internal - path: /etc/sysconfig/network/routes mode: 0644 overwrite: true contents: inline: | default ${SALT_network_ip} - - - path: /etc/rancher/k3s/registries.yaml mode: 0600 contents: inline: | mirrors: docker.io: endpoint: - "http://${SALT_network_ip}:5000" - path: /etc/hostname mode: 0644 overwrite: true contents: inline: | rancher.${SALT_network_domain} EOF # Create the ignition file fi if [[ -f $HOME/rancherVM.ign ]];then echo "rancher ignition file already exists" else sudo podman run -i --rm quay.io/coreos/fcct:release --pretty --strict < $HOME/rancherVM.yaml > $HOME/rancherVM.ign fi #create the rancher VM sudo virt-install --import --connect qemu:///system \ --name rancher \ --ram "${SALT_rancher_ram}" \ --vcpus "$SALT_rancher_vcpus" \ --disk size=20,backing_store=/var/lib/libvirt/images/openSUSE-MicroOS.x86_64-ContainerHost-kvm-and-xen.qcow2,bus=virtio \ --os-variant=opensusetumbleweed \ --network bridge=br0,model=virtio,mac=E8:01:F0:52:2E:E2\ --noautoconsole \ --graphics spice,listen=127.0.0.1 \ --qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$HOME/rancherVM.ign" printf "%s" "Waiting for rancher VM ssh to come up" while ! nc -z rancher."${SALT_network_domain}" 22 &> /dev/null; do printf "%c" "." sleep 1 done printf "\nAdding rancher VM into ssh known_hosts\n" ssh-keyscan -H "rancher.${SALT_network_domain}" >> $HOME/.ssh/known_hosts ssh-keyscan -H "${SALT_network_ip%.*}.${SALT_network_hosts_rancher}" >> $HOME/.ssh/known_hosts echo "Setting DNS server" ssh root@rancher."${SALT_network_domain}" sed -i "s/^NETCONFIG_DNS_STATIC_SERVERS=\"\"/NETCONFIG_DNS_STATIC_SERVERS=\"${SALT_network_ip}\"/" /etc/sysconfig/network/config #TODO: need to reboot guest for some reason, stop answering to ping in this stage #TODO: need to investigate why echo "Reboot rancher VM" sudo virsh destroy rancher sleep 5 sudo virsh start rancher printf "%s" "Waiting for rancher VM ssh to come up" while ! nc -z rancher."${SALT_network_domain}" 22 &> /dev/null; do printf "%c" "." sleep 1 done echo "Installing k3s" ssh root@rancher."${SALT_network_domain}" 'bash -c "curl -sfL https://get.k3s.io | sh -"' echo "Waiting for k3s to be healthy" ssh root@rancher."${SALT_network_domain}" 'bash -c "while ! kubectl get cs &> /dev/null;do sleep 1; done"' } ######################### # # Main Script # ######################## #initialize all options ALL=true SALT=false ANSWER_YES=false RMT_SYNC=false RMT_MIRROR=false RMT_ENABLE_PRODUCTS=false INSTALL_TOOLS=false RANCHER=false while :; do case ${1-noop} in -h|-\?|--help) printHelp exit ;; -s|--salt) SALT=true ALL=false ;; -y|--yes) ANSWER_YES=true ;; -r|--rancher) RANCHER=true ALL=false ;; --rmt-sync) RMT_SYNC=true ALL=false ;; --rmt-mirror) RMT_MIRROR=true ALL=false ;; --rmt-enable-products) RMT_ENABLE_PRODUCTS=true ALL=false ;; -t|--tools) INSTALL_TOOLS=true ALL=false ;; --) #End of all options shift break ;; -?*) printf "'%s' is not a valid option\n" "$1" >&2 exit 1 ;; *) #Break out of case, no more options break esac shift done for cmd in git salt-minion curl;do check_prerequisites "$cmd" done [[ $ALL == true ]] || [[ $SALT == true ]] && do_salt_call [[ $ALL == true ]] || [[ $RMT_SYNC == true ]] && rmt_sync [[ $ALL == true ]] || [[ $RMT_ENABLE_PRODUCTS == true ]] && rmt_enable_products [[ $ALL == true ]] || [[ $RMT_MIRROR == true ]] && rmt_mirror [[ $ALL == true ]] || [[ $INSTALL_TOOLS == true ]] && install_tools [[ $ALL == true ]] || [[ $RANCHER == true ]] && install_rancher_vm printf "\n DONE!!!!!!!\n"