Published using Google Docs
Getting Started with Dockerized Servod
Updated automatically every 5 minutes

THIS DOCUMENT IS SHARED PUBLICLY

Getting Started with Dockerized Servod

Author: Keith Haddow

Date: Aug 24, 2022

Introduction

This is a quick introduction for those wishing to use servod in a dockerized container, both directly as part of implementing the docker servod into their lab processes.

It should be noted that as servod requires low level access to the USB hardware the container runs in protected mode, which takes down many of the protections to the host that a typical container would provide.   To be clear, it is not worse or better than running servod natively on the host.

Currently servod will only run on linux distributions, running on Windows is not supported.

Also currently the image is available only on x86 architectures but should also be available on arm64 later in 2022.   At that time the image will be multi architecture, so the instructions will be identical on arm64 devices.

Prerequisites

Before you start you need to install the docker application, python 3 and the python docker api package.

Install Docker

You need to install docker onto the machine that is going to be the host for the docker containers.

https://docs.docker.com/desktop/install/linux-install/

Install Python

The example below works for debian/ubuntu - your command may be different depending on your linux distribution.

sudo apt install python3

Install Python docker API.

docker · PyPI

Copy paste the code below and make the file start_servod_release.py.

#!/usr/bin/env python3

# Copyright 2022 The Chromium OS Authors. All rights reserved.

# Use of this source code is governed by a BSD-style license that can be

# found in the LICENSE file.

import docker

import logging

import argparse

IMAGE = "us-docker.pkg.dev/chromeos-hw-tools/servod/servod:release"

def setup():

    client = docker.from_env()

    try:

        client.images.pull(IMAGE)

    except docker.errors.APIError:

        logging.exception("Failed to pull image")

    return client

def start_servod(client, dut_hostname, board, model, serial_no):

    environment = [

        "BOARD=%s" % board,

        "MODEL=%s" % model,

        "SERIAL=%s" % serial_no,

        "PORT=%s" % "9999",

    ]

    name = "%s-docker_servod" % dut_hostname

    logs_volume = "%s_log" % dut_hostname

    command = ["bash", "/start_servod.sh"]

    cont = client.containers.run(

        IMAGE,

        remove=True,

        privileged=True,

        name=name,

        hostname=name,

        cap_add=["NET_ADMIN"],

        detach=True,

        volumes=["/dev:/dev", "%s:/var/log/servod_9999/" % logs_volume],

        environment=environment,

        command=command,

    )

    log_lines = cont.logs(stream=True, follow=True)

    started = False

    while log_lines and not started:

        cont.reload()

        for line in log_lines:

            print(line.decode("utf-8").strip())

            if b"servod - INFO - Listening on 0.0.0.0 port" in line:

                started = True

                logging.info("Detected servod has started.")

                break

        if cont.status == "removing":

            break

if __name__ == "__main__":

    parser = argparse.ArgumentParser(add_help=False)

    parser.add_argument(

        "-h",

        "--hostname",

        required=True,

        type=str,

        help="The IP or hostname of the DUT connected to servo.",

    )

    parser.add_argument(

        "-b", "--board", required=True, type=str, help="The board of the DUT."

    )

    parser.add_argument(

        "-m", "--model", required=True, type=str, help="The model of the DUT."

    )

    parser.add_argument(

        "-s",

        "--serial",

        required=True,

        type=str,

        help="The serial number of the servo.",

    )

    args = parser.parse_args()

    client = setup()

    start_servod(

        client, args.hostname, args.board, args.model, args.serial

    )

Using servod

Starting

Note the first time you run this it will download the image to your local machine so it may take some time.

chmod u+x start_servod_release.py

./start_servod_release.py -b <DUT board> -m <DUT Model> -s <servo serial number> -h <DUT IP/Hostname>

The DUT IP/Hostname just needs to be a unique string for the naming of the docker containers, any unique string will do.

You should see logs of logs ending with

Servod - INFO - Initialized servo_v4p1_uart_timestamp to on

Servod - INFO - Initialized servo_dts_mode to on

Servod - INFO - Initialized warm_reset to off

activeV4Device - INFO - Active device is already 'ccd_cr50'

DeviceWatchdog - INFO - Reinit capable device found. Polling rate set to 0.10s.

DeviceWatchdog - INFO - Watchdog setup for devices: [18d1:520d SERVOV4P1-S-2107250755, 18d1:5014 0700A01F-9420C774]

servod - INFO - Listening on 0.0.0.0 port 9999

At this point servod is running inside of your docker container.

Execute dut-control commands

To execute commands on the servo you can either:

Run bash on the container interactively - giving an experience similar to ssh into a host machine running the servod natively

docker exec -it <hostname>-docker_servod bash

Then you can just run dut-control commands as normal.

Yout can also just run the dut control command:

docker exec -it <hostname>-docker_servod dut-control --get-all

In this example I did not show opening the XML api to the host, this can be done.   There can be some extra configuration to get this working if you want to scale it by creating a docker network that the containers run in and then you just address each servo API as hostname:9999 vs before addressing as localhost:<port number>.   If more details on this scenario are needed please let me know.

Servod Logs

Logs are preserved in a docker volume for each hostname.  So there will be a volume called <hostname>_log

If you are in a servod container then the logs are just mounted at /var/log/servod_9999

If the container is not starting and you want to look at the logs, just start another vanilla container and mount the logs volume.  So:

docker run -it -v <hostname>_log:/tmp/servo_logs debian bash

And you will be able to see the logs at /tmp/servo_logs

Firmware Updates

Firmware updates can not run at the same time as servod.   So the container needs to change to running that command first.

You can change the command line in the script to run

  command = ["servo_updater", "-b", "<servo type>", "-s", serial_no]

Better solution coming soon…..