#!/usr/bin/env bash # # This file is part of the KubeVirt project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Copyright 2023 Red Hat, Inc. # # This script is based on: # - https://github.com/ovn-org/ovn-kubernetes/blob/master/contrib/kind.sh # - https://github.com/kiagnose/kiagnose/blob/main/automation/e2e.sh # - https://github.com/kiagnose/kiagnose/blob/main/checkups/kubevirt-vm-latency/automation/e2e.sh ARGCOUNT=$# # Returns the full directory name of the script DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" ARCH="" case $(uname -m) in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; esac set_default_params() { BIN_DIR=${BIN_DIR:-$DIR/../bin} KIND=${KIND:-$BIN_DIR/kind} KIND_VERSION=${KIND_VERSION:-v0.20.0} KUBECTL=${KUBECTL:-$BIN_DIR/kubectl} KUBECTL_VERSION=${KUBECTL_VERSION:-v1.27.3} KUBEVIRT_VERSION=${KUBEVIRT_VERSION:-v1.0.0} KUBEVIRT_COMMON_INSTANCETYPES_VERSION=${KUBEVIRT_COMMON_INSTANCETYPES_VERSION:-v0.3.0} KUBEVIRT_USE_EMULATION=${KUBEVIRT_USE_EMULATION:-"false"} CNAO_VERSION=${CNAO_VERSION:-v0.87.0} CLUSTER_NAME=${CLUSTER_NAME:-kind} SECONDARY_NETWORK_NAME=${NETWORK_NAME:-kindexgw} SECONDARY_NETWORK_SUBNET=${SECONDARY_NETWORK_SUBNET:-172.19.0.0/16} SECONDARY_NETWORK_RANGE_START=${SECONDARY_NETWORK_RANGE_START:-172.19.1.1} SECONDARY_NETWORK_RANGE_END=${SECONDARY_NETWORK_RANGE_END:-172.19.255.254} SECONDARY_NETWORK_GATEWAY=${SECONDARY_NETWORK_GATEWAY:-172.19.0.1} NAMESPACE=${NAMESPACE:-default} } # Taken from: # https://github.com/kubevirt/kubevirtci/blob/f661bfe0e3678e5409c057855951c50a912571a0/cluster-up/cluster/ephemeral-provider-common.sh#L26C1-L45C1 detect_cri() { PODMAN_SOCKET=${PODMAN_SOCKET:-"/run/podman/podman.sock"} if [ "${CRI}" = "podman" ]; then _cri_socket=$(detect_podman_socket) _cri_bin="podman --remote --url=unix://$_cri_socket" elif [ "${CRI}" = "docker" ]; then _cri_bin=docker _cri_socket="/var/run/docker.sock" else _cri_socket=$(detect_podman_socket) if [ -n "$_cri_socket" ]; then _cri_bin="podman --remote --url=unix://$_cri_socket" echo >&2 "selecting podman as container runtime" elif docker ps >/dev/null 2>&1; then _cri_bin=docker _cri_socket="/var/run/docker.sock" echo >&2 "selecting docker as container runtime" else echo >&2 "no working container runtime found. Neither docker nor podman seems to work." exit 1 fi fi } # Taken from: # https://github.com/kubevirt/kubevirtci/blob/f661bfe0e3678e5409c057855951c50a912571a0/cluster-up/cluster/ephemeral-provider-common.sh#L20 detect_podman_socket() { if curl --unix-socket "${PODMAN_SOCKET}" http://d/v3.0.0/libpod/info >/dev/null 2>&1; then echo "${PODMAN_SOCKET}" fi } install_kind() { if [ ! -f "${KIND}" ]; then echo "Installing kind" mkdir -p "${BIN_DIR}" curl -Lo "${KIND}" "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-${ARCH}" chmod +x "${KIND}" echo "Successfully installed kind at ${KIND}:" ${KIND} version fi } install_kubectl() { if [ ! -f "${KUBECTL}" ]; then echo "Installing kubectl" mkdir -p "${BIN_DIR}" curl -Lo "${KUBECTL}" "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl" chmod +x "${KUBECTL}" echo "Successfully installed kubectl at ${KUBECTL}:" ${KUBECTL} version --client fi } configure_inotify_limits() { echo "Configuring inotify limits" sudo sysctl fs.inotify.max_user_instances=512 sudo sysctl fs.inotify.max_user_watches=1048576 } create_cluster() { echo "Creating cluster with kind" DOCKER_HOST=unix://${_cri_socket} ${KIND} create cluster --wait 2m --name "${CLUSTER_NAME}" echo "Waiting for the network to be ready" ${KUBECTL} wait --for=condition=ready pods --namespace=kube-system -l k8s-app=kube-dns --timeout=2m echo "K8S cluster is up:" ${KUBECTL} get nodes -o wide } configure_secondary_network() { echo "Configuring secondary network" # Name of the single kind node local node=${CLUSTER_NAME}-control-plane # Interface added when connecting the secondary network local secondary_interface=eth1 ${_cri_bin} network create "${SECONDARY_NETWORK_NAME}" --driver=bridge --subnet="${SECONDARY_NETWORK_SUBNET}" ${_cri_bin} network connect "${SECONDARY_NETWORK_NAME}" "${node}" # Get the ip address assigned to the interface of the secondary network on the node local ip ip=$( ${_cri_bin} exec "${node}" ip ad show dev "${secondary_interface}" scope global | sed -n 's/^ inet \([[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\.[[:digit:]]\{1,3\}\/[[:digit:]]\{1,2\}\).*$/\1/p' ) # Configure a bridge inside the node that workloads can attach to ${_cri_bin} exec "${node}" ip link add "${SECONDARY_NETWORK_NAME}" type bridge ${_cri_bin} exec "${node}" ip link set "${secondary_interface}" master "${SECONDARY_NETWORK_NAME}" ${_cri_bin} exec "${node}" ip link set up "${SECONDARY_NETWORK_NAME}" # Move the ip address from the secondary interface to the newly created bridge ${_cri_bin} exec "${node}" ip address del "${ip}" dev "${secondary_interface}" ${_cri_bin} exec "${node}" ip address add "${ip}" dev "${SECONDARY_NETWORK_NAME}" } deploy_kubevirt() { echo "Deploying KubeVirt" ${KUBECTL} apply -f "https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml" ${KUBECTL} apply -f "https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml" if ! is_nested_virt_enabled; then echo "Configuring Kubevirt to use emulation" ${KUBECTL} patch kubevirt kubevirt --namespace kubevirt --type=merge --patch '{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}' fi echo "Waiting for KubeVirt to be ready" ${KUBECTL} wait --for=condition=Available kubevirt kubevirt --namespace=kubevirt --timeout=5m echo "Successfully deployed KubeVirt:" ${KUBECTL} get pods -n kubevirt } # Taken from: # https://github.com/ovn-org/ovn-kubernetes/blob/59e0b62f4048be3df5b364b894b495f52f729cf1/contrib/kind.sh#L1241 is_nested_virt_enabled() { local kvm_nested="unknown" if [ -f "/sys/module/kvm_intel/parameters/nested" ]; then kvm_nested=$(cat /sys/module/kvm_intel/parameters/nested) elif [ -f "/sys/module/kvm_amd/parameters/nested" ]; then kvm_nested=$(cat /sys/module/kvm_amd/parameters/nested) fi [ "$kvm_nested" == "1" ] || [ "$kvm_nested" == "Y" ] || [ "$kvm_nested" == "y" ] } deploy_kubevirt_common_instancetypes() { echo "Deploying KubeVirt common-instancetypes" ${KUBECTL} apply -f "https://github.com/kubevirt/common-instancetypes/releases/download/${KUBEVIRT_COMMON_INSTANCETYPES_VERSION}/common-instancetypes-all-bundle-${KUBEVIRT_COMMON_INSTANCETYPES_VERSION}.yaml" } deploy_cnao() { echo "Deploying CNAO (with multus and bridge CNIs)" ${KUBECTL} apply -f "https://github.com/kubevirt/cluster-network-addons-operator/releases/download/${CNAO_VERSION}/namespace.yaml" ${KUBECTL} apply -f "https://github.com/kubevirt/cluster-network-addons-operator/releases/download/${CNAO_VERSION}/network-addons-config.crd.yaml" ${KUBECTL} apply -f "https://github.com/kubevirt/cluster-network-addons-operator/releases/download/${CNAO_VERSION}/operator.yaml" cat <