mirror of
https://github.com/unraid/webgui.git
synced 2026-01-01 23:20:35 -06:00
670 lines
22 KiB
Bash
Executable File
670 lines
22 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# script: rc.docker
|
|
#
|
|
# Short-Description: Create lightweight, portable, self-sufficient containers.
|
|
# Description:
|
|
# Docker is an open-source project to easily create lightweight, portable,
|
|
# self-sufficient containers from any application. The same container that a
|
|
# developer builds and tests on a laptop can run at scale, in production, on
|
|
# VMs, bare metal, OpenStack clusters, public clouds and more.
|
|
#
|
|
# LimeTech - modified for Unraid OS
|
|
# Bergware - modified for Unraid OS, June 2025
|
|
|
|
DAEMON="Docker daemon"
|
|
UNSHARE="/usr/bin/unshare"
|
|
SYSTEM="/sys/class/net"
|
|
CONF6="/proc/sys/net/ipv6/conf"
|
|
STOCK="bond br eth wlan"
|
|
ACTIVE=$(ls --indicator-style=none $SYSTEM | awk "/^(${STOCK// /|})[0-9]/" ORS=' ')
|
|
NICS=$(ls --indicator-style=none $SYSTEM | awk '/^(eth|wlan)[0-9]+$/')
|
|
|
|
DOCKERD="dockerd"
|
|
DOCKER="/usr/bin/$DOCKERD"
|
|
DOCKER_PIDFILE="/var/run/$DOCKERD.pid"
|
|
DOCKER_LOG="/var/log/docker.log"
|
|
DOCKER_ROOT="/var/lib/docker"
|
|
DOCKER_CFG="/boot/config/docker.cfg"
|
|
DOCKER_TIMEOUT=$(awk -F'"' '/^DOCKER_TIMEOUT=/{print $2}' $DOCKER_CFG 2>/dev/null)
|
|
|
|
# network file references
|
|
INI=/var/local/emhttp/network.ini
|
|
STA=/var/local/emhttp/statics.ini
|
|
TMP=/var/tmp/network.tmp
|
|
|
|
# run & log functions
|
|
. /etc/rc.d/rc.runlog
|
|
|
|
# return active interface
|
|
active(){
|
|
if [[ -e $SYSTEM/${1/eth/br} ]]; then
|
|
echo ${1/eth/br}
|
|
elif [[ -e $SYSTEM/${1/eth/bond} ]]; then
|
|
echo ${1/eth/bond}
|
|
else
|
|
echo $1
|
|
fi
|
|
}
|
|
|
|
# wait for interface to go up
|
|
carrier(){
|
|
local n e
|
|
[[ -e $SYSTEM/$1 ]] && e=${2:-10} || return 1
|
|
for ((n=0; n<$e; n++)); do
|
|
[[ $(cat $SYSTEM/$1/carrier 2>/dev/null) == 1 ]] && return 0
|
|
[[ $e -gt 1 ]] && sleep 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# add entry to watch list
|
|
add_entry(){
|
|
rm -f /var/tmp/${1%% *}.down
|
|
[[ -e $STA ]] && echo "$1" >>$STA
|
|
}
|
|
|
|
# delete enty from watch list
|
|
del_entry(){
|
|
touch /var/tmp/$1.down
|
|
[[ -e $STA ]] && sed -i "/^$1 .*/d" $STA
|
|
sleep 0.5
|
|
}
|
|
|
|
# initialize docker settings
|
|
docker_read_options(){
|
|
# determine active port name
|
|
PORT=$(active eth0)
|
|
[[ ! $(carrier $PORT) && $(carrier wlan0 1) ]] && PORT=wlan0
|
|
|
|
# Set defaults used by the docker daemon
|
|
if [[ -f $DOCKER_CFG ]]; then
|
|
for NIC in $NICS; do
|
|
[[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC)
|
|
CFG=($(grep -Pom2 "_SUBNET_|_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG))
|
|
if [[ ${CFG[0]} == _SUBNET_ && -z ${CFG[1]} ]]; then
|
|
# interface has changed, update configuration
|
|
X=${NIC//[^0-9]/}
|
|
sed -ri "s/_(BR|BOND|ETH|WLAN)$X(_[0-9]+)?=/_${NIC^^}\2=/; s/(br|bond|eth|wlan)$X(\.[0-9]+)? /$NIC\2 /g" $DOCKER_CFG
|
|
fi
|
|
done
|
|
# Read (updated) Unraid docker configuration file
|
|
. $DOCKER_CFG
|
|
fi
|
|
|
|
# set storage driver to overlay2 if config value is found, otherwise fall back to native FS driver
|
|
if [[ $(awk -F'"' '/^DOCKER_BACKINGFS=/{print $2}' $DOCKER_CFG 2>/dev/null) == overlay2 ]]; then
|
|
DOCKER_OPTS="$DOCKER_OPTS --storage-driver=overlay2"
|
|
else
|
|
BACKINGFS=$(findmnt --output FSTYPE --noheadings $DOCKER_ROOT)
|
|
if [[ $BACKINGFS == btrfs ]]; then
|
|
DOCKER_OPTS="$DOCKER_OPTS --storage-driver=btrfs"
|
|
elif [[ $BACKINGFS == xfs ]]; then
|
|
DOCKER_OPTS="$DOCKER_OPTS --storage-driver=overlay2"
|
|
elif [[ $BACKINGFS == zfs ]]; then
|
|
DOCKER_OPTS="$DOCKER_OPTS --storage-driver=zfs"
|
|
fi
|
|
fi
|
|
|
|
# Less verbose logging by default
|
|
DOCKER_OPTS="--log-level=fatal $DOCKER_OPTS"
|
|
|
|
# Enable global docker LOG rotation
|
|
if [[ $DOCKER_LOG_ROTATION == yes ]]; then
|
|
[[ -z $DOCKER_LOG_SIZE ]] && DOCKER_LOG_SIZE=10m
|
|
[[ -z $DOCKER_LOG_FILES ]] && DOCKER_LOG_FILES=1
|
|
DOCKER_OPTS="--log-opt max-size=$DOCKER_LOG_SIZE --log-opt max-file=$DOCKER_LOG_FILES $DOCKER_OPTS"
|
|
fi
|
|
|
|
# Adjust MTU size if non-default
|
|
MTU=$(ip link show $PORT | grep -Po 'mtu \K\d+')
|
|
[[ -n $MTU && $MTU -ne 1500 ]] && DOCKER_OPTS="--mtu=$MTU $DOCKER_OPTS"
|
|
|
|
# Enable IPv6 for docker bridge network
|
|
if [[ -n $(ip -6 route show to default dev $PORT) ]]; then
|
|
DOCKER0='fd17::/64'
|
|
DOCKER_OPTS="--ipv6 --fixed-cidr-v6=$DOCKER0 $DOCKER_OPTS"
|
|
IPV6_FORWARD=${IPV6_FORWARD:=accept}
|
|
# create IPv6 NAT rule for docker0
|
|
[[ -z $(ip6tables -t nat -S | grep -o "$DOCKER0") ]] && run ip6tables -t nat -A POSTROUTING -s $DOCKER0 ! -o docker0 -j MASQUERADE
|
|
else
|
|
# ipv6 disabled
|
|
[[ -d $CONF6/docker0 ]] && echo 1 > $CONF6/docker0/disable_ipv6
|
|
fi
|
|
|
|
export DOCKER_RAMDISK=true
|
|
}
|
|
|
|
# Get docker daemon PID (if existing)
|
|
docker_pid(){
|
|
cat $DOCKER_PIDFILE 2>/dev/null
|
|
}
|
|
|
|
# Verify if docker daemon running
|
|
docker_running(){
|
|
sleep 0.1
|
|
[[ -S /var/run/docker.sock ]] || return 1
|
|
[[ $(docker info 2>&1) =~ "Cannot connect to the Docker daemon" ]] && return 1 || return 0
|
|
}
|
|
|
|
# Wait max 30s to daemon start
|
|
wait_daemon(){
|
|
for n in {1..30}; do
|
|
if docker_running; then return 0; else sleep 1; fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# All existing containers
|
|
all_containers(){
|
|
docker ps -a --format='{{.Names}}' 2>/dev/null
|
|
}
|
|
|
|
# Running containers
|
|
running_containers(){
|
|
docker ps --format='{{.Names}} {{.Labels}}' 2>/dev/null | grep 'net.unraid.docker.managed=' | awk '{print $1}'
|
|
}
|
|
|
|
# Network driver
|
|
driver(){
|
|
# user selection when bridge is enabled
|
|
if [[ -z $DOCKER_NETWORK_TYPE ]]; then
|
|
DETACH='ipvlan'
|
|
ATTACH='macvlan'
|
|
MODE='bridge'
|
|
else
|
|
DETACH='macvlan'
|
|
ATTACH='ipvlan'
|
|
MODE='l2 bridge'
|
|
fi
|
|
# fixed selection when bridge is disabled
|
|
if [[ $1 != br ]]; then
|
|
DETACH='ipvlan'
|
|
ATTACH='macvlan'
|
|
MODE='bridge'
|
|
fi
|
|
# wlan0 has forced ipvlan
|
|
[[ $1 == wlan && $2 == forced ]] && ATTACH=ipvlan
|
|
}
|
|
|
|
# Custom networks
|
|
network(){
|
|
docker network ls --filter driver="$1" --format='{{.Name}}' 2>/dev/null | grep -P "^[a-z]+$2(\$|\.)" | tr '\n' ' '
|
|
}
|
|
|
|
# Is container running?
|
|
container_running(){
|
|
local CONTAINER
|
|
for CONTAINER in $(running_containers); do
|
|
[[ $CONTAINER == $1 ]] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# Does the container exist?
|
|
container_exist(){
|
|
local CONTAINER
|
|
for CONTAINER in $(all_containers); do
|
|
[[ $CONTAINER == $1 ]] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
container_paths_exist(){
|
|
local CONTAINER=$1
|
|
while IFS=| read -r HOSTPATH; do
|
|
# Make sure hostpath exists
|
|
if [[ ! -e "$HOSTPATH" ]]; then
|
|
log "container \"$CONTAINER\" hostpath \"$HOSTPATH\" does not exist"
|
|
return 1
|
|
fi
|
|
done <<< $(docker inspect --format='{{range .Mounts}}{{.Source}}|{{end}}' $CONTAINER)
|
|
return 0
|
|
}
|
|
|
|
read_dom(){
|
|
local IFS=\>
|
|
read -d \< ENTITY CONTENT
|
|
}
|
|
|
|
container_add_route(){
|
|
local CT=($(docker inspect --format='{{.State.Pid}} {{.NetworkSettings.Networks}}' $1))
|
|
local PID=${CT[0]}
|
|
local NET=${CT[1]#*[}
|
|
local LAN=${NET%:*}
|
|
if [[ $PID -gt 0 && "eth0 br0 bond0 wlan0" =~ $LAN ]]; then
|
|
local THISIP=$(ip -4 -br addr show scope global primary dev $LAN | awk '{print $3;exit}')
|
|
for CFG in /etc/wireguard/wg*.cfg ; do
|
|
local NETWORK=$(ip -4 route show to $THISIP dev $LAN | awk '{print $1;exit}')
|
|
[[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via ${THISIP%/*} dev $LAN 2>/dev/null
|
|
done
|
|
fi
|
|
}
|
|
|
|
docker_network_start(){
|
|
log "Starting network..."
|
|
# ensure br_netfilter modules is loaded, re: https://github.com/moby/moby/issues/48948
|
|
modprobe br_netfilter
|
|
# create list of possible custom networks
|
|
EXCLUDE=; INCLUDE=$(ls --indicator-style=none $SYSTEM | awk '/^br[0-9]+/' ORS=' ')
|
|
while IFS=$'\n' read -r NETWORK; do
|
|
if [[ ${NETWORK:0:4} == bond ]]; then
|
|
if [[ $INCLUDE =~ "${NETWORK/bond/br} " ]]; then
|
|
EXCLUDE="${EXCLUDE}${NETWORK} ${NETWORK/bond/eth} "
|
|
else
|
|
INCLUDE="${INCLUDE}${NETWORK} "
|
|
EXCLUDE="${EXCLUDE}${NETWORK/bond/eth} "
|
|
fi
|
|
elif [[ ${NETWORK:0:3} == eth ]]; then
|
|
if [[ $INCLUDE =~ "${NETWORK/eth/br} " || $INCLUDE =~ "${NETWORK/eth/bond} " ]]; then
|
|
[[ $EXCLUDE =~ "$NETWORK " ]] || EXCLUDE="${EXCLUDE}${NETWORK} "
|
|
else
|
|
INCLUDE="${INCLUDE}${NETWORK} "
|
|
fi
|
|
else
|
|
INCLUDE="${INCLUDE}${NETWORK} "
|
|
fi
|
|
done <<< $(ls --indicator-style=none $SYSTEM | grep -P '^(bond|eth|wlan)[0-9]+')
|
|
if ! docker_running; then return 1; fi
|
|
# get container settings for custom networks to reconnect later
|
|
declare -A NETRESTORE CTRESTORE
|
|
for CONTAINER in $(docker container ls -a --format='{{.Names}}'); do
|
|
# the file case (due to fat32) might be different so use find to match
|
|
XMLFILE=$(find /boot/config/plugins/dockerMan/templates-user -maxdepth 1 -iname my-${CONTAINER}.xml)
|
|
if [[ -n $XMLFILE ]]; then
|
|
REBUILD=
|
|
MAIN=
|
|
# update custom network reference (if changed)
|
|
for NIC in $NICS; do
|
|
[[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC)
|
|
X=${NIC//[^0-9]/}
|
|
REF=$(grep -Pom1 "<Network>\K(br|bond|eth|wlan)$X" $XMLFILE)
|
|
[[ $X == 0 && ! $(carrier $NIC 1) ]] && continue
|
|
[[ $X == 0 && $NIC != wlan0 ]] && MAIN=$NIC
|
|
[[ $NIC == wlan0 && -n $MAIN ]] && continue
|
|
if [[ -n $REF && $REF != $NIC ]]; then
|
|
sed -ri "s/<Network>(br|bond|eth|wlan)$X(\.[0-9]+)?<\/Network>/<Network>$NIC\2<\/Network>/" $XMLFILE
|
|
# flag container for later rebuild
|
|
REBUILD=1
|
|
fi
|
|
done
|
|
MY_NETWORK= MY_IP=
|
|
while read_dom; do
|
|
[[ $ENTITY == Network ]] && MY_NETWORK=$CONTENT
|
|
[[ $ENTITY == MyIP ]] && MY_IP=${CONTENT// /,} && MY_IP=$(echo "$MY_IP" | tr -s "," ";")
|
|
done <$XMLFILE
|
|
# only restore valid networks
|
|
if [[ -n $MY_NETWORK ]]; then
|
|
NETRESTORE[$MY_NETWORK]="$CONTAINER,$MY_IP ${NETRESTORE[$MY_NETWORK]}"
|
|
# save container name for later rebuild
|
|
CTRESTORE[$MY_NETWORK]=$REBUILD
|
|
fi
|
|
fi
|
|
# restore user defined networks
|
|
USER_NETWORKS=$(docker inspect --format='{{range $key,$value:=.NetworkSettings.Networks}}{{$key}};{{if $value.IPAMConfig}}{{if $value.IPAMConfig.IPv4Address}}{{$value.IPAMConfig.IPv4Address}}{{end}}{{if $value.IPAMConfig.IPv6Address}},{{$value.IPAMConfig.IPv6Address}}{{end}}{{end}} {{end}}' $CONTAINER)
|
|
for ROW in $USER_NETWORKS; do
|
|
ROW=(${ROW/;/ })
|
|
USER_NETWORK=${ROW[0]}
|
|
USER_IP=${ROW[1]/,/;}
|
|
if [[ -n $USER_NETWORK && $USER_NETWORK != $MY_NETWORK ]]; then
|
|
LABEL=${USER_NETWORK//[0-9.]/}
|
|
IF_NO_PARTS=${USER_NETWORK#"$LABEL"}
|
|
IF_NO=${IF_NO_PARTS%%.*}
|
|
if [[ $STOCK =~ $LABEL && $IF_NO -gt 0 ]]; then
|
|
USER_NETWORK=$USER_NETWORK
|
|
elif [[ $STOCK =~ $LABEL && $LABEL != ${PORT:0:-1} ]]; then
|
|
USER_NETWORK=${USER_NETWORK/$LABEL/${PORT:0:-1}}
|
|
fi
|
|
log "container $CONTAINER has an additional network that will be restored: $USER_NETWORK"
|
|
NETRESTORE[$USER_NETWORK]="$CONTAINER,$USER_IP ${NETRESTORE[$USER_NETWORK]}"
|
|
fi
|
|
done
|
|
done
|
|
# detach custom networks
|
|
for NIC in $NICS; do
|
|
[[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC)
|
|
X=${NIC//[^0-9]/}
|
|
driver ${NIC//[0-9]/}
|
|
for NETWORK in $(network $DETACH $X); do
|
|
[[ $STOCK =~ ${NETWORK%%[0-9]*} || $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null
|
|
done
|
|
# get existing custom networks
|
|
for NETWORK in $(network $ATTACH $X); do
|
|
if [[ $STOCK =~ ${NETWORK%%[0-9]*} ]]; then
|
|
[[ $EXCLUDE =~ "$NETWORK " || ! $ACTIVE =~ "$NETWORK " ]] && docker network rm $NETWORK &>/dev/null
|
|
else
|
|
[[ $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null
|
|
fi
|
|
done
|
|
NETWORKS=$(network $ATTACH $X)
|
|
done
|
|
# add or remove custom network
|
|
for NETWORK in $INCLUDE; do
|
|
if [[ ! $DOCKER_CUSTOM_NETWORKS =~ "$NETWORK " ]]; then
|
|
# automatic assignment
|
|
AUTO=${NETWORK/./_}
|
|
AUTO=DOCKER_AUTO_${AUTO^^}
|
|
if [[ ${!AUTO} == no ]]; then
|
|
[[ $NETWORKS =~ "$NETWORK " ]] && docker network rm $NETWORK &>/dev/null
|
|
continue
|
|
fi
|
|
# add auto defined networks
|
|
SUBNET=; GATEWAY=; SERVER=; RANGE=;
|
|
[[ -z ${!AUTO} || ${!AUTO} =~ "4" ]] && IPV4=$(ip -4 -br addr show scope global primary dev $NETWORK | awk '{print $3;exit}') || IPV4=
|
|
if [[ -n $IPV4 ]]; then
|
|
SUBNET=$(ip -4 route show dev $NETWORK | sort | awk -v ORS=" " '$1 !~ /^default/ {print $1}' | sed 's/ $//')
|
|
GATEWAY=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}')
|
|
SERVER=${IPV4%/*}
|
|
DHCP=${NETWORK/./_}
|
|
DHCP=DOCKER_DHCP_${DHCP^^}
|
|
RANGE=${!DHCP}
|
|
fi
|
|
SUBNET6=; GATEWAY6=;
|
|
# get IPv6 address - ignore any /128 networks
|
|
[[ -z ${!AUTO} || ${!AUTO} =~ "6" ]] && IPV6=$(ip -6 -br addr show scope global primary -deprecated dev $NETWORK | awk '{print $3;exit}') || IPV6=
|
|
if [[ -n $IPV6 ]]; then
|
|
SUBNET6=$(ip -6 route show dev $NETWORK | sort | awk -v ORS=" " '$1 !~ /^(default|fe80)/ {print $1}' | sed 's/ $//')
|
|
GATEWAY6=$(ip -6 route show to default dev $NETWORK | awk '{print $3;exit}')
|
|
fi
|
|
else
|
|
# add user defined networks
|
|
IPV4=
|
|
IPV6=
|
|
DEVICE=${NETWORK/./_}
|
|
DEVICE=${DEVICE^^}
|
|
SUBNET=DOCKER_SUBNET_$DEVICE
|
|
SUBNET=${!SUBNET}
|
|
GATEWAY=DOCKER_GATEWAY_$DEVICE
|
|
GATEWAY=${!GATEWAY}
|
|
SERVER=
|
|
RANGE=DOCKER_RANGE_$DEVICE
|
|
RANGE=${!RANGE}
|
|
SUBNET6=DOCKER_SUBNET6_$DEVICE
|
|
SUBNET6=${!SUBNET6}
|
|
GATEWAY6=DOCKER_GATEWAY6_$DEVICE
|
|
GATEWAY6=${!GATEWAY6}
|
|
fi
|
|
# set parameters for custom network creation
|
|
[[ -n $SUBNET ]] && SET4=1 || SET4=0
|
|
[[ -n $SUBNET6 ]] && SET6=1 || SET6=0
|
|
if [[ $SET4 == 1 ]]; then
|
|
SUBNET="--subnet=${SUBNET// / --subnet=}"
|
|
[[ -n $GATEWAY ]] && GATEWAY="--gateway=$GATEWAY"
|
|
[[ -n $SERVER ]] && SERVER="--aux-address=server=$SERVER"
|
|
[[ -n $RANGE ]] && RANGE="--ip-range=$RANGE"
|
|
else
|
|
GATEWAY=
|
|
SERVER=
|
|
RANGE=
|
|
fi
|
|
if [[ $SET6 == 1 ]]; then
|
|
SUBNET6="--ipv6 --subnet=${SUBNET6// / --ipv6 --subnet=}"
|
|
[[ -n $GATEWAY6 && ${GATEWAY6:0:4} != fe80 ]] && GATEWAY6="--gateway=$GATEWAY6" || GATEWAY6=
|
|
else
|
|
GATEWAY6=
|
|
fi
|
|
if [[ $SET4 == 1 || $SET6 == 1 ]]; then
|
|
TYPE=${NETWORK//[0-9.]/}
|
|
driver $TYPE forced
|
|
if [[ $TYPE == br || $TYPE == wlan ]]; then
|
|
VHOST=$NETWORK
|
|
else
|
|
[[ -n $IPV4 && $DOCKER_ALLOW_ACCESS == yes ]] && VHOST=vhost${NETWORK//[^0-9.]/} || VHOST=$NETWORK
|
|
fi
|
|
# delete and recreate unconditionally
|
|
log "Processing... $NETWORK"
|
|
docker network rm $NETWORK &>/dev/null
|
|
docker network create -d $ATTACH $SUBNET $GATEWAY $SERVER $RANGE $SUBNET6 $GATEWAY6 -o parent=$VHOST $NETWORK | xargs docker network inspect -f "created network $ATTACH {{.Name}} with subnets: {{range .IPAM.Config}}{{.Subnet}}; {{end}}" 2>/dev/null | log
|
|
# connect containers to this new network
|
|
for CONNECT in ${NETRESTORE[$NETWORK]}; do
|
|
CONTAINER=${CONNECT%,*}
|
|
MY_TT=${CONNECT#*,}
|
|
MY_IP=
|
|
for IP in ${MY_TT//;/ }; do
|
|
[[ $IP =~ ':' ]] && MY_IP="$MY_IP --ip6 $IP" || MY_IP="$MY_IP --ip $IP"
|
|
done
|
|
log "connecting $CONTAINER to network $NETWORK"
|
|
docker network connect $MY_IP $NETWORK $CONTAINER >/dev/null
|
|
if [[ -n ${CTRESTORE[$NETWORK]} ]]; then
|
|
# rebuild the container to use changed network
|
|
log "rebuild container $CONTAINER"
|
|
/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/rebuild_container $CONTAINER
|
|
fi
|
|
done
|
|
# hack to let containers talk to host
|
|
if [[ $TYPE == br ]]; then
|
|
SHIM=shim-$NETWORK
|
|
if [[ $DOCKER_ALLOW_ACCESS == yes && -n $IPV4 ]]; then
|
|
# create shim interface
|
|
if [[ ! -e $SYSTEM/$SHIM ]]; then
|
|
run ip link add link $NETWORK name $SHIM type $ATTACH mode $MODE
|
|
run ip link set $SHIM up
|
|
fi
|
|
# disable IPv6 on shim interface
|
|
echo 1 >$CONF6/$SHIM/disable_ipv6
|
|
run ip -6 addr flush dev $SHIM
|
|
# copy parent IPv4 address to shim interface
|
|
run ip -4 addr add $IPV4 dev $SHIM metric 0
|
|
add_entry "$SHIM $IPV4 metric 0"
|
|
GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}')
|
|
if [[ -n $GW4 ]]; then
|
|
run ip -4 route add default via $GW4 dev $SHIM metric 0
|
|
add_entry "$SHIM GW4 default via $GW4 metric 0"
|
|
fi
|
|
log "created network $SHIM for host access"
|
|
elif [[ -e $SYSTEM/$SHIM ]]; then
|
|
# remove shim interface assignment
|
|
del_entry $SHIM
|
|
run ip -4 addr del $IPV4 dev $SHIM metric 0
|
|
fi
|
|
else
|
|
if [[ $TYPE == wlan ]]; then
|
|
VHOST=shim-$NETWORK
|
|
else
|
|
VHOST=vhost${NETWORK//[^0-9.]/}
|
|
fi
|
|
if [[ -n $IPV4 && $DOCKER_ALLOW_ACCESS == yes ]]; then
|
|
# disable IPv6 on vhost interface
|
|
echo 1 >$CONF6/$VHOST/disable_ipv6
|
|
run ip -6 addr flush dev $VHOST
|
|
# copy parent IPv4 address to vhost interface
|
|
run ip -4 addr add $IPV4 dev $VHOST metric 0
|
|
add_entry "$VHOST $IPV4 metric 0"
|
|
GW4=$(ip -4 route show to default dev $NETWORK | awk '{print $3;exit}')
|
|
if [[ -n $GW4 ]]; then
|
|
run ip -4 route add default via $GW4 dev $VHOST metric 0
|
|
add_entry "$VHOST GW4 default via $GW4 metric 0"
|
|
fi
|
|
log "created network $VHOST for host access"
|
|
elif [[ -n $IPV4 && -e $SYSTEM/$VHOST ]]; then
|
|
# remove vhost interface assignment
|
|
del_entry $VHOST
|
|
run ip -4 addr del $IPV4 dev $VHOST metric 0
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
# # create IPv6 forward accept rule
|
|
# if [[ $IPV6_FORWARD == accept ]]; then
|
|
# ip6tables -P FORWARD ACCEPT
|
|
# log "created forward accept rule for IPv6 network"
|
|
# fi
|
|
log "Network started."
|
|
}
|
|
|
|
docker_network_stop(){
|
|
log "Stopping network..."
|
|
if ! docker_running; then return 1; fi
|
|
# Read docker configuration file
|
|
[[ -f $DOCKER_CFG ]] && . $DOCKER_CFG
|
|
for NIC in $NICS; do
|
|
[[ ${NIC:0:3} == eth ]] && NIC=$(active $NIC)
|
|
driver ${NIC//[0-9]/} forced
|
|
for NETWORK in $(network $ATTACH ${NIC//[^0-9]/}); do
|
|
IPV4=$(ip -4 -br addr show scope global primary dev $NETWORK | awk '{print $3;exit}')
|
|
[[ $STOCK =~ ${NETWORK%%[0-9]*} || $DOCKER_USER_NETWORKS != preserve ]] && docker network rm $NETWORK &>/dev/null
|
|
TYPE=${NETWORK//[0-9.]/}
|
|
if [[ $TYPE == br || $TYPE == wlan ]]; then
|
|
SHIM=shim-$NETWORK
|
|
if [[ -e $SYSTEM/$SHIM ]]; then
|
|
del_entry $SHIM
|
|
run ip -4 addr del $IPV4 dev $SHIM metric 0
|
|
fi
|
|
else
|
|
VHOST=vhost${NETWORK//[^0-9.]/}
|
|
if [[ -e $SYSTEM/$VHOST ]]; then
|
|
del_entry $VHOST
|
|
run ip -4 addr del $IPV4 dev $VHOST metric 0
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
log "Network stopped."
|
|
}
|
|
|
|
docker_container_start(){
|
|
log "Starting containers..."
|
|
local CONTAINER
|
|
if ! docker_running; then return 1; fi
|
|
if [[ -f $DOCKER_ROOT/unraid-autostart ]]; then
|
|
while read -r CONTAINER; do
|
|
CONTAINER=($CONTAINER)
|
|
WAIT=${CONTAINER[1]}
|
|
if container_exist $CONTAINER && ! container_running $CONTAINER && container_paths_exist $CONTAINER; then
|
|
OUT=$(docker start $CONTAINER 2>&1)
|
|
if [[ $OUT =~ "Error:" ]]; then
|
|
log "$CONTAINER: $OUT" &
|
|
else
|
|
container_add_route $CONTAINER
|
|
log "$CONTAINER: started successfully!" &
|
|
if [[ $WAIT -gt 0 ]]; then
|
|
log "$CONTAINER: wait $WAIT seconds" &
|
|
sleep $WAIT
|
|
fi
|
|
fi
|
|
fi
|
|
done <$DOCKER_ROOT/unraid-autostart
|
|
fi
|
|
log "Containers started."
|
|
}
|
|
|
|
docker_container_stop(){
|
|
log "Stopping containers..."
|
|
if ! docker_running; then return 1; fi
|
|
[[ -n $(running_containers) ]] && docker stop --time=${DOCKER_TIMEOUT:-10} $(running_containers) >/dev/null
|
|
log "Unraid managed containers stopped."
|
|
}
|
|
|
|
docker_service_start(){
|
|
log "Starting $DAEMON..."
|
|
local REPLY
|
|
[[ -x $DOCKER ]] && REPLY= || REPLY="Failed"
|
|
if [[ -z $REPLY ]]; then
|
|
if ! mountpoint $DOCKER_ROOT &>/dev/null; then
|
|
REPLY="No image mounted at $DOCKER_ROOT"
|
|
elif docker_running; then
|
|
REPLY="Already started"
|
|
fi
|
|
fi
|
|
if [[ -z $REPLY ]]; then
|
|
# If there is an old PID file (no docker running), clean it up:
|
|
if [[ -r $DOCKER_PIDFILE ]]; then
|
|
if ! docker_running; then
|
|
rm -f $DOCKER_PIDFILE
|
|
fi
|
|
fi
|
|
nohup $UNSHARE --propagation slave -- $DOCKER -p $DOCKER_PIDFILE $DOCKER_OPTS >>$DOCKER_LOG 2>&1 &
|
|
wait_daemon
|
|
# after docket started, continue to accept non-docker IPv6 traffic on br0
|
|
ip6tables -P FORWARD ACCEPT
|
|
# log "created forward accept rule for IPv6 network"
|
|
if docker_running; then REPLY="Started"; else REPLY="Failed"; fi
|
|
fi
|
|
log "$DAEMON... $REPLY."
|
|
}
|
|
|
|
docker_service_stop(){
|
|
log "Stopping $DAEMON..."
|
|
local REPLY
|
|
# If there is no PID file, ignore this request...
|
|
if [[ -r $DOCKER_PIDFILE ]]; then
|
|
# Try to stop dockerd gracefully
|
|
kill $(docker_pid) 2>/dev/null
|
|
# show waiting message
|
|
echo "Waiting 30 seconds for $DAEMON to die."
|
|
TIMER=30
|
|
# must ensure daemon has exited
|
|
while [[ $TIMER -gt 0 ]]; do
|
|
sleep 1
|
|
if [[ $(ps -p $(docker_pid) -o comm= 2>/dev/null) != $DOCKERD ]]; then
|
|
rm -f $DOCKER_PIDFILE
|
|
# tear down the bridge
|
|
if [[ -e $SYSTEM/docker0 ]]; then
|
|
run ip link set docker0 down
|
|
run ip link del docker0
|
|
fi
|
|
REPLY="Stopped"
|
|
# signal successful stop
|
|
TIMER=-1
|
|
else
|
|
((TIMER--))
|
|
fi
|
|
done
|
|
if [[ $TIMER -eq 0 ]]; then
|
|
log "Error: process will not die!"
|
|
# Send SIGKILL to dockerd
|
|
kill -SIGKILL $(docker_pid) 2>/dev/null
|
|
# Remove .sock and .pid
|
|
rm -f /var/run/docker.sock $DOCKER_PIDFILE
|
|
REPLY="Killed"
|
|
fi
|
|
else
|
|
REPLY="Already stopped"
|
|
fi
|
|
log "$DAEMON... $REPLY."
|
|
}
|
|
|
|
docker_status(){
|
|
if docker_running; then
|
|
echo "$DAEMON is currently running."
|
|
else
|
|
echo "$DAEMON is not running."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
case "$1" in
|
|
'start')
|
|
docker_read_options
|
|
docker_service_start
|
|
docker_network_start
|
|
docker_container_start &>/dev/null &
|
|
;;
|
|
'stop')
|
|
docker_container_stop
|
|
docker_network_stop
|
|
docker_service_stop
|
|
;;
|
|
'force_stop')
|
|
docker_container_stop
|
|
docker_service_stop
|
|
;;
|
|
'restart')
|
|
docker_container_stop
|
|
docker_network_stop
|
|
docker_service_stop
|
|
sleep 1
|
|
docker_read_options
|
|
docker_service_start
|
|
docker_network_start
|
|
docker_container_start &>/dev/null &
|
|
;;
|
|
'status')
|
|
docker_status
|
|
;;
|
|
*)
|
|
echo "Usage: $BASENAME start|stop|force_stop|restart|status"
|
|
exit 1
|
|
esac
|
|
exit 0
|