Automatic gadget asset updates

One of the requests we get from integrators is to allow to update assets in the gadget snap. The gadget snap is currently updated (like any other snap).

However the parts described in meta/gadget.yaml is only read on image provisioning (example: https://github.com/snapcore/pc-amd64-gadget/blob/master/gadget.yaml).

I propose we add a new yaml key under “content” that allows to specify “auto-refresh: true” as an opt-in. If snapd finds content with this option it will copy those files from the gadget snap to the target filesystem if the files are different.

There is also the idea of adding more semantic descriptions for this.

This should solve bug https://bugs.launchpad.net/snapd/+bug/1664388

1 Like

well, depends with regard to that specific bug … on a pi install you might manually modify things like config.txt or cmdline.txt for specific system related bits (fixed HDMI resolution etc), blindly overwriting such files seems like a bad idea in that case.

  • we could allow a file blacklist “never-touch: […]”
  • add a checksum test, update only if the file is original (but then we should notify the user)
  • or we actually parse the file and carry changes over

in general it seems like a good plan for all bootloader binaries though.

We discussed this topic at length in the prior sprint and agreed on details of how the process should work:

The topic was discussed again during Malta engineering sprint and work has commenced.

Near term plan

  • updates are opt-in
  • there is a per structure entry in gadget.yaml (https://github.com/snapcore/snapd/pull/6609)
    device-tree: bcm2709-rpi-2-b
    volumes:
      pi:
        schema: mbr
        bootloader: u-boot
        structure:
          - type: 0C
            filesystem: vfat
            filesystem-label: system-boot
            size: 128M
            content:
              - source: boot-assets/
                target: /
            # new entries
            update:
                edition: 5
                preserve: 
                  - uboot.env
    
  • update only iff edition is different
  • preserve entries listed in preserve list:
    • is the list case sensitive?
      • warn/error out when duplicate entries with different casing?
    • can use glob?
  • no support for preserving inside images, mbr entry below will updated by overwriting the whole image
    volumes:
      pc:
        bootloader: grub
        structure:
          - name: mbr
            type: mbr
            size: 440
            content:
              - image: pc-boot.img
            update:
              edition: 2
    

Long term plan

  • referencing kernel assets

    # gadget.yaml
    volumes:
      pi:
        schema: mbr
        bootloader: u-boot
        structure:
          - type: 0C
            filesystem: vfat
            filesystem-label: system-boot
            size: 128M
            content:
              ...
              - source: $kernel:dtb/
                target: /
                update: true
    

    NOTE: will require changes in ubuntu-image

  • revive kernel.yaml?

    assets: 
        <name>: 
        edition: 1 
        content: 
            - a.bin
             - ...
    
    • kernel.yaml does not seem to be used in current snapd anymore
  • update when edition in kernel.yaml changes && update: true in gadget.yaml

Quick discussion with @mvo and @pedronis to hash some things out.

Notes:

  • Add internal API for writing the structure, don’t write it yet

  • try to do the writes atomically

  • DTBs may have a fallback strategy

    • defer supporting DBTs until we have a fallback strategy
  • UC20 always use the recovery bootloader

  • When in the snap update cycle apply the update?

    • updates are opt-in
    • last task in the gadget update
      • after mount
      • apply update & reboot
      • update task is noop if no updates are defined in gadget.yaml
    • look into preventing other tasks from running in parallel
    • order of structure updates follows YAML
    • Reboot must be before auto-connect, in case gadget slots only make sense after the update has been applied
  • Undo

    • Copy out the existing data
    • Clean it up in the cleanup task
    • Data must survive reboot
    • Store data /var/snap or somewhere under /var/lib/snapd?
    • Do not touch entries that are in preserve section
  • Structure update

    • Do not support removing entries until there is a need to do so
  • gadget.yaml

    • validation
      • not needed for the first stage of work
      • replicate ubuntu-image validation once we split out the binary
      • single structure sanity
      • cross structure sanity (eg. overlap)
    • structure size change, error out
    • filesystem-label change, error out
    • filesystem change, error out
    • type, error out
    • think about using the old revision for cross-revision validation?
    • ignore name casing (for duplicates), look at what ubuntu-image does
    • adding new structure entries does not need to be supported initially\
      • error out initally?
  • refactor current snapd packages

    • introduce a bootloader package
      • preferably move grub/uboot wrappers and handlers to the new package

you might also want to error on structure offset change (which would (have to) result in re-partitioning otherwise)

A short status update for those who are interested.

There is a bunch of open pull requests, some with reviews. The whole end-to-end update is functional, but still lives in a branch within my snapd fork. What works/status:

  • update of filesystem structures
    • dropping new files at the right mount point
    • optionally preserving explicitly listed entries
  • update of bare structures
    • completely replace the content of bare structure
  • only modified content is updated
  • gadget assets update is followed by a reboot
  • failure to deploy the contents (be it filesystem or raw images) does a complete rollback, so the update does not stay half applied
  • there is no undo of boot assets installation

Limitations:

  • structures need to be named in order to be found during update
    • using name: <foo> or filesystem-label: <foo>
  • bare structures need to have a partition entry
    • eg. the update will not be able to identify a structure of type bare (or legacy mbr)
    • there are possible options to mitigate this, eg. look at other structures from the volume, assume writable is on the same device or have an explicit configuration entry with device name
    • I would be wary of any heuristics in identifying the device/partition

Open questions:

  • handling of update when it is removed in subsequent revision of gadget YAML
    • device is at rev 1, say rev 2 has a structure with update field, so gadget assets update is applied, but then update is dropped in rev 3 (@mvo @pedronis maybe we should have a chat about this)
  • do we need to reboot after updating gadget assets

Bonus:

  • a tool to generate images, dubbed snap-image (strawman)
    • takes a prepared rootfs (snap prepare-image), volume name and any additional partitions and creates a bootable image

Last PR in the series has landed. This will be part of 2.41 release.

Hi @mborzecki @mvo,

Great information about gadget update mechanism, in order to let more people know / howto, I’ve edited the doc for the gadget about asset updates feature by adding new section after content:

Can you review the yaml syntax to make sure my understanding is correct or not?
Thanks.

2 Likes

Thanks. I’ve added some more details in a dedicated page: Updating gadget boot assets