aboutsummaryrefslogtreecommitdiff
path: root/contrib/rootless-cni-infra/rootless-cni-infra
blob: 463254c7f21c8b58d56b2c0cf785367275849848 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/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}" "$@"