...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/cgroup.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package server
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"regexp"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/pkg/errors"
    26  	v1 "k8s.io/api/core/v1"
    27  
    28  	"github.com/chaos-mesh/chaos-mesh/pkg/bpm"
    29  	"github.com/chaos-mesh/chaos-mesh/pkg/ctrl/server/model"
    30  )
    31  
    32  // GetCgroups returns result of cat /proc/cgroups
    33  func (r *Resolver) GetCgroups(ctx context.Context, obj *model.PodStressChaos) (*model.Cgroups, error) {
    34  	cmd := "cat /proc/cgroups"
    35  
    36  	// the raw looks like:
    37  	// ```
    38  	// #subsys_name    hierarchy       num_cgroups     enabled
    39  	// cpuset  0       127     1
    40  	// cpu     0       127     1
    41  	// cpuacct 0       127     1
    42  	// blkio   0       127     1
    43  	// memory  0       127     1
    44  	// devices 0       127     1
    45  	// freezer 0       127     1
    46  	// net_cls 0       127     1
    47  	// perf_event      0       127     1
    48  	// net_prio        0       127     1
    49  	// hugetlb 0       127     1
    50  	// pids    0       127     1
    51  	// rdma    0       127     1
    52  	// misc    0       127     1
    53  	// ```
    54  	raw, err := r.ExecBypass(ctx, obj.Pod, cmd, bpm.PidNS, bpm.MountNS)
    55  
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	cgroups := &model.Cgroups{
    61  		Raw: raw,
    62  	}
    63  
    64  	// no more info for StressngStressors
    65  	if obj.StressChaos.Spec.StressngStressors != "" || obj.StressChaos.Spec.Stressors == nil {
    66  		return cgroups, nil
    67  	}
    68  
    69  	isCPU := true
    70  	if obj.StressChaos.Spec.Stressors.CPUStressor == nil {
    71  		isCPU = false
    72  	}
    73  
    74  	if isCPU {
    75  		var cpuMountType string
    76  		if regexp.MustCompile("(cpu,cpuacct)").MatchString(string(raw)) {
    77  			cpuMountType = "cpu,cpuacct"
    78  		} else {
    79  			// cgroup does not support cpuacct sub-system
    80  			cpuMountType = "cpu"
    81  		}
    82  		cgroups.CPU = &model.CgroupsCPU{}
    83  		cgroups.CPU.Quota, err = r.GetCPUQuota(ctx, obj.Pod, cpuMountType)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		cgroups.CPU.Period, err = r.GetCPUPeriod(ctx, obj.Pod, cpuMountType)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  	} else {
    92  		cgroups.Memory = &model.CgroupsMemory{}
    93  		cgroups.Memory.Limit, err = r.GetMemoryLimit(ctx, obj.Pod)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  	}
    98  
    99  	return cgroups, nil
   100  }
   101  
   102  // GetCgroup returns result of cat /proc/:pid/cgroup
   103  // The output looks like:
   104  // ```
   105  // 11:freezer:/
   106  // 10:hugetlb:/
   107  // 9:memory:/system.slice/sshd.service
   108  // 8:pids:/system.slice/sshd.service
   109  // 7:perf_event:/
   110  // 6:net_cls,net_prio:/
   111  // 5:devices:/system.slice/sshd.service
   112  // 4:blkio:/system.slice/sshd.service
   113  // 3:cpu,cpuacct:/system.slice/sshd.service
   114  // 2:cpuset:/
   115  // 1:name=systemd:/system.slice/sshd.service
   116  // ```
   117  func (r *Resolver) GetCgroup(ctx context.Context, obj *v1.Pod, pid string) (string, error) {
   118  	cmd := fmt.Sprintf("cat /proc/%s/cgroup", pid)
   119  	return r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS)
   120  }
   121  
   122  // GetCPUQuota returns result of cat /sys/fs/cgroup/:cpuMountType/cpu.cfs_quota_us
   123  func (r *Resolver) GetCPUQuota(ctx context.Context, obj *v1.Pod, cpuMountType string) (int, error) {
   124  	cmd := fmt.Sprintf("cat /sys/fs/cgroup/%s/cpu.cfs_quota_us", cpuMountType)
   125  	out, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS)
   126  	if err != nil {
   127  		return 0, err
   128  	}
   129  	return strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
   130  }
   131  
   132  // GetCPUPeriod returns result of cat /sys/fs/cgroup/:cpuMountType/cpu.cfs_period_us
   133  func (r *Resolver) GetCPUPeriod(ctx context.Context, obj *v1.Pod, cpuMountType string) (int, error) {
   134  	cmd := fmt.Sprintf("cat /sys/fs/cgroup/%s/cpu.cfs_period_us", cpuMountType)
   135  	out, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS)
   136  	if err != nil {
   137  		return 0, err
   138  	}
   139  	return strconv.Atoi(strings.TrimSuffix(string(out), "\n"))
   140  }
   141  
   142  // GetMemoryLimit returns result of cat /sys/fs/cgroup/memory/memory.limit_in_bytes
   143  func (r *Resolver) GetMemoryLimit(ctx context.Context, obj *v1.Pod) (int64, error) {
   144  	cmd := "cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
   145  	rawLimit, err := r.ExecBypass(ctx, obj, cmd, bpm.PidNS, bpm.MountNS)
   146  	if err != nil {
   147  		return 0, errors.Wrap(err, "could not get memory.limit_in_bytes")
   148  	}
   149  	limit, err := strconv.ParseUint(strings.TrimSuffix(rawLimit, "\n"), 10, 64)
   150  	if err != nil {
   151  		return 0, errors.Wrap(err, "could not parse memory.limit_in_bytes")
   152  	}
   153  	return int64(limit), nil
   154  }
   155