...

Source file src/github.com/containerd/cgroups/systemd.go

Documentation: github.com/containerd/cgroups

     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 cgroups
    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  }
   159  

View as plain text