From af98f37ffdebff367094d3fdf3fe0543cb6b6165 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Wed, 11 Jul 2018 17:18:56 -0400 Subject: [PATCH] stages/files: add support for runtime systemd units Teach `writeSystemdUnit()` how to create runtime units in `/run`. This only adds *internal* support for our own purposes. It does not extend the Ignition spec to allow users to specify it. Though we could do this too later on. --- internal/exec/stages/files/units.go | 19 +++++++----- internal/exec/util/path.go | 12 ++++++++ internal/exec/util/unit.go | 45 ++++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/internal/exec/stages/files/units.go b/internal/exec/stages/files/units.go index 6aba6fd62..15c2c31bf 100644 --- a/internal/exec/stages/files/units.go +++ b/internal/exec/stages/files/units.go @@ -22,7 +22,7 @@ import ( // createUnits creates the units listed under systemd.units and networkd.units. func (s stage) createUnits(config types.Config) error { for _, unit := range config.Systemd.Units { - if err := s.writeSystemdUnit(unit); err != nil { + if err := s.writeSystemdUnit(unit, false); err != nil { return err } if unit.Enable { @@ -71,20 +71,25 @@ func (s stage) createUnits(config types.Config) error { // writeSystemdUnit creates the specified unit and any dropins for that unit. // If the contents of the unit or are empty, the unit is not created. The same // applies to the unit's dropins. -func (s stage) writeSystemdUnit(unit types.Unit) error { +func (s stage) writeSystemdUnit(unit types.Unit, runtime bool) error { + // use a different DestDir if it's runtime so it affects our /run + u := s.Util + if runtime { + u.DestDir = "/" + } + return s.Logger.LogOp(func() error { for _, dropin := range unit.Dropins { if dropin.Contents == "" { continue } - - f, err := util.FileFromSystemdUnitDropin(unit, dropin) + f, err := util.FileFromSystemdUnitDropin(unit, dropin, runtime) if err != nil { s.Logger.Crit("error converting systemd dropin: %v", err) return err } if err := s.Logger.LogOp( - func() error { return s.PerformFetch(f) }, + func() error { return u.PerformFetch(f) }, "writing systemd drop-in %q at %q", dropin.Name, f.Path, ); err != nil { return err @@ -95,13 +100,13 @@ func (s stage) writeSystemdUnit(unit types.Unit) error { return nil } - f, err := util.FileFromSystemdUnit(unit) + f, err := util.FileFromSystemdUnit(unit, runtime) if err != nil { s.Logger.Crit("error converting unit: %v", err) return err } if err := s.Logger.LogOp( - func() error { return s.PerformFetch(f) }, + func() error { return u.PerformFetch(f) }, "writing unit %q at %q", unit.Name, f.Path, ); err != nil { return err diff --git a/internal/exec/util/path.go b/internal/exec/util/path.go index 5cd0b8d30..ed78e6d79 100644 --- a/internal/exec/util/path.go +++ b/internal/exec/util/path.go @@ -22,6 +22,14 @@ func SystemdUnitsPath() string { return filepath.Join("etc", "systemd", "system") } +func SystemdRuntimeUnitsPath() string { + return filepath.Join("run", "systemd", "system") +} + +func SystemdRuntimeUnitWantsPath(unitName string) string { + return filepath.Join("run", "systemd", "system", unitName+".wants") +} + func NetworkdUnitsPath() string { return filepath.Join("etc", "systemd", "network") } @@ -30,6 +38,10 @@ func SystemdDropinsPath(unitName string) string { return filepath.Join("etc", "systemd", "system", unitName+".d") } +func SystemdRuntimeDropinsPath(unitName string) string { + return filepath.Join("run", "systemd", "system", unitName+".d") +} + func NetworkdDropinsPath(unitName string) string { return filepath.Join("etc", "systemd", "network", unitName+".d") } diff --git a/internal/exec/util/unit.go b/internal/exec/util/unit.go index a3e05af12..1a89327c8 100644 --- a/internal/exec/util/unit.go +++ b/internal/exec/util/unit.go @@ -31,13 +31,21 @@ const ( DefaultPresetPermissions os.FileMode = 0644 ) -func FileFromSystemdUnit(unit types.Unit) (*FetchOp, error) { +func FileFromSystemdUnit(unit types.Unit, runtime bool) (*FetchOp, error) { u, err := url.Parse(dataurl.EncodeBytes([]byte(unit.Contents))) if err != nil { return nil, err } + + var path string + if runtime { + path = SystemdRuntimeUnitsPath() + } else { + path = SystemdUnitsPath() + } + return &FetchOp{ - Path: filepath.Join(SystemdUnitsPath(), string(unit.Name)), + Path: filepath.Join(path, string(unit.Name)), Url: *u, Mode: configUtil.IntToPtr(int(DefaultFilePermissions)), }, nil @@ -55,13 +63,21 @@ func FileFromNetworkdUnit(unit types.Networkdunit) (*FetchOp, error) { }, nil } -func FileFromSystemdUnitDropin(unit types.Unit, dropin types.SystemdDropin) (*FetchOp, error) { +func FileFromSystemdUnitDropin(unit types.Unit, dropin types.SystemdDropin, runtime bool) (*FetchOp, error) { u, err := url.Parse(dataurl.EncodeBytes([]byte(dropin.Contents))) if err != nil { return nil, err } + + var path string + if runtime { + path = SystemdRuntimeDropinsPath(string(unit.Name)) + } else { + path = SystemdDropinsPath(string(unit.Name)) + } + return &FetchOp{ - Path: filepath.Join(SystemdDropinsPath(string(unit.Name)), string(dropin.Name)), + Path: filepath.Join(path, string(dropin.Name)), Url: *u, Mode: configUtil.IntToPtr(int(DefaultFilePermissions)), }, nil @@ -94,6 +110,27 @@ func (u Util) EnableUnit(unit types.Unit) error { return u.appendLineToPreset(fmt.Sprintf("enable %s", unit.Name)) } +// presets link in /etc, which doesn't make sense for runtime units +// Related: https://github.com/coreos/ignition/issues/588 +func (u Util) EnableRuntimeUnit(unit types.Unit, target string) error { + // we want to affect /run, which will be carried into the pivot, + // not a directory named /$DestDir/run + u.DestDir = "/" + + link := types.Link{ + Node: types.Node{ + Filesystem: "root", + // XXX(jl): make Wants/Required a parameter + Path: filepath.Join(SystemdRuntimeUnitWantsPath(target), string(unit.Name)), + }, + LinkEmbedded1: types.LinkEmbedded1{ + Target: filepath.Join("/", SystemdRuntimeUnitsPath(), string(unit.Name)), + }, + } + + return u.WriteLink(link) +} + func (u Util) DisableUnit(unit types.Unit) error { return u.appendLineToPreset(fmt.Sprintf("disable %s", unit.Name)) }