#!/bin/sh set -eu ARG0="$0" BASE="/run/rootless-cni-infra" wait_unshare_net() { pid="$1" # NOTE: busybox shell doesn't support the `for ((i=0; i < $MAX; i++)); do foo; done` statement i=0 while :; do if [ "$(readlink /proc/self/ns/net)" != "$(readlink /proc/${pid}/ns/net)" ]; then break fi sleep 0.1 if [ $i -ge 10 ]; then echo >&2 "/proc/${pid}/ns/net cannot be unshared" exit 1 fi i=$((i + 1)) done } # CLI subcommand: "alloc $CONTAINER_ID $NETWORK_NAME $POD_NAME" cmd_entrypoint_alloc() { if [ "$#" -ne 3 ]; then echo >&2 "Usage: $ARG0 alloc CONTAINER_ID NETWORK_NAME POD_NAME" exit 1 fi ID="$1" NET="$2" K8S_POD_NAME="$3" dir="${BASE}/${ID}" mkdir -p "${dir}/attached" "${dir}/attached-args" pid="" if [ -f "${dir}/pid" ]; then pid=$(cat "${dir}/pid") else unshare -n sleep infinity & pid="$!" wait_unshare_net "${pid}" echo "${pid}" >"${dir}/pid" nsenter -t "${pid}" -n ip link set lo up fi CNI_ARGS="IgnoreUnknown=1;K8S_POD_NAME=${K8S_POD_NAME}" nwcount=$(find "${dir}/attached" -type f | wc -l) CNI_IFNAME="eth${nwcount}" export CNI_ARGS CNI_IFNAME cnitool add "${NET}" "/proc/${pid}/ns/net" >"${dir}/attached/${NET}" echo "${CNI_ARGS}" >"${dir}/attached-args/${NET}" # return the result ns="/proc/${pid}/ns/net" echo "{\"ns\":\"${ns}\"}" } # CLI subcommand: "dealloc $CONTAINER_ID $NETWORK_NAME" cmd_entrypoint_dealloc() { if [ "$#" -ne 2 ]; then echo >&2 "Usage: $ARG0 dealloc CONTAINER_ID NETWORK_NAME" exit 1 fi ID=$1 NET=$2 dir="${BASE}/${ID}" if [ ! -f "${dir}/pid" ]; then exit 0 fi pid=$(cat "${dir}/pid") if [ -f "${dir}/attached-args/${NET}" ]; then CNI_ARGS=$(cat "${dir}/attached-args/${NET}") export CNI_ARGS fi cnitool del "${NET}" "/proc/${pid}/ns/net" rm -f "${dir}/attached/${NET}" "${dir}/attached-args/${NET}" nwcount=$(find "${dir}/attached" -type f | wc -l) if [ "${nwcount}" = 0 ]; then kill -9 "${pid}" rm -rf "${dir}" fi # return empty json echo "{}" } # CLI subcommand: "is-idle" cmd_entrypoint_is_idle() { if [ ! -d ${BASE} ]; then echo '{"idle": true}' elif [ -z "$(ls -1 ${BASE})" ]; then echo '{"idle": true}' else echo '{"idle": false}' fi } # CLI subcommand: "print-cni-result $CONTAINER_ID $NETWORK_NAME" cmd_entrypoint_print_cni_result() { if [ "$#" -ne 2 ]; then echo >&2 "Usage: $ARG0 print-cni-result CONTAINER_ID NETWORK_NAME" exit 1 fi ID=$1 NET=$2 # the result shall be CNI JSON cat "${BASE}/${ID}/attached/${NET}" } # CLI subcommand: "print-netns-path $CONTAINER_ID" cmd_entrypoint_print_netns_path() { if [ "$#" -ne 1 ]; then echo >&2 "Usage: $ARG0 print-netns-path CONTAINER_ID" exit 1 fi ID=$1 pid=$(cat "${BASE}/${ID}/pid") path="/proc/${pid}/ns/net" # return the result echo "{\"path\":\"${path}\"}" } # CLI subcommand: "help" cmd_entrypoint_help() { echo "Usage: ${ARG0} COMMAND" echo echo "Rootless CNI Infra container" echo echo "Commands:" echo " alloc Allocate a netns" echo " dealloc Deallocate a netns" echo " is-idle Print whether the infra container is idle" echo " print-cni-result Print CNI result" echo " print-netns-path Print netns path" echo " help Print help" echo " version Print version" } # CLI subcommand: "version" cmd_entrypoint_version() { echo "{\"version\": \"${ROOTLESS_CNI_INFRA_VERSION}\"}" } # parse args command="${1:-}" if [ -z "$command" ]; then echo >&2 "No command was specified. Run \`${ARG0} help\` to see the usage." exit 1 fi command_func=$(echo "cmd_entrypoint_${command}" | sed -e "s/-/_/g") if ! command -v "${command_func}" >/dev/null 2>&1; then echo >&2 "Unknown command: ${command}. Run \`${ARG0} help\` to see the usage." exit 1 fi # start the command func shift "${command_func}" "$@"