Last active
October 2, 2020 04:40
-
-
Save Andrei-Pozolotin/6bc4f2caa18700cdd94d910e588a555c to your computer and use it in GitHub Desktop.
cni-bash-plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cni-bash-plugin | |
files: | |
/etc/rkt/net.d/bridge.sh.conf | |
/etc/rkt/net.d/bridge-dhcp.sh | |
/etc/rkt/net.d/bridge.sh | |
usage: | |
rkt run \ | |
--insecure-options=all \ | |
--net=bridge.sh;machine_name=aci-serv;manchine_mac=name;dhcp=enable \ | |
docker://carrotgarden/aci-serv | |
see: | |
https://github.com/coreos/rkt/issues/2895 | |
https://github.com/containernetworking/cni/issues/265 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# {{ ansible_managed }} | |
# udhcpc script | |
# https://udhcp.busybox.net/README.udhcpc | |
# https://github.com/mirror/busybox/tree/master/examples/udhcp | |
log() { | |
logger -t "rkt" "$DHCP_RUNNER :: $@" | |
} | |
route_create() { | |
[[ "$interface" ]] || { log "missing interface" ; return ; } | |
[[ "$router" ]] || { log "missing router" ; return ; } | |
local entry= | |
for entry in $router ; do | |
ip route add default via $entry dev $interface | |
done | |
} | |
route_delete() { | |
[[ "$interface" ]] || { log "missing interface" ; return ; } | |
while ip route del dev $interface 2> /dev/null ; do | |
: | |
done | |
} | |
address_create() { | |
[[ "$interface" ]] || { log "missing interface" ; return ; } | |
[[ "$subnet" ]] || { log "missing subnet" ; return ; } | |
[[ "$broadcast" ]] || { log "missing broadcast" ; return ; } | |
ip address add $ip/$subnet broadcast $broadcast dev $interface | |
} | |
address_delete() { | |
[[ "$interface" ]] || { log "missing interface" ; return ; } | |
ip address flush dev $interface | |
} | |
dhcp_create() { | |
log "create" | |
address_create | |
route_create | |
env | sort > "$DHCP_STATUS" | |
} | |
dhcp_ensure() { | |
log "ensure" | |
dhcp_delete | |
dhcp_create | |
} | |
dhcp_delete() { | |
log "delete" | |
rm -f "$DHCP_STATUS" | |
route_delete | |
address_delete | |
} | |
dhcp_error() { | |
log "error: message=$message" | |
} | |
arguments() { | |
readonly DHCP_RUNNER="$BASH_SOURCE" | |
readonly DHCP_STATUS="$DHCP_RUNNER.status" | |
} | |
main() { | |
arguments | |
case "$command" in | |
bound) dhcp_create ;; | |
renew) dhcp_ensure ;; | |
deconfig) dhcp_delete ;; | |
nak|leasefail) dhcp_error ;; | |
*) log "wrong command $command" ;; | |
esac | |
} | |
### | |
export readonly command="$1" | |
main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# {{ ansible_managed }} | |
# cni bridge+dhcp plugin | |
# https://github.com/containernetworking/cni | |
log() { | |
logger -t "rkt" "$SCRIPT_NAME :: $@" | |
} | |
log_cni() { | |
log "CNI_VERSION $CNI_VERSION" | |
log "CNI_COMMAND $CNI_COMMAND" | |
log "CNI_CONTAINERID $CNI_CONTAINERID" | |
log "CNI_NETNS $CNI_NETNS" | |
log "CNI_IFNAME $CNI_IFNAME" | |
log "CNI_ARGS $CNI_ARGS" | |
log "CNI_PATH $CNI_PATH" | |
} | |
json_list() { | |
local list=$(echo "$1" | tr ' ' '","') | |
[[ "$list" ]] && echo '[ "'$list'" ]' || echo '[]' | |
} | |
make_face() { | |
local prefix="$1" ; [[ "$prefix" ]] || prefix="rkt" | |
echo "$CNI_CONTAINERID" | sed -r "s/(........).*/$prefix-\1/" | |
} | |
make_mac_uuid() { | |
local "$@" | |
[[ "$uuid" ]] || local uuid="00000000-0000-0000-0000-000000000000" | |
echo "$uuid" | sed -r "s/(..)(..)(..)(..)-(..).*/02:\1:\2:\3:\4:\5/" | |
} | |
make_mac_name() { | |
local "$@" | |
[[ "$name" ]] || local name="machine" | |
echo "$name" | md5sum | sed -r "s/(..)(..)(..)(..)(..).*/12:\1:\2:\3:\4:\5/" | |
} | |
make_mac_convert() { | |
local "$@" | |
[[ "$mac" ]] || local mac="12-34-56-78-90-ab" | |
echo "$mac" | tr '-' ':' | |
} | |
netns_exec() { | |
ip netns exec $NETNS_NAME $@ | |
} | |
result_ip() { | |
local "$@" | |
netns_exec ip -oneline -family "$family" addr show dev $MACHINE_FACE | awk '{ print $4 }' | |
} | |
result_ipv4() { | |
result_ip family=inet | head --lines 1 | |
} | |
result_ipv6() { | |
result_ip family=inet6 | head --lines 1 | |
} | |
result_dns() { | |
has_dhcp_status && local $(read_dhcp_staus) && echo $dns || return 0 | |
} | |
result_domain() { | |
has_dhcp_status && local $(read_dhcp_staus) && echo $domain || return 0 | |
} | |
face_create() { | |
netns_exec ip link add $MACHINE_FACE type veth peer name $BRIDGE_FACE | |
netns_exec ip link set $MACHINE_FACE address $MACHINE_MAC | |
netns_exec ip link set $MACHINE_FACE up | |
netns_exec ip link set lo up | |
netns_exec ip link set $BRIDGE_FACE netns 1 | |
} | |
face_delete() { | |
netns_exec ip link set $MACHINE_FACE down | |
netns_exec ip link del $MACHINE_FACE | |
netns_exec ip link set lo down | |
} | |
is_dhcp_enable() { | |
[[ "$DHCP" == "enable" ]] | |
} | |
has_dhcp_status() { | |
[[ -e "$DHCP_STATUS" ]] | |
} | |
read_dhcp_staus() { | |
cat "$DHCP_STATUS" | |
} | |
dhcp_create() { | |
is_dhcp_enable || return 0 | |
# | |
mkdir -p "$DHCP_DIR" | |
rm -f "$DHCP_STATUS" | |
ln -s "$DHCP_SCRIPT" "$DHCP_RUNNER" | |
# | |
systemd-run \ | |
--property="SyslogIdentifier=$DHCP_NAME" \ | |
--description="CNI Service $DHCP_NAME" \ | |
--unit="$DHCP_UNIT" \ | |
--no-block \ | |
$(dhcp_command) | |
} | |
dhcp_delete() { | |
is_dhcp_enable || return 0 | |
# | |
systemctl stop "$DHCP_UNIT" | |
# | |
rm -f "$DHCP_RUNNER" | |
rm -f "$DHCP_STATUS" | |
} | |
dhcp_await() { | |
is_dhcp_enable || return 0 | |
local step=0 size=5 | |
while ! has_dhcp_status ; do | |
[[ $(( step % size )) == 0 ]] && log "dhcp await: $step" | |
step=$(( step + 1 )) | |
sleep 1 | |
done | |
} | |
exec_path() { | |
type -P $1 | |
} | |
dhcp_command() { | |
echo "\ | |
$(exec_path ip) netns exec $NETNS_NAME \ | |
$(exec_path busybox) udhcpc \ | |
--fqdn $MACHINE_NAME \ | |
--interface $MACHINE_FACE \ | |
--script $DHCP_RUNNER \ | |
--retries 0 \ | |
--timeout $DHCP_TIMEOUT \ | |
--tryagain $DHCP_TIMEOUT \ | |
--release \ | |
--foreground \ | |
" | |
} | |
join_create() { | |
brctl addif $BRIDGE_ROOT $BRIDGE_FACE | |
} | |
join_delete() { | |
brctl delif $BRIDGE_ROOT $BRIDGE_FACE | |
} | |
main_create() { | |
face_create | |
join_create | |
dhcp_create | |
dhcp_await | |
report_success \ | |
ip4=$(result_ipv4) ip6=$(result_ipv6) \ | |
dns=$(result_dns) domain=$(result_domain) | |
} | |
main_delete() { | |
dhcp_delete | |
join_delete | |
face_delete | |
report_success | |
} | |
is_bridge_present() { | |
local "$@" | |
brctl show | grep -q -E "^$name\s" | |
} | |
make_bridge_root() { | |
local "$@" | |
case "$bridge" in | |
ensure) # make when missing | |
log "TODO $bridge not implemented. CNI_ARGS: $CNI_ARGS" ; return 1 | |
;; | |
discover) # find best matching | |
log "TODO $bridge not implemented. CNI_ARGS: $CNI_ARGS" ; return 1 | |
;; | |
existing) # user config or default | |
[[ "$bridge_root" ]] && echo $bridge_root || echo br0 | |
;; | |
*) log "wrong bridge $bridge. CNI_ARGS: $CNI_ARGS" ; return 1 | |
;; | |
esac | |
} | |
make_machine_mac() { | |
local "$@" | |
case "$mac" in | |
"") make_mac_uuid uuid=$uuid ;; | |
name) make_mac_name name=$name ;; | |
*) make_mac_convert mac=$mac ;; | |
esac | |
} | |
arguments() { | |
local _args_= | |
_args_=$(echo "$CNI_ARGS" | tr ';' ' ') | |
[[ "${_args_}" ]] && local ${_args_} || true | |
# | |
readonly NETNS_NAME=$(basename "$CNI_NETNS") | |
# | |
readonly BRIDGE=$([[ "$bridge" ]] && echo $bridge || echo existing) | |
readonly BRIDGE_FACE=$([[ "$bridge_face" ]] && echo $bridge_face || make_face) | |
readonly BRIDGE_ROOT=$(make_bridge_root bridge=$BRIDGE bridge_root=$bridge_root) | |
is_bridge_present name="$BRIDGE_ROOT" || \ | |
report_failure code=110 message="invalid bridge" details="CNI_ARGS: $CNI_ARGS" | |
# | |
readonly MACHINE_NAME=$([[ "$machine_name" ]] && echo $machine_name || echo $BRIDGE_FACE) | |
readonly MACHINE_FACE=$([[ "$machine_face" ]] && echo $machine_face || echo $CNI_IFNAME) | |
readonly MACHINE_MAC=$(make_machine_mac mac=$machine_mac name=$MACHINE_NAME uuid=$CNI_CONTAINERID) | |
# | |
readonly DHCP=$([[ "$dhcp" ]] && echo $dhcp || echo disable) | |
readonly DHCP_DIR=$([[ "$dhcp_dir" ]] && echo $dhcp_dir || echo $SCRIPT_SPACE) | |
readonly DHCP_NAME=$([[ "$dhcp_name" ]] && echo $dhcp_name || echo dhcp-$MACHINE_NAME) | |
readonly DHCP_UNIT=$([[ "$dhcp_unit" ]] && echo $dhcp_unit || echo $DHCP_NAME-$BRIDGE_FACE) | |
readonly DHCP_TIMEOUT=$([[ "$dhcp_timeout" ]] && echo $dhcp_timeout || echo 1) | |
readonly DHCP_SCRIPT=$([[ "$dhcp_script" ]] && echo $dhcp_script || echo ${BASH_SOURCE%.*}-dhcp.sh) | |
readonly DHCP_RUNNER="$DHCP_DIR/$DHCP_UNIT.sh" | |
readonly DHCP_STATUS="$DHCP_RUNNER.status" | |
} | |
defaults() { | |
readonly REPORT_VERSION="0.3.0" | |
readonly UNDEFINED_IP4="0.0.0.0/32" | |
readonly UNDEFINED_IP6="::/128" | |
} | |
flush_output() { | |
stdbuf --output=0 $@ | |
} | |
switch_output() { | |
local "$@" | |
mkdir -p $(dirname "$SCRIPT_OUTPUT") | |
case "$mode" in | |
external) # redirect stdout and stderr | |
exec 11>&1 22>&2 # save stdout/stderr | |
exec &> "$SCRIPT_OUTPUT" # collect output to file | |
;; | |
original) # restore stdout and stderr | |
flush_output echo >> "$SCRIPT_OUTPUT" | |
exec 1>&11 2>&22 # restore stdout/stderr | |
exec 11>&- 22>&- # release file descriptors | |
;; | |
*) | |
exit 123 # program error | |
;; | |
esac | |
} | |
define() { | |
IFS='\n' read -r -d '' ${1} || true | |
} | |
report_success() { | |
local "$@" result= code=0 | |
[[ "$ip4" ]] || local ip4="$UNDEFINED_IP4" | |
[[ "$ip6" ]] || local ip6="$UNDEFINED_IP6" | |
define result << EOF_SUCCESS | |
{ | |
"cniVersion" : "$REPORT_VERSION", | |
"ip4" : { | |
"ip" : "$ip4" | |
}, | |
"ip6" : { | |
"ip" : "$ip6" | |
}, | |
"dns" : { | |
"domain" : "$domain", | |
"nameservers" : $(json_list $dns) | |
} | |
} | |
EOF_SUCCESS | |
main_exit code=$code result="$result" | |
} | |
report_failure() { | |
local code=200 "$@" result= | |
define result << EOF_FAILURE | |
{ | |
"cniVersion": "$REPORT_VERSION", | |
"code": $code, | |
"msg": "$message", | |
"details": "$details" | |
} | |
EOF_FAILURE | |
main_exit code=$code result="$result" | |
} | |
main_exit() { | |
local "$@" | |
[[ "$BASH_SUBSHELL" == "0" ]] || exit $code | |
switch_output mode=original | |
flush_output echo "$result" | |
[[ $code == 0 ]] && rm -f "$SCRIPT_OUTPUT" || true | |
exit $code | |
} | |
main() { | |
switch_output mode=external | |
defaults | |
arguments | |
case "$CNI_COMMAND" in | |
ADD) main_create ;; | |
DEL) main_delete ;; | |
*) log_cni ; report_failure code=101 message="wrong command" ;; | |
esac | |
} | |
error() { | |
local variables=$(set -o posix ; set | sort) | |
flush_output echo "\n### VARIABLES ###\n\n$variables" >> "$SCRIPT_OUTPUT" | |
local message="script error: $SCRIPT_NAME :: $@" | |
local details="script output: $SCRIPT_OUTPUT" | |
log "$message" | |
report_failure code=102 message="$message" details="$details" | |
} | |
### | |
set -o errexit | |
set -o errtrace | |
readonly SCRIPT_NAME=$(basename $BASH_SOURCE) | |
readonly SCRIPT_SPACE="/run/rkt/cni/$SCRIPT_NAME" | |
readonly SCRIPT_OUTPUT="$SCRIPT_SPACE/output-$CNI_CONTAINERID.log" | |
trap 'error line=["$LINENO"] function=["$FUNCNAME"] command=["$BASH_COMMAND"]' ERR | |
main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "bridge.sh", | |
"type": "bridge.sh" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment