Cloud-init with netplan

A customer is using cloud-init to pre-configure their core (pi3) image. They want to pre-configure the network by adding a netplan file that includes Ethernet (DHCP4) and a preconfigured wifi (AP & passphrase).

(For now, it’s unclear whether the image also suppresses console-conf.)

They’ve hit some issues (a long delay on boot when the Ethernet cable is disconnected). Any examples on how to do this?

Cheers

I figured out how to do what I needed, which was specifically:

  • build a core image for the pi3
  • that uses cloud-init
  • to install a netplan file
  • with eth0 set to a working static IP
  • with a wifi access point declared with passphrase and auto-connecting
  • with console-conf disabled
  • and a system-user imported from a usb key on first boot

I made and use below some helper scripts, some of which are used: https://github.com/knitzsche/core-build-scripts

== Assume a model.json file:

{
  "type": "model",
  "system-user-authority": "*",
  "authority-id": "MYSSOACOUNTID", <- NOT a real id
  "brand-id": "MYSSOACCOUNTID", <- NOT real
  "series": "16",
  "model": "testmodel",
  "architecture": "armhf",
  "kernel": "pi2-kernel",
  "gadget": "pi3",
  "timestamp": "2017-07-11T15:55:59+00:00"
}

== Make the model assertion using “model” key (see -h)

$ ./make-model-assertion.sh model-pi3.json model > model.assertion

You need a passphrase to unlock the secret key for
user: "model"
4096-bit RSA key, ID C215EA0F, created 2017-01-01

== Make the image and put it in img-test:

$ sudo ./make-img.sh model.assertion stable img-test
Fetching core
Fetching pi2-kernel
Fetching pi3
built: img-test, with model: model.assertion, from channel: stable

== Enable the image for cloud-init

$ sudo ./enable-cloud-init.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
Removing cloud-init.disabled file
done: img-test/pi3.img

== Disable console-conf

$ sudo ./disable-console-conf.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
done: img-test/pi3.img

== Mount the writable partition of the image

$ sudo ./mount-do-nothing.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
The image is now mounted in mnt/
Press any key to unmount and complete

== In another terminal in same dir, copy a netplan file like this to the correct place in the mounted partition

The netplan file

$ cat mynetplan.yaml 
network:
  version: 2
  ethernets:
    eth0:
      addresses:
        - 10.0.0.244/24
      gateway4:
        10.0.0.1
  wifis:
    wlan0:
      dhcp4:
        true
      access-points:
        "myap":
          password:
            "mypassword"

Make the dir in the mounted partition, and copy the netplan file in

$ sudo mkdir  mnt/system-data/etc/netplan
$ sudo cp mynetplan.yaml mnt/system-data/etc/netplan/01-custom.yaml

=== In previous terminal press Enter to unmount

$ sudo ./mount-do-nothing.sh img-test/pi3.img 
loop_path: /dev/mapper/loop17p2
The image is now mounted in mnt/
Press any key to unmount and complete
[ENTER]
$ 

== dd the image to SD card inserted and mounted to /dev/sdb

WARNING: This script assumes SD is on sdb. It will erase all data on sdb. So you might want to do it manually!

$ sudo ./dd-to-sdb.sh img-test/pi3.img 
19+1 records in
19+1 records out
634260480 bytes (634 MB, 605 MiB) copied, 7.7398 s, 81.9 MB/s
$ 

== Unmount the two partitions on sdb

$ sudo umount /dev/sdb1
$ sudo umount /dev/sdb2

== Remove the SD card

== Make a system-user assertion

$ snap install make-system-user

See make-system-user.run -h to see how to fill in fields

Run it perhaps like this, given the above model.json and the existence of a snapcraft key named “kykey”

$ make-system-user.run -b MYSSOACCOUNTID -m testmodel -u ubuntu -p ubuntu -k mykey

You need a passphrase to unlock the secret key for
user: "mykey"
4096-bit RSA key, ID C375E301, created 2016-01-01

Done. You may copy auto-import.assert to a USB stick and insert it into an unmanaged Core system, after which you can log in using the username and password you provided.

And copy the generated auto-import.assert file to the root dir of your USB key.

== Insert SD, USB and boot

Should work as expected (although nothing yet creates the /etc/cloud/cloud-init.disabled command after first boot, so cloud init would run on every boot, a solvable problem, maybe with a custom systemd unit)

2 Likes

I always thought the plan here was to have the netplan yaml be part of the core snap’s config (which could then be overridden by the gadget).

You shouldn’t need to disable console-conf when using a system user assertion.

@mwhudson, that’s the kind of info I was looking for when I first posted … :wink:

I’ll take a look at using a gadget for the cloud-init/netplan part.

Can’t get a gadget with cloud.conf to work.

If I snap a gadget containing cloud.conf whose content is:

#cloud-config
write_files:
  - encoding: 64
    content: |
      bmV0d29yazoKICB2ZXJzaW9uOiAyCiAgZXRoZXJuZXRzOgogICAgZXRoMDoKICAgICAgYWRkcmVzc2VzOgogICAgICAgIC0gMTAuMC4wLjI0NC8yNAogICAgICBnYXRld2F5NDoKICAgICAgICAxMC4wLjAuMQogIHdpZmlzOgogICAgd2xhbjA6CiAgICAgIGRoY3A0OgogICAgICAgIHRydWUKICAgICAgYWNjZXNzLXBvaW50czoKICAgICAgICAiYXN0cm9fZ2FyZGVuXzIiOgogICAgICAgICAgcGFzc3dvcmQ6CiAgICAgICAgICAgICJ1YnVudHV1YnVudHUi
    owner: root:root
    path: /etc/netplan/01-cloud-init.yaml
    permissions: '0644'

I do not end up with that file created after boot (although cloud-init was enabled in the image). It does end up in /etc/cloud/cloud.cfg, and I can see that being read in journal:

... util.py[DEBUG]: Read 497 bytes from /etc/cloud/cloud.cfg
... util.py[DEBUG]: Attempting to load yaml from string of length 497 with allowed root types (<class 'dict'>,)
... util.py[DEBUG]: Reading from /run/cloud-init/cloud.cfg (quiet=False)

But I finally get the standard /etc/netplan/00-snapd-config.yaml that defines network, not my netplan file from the gadget cloud.conf.

I based that write_files approach on https://cloudinit.readthedocs.io/en/latest/topics/examples.html#writing-out-arbitrary-files

Couple other points:

  • I’d like to use cloud-init’s native ability to declare network config (instead of write_files). In the case of core, seems like the approach would be Network Config Version 2 (https://cloudinit.readthedocs.io/en/latest/topics/network-config.html). But this is said to not support the netplan “wifis” key, which I need. It’s not clear to me whether there is another viable option for core.

  • Giving up on the gadget approach for now, I also tried using a cloud.conf file passed to ubuntu-image with --cloud-config FILE. Unexpectedly, the resulting image seems to have cloud-init disabled:

$ ls mnt/system-data/etc/cloud/
cloud-init.disabled

So, I am so far unable to use the gadget snap cloud.conf to configure netplan with wifi. I see no other way but to mount the image and add my netplan file (as above).

kyleN https://forum.snapcraft.io/u/kylen July 14

@mwhudson https://forum.snapcraft.io/u/mwhudson, that’s the kind of info I was looking for when I first posted … [image: :wink:]

I’ll take a look at using a gadget for the cloud-init/netplan part

I said I thought that was the plan, not that I thought this had happened yet! Sorry if I mislead you