gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

systemd.go (4049B)


      1 /*
      2    Copyright The containerd Authors.
      3 
      4    Licensed under the Apache License, Version 2.0 (the "License");
      5    you may not use this file except in compliance with the License.
      6    You may obtain a copy of the License at
      7 
      8        http://www.apache.org/licenses/LICENSE-2.0
      9 
     10    Unless required by applicable law or agreed to in writing, software
     11    distributed under the License is distributed on an "AS IS" BASIS,
     12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13    See the License for the specific language governing permissions and
     14    limitations under the License.
     15 */
     16 
     17 package cgroup1
     18 
     19 import (
     20 	"context"
     21 	"path/filepath"
     22 	"strings"
     23 	"sync"
     24 
     25 	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
     26 	"github.com/godbus/dbus/v5"
     27 	specs "github.com/opencontainers/runtime-spec/specs-go"
     28 )
     29 
     30 const (
     31 	SystemdDbus  Name = "systemd"
     32 	defaultSlice      = "system.slice"
     33 )
     34 
     35 var (
     36 	canDelegate bool
     37 	once        sync.Once
     38 )
     39 
     40 func Systemd() ([]Subsystem, error) {
     41 	root, err := v1MountPoint()
     42 	if err != nil {
     43 		return nil, err
     44 	}
     45 	defaultSubsystems, err := defaults(root)
     46 	if err != nil {
     47 		return nil, err
     48 	}
     49 	s, err := NewSystemd(root)
     50 	if err != nil {
     51 		return nil, err
     52 	}
     53 	// make sure the systemd controller is added first
     54 	return append([]Subsystem{s}, defaultSubsystems...), nil
     55 }
     56 
     57 func Slice(slice, name string) Path {
     58 	if slice == "" {
     59 		slice = defaultSlice
     60 	}
     61 	return func(subsystem Name) (string, error) {
     62 		return filepath.Join(slice, name), nil
     63 	}
     64 }
     65 
     66 func NewSystemd(root string) (*SystemdController, error) {
     67 	return &SystemdController{
     68 		root: root,
     69 	}, nil
     70 }
     71 
     72 type SystemdController struct {
     73 	mu   sync.Mutex
     74 	root string
     75 }
     76 
     77 func (s *SystemdController) Name() Name {
     78 	return SystemdDbus
     79 }
     80 
     81 func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
     82 	ctx := context.TODO()
     83 	conn, err := systemdDbus.NewWithContext(ctx)
     84 	if err != nil {
     85 		return err
     86 	}
     87 	defer conn.Close()
     88 	slice, name := splitName(path)
     89 	// We need to see if systemd can handle the delegate property
     90 	// Systemd will return an error if it cannot handle delegate regardless
     91 	// of its bool setting.
     92 	checkDelegate := func() {
     93 		canDelegate = true
     94 		dlSlice := newProperty("Delegate", true)
     95 		if _, err := conn.StartTransientUnitContext(ctx, slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
     96 			if dbusError, ok := err.(dbus.Error); ok {
     97 				// Starting with systemd v237, Delegate is not even a property of slices anymore,
     98 				// so the D-Bus call fails with "InvalidArgs" error.
     99 				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
    100 					canDelegate = false
    101 				}
    102 			}
    103 		}
    104 
    105 		_, _ = conn.StopUnitContext(ctx, slice, "testDelegate", nil)
    106 	}
    107 	once.Do(checkDelegate)
    108 	properties := []systemdDbus.Property{
    109 		systemdDbus.PropDescription("cgroup " + name),
    110 		systemdDbus.PropWants(slice),
    111 		newProperty("DefaultDependencies", false),
    112 		newProperty("MemoryAccounting", true),
    113 		newProperty("CPUAccounting", true),
    114 		newProperty("BlockIOAccounting", true),
    115 	}
    116 
    117 	// If we can delegate, we add the property back in
    118 	if canDelegate {
    119 		properties = append(properties, newProperty("Delegate", true))
    120 	}
    121 
    122 	ch := make(chan string)
    123 	_, err = conn.StartTransientUnitContext(ctx, name, "replace", properties, ch)
    124 	if err != nil {
    125 		return err
    126 	}
    127 	<-ch
    128 	return nil
    129 }
    130 
    131 func (s *SystemdController) Delete(path string) error {
    132 	ctx := context.TODO()
    133 	conn, err := systemdDbus.NewWithContext(ctx)
    134 	if err != nil {
    135 		return err
    136 	}
    137 	defer conn.Close()
    138 	_, name := splitName(path)
    139 	ch := make(chan string)
    140 	_, err = conn.StopUnitContext(ctx, name, "replace", ch)
    141 	if err != nil {
    142 		return err
    143 	}
    144 	<-ch
    145 	return nil
    146 }
    147 
    148 func newProperty(name string, units interface{}) systemdDbus.Property {
    149 	return systemdDbus.Property{
    150 		Name:  name,
    151 		Value: dbus.MakeVariant(units),
    152 	}
    153 }
    154 
    155 func splitName(path string) (slice string, unit string) {
    156 	slice, unit = filepath.Split(path)
    157 	return strings.TrimSuffix(slice, "/"), unit
    158 }