mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Support for setting systemd properties via annotations
In case systemd is used to set cgroups for the container,
it creates a scope unit dedicated to it (usually named
`runc-$ID.scope`).
This patch adds an ability to set arbitrary systemd properties
for the systemd unit via runtime spec annotations.
Initially this was developed as an ability to specify the
`TimeoutStopUSec` property, but later generalized to work with
arbitrary ones.
Example usage: add the following to runtime spec (config.json):
```
"annotations": {
"org.systemd.property.TimeoutStopUSec": "uint64 123456789",
"org.systemd.property.CollectMode":"'inactive-or-failed'"
},
```
and start the container (e.g. `runc --systemd-cgroup run $ID`).
The above will set the following systemd parameters:
* `TimeoutStopSec` to 2 minutes and 3 seconds,
* `CollectMode` to "inactive-or-failed".
The values are in the gvariant format (see [1]). To figure out
which type systemd expects for a particular parameter, see
systemd sources.
In particular, parameters with `USec` suffix require an `uint64`
typed argument, while gvariant assumes int32 for a numeric values,
therefore the explicit type is required.
NOTE that systemd receives the time-typed parameters as *USec
but shows them (in `systemctl show`) as *Sec. For example,
the stop timeout should be set as `TimeoutStopUSec` but
is shown as `TimeoutStopSec`.
[1] https://developer.gnome.org/glib/stable/gvariant-text.html
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/godbus/dbus"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs/validate"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
@@ -450,3 +451,82 @@ func TestNonZeroEUIDCompatibleSpecconvValidate(t *testing.T) {
|
||||
t.Errorf("Expected specconv to produce valid rootless container config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitSystemdProps(t *testing.T) {
|
||||
type inT struct {
|
||||
name, value string
|
||||
}
|
||||
type expT struct {
|
||||
isErr bool
|
||||
name string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
in inT
|
||||
exp expT
|
||||
}{
|
||||
{
|
||||
in: inT{"org.systemd.property.TimeoutStopUSec", "uint64 123456789"},
|
||||
exp: expT{false, "TimeoutStopUSec", uint64(123456789)},
|
||||
},
|
||||
{
|
||||
in: inT{"org.systemd.property.CollectMode", "'inactive-or-failed'"},
|
||||
exp: expT{false, "CollectMode", "inactive-or-failed"},
|
||||
},
|
||||
{
|
||||
desc: "unrelated property",
|
||||
in: inT{"some.other.annotation", "0"},
|
||||
exp: expT{false, "", ""},
|
||||
},
|
||||
{
|
||||
desc: "too short property name",
|
||||
in: inT{"org.systemd.property.Xo", "1"},
|
||||
exp: expT{true, "", ""},
|
||||
},
|
||||
{
|
||||
desc: "invalid character in property name",
|
||||
in: inT{"org.systemd.property.Number1", "1"},
|
||||
exp: expT{true, "", ""},
|
||||
},
|
||||
{
|
||||
desc: "invalid property value",
|
||||
in: inT{"org.systemd.property.ValidName", "invalid-value"},
|
||||
exp: expT{true, "", ""},
|
||||
},
|
||||
}
|
||||
|
||||
spec := &specs.Spec{}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
spec.Annotations = map[string]string{tc.in.name: tc.in.value}
|
||||
|
||||
outMap, err := initSystemdProps(spec)
|
||||
//t.Logf("input %+v, expected %+v, got err:%v out:%+v", tc.in, tc.exp, err, outMap)
|
||||
|
||||
if tc.exp.isErr != (err != nil) {
|
||||
t.Errorf("input %+v, expecting error: %v, got %v", tc.in, tc.exp.isErr, err)
|
||||
}
|
||||
expLen := 1 // expect a single item
|
||||
if tc.exp.name == "" {
|
||||
expLen = 0 // expect nothing
|
||||
}
|
||||
if len(outMap) != expLen {
|
||||
t.Fatalf("input %+v, expected %d, got %d entries: %v", tc.in, expLen, len(outMap), outMap)
|
||||
}
|
||||
if expLen == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
out := outMap[0]
|
||||
if tc.exp.name != out.Name {
|
||||
t.Errorf("input %+v, expecting name: %q, got %q", tc.in, tc.exp.name, out.Name)
|
||||
}
|
||||
expValue := dbus.MakeVariant(tc.exp.value).String()
|
||||
if expValue != out.Value.String() {
|
||||
t.Errorf("input %+v, expecting value: %s, got %s", tc.in, expValue, out.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user