Starting a script on first boot via a systemd service
Make sure that you have completed the steps described in the initial setup page before starting this tutorial. |
In this tutorial, we will run a script on the first boot via a systemd service. We will add the following to the Butane config from the previous scenario:
-
Add a script at
/usr/local/bin/public-ipv4.sh
. -
Configure a systemd service to run the script on first boot.
Writing the script
Let’s write a simple script that uses icanhazip.com to create an issue file to display as a prelogin message on the console:
#!/bin/bash
echo "Detected Public IPv4: is $(curl https://ipv4.icanhazip.com)" > \
/etc/issue.d/50_public-ipv4.issue
This could be useful in cloud environments where you might have different public and private addresses.
We will store this script into /usr/local/bin/public-ipv4.sh
when we provision the machine.
Writing the systemd service
We need to call the script from the previous section by using a systemd unit. Here is one that works for what we want, which is to execute on first boot and not again:
[Unit]
Before=systemd-user-sessions.service
Wants=network-online.target
After=network-online.target
ConditionPathExists=!/var/lib/issuegen-public-ipv4
[Service]
Type=oneshot
ExecStart=/usr/local/bin/public-ipv4.sh
ExecStartPost=/usr/bin/touch /var/lib/issuegen-public-ipv4
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
We will call this unit issuegen-public-ipv4.service
and we will embed it into the Butane config in the next section.
Writing the Butane config and converting to Ignition
We can now create a Butane config by including the script and the systemd unit directly as inline content into the systemd/units and storage/files sections. The final Butane config, stored in services.bu
, will be:
variant: fcos
version: 1.4.0
systemd:
units:
- name: serial-getty@ttyS0.service
dropins:
- name: autologin-core.conf
contents: |
[Service]
# Override Execstart in main unit
ExecStart=
# Add new Execstart with `-` prefix to ignore failure`
ExecStart=-/usr/sbin/agetty --autologin core --noclear %I $TERM
- name: issuegen-public-ipv4.service
enabled: true
contents: |
[Unit]
Before=systemd-user-sessions.service
Wants=network-online.target
After=network-online.target
ConditionPathExists=!/var/lib/issuegen-public-ipv4
[Service]
Type=oneshot
ExecStart=/usr/local/bin/public-ipv4.sh
ExecStartPost=/usr/bin/touch /var/lib/issuegen-public-ipv4
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
storage:
files:
- path: /etc/hostname
mode: 0644
contents:
inline: |
tutorial
- path: /etc/profile.d/systemd-pager.sh
mode: 0644
contents:
inline: |
# Tell systemd to not use a pager when printing information
export SYSTEMD_PAGER=cat
- path: /usr/local/bin/public-ipv4.sh
mode: 0755
contents:
inline: |
#!/bin/bash
echo "Detected Public IPv4: is $(curl https://ipv4.icanhazip.com)" > \
/etc/issue.d/50_public-ipv4.issue
And then convert to Ignition:
butane --pretty --strict services.bu --output services.ign
Testing
Just as before we will use the following to boot the instance:
# Setup the correct SELinux label to allow access to the config
chcon --verbose --type svirt_home_t services.ign
# Start a Fedora CoreOS virtual machine
virt-install --name=fcos --vcpus=2 --ram=2048 --os-variant=fedora-coreos-stable \
--import --network=bridge=virbr0 --graphics=none \
--qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=${PWD}/services.ign" \
--disk=size=20,backing_store=${PWD}/fedora-coreos.qcow2
And view on the console that the Detected Public IPv4
is shown in the console output right before you are dropped to a login prompt:
Fedora CoreOS 36.20220723.3.1 Kernel 5.18.13-200.fc36.x86_64 on an x86_64 (ttyS0) SSH host key: SHA256:YqTZ3U/ii68ApKg79keHqPAzf/PsdKzLovB53apvgXs (ECDSA) SSH host key: SHA256:4a81UJYA4p3bWDlDDTGk0DyBm7ZNdxp1CsQXiUncnPk (ED25519) SSH host key: SHA256:AEWciPbGCeMDypbP7paIE0GC3i6eRBUO4+xME4NGbQw (RSA) enp1s0: 192.168.122.109 fe80::4e18:28bb:b37f:7c61 Ignition: ran on 2022/08/21 01:27:20 UTC (this boot) Ignition: user-provided config was applied No SSH authorized keys provided by Ignition or Afterburn Detected Public IPv4: is 82.255.80.95 tutorial login: core (automatic login) Fedora CoreOS 36.20220723.3.1 [core@tutorial ~]$
And the service shows it was launched successfully:
[core@tutorial ~]$ systemctl status --full issuegen-public-ipv4.service ● issuegen-public-ipv4.service Loaded: loaded (/etc/systemd/system/issuegen-public-ipv4.service; enabled; vendor preset: enabled) Active: active (exited) since Sun 2022-08-21 01:27:29 UTC; 2min 11s ago Process: 1646 ExecStart=/usr/local/bin/public-ipv4.sh (code=exited, status=0/SUCCESS) Process: 1677 ExecStartPost=/usr/bin/touch /var/lib/issuegen-public-ipv4 (code=exited, status=0/SUCCESS) Main PID: 1646 (code=exited, status=0/SUCCESS) CPU: 42ms Aug 21 01:27:29 tutorial systemd[1]: Starting issuegen-public-ipv4.service... Aug 21 01:27:29 tutorial public-ipv4.sh[1647]: % Total % Received % Xferd Average Speed Time Time Time Current Aug 21 01:27:29 tutorial public-ipv4.sh[1647]: Dload Upload Total Spent Left Speed Aug 21 01:27:29 tutorial public-ipv4.sh[1647]: [237B blob data] Aug 21 01:27:29 tutorial systemd[1]: Finished issuegen-public-ipv4.service.
Cleanup
Now let’s take down the instance for the next test. First, disconnect from the serial console by pressing CTRL
+ ]
and then destroy the machine:
virsh destroy fcos virsh undefine --remove-all-storage fcos
You may now proceed with the next tutorial.
Want to help? Learn how to contribute to Fedora Docs ›