Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(inputs.systemd_units): Support user scoped units (#12053) #15458

Merged
merged 8 commits into from
Jun 25, 2024
13 changes: 7 additions & 6 deletions plugins/inputs/systemd_units/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ These metrics are available in both modes:
- load (string, load state)
- active (string, active state)
- sub (string, sub state)
- user (string, username when `scope = "user"`, empty when `scope = "system"`)
- fields:
- load_code (int, see below)
- active_code (int, see below)
Expand Down Expand Up @@ -198,15 +199,15 @@ were removed, tables are hex aligned to keep some space for future values
### Output in non-detailed mode

```text
systemd_units,host=host1.example.com,name=dbus.service,load=loaded,active=active,sub=running load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
systemd_units,host=host1.example.com,name=networking.service,load=loaded,active=failed,sub=failed load_code=0i,active_code=3i,sub_code=12i 1533730725000000000
systemd_units,host=host1.example.com,name=ssh.service,load=loaded,active=active,sub=running load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
systemd_units,host=host1.example.com,name=dbus.service,load=loaded,active=active,sub=running,user=telegraf load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
systemd_units,host=host1.example.com,name=networking.service,load=loaded,active=failed,sub=failed,user=telegraf load_code=0i,active_code=3i,sub_code=12i 1533730725000000000
systemd_units,host=host1.example.com,name=ssh.service,load=loaded,active=active,sub=running,user=telegraf load_code=0i,active_code=0i,sub_code=0i 1533730725000000000
```

### Output in detailed mode

```text
systemd_units,active=active,host=host1.example.com,load=loaded,name=dbus.service,sub=running,preset=disabled,state=static active_code=0i,load_code=0i,mem_avail=6470856704i,mem_current=2691072i,mem_peak=3895296i,pid=481i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=794624i,swap_peak=884736i 1533730725000000000
systemd_units,active=inactive,host=host1.example.com,load=not-found,name=networking.service,sub=dead active_code=2i,load_code=2i,pid=0i,restarts=0i,status_errno=0i,sub_code=1i 1533730725000000000
systemd_units,active=active,host=host1.example.com,load=loaded,name=pcscd.service,sub=running,preset=disabled,state=indirect active_code=0i,load_code=0i,mem_avail=6370541568i,mem_current=512000i,mem_peak=4399104i,pid=1673i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=3149824i,swap_peak=3149824i 1533730725000000000
systemd_units,active=active,host=host1.example.com,load=loaded,name=dbus.service,sub=running,preset=disabled,state=static,user=telegraf active_code=0i,load_code=0i,mem_avail=6470856704i,mem_current=2691072i,mem_peak=3895296i,pid=481i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=794624i,swap_peak=884736i 1533730725000000000
systemd_units,active=inactive,host=host1.example.com,load=not-found,name=networking.service,sub=dead,user=telegraf active_code=2i,load_code=2i,pid=0i,restarts=0i,status_errno=0i,sub_code=1i 1533730725000000000
systemd_units,active=active,host=host1.example.com,load=loaded,name=pcscd.service,sub=running,preset=disabled,state=indirect,user=telegraf active_code=0i,load_code=0i,mem_avail=6370541568i,mem_current=512000i,mem_peak=4399104i,pid=1673i,restarts=0i,status_errno=0i,sub_code=0i,swap_current=3149824i,swap_peak=3149824i 1533730725000000000
```
1 change: 1 addition & 0 deletions plugins/inputs/systemd_units/systemd_units.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var sampleConfig string
type SystemdUnits struct {
Pattern string `toml:"pattern"`
UnitType string `toml:"unittype"`
Scope string `toml:"scope"`
Details bool `toml:"details"`
CollectDisabled bool `toml:"collect_disabled_units"`
Timeout config.Duration `toml:"timeout"`
Expand Down
28 changes: 27 additions & 1 deletion plugins/inputs/systemd_units/systemd_units_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"fmt"
"math"
"os"
"path"
"strings"
"time"
Expand Down Expand Up @@ -131,6 +132,8 @@ type archParams struct {
pattern []string
filter filter.Filter
unitTypeDBus string
scope string
user string
}

func (s *SystemdUnits) Init() error {
Expand Down Expand Up @@ -158,12 +161,34 @@ func (s *SystemdUnits) Init() error {
}
s.filter = f

switch s.Scope {
case "", "system":
s.scope = "system"
s.user = ""
case "user":
s.scope = "user"
s.user = os.Getenv("USER")
default:
return fmt.Errorf("invalid 'scope' %q", s.Scope)
}

return nil
}

func (s *SystemdUnits) Start(telegraf.Accumulator) error {
var (
client *dbus.Conn
err error
)

ctx := context.Background()
client, err := dbus.NewSystemConnectionContext(ctx)

switch s.scope {
case "user":
client, err = dbus.NewUserConnectionContext(ctx)
default:
client, err = dbus.NewSystemConnectionContext(ctx)
}
if err != nil {
return err
}
Expand Down Expand Up @@ -320,6 +345,7 @@ func (s *SystemdUnits) Gather(acc telegraf.Accumulator) error {
"load": state.LoadState,
"active": state.ActiveState,
"sub": state.SubState,
"user": s.user,
}

fields := map[string]interface{}{
Expand Down
65 changes: 65 additions & 0 deletions plugins/inputs/systemd_units/systemd_units_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"math"
"os"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -38,6 +39,52 @@ func TestDefaultPattern(t *testing.T) {
require.Equal(t, "*", plugin.Pattern)
}

func TestDefaultScope(t *testing.T) {
tests := []struct {
name string
scope string
expected map[string]string
}{
{
scope: "",
expected: map[string]string{
"scope": "system",
"user": "",
},
},
{
scope: "system",
expected: map[string]string{
"scope": "system",
"user": "",
},
},
{
scope: "user",
expected: map[string]string{
"scope": "user",
"user": os.Getenv("USER"),
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
plugin := &SystemdUnits{
Scope: tt.scope,
}
require.NoError(t, plugin.Init())
if tt.expected["scope"] != plugin.scope {
t.Fatalf("Incorrect scope set: %q", plugin.scope)
}

if tt.expected["user"] != plugin.user {
t.Fatalf("Wrong username established: %q", plugin.user)
}
})
}
}

func TestListFiles(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -68,6 +115,7 @@ func TestListFiles(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "running",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -100,6 +148,7 @@ func TestListFiles(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "exited",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -132,6 +181,7 @@ func TestListFiles(t *testing.T) {
"load": "loaded",
"active": "failed",
"sub": "failed",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -164,6 +214,7 @@ func TestListFiles(t *testing.T) {
"load": "not-found",
"active": "inactive",
"sub": "dead",
"user": "",
},
map[string]interface{}{
"load_code": 2,
Expand Down Expand Up @@ -281,6 +332,7 @@ func TestShow(t *testing.T) {
"sub": "running",
"state": "enabled",
"preset": "disabled",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -329,6 +381,7 @@ func TestShow(t *testing.T) {
"sub": "exited",
"state": "enabled",
"preset": "disabled",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -381,6 +434,7 @@ func TestShow(t *testing.T) {
"sub": "failed",
"state": "enabled",
"preset": "disabled",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -426,6 +480,7 @@ func TestShow(t *testing.T) {
"sub": "dead",
"state": "enabled",
"preset": "disabled",
"user": "",
},
map[string]interface{}{
"load_code": 2,
Expand Down Expand Up @@ -496,6 +551,7 @@ func TestShow(t *testing.T) {
"sub": "dead",
"state": "disabled",
"preset": "disabled",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand Down Expand Up @@ -569,6 +625,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "running",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -584,6 +641,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "running",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -599,6 +657,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "exited",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -620,6 +679,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "running",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -635,6 +695,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "exited",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -656,6 +717,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "active",
"sub": "exited",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -677,6 +739,7 @@ func TestMultiInstance(t *testing.T) {
"load": "loaded",
"active": "inactive",
"sub": "dead",
"user": "",
},
map[string]interface{}{
"load_code": 0,
Expand All @@ -698,6 +761,7 @@ func TestMultiInstance(t *testing.T) {
"load": "stub",
"active": "inactive",
"sub": "dead",
"user": "",
},
map[string]interface{}{
"load_code": 1,
Expand Down Expand Up @@ -966,6 +1030,7 @@ func oldParseListUnits(line string) ([]telegraf.Metric, error) {
"load": load,
"active": active,
"sub": sub,
"user": "",
}

var (
Expand Down
Loading