Change the commandline used for systemd-run depeding on the installed version

We found when testing on some ditros that they had older versions of systemd installed.

Versions before 246 use `MemoryLimit` and after that use `MemoryMax` so we need to know which version we have when constructing the commandline.

Also older versions didn't support the `-E` flag for environment variables and instead use the longer form `--setenv`.  This same flag is supported in both old and new versions
This commit is contained in:
Dave Poole 2024-05-06 09:51:49 -07:00
Родитель 62799315b6
Коммит f9ff9c5cea
2 изменённых файлов: 67 добавлений и 3 удалений

Просмотреть файл

@ -329,16 +329,28 @@ func setupVMWatchCommand(s *vmWatchSettings, hEnv *handlerenv.HandlerEnvironment
var cmd *exec.Cmd
// if we have systemd available, we will use that to launch the process, otherwise we will launch directly and manipulate our own cgroups
if isSystemdAvailable() {
systemdVersion := getSystemdVersion()
// since systemd-run is in different paths on different distros, we will check for systemd but not use the full path
// to systemd-run. This is how guest agent handles it also so seems appropriate.
systemdArgs := []string{"--scope", "-p", fmt.Sprintf("CPUQuota=%v%%", s.MaxCpuPercentage), "-p", fmt.Sprintf("MemoryMax=%v", s.MemoryLimitInBytes)}
// now append the env variables
systemdArgs := []string{"--scope", "-p", fmt.Sprintf("CPUQuota=%v%%", s.MaxCpuPercentage)}
// systemd versions prior to 246 do not support MemoryMax, instead MemoryLimit should be used
if (systemdVersion < 246) {
systemdArgs = append(systemdArgs, "-p", fmt.Sprintf("MemoryLimit=%v", s.MemoryLimitInBytes))
} else {
systemdArgs = append(systemdArgs, "-p", fmt.Sprintf("MemoryMax=%v", s.MemoryLimitInBytes))
}
// now append the env variables (--setenv is supported in all versions, -E only in newer versions)
for _, v := range GetVMWatchEnvironmentVariables(s.ParameterOverrides, hEnv) {
systemdArgs = append(systemdArgs, "-E", v)
systemdArgs = append(systemdArgs, "--setenv", v)
}
systemdArgs = append(systemdArgs, GetVMWatchBinaryFullPath(processDirectory))
systemdArgs = append(systemdArgs, args...)
// since systemd-run is in different paths on different distros, we will check for systemd but not use the full path
// to systemd-run. This is how guest agent handles it also so seems appropriate.
cmd = exec.Command("systemd-run", systemdArgs...)
} else {
cmd = exec.Command(GetVMWatchBinaryFullPath(processDirectory), args...)
@ -354,6 +366,42 @@ func isSystemdAvailable() bool {
return err == nil && info.IsDir()
}
func getSystemdVersion() (int) {
cmd := exec.Command("systemd-run", "--version")
// Execute the command and capture the output
output, err := cmd.CombinedOutput()
if err != nil {
return 0
}
// Convert output bytes to string
outputStr := string(output)
// Find the version information in the output
return extractVersion(outputStr)
}
// Function to extract the version information from the output
// returns the version or 0 if not found
func extractVersion(output string) int {
lines := strings.Split(output, "\n")
for _, line := range lines {
if strings.HasPrefix(line, "systemd") {
parts := strings.Fields(line)
if len(parts) >= 2 {
ret, err := strconv.Atoi(parts[1])
if err == nil {
return ret
}
return 0
}
}
}
return 0
}
func createAndAssignCgroups(lg log.Logger, vmwatchSettings *vmWatchSettings, vmWatchPid int) error {
// get our process and use this to determine the appropriate mount points for the cgroups
myPid := os.Getpid()

Просмотреть файл

@ -30,3 +30,19 @@ func TestGetMessageCorrectValue(t *testing.T) {
res = VMWatchResult{Status: Running}
require.Equal(t, "VMWatch is running", res.GetMessage())
}
func TestExtractVersion(t *testing.T) {
v := extractVersion("systemd 123")
require.Equal(t, 123, v)
v = extractVersion(`someline
systemd 123
some other line`)
require.Equal(t, 123, v)
v = extractVersion(`someline
systemd abc
some other line`)
require.Equal(t, 0, v)
v = extractVersion("junk")
require.Equal(t, 0, v)
}