diff --git a/pkg/kubelet/cm/cgroup_manager_linux.go b/pkg/kubelet/cm/cgroup_manager_linux.go new file mode 100644 index 00000000000..e147319ec6f --- /dev/null +++ b/pkg/kubelet/cm/cgroup_manager_linux.go @@ -0,0 +1,113 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cm + +import ( + "fmt" + + libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs" +) + +// cgroupManagerImpl implements the CgroupManager interface. +// Its a stateless object which can be used to +// update,create or delete any number of cgroups +// It uses the Libcontainer raw fs cgroup manager for cgroup management. +type cgroupManagerImpl struct { + // subsystems holds information about all the + // mounted cgroup subsytems on the node + subsystems *cgroupSubsystems +} + +// Make sure that cgroupManagerImpl implements the CgroupManager interface +var _ CgroupManager = &cgroupManagerImpl{} + +// NewCgroupManager is a factory method that returns a CgroupManager +func NewCgroupManager(cs *cgroupSubsystems) CgroupManager { + return &cgroupManagerImpl{ + subsystems: cs, + } +} + +// Destroy destroys the specified cgroup +func (m *cgroupManagerImpl) Destroy(cgroupConfig *CgroupConfig) error { + //cgroup name + name := cgroupConfig.Name + + // get the fscgroup Manager with the specified cgroup configuration + fsCgroupManager, err := getLibcontainerCgroupManager(cgroupConfig, m.subsystems) + + if err != nil { + return fmt.Errorf("Unable to destroy cgroup paths for cgroup %v : %v", name, err) + } + // Delete cgroups using libcontainers Managers Destroy() method + if err := fsCgroupManager.Destroy(); err != nil { + return fmt.Errorf("Unable to destroy cgroup paths for cgroup %v : %v", name, err) + } + return nil +} + +// Update updates the cgroup with the specified Cgroup Configuration +func (m *cgroupManagerImpl) Update(cgroupConfig *CgroupConfig) error { + //cgroup name + name := cgroupConfig.Name + + // get the fscgroup Manager with the specified cgroup configuration + fsCgroupManager, err := getLibcontainerCgroupManager(cgroupConfig, m.subsystems) + if err != nil { + return fmt.Errorf("Failed to update cgroup for %v : %v", name, err) + } + // get config object for passing to Set() + config := &libcontainerconfigs.Config{ + Cgroups: fsCgroupManager.Cgroups, + } + + // Update cgroup configuration using libcontainers Managers Set() method + if err := fsCgroupManager.Set(config); err != nil { + return fmt.Errorf("Failed to update cgroup for %v: %v", name, err) + } + return nil +} + +// Create creates the specified cgroup +func (m *cgroupManagerImpl) Create(cgroupConfig *CgroupConfig) error { + //cgroup name + name := cgroupConfig.Name + + // get the fscgroup Manager with the specified cgroup configuration + fsCgroupManager, err := getLibcontainerCgroupManager(cgroupConfig, m.subsystems) + if err != nil { + return fmt.Errorf("Failed to create cgroup for %v : %v", name, err) + } + // get config object for passing to libcontainer's Set() method + config := &libcontainerconfigs.Config{ + Cgroups: fsCgroupManager.Cgroups, + } + //Apply(0) is a hack to create the cgroup directories for each resource + // subsystem. The function [cgroups.Manager.apply()] applies cgroup + // configuration to the process with the specified pid. + // It creates cgroup files for each subsytems and writes the pid + // in the tasks file. We use the function to create all the required + // cgroup files but not attach any "real" pid to the cgroup. + if err := fsCgroupManager.Apply(0); err != nil { + return fmt.Errorf("Failed to create cgroup for %v: %v", name, err) + } + // Update cgroup configuration using libcontainers Managers Set() method + if err := fsCgroupManager.Set(config); err != nil { + return fmt.Errorf("Failed to create cgroup for %v: %v", name, err) + } + return nil +} diff --git a/pkg/kubelet/cm/cgroup_manager_unsupported.go b/pkg/kubelet/cm/cgroup_manager_unsupported.go new file mode 100644 index 00000000000..a00e030a2e2 --- /dev/null +++ b/pkg/kubelet/cm/cgroup_manager_unsupported.go @@ -0,0 +1,42 @@ +// +build !linux + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cm + +import "fmt" + +type unsupportedCgroupManager struct{} + +// Make sure that unsupportedCgroupManager implements the CgroupManager interface +var _ CgroupManager = &unsupportedCgroupManager{} + +func NewCgroupManager(_ *cgroupSubsystems) CgroupManager { + return &unsupportedCgroupManager{} +} + +func (m *unsupportedCgroupManager) Destroy(_ *CgroupConfig) error { + return nil +} + +func (m *unsupportedCgroupManager) Update(_ *CgroupConfig) error { + return nil +} + +func (m *unsupportedCgroupManager) Create(_ *CgroupConfig) error { + return fmt.Errorf("Cgroup Manager is not supported in this build") +} diff --git a/pkg/kubelet/cm/helpers_linux.go b/pkg/kubelet/cm/helpers_linux.go new file mode 100644 index 00000000000..12a0b315c63 --- /dev/null +++ b/pkg/kubelet/cm/helpers_linux.go @@ -0,0 +1,98 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cm + +import ( + "fmt" + "path" + + libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" + cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" + libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs" +) + +// cgroupSubsystems holds information about the mounted cgroup subsytems +type cgroupSubsystems struct { + // Cgroup subsystem mounts. + // e.g.: "/sys/fs/cgroup/cpu" -> ["cpu", "cpuacct"] + mounts []libcontainercgroups.Mount + + // Cgroup subsystem to their mount location. + // e.g.: "cpu" -> "/sys/fs/cgroup/cpu" + mountPoints map[string]string +} + +// GetCgroupSubsystems returns information about the mounted cgroup subsystems +func getCgroupSubsystems() (*cgroupSubsystems, error) { + // Get all cgroup mounts. + allCgroups, err := libcontainercgroups.GetCgroupMounts() + if err != nil { + return &cgroupSubsystems{}, err + } + if len(allCgroups) == 0 { + return &cgroupSubsystems{}, fmt.Errorf("failed to find cgroup mounts") + } + + //TODO(@dubstack) should we trim to only the supported ones + mountPoints := make(map[string]string, len(allCgroups)) + for _, mount := range allCgroups { + for _, subsystem := range mount.Subsystems { + mountPoints[subsystem] = mount.Mountpoint + } + } + return &cgroupSubsystems{ + mounts: allCgroups, + mountPoints: mountPoints, + }, nil +} + +// getLibcontainerCgroupManager returns libcontainer's cgroups manager +// object with the specified cgroup configuration +func getLibcontainerCgroupManager(cgroupConfig *CgroupConfig, subsystems *cgroupSubsystems) (*cgroupfs.Manager, error) { + // get cgroup name + name := cgroupConfig.Name + + // Get map of all cgroup paths on the system for the particular cgroup + cgroupPaths := make(map[string]string, len(subsystems.mountPoints)) + for key, val := range subsystems.mountPoints { + cgroupPaths[key] = path.Join(val, name) + } + + // Extract the cgroup resource parameters + resourceConfig := cgroupConfig.ResourceParameters + resources := &libcontainerconfigs.Resources{} + resources.AllowAllDevices = true + if resourceConfig.Memory != nil { + resources.Memory = *resourceConfig.Memory + } + if resourceConfig.CpuShares != nil { + resources.CpuShares = *resourceConfig.CpuShares + } + if resourceConfig.CpuQuota != nil { + resources.CpuQuota = *resourceConfig.CpuQuota + } + // Initialize libcontainer's cgroup config + libcontainerCgroupConfig := &libcontainerconfigs.Cgroup{ + Name: path.Base(name), + Parent: path.Dir(name), + Resources: resources, + } + return &cgroupfs.Manager{ + Cgroups: libcontainerCgroupConfig, + Paths: cgroupPaths, + }, nil +} diff --git a/pkg/kubelet/cm/types.go b/pkg/kubelet/cm/types.go new file mode 100644 index 00000000000..a225bb8d6d0 --- /dev/null +++ b/pkg/kubelet/cm/types.go @@ -0,0 +1,56 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cm + +// ResourceConfig holds information about all the supported cgroup resource parameters. +type ResourceConfig struct { + // Memory limit (in bytes). + Memory *int64 + // CPU shares (relative weight vs. other containers). + CpuShares *int64 + // CPU hardcap limit (in usecs). Allowed cpu time in a given period. + CpuQuota *int64 +} + +// CgroupConfig holds the cgroup configuration information. +// This is common object which is used to specify +// cgroup information to both systemd and raw cgroup fs +// implementation of the Cgroup Manager interface. +type CgroupConfig struct { + // We would expect systemd implementation to make appropriate + // name conversion. For example, if we pass /foo/bar + // then systemd should convert the name to something like + // foo.slice/foo-bar.slice + + // Fully qualified name + Name string + // ResourceParameters contains various cgroups settings to apply. + ResourceParameters *ResourceConfig +} + +// CgroupManager allows for cgroup management. +// Supports Cgroup Creation ,Deletion and Updates. +type CgroupManager interface { + // Create creates and applies the cgroup configurations on the cgroup. + // It just creates the leaf cgroups. + // It expects the parent cgroup to already exist. + Create(*CgroupConfig) error + // Destroys the cgroup. + Destroy(*CgroupConfig) error + // Update cgroup configuration. + Update(*CgroupConfig) error +}