Service Scripts
This document describes Terragraph's service scripts and some related utilities.
Cloud Services
Terragraph manages its cloud services on x86 hosts using systemd.
systemd scripts
All systemd scripts reside in /etc/tg_systemd_config/
. The actual service
scripts are expected to be installed on the host manually, while the start/stop
scripts remain in the rootfs. More details about the systemd scripts can be
found in src/terragraph-e2e/systemd/README.md
.
The set of files used in each service is as follows:
/etc/tg_systemd_config/
<service>.service - systemd service file (to be installed on host)
<service>.start - start script
<service>.docker.start - start script (when running in Docker container)
<service>.stop - stop script
Node Services
Services on Terragraph nodes are managed using runit.
runit scripts
All runit scripts reside in /etc/sv/<service>/
on the nodes. Most will run by
default (e.g. e2e_minion
, openr
), some are disabled (e.g. e2e_controller
),
and others run only once after boot (e.g. pop_config
). Many of these scripts
can be enabled or disabled via node configuration; a common pattern in the run
scripts is to sleep until seeing an "enabled" flag in the configuration.
Logs from each service are written to /var/log/<service>/current
and are
automatically rotated.
The basic directory structure for each service is as follows:
/etc/sv/<service>/
run - start script
finish - shutdown script
down - if present, service is disabled by default
log/
run - log script (executes svlogd)
The runit framework is started via /etc/init.d/runit
(installed from
recipes-utils/runit/files/runit.init
). Some noteworthy points are below:
runsv
needs to write to/etc/sv/
, but this is on a read-only partition. To handle this, scripts are actually installed in/etc/sv.bak/
, then copied to/var/run/sv/
during runtime. A symbolic link is created from/etc/sv
to/var/run/sv
.runsvdir
is executed withtaskset
to run all applications on the last available core only.
Initializing drivers, firmware, and interfaces
There are several scripts called when starting either e2e_minion
(via
/usr/sbin/e2e_minion_wrapper.sh
) or driver_if_daemon
(via
/usr/sbin/driver_if_start.sh
):
/usr/sbin/fb_tg_load_common.sh
- Provides functions to run, stop, and restart a service. The_run
function callsfb_load_dr_fw.sh
./usr/bin/fb_load_dr_fw.sh
- Provides a function to load the drivers and firmware, then bring up link interfaces, among other things. This calls the vendor-specific scriptfb_load_bh_drv.sh
./usr/bin/fb_load_bh_drv.sh
- Provides functions to load the wireless ("backhaul") driver.
A pair of helper scripts is provided to associate a point-to-point link using
r2d2
and driver_if_daemon
:
/usr/bin/tfdn_r2d2.sh
- Used on the initiator node/usr/bin/tfcn_r2d2.sh
- Used on the responder node
Environment variables
Most environment variables are loaded in scripts via
/usr/sbin/config_get_env.sh
, which exports fields in the envParams
node
configuration structure. This will call /usr/sbin/config_read_env
to generate
an intermediate file, /data/cfg/config
, as needed. If the node configuration
file (/data/cfg/node_config.json
) does not yet exist or cannot be parsed, it
is also generated in this process.
Additional vendor-specific environment variables, mostly relating to kernel
modules, are static and contained in /usr/bin/tg.env
.
Hardware-related information is written to /var/run/node_info
, which is
generated at boot time by /etc/init.d/gen_node_info_file.sh
. The node info
file is required by several services (e.g. e2e_minion
). Most fields in this
file are read from EEPROM. The file contents are as follows:
NODE_ID="node ID, must be a MAC address (ex. nic0 or wlan0)"
TG_IF2IF="use IF2IF firmware files (0 or 1)"
NUM_WLAN_MACS="number of radios"
MAC_X="baseband MAC address X"
BUS_X="PCI bus X"
GPIO_X="GPIO X (default: -1)"
NVRAM_X="NVRAM X (default: bottom_lvds)"
PCI_ORDER="ordering of pci slots for interface indexing"
HW_MODEL="hardware model string"
HW_VENDOR="hardware vendor"
HW_BOARD_ID="hardware board ID"
HW_REV="hardware revision number"
HW_BATCH="hardware batch number"
HW_SN="hardware serial number"
Note that on Puma hardware when using the PMD, the default MAC address is
read from OTP, and these
usually do not match the fields in EEPROM (i.e. MAC_X
above). Some services
will write and read a modified node info file in /tmp/node_info
that contains
the correct WLAN MAC addresses.
Custom startup scripts
User scripts can be executed as part of the boot sequence by placing them in
/data/startup/
. This is done via /etc/init.d/data_startup.sh
. For example,
the following lines may be helpful for development:
# Disable software watchdog (to avoid unexpected reboots or service restarts)
source /etc/monit_config.sh
mkdir -p "$progress_dir"
disable_all_tg_scripts
# Make root writeable (if manually modifying files in read-only paths)
mount -o remount, rw /
System time
For systems without an RTC module (ex. Puma), there may be several time jumps as the system boots:
- The system time is initialized using the
/etc/timestamp
file. This file is written at build time during rootfs generation, and holds the build date (format:+%4Y%2m%2d%2H%2M%2S
). - The
chronyd
time daemon runs via an/etc/init.d/
init script. This will synchronize system time to NTP servers defined in node configuration (sysParams.ntpServers
), ortime.facebook.com
by default. It will also use GPS/PPS as a time source if configured (envParams.GPSD_PPS_DEVICE
,envParams.GPSD_NMEA_TIME_OFFSET
). Logs are written to/var/log/chrony/
. - The
time_set
script runs via an/etc/init.d/
init script after at least 90 seconds of system uptime. This attempts to runchronyd -q
(one-time clock step, similar tontpdate
) to NTP servers in theoob
(out-of-band) network namespace. Logs are written to/tmp/time_set.log
.
Syslog
Nodes run the rsyslogd
daemon to configure system logging via
/etc/rsyslog.conf
. Some standard files are disabled to save space. Note that
any boot-time syslog messages are dropped if they are written before rsyslogd
has started (e.g. in the init.d sequence).
Log rotation
Log rotation is managed using the logrotate
utility, and application-specific
configuration is located in the /etc/logrotate.d/
directory. logrotate
is
triggered periodically via the cron job /etc/cron.d/logrotate
. Note that a
daily logrotate entry for /data/log/logs.tar.gz
will save an archive of
/var/log/
into the persistent /data/
directory.
Scripting Languages
The sections below briefly describe the scripting languages used in Terragraph and how they are set up.
Shell
Most included shell scripts are compliant with POSIX shell, but some require Bash. Code is validated using ShellCheck.
Python
Terragraph installs Python 3.8, with the interpreter at /usr/bin/python3
(along with related links) and core/user packages at /usr/lib/python3.8/
. In
terragraph-image-minimal
, only .pyc
files are kept (.py
and .opt-*
files
are deleted).
Code is auto-formatted with Black and isort (config: .isort.cfg
), and is
linted using Flake8 (config: .flake8
). Python tests are installed to
terragraph-image-x86
and run using ptr (config: .ptrconfig
) via
meta-x86/recipes-testing/ptr/files/run_ptr.sh
.
Python code is not critical for production. To exclude Python and all dependent
packages from an image, build with conf/no-python.conf
.
Lua
Terragraph installs Lua 5.2, with all user scripts and dependencies captured in
recipes-facebook/e2e/e2e-files-lua_0.1.bb
. Library code is minified using
LuaMinify. The installed file structure is as follows:
/usr/bin/{lua,luac} - Lua interpreter/compiler
/usr/sbin/*.lua - user scripts
/usr/sbin/tests/lua/*_test.lua - unit tests (X86 only)
/usr/lib/lua/5.2/ - library path (not /usr/share/lua/)
/usr/lib/liblua*.so* - Thrift .so libraries (others are in the standard library path)
Code is validated using Luacheck (config: .luacheckrc
). Code documentation
is auto-generated using LDoc (config: .config.ld
). Lua tests are written
using LuaUnit and installed to terragraph-image-x86
.
Note that user scripts are generally not compatible with Lua 5.1/5.3+ or
LuaJIT. However, they are mostly functional in Lua 5.1 after installing the
compat52 module (see recipes-support/lua-compat52/lua-compat52_0.3.bb
) and
importing it globally via require("compat52")
, for example at the beginning of
the tg.utils
module (src/terragraph-e2e/lua/tg/utils.lua
).
Resources
- systemd - Linux init system with service management
- runit - UNIX init scheme with service supervision
- ShellCheck - Shell script static analyzer
- Black - Python code formatter
- isort - Python import organizer
- Flake8 - Python linter
- ptr - Python test runner
- LuaMinify - Lua code minifier
- Luacheck - Lua static analyzer and linter
- LDoc - Lua documentation generator
- LuaUnit - Lua unit testing framework
- compat52 - Lua compatibility module providing Lua-5.2-style APIs for Lua 5.1