-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Steffen Vogel <[email protected]>
- Loading branch information
Showing
18 changed files
with
1,193 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// SPDX-FileCopyrightText: 2024 Steffen Vogel <[email protected]> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package gont | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/coreos/go-systemd/v22/dbus" | ||
) | ||
|
||
type CGroupOption interface { | ||
ApplyCGroup(s *CGroup) | ||
} | ||
|
||
type CGroup struct { | ||
Name string | ||
Type string | ||
Properties []dbus.Property | ||
|
||
sdConn *dbus.Conn | ||
} | ||
|
||
func NewCGroup(c *dbus.Conn, typ, name string, opts ...Option) (g *CGroup, err error) { | ||
g = &CGroup{ | ||
Name: name, | ||
Type: typ, | ||
sdConn: c, | ||
} | ||
|
||
// Create D-Bus connection if not existing | ||
if g.sdConn == nil { | ||
if g.sdConn, err = dbus.NewWithContext(context.Background()); err != nil { | ||
return nil, fmt.Errorf("failed to connect to D-Bus: %w", err) | ||
} | ||
} | ||
|
||
for _, opt := range opts { | ||
if opt, ok := opt.(CGroupOption); ok { | ||
opt.ApplyCGroup(g) | ||
} | ||
} | ||
|
||
return g, nil | ||
} | ||
|
||
func (g *CGroup) Unit() string { | ||
return g.Name + "." + g.Type | ||
} | ||
|
||
// Start creates the CGroup | ||
func (g *CGroup) Start() error { | ||
if _, err := g.sdConn.StartTransientUnitContext(context.Background(), g.Unit(), "replace", g.Properties, nil); err != nil { | ||
return fmt.Errorf("failed to create slice: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Stop stops the CGroup and kills all contained processes | ||
func (g *CGroup) Stop() error { | ||
ch := make(chan string) | ||
if _, err := g.sdConn.StopUnitContext(context.Background(), g.Unit(), "fail", ch); err != nil { | ||
return fmt.Errorf("failed to remove slice: %w", err) | ||
} | ||
|
||
if state := <-ch; state != "done" { | ||
return fmt.Errorf("failed to wait for CGroup shutdown: state is %s", state) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Freeze suspends execution of all processes in the control group. | ||
func (g *CGroup) Freeze() error { | ||
return g.sdConn.FreezeUnit(context.Background(), g.Unit()) | ||
} | ||
|
||
// Thaw resumes execution of all processes in the control group. | ||
func (g *CGroup) Thaw() error { | ||
return g.sdConn.ThawUnit(context.Background(), g.Unit()) | ||
} | ||
|
||
// SetProperties sets transient systemd CGroup properties of the unit. | ||
// See: https://systemd.io/TRANSIENT-SETTINGS/ | ||
func (g *CGroup) SetProperties(opts ...CGroupOption) error { | ||
so := &CGroup{} | ||
for _, opt := range opts { | ||
opt.ApplyCGroup(g) | ||
opt.ApplyCGroup(so) | ||
} | ||
|
||
return g.sdConn.SetUnitPropertiesContext(context.Background(), g.Unit(), true, so.Properties...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// SPDX-FileCopyrightText: 2023 Steffen Vogel <[email protected]> | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package gont_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
g "cunicu.li/gont/v2/pkg" | ||
sdo "cunicu.li/gont/v2/pkg/options/systemd" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestCGroup(t *testing.T) { | ||
n, err := g.NewNetwork("", globalNetworkOptions...) | ||
require.NoError(t, err, "Failed to create network") | ||
defer n.Close() | ||
|
||
h, err := n.AddHost("h1") | ||
require.NoError(t, err) | ||
|
||
cmd := h.Command("cat", "/proc/self/cgroup") | ||
out, err := cmd.CombinedOutput() | ||
require.NoError(t, err) | ||
|
||
expectedCgroup := fmt.Sprintf("0::/gont.slice/gont-%s.slice/gont-%s-%s.slice/gont-run-%d.scope\n", n.Name, n.Name, h.Name(), cmd.ProcessState.Pid()) | ||
require.Equal(t, expectedCgroup, string(out)) | ||
} | ||
|
||
func TestCGroupPropertyNetwork(t *testing.T) { | ||
n, err := g.NewNetwork("", g.Customize(globalNetworkOptions, sdo.MemoryMax(5<<20))...) | ||
require.NoError(t, err, "Failed to create network") | ||
defer n.Close() | ||
|
||
h, err := n.AddHost("h1") | ||
require.NoError(t, err) | ||
|
||
cmd := h.Command("bash", "-c", "systemctl show "+n.Unit()+" | grep ^MemoryMax=") | ||
out, err := cmd.CombinedOutput() | ||
require.NoError(t, err) | ||
|
||
outExpected := fmt.Sprintf("MemoryMax=%d\n", 5<<20) | ||
require.Equal(t, outExpected, string(out)) | ||
} | ||
|
||
func TestCGroupPropertyHost(t *testing.T) { | ||
n, err := g.NewNetwork("", globalNetworkOptions...) | ||
require.NoError(t, err, "Failed to create network") | ||
defer n.Close() | ||
|
||
h, err := n.AddHost("h1", sdo.MemoryMax(5<<20)) | ||
require.NoError(t, err) | ||
|
||
cmd := h.Command("bash", "-c", "systemctl show "+h.Unit()+" | grep ^MemoryMax=") | ||
out, err := cmd.CombinedOutput() | ||
require.NoError(t, err) | ||
|
||
outExpected := fmt.Sprintf("MemoryMax=%d\n", 5<<20) | ||
require.Equal(t, outExpected, string(out)) | ||
} | ||
|
||
func TestCGroupPropertyCommand(t *testing.T) { | ||
n, err := g.NewNetwork("", globalNetworkOptions...) | ||
require.NoError(t, err, "Failed to create network") | ||
defer n.Close() | ||
|
||
h, err := n.AddHost("h1") | ||
require.NoError(t, err) | ||
|
||
cmd := h.Command("bash", "-c", "systemctl show gont-run-$$.scope | grep ^MemoryMax=", sdo.MemoryMax(5<<20)) | ||
out, err := cmd.CombinedOutput() | ||
require.NoError(t, err) | ||
|
||
outExpected := fmt.Sprintf("MemoryMax=%d\n", 5<<20) | ||
require.Equal(t, outExpected, string(out)) | ||
} | ||
|
||
func TestCGroupTeardown(t *testing.T) { | ||
n, err := g.NewNetwork("", globalNetworkOptions...) | ||
require.NoError(t, err, "Failed to create network") | ||
|
||
h, err := n.AddHost("h1", sdo.MemoryMax(5<<20)) | ||
require.NoError(t, err) | ||
|
||
cmd := h.Command("sleep", 3600) | ||
err = cmd.Start() | ||
require.NoError(t, err) | ||
|
||
exited := make(chan bool) | ||
go func() { | ||
cmd.Wait() | ||
close(exited) | ||
}() | ||
|
||
time.Sleep(10 * time.Millisecond) | ||
|
||
err = n.Close() | ||
require.NoError(t, err) | ||
|
||
select { | ||
case <-exited: | ||
|
||
case <-time.After(10 * time.Millisecond): | ||
require.Fail(t, "Process did not terminate") | ||
} | ||
} |
Oops, something went wrong.