meta-google: gbmc-bridge: DHCP term when idle

We don't want to terminate just after 5 minutes, we want to make sure
the DHCP process has been idle for at least that long too.

Change-Id: I6311a6baf21c7bc10ece2d4994f225dbc8c06cc4
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp-term.sh b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp-term.sh
index 6a0c8b0..c43647c 100644
--- a/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp-term.sh
+++ b/meta-google/recipes-google/networking/gbmc-bridge/gbmc-br-dhcp-term.sh
@@ -18,16 +18,60 @@
 while ! ping -c 1 -W 1 2001:4860:4860::8888 >/dev/null 2>&1; do
   sleep 1
 done
+
+# We need to guarantee we wait at least 5 minutes from reachable in
+# case networking just came up
 wait_min=5
-echo "Network is reachable, waiting $wait_min minutes" >&2
-# Wait 5 minutes for any potential DHCP that hasn't landed yet
+echo "Network is reachable, waiting $wait_min min" >&2
 sleep $((60 * wait_min))
-# If the DHCP configuration process is running, wait for it to finish
-if pid="$(cat /run/gbmc-br-dhcp.pid 2>/dev/null)"; then
-  echo "DHCP still running ($pid), waiting" >&2
-  while [[ -e /proc/$pid ]]; do
-    sleep 1
-  done
-fi
+
+get_dhcp_unit_json() {
+  busctl -j call \
+    org.freedesktop.systemd1 \
+    /org/freedesktop/systemd1/unit/gbmc_2dbr_2ddhcp_2eservice \
+    org.freedesktop.DBus.Properties \
+    GetAll s org.freedesktop.systemd1.Unit
+}
+
+# Follow the process and make sure it idles for at least 5 minutes before
+# shutting down. This allows for failures and retries to happen.
+while true; do
+  json="$(get_dhcp_unit_json)" || exit
+  last_ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
+  if pid="$(cat /run/gbmc-br-dhcp.pid 2>/dev/null)"; then
+    # If the DHCP configuration process is running, wait for it to finish
+    echo "DHCP still running ($pid), waiting" >&2
+    while [[ -e /proc/$pid ]]; do
+      sleep 1
+    done
+    # Wait for systemd to detect the process state change
+    while true; do
+      json="$(get_dhcp_unit_json)" || exit
+      ms="$(echo "$json" | jq -r '.data[0].StateChangeTimestampMonotonic.data')"
+      (( ms != last_ms )) && break
+      sleep 1
+    done
+  fi
+
+  echo 'Checking DHCP Active State' >&2
+  json="$(get_dhcp_unit_json)" || exit
+  activestr="$(echo "$json" | jq -r '.data[0].ActiveState.data')"
+
+  # The process is already stopped, we are done
+  [[ "$activestr" == 'inactive' ]] && exit
+
+  # If the process is running, give it at least 5 minutes from when it started
+  cur_s="$(cut -d' ' -f1 /proc/uptime)"
+  if [[ "$activestr" == 'active' ]]; then
+    active_ms="$(echo "$json" | jq -r '.data[0].ActiveEnterTimestampMonotonic.data')"
+  else
+    active_ms=$((cur_s*1000*1000))
+  fi
+  w=$((active_ms/1000/1000 + (wait_min*60) - cur_s))
+  [ "$w" -lt 0 ] && break
+  echo "Waiting ${w}s for DHCP process" >&2
+  sleep $w
+done
+
 echo "Stopping DHCP processing" >&2
 systemctl stop --no-block gbmc-br-dhcp