Flashtool Implementation

This describes the implementation of the Flashtool that has been worked out according to the design of the Flashtool.

Overview

The next figure shows the structure of the Flashtool.

Flashtool_overview

Configuration File And Working Directory

The configuration file for the Flashtool is saved in a own working directory for the Flashtool. This working directory can be set by the user when the tool is initialized. When the user does not specify the working directory it will be created in the home directory with the folder name ".flashtool.

This working directory is used to save the configuration files for the platforms and logging files of the Flashtool.

Recipe File For Platforms

The configuration file for the platform act as recipe for the setup procedure. The user is able to define how to partition a MMC storage device of the platform and where the products should be loaded. The Flashtool supports the MMC storage device, because the platforms used in the HTWG context use SD-cards as storage media. How to implement a new recipe type is explained in the deployment section of the Flashtool.

Language

The language of the recipe file is YAML. A recipe file must contain at least one YAML document. Each YAML document specifies a recipe. So a recipe file contains one or more recipes. Each recipe must have a python counterpart, which ensures if all required settings are given, checks the values of the settings and implements the deployment procedure for the storage device.

---
type : ${recipe type}

recipe:
    ${settings for recipe}

This example shows the basic structure of a recipe. Multiple recipes in a recipe file must be divided by ---.

Name Scheme

The name scheme of a recipe file is as follows:

{platform name}.yml} or {platform name}_{identifier}.yml

The platform name and the identifier must not contain underscores. The platform name must also exist on the buildserver configuration for the specific platform. With the identifier it is possible to set multiple recipe files for a platform.

Availability of predefined recipe files

The Flashtool retrieves its recipe files via a repository which is configured on github. This repository already contains recipe files for the rapsberry pi, beaglebone black, utilite pro and banana pi, which are used in the HTWG context. It is also possible to use an other repository with other recipe files.

The repository must be a git repository and the URL to it must be configured in the Flashtool configuration.

User defined recipe files

It is also possible for the user to add a directory for the Flashtool where the user can add own recipe files. This directory is configured in the Flashtool configuration file by the user.

Retrieving software products

The built software product must be retrieved from the builbot web server. The web server provides a JSON api to get all information about every built which was made. This JSON information must be parsed by the Flashtool to get all valid builds. The next list shows the paths which provide different information about the buildbot master and which data is useful for the Flashtool.

The retrieved information of the web server tells the Flashtool which product is available for which platform. The information for the architecture of a platform is also provided in the JSON strings. This information is not stored in the Flashtool and can only be retrieved from the buildserver.

Recognizing MMC devices

To recognize a plugged in MMC device the Flashtool uses the pyudev package. This package allows to listen to the udev events on the system and filter them by some keywords.

First of all the user will be asked to remove the MMC media first. After confirming this step, the python script listens for a udev event:

context = Context()
monitor_mmc = Monitor.from_netlink(context)
monitor_mmc.filter_by(subsystem='block', device_type='disk')

for action, device in monitor_mmc:
    if action in ['add', 'change']:
        self.__count(action, device)
        break

The udev system will trigger various events when plugging in a MMC device. Every event returns an action and a device name. The important event actions are the add and change event. These events are counted for every device.

With this information, the Flashtool decides which of the recorded devices were plugged in by the user. There are 4 scenarios how the user could plug in a MMC card.

  1. User inserts MMC device into a external MMC card reader with multiple MMC slots:

    Python dictionary looks like: (device sdd is MMC card)

    {'add': {}, 'change': {u'sdd': 2}}
    
  2. User inserts the external MMC card reader in the usb port and then inserts the MMC device into the card reader:

    Python dictionary looks like: (device sdd is MMC card)

    {'add': {u'sdb': 1, u'sdc': 1, u'sdd': 1, u'sde': 1, u'sdf': 1},
     'change': {u'sdb': 1, u'sdc': 1, u'sdd': 5, u'sde': 1, u'sdf': 1}}
    
  3. User inserts the external MMC card reader in the usb port and the MMC device was already plugged in the external MMC card reader:

    Python dictionary looks like: (device sdd is MMC card)

    {'add': {u'sdb': 1, u'sdc': 1, u'sdd': 1, u'sde': 1, u'sdf': 1},
     'change': {u'sdb': 1, u'sdc': 1, u'sde': 1, u'sdf': 1}}
    

    This scenario could also lead to a state, that the Flashtool would recognize multiple MMC devices, if there were plugged in multiple MMC devices in the external reader. If that happens the tool will ask the user to choose one of the recognized devices.

  4. User inserts MMC device into an internal MMC card reader:

    Python dictionary looks like: (device mmcblk0 is MMC card)

    {'add': {u'mmcblk0': 1}, 'change': {}}
    

After recognizing the MMC device, the Flashtool will proceed with its setup routine.

Deployment Of Products To The MMC Device

For the deployment procedure several steps has to be done. The sections below will describe these steps:

Checking First MB of MMC device

Before partition the MMC device, the Flashtool generates one Megabyte of random data and copies this data on the first Megabyte of the MMC device. After that the Flashtool reads this Megabyte from the MMC device. A MD5 hash will be generated for the read data and the generated data and will be compared. When the hash strings are the same, the tool assumes that there is no corrupted sector in the storage where the MBR or GPT is saved.

Partition The Device

In the section evaluation a decision was made for the pyparted package for partitioning the MMC device. The Partition layout will be given by the specified recipe file. The usage of the MMC recipe is described in the usage section of the flashtool.

Format The Partitions

The Flashtool uses the mkfs tools of the system to format the partitions. These command will be executed with the subprocess package.

Load The Products On The MMC Device

The Flashtool retrieves all information about built products of the buildbot server. The user can select which version of a product he wants to load on the device. This can be done at the call of the Flashtool with the options linux, uboot, misc, rootfs (see usage Chapter). If the string from the user matches for multiple files the specific file must be selected during the deployment procedure.

Example:

$ flashtool setup raspberry-pi

 +-----------------------------+
 | product:    rootfs          |
 | reg_name:                   |
 | file_types: rootfs, portage |
 +-----------------------------+
Found one version for product rootfs with regex .*.*
-> Selected version: armv6j_hardfp_factory-systemd_20150306055251_c7ce255:

 +-------------------+
 | product:    uboot |
 | reg_name:         |
 | file_types: uboot |
 +-------------------+
Found multiple versions for product uboot with regex .*.*
  [0]: 2015.01-rc1_raspberry-pi_20150101144851_ef42c9b
  [1]: 2015.01_raspberry-pi_20150302180956_7021c3c

[MANUAL-MODE] Please select a file: [0-1]:

After selecting the product versions, the MMC device will be partition and the partitions will be formated. Then the Flashtool will download the product files with the python package urllib.

   +-------------------+
   | LOAD FILES ON MMC |
   +-------------------+

GET BUILD FILES ROOTFS, LINUX, UBOOT, MISC FOR PLATFORM RASPBERRY-PI

  [rootfs]:
    DOWNLOAD FILE:
    URL:  http://moe.in.htwg-konstanz.de:8010/rootfs/factory-systemd/armv6j_hardfp_factory-systemd_20150306055251_c7ce255_rootfs.tbz2
    FILE: armv6j_hardfp_factory-systemd_20150306055251_c7ce255_rootfs.tbz2

     0.5% of 83.7818 MBytes

Generating fstab

At the end of the Flashtool it generates a fstab file and copies it to the rootfs partition of the MMC device. The fstab will be generated with a jinja2 template. The values for the template are retrieved from the given recipe file and the information of pyudev.

Example:

Recipe file:

---
type: mmc

recipe:
    partition_table: msdos
    partitions:
        -   name: boot
            size: 100mb
            fs_type: fat32
            mount_point: /boot
            mount_opts:
            flags: lba
        -   name: rootfs
            size: max
            fs_type: btrfs
            mount_point: /
            mount_opts:
            flags: 
...

jinja2 template:

# <fs>          <mountpoint>    <type>      <opts>      <dump/pass>
{% for obj in info %}
{{obj.uuid}}     {{obj.mountpoint}}     {{obj.type}}     {{obj.options}}     {{obj.dump}}     {{obj.pas}}
{% endfor %}

result fstab:

# <fs>          <mountpoint>    <type>      <opts>      <dump/pass>
UUID=cb7afe2c-d2de-4127-ba87-e8734f144b5f   /boot        vfat       defaults    0       0         
UUID=dc47945f-0282-4994-827e-fdc468bbc432   /        btrfs       defaults    0       0         

List of features

The table below shows a quick overview of the features of the Flashtool. A detailed description of the command can be found in the usage section of the Flashtool

command description
init / config Configure needed options for the Flashtool. Must be done as first step (init) and can be changed any time (config)
platform_recipes Get or update platform recipes from git repository
list_platforms Shows which platforms have a recipe file and can be set up
list_builds List all versions of software components on the platform, grouped by platform and product type
setup runs a deployment procedure for the specified platform
check_mmc Does a filesystem check on every partition on a mmc media

Directory structure of the Flashtool

flashtool
├── configmanager               # Handles the flashtool configuration file
│   └── __init__.py
│
├── server                      # Modules to connec to a Server
│   ├── buildserver.py          # Buildbot server, parsing json data, download files
│   ├── cfgserver.py            # Cloning and pulling from git server
│   └── __init__.py
│ 
├── setup                       # Setup related modules
│   ├── constants.py
│   ├── deploy                  # All packages for preparing hardware and loading software on device
│   │   ├── __init__.py
│   │   ├── load.py
│   │   ├── mmc.py
│   │   └── templateloader.py
│   ├── devlaout                # Contains all modules for setting up a layout for a storage device
│   │   ├── __init__.py
│   │   └── blockdev            # Functions for partition a blockdevice
│   ├── recipe                  # Python recipe representation, check keywords and values
│   │   ├── __init__.py
│   │   └── mmc.py
│   ├── setupfactory            # Loads the right modules statet in the recipe file
│   │   └── __init__.py
│   ├── udev                    # All udev related modules
│   │   ├── __init__.py
│   │   └── mmc.py              # Udev recognition of MMC devices
│   └── __init__.py
│
├── templates                   # Templates
│   └── fstab                   # fstab template
│
├── utility                     # Helper functions which are commonly used
│   └── __init__.py
│
├── tests                       # Directory for unit tests
│   ├── test_recipe.py
│   ├── test_recipe_load.py
│   ├── test_recipe_mmc.py
│   └── mock_path               # path mocks
│
└── __init__.py                 # Entry point of the Flashtool