Use parser.UnitFile

Uses the systemd unit file parser to build unit files instead of having
them be just blocks of hard-coded strings.

Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
This commit is contained in:
Jake Correnti
2023-11-16 15:32:10 -05:00
parent c728eeb39e
commit 98f332d482
4 changed files with 172 additions and 153 deletions

View File

@ -26,6 +26,7 @@ import (
"github.com/containers/podman/v4/pkg/machine/vmconfigs" "github.com/containers/podman/v4/pkg/machine/vmconfigs"
"github.com/containers/podman/v4/pkg/machine/ignition" "github.com/containers/podman/v4/pkg/machine/ignition"
"github.com/containers/podman/v4/pkg/strongunits" "github.com/containers/podman/v4/pkg/strongunits"
"github.com/containers/podman/v4/pkg/systemd/parser"
"github.com/containers/podman/v4/pkg/util" "github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils" "github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/lockfile" "github.com/containers/storage/pkg/lockfile"
@ -46,21 +47,13 @@ const (
apiUpTimeout = 20 * time.Second apiUpTimeout = 20 * time.Second
) )
// appleHVReadyUnit is a unit file that sets up the virtual serial device // VfkitHelper describes the use of vfkit: cmdline and endpoint
// where when the VM is done configuring, it will send an ack type VfkitHelper struct {
// so a listening host knows it can begin interacting with it LogLevel logrus.Level
const appleHVReadyUnit = `[Unit] Endpoint string
Requires=dev-virtio\\x2dports-%s.device VfkitBinaryPath *define.VMFile
After=remove-moby.service sshd.socket sshd.service VirtualMachine *vfConfig.VirtualMachine
OnFailure=emergency.target }
OnFailureJobMode=isolate
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:1025'
[Install]
RequiredBy=default.target
`
type MacMachine struct { type MacMachine struct {
// ConfigPath is the fully qualified path to the configuration file // ConfigPath is the fully qualified path to the configuration file
@ -274,10 +267,15 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
return false, err return false, err
} }
readyUnitFile, err := createReadyUnitFile()
if err != nil {
return false, err
}
builder.WithUnit(ignition.Unit{ builder.WithUnit(ignition.Unit{
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: "ready.service", Name: "ready.service",
Contents: ignition.StrToPtr(fmt.Sprintf(appleHVReadyUnit, "vsock")), Contents: ignition.StrToPtr(readyUnitFile),
}) })
builder.WithUnit(generateSystemDFilesForVirtiofsMounts(virtiofsMnts)...) builder.WithUnit(generateSystemDFilesForVirtiofsMounts(virtiofsMnts)...)
@ -288,6 +286,13 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
return err == nil, err return err == nil, err
} }
func createReadyUnitFile() (string, error) {
readyUnit := ignition.DefaultReadyUnitFile()
readyUnit.Add("Unit", "Requires", "dev-virtio\\x2dports-vsock.device")
readyUnit.Add("Service", "ExecStart", "/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:1025'")
return readyUnit.ToString()
}
func (m *MacMachine) removeSSHKeys() error { func (m *MacMachine) removeSSHKeys() error {
if err := os.Remove(fmt.Sprintf("%s.pub", m.IdentityPath)); err != nil { if err := os.Remove(fmt.Sprintf("%s.pub", m.IdentityPath)); err != nil {
logrus.Error(err) logrus.Error(err)
@ -1111,31 +1116,34 @@ func generateSystemDFilesForVirtiofsMounts(mounts []machine.VirtIoFs) []ignition
// Here we are looping the mounts and for each mount, we are adding two unit files // Here we are looping the mounts and for each mount, we are adding two unit files
// for virtiofs. One unit file is the mount itself and the second is to automount it // for virtiofs. One unit file is the mount itself and the second is to automount it
// on boot. // on boot.
autoMountUnit := `[Automount] autoMountUnit := parser.NewUnitFile()
Where=%s autoMountUnit.Add("Automount", "Where", "%s")
[Install] autoMountUnit.Add("Install", "WantedBy", "multi-user.target")
WantedBy=multi-user.target autoMountUnit.Add("Unit", "Description", "Mount virtiofs volume %s")
autoMountUnitFile, err := autoMountUnit.ToString()
if err != nil {
logrus.Warnf(err.Error())
}
[Unit] mountUnit := parser.NewUnitFile()
Description=Mount virtiofs volume %s mountUnit.Add("Mount", "What", "%s")
` mountUnit.Add("Mount", "Where", "%s")
mountUnit := `[Mount] mountUnit.Add("Mount", "Type", "virtiofs")
What=%s mountUnit.Add("Install", "WantedBy", "multi-user.target")
Where=%s mountUnitFile, err := mountUnit.ToString()
Type=virtiofs if err != nil {
logrus.Warnf(err.Error())
}
[Install]
WantedBy=multi-user.target
`
virtiofsAutomount := ignition.Unit{ virtiofsAutomount := ignition.Unit{
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: fmt.Sprintf("%s.automount", mnt.Tag), Name: fmt.Sprintf("%s.automount", mnt.Tag),
Contents: ignition.StrToPtr(fmt.Sprintf(autoMountUnit, mnt.Target, mnt.Target)), Contents: ignition.StrToPtr(fmt.Sprintf(autoMountUnitFile, mnt.Target, mnt.Target)),
} }
virtiofsMount := ignition.Unit{ virtiofsMount := ignition.Unit{
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: fmt.Sprintf("%s.mount", mnt.Tag), Name: fmt.Sprintf("%s.mount", mnt.Tag),
Contents: ignition.StrToPtr(fmt.Sprintf(mountUnit, mnt.Tag, mnt.Target)), Contents: ignition.StrToPtr(fmt.Sprintf(mountUnitFile, mnt.Tag, mnt.Target)),
} }
// This "unit" simulates something like systemctl enable virtiofs-mount-prepare@ // This "unit" simulates something like systemctl enable virtiofs-mount-prepare@
@ -1149,23 +1157,24 @@ WantedBy=multi-user.target
// mount prep is a way to workaround the FCOS limitation of creating directories // mount prep is a way to workaround the FCOS limitation of creating directories
// at the rootfs / and then mounting to them. // at the rootfs / and then mounting to them.
mountPrep := ` mountPrep := parser.NewUnitFile()
[Unit] mountPrep.Add("Unit", "Description", "Allow virtios to mount to /")
Description=Allow virtios to mount to / mountPrep.Add("Unit", "DefaultDependencies", "no")
DefaultDependencies=no mountPrep.Add("Unit", "ConditionPathExists", "!%f")
ConditionPathExists=!%f
[Service] mountPrep.Add("Service", "Type", "oneshot")
Type=oneshot mountPrep.Add("Service", "ExecStartPre", "chattr -i /")
ExecStartPre=chattr -i / mountPrep.Add("Service", "ExecStart", "mkdir -p '%f'")
ExecStart=mkdir -p '%f' mountPrep.Add("Service", "ExecStopPost", "chattr +i /")
ExecStopPost=chattr +i /
mountPrep.Add("Install", "WantedBy", "remote-fs.target")
mountPrepFile, err := mountPrep.ToString()
if err != nil {
logrus.Warnf(err.Error())
}
[Install]
WantedBy=remote-fs.target
`
virtioFSChattr := ignition.Unit{ virtioFSChattr := ignition.Unit{
Contents: ignition.StrToPtr(mountPrep), Contents: ignition.StrToPtr(mountPrepFile),
Name: "virtiofs-mount-prepare@.service", Name: "virtiofs-mount-prepare@.service",
} }
unitFiles = append(unitFiles, virtioFSChattr) unitFiles = append(unitFiles, virtioFSChattr)

View File

@ -24,6 +24,7 @@ import (
"github.com/containers/podman/v4/pkg/machine/vmconfigs" "github.com/containers/podman/v4/pkg/machine/vmconfigs"
"github.com/containers/podman/v4/pkg/machine/ignition" "github.com/containers/podman/v4/pkg/machine/ignition"
"github.com/containers/podman/v4/pkg/strongunits" "github.com/containers/podman/v4/pkg/strongunits"
"github.com/containers/podman/v4/pkg/systemd/parser"
"github.com/containers/podman/v4/pkg/util" "github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils" "github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/lockfile" "github.com/containers/storage/pkg/lockfile"
@ -46,40 +47,6 @@ const (
apiUpTimeout = 20 * time.Second apiUpTimeout = 20 * time.Second
) )
// hyperVReadyUnit is a unit file that sets up the virtual serial device
// where when the VM is done configuring, it will send an ack
// so a listening host knows it can begin interacting with it
//
// VSOCK-CONNECT:2 <- shortcut to connect to the hostvm
const hyperVReadyUnit = `[Unit]
After=remove-moby.service sshd.socket sshd.service
After=systemd-user-sessions.service
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:%d'
[Install]
RequiredBy=default.target
`
// hyperVVsockNetUnit is a systemd unit file that calls the vm helper utility
// needed to take traffic from a network vsock0 device to the actual vsock
// and onto the host
const hyperVVsockNetUnit = `
[Unit]
Description=vsock_network
After=NetworkManager.service
[Service]
ExecStart=/usr/libexec/podman/gvforwarder -preexisting -iface vsock0 -url vsock://2:%d/connect
ExecStartPost=/usr/bin/nmcli c up vsock0
[Install]
WantedBy=multi-user.target
`
const hyperVVsockNMConnection = ` const hyperVVsockNMConnection = `
[connection] [connection]
id=vsock0 id=vsock0
@ -278,14 +245,24 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
return false, err return false, err
} }
readyUnitFile, err := createReadyUnit(m.ReadyHVSock.Port)
if err != nil {
return false, err
}
builder.WithUnit(ignition.Unit{ builder.WithUnit(ignition.Unit{
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: "ready.service", Name: "ready.service",
Contents: ignition.StrToPtr(fmt.Sprintf(hyperVReadyUnit, m.ReadyHVSock.Port)), Contents: ignition.StrToPtr(readyUnitFile),
}) })
netUnitFile, err := createNetworkUnit(m.NetworkHVSock.Port)
if err != nil {
return false, err
}
builder.WithUnit(ignition.Unit{ builder.WithUnit(ignition.Unit{
Contents: ignition.StrToPtr(fmt.Sprintf(hyperVVsockNetUnit, m.NetworkHVSock.Port)), Contents: ignition.StrToPtr(netUnitFile),
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: "vsock-network.service", Name: "vsock-network.service",
}) })
@ -316,6 +293,23 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
return err == nil, err return err == nil, err
} }
func createReadyUnit(readyPort uint64) (string, error) {
readyUnit := ignition.DefaultReadyUnitFile()
readyUnit.Add("Unit", "After", "systemd-user-sessions.service")
readyUnit.Add("Service", "ExecStart", fmt.Sprintf("/bin/sh -c '/usr/bin/echo Ready | socat - VSOCK-CONNECT:2:%d'", readyPort))
return readyUnit.ToString()
}
func createNetworkUnit(netPort uint64) (string, error) {
netUnit := parser.NewUnitFile()
netUnit.Add("Unit", "Description", "vsock_network")
netUnit.Add("Unit", "After", "NetworkManager.service")
netUnit.Add("Service", "ExecStart", fmt.Sprintf("/usr/libexec/podman/gvforwarder -preexisting -iface vsock0 -url vsock://2:%d/connect", netPort))
netUnit.Add("Service", "ExecStartPost", "/usr/bin/nmcli c up vsock0")
netUnit.Add("Install", "WantedBy", "multi-user.target")
return netUnit.ToString()
}
func (m *HyperVMachine) unregisterMachine() error { func (m *HyperVMachine) unregisterMachine() error {
vmm := hypervctl.NewVirtualMachineManager() vmm := hypervctl.NewVirtualMachineManager()
vm, err := vmm.GetMachine(m.Name) vm, err := vmm.GetMachine(m.Name)

View File

@ -11,6 +11,7 @@ import (
"path/filepath" "path/filepath"
"github.com/containers/podman/v4/pkg/machine/define" "github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/pkg/systemd/parser"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -134,23 +135,24 @@ func (ign *DynamicIgnition) GenerateIgnitionConfig() error {
ignStorage.Links = append(ignStorage.Links, tzLink) ignStorage.Links = append(ignStorage.Links, tzLink)
} }
deMoby := `[Unit] deMoby := parser.NewUnitFile()
Description=Remove moby-engine deMoby.Add("Unit", "Description", "Remove moby-engine")
# Run once for the machine deMoby.Add("Unit", "After", "systemd-machine-id-commit.service")
After=systemd-machine-id-commit.service deMoby.Add("Unit", "Before", "zincati.service")
Before=zincati.service deMoby.Add("Unit", "ConditionPathExists", "!/var/lib/%N.stamp")
ConditionPathExists=!/var/lib/%N.stamp
[Service] deMoby.Add("Service", "Type", "oneshot")
Type=oneshot deMoby.Add("Service", "RemainAfterExit", "yes")
RemainAfterExit=yes deMoby.Add("Service", "ExecStart", "/usr/bin/rpm-ostree override remove moby-engine")
ExecStart=/usr/bin/rpm-ostree override remove moby-engine deMoby.Add("Service", "ExecStart", "/usr/bin/rpm-ostree ex apply-live --allow-replacement")
ExecStart=/usr/bin/rpm-ostree ex apply-live --allow-replacement deMoby.Add("Service", "ExecStartPost", "/bin/touch /var/lib/%N.stamp")
ExecStartPost=/bin/touch /var/lib/%N.stamp
deMoby.Add("Install", "WantedBy", "default.target")
deMobyFile, err := deMoby.ToString()
if err != nil {
return err
}
[Install]
WantedBy=default.target
`
// This service gets environment variables that are provided // This service gets environment variables that are provided
// through qemu fw_cfg and then sets them into systemd/system.conf.d, // through qemu fw_cfg and then sets them into systemd/system.conf.d,
// profile.d and environment.d files // profile.d and environment.d files
@ -158,34 +160,39 @@ WantedBy=default.target
// Currently, it is used for propagating // Currently, it is used for propagating
// proxy settings e.g. HTTP_PROXY and others, on a start avoiding // proxy settings e.g. HTTP_PROXY and others, on a start avoiding
// a need of re-creating/re-initiating a VM // a need of re-creating/re-initiating a VM
envset := `[Unit]
Description=Environment setter from QEMU FW_CFG envset := parser.NewUnitFile()
[Service] envset.Add("Unit", "Description", "Environment setter from QEMU FW_CFG")
Type=oneshot
RemainAfterExit=yes envset.Add("Service", "Type", "oneshot")
Environment=FWCFGRAW=/sys/firmware/qemu_fw_cfg/by_name/opt/com.coreos/environment/raw envset.Add("Service", "RemainAfterExit", "yes")
Environment=SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf envset.Add("Service", "Environment", "FWCFGRAW=/sys/firmware/qemu_fw_cfg/by_name/opt/com.coreos/environment/raw")
Environment=ENVD_CONF=/etc/environment.d/default-env.conf envset.Add("Service", "Environment", "SYSTEMD_CONF=/etc/systemd/system.conf.d/default-env.conf")
Environment=PROFILE_CONF=/etc/profile.d/default-env.sh envset.Add("Service", "Environment", "ENVD_CONF=/etc/environment.d/default-env.conf")
ExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} &&\ envset.Add("Service", "Environment", "PROFILE_CONF=/etc/profile.d/default-env.sh")
echo "[Manager]\n#Got from QEMU FW_CFG\nDefaultEnvironment=$(/usr/bin/base64 -d ${FWCFGRAW} | sed -e "s+|+ +g")\n" > ${SYSTEMD_CONF} ||\ envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} &&\
echo "[Manager]\n#Got nothing from QEMU FW_CFG\n#DefaultEnvironment=\n" > ${SYSTEMD_CONF}' echo "[Manager]\n#Got from QEMU FW_CFG\nDefaultEnvironment=$(/usr/bin/base64 -d ${FWCFGRAW} | sed -e "s+|+ +g")\n" > ${SYSTEMD_CONF} ||\
ExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\ echo "[Manager]\n#Got nothing from QEMU FW_CFG\n#DefaultEnvironment=\n" > ${SYSTEMD_CONF}'`)
echo "#Got from QEMU FW_CFG"> ${ENVD_CONF};\ envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\
IFS="|";\ echo "#Got from QEMU FW_CFG"> ${ENVD_CONF};\
for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\ IFS="|";\
echo "$iprxy" >> ${ENVD_CONF}; done ) || \ for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\
echo "#Got nothing from QEMU FW_CFG"> ${ENVD_CONF}' echo "$iprxy" >> ${ENVD_CONF}; done ) || \
ExecStart=/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\ echo "#Got nothing from QEMU FW_CFG"> ${ENVD_CONF}'`)
echo "#Got from QEMU FW_CFG"> ${PROFILE_CONF};\ envset.Add("Service", "ExecStart", `/usr/bin/bash -c '/usr/bin/test -f ${FWCFGRAW} && (\
IFS="|";\ echo "#Got from QEMU FW_CFG"> ${PROFILE_CONF};\
for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\ IFS="|";\
echo "export $iprxy" >> ${PROFILE_CONF}; done ) || \ for iprxy in $(/usr/bin/base64 -d ${FWCFGRAW}); do\
echo "#Got nothing from QEMU FW_CFG"> ${PROFILE_CONF}' echo "export $iprxy" >> ${PROFILE_CONF}; done ) || \
ExecStartPost=/usr/bin/systemctl daemon-reload echo "#Got nothing from QEMU FW_CFG"> ${PROFILE_CONF}'`)
[Install] envset.Add("Service", "ExecStartPost", "/usr/bin/systemctl daemon-reload")
WantedBy=sysinit.target
` envset.Add("Install", "WantedBy", "sysinit.target")
envsetFile, err := envset.ToString()
if err != nil {
return err
}
ignSystemd := Systemd{ ignSystemd := Systemd{
Units: []Unit{ Units: []Unit{
{ {
@ -205,7 +212,7 @@ WantedBy=sysinit.target
{ {
Enabled: BoolToPtr(true), Enabled: BoolToPtr(true),
Name: "remove-moby.service", Name: "remove-moby.service",
Contents: &deMoby, Contents: &deMobyFile,
}, },
{ {
// Disable auto-updating of fcos images // Disable auto-updating of fcos images
@ -220,7 +227,7 @@ WantedBy=sysinit.target
qemuUnit := Unit{ qemuUnit := Unit{
Enabled: BoolToPtr(true), Enabled: BoolToPtr(true),
Name: "envset-fwcfg.service", Name: "envset-fwcfg.service",
Contents: &envset, Contents: &envsetFile,
} }
ignSystemd.Units = append(ignSystemd.Units, qemuUnit) ignSystemd.Units = append(ignSystemd.Units, qemuUnit)
} }
@ -299,13 +306,16 @@ func getDirs(usrName string) []Directory {
func getFiles(usrName string, uid int, rootful bool, vmtype define.VMType) []File { func getFiles(usrName string, uid int, rootful bool, vmtype define.VMType) []File {
files := make([]File, 0) files := make([]File, 0)
lingerExample := `[Unit] lingerExample := parser.NewUnitFile()
Description=A systemd user unit demo lingerExample.Add("Unit", "Description", "A systemd user unit demo")
After=network-online.target lingerExample.Add("Unit", "After", "network-online.target")
Wants=network-online.target podman.socket lingerExample.Add("Unit", "Wants", "network-online.target podman.socket")
[Service] lingerExample.Add("Service", "ExecStart", "/usr/bin/sleep infinity")
ExecStart=/usr/bin/sleep infinity lingerExampleFile, err := lingerExample.ToString()
` if err != nil {
logrus.Warnf(err.Error())
}
containers := `[containers] containers := `[containers]
netns="bridge" netns="bridge"
` `
@ -336,7 +346,7 @@ Delegate=memory pids cpu io
FileEmbedded1: FileEmbedded1{ FileEmbedded1: FileEmbedded1{
Append: nil, Append: nil,
Contents: Resource{ Contents: Resource{
Source: EncodeDataURLPtr(lingerExample), Source: EncodeDataURLPtr(lingerExampleFile),
}, },
Mode: IntToPtr(0744), Mode: IntToPtr(0744),
}, },
@ -731,3 +741,14 @@ func (i *IgnitionBuilder) BuildWithIgnitionFile(ignPath string) error {
func (i *IgnitionBuilder) Build() error { func (i *IgnitionBuilder) Build() error {
return i.dynamicIgnition.Write() return i.dynamicIgnition.Write()
} }
func DefaultReadyUnitFile() parser.UnitFile {
u := parser.NewUnitFile()
u.Add("Unit", "After", "remove-moby.service sshd.socket sshd.service")
u.Add("Unit", "OnFailure", "emergency.target")
u.Add("Unit", "OnFailureJobMode", "isolate")
u.Add("Service", "Type", "oneshot")
u.Add("Service", "RemainAfterExit", "yes")
u.Add("Install", "RequiredBy", "default.target")
return *u
}

View File

@ -47,23 +47,6 @@ const (
dockerConnectTimeout = 5 * time.Second dockerConnectTimeout = 5 * time.Second
) )
// qemuReadyUnit is a unit file that sets up the virtual serial device
// where when the VM is done configuring, it will send an ack
// so a listening host tknows it can begin interacting with it
const qemuReadyUnit = `[Unit]
Requires=dev-virtio\\x2dports-%s.device
After=remove-moby.service sshd.socket sshd.service
After=systemd-user-sessions.service
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c '/usr/bin/echo Ready >/dev/%s'
[Install]
RequiredBy=default.target
`
type MachineVM struct { type MachineVM struct {
// ConfigPath is the path to the configuration file // ConfigPath is the path to the configuration file
ConfigPath define.VMFile ConfigPath define.VMFile
@ -230,10 +213,14 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
return false, err return false, err
} }
readyUnitFile, err := createReadyUnitFile()
if err != nil {
return false, err
}
readyUnit := ignition.Unit{ readyUnit := ignition.Unit{
Enabled: ignition.BoolToPtr(true), Enabled: ignition.BoolToPtr(true),
Name: "ready.service", Name: "ready.service",
Contents: ignition.StrToPtr(fmt.Sprintf(qemuReadyUnit, "vport1p1", "vport1p1")), Contents: ignition.StrToPtr(readyUnitFile),
} }
builder.WithUnit(readyUnit) builder.WithUnit(readyUnit)
@ -243,6 +230,14 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) {
return err == nil, err return err == nil, err
} }
func createReadyUnitFile() (string, error) {
readyUnit := ignition.DefaultReadyUnitFile()
readyUnit.Add("Unit", "Requires", "dev-virtio\\x2dports-vport1p1.device")
readyUnit.Add("Unit", "After", "systemd-user-sessions.service")
readyUnit.Add("Service", "ExecStart", "/bin/sh -c '/usr/bin/echo Ready >/dev/vport1p1'")
return readyUnit.ToString()
}
func (v *MachineVM) removeSSHKeys() error { func (v *MachineVM) removeSSHKeys() error {
if err := os.Remove(fmt.Sprintf("%s.pub", v.IdentityPath)); err != nil { if err := os.Remove(fmt.Sprintf("%s.pub", v.IdentityPath)); err != nil {
logrus.Error(err) logrus.Error(err)