Using systemd and udev rules

In our example we will use libvirt VM with Container Linux and run systemd unit on disk attach event. First of all we have to create systemd unit file /etc/systemd/system/device-attach.service:

[Service]
Type=oneshot
ExecStart=/usr/bin/echo 'device has been attached'

This unit file will be triggered by our udev rule.

Then we have to start udevadm monitor --environment to monitor kernel events.

Once you've attached virtio libvirt device (i.e. virsh attach-disk coreos /dev/VG/test vdc) you'll see similar udevadm output:

UDEV  [545.954641] add      /devices/pci0000:00/0000:00:18.0/virtio4/block/vdb (block)
.ID_FS_TYPE_NEW=
ACTION=add
DEVNAME=/dev/vdb
DEVPATH=/devices/pci0000:00/0000:00:18.0/virtio4/block/vdb
DEVTYPE=disk
ID_FS_TYPE=
MAJOR=254
MINOR=16
SEQNUM=1327
SUBSYSTEM=block
USEC_INITIALIZED=545954447

According to text above udev generates event which contains directives (ACTION=add and SUBSYSTEM=block) we will use in our rule. It should look this way:

ACTION=="add", SUBSYSTEM=="block", TAG+="systemd", ENV{SYSTEMD_WANTS}="device-attach.service"

That rule means that udev will trigger device-attach.service systemd unit on any block device attachment. Now when we use this command virsh attach-disk coreos /dev/VG/test vdc on host machine, we should see device has been attached message in Container Linux node's journal. This example should be similar to USB/SAS/SATA device attach.

Container Linux Config example

To use the unit and udev rule with a Container Linux Config, modify this example as needed:

This is the human-readable config file. This should not be immediately passed to Container Linux. Learn more.
# This config is meant to be consumed by the config transpiler, which will
# generate the corresponding Ignition config. Do not pass this config directly
# to instances of Container Linux.

storage:
  files:
    - path: /etc/udev/rules.d/01-block.rules 
      filesystem: root
      mode: 0644
      contents:
        inline: |
          ACTION=="add", SUBSYSTEM=="block", TAG+="systemd", ENV{SYSTEMD_WANTS}="device-attach.service"
systemd:
  units:
    - name: device-attach.service
      contents: |
        [Unit]
        Description=Notify about attached device

        [Service]
        Type=oneshot
        ExecStart=/usr/bin/echo 'device has been attached'
This is the raw machine configuration, which is not intended for editing. Learn more. Validate the config here.
{
  "ignition": {
    "version": "2.0.0",
    "config": {}
  },
  "storage": {
    "files": [
      {
        "filesystem": "root",
        "path": "/etc/udev/rules.d/01-block.rules",
        "contents": {
          "source": "data:,ACTION%3D%3D%22add%22%2C%20SUBSYSTEM%3D%3D%22block%22%2C%20TAG%2B%3D%22systemd%22%2C%20ENV%7BSYSTEMD_WANTS%7D%3D%22device-attach.service%22%0A",
          "verification": {}
        },
        "mode": 420,
        "user": {},
        "group": {}
      }
    ]
  },
  "systemd": {
    "units": [
      {
        "name": "device-attach.service",
        "contents": "[Unit]\nDescription=Notify about attached device\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/echo 'device has been attached'"
      }
    ]
  },
  "networkd": {},
  "passwd": {}
}

More systemd examples

For more systemd examples, check out these documents:

Customizing Docker Customizing the SSH Daemon Using systemd Drop-In Units

More information

systemd.service Docs systemd.unit Docs systemd.target Docs udev Docs