From 2fa0854d5402ddf13d3766750f9cd70e3deb4937 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Thu, 13 Dec 2018 10:24:45 -0600 Subject: [PATCH 01/10] dbus: Add GetUnitByPID --- dbus/methods.go | 9 ++++++++ dbus/methods_test.go | 43 +++++++++++++++++++++++++++++++++++ fixtures/get-unit-pid.service | 5 ++++ fixtures/get-unit-pid.sh | 2 ++ 4 files changed, 59 insertions(+) create mode 100644 fixtures/get-unit-pid.service create mode 100755 fixtures/get-unit-pid.sh diff --git a/dbus/methods.go b/dbus/methods.go index 6a0aa656..a1531836 100644 --- a/dbus/methods.go +++ b/dbus/methods.go @@ -288,6 +288,15 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { return status, nil } +// GetUnitByPID returns an array with all currently loaded units. Note that +func (c *Conn) GetUnitByPID(pid int) (dbus.ObjectPath, error) { + var op dbus.ObjectPath + if err := c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnitByPID", 0, uint(pid)).Store(&op); err != nil { + return dbus.ObjectPath(""), err + } + return op, nil +} + // ListUnits returns an array with all currently loaded units. Note that // units may be known by multiple names at the same time, and hence there might // be more unit names loaded than actual units behind them. diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 061605bf..277e97c8 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -16,11 +16,14 @@ package dbus import ( "fmt" + "io/ioutil" + "log" "os" "os/exec" "path" "path/filepath" "reflect" + "strconv" "syscall" "testing" "time" @@ -132,6 +135,18 @@ func runStopUnit(t *testing.T, conn *Conn, trTarget TrUnitProp) error { return nil } +func assertNoError(t *testing.T, err error) { + if err != nil { + t.Fatal(err) + } +} + +func assertEqualStr(t *testing.T, shouldBe, target string) { + if target != shouldBe { + t.Fatalf("expected %q to equal %q", target, shouldBe) + } +} + // Ensure that basic unit starting and stopping works. func TestStartStopUnit(t *testing.T) { target := "start-stop.service" @@ -1539,3 +1554,31 @@ func TestUnitName(t *testing.T) { } } } + +func TestGetUnitByPID(t *testing.T) { + target := "get-unit-pid.service" + conn := setupConn(t) + defer conn.Close() + + setupUnit(target, conn, t) + linkUnit(target, conn, t) + + reschan := make(chan string) + _, err := conn.StartUnit(target, "replace", reschan) + assertNoError(t, err) + + job := <-reschan + if job != "done" { + t.Fatal("Job is not done:", job) + } + + pidStr, err := ioutil.ReadFile("../fixtures/get-unit-pid.pid") + assertNoError(t, err) + pid, err := strconv.Atoi(string(pidStr)) + assertNoError(t, err) + objectPath, err := conn.GetUnitByPID(pid) + if err != nil { + log.Fatalf("conn.getunitbypid ntp: %v", err) + } + assertEqualStr(t, "foo", string(objectPath)) +} diff --git a/fixtures/get-unit-pid.service b/fixtures/get-unit-pid.service new file mode 100644 index 00000000..a6a59f33 --- /dev/null +++ b/fixtures/get-unit-pid.service @@ -0,0 +1,5 @@ +[Unit] +Description=get unit pid + +[Service] +ExecStart=get-unit-pid.sh diff --git a/fixtures/get-unit-pid.sh b/fixtures/get-unit-pid.sh new file mode 100755 index 00000000..fcf92c18 --- /dev/null +++ b/fixtures/get-unit-pid.sh @@ -0,0 +1,2 @@ +/bin/echo ${PID} >get-unit-pid.pid +/bin/sleep 400 From 802a0d96a7d8d47c71dda525c94e704c936d8605 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:01:10 -0800 Subject: [PATCH 02/10] fix up test --- dbus/methods.go | 2 +- dbus/methods_test.go | 44 ++++++++++++++++------------------- fixtures/get-unit-pid.service | 2 +- fixtures/get-unit-pid.sh | 2 -- 4 files changed, 22 insertions(+), 28 deletions(-) delete mode 100755 fixtures/get-unit-pid.sh diff --git a/dbus/methods.go b/dbus/methods.go index a1531836..90465c90 100644 --- a/dbus/methods.go +++ b/dbus/methods.go @@ -289,7 +289,7 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { } // GetUnitByPID returns an array with all currently loaded units. Note that -func (c *Conn) GetUnitByPID(pid int) (dbus.ObjectPath, error) { +func (c *Conn) GetUnitByPID(pid uint32) (dbus.ObjectPath, error) { var op dbus.ObjectPath if err := c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnitByPID", 0, uint(pid)).Store(&op); err != nil { return dbus.ObjectPath(""), err diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 277e97c8..c520fb78 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -16,14 +16,11 @@ package dbus import ( "fmt" - "io/ioutil" - "log" "os" "os/exec" "path" "path/filepath" "reflect" - "strconv" "syscall" "testing" "time" @@ -135,18 +132,6 @@ func runStopUnit(t *testing.T, conn *Conn, trTarget TrUnitProp) error { return nil } -func assertNoError(t *testing.T, err error) { - if err != nil { - t.Fatal(err) - } -} - -func assertEqualStr(t *testing.T, shouldBe, target string) { - if target != shouldBe { - t.Fatalf("expected %q to equal %q", target, shouldBe) - } -} - // Ensure that basic unit starting and stopping works. func TestStartStopUnit(t *testing.T) { target := "start-stop.service" @@ -1555,6 +1540,18 @@ func TestUnitName(t *testing.T) { } } +func assertNoError(t *testing.T, err error) { + if err != nil { + t.Fatal(err) + } +} + +func assertEqualStr(t *testing.T, shouldBe, target string) { + if target != shouldBe { + t.Fatalf("expected %q to equal %q", target, shouldBe) + } +} + func TestGetUnitByPID(t *testing.T) { target := "get-unit-pid.service" conn := setupConn(t) @@ -1568,17 +1565,16 @@ func TestGetUnitByPID(t *testing.T) { assertNoError(t, err) job := <-reschan - if job != "done" { - t.Fatal("Job is not done:", job) + assertEqualStr(t, "done", job) + prop, err := conn.GetServiceProperty("get-unit-pid.service", "MainPID") + assertNoError(t, err) + + pid, ok := prop.Value.Value().(uint32) + if !ok { + t.Fatalf("expected MainPID to be uint32, got %T", prop.Value) } - pidStr, err := ioutil.ReadFile("../fixtures/get-unit-pid.pid") - assertNoError(t, err) - pid, err := strconv.Atoi(string(pidStr)) - assertNoError(t, err) objectPath, err := conn.GetUnitByPID(pid) - if err != nil { - log.Fatalf("conn.getunitbypid ntp: %v", err) - } + assertNoError(t, err) assertEqualStr(t, "foo", string(objectPath)) } diff --git a/fixtures/get-unit-pid.service b/fixtures/get-unit-pid.service index a6a59f33..63200947 100644 --- a/fixtures/get-unit-pid.service +++ b/fixtures/get-unit-pid.service @@ -2,4 +2,4 @@ Description=get unit pid [Service] -ExecStart=get-unit-pid.sh +ExecStart=/bin/sleep 400 diff --git a/fixtures/get-unit-pid.sh b/fixtures/get-unit-pid.sh deleted file mode 100755 index fcf92c18..00000000 --- a/fixtures/get-unit-pid.sh +++ /dev/null @@ -1,2 +0,0 @@ -/bin/echo ${PID} >get-unit-pid.pid -/bin/sleep 400 From 698ff266239daf3ebf3270ff9b4a588a553660e5 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:05:18 -0800 Subject: [PATCH 03/10] fix test assertion --- dbus/methods_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index c520fb78..17f25754 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -1571,10 +1571,10 @@ func TestGetUnitByPID(t *testing.T) { pid, ok := prop.Value.Value().(uint32) if !ok { - t.Fatalf("expected MainPID to be uint32, got %T", prop.Value) + t.Fatalf("expected MainPID to be uint32, got value %v of type %T", prop.Value, prop.Value) } objectPath, err := conn.GetUnitByPID(pid) assertNoError(t, err) - assertEqualStr(t, "foo", string(objectPath)) + assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) } From 20f22b5d86dd08106e927e9ccb36cde8027452b0 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:11:36 -0800 Subject: [PATCH 04/10] fix docs --- dbus/methods.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dbus/methods.go b/dbus/methods.go index 90465c90..99abdbcc 100644 --- a/dbus/methods.go +++ b/dbus/methods.go @@ -288,7 +288,8 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) { return status, nil } -// GetUnitByPID returns an array with all currently loaded units. Note that +// GetUnitByPID returns the object path of the unit a process ID belongs to. +// The pid must refer to an existing process on the system. func (c *Conn) GetUnitByPID(pid uint32) (dbus.ObjectPath, error) { var op dbus.ObjectPath if err := c.sysobj.Call("org.freedesktop.systemd1.Manager.GetUnitByPID", 0, uint(pid)).Store(&op); err != nil { From c95fcd8194307787e7a6ecaf1d04cf7d9463e074 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:14:04 -0800 Subject: [PATCH 05/10] stop unit --- dbus/methods_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 17f25754..3add1f6b 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -1577,4 +1577,8 @@ func TestGetUnitByPID(t *testing.T) { objectPath, err := conn.GetUnitByPID(pid) assertNoError(t, err) assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) + + _, err = conn.StopUnit(target, "replace", reschan) + assertNoError(t, err) + <-reschan } From 0f72dcf7c1a246e423bd44b0be2c1e2bce461349 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:19:22 -0800 Subject: [PATCH 06/10] decorate helper functions --- dbus/methods_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 3add1f6b..53a2792e 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -1541,12 +1541,14 @@ func TestUnitName(t *testing.T) { } func assertNoError(t *testing.T, err error) { + t.Helper() if err != nil { t.Fatal(err) } } func assertEqualStr(t *testing.T, shouldBe, target string) { + t.Helper() if target != shouldBe { t.Fatalf("expected %q to equal %q", target, shouldBe) } From a00023ff4b5ee76942d833a0d7a64da0f0679cfd Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:25:10 -0800 Subject: [PATCH 07/10] remove test helper decoration for golang compatibility --- dbus/methods_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 53a2792e..3add1f6b 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -1541,14 +1541,12 @@ func TestUnitName(t *testing.T) { } func assertNoError(t *testing.T, err error) { - t.Helper() if err != nil { t.Fatal(err) } } func assertEqualStr(t *testing.T, shouldBe, target string) { - t.Helper() if target != shouldBe { t.Fatalf("expected %q to equal %q", target, shouldBe) } From 921543a2291a3f2c074e4be5466186137869a3e5 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 17:28:50 -0800 Subject: [PATCH 08/10] add pid info to tests --- dbus/methods_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 3add1f6b..013aceed 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -1573,10 +1573,17 @@ func TestGetUnitByPID(t *testing.T) { if !ok { t.Fatalf("expected MainPID to be uint32, got value %v of type %T", prop.Value, prop.Value) } + if pid == 0 { + t.Fatal("expected MainPID to be greater than 0") + } objectPath, err := conn.GetUnitByPID(pid) assertNoError(t, err) - assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) + // assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) + expectPath := "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice" + if string(objectPath) != expectPath { + t.Fatalf("expected %q to equal %q for pid %d", string(objectPath), expectPath, pid) + } _, err = conn.StopUnit(target, "replace", reschan) assertNoError(t, err) From 568f78e39657bf226b39b1d7ef0ee2e71574d5a2 Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 18:23:19 -0800 Subject: [PATCH 09/10] handle slice --- dbus/methods_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dbus/methods_test.go b/dbus/methods_test.go index 013aceed..aae7aeb1 100644 --- a/dbus/methods_test.go +++ b/dbus/methods_test.go @@ -21,6 +21,7 @@ import ( "path" "path/filepath" "reflect" + "strings" "syscall" "testing" "time" @@ -1579,10 +1580,12 @@ func TestGetUnitByPID(t *testing.T) { objectPath, err := conn.GetUnitByPID(pid) assertNoError(t, err) - // assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) - expectPath := "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice" - if string(objectPath) != expectPath { - t.Fatalf("expected %q to equal %q for pid %d", string(objectPath), expectPath, pid) + if strings.HasSuffix(string(objectPath), "_2eslice") { + // in ubuntu:18.04 the top-level root slice container is the unit that gets returned + assertEqualStr(t, "/org/freedesktop/systemd1/unit/_2d_2eslice", string(objectPath)) + } else { + // otherwise, the service itself is returned + assertEqualStr(t, "/org/freedesktop/systemd1/unit/get_2dunit_2dpid_2eservice", string(objectPath)) } _, err = conn.StopUnit(target, "replace", reschan) From 302951d4dedf197b60123d829378461d7026669d Mon Sep 17 00:00:00 2001 From: "R. Tyler Julian" Date: Sun, 16 Dec 2018 18:54:53 -0800 Subject: [PATCH 10/10] rerun