From 253ea2e82b16f38ede7c7f4be51c801df6a01943 Mon Sep 17 00:00:00 2001 From: Nikolay Sivko Date: Mon, 9 Feb 2026 10:55:33 -0300 Subject: [PATCH] refactor systemd D-Bus client: add caching, reconnection, and proper error propagation --- containers/registry.go | 5 +-- containers/systemd.go | 72 +++++++++++++++++++++++++++++++----------- go.mod | 6 ++-- go.sum | 13 ++++---- 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/containers/registry.go b/containers/registry.go index 3181b63..b5f6a00 100644 --- a/containers/registry.go +++ b/containers/registry.go @@ -548,9 +548,10 @@ func calcId(cg *cgroup.Cgroup, md *ContainerMetadata) ContainerID { func getContainerMetadata(cg *cgroup.Cgroup) (*ContainerMetadata, error) { switch cg.ContainerType { case cgroup.ContainerTypeSystemdService: + var err error md := &ContainerMetadata{} - md.systemd = getSystemdProperties(cg.Id) - return md, nil + md.systemd, err = getSystemdProperties(cg.Id) + return md, err case cgroup.ContainerTypeDocker, cgroup.ContainerTypeContainerd, cgroup.ContainerTypeSandbox, cgroup.ContainerTypeCrio: default: return &ContainerMetadata{}, nil diff --git a/containers/systemd.go b/containers/systemd.go index ea9367c..7e865d4 100644 --- a/containers/systemd.go +++ b/containers/systemd.go @@ -2,6 +2,7 @@ package containers import ( "context" + "fmt" "os" "strconv" "strings" @@ -11,13 +12,11 @@ import ( "github.com/coreos/go-systemd/v22/dbus" gdbus "github.com/godbus/dbus/v5" - - "k8s.io/klog/v2" ) var ( - dbusConn *dbus.Conn dbusTimeout = time.Second + dbusClient = NewDbusClient() systemServicePrefixes = []string{ "systemd-", @@ -37,22 +36,63 @@ var ( } ) -func init() { +type DbusClient struct { + conn *dbus.Conn + cache map[string]map[string]any +} + +func NewDbusClient() *DbusClient { + return &DbusClient{ + cache: map[string]map[string]any{}, + } +} + +func (c *DbusClient) close() { + if c.conn != nil { + c.conn.Close() + c.conn = nil + } +} + +func (c *DbusClient) connect() error { var err error - dbusConn, err = dbus.NewConnection(func() (*gdbus.Conn, error) { - c, err := gdbus.Dial("unix:path=" + proc.HostPath("/run/systemd/private")) + c.conn, err = dbus.NewConnection(func() (*gdbus.Conn, error) { + conn, err := gdbus.Dial("unix:path=" + proc.HostPath("/run/systemd/private")) if err != nil { return nil, err } methods := []gdbus.Auth{gdbus.AuthExternal(strconv.Itoa(os.Getuid()))} - if err = c.Auth(methods); err != nil { - dbusConn.Close() + if err = conn.Auth(methods); err != nil { + conn.Close() return nil, err } - return c, nil + return conn, nil }) if err != nil { - klog.Warningln("failed to connect to systemd bus:", err) + return fmt.Errorf("failed to connect to systemd bus: %w", err) + } + return nil +} + +func (c *DbusClient) GetAllPropertiesContext(ctx context.Context, unit string, retry bool) (map[string]any, error) { + if res, ok := c.cache[unit]; ok { + return res, nil + } + if c.conn == nil { + if err := c.connect(); err != nil { + return nil, err + } + } + res, err := c.conn.GetAllPropertiesContext(ctx, unit) + switch { + case err == nil: + c.cache[unit] = res + return res, nil + case retry: + c.close() + return c.GetAllPropertiesContext(ctx, unit, false) + default: + return nil, err } } @@ -82,11 +122,8 @@ func (sp SystemdProperties) IsSystemService() bool { return false } -func getSystemdProperties(id string) SystemdProperties { +func getSystemdProperties(id string) (SystemdProperties, error) { props := SystemdProperties{} - if dbusConn == nil { - return props - } ctx, cancel := context.WithTimeout(context.Background(), dbusTimeout) defer cancel() parts := strings.Split(id, "/") @@ -99,10 +136,9 @@ func getSystemdProperties(id string) SystemdProperties { if props.Unit == "" { props.Unit = parts[len(parts)-1] } - properties, err := dbusConn.GetAllPropertiesContext(ctx, props.Unit) + properties, err := dbusClient.GetAllPropertiesContext(ctx, props.Unit, true) if err != nil { - klog.Warningln("failed to get systemd properties:", err) - return props + return props, fmt.Errorf("failed to get systemd properties: %w", err) } if v, ok := properties["TriggeredBy"]; ok { if values, _ := v.([]string); len(values) > 0 { @@ -112,5 +148,5 @@ func getSystemdProperties(id string) SystemdProperties { if v, ok := properties["Type"]; ok { props.Type, _ = v.(string) } - return props + return props, nil } diff --git a/go.mod b/go.mod index d4f2b86..4a4e779 100644 --- a/go.mod +++ b/go.mod @@ -10,13 +10,13 @@ require ( github.com/cilium/ebpf v0.20.0 github.com/containerd/cgroups v1.1.0 github.com/containerd/containerd v1.7.29 - github.com/coreos/go-systemd/v22 v22.5.0 + github.com/coreos/go-systemd/v22 v22.7.0 github.com/coroot/logparser v1.2.1 github.com/docker/docker v27.4.0+incompatible github.com/florianl/go-conntrack v0.3.0 github.com/go-kit/log v0.2.1 github.com/gobwas/glob v0.2.3 - github.com/godbus/dbus/v5 v5.1.0 + github.com/godbus/dbus/v5 v5.2.2 github.com/golang/snappy v0.0.4 github.com/grafana/pyroscope/ebpf v0.4.9 github.com/jpillora/backoff v1.0.0 @@ -40,7 +40,7 @@ require ( golang.org/x/arch v0.4.0 golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa golang.org/x/net v0.46.0 - golang.org/x/sys v0.37.0 + golang.org/x/sys v0.40.0 golang.org/x/time v0.12.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index 567a053..fc5ee2f 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,8 @@ github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9Fqctt github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= +github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= github.com/coroot/dotnetdiag v1.2.2 h1:PVP/By8o+xhPjfVolJYcjHLbFQInM7pkaD6/otPLc8Q= github.com/coroot/dotnetdiag v1.2.2/go.mod h1:veXCMlFzm1yNl7wwJb/ZLxO4WbzhDBoy1VG1XtkH2ls= github.com/coroot/logparser v1.2.1 h1:NLU4VAgGwqMTtKyRHDpTtE9BtPQJLOhDIuB5yiQdelQ= @@ -172,9 +172,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -536,8 +535,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=