diff --git a/libcontainer/cgroups/systemd/common.go b/libcontainer/cgroups/systemd/common.go index cdf656b8..53fa3f2c 100644 --- a/libcontainer/cgroups/systemd/common.go +++ b/libcontainer/cgroups/systemd/common.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "os" + "regexp" "strconv" "strings" "sync" @@ -365,22 +366,28 @@ func systemdVersion(conn *systemdDbus.Conn) (int, error) { return } - // verStr is like "v245.4-1.fc32" (including quotes) - if !strings.HasPrefix(verStr, `"v`) { - versionErr = fmt.Errorf("can't parse version %s", verStr) - return - } - // remove `"v` prefix and everything after the first dot - ver, err := strconv.Atoi(strings.SplitN(verStr[2:], ".", 2)[0]) - if err != nil { - versionErr = err - } - version = ver + version, versionErr = systemdVersionAtoi(verStr) + return }) return version, versionErr } +func systemdVersionAtoi(verStr string) (int, error) { + // verStr should be of the form: + // "v245.4-1.fc32", "245", "v245-1.fc32", "245-1.fc32" + // all the input strings include quotes, and the output int should be 245 + // thus, we unconditionally remove the `"v` + // and then match on the first integer we can grab + re := regexp.MustCompile(`"?v?([0-9]+)`) + matches := re.FindStringSubmatch(verStr) + if len(matches) < 2 { + return 0, errors.Errorf("can't parse version %s: incorrect number of matches %v", verStr, matches) + } + ver, err := strconv.Atoi(matches[1]) + return ver, errors.Wrapf(err, "can't parse version %s", verStr) +} + func addCpuQuota(conn *systemdDbus.Conn, properties *[]systemdDbus.Property, quota int64, period uint64) { if period != 0 { // systemd only supports CPUQuotaPeriodUSec since v242 diff --git a/libcontainer/cgroups/systemd/systemd_test.go b/libcontainer/cgroups/systemd/systemd_test.go new file mode 100644 index 00000000..0c98a117 --- /dev/null +++ b/libcontainer/cgroups/systemd/systemd_test.go @@ -0,0 +1,32 @@ +package systemd + +import ( + "testing" +) + +func TestSystemdVersion(t *testing.T) { + var systemdVersionTests = []struct { + verStr string + expectedVer int + expectErr bool + }{ + {`"219"`, 219, false}, + {`"v245.4-1.fc32"`, 245, false}, + {`"241-1"`, 241, false}, + {`"v241-1"`, 241, false}, + {"NaN", 0, true}, + {"", 0, true}, + } + for _, sdTest := range systemdVersionTests { + ver, err := systemdVersionAtoi(sdTest.verStr) + if !sdTest.expectErr && err != nil { + t.Errorf("systemdVersionAtoi(%s); want nil; got %v", sdTest.verStr, err) + } + if sdTest.expectErr && err == nil { + t.Errorf("systemdVersionAtoi(%s); wanted failure; got nil", sdTest.verStr) + } + if ver != sdTest.expectedVer { + t.Errorf("systemdVersionAtoi(%s); want %d; got %d", sdTest.verStr, sdTest.expectedVer, ver) + } + } +}