Skip to content

Commit 0701e9b

Browse files
committed
support building w/o systemd
Compile w/ build tag "no_systemd" for opting out from systemd support and its dependencies - thus massively reducing binary size (for cgctl, about 20%) Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
1 parent a0ae1c2 commit 0701e9b

File tree

6 files changed

+314
-225
lines changed

6 files changed

+314
-225
lines changed

cgroup1/systemd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//go:build linux && !no_systemd
12
/*
23
Copyright The containerd Authors.
34

cgroup2/manager.go

Lines changed: 0 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ package cgroup2
1818

1919
import (
2020
"bufio"
21-
"context"
2221
"errors"
2322
"fmt"
24-
"math"
2523
"os"
2624
"path/filepath"
2725
"strconv"
@@ -30,8 +28,6 @@ import (
3028

3129
"github.com/containerd/cgroups/v3/cgroup2/stats"
3230

33-
systemdDbus "github.com/coreos/go-systemd/v22/dbus"
34-
"github.com/godbus/dbus/v5"
3531
"github.com/opencontainers/runtime-spec/specs-go"
3632
"github.com/sirupsen/logrus"
3733
"golang.org/x/sys/unix"
@@ -761,208 +757,3 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
761757
}
762758
return nil
763759
}
764-
765-
// getSystemdFullPath returns the full systemd path when creating a systemd slice group.
766-
// the reason this is necessary is because the "-" character has a special meaning in
767-
// systemd slice. For example, when creating a slice called "my-group-112233.slice",
768-
// systemd will create a hierarchy like this:
769-
//
770-
// /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice
771-
func getSystemdFullPath(slice, group string) string {
772-
return filepath.Join(defaultCgroup2Path, dashesToPath(slice), dashesToPath(group))
773-
}
774-
775-
// dashesToPath converts a slice name with dashes to it's corresponding systemd filesystem path.
776-
func dashesToPath(in string) string {
777-
path := ""
778-
if strings.HasSuffix(in, ".slice") && strings.Contains(in, "-") {
779-
parts := strings.Split(in, "-")
780-
for i := range parts {
781-
s := strings.Join(parts[0:i+1], "-")
782-
if !strings.HasSuffix(s, ".slice") {
783-
s += ".slice"
784-
}
785-
path = filepath.Join(path, s)
786-
}
787-
} else {
788-
path = filepath.Join(path, in)
789-
}
790-
return path
791-
}
792-
793-
func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, error) {
794-
if slice == "" {
795-
slice = defaultSlice
796-
}
797-
ctx := context.TODO()
798-
path := getSystemdFullPath(slice, group)
799-
conn, err := systemdDbus.NewWithContext(ctx)
800-
if err != nil {
801-
return &Manager{}, err
802-
}
803-
defer conn.Close()
804-
805-
properties := []systemdDbus.Property{
806-
systemdDbus.PropDescription("cgroup " + group),
807-
newSystemdProperty("DefaultDependencies", false),
808-
newSystemdProperty("MemoryAccounting", true),
809-
newSystemdProperty("CPUAccounting", true),
810-
newSystemdProperty("IOAccounting", true),
811-
}
812-
813-
// if we create a slice, the parent is defined via a Wants=
814-
if strings.HasSuffix(group, ".slice") {
815-
properties = append(properties, systemdDbus.PropWants(defaultSlice))
816-
} else {
817-
// otherwise, we use Slice=
818-
properties = append(properties, systemdDbus.PropSlice(defaultSlice))
819-
}
820-
821-
// only add pid if its valid, -1 is used w/ general slice creation.
822-
if pid != -1 {
823-
properties = append(properties, newSystemdProperty("PIDs", []uint32{uint32(pid)}))
824-
}
825-
826-
if resources.Memory != nil && resources.Memory.Min != nil && *resources.Memory.Min != 0 {
827-
properties = append(properties,
828-
newSystemdProperty("MemoryMin", uint64(*resources.Memory.Min)))
829-
}
830-
831-
if resources.Memory != nil && resources.Memory.Max != nil && *resources.Memory.Max != 0 {
832-
properties = append(properties,
833-
newSystemdProperty("MemoryMax", uint64(*resources.Memory.Max)))
834-
}
835-
836-
if resources.CPU != nil && resources.CPU.Weight != nil && *resources.CPU.Weight != 0 {
837-
properties = append(properties,
838-
newSystemdProperty("CPUWeight", *resources.CPU.Weight))
839-
}
840-
841-
if resources.CPU != nil && resources.CPU.Max != "" {
842-
quota, period := resources.CPU.Max.extractQuotaAndPeriod()
843-
// cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
844-
// corresponds to USEC_INFINITY in systemd
845-
// if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
846-
// always setting a property value ensures we can apply a quota and remove it later
847-
cpuQuotaPerSecUSec := uint64(math.MaxUint64)
848-
if quota > 0 {
849-
// systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
850-
// (integer percentage of CPU) internally. This means that if a fractional percent of
851-
// CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
852-
// 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
853-
cpuQuotaPerSecUSec = uint64(quota*1000000) / period
854-
if cpuQuotaPerSecUSec%10000 != 0 {
855-
cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
856-
}
857-
}
858-
properties = append(properties,
859-
newSystemdProperty("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
860-
}
861-
862-
// If we can delegate, we add the property back in
863-
if canDelegate {
864-
properties = append(properties, newSystemdProperty("Delegate", true))
865-
}
866-
867-
if resources.Pids != nil && resources.Pids.Max > 0 {
868-
properties = append(properties,
869-
newSystemdProperty("TasksAccounting", true),
870-
newSystemdProperty("TasksMax", uint64(resources.Pids.Max)))
871-
}
872-
873-
if err := startUnit(conn, group, properties, pid == -1); err != nil {
874-
return &Manager{}, err
875-
}
876-
877-
return &Manager{
878-
path: path,
879-
}, nil
880-
}
881-
882-
func startUnit(conn *systemdDbus.Conn, group string, properties []systemdDbus.Property, ignoreExists bool) error {
883-
ctx := context.TODO()
884-
885-
statusChan := make(chan string, 1)
886-
defer close(statusChan)
887-
888-
retry := true
889-
started := false
890-
891-
for !started {
892-
if _, err := conn.StartTransientUnitContext(ctx, group, "replace", properties, statusChan); err != nil {
893-
if !isUnitExists(err) {
894-
return err
895-
}
896-
897-
if ignoreExists {
898-
return nil
899-
}
900-
901-
if retry {
902-
retry = false
903-
// When a unit of the same name already exists, it may be a leftover failed unit.
904-
// If we reset it once, systemd can try to remove it.
905-
attemptFailedUnitReset(conn, group)
906-
continue
907-
}
908-
909-
return err
910-
} else {
911-
started = true
912-
}
913-
}
914-
915-
select {
916-
case s := <-statusChan:
917-
if s != "done" {
918-
attemptFailedUnitReset(conn, group)
919-
return fmt.Errorf("error creating systemd unit `%s`: got `%s`", group, s)
920-
}
921-
case <-time.After(30 * time.Second):
922-
logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", group)
923-
}
924-
925-
return nil
926-
}
927-
928-
func attemptFailedUnitReset(conn *systemdDbus.Conn, group string) {
929-
err := conn.ResetFailedUnitContext(context.TODO(), group)
930-
931-
if err != nil {
932-
logrus.Warnf("Unable to reset failed unit: %v", err)
933-
}
934-
}
935-
936-
func LoadSystemd(slice, group string) (*Manager, error) {
937-
if slice == "" {
938-
slice = defaultSlice
939-
}
940-
path := getSystemdFullPath(slice, group)
941-
return &Manager{
942-
path: path,
943-
}, nil
944-
}
945-
946-
func (c *Manager) DeleteSystemd() error {
947-
ctx := context.TODO()
948-
conn, err := systemdDbus.NewWithContext(ctx)
949-
if err != nil {
950-
return err
951-
}
952-
defer conn.Close()
953-
group := systemdUnitFromPath(c.path)
954-
ch := make(chan string)
955-
_, err = conn.StopUnitContext(ctx, group, "replace", ch)
956-
if err != nil {
957-
return err
958-
}
959-
<-ch
960-
return nil
961-
}
962-
963-
func newSystemdProperty(name string, units interface{}) systemdDbus.Property {
964-
return systemdDbus.Property{
965-
Name: name,
966-
Value: dbus.MakeVariant(units),
967-
}
968-
}

cgroup2/manager_no_systemd.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//go:build linux && no_systemd
2+
3+
/*
4+
Copyright The containerd Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package cgroup2
20+
21+
import (
22+
"errors"
23+
)
24+
25+
func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, error) {
26+
return &Manager{}, errors.New("no systemd support")
27+
}
28+
29+
func LoadSystemd(slice, group string) (*Manager, error) {
30+
return &Manager{}, errors.New("no systemd support")
31+
}
32+
33+
func (c *Manager) DeleteSystemd() error {
34+
return errors.New("no systemd support")
35+
}

0 commit comments

Comments
 (0)