Skip to content

Commit

Permalink
Use parser.UnitFile
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jakecorrenti committed Jan 4, 2024
1 parent c728eeb commit 98f332d
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 159 deletions.
109 changes: 59 additions & 50 deletions pkg/machine/applehv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
"github.com/containers/podman/v4/pkg/machine/ignition"
"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/utils"
"github.com/containers/storage/pkg/lockfile"
Expand All @@ -46,21 +47,13 @@ const (
apiUpTimeout = 20 * time.Second
)

// appleHVReadyUnit 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
const appleHVReadyUnit = `[Unit]
Requires=dev-virtio\\x2dports-%s.device
After=remove-moby.service sshd.socket sshd.service
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
`
// VfkitHelper describes the use of vfkit: cmdline and endpoint
type VfkitHelper struct {
LogLevel logrus.Level
Endpoint string
VfkitBinaryPath *define.VMFile
VirtualMachine *vfConfig.VirtualMachine
}

type MacMachine struct {
// ConfigPath is the fully qualified path to the configuration file
Expand Down Expand Up @@ -274,10 +267,15 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
return false, err
}

readyUnitFile, err := createReadyUnitFile()
if err != nil {
return false, err
}

builder.WithUnit(ignition.Unit{
Enabled: ignition.BoolToPtr(true),
Name: "ready.service",
Contents: ignition.StrToPtr(fmt.Sprintf(appleHVReadyUnit, "vsock")),
Contents: ignition.StrToPtr(readyUnitFile),
})
builder.WithUnit(generateSystemDFilesForVirtiofsMounts(virtiofsMnts)...)

Expand All @@ -288,6 +286,13 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
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 {
if err := os.Remove(fmt.Sprintf("%s.pub", m.IdentityPath)); err != nil {
logrus.Error(err)
Expand Down Expand Up @@ -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
// for virtiofs. One unit file is the mount itself and the second is to automount it
// on boot.
autoMountUnit := `[Automount]
Where=%s
[Install]
WantedBy=multi-user.target
[Unit]
Description=Mount virtiofs volume %s
`
mountUnit := `[Mount]
What=%s
Where=%s
Type=virtiofs
[Install]
WantedBy=multi-user.target
`
autoMountUnit := parser.NewUnitFile()
autoMountUnit.Add("Automount", "Where", "%s")
autoMountUnit.Add("Install", "WantedBy", "multi-user.target")
autoMountUnit.Add("Unit", "Description", "Mount virtiofs volume %s")
autoMountUnitFile, err := autoMountUnit.ToString()
if err != nil {
logrus.Warnf(err.Error())
}

mountUnit := parser.NewUnitFile()
mountUnit.Add("Mount", "What", "%s")
mountUnit.Add("Mount", "Where", "%s")
mountUnit.Add("Mount", "Type", "virtiofs")
mountUnit.Add("Install", "WantedBy", "multi-user.target")
mountUnitFile, err := mountUnit.ToString()
if err != nil {
logrus.Warnf(err.Error())
}

virtiofsAutomount := ignition.Unit{
Enabled: ignition.BoolToPtr(true),
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{
Enabled: ignition.BoolToPtr(true),
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@
Expand All @@ -1149,23 +1157,24 @@ WantedBy=multi-user.target

// mount prep is a way to workaround the FCOS limitation of creating directories
// at the rootfs / and then mounting to them.
mountPrep := `
[Unit]
Description=Allow virtios to mount to /
DefaultDependencies=no
ConditionPathExists=!%f
[Service]
Type=oneshot
ExecStartPre=chattr -i /
ExecStart=mkdir -p '%f'
ExecStopPost=chattr +i /
[Install]
WantedBy=remote-fs.target
`
mountPrep := parser.NewUnitFile()
mountPrep.Add("Unit", "Description", "Allow virtios to mount to /")
mountPrep.Add("Unit", "DefaultDependencies", "no")
mountPrep.Add("Unit", "ConditionPathExists", "!%f")

mountPrep.Add("Service", "Type", "oneshot")
mountPrep.Add("Service", "ExecStartPre", "chattr -i /")
mountPrep.Add("Service", "ExecStart", "mkdir -p '%f'")
mountPrep.Add("Service", "ExecStopPost", "chattr +i /")

mountPrep.Add("Install", "WantedBy", "remote-fs.target")
mountPrepFile, err := mountPrep.ToString()
if err != nil {
logrus.Warnf(err.Error())
}

virtioFSChattr := ignition.Unit{
Contents: ignition.StrToPtr(mountPrep),
Contents: ignition.StrToPtr(mountPrepFile),
Name: "[email protected]",
}
unitFiles = append(unitFiles, virtioFSChattr)
Expand Down
66 changes: 30 additions & 36 deletions pkg/machine/hyperv/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/containers/podman/v4/pkg/machine/vmconfigs"
"github.com/containers/podman/v4/pkg/machine/ignition"
"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/utils"
"github.com/containers/storage/pkg/lockfile"
Expand All @@ -46,40 +47,6 @@ const (
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 = `
[connection]
id=vsock0
Expand Down Expand Up @@ -278,14 +245,24 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
return false, err
}

readyUnitFile, err := createReadyUnit(m.ReadyHVSock.Port)
if err != nil {
return false, err
}

builder.WithUnit(ignition.Unit{
Enabled: ignition.BoolToPtr(true),
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{
Contents: ignition.StrToPtr(fmt.Sprintf(hyperVVsockNetUnit, m.NetworkHVSock.Port)),
Contents: ignition.StrToPtr(netUnitFile),
Enabled: ignition.BoolToPtr(true),
Name: "vsock-network.service",
})
Expand Down Expand Up @@ -316,6 +293,23 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) {
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 {
vmm := hypervctl.NewVirtualMachineManager()
vm, err := vmm.GetMachine(m.Name)
Expand Down
Loading

0 comments on commit 98f332d

Please sign in to comment.