From 965dd1eff9e425b8648fb284c6794165ab708fa9 Mon Sep 17 00:00:00 2001 From: Sohan Kunkerkar Date: Wed, 11 Mar 2020 09:30:51 -0400 Subject: [PATCH] Code to fix the systemd instatiated services when enabled/disabled via ignition --- internal/exec/stages/files/units.go | 132 +++++++++++++++++++++++++--- internal/exec/util/unit.go | 8 +- 2 files changed, 125 insertions(+), 15 deletions(-) diff --git a/internal/exec/stages/files/units.go b/internal/exec/stages/files/units.go index d984c1c3f4..7a4ecb2e94 100644 --- a/internal/exec/stages/files/units.go +++ b/internal/exec/stages/files/units.go @@ -17,34 +17,89 @@ package files import ( "fmt" "path/filepath" + "strconv" "strings" + "github.com/coreos/go-systemd/dbus" "github.com/coreos/ignition/v2/config/v3_1_experimental/types" "github.com/coreos/ignition/v2/internal/distro" "github.com/coreos/ignition/v2/internal/exec/util" ) +type Preset struct { + unit string + enabled bool + instantiateable bool + instances []string +} + +// warnOnOldSystemdVersion checks the version of Systemd +// in a given system. +func (s *stage) warnOnOldSystemdVersion() error { + var systemdVersion string + var begin, end int + conn, err := dbus.New() + if err != nil { + return err + } + version, err := conn.GetManagerProperty("Version") + if err != nil { + return err + } + // Handle different systemd versioning schemes that are being returned. + // for e.g: + // - Fedora 31: `v243.5-1.fc31` + // - RHEL 8: `239` + if strings.HasPrefix(version, "v") { + begin = 1 + + } else { + begin = 0 + } + end = strings.Index(version, ".") + if end == -1 { + end = len(version) + } + systemdVersion = version[begin:end] + if value, err := strconv.Atoi(systemdVersion); err == nil { + if value < 240 { + if err := s.Logger.Warning("The version of systemd (%q) is less than 240. Enabling/disabling instantiated units may not work. See https://github.com/coreos/ignition/issues/586 for more information.", systemdVersion); err != nil { + return err + } + } + } else { + return err + } + return nil +} + // createUnits creates the units listed under systemd.units. func (s *stage) createUnits(config types.Config) error { enabledOneUnit := false + presets := make(map[string]*Preset) for _, unit := range config.Systemd.Units { if err := s.writeSystemdUnit(unit, false); err != nil { return err } if unit.Enabled != nil { if *unit.Enabled { - if err := s.Logger.LogOp( - func() error { return s.EnableUnit(unit) }, - "enabling unit %q", unit.Name, - ); err != nil { - return err + unitName, instanceUnit := parseInstanceUnit(unit) + if len(instanceUnit) > 0 { + if _, ok := presets[instanceUnit[0]]; ok { + presets[instanceUnit[0]].instances = append(presets[instanceUnit[0]].instances, instanceUnit[1]) + } else { + presets[instanceUnit[0]] = &Preset{instanceUnit[0], true, true, []string{instanceUnit[1]}} + } + } else { + presets[unitName] = &Preset{unitName, true, false, []string{}} } + } else { - if err := s.Logger.LogOp( - func() error { return s.DisableUnit(unit) }, - "disabling unit %q", unit.Name, - ); err != nil { - return err + unitName, instanceUnit := parseInstanceUnit(unit) + if len(instanceUnit) > 0 { + presets[instanceUnit[0]] = &Preset{instanceUnit[0], false, true, []string{instanceUnit[1]}} + } else { + presets[unitName] = &Preset{unitName, false, false, []string{}} } } enabledOneUnit = true @@ -66,8 +121,63 @@ func (s *stage) createUnits(config types.Config) error { } // and relabel the preset file itself if we enabled/disabled something if enabledOneUnit { - s.relabel(util.PresetPath) + if err := s.createSystemdPresetFile(presets); err != nil { + return err + } + } + + return nil +} + +func parseInstanceUnit(unit types.Unit) (string, []string) { + var instanceUnitArr []string + if strings.Contains(unit.Name, "@") { + at := strings.Index(unit.Name, "@") + dot := strings.Index(unit.Name, ".") + instance := unit.Name[at+1 : dot] + serviceInstance := unit.Name[0:at+1] + unit.Name[dot:len(unit.Name)] + instanceUnitArr = append(instanceUnitArr, serviceInstance, instance) + } + return unit.Name, instanceUnitArr +} + +// createSystemdPresetFile creates the presetfile for enabled/disabled +// instantiated/systemd units. +func (s *stage) createSystemdPresetFile(presets map[string]*Preset) error { + var enableUnitString, disableUnitString string + flag := false + for _, value := range presets { + if value.instantiateable && flag == false { + s.warnOnOldSystemdVersion() + flag = true + } + if value.enabled { + if value.instantiateable { + enableUnitString = value.unit + " " + strings.Join(value.instances, " ") + } else { + enableUnitString = value.unit + } + if err := s.Logger.LogOp( + func() error { return s.EnableUnit(enableUnitString) }, + "enabling unit %q", enableUnitString, + ); err != nil { + return err + } + } else { + if value.instantiateable { + disableUnitString = value.unit + " " + strings.Join(value.instances, " ") + } else { + disableUnitString = value.unit + } + if err := s.Logger.LogOp( + func() error { return s.DisableUnit(disableUnitString) }, + "disabling unit %q", disableUnitString, + ); err != nil { + return err + } + } } + s.relabel(util.PresetPath) return nil } diff --git a/internal/exec/util/unit.go b/internal/exec/util/unit.go index e9c7bc73dc..b45a3038e1 100644 --- a/internal/exec/util/unit.go +++ b/internal/exec/util/unit.go @@ -110,8 +110,8 @@ func (ut Util) MaskUnit(unit types.Unit) (string, error) { return filepath.Join("/", SystemdUnitsPath(), unit.Name), nil } -func (ut Util) EnableUnit(unit types.Unit) error { - return ut.appendLineToPreset(fmt.Sprintf("enable %s", unit.Name)) +func (ut Util) EnableUnit(enabledUnit string) error { + return ut.appendLineToPreset(fmt.Sprintf("enable %s", enabledUnit)) } // presets link in /etc, which doesn't make sense for runtime units @@ -145,8 +145,8 @@ func (ut Util) EnableRuntimeUnit(unit types.Unit, target string) error { return ut.WriteLink(link) } -func (ut Util) DisableUnit(unit types.Unit) error { - return ut.appendLineToPreset(fmt.Sprintf("disable %s", unit.Name)) +func (ut Util) DisableUnit(disabledUnit string) error { + return ut.appendLineToPreset(fmt.Sprintf("disable %s", disabledUnit)) } func (ut Util) appendLineToPreset(data string) error {