|  |  |  | @@ -17,6 +17,7 @@ limitations under the License. | 
		
	
		
			
				|  |  |  |  | package cm | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | import ( | 
		
	
		
			
				|  |  |  |  | 	"errors" | 
		
	
		
			
				|  |  |  |  | 	"fmt" | 
		
	
		
			
				|  |  |  |  | 	"io/ioutil" | 
		
	
		
			
				|  |  |  |  | 	"os" | 
		
	
	
		
			
				
					
					|  |  |  | @@ -29,6 +30,7 @@ import ( | 
		
	
		
			
				|  |  |  |  | 	libcontainercgroups "github.com/opencontainers/runc/libcontainer/cgroups" | 
		
	
		
			
				|  |  |  |  | 	cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" | 
		
	
		
			
				|  |  |  |  | 	cgroupfs2 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" | 
		
	
		
			
				|  |  |  |  | 	"github.com/opencontainers/runc/libcontainer/cgroups/fscommon" | 
		
	
		
			
				|  |  |  |  | 	cgroupsystemd "github.com/opencontainers/runc/libcontainer/cgroups/systemd" | 
		
	
		
			
				|  |  |  |  | 	libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs" | 
		
	
		
			
				|  |  |  |  | 	libcontainerdevices "github.com/opencontainers/runc/libcontainer/devices" | 
		
	
	
		
			
				
					
					|  |  |  | @@ -330,27 +332,6 @@ func (m *cgroupManagerImpl) Destroy(cgroupConfig *CgroupConfig) error { | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | type subsystem interface { | 
		
	
		
			
				|  |  |  |  | 	// Name returns the name of the subsystem. | 
		
	
		
			
				|  |  |  |  | 	Name() string | 
		
	
		
			
				|  |  |  |  | 	// Set the cgroup represented by cgroup. | 
		
	
		
			
				|  |  |  |  | 	Set(path string, cgroup *libcontainerconfigs.Resources) error | 
		
	
		
			
				|  |  |  |  | 	// GetStats returns the statistics associated with the cgroup | 
		
	
		
			
				|  |  |  |  | 	GetStats(path string, stats *libcontainercgroups.Stats) error | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // getSupportedSubsystems returns a map of subsystem and if it must be mounted for the kubelet to function. | 
		
	
		
			
				|  |  |  |  | func getSupportedSubsystems() map[subsystem]bool { | 
		
	
		
			
				|  |  |  |  | 	supportedSubsystems := map[subsystem]bool{ | 
		
	
		
			
				|  |  |  |  | 		&cgroupfs.MemoryGroup{}: true, | 
		
	
		
			
				|  |  |  |  | 		&cgroupfs.CpuGroup{}:    true, | 
		
	
		
			
				|  |  |  |  | 		&cgroupfs.PidsGroup{}:   true, | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	// not all hosts support hugetlb cgroup, and in the absent of hugetlb, we will fail silently by reporting no capacity. | 
		
	
		
			
				|  |  |  |  | 	supportedSubsystems[&cgroupfs.HugetlbGroup{}] = false | 
		
	
		
			
				|  |  |  |  | 	return supportedSubsystems | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // getCpuWeight converts from the range [2, 262144] to [1, 10000] | 
		
	
		
			
				|  |  |  |  | func getCpuWeight(cpuShares *uint64) uint64 { | 
		
	
		
			
				|  |  |  |  | 	if cpuShares == nil { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -393,51 +374,6 @@ func getSupportedUnifiedControllers() sets.String { | 
		
	
		
			
				|  |  |  |  | 	return supportedControllers.Intersection(availableRootControllers) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // propagateControllers on an unified hierarchy enables all the supported controllers for the specified cgroup | 
		
	
		
			
				|  |  |  |  | func propagateControllers(path string) error { | 
		
	
		
			
				|  |  |  |  | 	if err := os.MkdirAll(filepath.Join(cmutil.CgroupRoot, path), 0755); err != nil { | 
		
	
		
			
				|  |  |  |  | 		return fmt.Errorf("failed to create cgroup %q : %v", path, err) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// Retrieve all the supported controllers from the cgroup root | 
		
	
		
			
				|  |  |  |  | 	controllersFileContent, err := ioutil.ReadFile(filepath.Join(cmutil.CgroupRoot, "cgroup.controllers")) | 
		
	
		
			
				|  |  |  |  | 	if err != nil { | 
		
	
		
			
				|  |  |  |  | 		return fmt.Errorf("failed to read controllers from %q : %v", cmutil.CgroupRoot, err) | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	supportedControllers := getSupportedUnifiedControllers() | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// The retrieved content looks like: "cpuset cpu io memory hugetlb pids".  Prepend each of the controllers | 
		
	
		
			
				|  |  |  |  | 	// with '+', so we have something like "+cpuset +cpu +io +memory +hugetlb +pids" | 
		
	
		
			
				|  |  |  |  | 	controllers := "" | 
		
	
		
			
				|  |  |  |  | 	for _, controller := range strings.Fields(string(controllersFileContent)) { | 
		
	
		
			
				|  |  |  |  | 		// ignore controllers we don't care about | 
		
	
		
			
				|  |  |  |  | 		if !supportedControllers.Has(controller) { | 
		
	
		
			
				|  |  |  |  | 			continue | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		sep := " +" | 
		
	
		
			
				|  |  |  |  | 		if controllers == "" { | 
		
	
		
			
				|  |  |  |  | 			sep = "+" | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		controllers = controllers + sep + controller | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	current := cmutil.CgroupRoot | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	// Write the controllers list to each "cgroup.subtree_control" file until it reaches the parent cgroup. | 
		
	
		
			
				|  |  |  |  | 	// For the /foo/bar/baz cgroup, controllers must be enabled sequentially in the files: | 
		
	
		
			
				|  |  |  |  | 	// - /sys/fs/cgroup/foo/cgroup.subtree_control | 
		
	
		
			
				|  |  |  |  | 	// - /sys/fs/cgroup/foo/bar/cgroup.subtree_control | 
		
	
		
			
				|  |  |  |  | 	for _, p := range strings.Split(filepath.Dir(path), "/") { | 
		
	
		
			
				|  |  |  |  | 		current = filepath.Join(current, p) | 
		
	
		
			
				|  |  |  |  | 		if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), []byte(controllers), 0755); err != nil { | 
		
	
		
			
				|  |  |  |  | 			return fmt.Errorf("failed to enable controllers on %q: %v", cmutil.CgroupRoot, err) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcontainerconfigs.Resources { | 
		
	
		
			
				|  |  |  |  | 	resources := &libcontainerconfigs.Resources{ | 
		
	
		
			
				|  |  |  |  | 		Devices: []*libcontainerdevices.Rule{ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -535,10 +471,6 @@ func (m *cgroupManagerImpl) Update(cgroupConfig *CgroupConfig) error { | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 	if unified { | 
		
	
		
			
				|  |  |  |  | 		if err := propagateControllers(libcontainerCgroupConfig.Path); err != nil { | 
		
	
		
			
				|  |  |  |  | 			return err | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		supportedControllers := getSupportedUnifiedControllers() | 
		
	
		
			
				|  |  |  |  | 		if !supportedControllers.Has("hugetlb") { | 
		
	
		
			
				|  |  |  |  | 			resources.HugetlbLimit = nil | 
		
	
	
		
			
				
					
					|  |  |  | @@ -669,53 +601,21 @@ func (m *cgroupManagerImpl) ReduceCPULimits(cgroupName CgroupName) error { | 
		
	
		
			
				|  |  |  |  | 	return m.Update(containerConfig) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func getStatsSupportedSubsystems(cgroupPaths map[string]string) (*libcontainercgroups.Stats, error) { | 
		
	
		
			
				|  |  |  |  | 	stats := libcontainercgroups.NewStats() | 
		
	
		
			
				|  |  |  |  | 	for sys, required := range getSupportedSubsystems() { | 
		
	
		
			
				|  |  |  |  | 		if _, ok := cgroupPaths[sys.Name()]; !ok { | 
		
	
		
			
				|  |  |  |  | 			if required { | 
		
	
		
			
				|  |  |  |  | 				return nil, fmt.Errorf("failed to find subsystem mount for required subsystem: %v", sys.Name()) | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			// the cgroup is not mounted, but its not required so continue... | 
		
	
		
			
				|  |  |  |  | 			klog.V(6).InfoS("Unable to find subsystem mount for optional subsystem", "subsystemName", sys.Name()) | 
		
	
		
			
				|  |  |  |  | 			continue | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		if err := sys.GetStats(cgroupPaths[sys.Name()], stats); err != nil { | 
		
	
		
			
				|  |  |  |  | 			return nil, fmt.Errorf("failed to get stats for supported subsystems : %v", err) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return stats, nil | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | func toResourceStats(stats *libcontainercgroups.Stats) *ResourceStats { | 
		
	
		
			
				|  |  |  |  | 	return &ResourceStats{ | 
		
	
		
			
				|  |  |  |  | 		MemoryStats: &MemoryStats{ | 
		
	
		
			
				|  |  |  |  | 			Usage: int64(stats.MemoryStats.Usage.Usage), | 
		
	
		
			
				|  |  |  |  | 		}, | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // Get sets the ResourceParameters of the specified cgroup as read from the cgroup fs | 
		
	
		
			
				|  |  |  |  | func (m *cgroupManagerImpl) GetResourceStats(name CgroupName) (*ResourceStats, error) { | 
		
	
		
			
				|  |  |  |  | 	var err error | 
		
	
		
			
				|  |  |  |  | 	var stats *libcontainercgroups.Stats | 
		
	
		
			
				|  |  |  |  | // MemoryUsage returns the current memory usage of the specified cgroup, | 
		
	
		
			
				|  |  |  |  | // as read from cgroupfs. | 
		
	
		
			
				|  |  |  |  | func (m *cgroupManagerImpl) MemoryUsage(name CgroupName) (int64, error) { | 
		
	
		
			
				|  |  |  |  | 	var path, file string | 
		
	
		
			
				|  |  |  |  | 	if libcontainercgroups.IsCgroup2UnifiedMode() { | 
		
	
		
			
				|  |  |  |  | 		cgroupPath := m.buildCgroupUnifiedPath(name) | 
		
	
		
			
				|  |  |  |  | 		manager, err := cgroupfs2.NewManager(nil, cgroupPath, false) | 
		
	
		
			
				|  |  |  |  | 		if err != nil { | 
		
	
		
			
				|  |  |  |  | 			return nil, fmt.Errorf("failed to create cgroup v2 manager: %v", err) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		stats, err = manager.GetStats() | 
		
	
		
			
				|  |  |  |  | 		if err != nil { | 
		
	
		
			
				|  |  |  |  | 			return nil, fmt.Errorf("failed to get stats for cgroup %v: %v", name, err) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		path = m.buildCgroupUnifiedPath(name) | 
		
	
		
			
				|  |  |  |  | 		file = "memory.current" | 
		
	
		
			
				|  |  |  |  | 	} else { | 
		
	
		
			
				|  |  |  |  | 		cgroupPaths := m.buildCgroupPaths(name) | 
		
	
		
			
				|  |  |  |  | 		stats, err = getStatsSupportedSubsystems(cgroupPaths) | 
		
	
		
			
				|  |  |  |  | 		if err != nil { | 
		
	
		
			
				|  |  |  |  | 			return nil, fmt.Errorf("failed to get stats supported cgroup subsystems for cgroup %v: %v", name, err) | 
		
	
		
			
				|  |  |  |  | 		mp, ok := m.subsystems.MountPoints["memory"] | 
		
	
		
			
				|  |  |  |  | 		if !ok { // should not happen | 
		
	
		
			
				|  |  |  |  | 			return -1, errors.New("no cgroup v1 mountpoint for memory controller found") | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		path = mp + "/" + m.Name(name) | 
		
	
		
			
				|  |  |  |  | 		file = "memory.usage_in_bytes" | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  | 	return toResourceStats(stats), nil | 
		
	
		
			
				|  |  |  |  | 	val, err := fscommon.GetCgroupParamUint(path, file) | 
		
	
		
			
				|  |  |  |  | 	return int64(val), err | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					
					| 
							
							
							
						 |  |  |   |