Commit 7bd20155 authored by Ellen Wang's avatar Ellen Wang

Move zerotier interface and address discovery into the container

Instead of exposing the details in init (and having to do it
in sh), it's much better to do all the work in
Now it can create the networks, join them, wait for the interfaces
to appear, and return only the necessary information back to init.
parent 29fec63e
import os
import sys
import time
import re
from zerotier import zt_get, zt_post
def stderr(msg):
print(msg, file = sys.stderr)
if len(sys.argv) < 1:
print("Usage: <network name>")
stderr("Usage: <network name>")
netname = sys.argv[1]
......@@ -15,14 +20,15 @@ while True:
if status and status["online"]:
hostid = status["address"]
print("Waiting for zerotier-one to start")
stderr("Waiting for zerotier-one to start")
print("Got host id: %s" % hostid)
stderr("Got host id: %s" % hostid)
netid = None
adhocid = "ff05390539000000"
#Join the adhoc network.
zt_post("network/ff05390539000000", {})
zt_post("network/%s" % adhocid, {})
#Check to see if network is already there.
networks = zt_get("controller/network")
......@@ -30,14 +36,14 @@ for id in networks:
net = zt_get("controller/network/" + id)
if net["name"] == netname:
netid = net["id"]
print("Got network id: %s" % netid)
stderr("Got network id: %s" % netid)
#XXX Would be cool to use subnets here, but that is broken in ZT:
# If we do that, linux/windows/mac need to "allowGlobal" too.
if not netid: #Create the network
print("Network %s doesn't exist, creating" % netname)
stderr("Network %s doesn't exist, creating" % netname)
newnet = {
'name': netname,
'multicastLimit': 16,
......@@ -55,13 +61,7 @@ if not netid: #Create the network
net = zt_post("controller/network/%s______" % hostid, newnet)
netid = net["id"]
print("Created network id: %s" % netid)
# (Pre)authorize additional hosts, for devel bring-up only
for ahost in os.getenv("ZEROTIER_AUTHORIZED_HOSTS", "").split():
print("Authorizing host %s" % ahost)
zt_post("controller/network/%s/member/%s" % (netid, ahost),
{'authorized': True, 'activeBridge': False})
stderr("Created network id: %s" % netid)
#Join the network. This is harmless if we're already a member.
zt_post("network/%s" % netid, {})
......@@ -72,12 +72,12 @@ while True:
member = zt_get("controller/network/%s/member/%s" % (netid, hostid))
if member:
print("Waiting to join network")
stderr("Waiting to join network")
#Now authorize ourselves, if we're not already.
if member["authorized"] != True:
newmember = {
'authorized': True,
'activeBridge': True,
......@@ -85,3 +85,35 @@ if member["authorized"] != True:
zt_post("controller/network/%s/member/%s" % (netid, hostid),
#Wait for interfaces to come up
ztif = None
bootstrap_ipv6 = None
while True:
net = zt_get("network/%s" % netid)
if net["status"] == "OK":
ztif = net["portDeviceName"]
stderr("Waiting for %s interface to appear" % netname)
while True:
net = zt_get("network/%s" % adhocid)
if net["status"] == "OK":
m = None
for addr in net["assignedAddresses"]:
m = re.fullmatch("(fc[0-9a-f:]+)/40", addr)
if m:
if m:
bootstrap_ipv6 =
# bad bad bad
stderr("Bootstrap interface %s exists " +
"but does not have a suitable address." % adhocid)
stderr("assignedAddresses: %s" % net["assignedAddresses"])
stderr("Waiting for bootstrap interface to appear")
stderr("Private interface: %s" % ztif)
stderr("Bootstrop address: %s" % bootstrap_ipv6)
print("%s %s" % (ztif, bootstrap_ipv6))
......@@ -23,6 +23,13 @@ while read line; do
[ -z "$line" ] || modprobe $line
done </etc/modules
# XXX debugging: fix files masked by overlays (see initrdsrc/init)
#chmod og+rw /dev/net/tun
#echo 'ntpd:x:101:101::/var/run/openntpd:/bin/false' >> /etc/passwd
#echo 'ntpd:x:101:' >> /etc/group
#echo 'docker:x:999:' >> /etc/group
#echo 'netdev:x:102:' >> /etc/group
(netd &)
# Bring up mdev to run storage manager
......@@ -66,26 +73,12 @@ else
echo "ERROR: No persistent storage for ZeroTier state!"
#XXX Need a scheme to handle this!
docker run --rm -d --net=host \
--cap-add=NET_ADMIN --cap-add=SYS_ADMIN --device=/dev/net/tun \
$MOUNT -v /boot/pairingkey:/pairingkey --name zerotier zerotier /start private
# Run this in the foreground (for now) so we can see the network id.
# Also, it makes zerotier startup more sychronous, which is nice.
docker exec -it \
zerotier python3 / private
while true; do
ZTIF=`ip -o address | grep -Eo '^[0-9]+: zt.+ +inet +172\.18\.0\.1/' | cut -d' ' -f2`
if [ -n "$ZTIF" ]; then
echo "Zerotier interface $ZTIF"
echo "Waiting for Zerotier interface to appear..."
sleep 1
BOOTSTRAP_IPV6=`ip -o address | grep -Eo '^[0-9]+: zt.+ +inet6 fc[0-9a-f:]+/40 scope global' | grep -v " $ZTIF " | awk '{print $4}' | cut -d'/' -f1`
x="`docker exec zerotier python3 / private`"
ZTIF="${x%% *}"
BOOTSTRAP_IPV6="${x##* }"
#Start registration container if needed.
if [ ! -s /boot/apikey ]; then
......@@ -160,6 +153,7 @@ docker run -d --name haproxy haproxy
# XXX eventually this will be some form of getty
setsid -cw bash -l
docker kill haproxy
docker kill appstore
docker kill web
docker kill dnsd
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment