#!/usr/bin/env bash # Copyright (c) 2019 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 # set -o errexit set -o pipefail set -o nounset crio_drop_in_conf_dir="/etc/crio/crio.conf.d/" crio_drop_in_conf_file="${crio_drop_in_conf_dir}/99-kata-deploy" crio_drop_in_conf_file_debug="${crio_drop_in_conf_dir}/100-debug" containerd_conf_file="/etc/containerd/config.toml" containerd_conf_file_backup="${containerd_conf_file}.bak" IFS=' ' read -a shims <<< "$SHIMS" default_shim="$DEFAULT_SHIM" # If we fail for any reason a message will be displayed die() { msg="$*" echo "ERROR: $msg" >&2 exit 1 } function host_systemctl() { nsenter --target 1 --mount systemctl "${@}" } function print_usage() { echo "Usage: $0 [install/cleanup/reset]" } function create_runtimeclasses() { echo "Creating the runtime classes" for shim in "${shims[@]}"; do echo "Creating the kata-${shim} runtime class" kubectl apply -f /opt/kata-artifacts/runtimeclasses/kata-${shim}.yaml done if [[ "${CREATE_DEFAULT_RUNTIMECLASS}" == "true" ]]; then echo "Creating the kata runtime class for the default shim (an alias for kata-${default_shim})" cp /opt/kata-artifacts/runtimeclasses/kata-${default_shim}.yaml /tmp/kata.yaml sed -i -e 's/name: kata-'${default_shim}'/name: kata/g' /tmp/kata.yaml kubectl apply -f /tmp/kata.yaml rm -f /tmp/kata.yaml fi } function delete_runtimeclasses() { echo "Deleting the runtime classes" for shim in "${shims[@]}"; do echo "Deleting the kata-${shim} runtime class" kubectl delete -f /opt/kata-artifacts/runtimeclasses/kata-${shim}.yaml done if [[ "${CREATE_DEFAULT_RUNTIMECLASS}" == "true" ]]; then echo "Deleting the kata runtime class for the default shim (an alias for kata-${default_shim})" cp /opt/kata-artifacts/runtimeclasses/kata-${default_shim}.yaml /tmp/kata.yaml sed -i -e 's/name: kata-'${default_shim}'/name: kata/g' /tmp/kata.yaml kubectl delete -f /tmp/kata.yaml rm -f /tmp/kata.yaml fi } function get_container_runtime() { local runtime=$(kubectl get node $NODE_NAME -o jsonpath='{.status.nodeInfo.containerRuntimeVersion}') if [ "$?" -ne 0 ]; then die "invalid node name" fi if echo "$runtime" | grep -qE "cri-o"; then echo "cri-o" elif echo "$runtime" | grep -qE 'containerd.*-k3s'; then if host_systemctl is-active --quiet rke2-agent; then echo "rke2-agent" elif host_systemctl is-active --quiet rke2-server; then echo "rke2-server" elif host_systemctl is-active --quiet k3s-agent; then echo "k3s-agent" else echo "k3s" fi # Note: we assumed you used a conventional k0s setup and k0s will generate a systemd entry k0scontroller.service and k0sworker.service respectively # and it is impossible to run this script without a kubelet, so this k0s controller must also have worker mode enabled elif host_systemctl is-active --quiet k0scontroller; then echo "k0s-controller" elif host_systemctl is-active --quiet k0sworker; then echo "k0s-worker" else echo "$runtime" | awk -F '[:]' '{print $1}' fi } function install_artifacts() { echo "copying kata artifacts onto host" cp -au /opt/kata-artifacts/opt/kata/* /opt/kata/ chmod +x /opt/kata/bin/* [ -d /opt/kata/runtime-rs/bin ] && \ chmod +x /opt/kata/runtime-rs/bin/* # Allow enabling debug for Kata Containers if [[ "${DEBUG}" == "true" ]]; then config_path="/opt/kata/share/defaults/kata-containers/" for shim in "${shims[@]}"; do sed -i -e 's/^#\(enable_debug\).*=.*$/\1 = true/g' "${config_path}/configuration-${shim}.toml" sed -i -e 's/^#\(debug_console_enabled\).*=.*$/\1 = true/g' "${config_path}/configuration-${shim}.toml" sed -i -e 's/^kernel_params = "\(.*\)"/kernel_params = "\1 agent.log=debug initcall_debug"/g' "${config_path}/configuration-${shim}.toml" done fi # Allow Mariner to use custom configuration. if [ "${HOST_OS:-}" == "cbl-mariner" ]; then config_path="/opt/kata/share/defaults/kata-containers/configuration-clh.toml" clh_path="/opt/kata/bin/cloud-hypervisor-glibc" sed -i -E 's|(enable_annotations) = .+|\1 = ["enable_iommu", "initrd", "kernel"]|' "${config_path}" sed -i -E "s|(valid_hypervisor_paths) = .+|\1 = [\"${clh_path}\"]|" "${config_path}" sed -i -E "s|(path) = \".+/cloud-hypervisor\"|\1 = \"${clh_path}\"|" "${config_path}" fi if [[ "${CREATE_RUNTIMECLASSES}" == "true" ]]; then create_runtimeclasses fi } function wait_till_node_is_ready() { local ready="False" while ! [[ "${ready}" == "True" ]]; do sleep 2s ready=$(kubectl get node $NODE_NAME -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}') done } function configure_cri_runtime() { configure_different_shims_base case $1 in crio) configure_crio ;; containerd | k3s | k3s-agent | rke2-agent | rke2-server | k0s-controller | k0s-worker) configure_containerd "$1" ;; esac if [ "$1" == "k0s-worker" ] || [ "$1" == "k0s-controller" ]; then # do nothing, k0s will automatically load the config on the fly : else host_systemctl daemon-reload host_systemctl restart "$1" fi wait_till_node_is_ready } function backup_shim() { local shim_file="$1" local shim_backup="${shim_file}.bak" if [ -f "${shim_file}" ]; then echo "warning: ${shim_file} already exists" >&2 if [ ! -f "${shim_backup}" ]; then mv "${shim_file}" "${shim_backup}" else rm -f "${shim_file}" fi fi } function configure_different_shims_base() { # Currently containerd has an assumption on the location of the shimv2 implementation # This forces kata-deploy to create files in a well-defined location that's part of # the PATH, pointing to the containerd-shim-kata-v2 binary in /opt/kata/bin # Issues: # https://github.com/containerd/containerd/issues/3073 # https://github.com/containerd/containerd/issues/5006 local default_shim_file="/usr/local/bin/containerd-shim-kata-v2" mkdir -p /usr/local/bin for shim in "${shims[@]}"; do local shim_binary="containerd-shim-kata-${shim}-v2" local shim_file="/usr/local/bin/${shim_binary}" backup_shim "${shim_file}" if [[ "${shim}" == "dragonball" ]]; then ln -sf /opt/kata/runtime-rs/bin/containerd-shim-kata-v2 "${shim_file}" else ln -sf /opt/kata/bin/containerd-shim-kata-v2 "${shim_file}" fi chmod +x "$shim_file" if [ "${shim}" == "${default_shim}" ]; then backup_shim "${default_shim_file}" echo "Creating the default shim-v2 binary" ln -sf "${shim_file}" "${default_shim_file}" fi done } function restore_shim() { local shim_file="$1" local shim_backup="${shim_file}.bak" if [ -f "${shim_backup}" ]; then mv "$shim_backup" "$shim_file" fi } function cleanup_different_shims_base() { local default_shim_file="/usr/local/bin/containerd-shim-kata-v2" for shim in "${shims[@]}"; do local shim_binary="containerd-shim-kata-${shim}-v2" local shim_file="/usr/local/bin/${shim_binary}" rm -f "${shim_file}" restore_shim "${shim_file}" done rm -f "${default_shim_file}" restore_shim "${default_shim_file}" if [[ "${CREATE_RUNTIMECLASSES}" == "true" ]]; then delete_runtimeclasses fi } function configure_crio_runtime() { local runtime="kata" local configuration="configuration" if [ -n "${1-}" ]; then runtime+="-$1" configuration+="-$1" fi local kata_path="/usr/local/bin/containerd-shim-${runtime}-v2" local kata_conf="crio.runtime.runtimes.${runtime}" local kata_config_path="/opt/kata/share/defaults/kata-containers/$configuration.toml" cat <" $containerd_conf_file || [ "$1" == "k0s-worker" ] || [ "$1" == "k0s-controller" ]; then pluginid=\"io.containerd.grpc.v1.cri\" fi local runtime_table="plugins.${pluginid}.containerd.runtimes.$runtime" local runtime_type="io.containerd.$runtime.v2" local options_table="$runtime_table.options" local config_path="/opt/kata/share/defaults/kata-containers/$configuration.toml" if grep -q "\[$runtime_table\]" $containerd_conf_file; then echo "Configuration exists for $runtime_table, overwriting" sed -i "/\[$runtime_table\]/,+1s#runtime_type.*#runtime_type = \"${runtime_type}\"#" $containerd_conf_file else cat < "$containerd_conf_file" fi fi action=${1:-} if [ -z "$action" ]; then print_usage die "invalid arguments" fi # only install / remove / update if we are dealing with CRIO or containerd if [[ "$runtime" =~ ^(crio|containerd|k3s|k3s-agent|rke2-agent|rke2-server|k0s-worker|k0s-controller)$ ]]; then case "$action" in install) install_artifacts configure_cri_runtime "$runtime" kubectl label node "$NODE_NAME" --overwrite katacontainers.io/kata-runtime=true ;; cleanup) cleanup_cri_runtime "$runtime" kubectl label node "$NODE_NAME" --overwrite katacontainers.io/kata-runtime=cleanup remove_artifacts ;; reset) reset_runtime $runtime ;; *) echo invalid arguments print_usage ;; esac fi #It is assumed this script will be called as a daemonset. As a result, do # not return, otherwise the daemon will restart and rexecute the script sleep infinity } main "$@"