Skip to content
Gustavo Niemeyer edited this page Oct 7, 2016 · 21 revisions

Introduction

The gadget snap is responsible for defining and manipulating the system properties which are specific to one or more devices that will usually look similar to one another from an implementation perspective. This snap must necessarily be produced and signed by the device brand, which is defined via the model assertion. The brand knows where and how that device will be used, and designs the gadget snap accordingly.

For example, the brand may know that the device is actually a special VM to be used on a particular cloud, or it may know that it is going to be manufactured in a particular factory. The gadget snap may encode the mechanisms for device initialization - key generation and identity certification - as well as particular processes for the lifecycle of the device, such as factory resets. It is perfectly possible for different models to share a gadget snap.

Canonical publishes some reference gadget snaps as well as gadget snaps for main Canonical models such as official Ubuntu Core VMs on various certified public clouds, as well as general purpose computing images for popular physical devices like the 64-bit x86 PC and Raspberry Pi 2 and 3.

Setup files

In additional to traditional snap metadata, the gadget snap also holds some setup files fundamental to the initialization and lifecycle of the device:

  • meta/snap.yaml - Traditional snap details, with type: gadget explicitly defined.
  • meta/gadget.yaml - Gadget-specific information. See below.
  • grub.conf - Required grub configuration when using this bootloader
  • u-boot.conf - Required u-boot configuration when using this bootloader
  • cloud.conf - Optional cloud-init configuration; cloud-init is disabled if missing.

Sample configuration files may be found in the reference gadget snaps.

gadget.yaml

The meta/gadget.yaml file contains the basic metadata for gadget-specific functionality, including a detailed specification of which structure items composed an image. The latter is used both by snapd and by ubuntu-image when creating images for these devices.

The following specification defines what is supported in gadget.yaml:

# Default configuration options for the defined snaps, applied on installation.
defaults:
    <snap id>:
        <key>: <value>

# If device-tree is specified, `dtbs/<filename>` must exist in kernel or
# gadget snap (depends on origin) and `snap_device_tree_origin` and
# and `snap_device_tree` are made available for u-boot and grub .
device-tree: <filename>
device-tree-origin: kernel

# Volumes defining the structure and content for the images to be written
# into one ore more block devices of the gadget device. Each volume in
# in the structure represents a different image for a "disk" in the device.
volumes:

  # Name of volume and image file generated. Must be formed by [a-z-]+.
  <volume name>:

    # 2-digit hex code for MBR disk ID or GUID for GPT disk id.
    id: <id>
                  
    # Bootloader in the volume. Required in at least one volume.
    bootloader: grub | u-boot

    # Which partitioning schema to use. Defaults to gpt.
    schema: mbr | gpt | mbr,gpt

    # Layout of what goes into the volume, their properties and content.
    structure:
      - # Structure is a list of items.

        # Optional structure item name. There's an implementation-specific
        # constraint on the maximum length. The maximum length of a
        # partition name for GPT is 36 characters in the UTF-16 character set.
        name: <name>

        # GPT unique partition id, unsupported on MBR volumes.
        id: <id>

        # Required type of structure. May be specified as a two-hex-digit
        # MBR partition type, a GPT partition type GUID, or both for hybrid
        # schemas. It may also be "mbr" for the Master Boot Record of a disk.
        type: <mbr type> | <gpt guid> | <mbr type>,<gpt guide> | mbr

        # Required size of the structure. Maximum of 446 for the "mbr" type.
        size: <bytes> | <bytes/2^20>M | <bytes/2^30>G

        # The offset from the beginning of the image. Defaults to right after
        # prior structure item.
        offset: <bytes> | <bytes/2^20>M | <bytes/2^30>G

        # Optional location in which the offset of this structure is written
        # into. It may be specified relative to another structure item, and
        # is written in LBA48 pointer format (32-bit little-endian with index
        # of disk sector).
        offset-write: [<name>+]<bytes> |
                      [<name>+]<bytes/2^20>M |
                      [<name>+]<bytes/2^30>G

        filesystem: none | vfat | ext4  # Defaults to none.
        filesystem-label: <label>       # Defaults to structure item name.

        # Content to be copied from gadget snap into the structure. This
        # field takes a list of one of the following formats:
        content:

            # Copy source (relative to gadget base directory) into filesystem
            # at target (relative to root). Directories must end in a slash.
            - source: <filename> | <dir>/
              target: <filename> | <dir>/

            # Dump image (relative to gadget base directory) of the raw data
            # as-is into the structure at offset. If offset is omitted it
            # defaults to right after prior content item. If size is omitted,
            # defaults to size of contained data.
            - image: <filename>
              offset: <bytes> | <bytes/2^20>M | <bytes/2^30>G
              offset-write: (see respective item above)
              size: <bytes> | <bytes/2^20>M | <bytes/2^30>G
# The prepare-device hook

The optional prepare-device hook will be called on the gadget at the start of the device initialization process, after the gadget snap has been installed. The hook will also be called if this process is retried later from scratch in case of initialization failures.

The device initialization process is for example responsible of setting the serial identification of the device through an exchange with a device service. The prepare-device hook can for example redirect this exchange and dynamically set options relevant to it.

Example

#!/bin/sh

# optionally set the url of the service
snapctl set device-service.url="https://device-service"
# set optional extra HTTP headers for requests to the service
snapctl set device-service.headers='{"token": "TOKEN"}'

# set an optional proposed serial identifier, depending on the service
# this can end up being ignored;
# this might need to be obtained dynamically
snapctl set registration.proposed-serial="DEVICE-SERIAL"

# optionally pass details of the device as the body of registration request,
# the body is text, typically YAML;
# this might need to be obtained dynamically
snapctl set registration.body='mac: "00:00:00:00:ff:00"'
Clone this wiki locally