| Mode | Size | Name |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -r-xr-xr-x |   | |
| -rw-r--r-- | 25 | .gitignore |
| -rw-r--r-- | 1060 | .sai.json |
| -rw-r--r-- | 5645 | CMakeLists.txt |
| -rw-r--r-- | 17827 | README.md |
A sai-server daemon runs on a server to receive wss connections from the builders, git update hooks POST signed JSON job matrices from configured git servers, and sai-server coordinates dispatching concurrent jobs to dynamically availabe remote builders of the correct platforms, collecting logs and results. A sai-web server daemon is also available usually on :443 or via a proxy to provide a live web / websockets interface with synamic updates and realtime build logs in the browser, with JWT-authentication for manual job control.
General approach
Build flow and support for embedded
Testing is based around CTest, it can either run on the build host inside the container, or run on a separate embedded device. In the separate case, the flow can include steps to flash the image that was built and to observe and drive testing via usually USB tty devices. IO on these additional ttys is logged separately than IO from build host subprocess stdout and stderr. Sharing embedded devices on the test hostEmbedded devices are actually build host-wide assets that may be called upon and shared by different containers and different build platforms. For example, a cross-built flash image on Centos8 and another cross-built on Ubuntu Bionic for the same platform may want to flash and test on the same pool of embedded devices. Even images from different build platforms for the same kind of device may wish to flash the same embedded device, where the device can be flashed to completely different OSes. Devices may be needed by post-build actions, but they are not something
a sai-builder for a platform can "own" or manage by itself. Instead they are
requested from inside the build action by another tool built with
Rather than reserve the device when the build is spawned, the reservation needs to happen only when the build inside the build context has completed. That in turn means that a different sai utility has to run at that time from inside the build process, in order that it can set things in the already- existing subprocess environment. Devices are logically defined inside a separate conf file
When the build process wants to acquire an embedded device of a particular type
for testing, it runs in the building context, eg, This waits until it can flock() all the ttys of one of the given type of
configured devices ("esp32" in the example), sets up environment vars for each
Baud rate is not considered an attribute of the tty definition but something set for each sai-expect. When the child process or build process ends, the locking is undone and the
device may be acquired by another waiting The underlying locking is done hostwide using flock() on bind mounts of the tty devices, the other containers will observe the locking no matter who did it. Availability of the device node via an environment variable means that CTest or other scripts are able to directly write to the device. Logging of device tty activityThe The paths of these "log proxy" Unix Domain Sockets are exported as environment variables to the child build and test process as follows
Because some kinds of device share the same tty for flashing the device, at
which time nothing else must be reading from the tty, tty activity is only
captured and proxied during actual user testing by Sai device tty loggingDevices may have multiple ttys defined, for example a device with separate ttys and log channels for a main cpu and a coprocessor is supported. The ttys listed on devices have their own log channel index and are timestamped according to when they were read from the tty. In the event many channels are "talking at once", in the web UI the different log channel content appears in different css colours and in chunks of 100 bytes or so, which tends to keep isolated lines of logging intact. Non-Linux: use /home/sai in the main rootfsFor OSX and other cases that doesn't support overlayfs, the same flow occurs just in the main rootfs /home/sai instead of the overlayfs /home/sai. It means things can only be built in the context of the main OS, but since OSX doesn't have different distros, which is the main use of the Linux overlayfs feature, it's still okay. Builder instancesThe config JSON for sai-builder can specify the number of build instances for
each platform. These instances do not have any relationship about what they
are building, just they run in the same platform context (and are managed by
the one Tests have to take care to disambiguate which instance they are running on,
since the network namespace is shared between instances that are running in the
same sai-builder process on the same platform. An environment var
For network related tests, Builder git cachingFor each systemd-nspawn supportOn Linux, it's recommended to use systemd-nspawn to provide multiple distro environments conveniently on one machine. There are instructions for setting up individual virtual ethernet devices managed by nmcli on the host.
|
| Server executables | Function |
|---|---|
| sai-server | The server that builders connect to |
| sai-web | The server that browsers connect to |
| Builder executables | Function |
|---|---|
| sai-builder | The daemon that connects to sai-server and runs builds |
| sai-device | Helper that coordinates which builds wants and can use specific embedded hardware |
| sai-expect | Helper run by embedded build flow to capture serial traffic and react to keywords |
| sai-jig | Helper for embedded devices that lets another device control its buttons, reset etc as part of the embedded build flow |
First you must build lws with appropriate options.
For redhat type distros, you probably need to add /usr/local/lib to the /etc/ld.so.conf before ldconfig can rgister the new libwebsockets.so
$ git clone https://libwebsockets.org/repo/libwebsockets
$ cd libwebsockets && mkdir build && cd build && \
cmake .. -DLWS_UNIX_SOCK=1 -DLWS_WITH_STRUCT_JSON=1 -DLWS_WITH_JOSE=1 \
-DLWS_WITH_STRUCT_SQLITE3=1 -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_SPAWN=1 \
-DLWS_WITH_SECURE_STREAMS=1 -DLWS_WITH_THREADPOOL=1
$ make -j && sudo make -j install && sudo ldconfig
The actual cmake options needed depends on if you are building sai-server and / or sai-builder.
| Feature | lws options |
|---|---|
| either | -DLWS_WITH_STRUCT_JSON=1 -DLWS_WITH_SECURE_STREAMS=1 |
| server | -DLWS_UNIX_SOCK=1 -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_STRUCT_SQLITE3=1 -DLWS_WITH_JOSE=1 |
| builder + related | -DLWS_WITH_SPAWN=1 -DLWS_WITH_THREADPOOL=1 |
You can also define -DLWS_WITH_SYS_METRICS=1 on lws to enable build of
openmetrics pieces in sai when built against lws.
Similarly the two daemons bring in different dependencies
| Feature | dependency |
|---|---|
| either | libwebsockets |
| server | libsqlite3 |
| builder | libgit2 pthreads |
| jig (linux only) | libgpiod |
Unix / Linux
$ git clone https://warmcat.com/repo/sai
$ cd sai && mkdir build && cd build && cmake .. && make && sudo make install
$ sudo cp ../scripts/sai-builder.service /etc/systemd/system
$ sudo mkdir -p /etc/sai/builder
$ sudo cp ../scripts/builder-conf /etc/sai/builder/conf
$ sudo vim /etc/sai/builder/conf
$ sudo systemctl enable sai-builder
Windows builder only
Build libgit2 via vcpkg, this takes <10mins
> vcpkg install libgit2:x64-windows
You have to make git2.dll and some deps visible, in /windows/system32 or similar
> sudo cp "\Users\<user>\vcpkg\installed\x64-windows\bin\pcre.dll" "\windows\system32"
> sudo cp "\Users\<user>\vcpkg\libgit2_x64-windows\bin\git2.dll" "\windows\system32"
Build lws the same way as for unix, except with
> cmake --build . --config DEBUG
> sudo cmake --install . --config DEBUG
For sai it's also very similar to unix, but with
> cmake .. -DSAI_SERVER=0 -DSAI_LWS_INC_PATH="\Users\<user>\libwebsockets\build\include" -DSAI_LWS_LIB_PATH="\Users\<user>\libwebsockets\build\lib\Debug\websockets.lib" -DSAI_GIT2_INC_PATH="\Users\<user>\vcpkg\packages\libgit2_x64-windows\include" -DSAI_GIT2_LIB_PATH="\Users\<user>\vcpkg\packages\libgit2_x64-windows\lib\git2.lib" -DSAI_EXT_PTHREAD_INCLUDE_DIR="C:\Program Files (x86)\pthreads\include" -DSAI_EXT_PTHREAD_LIBRARIES="C:\Program Files (x86)\pthreads\lib\x64\libpthreadGC2.a"
> cmake --build . --config DEBUG
> sudo cmake --install . --config DEBUG
On Windows, the config exists in C:\ProgramData\sai\builder\conf rather than etc.
Additional steps for freebsd
Freebsd presents a few differences from Linux.
1) pkg install bash and other prerequisites like git, cmake etc
2) Create the sai user via adduser and set the uid to 883.
3) Create the builder logproxy socket dir one time as root
# mkdir -p /var/run/com.warmcat.com.saib.logproxy
# chown sai /var/run/com.warmcat.com.saib.logproxy
4) For script portability, ln -sf /usr/local/bin/bash /bin/bash
5) As root copy scripts/etc-rc.d-sai_builder-FreeBSD to /etc/rc.d.
6) As root, edit /etc/rc.conf and add a line sai_builder_enable="YES", then,
sudo /etc/rc.d/sai_builder start
7) Create and prepare /etc/sai/builder/conf as for Linux



