A REST API for cloud embedded board reservation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
John-Mark Gurney 3934030af1 flesh out the docs for this a little bit. There is still a lot more 4 months ago
bitelab add test stub for a function to fetch the auth... 4 months ago
fixtures push down code for reserve/release into BoardImpl... 7 months ago
.gitignore Initial work on the API for the lab... 8 months ago
Makefile log the access to stdout for now.. 7 months ago
NOTES.md add some notes about future improvements for auth.. 7 months ago
README.md flesh out the docs for this a little bit. There is still a lot more 4 months ago
requirements.txt Initial work on the API for the lab... 8 months ago
setup.py mark this as requiring 3.8.. needed for asyncio tests and more.. 7 months ago



Bitelab is the server and client portions implemented for a fully remote controlled lab, allowing for each board to have a different set of attributes, which are for things like power control and network access. This means that the board’s power can be controlled via different methods, such as GPIO (not implemented yet) or SNMP control of PoE switches.

This repository is both the client and the server for the bitelab infrastructure.


  • Tunneling of ssh over HTTP(S), allowing only the HTTP endpoint to be exposed publicly, making deployment significantly easier.
  • UCL for configuration of boards


The client expects two environment variables to be set, BITELAB_URL and BITELAB_AUTH. The BITELAB_URL is set to the base URL of the Bitelab API. The BITELAB_AUTH is set to the authentication token. To get an auth token, use the command:

ssh -o 'ProxyCommand bitelab contssh' -l lab bitelab

The last argument, bitelab is not important, just should be unique from other labs, and consistent.

The client provides basic commands to talk to the API. The


The server uses a local configuration file, .env. And example file is:


The db_file entry is used for recording state, but it is also contains the hashed access tokens to grant access to the boards.

The board_conf entry is a pointer to a UCL file that defines all the boards that are supported by the system. An example file is:

setup_script = /ztank/prog/board_script;

classes {
        cora-z7s = { arch = arm-armv7; }
        pine64-a64-lts = { arch = arm64-aarch64; }

boards [
                name = cora-1;
                brdclass = cora-z7s;
                options = [
                        { cls = snmppower, host = poe, port = 2 },
                name = a64lts-1;
                brdclass = pine64-a64-lts;
                options = [
                        { cls = etheriface, val = awg0.103 },
                        { cls = serialconsole, val = /dev/ttyU0 },
                        { cls = snmppower, host = poe, port = 3 },

The setup_script is run when a board is reserved or released. This contains the logic to setup/destroy the file system for the jail, start/terminate the jail and reserve and release resources such as the IP address for the jail.

The classes object contains entires for each class of board. This contains the common parameters for boards that are the same. Boards in a class should be the same so that a user can check out a class, and get a board that matches their needs. This allows adding multiple boards that are popular and allow automatic selection of an available board.

The specific configuration for each board is in the list boards. Each board MUST have a name which needs to be unique, a brdclass to which the board belongs (from the previous classes), and an options list which contains the configuration of the board.

Each option must have a cls parameter, which defines the behavior of the rest of the options.

The following cls values are supported (see _option_map attribute of the class BoardManager in bitelab/__init__.py):

  • etheriface
  • serialconsole
  • snmppower

The remaining items in the object are passed as key word arugments to the respective classes.


This will only work w/ the sqlite3 backend. The orm package does not properly wrap database errors in a database independant exception. The necessary errors should be caught by the test suite, so supporting other databases should be straight forward to do.